Decompiled source of Bretaheim v0.3.3

plugins/Bretaheim/Bretaheim.dll

Decompiled 8 hours 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.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using Bretaheim.Data;
using Bretaheim.DevTools;
using Bretaheim.WorldGen;
using Bretaheim.WorldGen.Core;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Jotunn.Utils;
using SoftReferenceableAssets;
using Splatform;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Rendering;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("Bretaheim")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+f3a4c989d38b33dd892947fe2cbae2cc85bfc7be")]
[assembly: AssemblyProduct("Bretaheim")]
[assembly: AssemblyTitle("Bretaheim")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Bretaheim
{
	[BepInPlugin("tarbaby.bretaheim", "Bretaheim", "0.3.3")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
	public class Plugin : BaseUnityPlugin
	{
		public const string PluginGUID = "tarbaby.bretaheim";

		public const string PluginName = "Bretaheim";

		public const string PluginVersion = "0.3.3";

		private Harmony harmony;

		public static Plugin Instance { get; private set; }

		public static ManualLogSource Log { get; private set; }

		public static U5Data U5 { get; private set; }

		public static ConfigEntry<string> U5Directory { get; private set; }

		public static ConfigEntry<float> TileMetres { get; private set; }

		public static ConfigEntry<bool> NewWorldsAreBritannia { get; private set; }

		public static ConfigEntry<string> DumpPieceGeometry { get; private set; }

		public static ConfigEntry<bool> SelfTest { get; private set; }

		public static ConfigEntry<bool> LogHitches { get; private set; }

		public static ConfigEntry<string> BuildSettlements { get; private set; }

		public static ConfigEntry<string> CombinedShells { get; private set; }

		public static ConfigEntry<int> SpawnLocation { get; private set; }

		public static string PluginDirectory { get; private set; } = "";

		private void Awake()
		{
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Expected O, but got Unknown
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_018d: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			PluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? "";
			U5Directory = ((BaseUnityPlugin)this).Config.Bind<string>("General", "UltimaVDirectory", "", "Folder of your own copy of Ultima V (e.g. the GOG install) containing DATA.OVL, BRIT.DAT, TOWNE.DAT, ... The mod reads the world, towns, people and conversations from it at start-up; no Ultima V data ships with the mod.");
			TileMetres = ((BaseUnityPlugin)this).Config.Bind<float>("World", "TileMetres", 32f, new ConfigDescription("Size of one Ultima V tile in metres (32 = Britannia is an 8.2 km square). Must be the same on the server and every client.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(8f, 36f), Array.Empty<object>()));
			NewWorldsAreBritannia = ((BaseUnityPlugin)this).Config.Bind<bool>("World", "NewWorldsAreBritannia", true, "New worlds get a seed starting with \"Britannia\", which makes them Britannia. A world is Britannia exactly when its seed starts with \"Britannia\"; worlds with other seeds stay vanilla.");
			BuildSettlements = ((BaseUnityPlugin)this).Config.Bind<string>("World", "BuildSettlements", "1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32", "Location numbers of the settlements built from their maps in new Britannia worlds (2 Britain, 4 Yew, 13 Iolo's hut, 17 Lord British's castle, 19-21 West, North and East Britanny, 25 Ararat in the Underworld; see 'u5 dump locations'). Must be the same on the server and every client.");
			CombinedShells = ((BaseUnityPlugin)this).Config.Bind<string>("World", "CombinedShells", "*", "Settlements whose building shells (walls, floors, roofs) are built as one combined object per zone instead of thousands of separate pieces (* = all of them). Must match on every peer.");
			SpawnLocation = ((BaseUnityPlugin)this).Config.Bind<int>("World", "SpawnLocation", 13, "Where players first appear in a new Britannia world: 13 = inside Iolo's hut (the game's start), or the location number of a built settlement to start just outside it (2 = Britain). Read by whoever creates the world (the server, or the host); existing worlds keep their spawn.");
			DumpPieceGeometry = ((BaseUnityPlugin)this).Config.Bind<string>("Development", "DumpPieceGeometry", "", "Comma-separated prefab names (or *) whose snap points and bounds are written to BepInEx/u5_piece_geometry.json at start-up. Leave empty.");
			SelfTest = ((BaseUnityPlugin)this).Config.Bind<bool>("Development", "SelfTest", false, "Log development self-checks at start-up. Leave off.");
			LogHitches = ((BaseUnityPlugin)this).Config.Bind<bool>("Development", "LogHitches", true, "Log every frame over 150 ms (\"hitch\") with what ran in it: zone spawning, terrain, object creation, settlement pieces, townsfolk, structures.");
			harmony = new Harmony("tarbaby.bretaheim");
			PieceGeometryDump.Install(harmony);
			U5Command.Install(harmony);
			if (!LoadU5Data())
			{
				Log.LogError((object)("Bretaheim is disabled until UltimaVDirectory points at an Ultima V install (edit " + ((BaseUnityPlugin)this).Config.ConfigFilePath + " and restart)."));
				return;
			}
			harmony.PatchAll();
			WorldGenPatches.Install(harmony);
			if (WorldGenPatches.Installed)
			{
				WorldSize.Install(harmony);
				Underworld.Install(harmony);
				Whirlpool.Register();
				TownFurniture.Install(harmony);
				Whirlpool.Install(harmony);
				((Component)this).gameObject.AddComponent<UnderworldWatch>();
				PlaceMarkers.Install(harmony);
				Settlements.Install(harmony);
				Structures.Register();
				TownsfolkSpawner.Register();
				Ballistas.Register();
				Ettin.Register();
				Camp.Register();
				Ladders.Register();
				Furnishings.Register();
				Stairs.Register();
				Dungeons.Register();
				UltimaItems.Register();
				SpellStatus.Register();
				Treasure.Register();
				TalkPanel.Install(harmony);
				ShopTrading.Install(harmony);
				BigInventory.Install(harmony);
				PouchPanel.Install(harmony);
				StartingGold.Install(harmony);
				TownWatch.Install(harmony);
				TownsfolkPatches.Install(harmony);
				UltimaCreatures.Install(harmony);
				AvatarStats.Install(harmony);
				Ballistas.Install(harmony);
				Crime.Install(harmony);
				TownDoors.Install(harmony);
				CreatureTalker.Install(harmony);
				ResidentMonster.Install(harmony);
				Sleep.Install(harmony);
				Respawn.Install(harmony);
				Stage.Install(harmony);
				TerrainQueue.Install(harmony);
				Dungeons.Install(harmony);
				Treasure.Install(harmony);
				UseItems.Install(harmony);
				WornEffects.Install(harmony);
				MagicCarpet.Register();
				Horses.Register();
				Horses.Install(harmony);
				Vessels.Install(harmony);
				((Component)this).gameObject.AddComponent<TransportWatch>();
				((Component)this).gameObject.AddComponent<WornEffects.Tick>();
				((Component)this).gameObject.AddComponent<BlackthornGuards>();
				BlackthornCapture.Install(harmony);
				((Component)this).gameObject.AddComponent<Endgame.Watch>();
				Moongates.Install(harmony);
				Shadowlords.Install(harmony);
				((Component)this).gameObject.AddComponent<MoongateKeeper>();
				((Component)this).gameObject.AddComponent<ShadowlordWatch>();
				KarmaDeeds.Install(harmony);
				RationsWatch.Install(harmony);
				Restrictions.Install(harmony);
				Intro.Install(harmony);
				IolosHut.Install(harmony);
				Spells.Install(harmony);
				Shrines.Install(harmony);
				Furnishings.Install(harmony);
				Stairs.Install(harmony);
				if (LogHitches.Value)
				{
					LoadProfiler.Install(harmony);
				}
				((Component)this).gameObject.AddComponent<Crime.Watch>();
				((Component)this).gameObject.AddComponent<Camp.Keys>();
				((Component)this).gameObject.AddComponent<Spells.Keys>();
				((Component)this).gameObject.AddComponent<RationsWatch>();
				((Component)this).gameObject.AddComponent<Restrictions.ToolWatch>();
				((Component)this).gameObject.AddComponent<IolosHut.Keeper>();
				((Component)this).gameObject.AddComponent<UltimaSpawner>();
				FixedPieces.Install(harmony);
				BiomeBlend.Install(harmony);
				RiverBanks.Install(harmony);
				Bridges.Install(harmony);
				((Component)this).gameObject.AddComponent<WorldWrap>();
				((Component)this).gameObject.AddComponent<DungeonRunner>();
				if (SelfTest.Value)
				{
					((Component)this).gameObject.AddComponent<TownsfolkSelfTest>();
				}
				if (LogHitches.Value)
				{
					((Component)this).gameObject.AddComponent<LoadProfiler>();
				}
			}
			Log.LogInfo((object)"Bretaheim v0.3.3 loaded.");
		}

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

		private static bool LoadU5Data()
		{
			string value = U5Directory.Value;
			if (string.IsNullOrWhiteSpace(value))
			{
				Log.LogError((object)"UltimaVDirectory is not set.");
				return false;
			}
			value = Environment.ExpandEnvironmentVariables(value.Trim());
			if (value.StartsWith("~"))
			{
				value = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + value.Substring(1);
			}
			List<string> list = U5Data.Validate(value);
			if (list.Count > 0)
			{
				Log.LogError((object)("UltimaVDirectory '" + value + "' is not a usable Ultima V install; missing: " + string.Join(", ", list)));
				return false;
			}
			try
			{
				Stopwatch stopwatch = Stopwatch.StartNew();
				U5 = U5Data.Load(value);
				Log.LogInfo((object)($"Read Ultima V from '{value}' in {stopwatch.ElapsedMilliseconds} ms: " + $"{U5.Locations.Length} locations, {U5.DungeonRooms.Count} dungeon rooms."));
				return true;
			}
			catch (Exception ex) when (ex is IOException || ex is U5FormatException || ex is IndexOutOfRangeException)
			{
				Log.LogError((object)("Could not read Ultima V from '" + value + "': " + ex.Message));
				return false;
			}
		}
	}
	public static class U5Command
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleEvent <>9__1_0;

			public static Func<string, int, bool> <>9__2_2;

			internal void <InitTerminal_Postfix>b__1_0(ConsoleEventArgs args)
			{
				Run(args.Context, args.Args.Skip(1).ToArray());
			}

			internal bool <Run>b__2_2(string _, int i)
			{
				return i != 1;
			}
		}

		public static void Install(Harmony harmony)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogError((object)"Terminal.InitTerminal not found: the u5 console command is unavailable");
			}
			else
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(U5Command), "InitTerminal_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void InitTerminal_Postfix()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Expected O, but got Unknown
			object obj = <>c.<>9__1_0;
			if (obj == null)
			{
				ConsoleEvent val = delegate(ConsoleEventArgs args)
				{
					Run(args.Context, args.Args.Skip(1).ToArray());
				};
				<>c.<>9__1_0 = val;
				obj = (object)val;
			}
			new ConsoleCommand("u5", "Ultima V data: u5 dump <locations|map|npcs|talk|items|monsters|spells|...> [args]; u5 encounter [type [body]] (devcommands) brings a random encounter, or one creature of that type before you (in that Valheim body); u5 play <notes> plays the harpsichord you stand at; u5 press next|skip|<letter>|<button> presses on the Ultima screens and the talk panel; u5 key cast|mix|close and u5 mix <spell> [n] do the magic keys, u5 pouch [give reagent|spell <i> <n> | ready <spell>] the reagents and spells held, u5 type <text> answers the open text box (tests); u5 intro [fast] [2d | scene] replays the introduction (in the world, from scene 0..3, or the original's screens; fast: four times as fast); u5 karma [n]; u5 exp [n] (setting needs devcommands); u5 unmake (devcommands) to meet Hildir again; u5 time | moons | dusk | dawn | midnight: Britannia's clock, moons and moongates; u5 dungeon <name> (devcommands) takes you to a dungeon entrance; u5 quest: the state of the quest; u5 resurrect [2d], u5 blackthorn and u5 endgame [box] (devcommands) play Blackthorn's interrogation and Lord British's rescue; u5 under [<x> <y> | surface <x> <y> | falls | whirlpool | doom | ararat | <dungeon>] where you are, or (devcommands) to the Underworld; u5 vessel frigate|skiff|pirates|horse (devcommands) brings one", (ConsoleEvent)obj, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false);
		}

		private static void Run(Terminal terminal, string[] args)
		{
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_021c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0228: Unknown result type (might be due to invalid IL or missing references)
			//IL_0232: Unknown result type (might be due to invalid IL or missing references)
			//IL_0237: Unknown result type (might be due to invalid IL or missing references)
			//IL_023c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0241: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_014e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0401: Unknown result type (might be due to invalid IL or missing references)
			//IL_0770: Unknown result type (might be due to invalid IL or missing references)
			//IL_0781: Unknown result type (might be due to invalid IL or missing references)
			//IL_0645: Unknown result type (might be due to invalid IL or missing references)
			//IL_0651: Unknown result type (might be due to invalid IL or missing references)
			//IL_0664: Unknown result type (might be due to invalid IL or missing references)
			//IL_0672: Unknown result type (might be due to invalid IL or missing references)
			//IL_06a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_06ad: Unknown result type (might be due to invalid IL or missing references)
			if (args.Length > 1 && args[0] == "vessel")
			{
				Player localPlayer = Player.m_localPlayer;
				if (!Terminal.m_cheat)
				{
					Print("u5 vessel needs devcommands");
					return;
				}
				if ((Object)(object)localPlayer == (Object)null || Britannia.Active == null)
				{
					Print("u5 vessel: only in Britannia");
					return;
				}
				Vector3 val = ((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 25f;
				switch (args[1])
				{
				case "frigate":
				case "skiff":
				{
					bool flag = args[1] == "frigate";
					GameObject val2 = Vessels.Spawn(flag, val, ((Component)localPlayer).transform.eulerAngles.y, localPlayer.GetPlayerID(), localPlayer.GetPlayerName(), flag ? Shops.SkiffsAboard(130) : 0);
					Print(((Object)(object)val2 != (Object)null) ? $"a {args[1]} at {val}" : "no such vessel");
					break;
				}
				case "pirates":
					Print(Pirates.Spawn(((Component)localPlayer).transform.position + ((Component)localPlayer).transform.forward * 70f, new Random()) ?? "no deep water 70 m ahead");
					break;
				case "horse":
				{
					Print(Horses.Buy(localPlayer, out var where) ? ("a horse " + where) : "no room for a horse here");
					break;
				}
				default:
					Print("u5 vessel frigate|skiff|pirates|horse");
					break;
				}
				return;
			}
			if (args.Length != 0 && args[0] == "encounter")
			{
				Player localPlayer2 = Player.m_localPlayer;
				int result;
				if (!Terminal.m_cheat)
				{
					Print("u5 encounter needs devcommands");
				}
				else if ((Object)(object)localPlayer2 == (Object)null || Britannia.Active == null)
				{
					Print("u5 encounter: only in Britannia");
				}
				else if (args.Length > 1 && int.TryParse(args[1], out result))
				{
					Character val3 = UltimaCreatures.Spawn(result, ((Component)localPlayer2).transform.position + ((Component)localPlayer2).transform.forward * 6f + Vector3.up, wild: false, (args.Length > 2) ? args[2] : null);
					Print(((Object)(object)val3 != (Object)null) ? (val3.m_name + " (" + Utils.GetPrefabName(((Component)val3).gameObject) + ")") : $"no body for creature type {result}");
				}
				else
				{
					Print(UltimaSpawner.Encounter(((Component)localPlayer2).transform.position, localPlayer2.GetPlayerName(), new Random()) ?? "nothing comes here (no monster for this land, a town, or 8 already near)");
				}
				return;
			}
			if (args.Length > 1 && args[0] == "press")
			{
				foreach (string item in args.Skip(1))
				{
					if (!UltimaScreenPanel.Press(item.ToLowerInvariant()) && !TalkPanel.Press(item.Replace('_', ' ')))
					{
						Print("u5 press: " + item + " is not offered");
						break;
					}
				}
				return;
			}
			int result4;
			if (args.Length > 1 && (args[0] == "key" || args[0] == "mix"))
			{
				Player localPlayer3 = Player.m_localPlayer;
				if ((Object)(object)localPlayer3 == (Object)null)
				{
					return;
				}
				int result2;
				int result3;
				if (args[0] == "key" && args[1] == "cast")
				{
					Spells.CastReadied(localPlayer3);
				}
				else if (args[0] == "key" && args[1] == "close")
				{
					MixPanel.Close();
					SkyPanel.Close();
					UltimaScreenPanel.Close();
				}
				else if (args[0] == "key" && args[1] == "mix")
				{
					if (Spells.NearFire(((Component)localPlayer3).transform.position))
					{
						MixPanel.Open(localPlayer3);
					}
					else
					{
						Print("u5 key mix: no fire near");
					}
				}
				else if (!(args[0] == "mix") || !int.TryParse(args[1], out result2) || !MixPanel.Choose(result2, (args.Length <= 2 || !int.TryParse(args[2], out result3)) ? 1 : result3))
				{
					Print("u5 key cast|mix|close; u5 mix <spell 0-47> [count] with the mixing panel open");
				}
			}
			else if (args.Length != 0 && args[0] == "pouch")
			{
				if (Plugin.U5 == null)
				{
					Print("Ultima V data is not loaded");
				}
				else
				{
					Print(PouchPanel.Command(args));
				}
			}
			else if (args.Length > 1 && args[0] == "scroll" && int.TryParse(args[1], out result4))
			{
				BigInventory.ScrollTo(result4);
			}
			else if (args.Length > 1 && args[0] == "type")
			{
				if (!UltimaScreenPanel.Type(string.Join(" ", args.Skip(1))))
				{
					if (!TextInput.IsVisible() || (Object)(object)TextInput.instance == (Object)null)
					{
						Print("u5 type: no text box open");
						return;
					}
					TextInput instance = TextInput.instance;
					AccessTools.Method(typeof(TextInput), "setText", (Type[])null, (Type[])null)?.Invoke(instance, new object[1] { string.Join(" ", args.Skip(1)) });
					instance.Hide();
				}
			}
			else if (args.Length != 0 && args[0] == "under")
			{
				Underworld.Command(args, Print);
			}
			else if (args.Length != 0 && args[0] == "dungeon")
			{
				Player localPlayer4 = Player.m_localPlayer;
				int result5;
				int num = ((args.Length <= 1) ? (-1) : (int.TryParse(args[1], out result5) ? result5 : ((Plugin.U5?.FindLocation(args[1])?.Number).GetValueOrDefault() - 33)));
				Vector2? val4 = Dungeons.Centre(num);
				if (!Terminal.m_cheat)
				{
					Print("u5 dungeon needs devcommands");
					return;
				}
				if ((Object)(object)localPlayer4 == (Object)null || !val4.HasValue)
				{
					Print("u5 dungeon <Deceit|Despise|Destard|Wrong|Covetous|Shame|Hythloth>: only in Britannia");
					return;
				}
				BritanniaShape britanniaShape = Britannia.ShapeAt(val4.Value.x, val4.Value.y);
				float x = val4.Value.x;
				float num2 = val4.Value.y - 9f;
				((Character)localPlayer4).TeleportTo(new Vector3(x, 30f + britanniaShape.Height(x, num2) + 1f, num2), ((Component)localPlayer4).transform.rotation, true);
				Print("to " + Dungeons.Name(num) + ": say " + Plugin.U5.Ovl.WordsOfPower[num] + " near its door to open it");
			}
			else if (args.Length != 0 && args[0] == "play")
			{
				Player me = Player.m_localPlayer;
				Harpsichord harpsichord = (((Object)(object)me == (Object)null) ? null : (from h in Object.FindObjectsByType<Harpsichord>((FindObjectsSortMode)0)
					orderby Vector3.Distance(((Component)h).transform.position, ((Component)me).transform.position)
					select h).FirstOrDefault());
				if ((Object)(object)harpsichord == (Object)null || Vector3.Distance(((Component)harpsichord).transform.position, ((Component)me).transform.position) > 5f)
				{
					Print("u5 play: no harpsichord here");
				}
				else
				{
					harpsichord.SetText(string.Join("", args.Skip(1)));
				}
			}
			else
			{
				if ((Plugin.U5 != null && ClockCommands.Run(args, Print)) || (Plugin.U5 != null && StoryCommands.Run(args, Print)))
				{
					return;
				}
				if (args.Length != 0 && (args[0] == "intro" || args[0] == "karma" || args[0] == "exp" || args[0] == "unmake"))
				{
					Player localPlayer5 = Player.m_localPlayer;
					int result7;
					if ((Object)(object)localPlayer5 == (Object)null || Britannia.Active == null)
					{
						Print("u5 " + args[0] + ": only in Britannia");
					}
					else if (args[0] == "intro" && args.Length > 2 && args[1] == "hide")
					{
						Print(IntroStage.Toggle(args[2]));
					}
					else if (args[0] == "intro")
					{
						if (args.Length > 1 && args[1] == "fast")
						{
							IntroStage.Speed = 4f;
							args = args.Where((string _, int i) => i != 1).ToArray();
						}
						((MonoBehaviour)Plugin.Instance).StartCoroutine(Intro.Play(args.Length > 1 && args[1] == "2d", (args.Length > 1 && int.TryParse(args[1], out var result6)) ? result6 : 0));
					}
					else if (args[0] == "karma" && args.Length > 1 && Terminal.m_cheat && int.TryParse(args[1], out result7))
					{
						Karma.Set(localPlayer5.m_customData, result7);
						Print($"karma {Karma.Get(localPlayer5.m_customData)}");
					}
					else if (args[0] == "karma")
					{
						Print(string.Format("karma {0}{1}", KarmaDeeds.Of(localPlayer5), KarmaDeeds.WearsAnkh(localPlayer5) ? $" ({Karma.Get(localPlayer5.m_customData)} and the Ankh's {10})" : ""));
					}
					else if (args[0] == "exp")
					{
						Avatar mine = AvatarStats.Mine;
						if (args.Length > 1 && Terminal.m_cheat && int.TryParse(args[1], out var result8))
						{
							mine.Experience = Math.Max(0, Math.Min(9999, result8));
							mine.Save(localPlayer5.m_customData);
						}
						Print($"experience {mine.Experience}, level {mine.Level}, {mine.MaxHitPoints} hit points, mana {mine.Mana}");
					}
					else if (!Terminal.m_cheat)
					{
						Print("u5 unmake needs devcommands");
					}
					else
					{
						Avatar mine2 = AvatarStats.Mine;
						mine2.Made = false;
						mine2.Strength = (mine2.Dexterity = (mine2.Intelligence = (mine2.Mana = 0)));
						mine2.Save(localPlayer5.m_customData);
						Print("the Avatar is unmade: speak with Hildir in Iolo's hut");
					}
					return;
				}
				if (args.Length == 0 || args[0] != "dump")
				{
					Print("u5 dump <what> [args]\n  locations                 the 40 places with map file, floors and overworld position\n  map <location> [z]        a settlement floor as tile ids (hex)\n  npcs <location>           NPCs: type, dialogue, schedule\n  talk <location> <slot>    an NPC's conversation decoded\n  items                     equipment names, attack/defence/range/price\n  monsters                  creature names and raw stats\n  spells | reagents | virtues | words\n  dungeon <0-7|name> <level> [plan]  DUNGEON.DAT cells; plan: the level as built (88x88 tiles), its rooms\n  room <index> | room <dungeon> <n>  a DUNGEON.CBT room (11x11 + metadata), by file index or by dungeon\n  world <x> <y> [w] [h] [under]  overworld tile ids\n  tiles [from] [count]      LOOK2.DAT tile names\n  signs [location]          SIGNS.DAT\n  init                      INIT.GAM: party, inventory, karma, date, position");
					return;
				}
				if (Plugin.U5 != null)
				{
					try
					{
						Print(Dump.Run(Plugin.U5, args.Skip(1).ToArray()));
						return;
					}
					catch (Exception ex)
					{
						Print("error: " + ex.Message);
						return;
					}
				}
				Print("Ultima V data is not loaded: set UltimaVDirectory in BepInEx/config/tarbaby.bretaheim.cfg and restart.");
			}
			void Print(string text)
			{
				string[] array = text.TrimEnd('\n').Split('\n');
				foreach (string text2 in array)
				{
					terminal.AddString(text2);
				}
			}
		}
	}
}
namespace Bretaheim.WorldGen
{
	public static class AvatarStats
	{
		private const string ExperienceRpc = "U5_Experience";

		private static readonly Random random = new Random();

		private static readonly int[] comfort = new int[9]
		{
			SEMan.s_statusEffectRested,
			SEMan.s_statusEffectResting,
			SEMan.s_statusEffectWet,
			SEMan.s_statusEffectCold,
			SEMan.s_statusEffectFreezing,
			SEMan.s_statusEffectShelter,
			SEMan.s_statusEffectCampFire,
			SEMan.s_statusEffectSoftDeath,
			StringExtensionMethods.GetStableHashCode("CorpseRun")
		};

		private static Player Me => Player.m_localPlayer;

		private static bool Active => Britannia.Active != null;

		public static Avatar Mine
		{
			get
			{
				if (!((Object)(object)Me != (Object)null))
				{
					return new Avatar();
				}
				return Avatar.Load(Me.m_customData);
			}
		}

		public static void Install(Harmony harmony)
		{
			//IL_0192: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Expected O, but got Unknown
			//IL_01bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ca: Expected O, but got Unknown
			//IL_02f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0307: Expected O, but got Unknown
			Patch(harmony, typeof(Player), "SetMaxHealth", "SetMaxHealth_Prefix");
			Patch(harmony, typeof(Player), "SetSleeping", null, "SetSleeping_Postfix");
			Patch(harmony, typeof(Character), "OnDeath", "OnDeath_Prefix");
			Patch(harmony, typeof(SkillsDialog), "Setup", null, "SkillsSetup_Postfix");
			Patch(harmony, typeof(Skills), "RaiseSkill", "RaiseSkill_Prefix");
			Patch(harmony, typeof(Skills), "GetSkillLevel", "GetSkillLevel_Prefix");
			Patch(harmony, typeof(Skills), "OnDeath", "RaiseSkill_Prefix");
			MethodInfo methodInfo = AccessTools.Method(typeof(SEMan), "AddStatusEffect", new Type[5]
			{
				typeof(int),
				typeof(bool),
				typeof(int),
				typeof(float),
				typeof(short)
			}, (Type[])null);
			MethodInfo methodInfo2 = AccessTools.Method(typeof(SEMan), "AddStatusEffect", new Type[5]
			{
				typeof(StatusEffect),
				typeof(bool),
				typeof(int),
				typeof(float),
				typeof(short)
			}, (Type[])null);
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(AvatarStats), "AddStatusEffectHash_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(AvatarStats), "AddStatusEffect_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (methodInfo == null || methodInfo2 == null)
			{
				Plugin.Log.LogWarning((object)"Avatar stats: SEMan.AddStatusEffect not found (Valheim's Rested stays)");
			}
			Patch(harmony, typeof(Game), "Start", null, "GameStart_Postfix");
			Patch(harmony, typeof(Player), "OnSpawned", null, "OnSpawned_Postfix");
			Patch(harmony, typeof(Player), "RPC_UseStamina", "UseStamina_Prefix");
			Patch(harmony, typeof(Bed), "Interact", "BedInteract_Prefix");
			Patch(harmony, typeof(Bed), "GetHoverText", "BedHover_Prefix");
			Patch(harmony, typeof(Hud), "UpdateHealth", null, "UpdateHealth_Postfix");
			MethodInfo methodInfo3 = AccessTools.Method(typeof(DamageText), "ShowText", new Type[4]
			{
				typeof(TextType),
				typeof(Vector3),
				typeof(float),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo3 != null)
			{
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(AvatarStats), "ShowText_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			else
			{
				Plugin.Log.LogWarning((object)"Avatar stats: DamageText.ShowText not found");
			}
		}

		private static void Patch(Harmony h, Type t, string m, string prefix = null, string postfix = null)
		{
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.Method(t, m, (!(t == typeof(Player)) || !(m == "SetMaxHealth")) ? null : new Type[2]
			{
				typeof(float),
				typeof(bool)
			}, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)("Avatar stats: " + t.Name + "." + m + " not found"));
			}
			else
			{
				h.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(AvatarStats), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(AvatarStats), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static void SetMaxHealth_Prefix(Player __instance, ref float health)
		{
			if (Active && !((Object)(object)__instance != (Object)(object)Me))
			{
				health = (float)Mine.MaxHitPoints * 10f;
			}
		}

		private static void UpdateHealth_Postfix(Hud __instance, Player player)
		{
			if (Active && (Object)(object)player != (Object)null)
			{
				__instance.m_healthText.text = Mathf.CeilToInt(((Character)player).GetHealth() / 10f).ToString();
			}
		}

		private static void ShowText_Prefix(ref float dmg)
		{
			if (Active)
			{
				dmg /= 10f;
			}
		}

		private static bool UseStamina_Prefix()
		{
			return !Active;
		}

		private static bool TownBed(Bed bed)
		{
			if (Active)
			{
				return (Object)(object)((Component)bed).GetComponentInParent<U5Fixed>() != (Object)null;
			}
			return false;
		}

		private static bool BedInteract_Prefix(Bed __instance, Humanoid human, bool repeat, ref bool __result)
		{
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			if (!TownBed(__instance))
			{
				return true;
			}
			__result = false;
			if (repeat)
			{
				return false;
			}
			Player val = (Player)(object)((human is Player) ? human : null);
			if (val != null && (Object)(object)val == (Object)(object)Player.m_localPlayer)
			{
				if (Inns.MayRest(val, __instance, out var why))
				{
					Sleep.LieDown(val, ((Object)(object)__instance.m_spawnPoint != (Object)null) ? __instance.m_spawnPoint : ((Component)__instance).transform, ((Component)__instance).gameObject);
					return false;
				}
				if (why != null)
				{
					Plugin.Log.LogInfo((object)("Inn bed refused: " + why));
				}
			}
			Player val2 = (Player)(object)((human is Player) ? human : null);
			if (val2 != null && (Object)(object)val2 == (Object)(object)Player.m_localPlayer)
			{
				Searching.Search(((Component)__instance).transform.position, 2.3f, 35274, val2);
			}
			__result = true;
			return false;
		}

		private static bool BedHover_Prefix(Bed __instance, ref string __result)
		{
			if (!TownBed(__instance))
			{
				return true;
			}
			Player localPlayer = Player.m_localPlayer;
			__result = Localization.instance.Localize(__instance.GetHoverName() + (((Object)(object)localPlayer != (Object)null && Inns.MayRest(localPlayer, __instance)) ? "\n[<color=yellow><b>$KEY_Use</b></color>] Sleep" : "\n[<color=yellow><b>$KEY_Use</b></color>] Search"));
			return false;
		}

		public static int WeaponAttack(Player player)
		{
			ItemData currentWeapon = ((Humanoid)player).GetCurrentWeapon();
			object obj;
			if (currentWeapon == null)
			{
				obj = null;
			}
			else
			{
				GameObject dropPrefab = currentWeapon.m_dropPrefab;
				obj = ((dropPrefab != null) ? ((Object)dropPrefab).name : null);
			}
			string text = (string)obj;
			int num = ((text != null && currentWeapon != ((Humanoid)player).m_unarmedWeapon?.m_itemData) ? ShopTrading.Items.EquipmentOf(text) : (-1));
			int val = ((num < 0) ? 1 : Plugin.U5.Ovl.ItemAttack(num));
			return Ultima.WeaponRoll(Math.Max(1, val), random);
		}

		public static int Defence(Player player)
		{
			IEnumerable<int> worn = from i in ((Humanoid)player).GetInventory().GetEquippedItems()
				where (Object)(object)i.m_dropPrefab != (Object)null
				select ShopTrading.Items.EquipmentOf(((Object)i.m_dropPrefab).name);
			return Avatar.Defence(Plugin.U5.Ovl, worn) + WornEffects.ExtraDefence(player) + (SpellStatus.Has(player, "U5_Protection") ? 3 : 0);
		}

		private static void OnDeath_Prefix(Character __instance)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			CreatureStats creatureStats = UltimaCreatures.Of(__instance);
			if (creatureStats == null || (Object)(object)((Component)__instance).GetComponent<TownNpc>() != (Object)null)
			{
				return;
			}
			HitData value = Traverse.Create((object)__instance).Field("m_lastHit").GetValue<HitData>();
			Character obj = ((value != null) ? value.GetAttacker() : null);
			Player val = (Player)(object)((obj is Player) ? obj : null);
			if (val == null)
			{
				return;
			}
			int num = Avatar.ExperienceFor(creatureStats);
			if ((Object)(object)val == (Object)(object)Me)
			{
				Earn(num);
				return;
			}
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				ZDOID zDOID = ((Character)val).GetZDOID();
				instance.InvokeRoutedRPC(((ZDOID)(ref zDOID)).UserID, "U5_Experience", new object[1] { num });
			}
		}

		private static void GameStart_Postfix()
		{
			ZRoutedRpc instance = ZRoutedRpc.instance;
			if (instance != null)
			{
				instance.Register<int>("U5_Experience", (Action<long, int>)delegate(long sender, int exp)
				{
					Earn(exp);
				});
			}
		}

		private static void Earn(int exp)
		{
			if (!((Object)(object)Me == (Object)null) && Active)
			{
				Avatar mine = Mine;
				mine.Experience = Math.Min(9999, mine.Experience + exp);
				mine.Save(Me.m_customData);
				((Character)Me).Message((MessageType)1, $"+{exp} experience", 0, (Sprite)null, false);
			}
		}

		private static void SetSleeping_Postfix(Player __instance, bool sleep)
		{
			if (!sleep && Active && !((Object)(object)__instance != (Object)(object)Me))
			{
				Avatar mine = Mine;
				int num = mine.LevelUp(random);
				if (num >= 0)
				{
					mine.Save(Me.m_customData);
					Me.SetMaxHealth((float)mine.MaxHitPoints * 10f, true);
					((Character)Me).SetHealth((float)mine.MaxHitPoints * 10f);
					((Character)Me).Message((MessageType)2, Plugin.U5.Ovl.CStr(30544).Trim() + "\n" + Avatar.LevelUpWords(Plugin.U5.Ovl, Me.GetPlayerName(), mine.Level, num), 0, (Sprite)null, false);
					Plugin.Log.LogInfo((object)$"{Me.GetPlayerName()} is now level {mine.Level}");
				}
			}
		}

		private static bool RaiseSkill_Prefix()
		{
			return !Active;
		}

		private static bool GetSkillLevel_Prefix(ref float __result)
		{
			if (!Active)
			{
				return true;
			}
			__result = 0f;
			return false;
		}

		private static bool Restful(int hash)
		{
			return Array.IndexOf(comfort, hash) >= 0;
		}

		private static void OnSpawned_Postfix(Player __instance)
		{
			if (Active && !((Object)(object)__instance != (Object)(object)Me))
			{
				int[] array = comfort;
				foreach (int num in array)
				{
					((Character)__instance).GetSEMan().RemoveStatusEffect(num, false);
				}
			}
		}

		private static bool AddStatusEffectHash_Prefix(int nameHash, ref StatusEffect __result)
		{
			if (!Active || !Restful(nameHash))
			{
				return true;
			}
			__result = null;
			return false;
		}

		private static bool AddStatusEffect_Prefix(StatusEffect statusEffect, ref StatusEffect __result)
		{
			if (!Active || (Object)(object)statusEffect == (Object)null || !Restful(statusEffect.NameHash()))
			{
				return true;
			}
			__result = null;
			return false;
		}

		private static void SkillsSetup_Postfix(SkillsDialog __instance, Player player)
		{
			//IL_0266: Unknown result type (might be due to invalid IL or missing references)
			//IL_026b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0284: Unknown result type (might be due to invalid IL or missing references)
			//IL_029d: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_0412: Unknown result type (might be due to invalid IL or missing references)
			//IL_0418: Unknown result type (might be due to invalid IL or missing references)
			if (!Active || (Object)(object)player != (Object)(object)Me)
			{
				return;
			}
			List<GameObject> value = Traverse.Create((object)__instance).Field("m_elements").GetValue<List<GameObject>>();
			if (value == null)
			{
				return;
			}
			Avatar mine = Mine;
			int num = KarmaDeeds.Of(player);
			int num2 = ((mine.Level >= 8) ? mine.Experience : (100 << mine.Level - 1));
			(string, string, float, string)[] array = new(string, string, float, string)[8]
			{
				("Strength", mine.Strength.ToString(), (float)mine.Strength / 30f, "Ultima strength (up to 30)"),
				("Dexterity", mine.Dexterity.ToString(), (float)mine.Dexterity / 30f, "Ultima dexterity (up to 30)"),
				("Intelligence", mine.Intelligence.ToString(), (float)mine.Intelligence / 30f, "Ultima intelligence (up to 30)"),
				("Magic", mine.Mana.ToString(), (mine.Intelligence > 0) ? ((float)mine.Mana / (float)mine.Intelligence) : 0f, "Mana for spells"),
				("Hit points", $"{Mathf.CeilToInt(((Character)player).GetHealth() / 10f)}/{mine.MaxHitPoints}", ((Character)player).GetHealth() / Mathf.Max(1f, (float)mine.MaxHitPoints * 10f), "30 a level"),
				("Level", mine.Level.ToString(), (float)mine.Level / 8f, "Lord British's apparition raises it when thou sleepest, once thy deeds have earned it"),
				("Experience", mine.Experience.ToString(), (num2 > 0) ? Mathf.Clamp01((float)mine.Experience / (float)num2) : 1f, (mine.Level >= 8) ? "" : $"Level {mine.Level + 1} at {num2}"),
				("Karma", num.ToString(), (float)num / 99f, KarmaDeeds.WearsAnkh(player) ? $"Thy virtue (the Ankh: +{10})" : "Thy virtue")
			};
			while (value.Count < array.Length)
			{
				GameObject val = Object.Instantiate<GameObject>(__instance.m_elementPrefab, Vector3.zero, Quaternion.identity, (Transform)(object)__instance.m_listRoot);
				((RectTransform)val.transform).anchoredPosition = new Vector2(0f, (float)(-value.Count) * __instance.m_spacing);
				value.Add(val);
			}
			RectTransform listRoot = __instance.m_listRoot;
			Rect rect = __instance.m_listRoot.rect;
			listRoot.SetSizeWithCurrentAnchors((Axis)1, Mathf.Max(((Rect)(ref rect)).height, (float)array.Length * __instance.m_spacing));
			for (int i = 0; i < value.Count; i++)
			{
				GameObject val2 = value[i];
				if (i >= array.Length)
				{
					val2.SetActive(false);
					continue;
				}
				val2.SetActive(true);
				var (text, text2, value2, text3) = array[i];
				((Component)Utils.FindChild(val2.transform, "name", (IterativeSearchType)0)).GetComponent<TMP_Text>().text = text;
				((Component)Utils.FindChild(val2.transform, "leveltext", (IterativeSearchType)0)).GetComponent<TMP_Text>().text = text2;
				((Component)Utils.FindChild(val2.transform, "bonustext", (IterativeSearchType)0)).gameObject.SetActive(false);
				((Component)Utils.FindChild(val2.transform, "levelbar_total", (IterativeSearchType)0)).GetComponent<GuiBar>().SetValue(value2);
				((Component)Utils.FindChild(val2.transform, "levelbar", (IterativeSearchType)0)).GetComponent<GuiBar>().SetValue(value2);
				((Component)Utils.FindChild(val2.transform, "currentlevel", (IterativeSearchType)0)).GetComponent<GuiBar>().SetValue(0f);
				UITooltip componentInChildren = val2.GetComponentInChildren<UITooltip>();
				if (componentInChildren != null)
				{
					componentInChildren.Set(text, text3, __instance.m_tooltipAnchor, default(Vector2));
				}
			}
			__instance.m_totalSkillText.text = $"<color=orange>Level {mine.Level}</color>";
		}
	}
	public static class Ballistas
	{
		public const string BoltName = "u5_explosive_bolt";

		public const string ProjectileName = "u5_explosive_bolt_projectile";

		public const float BoltDamage = 400f;

		private const float BlastRadius = 4f;

		internal static Character firing;

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Create;
		}

		private static void Create()
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Create;
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("u5_explosive_bolt_projectile", "Turret_projectile");
			GameObject val2 = PrefabManager.Instance.CreateClonedPrefab("u5_explosive_bolt", "TurretBolt");
			GameObject prefab = PrefabManager.Instance.GetPrefab("fx_siegebomb_explosion");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				Plugin.Log.LogError((object)"Ballistas: no Turret_projectile/TurretBolt to make explosive bolts from");
				return;
			}
			Projectile component = val.GetComponent<Projectile>();
			component.m_aoe = 4f;
			component.m_respawnItemOnHit = false;
			if ((Object)(object)prefab != (Object)null)
			{
				component.m_hitEffects.m_effectPrefabs = ((IEnumerable<EffectData>)(((object)component.m_hitEffects.m_effectPrefabs) ?? ((object)new EffectData[0]))).Concat((IEnumerable<EffectData>)(object)new EffectData[1]
				{
					new EffectData
					{
						m_prefab = prefab,
						m_enabled = true
					}
				}).ToArray();
			}
			SharedData shared = val2.GetComponent<ItemDrop>().m_itemData.m_shared;
			shared.m_name = "Explosive bolt";
			shared.m_attack.m_attackProjectile = val;
			shared.m_damages = new DamageTypes
			{
				m_damage = 400f
			};
			ItemManager.Instance.AddItem(new CustomItem(val2, false));
		}

		public static void Install(Harmony harmony)
		{
			Patch(harmony, "UpdateTarget", "UpdateTarget_Prefix");
			Patch(harmony, "Interact", "Interact_Prefix");
			Patch(harmony, "UseItem", "UseItem_Prefix");
			Patch(harmony, "GetHoverText", "GetHoverText_Prefix");
			Patch(harmony, "ShootProjectile", null, "ShootProjectile_Postfix");
		}

		private static void Patch(Harmony h, string m, string prefix = null, string postfix = null)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0062: Unknown result type (might be due to invalid IL or missing references)
			MethodInfo methodInfo = AccessTools.Method(typeof(Turret), m, (Type[])null, (Type[])null);
			if (methodInfo == null)
			{
				Plugin.Log.LogWarning((object)("Ballistas: Turret." + m + " not found"));
			}
			else
			{
				h.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Ballistas), prefix, (Type[])null), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(typeof(Ballistas), postfix, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
		}

		private static bool UpdateTarget_Prefix(Turret __instance)
		{
			TownBallista component = ((Component)__instance).GetComponent<TownBallista>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			component.Aim();
			return false;
		}

		private static bool Interact_Prefix(Turret __instance, Humanoid character, bool hold, ref bool __result)
		{
			TownBallista component = ((Component)__instance).GetComponent<TownBallista>();
			if ((Object)(object)component == (Object)null)
			{
				return true;
			}
			int num;
			if (!hold)
			{
				Player val = (Player)(object)((character is Player) ? character : null);
				if (val != null)
				{
					num = (component.PlayerFires(val) ? 1 : 0);
					goto IL_002a;
				}
			}
			num = 0;
			goto IL_002a;
			IL_002a:
			__result = (byte)num != 0;
			return false;
		}

		private static bool UseItem_Prefix(Turret __instance, ref bool __result)
		{
			if ((Object)(object)((Component)__instance).GetComponent<TownBallista>() == (Object)null)
			{
				return true;
			}
			__result = false;
			return false;
		}

		private static bool GetHoverText_Prefix(Turret __instance, ref string __result)
		{
			if ((Object)(object)((Component)__instance).GetComponent<TownBallista>() == (Object)null)
			{
				return true;
			}
			__result = Localization.instance.Localize("Ballista\n[<color=yellow><b>$KEY_Use</b></color>] Fire");
			return false;
		}

		private static void ShootProjectile_Postfix(Turret __instance)
		{
			TownBallista component = ((Component)__instance).GetComponent<TownBallista>();
			if (!((Object)(object)component == (Object)null))
			{
				GameObject value = Traverse.Create((object)__instance).Field("m_lastProjectile").GetValue<GameObject>();
				Projectile val = (((Object)(object)value != (Object)null) ? value.GetComponent<Projectile>() : null);
				Character val2 = firing ?? component.CrewBody;
				if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
				{
					Traverse.Create((object)val).Field("m_owner").SetValue((object)val2);
				}
			}
		}
	}
	public class TownBallista : MonoBehaviour
	{
		private const float Range = 50f;

		private const float Arc = 60f;

		private const float ManFor = 15f;

		private const float CheckEvery = 0.5f;

		private const float CrewBehind = 1.6f;

		private static readonly int SightMask = LayerMask.GetMask(new string[5] { "Default", "static_solid", "Default_small", "piece", "terrain" });

		private Turret turret;

		private ZNetView nview;

		private Settlements.Built town;

		private TownNpc crew;

		private Character target;

		private float checkAt;

		private float seenAt = -100f;

		public Character CrewBody
		{
			get
			{
				if (!((Object)(object)crew != (Object)null))
				{
					return null;
				}
				return ((Component)crew).GetComponent<Character>();
			}
		}

		private bool Manned
		{
			get
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_002c: Unknown result type (might be due to invalid IL or missing references)
				if ((Object)(object)crew != (Object)null && !crew.IsDead)
				{
					return Vector3.Distance(((Component)crew).transform.position, CrewSpot) < 2.5f;
				}
				return false;
			}
		}

		private Vector3 CrewSpot => ((Component)this).transform.position - ((Component)this).transform.forward * 1.6f + Vector3.up * 0.1f;

		private Settlements.Built Town
		{
			get
			{
				//IL_001c: Unknown result type (might be due to invalid IL or missing references)
				//IL_0021: Unknown result type (might be due to invalid IL or missing references)
				if (town != null)
				{
					return town;
				}
				Vector3 p = ((Component)this).transform.position;
				return town = Settlements.All.FirstOrDefault((Settlements.Built b) => Mathf.Max(Mathf.Abs(p.x - b.Origin.x), Mathf.Abs(p.z - b.Origin.z)) < b.Site.Half + 1f);
			}
		}

		private void Awake()
		{
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			turret = ((Component)this).GetComponent<Turret>();
			nview = ((Component)this).GetComponent<ZNetView>();
			ZNetScene instance = ZNetScene.instance;
			object obj;
			if (instance == null)
			{
				obj = null;
			}
			else
			{
				GameObject prefab = instance.GetPrefab("u5_explosive_bolt");
				obj = ((prefab != null) ? prefab.GetComponent<ItemDrop>() : null);
			}
			ItemDrop val = (ItemDrop)obj;
			if ((Object)(object)val != (Object)null)
			{
				turret.m_defaultAmmo = val;
				AmmoType val2 = ((IEnumerable<AmmoType>)turret.m_allowedAmmo).FirstOrDefault((Func<AmmoType, bool>)((AmmoType a) => (Object)(object)a.m_ammo != (Object)null && ((Object)a.m_ammo).name == "TurretBolt"));
				if ((Object)(object)val2.m_visual != (Object)null)
				{
					turret.m_allowedAmmo.Add(new AmmoType
					{
						m_ammo = val,
						m_visual = val2.m_visual
					});
				}
			}
			turret.m_maxAmmo = 0;
			turret.m_viewDistance = 50f;
			turret.m_horizontalAngle = 60f;
			turret.m_targetPlayers = false;
			turret.m_targetTamed = false;
		}

		private void Update()
		{
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nview == (Object)null || nview.GetZDO() == null || !nview.IsOwner() || Time.time < checkAt)
			{
				return;
			}
			checkAt = Time.time + 0.5f;
			target = Spot();
			if ((Object)(object)target != (Object)null)
			{
				seenAt = Time.time;
				if (((Object)(object)crew == (Object)null || crew.IsDead) && Town != null)
				{
					Settlements.Built b = Town;
					Vector3 crewSpot = CrewSpot;
					Quaternion rotation = ((Component)this).transform.rotation;
					crew = TownsfolkSpawner.SpawnCrew(b, crewSpot, ((Quaternion)(ref rotation)).eulerAngles.y, this);
					if ((Object)(object)crew != (Object)null)
					{
						Plugin.Log.LogInfo((object)(Town.Location.Name + ": a guard mans the ballista against " + target.m_name));
					}
				}
			}
			else if ((Object)(object)crew != (Object)null && Time.time - seenAt > 15f)
			{
				Dismiss();
			}
		}

		private void OnDestroy()
		{
			Dismiss();
		}

		private void Dismiss()
		{
			if ((Object)(object)crew != (Object)null)
			{
				ZNetView component = ((Component)crew).GetComponent<ZNetView>();
				if (((component != null) ? component.GetZDO() : null) != null && crew.IsOwned)
				{
					ZNetScene.instance.Destroy(((Component)crew).gameObject);
				}
			}
			crew = null;
		}

		private Character Spot()
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Unknown result type (might be due to invalid IL or missing references)
			//IL_0122: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Invalid comparison between Unknown and I4
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = (((Object)(object)turret.m_eye != (Object)null) ? turret.m_eye.transform.position : (((Component)this).transform.position + Vector3.up * 1.5f));
			Character result = null;
			float num = 50f;
			Vector3 val3 = default(Vector3);
			foreach (Character allCharacter in Character.GetAllCharacters())
			{
				if ((Object)(object)allCharacter == (Object)null || allCharacter.IsPlayer() || allCharacter.IsDead() || allCharacter.IsTamed() || (Object)(object)((Component)allCharacter).GetComponent<TownNpc>() != (Object)null || (Object)(object)((Component)allCharacter).GetComponent<CreatureTalker>() != (Object)null || ResidentMonster.Is(allCharacter) || (UltimaCreatures.Of(allCharacter) == null && ((Object)(object)allCharacter.GetBaseAI() == (Object)null || (int)allCharacter.GetFaction() == 1 || (int)allCharacter.GetFaction() == 0)))
				{
					continue;
				}
				Vector3 val2 = allCharacter.GetCenterPoint() - val;
				float magnitude = ((Vector3)(ref val2)).magnitude;
				if (!(magnitude >= num))
				{
					((Vector3)(ref val3))..ctor(val2.x, 0f, val2.z);
					if (!(Vector3.Angle(((Component)this).transform.forward, val3) > 60f) && !Blocked(val, allCharacter.GetCenterPoint()))
					{
						result = allCharacter;
						num = magnitude;
					}
				}
			}
			return result;
		}

		private bool Blocked(Vector3 from, Vector3 to)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_0020: 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)
			RaycastHit[] array = Physics.RaycastAll(from, to - from, Vector3.Distance(from, to), SightMask);
			for (int i = 0; i < array.Length; i++)
			{
				RaycastHit val = array[i];
				if (!((Component)((RaycastHit)(ref val)).collider).transform.IsChildOf(((Component)this).transform))
				{
					return true;
				}
			}
			return false;
		}

		public void Aim()
		{
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)nview == (Object)null) && nview.IsValid() && nview.IsOwner())
			{
				Character val = ((Manned && (Object)(object)target != (Object)null && !target.IsDead()) ? target : null);
				Character value = Traverse.Create((object)turret).Field("m_target").GetValue<Character>();
				if (!((Object)(object)val == (Object)(object)value))
				{
					nview.InvokeRPC(ZNetView.Everybody, "RPC_SetTarget", new object[1] { ((Object)(object)val != (Object)null) ? val.GetZDOID() : ZDOID.None });
				}
			}
		}

		public bool PlayerFires(Player player)
		{
			if (turret.IsCoolingDown())
			{
				return false;
			}
			nview.ClaimOwnership();
			Ballistas.firing = (Character)(object)player;
			try
			{
				turret.ShootProjectile();
			}
			finally
			{
				Ballistas.firing = null;
			}
			((Character)player).Message((MessageType)2, Plugin.U5.Ovl.CStr(17138).Trim(), 0, (Sprite)null, false);
			if (Town != null)
			{
				Crime.Commit(player, Town);
			}
			return true;
		}
	}
	public static class BigInventory
	{
		private static int visible = 4;

		private static int first;

		private static Text rowsText;

		private static readonly FieldRef<InventoryGrid, List<InventoryElement>> Elements = AccessTools.FieldRefAccess<InventoryGrid, List<InventoryElement>>("m_elements");

		private static readonly FieldRef<InventoryGrid, Vector2i> Selected = AccessTools.FieldRefAccess<InventoryGrid, Vector2i>("m_selected");

		private static readonly Dictionary<InventoryElement, Vector2> placed = new Dictionary<InventoryElement, Vector2>();

		public static void Install(Harmony harmony)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Expected O, but got Unknown
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Expected O, but got Unknown
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Expected O, but got Unknown
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_0152: Expected O, but got Unknown
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			//IL_0196: Expected O, but got Unknown
			//IL_01cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_01da: Expected O, but got Unknown
			MethodInfo methodInfo = AccessTools.Method(typeof(Player), "OnSpawned", (Type[])null, (Type[])null);
			if (methodInfo != null)
			{
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(BigInventory), "OnSpawned_Postfix", (Type[])null)
				{
					priority = 800
				}, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo2 = AccessTools.Method(typeof(Player), "SetInventorySize", (Type[])null, (Type[])null);
			if (methodInfo2 != null)
			{
				harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(typeof(BigInventory), "SetInventorySize_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo3 = AccessTools.Method(typeof(Humanoid), "DropInvalidItems", (Type[])null, (Type[])null);
			if (methodInfo3 != null)
			{
				harmony.Patch((MethodBase)methodInfo3, new HarmonyMethod(typeof(BigInventory), "DropInvalidItems_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo4 = AccessTools.Method(typeof(Humanoid), "DrainEquipedItemDurability", (Type[])null, (Type[])null);
			if (methodInfo4 != null)
			{
				harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeof(BigInventory), "Drain_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo5 = AccessTools.Method(typeof(Inventory), "FindEmptySlot", (Type[])null, (Type[])null);
			if (methodInfo5 != null)
			{
				harmony.Patch((MethodBase)methodInfo5, new HarmonyMethod(typeof(BigInventory), "FindEmptySlot_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo6 = AccessTools.Method(typeof(InventoryGui), "Show", (Type[])null, (Type[])null);
			if (methodInfo6 != null)
			{
				harmony.Patch((MethodBase)methodInfo6, (HarmonyMethod)null, new HarmonyMethod(typeof(BigInventory), "Show_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			MethodInfo methodInfo7 = AccessTools.Method(typeof(InventoryGrid), "UpdateInventory", (Type[])null, (Type[])null);
			if (methodInfo7 != null)
			{
				harmony.Patch((MethodBase)methodInfo7, (HarmonyMethod)null, new HarmonyMethod(typeof(BigInventory), "UpdateInventory_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || methodInfo6 == null || methodInfo7 == null)
			{
				Plugin.Log.LogWarning((object)"Inventory: Player.OnSpawned / SetInventorySize, Humanoid.DropInvalidItems / DrainEquipedItemDurability, InventoryGui.Show or InventoryGrid.UpdateInventory not found");
			}
		}

		private static void OnSpawned_Postfix(Player __instance)
		{
			if (!((Object)(object)__instance != (Object)(object)Player.m_localPlayer))
			{
				Apply(__instance);
				PouchPanel.Migrate(__instance);
			}
		}

		private static void SetInventorySize_Postfix(Player __instance)
		{
			if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer)
			{
				Apply(__instance);
			}
		}

		private static int VanillaRows(Player p)
		{
			string s = default(string);
			if (!p.TryGetUniqueKeyValue("invrows", ref s) || !int.TryParse(s, out var result))
			{
				return 4;
			}
			return Mathf.Clamp(result, 1, 9);
		}

		public static void Apply(Player p)
		{
			Inventory inventory = ((Humanoid)p).GetInventory();
			int vanillaRows = VanillaRows(p);
			int num = InventorySize.RowsFor(Britannia.Active != null, vanillaRows, from i in inventory.GetAllItems()
				select i.m_gridPos.y);
			if (num != inventory.GetHeight())
			{
				inventory.SetHeight(num);
				Plugin.Log.LogInfo((object)string.Format("Inventory: {0} × {1} slots{2}", inventory.GetWidth(), num, (Britannia.Active != null) ? " (Britannia)" : ""));
			}
			InventoryGui instance = InventoryGui.instance;
			if (!((Object)(object)instance == (Object)null))
			{
				visible = InventorySize.VisibleFor(num, vanillaRows);
				instance.SetInventorySize(visible);
			}
		}

		private static void DropInvalidItems_Prefix(Humanoid __instance)
		{
			Player val = (Player)(object)((__instance is Player) ? __instance : null);
			if (val != null)
			{
				Inventory inventory = ((Humanoid)val).GetInventory();
				int num = (from i in inventory.GetAllItems()
					select i.m_gridPos.y + 1).DefaultIfEmpty(0).Max();
				if (num > inventory.GetHeight())
				{
					inventory.SetHeight(num);
				}
			}
		}

		private static bool Drain_Prefix(Humanoid __instance, ItemData item, float dt)
		{
			if (item == null || item.m_stack <= 1 || (Object)(object)item.m_dropPrefab == (Object)null || UltimaItems.Map.Get(((Object)item.m_dropPrefab).name) == null)
			{
				return true;
			}
			if (item.m_durability - item.m_shared.m_durabilityDrain * dt * Game.m_durabilityRate > 0f)
			{
				return true;
			}
			item.m_stack--;
			item.m_durability = item.GetMaxDurability();
			((Character)__instance).Message((MessageType)1, Localization.instance.Localize("$msg_broke", new string[1] { item.m_shared.m_name }), 0, item.GetIcon(), false);
			__instance.GetInventory().m_onChanged?.Invoke();
			return false;
		}

		private static bool FindEmptySlot_Prefix(Inventory __instance, bool topFirst, ref Vector2i __result)
		{
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: 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)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			Player localPlayer = Player.m_localPlayer;
			if (topFirst || (Object)(object)localPlayer == (Object)null || __instance != ((Humanoid)localPlayer).GetInventory() || __instance.GetHeight() <= 6)
			{
				return true;
			}
			int width = __instance.GetWidth();
			int height = __instance.GetHeight();
			for (int i = 1; i <= height; i++)
			{
				int num = i % height;
				for (int j = 0; j < width; j++)
				{
					if (__instance.GetItemAt(j, num) == null)
					{
						__result = new Vector2i(j, num);
						return false;
					}
				}
			}
			__result = new Vector2i(-1, -1);
			return false;
		}

		private static void Show_Postfix(InventoryGui __instance)
		{
			Player localPlayer = Player.m_localPlayer;
			if ((Object)(object)localPlayer != (Object)null)
			{
				Apply(localPlayer);
			}
		}

		public static void ScrollTo(int row)
		{
			first = row;
		}

		private static void UpdateInventory_Postfix(InventoryGrid __instance, Inventory inventory, Player player)
		{
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0119: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_017d: Unknown result type (might be due to invalid IL or missing references)
			//IL_017e: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0243: Unknown result type (might be due to invalid IL or missing references)
			//IL_0252: Unknown result type (might be due to invalid IL or missing references)
			//IL_0261: Unknown result type (might be due to invalid IL or missing references)
			//IL_0271: Unknown result type (might be due to invalid IL or missing references)
			//IL_0277: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
			InventoryGui instance = InventoryGui.instance;
			if ((Object)(object)instance == (Object)null || (Object)(object)__instance != (Object)(object)instance.m_playerGrid || (Object)(object)player == (Object)null || inventory == null)
			{
				return;
			}
			int height = inventory.GetHeight();
			int num = Mathf.Min(visible, height);
			Transform transform = ((Component)__instance).transform;
			RectTransform val = (RectTransform)(object)((transform is RectTransform) ? transform : null);
			float elementSpace = __instance.m_elementSpace;
			if (height > num)
			{
				Vector3 pointerPosition = ZInput.pointerPosition;
				Rect rect = val.rect;
				if (((Rect)(ref rect)).Contains(((Transform)val).InverseTransformPoint(pointerPosition)))
				{
					float mouseScrollWheel = ZInput.GetMouseScrollWheel();
					if (mouseScrollWheel < 0f)
					{
						first++;
					}
					else if (mouseScrollWheel > 0f)
					{
						first--;
					}
				}
				if (ZInput.IsGamepadActive())
				{
					int y = Selected.Invoke(__instance).y;
					if (y < first)
					{
						first = y;
					}
					else if (y >= first + num)
					{
						first = y - num + 1;
					}
				}
			}
			first = Mathf.Clamp(first, 0, height - num);
			RectTransform gridRoot = __instance.m_gridRoot;
			gridRoot.anchoredPosition = new Vector2(gridRoot.anchoredPosition.x, (float)first * elementSpace);
			foreach (InventoryElement item in Elements.Invoke(__instance))
			{
				if (!((Object)(object)item == (Object)null))
				{
					Transform transform2 = ((Component)item).transform;
					RectTransform val2 = (RectTransform)(object)((transform2 is RectTransform) ? transform2 : null);
					if (!placed.TryGetValue(item, out var value))
					{
						value = (placed[item] = val2.anchoredPosition);
					}
					bool flag = item.Position.y >= first && item.Position.y < first + num;
					if (((Component)item).gameObject.activeSelf != flag)
					{
						((Component)item).gameObject.SetActive(flag);
					}
					val2.anchoredPosition = (flag ? value : (value + new Vector2(100000f, 0f)));
				}
			}
			if (height > num && (Object)(object)rowsText == (Object)null)
			{
				GUIManager instance2 = GUIManager.Instance;
				rowsText = instance2.CreateText("", (Transform)(object)instance.m_player, new Vector2(1f, 0f), new Vector2(1f, 0f), new Vector2(-120f, -14f), instance2.AveriaSerifBold, 15, instance2.ValheimOrange, true, Color.black, 240f, 24f, false).GetComponent<Text>();
				rowsText.alignment = (TextAnchor)5;
			}
			if (!((Object)(object)rowsText == (Object)null))
			{
				((Component)rowsText).gameObject.SetActive(height > num);
				rowsText.text = $"rows {first + 1}–{first + num} of {height} (mouse wheel)";
			}
		}
	}
	public static class BiomeBlend
	{
		private const float Step = 4f;

		private const int Radius = 2;

		private static readonly List<Color32> colours = new List<Color32>();

		public static void Install(Harmony harmony)
		{
			//IL_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a2: Expected O, but got Unknown
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c3: Expected O, but got Unknown
			try
			{
				MethodInfo methodInfo = AccessTools.Method(typeof(Heightmap), "RebuildRenderMesh", (Type[])null, (Type[])null) ?? throw new MissingMethodException("Heightmap", "RebuildRenderMesh");
				MethodInfo methodInfo2 = AccessTools.Method(typeof(Heightmap), "GetBiome", new Type[3]
				{
					typeof(Vector3),
					typeof(float),
					typeof(bool)
				}, (Type[])null) ?? throw new MissingMethodException("Heightmap", "GetBiome");
				harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(BiomeBlend), "RebuildRenderMesh_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
				harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeof(BiomeBlend), "GetBiome_Prefix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Soft biome borders not installed: " + ex.Message));
			}
		}

		private static bool GetBiome_Prefix(Vector3 point, ref Biome __result)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			if (Britannia.Active == null)
			{
				return true;
			}
			__result = (Biome)Britannia.ShapeAt(point.x, point.z).Biome(point.x, point.z);
			return false;
		}

		private static void RebuildRenderMesh_Postfix(Heightmap __instance, Mesh ___m_renderMesh, int ___m_width, float ___m_scale, bool ___m_isDistantLod)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_008e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_016e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0187: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01b7: Unknown result type (might be due to invalid IL or missing references)
			if (Britannia.Active == null || ___m_isDistantLod || (Object)(object)___m_renderMesh == (Object)null)
			{
				return;
			}
			BritanniaShape britanniaShape = Britannia.ShapeAt(((Component)__instance).transform.position);
			float num = (float)___m_width * ___m_scale;
			Vector3 val = ((Component)__instance).transform.position - new Vector3(num / 2f, 0f, num / 2f);
			int num2 = Mathf.CeilToInt(num / 4f) + 1 + 4;
			Color[] array = (Color[])(object)new Color[num2 * num2];
			for (int i = 0; i < num2; i++)
			{
				for (int j = 0; j < num2; j++)
				{
					Biome val2 = (Biome)britanniaShape.Biome(val.x + (float)(j - 2) * 4f, val.z + (float)(i - 2) * 4f);
					array[i * num2 + j] = Color32.op_Implicit(Heightmap.GetBiomeColor(val2));
				}
			}
			array = Box(Box(array, num2, 1, 0), num2, 0, 1);
			int num3 = ___m_width + 1;
			colours.Clear();
			for (int k = 0; k < num3; k++)
			{
				for (int l = 0; l < num3; l++)
				{
					float num4 = (float)l * ___m_scale / 4f + 2f;
					float num5 = (float)k * ___m_scale / 4f + 2f;
					int num6 = Mathf.Min((int)num4, num2 - 2);
					int num7 = Mathf.Min((int)num5, num2 - 2);
					float num8 = num4 - (float)num6;
					float num9 = num5 - (float)num7;
					Color val3 = Color.Lerp(array[num7 * num2 + num6], array[num7 * num2 + num6 + 1], num8);
					Color val4 = Color.Lerp(array[(num7 + 1) * num2 + num6], array[(num7 + 1) * num2 + num6 + 1], num8);
					colours.Add(Color32.op_Implicit(Color.Lerp(val3, val4, num9)));
				}
			}
			if (colours.Count == ___m_renderMesh.vertexCount)
			{
				___m_renderMesh.SetColors(colours);
			}
		}

		private static Color[] Box(Color[] src, int g, int dx, int dy)
		{
			//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_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			Color[] array = (Color[])(object)new Color[src.Length];
			for (int i = 0; i < g; i++)
			{
				for (int j = 0; j < g; j++)
				{
					Color val = Color.clear;
					for (int k = -2; k <= 2; k++)
					{
						int num = Mathf.Clamp(j + k * dx, 0, g - 1);
						int num2 = Mathf.Clamp(i + k * dy, 0, g - 1);
						val += src[num2 * g + num];
					}
					array[i * g + j] = val / 5f;
				}
			}
			return array;
		}
	}
	public class BlackthornGuards : MonoBehaviour
	{
		private const float Reach = 3f;

		private const float Again = 30f;

		private float checkAt;

		private float askedAt = -999f;

		private bool passed;

		private void Update()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0054: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			if (Time.time < checkAt)
			{
				return;
			}
			checkAt = Time.time + 0.5f;
			Player localPlayer = Player.m_localPlayer;
			Settlements.Built built = Settlements.Get(18);
			if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead() || built == null || Britannia.Active == null)
			{
				return;
			}
			Vector3 position = ((Component)localPlayer).transform.position;
			if (!(Mathf.Max(Mathf.Abs(position.x - built.Origin.x), Mathf.Abs(position.z - built.Origin.z)) < built.Site.Half + built.Site.Blend))
			{
				passed = false;
			}
			else
			{
				if (passed || TalkPanel.IsOpen || Crime.WantedBy(localPlayer) != 0 || Crime.HostileTo(localPlayer) != 0 || Time.time - askedAt < 30f)
				{
					return;
				}
				foreach (Character allCharacter in Character.GetAllCharacters())
				{
					TownNpc townNpc = TownsfolkPatches.NpcOf(allCharacter);
					if (!((Object)(object)townNpc == (Object)null) && townNpc.IsGuard && !townNpc.IsDead && townNpc.Location == 18 && !(Vector3.Distance(((Component)allCharacter).transform.position, position) > 3f))
					{
						askedAt = Time.time;
						Challenge(localPlayer, townNpc, built);
						break;
					}
				}
			}
		}

		private void Challenge(Player me, TownNpc guard, Settlements.Built palace)
		{
			DataOvl ovl = Plugin.U5.Ovl;
			bool flag = (WornEffects.Bits(me) & 8) != 0;
			Plugin.Log.LogInfo((object)$"Blackthorn's guard challenges {me.GetPlayerName()} (badge {flag})");
			if (!flag)
			{
				Crime.Commit(me, palace);
				return;
			}
			string question = "\"" + ovl.CStr(37116).Replace("\n", " ").Trim() + "\"";
			TalkPanel.AskTyped(guard, guard.GetHoverName(), question, "Your response", delegate(string answer)
			{
				if (ItemUse.PasswordMatches(ovl, answer))
				{
					passed = true;
					TalkPanel.Tell("\"" + ovl.CStr(37178).Trim() + "\"");
					Plugin.Log.LogInfo((object)(me.GetPlayerName() + " gave Blackthorn's password"));
				}
				else
				{
					TalkPanel.Close();
					Crime.Commit(me, palace);
				}
			});
		}
	}
	public static class Bridges
	{
		private static Type clearAreaType;

		private static BritanniaShape planned;

		private static List<(Vector3 centre, List<Placement> pieces)> bridges = new List<(Vector3, List<Placement>)>();

		public static void Install(Harmony harmony)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Expected O, but got Unknown
			try
			{
				clearAreaType = AccessTools.Inner(typeof(ZoneSystem), "ClearArea") ?? throw new MissingMemberException("ZoneSystem", "ClearArea");
				harmony.Patch((MethodBase)(AccessTools.Method(typeof(ZoneSystem), "PlaceLocations", (Type[])null, (Type[])null) ?? throw new MissingMethodException("ZoneSystem", "PlaceLocations")), (HarmonyMethod)null, new HarmonyMethod(typeof(Bridges), "PlaceLocations_Postfix", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Bridges not installed: " + ex.Message));
			}
		}

		public static List<(Vector3 centre, List<Placement> pieces)> All()
		{
			BritanniaShape shape = Britannia.Active;
			if (shape == null)
			{
				return new List<(Vector3, List<Placement>)>();
			}
			if (planned == shape)
			{
				return bridges;
			}
			planned = shape;
			bridges = BridgePlanner.Bridges(shape).Select(delegate((int x, int y, bool eastWest) b)
			{
				//IL_0024: Unknown result type (might be due to invalid IL or missing references)
				shape.TileCentre(b.x, b.y, out var wx, out var wz);
				return ((Vector3, List<Placement>))(new Vector3(wx, 30f, wz), BridgePlanner.Plan(shape, b.x, b.y, b.eastWest));
			}).ToList();
			Plugin.Log.LogInfo((object)$"Bridges: {bridges.Count} ({bridges.Sum(((Vector3 centre, List<Placement> pieces) b) => b.pieces.Count)} pieces)");
			return bridges;
		}

		private static void PlaceLocations_Postfix(Vector2s zoneID, IList clearAreas, SpawnMode mode, List<GameObject> spawnedObjects)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Invalid comparison between Unknown and I4
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Invalid comparison between Unknown and I4
			//IL_0225: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0171: Unknown result type (might be due to invalid IL or missing references)
			//IL_0155: Unknown result type (might be due to invalid IL or missing references)
			//IL_0176: Unknown result type (might be due to invalid IL or missing references)
			//IL_0188: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e8: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Invalid comparison between Unknown and I4
			//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
			if (Britannia.Active == null || ((int)mode != 0 && (int)mode != 2))
			{
				return;
			}
			foreach (var item in All())
			{
				var (centre, list) = item;
				if (ZoneSystem.GetZone(centre) != zoneID)
				{
					continue;
				}
				float num = list.Max((Placement p) => Mathf.Max(Mathf.Abs(p.X - centre.x), Mathf.Abs(p.Z - centre.z))) + 4f;
				clearAreas.Add(Activator.CreateInstance(clearAreaType, centre, num));
				int num2 = 0;
				foreach (Placement item2 in list)
				{
					GameObject prefab = ZNetScene.instance.GetPrefab(item2.Prefab);
					if ((Object)(object)prefab == (Object)null)
					{
						continue;
					}
					if ((int)mode == 2)
					{
						ZNetView.StartGhostInit();
					}
					Quaternion val = Quaternion.Euler(0f, item2.Yaw, 0f);
					if (item2.Turned)
					{
						val *= Quaternion.Euler(item2.Tilt, 0f, 0f);
					}
					GameObject val2 = Object.Instantiate<GameObject>(prefab, new Vector3(item2.X, 30f + item2.Y, item2.Z), val);
					Vector3 val3 = (Vector3)(item2.Scaled ? new Vector3(item2.SX, item2.SY, item2.SZ) : Vector3.zero);
					if (item2.Scaled)
					{
						val2.transform.localScale = val3;
					}
					ZNetView component = val2.GetComponent<ZNetView>();
					ZDO val4 = ((component != null) ? component.GetZDO() : null);
					if (val4 != null)
					{
						val4.Set("u5_fixed", true);
						if (item2.Scaled)
						{
							val4.Set("u5_scale", val3);
						}
						WearNTear component2 = val2.GetComponent<WearNTear>();
						if ((Object)(object)component2 != (Object)null)
						{
							FixedPieces.Apply(component2, val4);
						}
					}
					if ((int)mode == 2)
					{
						spawnedObjects.Add(val2);
						ZNetView.FinishGhostInit();
					}
					num2++;
				}
				Plugin.Log.LogInfo((object)$"Zone {zoneID}: a bridge of {num2} pieces at {centre}");
			}
		}
	}
	public static class Britannia
	{
		public const string SeedPrefix = "Britannia";

		public const float SeaLevel = 30f;

		private static BritanniaShape cached;

		private static BritanniaShape cachedUnder;

		private static int cachedSeed;

		private static float cachedTile;

		private static TerrainTable terrain;

		private static TerrainTable underTerrain;

		public static BritanniaShape Active { get; private set; }

		public static string Failure { get; private set; }

		public static List<Poi> Pois { get; private set; } = new List<Poi>();

		public static int Seed { get; private set; }

		public static BritanniaShape Under { get; private set; }

		public static BritanniaShape ShapeAt(float wx, float wz)
		{
			if (Under == null || !Continents.InUnderworld(wx, Under.TileMetres))
			{
				return Active;
			}
			return Under;
		}

		public static BritanniaShape ShapeAt(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			return ShapeAt(p.x, p.z);
		}

		public static bool InUnderworld(Vector3 p)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			if (Active != null && ShapeAt(p.x, p.z) == Under)
			{
				return Under != null;
			}
			return false;
		}

		public static BritanniaShape Level(int z)
		{
			if (z != 0)
			{
				return Under;
			}
			return Active;
		}

		public static Vector3 TileCentre(int tx, int ty, bool underworld)
		{
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			BritanniaShape britanniaShape = (underworld ? Under : Active);
			britanniaShape.TileCentre(tx, ty, out var wx, out var wz);
			return new Vector3(wx, 30f + britanniaShape.Height(wx, wz), wz);
		}

		public static (int x, int y, int z) Tile(Vector3 p)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			BritanniaShape britanniaShape = ShapeAt(p);
			britanniaShape.ToTile(p.x, p.z, out var u, out var v);
			return (x: (int)Math.Floor(u) & 0xFF, y: (int)Math.Floor(v) & 0xFF, z: (britanniaShape == Under) ? (-1) : 0);
		}

		public static bool IsBritanniaSeed(string seedName)
		{
			return seedName?.StartsWith("Britannia", StringComparison.OrdinalIgnoreCase) ?? false;
		}

		public static void Activate(World world)
		{
			ActivateWorld(world);
			RiverBanks.WorldChanged();
		}

		private static void ActivateWorld(World world)
		{
			Active = null;
			Under = null;
			Failure = null;
			if (world == null || world.m_menu || !IsBritanniaSeed(world.m_seedName))
			{
				return;
			}
			if (Plugin.U5 == null)
			{
				Fail("World '" + world.m_name + "' is a Britannia world but the Ultima V data is not loaded (set UltimaVDirectory and restart).");
				return;
			}
			try
			{
				float value = Plugin.TileMetres.Value;
				if (cached == null || cachedSeed != world.m_seed || cachedTile != value)
				{
					Stopwatch stopwatch = Stopwatch.StartNew();
					string json = File.ReadAllText(Path.Combine(Plugin.PluginDirectory, "mappings", "terrain.json"));
					terrain = terrain ?? TerrainTable.Parse(json);
					underTerrain = underTerrain ?? TerrainTable.Parse(json, underworld: true);
					cached = new BritanniaShape(Plugin.U5.Britannia, terrain, world.m_seed, value);
					cachedUnder = Continents.UnderworldShape(Plugin.U5.Underworld, underTerrain, world.m_seed, value);
					cachedSeed = world.m_seed;
					cachedTile = value;
					Plugin.Log.LogInfo((object)$"Britannia and Underworld terrain for seed '{world.m_seedName}' built in {stopwatch.ElapsedMilliseconds} ms");
				}
				Pois = Bretaheim.WorldGen.Core.Pois.Build(Plugin.U5);
				Settlements.Prepare(cached, cachedUnder, Pois);
				PlaceMarkers.Reset();
				Shrines.Reset();
				Seed = world.m_seed;
				Under = cachedUnder;
				Active = cached;
				Plugin.Log.LogInfo((object)$"World '{world.m_name}' is Britannia ({Pois.Count} places).");
			}
			catch (Exception ex)
			{
				Plugin.Log.LogError((object)ex.ToString());
				Fail("Could not build Britannia for '" + world.m_name + "': " + ex.Message);
			}
		}

		private static void Fail(string why)
		{
			Active = null;
			Under = null;
			Failure = why + " World generation is stopped so nothing vanilla is saved into it: quit Valheim completely and restart.";
			Plugin.Log.LogError((object)Failure);
		}

		public static Vector3 TileCentre(int tx, int ty)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			Active.TileCentre(tx, ty, out var wx, out var wz);
			return new Vector3(wx, 30f + Active.Height(wx, wz), wz);
		}

		public static Vector3 SpawnPoint()
		{
			//IL_0009: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			if (Settlements.TrySpawnPoint(out var pos))
			{
				return pos;
			}
			SaveGame initialGame = Plugin.U5.InitialGame;
			Location location = Plugin.U5.Location((initialGame.Location >= 1 && initialGame.Location <= 40) ? initialGame.Location : 13);
			return TileCentre(location.X, location.Y);
		}
	}
	public static class Calendar
	{
		private static UltimaDate? start;

		private static Moons moons;

		public static UltimaDate Start
		{
			get
			{
				if (!start.HasValue)
				{
					SaveGame saveGame = Plugin.U5?.InitialGame;
					start = ((saveGame != null) ? new UltimaDate(saveGame.Year, saveGame.Month, saveGame.Day, saveGame.Hour, saveGame.Minute) : new UltimaDate(139, 4, 5, 8, 35));
				}
				return start.Value;
			}
		}

		public static bool Running
		{
			get
			{
				if ((Object)(object)ZNet.instance != (Object)null)
				{
					return (Object)(object)EnvMan.instance != (Object)null;
				}
				return false;
			}
		}

		public static double Seconds
		{
			get
			{
				if (!((Object)(object)ZNet.instance != (Object)null))
				{
					return 0.0;
				}
				return ZNet.instance.GetTimeSeconds();
			}
		}

		public static double DayLength => ((Object)(object)EnvMan.instance != (Object)null && EnvMan.instance.m_dayLengthSec > 0) ? EnvMan.instance.m_dayLengthSec : 1800;

		public static UltimaDate Now
		{
			get
			{
				if (!Running)
				{
					return Start.WithTime(12, 0);
				}
				return UltimaCalendar.At(Start, Seconds, DayLength);
			}
		}

		public static int Hour => Now.Hour;

		public static int Minute => Now.Minute;

		public static long WorldDay
		{
			get
			{
				if (!Running)
				{
					return 0L;
				}
				return UltimaCalendar.WorldDay(Seconds, DayLength);
			}
		}

		public static Moons Moons => moons ?? (moons = Moons.Of(Plugin.U5.Ovl));

		public static double SecondsUntil(int hour)
		{
			return UltimaCalendar.NextHour(Seconds, DayLength, hour) - Seconds;
		}

		public static string Describe()
		{
			UltimaDate now = Now;
			return $"It is {now.TimeText} on {now.DateText} (day {WorldDay + 1} of this world). {Moons.Describe(now)}.";
		}
	}
	public static class WorldKeys
	{
		public static string Get(string name)
		{
			string result = default(string);
			if (!((Object)(object)ZoneSystem.instance != (Object)null) || !ZoneSystem.instance.GetGlobalKey(name, ref result))
			{
				return null;
			}
			return result;
		}

		public static void Set(string name, string value)
		{
			if (!((Object)(object)ZoneSystem.instance == (Object)null))
			{
				ZoneSystem.instance.SetGlobalKey(string.IsNullOrEmpty(value) ? name : (name + " " + value));
			}
		}
	}
	public static class ClockCommands
	{
		public static bool Run(string[] args, Action<string> print)
		{
			//IL_0178: Unknown result type (might be due to invalid IL or missing references)
			//IL_0183: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e3: Unknown result type (might be due to invalid IL or missing references)
			if (args.Length == 0)
			{
				return false;
			}
			switch (args[0])
			{
			case "time":
			case "date":
				print(Calendar.Describe());
				if (Britannia.Active != null)
				{
					print(Shadowlords.Describe());
				}
				return true;
			case "gates":
			case "moons":
			{
				print(Calendar.Describe());
				if (Britannia.Active == null)
				{
					return true;
				}
				Player localPlayer = Player.m_localPlayer;
				for (int i = 0; i < 8; i++)
				{
					MoonstoneSite moonstoneSite = Moongates.Site(i);
					Vector3? val = Moongates.Position(moonstoneSite);
					string text = ((val.HasValue && (Object)(object)localPlayer != (Object)null) ? $", {Vector3.Distance(val.Value, ((Component)localPlayer).transform.position):0} m away" : "");
					print(string.Format("moonstone {0}: {1}{2}{3}", i, moonstoneSite, val.HasValue ? $" at ({val.Value.x:0}, {val.Value.z:0})" : "", text));
				}
				return true;
			}
			case "dusk":
				return Skip(20, print);
			case "dawn":
				return Skip(5, print);
			case "midnight":
				return Skip(0, print);
			default:
				return false;
			}
		}

		private static bool Skip(int hour, Action<string> print)
		{
			if (!Calendar.Running)
			{
				print("no world is loaded");
				return true;
			}
			double num = Math.Ceiling(Calendar.SecondsUntil(hour)) + 1.0;
			if (!Terminal.m_cheat || !ZNet.instance.IsServer())
			{
				print($"{hour}:00 is {num:0} s away: type \"skiptime {num:0}\" (devcommands; an admin on a dedicated server)");
				return true;
			}
			ZNet.instance.SetNetTime(ZNet.instance.GetTimeSeconds() + num);
			print($"skipped {num:0} s: {Calendar.Describe()}");
			return true;
		}
	}
	public static class Camp
	{
		public class Keys : MonoBehaviour
		{
			private void Update()
			{
				if (ZInput.GetKeyDown((KeyCode)104, true) && Britannia.Active != null)
				{
					Player localPlayer = Player.m_localPlayer;
					if (!((Object)(object)localPlayer == (Object)null) && !Busy())
					{
						Pitch(localPlayer);
					}
				}
			}

			private static bool Busy()
			{
				if ((!((Object)(object)Chat.instance != (Object)null) || !Chat.instance.HasFocus()) && !Console.IsVisible() && !TextInput.IsVisible() && !Menu.IsVisible() && !InventoryGui.IsVisible() && !Minimap.IsOpen() && !TalkPanel.IsOpen && !StoreGui.IsVisible())
				{
					return GameCamera.InFreeFly();
				}
				return true;
			}
		}

		public const string LeanToName = "u5_leanto";

		public const string FirePrefab = "fire_pit";

		public const string CampKey = "u5_camp";

		private const float LeanToAhead = 1.5f;

		private const float FireAhead = 4.2f;

		private const float Off = 0.3f;

		private const int SHoleUp = 41666;

		private const int SCamp = 41734;

		public static void Register()
		{
			PrefabManager.OnVanillaPrefabsAvailable += Create;
		}

		private static void Create()
		{
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00df: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected O, but got Unknown
			PrefabManager.OnVanillaPrefabsAvailable -= Create;
			GameObject val = PrefabManager.Instance.CreateClonedPrefab("u5_leanto", "wood_roof_45");
			GameObject prefab = PrefabManager.Instance.GetPrefab("wood_pole2");
			if ((Object)(object)val == (Object)null || (Object)(object)prefab == (Object)null)
			{
				Plugin.Log.LogError((object)"Camp: no wood_roof_45/wood_pole2 to make a lean-to of");
				return;
			}
			Piece component = val.GetComponent<Piece>();
			if ((Object)(object)component != (Object)null)
			{
				component.m_name = "Lean-to";
			}
			float[] array = new float[2] { -0.9f, 0.9f };
			foreach (float num in array)
			{
				GameObject obj = Visual(prefab);
				obj.transform.SetParent(val.transform, false);
				obj.transform.localPosition = new Vector3(num, 0f, -0.85f);
			}
			GameObject val2 = new GameObject("attach");
			val2.transform.SetParent(val.transform, false);
			val2.transform.localPosition = new Vector3(0f, -0.8f, 0.1f);
			val2.transform.localRotation = Quaternion.Euler(0f, 180f, 0f);
			val.AddComponent<LeanTo>();
			PrefabManager.Instance.AddPrefab(new CustomPrefab(val, false));
		}

		private static GameObject Visual(GameObject prefab)
		{
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Expected O, but got Unknown
			GameObject val = new GameObject("u5_camp_holder");
			val.SetActive(false);
			GameObject val2 = Object.Instantiate<GameObject>(prefab, val.transform);
			for (int i = 0; i < 4; i++)
			{
				Component[] componentsInChildren = val2.GetComponentsInChildren<Component>(true);
				foreach (Component val3 in componentsInChildren)
				{
					if (val3 is MonoBehaviour || val3 is Rigidbody)
					{
						Object.DestroyImmediate((Object)(object)val3);
					}
				}
			}
			val2.transform.SetParent((Transform)null, false);
			Object.Destroy((Object)(object)val);
			val2.SetActive(true);
			return val2;
		}

		public static bool Near(Vector3 at, float within)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			return LeanTo.All.Any((LeanTo l) => (Object)(object)l != (Object)null && Vector3.Distance(((Component)l).transform.position, at) < within + 1.5f);
		}

		public static void Pitch(Player me)
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0056: 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_0088: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Unknown result type (might be due to invalid IL or missing references)
			//IL_0098: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: 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_00a4: Unknown result type (might be due to invalid IL