Decompiled source of AutoVerk v0.1.0

AutoVerk.dll

Decompiled 15 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text;
using AutoVerk.Engine;
using AutoVerk.Game;
using AutoVerk.Skills;
using AutoVerk.Skills.Basic;
using AutoVerk.Skills.Farm;
using AutoVerk.Ui;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.InputSystem.Utilities;
using UnityEngine.Rendering;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace AutoVerk
{
	[BepInPlugin("autoverk", "AutoVerk", "0.1.0")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	[BepInProcess("valheim")]
	public sealed class Plugin : BaseUnityPlugin
	{
		public const string Guid = "autoverk";

		public const string Name = "AutoVerk";

		public const string Version = "0.1.0";

		private const float RefreshSeconds = 0.25f;

		internal static ManualLogSource Log;

		private Harmony _harmony;

		private ConfigEntry<KeyboardShortcut> _windowKey;

		private ConfigEntry<string> _windowPosition;

		private ConfigEntry<string> _lastStart;

		private readonly Dictionary<string, ConfigEntry<bool>> _interruptions = new Dictionary<string, ConfigEntry<bool>>();

		private ConfigEntry<bool> _jumpWhenStuck;

		private SkillForm _form;

		private Window _window;

		private float _nextRefresh;

		private bool _closeOnNextFrame;

		private string _message;

		private Skill _pending;

		private bool _resumePending;

		private RunState _shownState;

		private bool _resultSeen;

		private string _previewText;

		public Runner Runner { get; private set; }

		private void Awake()
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_023a: Unknown result type (might be due to invalid IL or missing references)
			Log = ((BaseUnityPlugin)this).Logger;
			_windowKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("Window", "Key", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Opens and closes the window.");
			_windowPosition = ((BaseUnityPlugin)this).Config.Bind<string>("Window", "Position", "-20, -100", "The window's top-right corner, from the screen's top-right corner. Saved when you move it.");
			_lastStart = ((BaseUnityPlugin)this).Config.Bind<string>("Window", "LastStart", "", "The window's last start, as a console line. Filled in next time.");
			_jumpWhenStuck = ((BaseUnityPlugin)this).Config.Bind<bool>("Movement", "JumpWhenStuck", true, "Jump (twice) when stuck on the way before giving up. Off: give up at once.");
			MoveTo.JumpWhenStuck = _jumpWhenStuck.Value;
			Runner = new Runner(() => Time.timeAsDouble, delegate(string text)
			{
				Log.LogInfo((object)text);
			});
			Runner.Guards.Add(new PlayerGuard());
			Runner.Guards.Add(new HumanInputGuard(_windowKey));
			Runner.Guards.Add(new MenuGuard());
			Builtins.Register();
			Commands.Register(this);
			ApplyInterruptionSettings();
			_form = new SkillForm();
			_form.Refresh();
			_form.Restore(_lastStart.Value);
			_window = new Window(new Window.Actions
			{
				Start = StartFromWindow,
				Preview = PreviewFromWindow,
				Press = delegate(Param p)
				{
					_message = _form.Press(p);
					_nextRefresh = 0f;
				},
				Resume = delegate
				{
					_message = ResumeWhenFree();
				},
				Stop = delegate
				{
					Runner.Stop("stopped from the window");
				},
				Again = AgainFromWindow,
				Close = delegate
				{
					_resultSeen = true;
					_window.SetVisible(visible: false);
				},
				Changed = delegate
				{
					_nextRefresh = 0f;
				},
				Moved = delegate(Vector2 corner)
				{
					//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)
					_windowPosition.Value = string.Format(CultureInfo.InvariantCulture, "{0:0}, {1:0}", corner.x, corner.y);
				}
			}, _form, ParseCorner(_windowPosition.Value));
			GUIManager.OnCustomGUIAvailable += _window.OnGuiRebuilt;
			_harmony = Harmony.CreateAndPatchAll(typeof(Plugin).Assembly, "autoverk");
		}

		private void Update()
		{
			bool flag = _window.Visible && _window.Blocking;
			Body.Clear();
			TickRun();
			ShowChanges();
			_window.SetInteractive(Runner.State != RunState.Running);
			if (_closeOnNextFrame)
			{
				_closeOnNextFrame = false;
				_window.SetVisible(visible: false);
			}
			if ((Object)(object)Senses.Player == (Object)null)
			{
				if (_window.Visible)
				{
					_window.SetVisible(visible: false);
				}
			}
			else if (WindowKeyDown())
			{
				if (!_window.Visible)
				{
					_form.Refresh();
				}
				_window.Toggle();
				_nextRefresh = 0f;
			}
			else if (flag && ZInput.GetKeyDown((KeyCode)27, false))
			{
				_closeOnNextFrame = true;
			}
			if (_window.Visible && Time.unscaledTime >= _nextRefresh)
			{
				_nextRefresh = Time.unscaledTime + 0.25f;
				_window.Show(BuildView());
			}
		}

		private void TickRun()
		{
			if (Senses.OpenMenu() == null)
			{
				if (_pending != null)
				{
					ApplyInterruptionSettings();
					Runner.Start(_pending);
					_pending = null;
					_message = null;
					_resultSeen = false;
					return;
				}
				if (_resumePending)
				{
					Runner.Resume();
					_resumePending = false;
					_message = null;
					return;
				}
			}
			Runner.Tick();
		}

		internal string StartWhenFree(Skill skill)
		{
			if ((Object)(object)Senses.Player == (Object)null)
			{
				return "not in a world";
			}
			string text = Senses.Busy(Senses.Player);
			if (text != null)
			{
				return "can't start: the character is " + text;
			}
			Markers.Hide();
			_previewText = null;
			_pending = skill;
			string text2 = Senses.OpenMenu();
			if (text2 != null)
			{
				return $"{skill} starts when you close the {text2}";
			}
			return $"starting {skill}";
		}

		internal string ResumeWhenFree()
		{
			if (Runner.State != RunState.Paused)
			{
				return Commands.Describe(Runner);
			}
			_resumePending = true;
			string text = Senses.OpenMenu();
			if (text != null)
			{
				return "resumes when you close the " + text;
			}
			return "resuming";
		}

		private void StartFromWindow()
		{
			string error;
			Skill skill = _form.Create(out error);
			if (skill == null)
			{
				_message = error;
				_nextRefresh = 0f;
			}
			else
			{
				_lastStart.Value = _form.Line;
				_message = StartWhenFree(skill);
				_nextRefresh = 0f;
			}
		}

		private void PreviewFromWindow()
		{
			_message = null;
			_previewText = null;
			if (Markers.Showing)
			{
				Markers.Hide();
			}
			else
			{
				string text = _form.Preview();
				if (Markers.Showing)
				{
					_previewText = text;
				}
				else
				{
					_message = text;
				}
			}
			_nextRefresh = 0f;
		}

		private void AgainFromWindow()
		{
			_resultSeen = true;
			string text = Runner.Root?.AgainLine;
			if (text == null)
			{
				_nextRefresh = 0f;
				return;
			}
			string error;
			Skill skill = Registry.FromLine(text, out error);
			_message = ((skill == null) ? error : StartWhenFree(skill));
			_nextRefresh = 0f;
		}

		private Window.View BuildView()
		{
			Window.View view = new Window.View();
			Skill root = Runner.Root;
			SkillInfo skillInfo = root?.Info;
			switch (Runner.State)
			{
			case RunState.Running:
				view.Look = Window.Look.Running;
				view.Heading = (skillInfo?.Doing ?? root.ToString()) + "…";
				Describe(view, root);
				view.Footnote = "Any key pauses.";
				break;
			case RunState.Paused:
				view.Look = Window.Look.Paused;
				view.Heading = "Paused";
				Describe(view, root);
				view.Footnote = Capitalized(Runner.PauseReason) + ". " + (skillInfo?.StopNote ?? "Resume carries on where it was.");
				break;
			case RunState.Finished:
				if (!_resultSeen)
				{
					view.Look = Window.Look.Finished;
					Result outcome = Runner.Outcome;
					view.Heading = root.Headline ?? (outcome.Ok ? "Done" : ((outcome.Code == "stopped") ? "Stopped" : ("Stopped: " + (outcome.Detail ?? outcome.Code))));
					Describe(view, root);
					if (view.Facts.Count == 0 && root.Report != null)
					{
						view.Facts.Add(Row("Result", root.Report));
					}
					view.AgainButton = ((root.AgainLine != null) ? (root.AgainLabel ?? "Again") : "New task");
					view.Footnote = _message ?? root.Advice ?? ((!(outcome.Code == "stopped")) ? null : skillInfo?.StopNote);
					break;
				}
				goto default;
			default:
				view.Look = Window.Look.Form;
				view.Message = _message;
				view.Previewing = Markers.Showing;
				view.PreviewText = (Markers.Showing ? _previewText : null);
				ApplyInterruptionSettings();
				foreach (Reflex reflex2 in Registry.Reflexes)
				{
					Reflex r = reflex2;
					ConfigEntry<bool> entry = _interruptions[r.Id];
					view.Settings.Add(new Window.Setting
					{
						Id = r.Id,
						Section = "Interruptions",
						Label = r.Description,
						On = () => entry.Value,
						SetOn = delegate(bool on)
						{
							Reflex reflex = r;
							bool enabled = (entry.Value = on);
							reflex.Enabled = enabled;
						}
					});
				}
				view.Settings.Add(new Window.Setting
				{
					Id = "jump",
					Section = "Movement",
					Label = "Jump when stuck on the way",
					On = () => _jumpWhenStuck.Value,
					SetOn = delegate(bool on)
					{
						bool jumpWhenStuck = (_jumpWhenStuck.Value = on);
						MoveTo.JumpWhenStuck = jumpWhenStuck;
					}
				});
				break;
			}
			return view;
		}

		private void ApplyInterruptionSettings()
		{
			foreach (Reflex reflex in Registry.Reflexes)
			{
				if (!_interruptions.TryGetValue(reflex.Id, out var value))
				{
					value = (_interruptions[reflex.Id] = ((BaseUnityPlugin)this).Config.Bind<bool>("Interruptions", reflex.Id, true, reflex.Description));
				}
				reflex.Enabled = value.Value;
			}
		}

		private void Describe(Window.View v, Skill root)
		{
			v.Subject = root.Subject;
			if (Runner.State != RunState.Finished && Runner.Status != null)
			{
				v.Facts.Add(Row("Now", Capitalized(Runner.Status)));
			}
			v.Facts.AddRange(root.Facts);
		}

		private static string Capitalized(string s)
		{
			if (!string.IsNullOrEmpty(s))
			{
				return char.ToUpperInvariant(s[0]) + s.Substring(1);
			}
			return s;
		}

		private static KeyValuePair<string, string> Row(string label, string value)
		{
			return new KeyValuePair<string, string>(label, value);
		}

		private void ShowChanges()
		{
			if (Runner.State == _shownState)
			{
				return;
			}
			_shownState = Runner.State;
			if (Runner.State == RunState.Paused || Runner.State == RunState.Finished)
			{
				if ((Object)(object)MessageHud.instance != (Object)null)
				{
					MessageHud.instance.ShowMessage((MessageType)2, (Runner.State == RunState.Paused) ? ("AutoVerk paused: " + Runner.PauseReason) : $"AutoVerk: {Runner.Outcome}", 0, (Sprite)null, false, true);
				}
				if (!((Object)(object)Senses.Player == (Object)null) && Senses.OpenMenu() == null)
				{
					_form.Refresh();
					_window.SetInteractive(interactive: true);
					_window.SetVisible(visible: true);
					_nextRefresh = 0f;
				}
			}
		}

		private bool WindowKeyDown()
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: 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)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			KeyboardShortcut value = _windowKey.Value;
			if ((int)((KeyboardShortcut)(ref value)).MainKey == 0 || !ZInput.GetKeyDown(((KeyboardShortcut)(ref value)).MainKey, false))
			{
				return false;
			}
			foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers)
			{
				if (!ZInput.GetKey(modifier, false))
				{
					return false;
				}
			}
			return true;
		}

		private static Vector2 ParseCorner(string text)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			string[] array = (text ?? "").Split(new char[1] { ',' });
			if (array.Length == 2 && float.TryParse(array[0].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && float.TryParse(array[1].Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result2))
			{
				return new Vector2(result, result2);
			}
			return new Vector2(-20f, -100f);
		}

		private void OnDestroy()
		{
			Runner?.Stop("the mod was unloaded");
			Body.Clear();
			Markers.Destroy();
			if (_window != null)
			{
				GUIManager.OnCustomGUIAvailable -= _window.OnGuiRebuilt;
				_window.Destroy();
			}
			Commands.Unregister();
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace AutoVerk.Ui
{
	internal static class Commands
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ConsoleOptionsFetcher <>9__2_1;

			internal List<string> <Register>b__2_1()
			{
				return new List<string> { "skills", "run", "preview", "pause", "resume", "stop", "status" };
			}
		}

		private const string Name = "autoverk";

		private const string Usage = "autoverk skills [all] | run <skill> [name=value …] | preview <skill> [name=value …] | preview hide | pause | resume | stop | status";

		public static void Register(Plugin plugin)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Expected O, but got Unknown
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Expected O, but got Unknown
			ConsoleEvent val = delegate(ConsoleEventArgs args)
			{
				Run(plugin, args);
			};
			object obj = <>c.<>9__2_1;
			if (obj == null)
			{
				ConsoleOptionsFetcher val2 = () => new List<string> { "skills", "run", "preview", "pause", "resume", "stop", "status" };
				<>c.<>9__2_1 = val2;
				obj = (object)val2;
			}
			new ConsoleCommand("autoverk", "autoverk skills [all] | run <skill> [name=value …] | preview <skill> [name=value …] | preview hide | pause | resume | stop | status", val, false, false, false, false, false, false, (ConsoleOptionsFetcher)obj, false, false, false);
		}

		public static void Unregister()
		{
			AccessTools.StaticFieldRefAccess<Terminal, Dictionary<string, ConsoleCommand>>("commands").Remove("autoverk");
		}

		private static void Run(Plugin plugin, ConsoleEventArgs args)
		{
			Action<string> action = args.Context.AddString;
			string text = ((args.Args.Length > 1) ? args.Args[1] : "status");
			Runner runner = plugin.Runner;
			switch (text)
			{
			case "skills":
			{
				bool flag = args.Args.Length > 2 && args.Args[2] == "all";
				foreach (SkillInfo item in flag ? Registry.AllSkills : Registry.Skills)
				{
					action(item.Usage + "  · " + (item.ForDevelopers ? "(dev) " : "") + item.Description);
				}
				if (!flag)
				{
					action("'autoverk skills all' lists the developer skills too");
				}
				break;
			}
			case "run":
			{
				string error;
				Skill skill = Registry.FromLine(string.Join(" ", args.Args.Skip(2)), out error);
				if (skill == null)
				{
					action(error);
				}
				else
				{
					action(plugin.StartWhenFree(skill));
				}
				break;
			}
			case "preview":
			{
				string text2 = string.Join(" ", args.Args.Skip(2));
				if (text2 == "" || text2 == "hide")
				{
					Markers.Hide();
					action("preview hidden");
				}
				else
				{
					action(Registry.PreviewLine(text2));
				}
				break;
			}
			case "pause":
				runner.Pause("paused from the console");
				action(Describe(runner));
				break;
			case "resume":
				action(plugin.ResumeWhenFree());
				break;
			case "stop":
				runner.Stop("stopped from the console");
				action(Describe(runner));
				break;
			case "status":
				action(Describe(runner));
				break;
			default:
				action("autoverk skills [all] | run <skill> [name=value …] | preview <skill> [name=value …] | preview hide | pause | resume | stop | status");
				break;
			}
		}

		public static string Describe(Runner runner)
		{
			return runner.State switch
			{
				RunState.Running => "running: " + runner.Path + ((runner.Status != null) ? (" · " + runner.Status) : ""), 
				RunState.Paused => "paused (" + runner.PauseReason + "): " + runner.Path, 
				RunState.Finished => string.Format("finished: {0} → {1}{2}", runner.Root, runner.Outcome, (runner.Root.Report != null) ? (" · " + runner.Root.Report) : ""), 
				_ => "idle", 
			};
		}
	}
	internal sealed class SkillForm
	{
		private readonly Dictionary<string, Dictionary<string, string>> _values = new Dictionary<string, Dictionary<string, string>>();

		private string _id;

		public IReadOnlyList<SkillInfo> Skills { get; private set; } = Array.Empty<SkillInfo>();

		public SkillInfo Skill => Skills.FirstOrDefault((SkillInfo s) => s.Id == _id);

		public int Selected => Skills.ToList().FindIndex((SkillInfo s) => s.Id == _id);

		public int Revision { get; private set; }

		public bool CanPreview => Skill?.Preview != null;

		public FormValues Values => new FormValues(delegate(string name)
		{
			Param param = Skill?.Params.FirstOrDefault((Param x) => x.Name == name);
			return (param != null) ? Value(param) : null;
		});

		public string Line
		{
			get
			{
				SkillInfo skill = Skill;
				if (skill == null)
				{
					return "";
				}
				return string.Join(" ", new string[1] { skill.Id }.Concat(skill.Params.Select((Param p) => p.Name + "=" + Quote(Value(p)))));
			}
		}

		public void Refresh()
		{
			Skills = Registry.Skills.ToList();
			if (Skill == null)
			{
				_id = Skills.FirstOrDefault()?.Id;
			}
			Revision++;
		}

		public void Select(int index)
		{
			if (index >= 0 && index < Skills.Count && !(Skills[index].Id == _id))
			{
				_id = Skills[index].Id;
				Revision++;
			}
		}

		public string Value(Param p)
		{
			string text;
			if (_id == null || !_values.TryGetValue(_id, out var value) || !value.TryGetValue(p.Name, out var value2))
			{
				text = p.Default;
				if (text == null)
				{
					return "";
				}
			}
			else
			{
				text = value2;
			}
			return text;
		}

		public void Set(Param p, string value)
		{
			if (_id != null)
			{
				if (!_values.TryGetValue(_id, out var value2))
				{
					value2 = (_values[_id] = new Dictionary<string, string>());
				}
				value2[p.Name] = value ?? "";
			}
		}

		public Skill Create(out string error)
		{
			SkillInfo skill = Skill;
			Args args = Filled(out error);
			if (args == null)
			{
				return null;
			}
			try
			{
				Skill skill2 = skill.Create(args);
				if (skill2 != null)
				{
					skill2.Info = skill;
				}
				return skill2;
			}
			catch (Exception ex)
			{
				error = skill.Id + " couldn't start: " + ex.Message;
				return null;
			}
		}

		public string Preview()
		{
			SkillInfo skill = Skill;
			if (skill != null && skill.Preview == null)
			{
				return skill.Id + " has no preview";
			}
			string error;
			Args args = Filled(out error);
			if (args == null)
			{
				return error;
			}
			try
			{
				return skill.Preview(args);
			}
			catch (Exception ex)
			{
				return skill.Id + " couldn't preview: " + ex.Message;
			}
		}

		public string Press(Param p)
		{
			if (p?.Button == null)
			{
				return null;
			}
			string result;
			try
			{
				result = p.Button.Press(Values);
			}
			catch (Exception ex)
			{
				return p.Button.Label + " failed: " + ex.Message;
			}
			if (p.Button.Clears)
			{
				Set(p, "");
			}
			Refresh();
			return result;
		}

		private Args Filled(out string error)
		{
			SkillInfo skill = Skill;
			if (skill == null)
			{
				error = "no skills registered";
				return null;
			}
			Dictionary<string, string> given = (from p in skill.Params
				select (Name: p.Name, Value: Value(p)) into v
				where v.Value != ""
				select v).ToDictionary(((string Name, string Value) v) => v.Name, ((string Name, string Value) v) => v.Value);
			return Args.Check(skill, given, out error);
		}

		public void Restore(string line)
		{
			Dictionary<string, string> values;
			string error;
			string id = Args.ParseLine(line, out values, out error);
			SkillInfo skillInfo = Registry.Find(id);
			if (skillInfo == null || skillInfo.ForDevelopers)
			{
				return;
			}
			if (Skills.Count == 0)
			{
				Refresh();
			}
			_id = id;
			foreach (Param item in skillInfo.Params)
			{
				if (values.TryGetValue(item.Name, out var value))
				{
					Set(item, value);
				}
			}
		}

		private static string Quote(string v)
		{
			if (!v.Any(char.IsWhiteSpace))
			{
				return v;
			}
			return "\"" + v + "\"";
		}
	}
	internal sealed class Window
	{
		public enum Look
		{
			Form,
			Running,
			Paused,
			Finished
		}

		private enum Tab
		{
			Tasks,
			Settings
		}

		public sealed class Actions
		{
			public Action Start;

			public Action Preview;

			public Action<Param> Press;

			public Action Resume;

			public Action Stop;

			public Action Again;

			public Action Close;

			public Action Changed;

			public Action<Vector2> Moved;
		}

		public sealed class Setting
		{
			public string Id;

			public string Section;

			public string Label;

			public Func<bool> On;

			public Action<bool> SetOn;
		}

		public sealed class View
		{
			public Look Look;

			public string Heading;

			public string Subject;

			public List<KeyValuePair<string, string>> Facts = new List<KeyValuePair<string, string>>();

			public string Footnote;

			public string AgainButton;

			public string Message;

			public List<Setting> Settings = new List<Setting>();

			public bool Previewing;

			public string PreviewText;
		}

		private sealed class ParamRow
		{
			public Param P;

			public Text Label;

			public RectTransform Control;

			public Text Caption;

			public Text Hint;

			public Text Note;

			public GameObject Button;

			public string ArmedFor;
		}

		private sealed class Section
		{
			public Text Header;

			public readonly List<ParamRow> Rows = new List<ParamRow>();
		}

		private sealed class Choice
		{
			private readonly Dropdown _dropdown;

			private string _key;

			public Choice(Dropdown dropdown, Action<int> changed)
			{
				_dropdown = dropdown;
				((UnityEvent<int>)(object)_dropdown.onValueChanged).AddListener((UnityAction<int>)delegate(int i)
				{
					changed(i);
				});
			}

			public void Set(List<string> options, int selected, string emptyText)
			{
				bool flag = options.Count == 0;
				if (flag)
				{
					options = new List<string> { emptyText ?? "" };
				}
				string text = string.Join("\n", options);
				if (text != _key)
				{
					_key = text;
					_dropdown.ClearOptions();
					_dropdown.AddOptions(options);
				}
				((Selectable)_dropdown).interactable = !flag;
				if (flag || selected < 0)
				{
					selected = 0;
				}
				if (_dropdown.value != selected)
				{
					_dropdown.SetValueWithoutNotify(selected);
				}
			}
		}

		private const float Width = 500f;

		private const float RunWidth = 400f;

		private const float Pad = 20f;

		private const float TitleY = -30f;

		private const float Top = -62f;

		private const float RowHeight = 34f;

		private const float Row = 40f;

		private const float LabelWidth = 95f;

		private const float ControlX = 120f;

		private const float ControlWidth = 200f;

		private const float HintX = 332f;

		private const float HintWidth = 150f;

		private const float FactLabelX = 40f;

		private const float FactValueX = 165f;

		private const float ButtonHeight = 40f;

		private const int SummarySize = 15;

		private static readonly Color Grey = new Color(0.8f, 0.78f, 0.74f);

		private static readonly Color Dim = new Color(0.68f, 0.65f, 0.6f);

		private readonly Actions _actions;

		private readonly SkillForm _form;

		private Vector2 _corner;

		private Tab _tab;

		private GameObject _canvas;

		private GameObject _panel;

		private Text _title;

		private Look _look;

		private bool _compact;

		private bool _blocking;

		private bool _interactive = true;

		private GameObject _formGroup;

		private GameObject[] _tabs;

		private GameObject _tasksGroup;

		private Choice _task;

		private RectTransform _taskRect;

		private Text _description;

		private RectTransform _formDivider;

		private GameObject _params;

		private string _paramsKey;

		private readonly List<Section> _sections = new List<Section>();

		private RectTransform _summaryBox;

		private Text _summary;

		private Text _warning;

		private Text _found;

		private Text _message;

		private GameObject _preview;

		private GameObject _start;

		private GameObject _settingsGroup;

		private string _settingsKey;

		private readonly List<(Setting setting, Text label, Toggle check)> _settingRows = new List<(Setting, Text, Toggle)>();

		private Text _settingsNote;

		private GameObject _statusGroup;

		private Text _heading;

		private Text _subject;

		private RectTransform _statusDivider;

		private GameObject _factsGroup;

		private readonly List<(Text label, Text value)> _facts = new List<(Text, Text)>();

		private GameObject _left;

		private GameObject _right;

		private Text _footnote;

		public bool Visible
		{
			get
			{
				if ((Object)(object)_panel != (Object)null)
				{
					return _panel.activeSelf;
				}
				return false;
			}
		}

		public bool Blocking => _blocking;

		public Window(Actions actions, SkillForm form, Vector2 corner)
		{
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			_actions = actions;
			_form = form;
			_corner = corner;
		}

		public void OnGuiRebuilt()
		{
			_canvas = null;
			_panel = null;
			Block(state: false);
		}

		public void Toggle()
		{
			SetVisible(!Visible);
		}

		public void SetVisible(bool visible)
		{
			if (visible && (Object)(object)_panel == (Object)null)
			{
				Create();
			}
			if (!((Object)(object)_panel == (Object)null))
			{
				if (!visible && _panel.activeSelf)
				{
					RememberCorner();
				}
				_panel.SetActive(visible);
				Block(visible && _interactive);
			}
		}

		public void SetInteractive(bool interactive)
		{
			_interactive = interactive;
			Block(Visible && interactive);
		}

		public void Show(View v)
		{
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			if (Visible)
			{
				_look = v.Look;
				bool flag = v.Look == Look.Form;
				_formGroup.SetActive(flag);
				_statusGroup.SetActive(!flag);
				float num = ((v.Look == Look.Running) ? 400f : 500f);
				float num2 = (flag ? LayOutForm(v) : LayOutStatus(v, num));
				Resize(new Vector2(num, num2), v.Look == Look.Running);
			}
		}

		public void Destroy()
		{
			Block(state: false);
			if ((Object)(object)_canvas != (Object)null)
			{
				Object.Destroy((Object)(object)_canvas);
			}
			_canvas = null;
			_panel = null;
		}

		private float LayOutForm(View v)
		{
			float num = 460f;
			float num2 = -62f;
			float num3 = (num - 12f) / 2f;
			for (int i = 0; i < _tabs.Length; i++)
			{
				Put(_tabs[i], 20f + (float)i * (num3 + 12f), num2, num3, 34f);
				Style(_tabs[i], _tab == (Tab)i);
			}
			num2 -= 48f;
			_tasksGroup.SetActive(_tab == Tab.Tasks);
			_settingsGroup.SetActive(_tab == Tab.Settings);
			_start.SetActive(_tab == Tab.Tasks);
			_preview.SetActive(_tab == Tab.Tasks && (_form.CanPreview || v.Previewing));
			if (_tab == Tab.Settings)
			{
				return LayOutSettings(v, num2);
			}
			SkillInfo info = _form.Skill;
			IReadOnlyList<SkillInfo> skills = _form.Skills;
			_task.Set(skills.Select((SkillInfo s) => s.Title).ToList(), _form.Selected, "no tasks");
			Put((Component)(object)_taskRect, 20f, num2, num, 36f);
			num2 -= 46f;
			_description.text = info?.Description ?? "";
			num2 -= PutText(_description, 20f, num2, num) + 12f;
			Put((Component)(object)_formDivider, 20f, num2, num, 2f);
			num2 -= 16f;
			ShowParams(info);
			FormValues values = _form.Values;
			foreach (Section section in _sections)
			{
				List<ParamRow> list = section.Rows.Where((ParamRow r) => Safe(() => r.P.Shown?.Invoke(values) ?? true, fallback: true)).ToList();
				bool flag = (Object)(object)section.Header != (Object)null && list.Count > 0;
				if ((Object)(object)section.Header != (Object)null)
				{
					((Component)section.Header).gameObject.SetActive(flag);
				}
				if (flag)
				{
					Put((Component)(object)section.Header, 20f, num2, num, 22f);
					num2 -= 28f;
				}
				foreach (ParamRow row in section.Rows)
				{
					bool flag2 = list.Contains(row);
					((Component)row.Label).gameObject.SetActive(flag2);
					((Component)row.Control).gameObject.SetActive(flag2);
					((Component)row.Hint).gameObject.SetActive(flag2);
					if ((Object)(object)row.Caption != (Object)null)
					{
						((Component)row.Caption).gameObject.SetActive(flag2);
					}
					if ((Object)(object)row.Button != (Object)null && !flag2)
					{
						row.Button.SetActive(false);
					}
					string text = (flag2 ? Safe(() => row.P.Note?.Invoke(values), null) : null);
					((Component)row.Note).gameObject.SetActive(!string.IsNullOrEmpty(text));
					if (!flag2)
					{
						continue;
					}
					Put((Component)(object)row.Label, 20f, num2, 95f, 34f);
					if ((Object)(object)row.Caption != (Object)null)
					{
						Put((Component)(object)row.Control, 120f, num2 - 3f, 28f, 28f);
						Put((Component)(object)row.Caption, 156f, num2, 170f, 34f);
					}
					else
					{
						Put((Component)(object)row.Control, 120f, num2, 200f, 34f);
					}
					ParamButton button = row.P.Button;
					bool flag3 = button != null && Safe(() => button.Shown?.Invoke(values) ?? true, fallback: false);
					if ((Object)(object)row.Button != (Object)null)
					{
						row.Button.SetActive(flag3);
					}
					((Component)row.Hint).gameObject.SetActive(!flag3);
					if (flag3)
					{
						string text2 = _form.Value(row.P);
						if (row.ArmedFor != text2)
						{
							row.ArmedFor = null;
						}
						SetText(row.Button, (row.ArmedFor != null) ? ("Really " + button.Label.ToLowerInvariant() + "?") : button.Label);
						Style(row.Button, row.ArmedFor != null);
						Put(row.Button, 332f, num2, 150f, 34f);
					}
					else
					{
						row.Hint.text = Safe(() => (row.P.Hint == null) ? ((!((Object)(object)row.Caption == (Object)null)) ? null : row.P.Description) : row.P.Hint(values), "") ?? "";
						Put((Component)(object)row.Hint, 332f, num2, 150f, 34f);
					}
					num2 -= 40f;
					if (!string.IsNullOrEmpty(text))
					{
						row.Note.text = text;
						num2 -= PutText(row.Note, 20f, num2 + 4f, num) + 2f;
					}
				}
				num2 -= 4f;
			}
			FormSummary formSummary = ((info?.Summary != null) ? Safe(() => info.Summary(values), null) : null);
			(Text, string)[] array = new(Text, string)[3]
			{
				(_summary, formSummary?.Text),
				(_warning, formSummary?.Warning),
				(_found, v.PreviewText)
			};
			bool flag4 = array.Any(((Text, string) l) => !string.IsNullOrEmpty(l.Item2));
			((Component)_summaryBox).gameObject.SetActive(flag4);
			if (flag4)
			{
				num2 -= 8f;
				float num4 = -8f;
				(Text, string)[] array2 = array;
				for (int num5 = 0; num5 < array2.Length; num5++)
				{
					var (val, text3) = array2[num5];
					((Component)val).gameObject.SetActive(!string.IsNullOrEmpty(text3));
					if (!string.IsNullOrEmpty(text3))
					{
						val.text = text3;
						num4 -= PutText(val, 10f, num4, num - 20f) + 2f;
					}
				}
				float num6 = 0f - num4 + 6f;
				Put((Component)(object)_summaryBox, 20f, num2, num, num6);
				num2 -= num6 + 12f;
			}
			((Component)_message).gameObject.SetActive(!string.IsNullOrEmpty(v.Message));
			if (!string.IsNullOrEmpty(v.Message))
			{
				_message.text = v.Message;
				num2 -= PutText(_message, 20f, num2, num) + 10f;
			}
			float num7 = (num - 12f) / 2f;
			SetText(_preview, v.Previewing ? "Hide" : (info?.PreviewText ?? "Preview"));
			SetText(_start, info?.StartText ?? "Start");
			Style(_start, marked: true);
			Put(_preview, 20f, num2, num7, 40f);
			Put(_start, 20f + num7 + 12f, num2, num7, 40f);
			return 0f - (num2 - 40f - 20f);
		}

		private void ShowParams(SkillInfo info)
		{
			//IL_013a: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_01f4: Expected O, but got Unknown
			//IL_0205: Unknown result type (might be due to invalid IL or missing references)
			//IL_02d7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0371: Unknown result type (might be due to invalid IL or missing references)
			//IL_0293: Unknown result type (might be due to invalid IL or missing references)
			//IL_02aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
			//IL_02cd: Expected O, but got Unknown
			string text = $"{info?.Id}#{_form.Revision}";
			if (text == _paramsKey)
			{
				return;
			}
			_paramsKey = text;
			if ((Object)(object)_params != (Object)null)
			{
				Object.Destroy((Object)(object)_params);
			}
			_params = Group(_tasksGroup.transform, "Params");
			_sections.Clear();
			if (info == null)
			{
				return;
			}
			GUIManager instance = GUIManager.Instance;
			Transform transform = _params.transform;
			foreach (Param item in info.Params)
			{
				Param p = item;
				Section section = _sections.LastOrDefault();
				if (section == null || (section.Rows.Count > 0 && section.Rows[0].P.Section != p.Section))
				{
					section = new Section();
					if (p.Section != null)
					{
						section.Header = Label(transform, Spaced(p.Section), 13, instance.ValheimOrange);
					}
					_sections.Add(section);
				}
				ParamRow paramRow = new ParamRow
				{
					P = p
				};
				paramRow.Label = Label(transform, p.Label ?? p.Name, 16, Color.white);
				if (p.Kind == ParamKind.Bool)
				{
					Toggle val = Check(transform, delegate(bool on)
					{
						_form.Set(p, on ? "yes" : "no");
					});
					val.SetIsOnWithoutNotify(_form.Value(p) == "yes");
					paramRow.Control = (RectTransform)((Component)val).transform;
					paramRow.Caption = Label(transform, p.Description, 15, Color.white);
				}
				else if (p.Kind == ParamKind.Choice)
				{
					paramRow.Control = Dropdown(transform, p, p.Options.ToList());
				}
				else if (p.Suggestions != null)
				{
					paramRow.Control = Dropdown(transform, p, Suggested(p));
				}
				else
				{
					ContentType content = (ContentType)((p.Kind == ParamKind.Number) ? 3 : 0);
					paramRow.Control = (RectTransform)((Component)Input(transform, _form.Value(p), content, delegate(string v)
					{
						_form.Set(p, v);
					})).transform;
				}
				paramRow.Hint = Label(transform, "", 13, Grey);
				paramRow.Hint.verticalOverflow = (VerticalWrapMode)1;
				if (p.Button != null)
				{
					ParamRow r = paramRow;
					r.Button = Button(transform, p.Button.Label, delegate
					{
						string text2 = _form.Value(p);
						if (p.Button.Confirm && r.ArmedFor != text2)
						{
							r.ArmedFor = text2;
						}
						else
						{
							r.ArmedFor = null;
							_actions.Press?.Invoke(p);
						}
						_actions.Changed?.Invoke();
					});
					r.Button.GetComponentInChildren<Text>().fontSize = 15;
				}
				paramRow.Note = Label(transform, "", 14, Grey);
				paramRow.Note.alignment = (TextAnchor)0;
				section.Rows.Add(paramRow);
			}
		}

		private static List<string> Suggested(Param p)
		{
			List<string> list = new List<string>();
			if (p.EmptyText != null)
			{
				list.Add("");
			}
			try
			{
				list.AddRange(from s in p.Suggestions()
					where !string.IsNullOrEmpty(s)
					select s);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("suggestions for " + p.Name + ": " + ex.Message));
			}
			return list;
		}

		private static string Display(Param p, string value)
		{
			if (value == "")
			{
				return p.EmptyText ?? "";
			}
			if (p.Names != null)
			{
				return Safe(() => p.Names(value), value);
			}
			if (p.Kind == ParamKind.Item)
			{
				return Senses.ItemName(value);
			}
			if (p.Kind == ParamKind.Choice)
			{
				return char.ToUpperInvariant(value[0]) + value.Substring(1);
			}
			return value;
		}

		private RectTransform Dropdown(Transform parent, Param p, List<string> values)
		{
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Expected O, but got Unknown
			string text = _form.Value(p);
			if (text == "" && p.EmptyText == null && values.Count > 0)
			{
				text = values[0];
				_form.Set(p, text);
			}
			if (text != "" && !values.Contains(text))
			{
				values.Add(text);
			}
			Dropdown obj = Drop(parent);
			new Choice(obj, delegate(int i)
			{
				_form.Set(p, values[i]);
			}).Set(values.Select((string v) => Display(p, v)).ToList(), values.IndexOf(text), "none found");
			return (RectTransform)((Component)obj).transform;
		}

		private float LayOutSettings(View v, float y)
		{
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Expected O, but got Unknown
			//IL_0173: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			string text = string.Join(",", v.Settings.Select((Setting s) => s.Id));
			if (text != _settingsKey)
			{
				_settingsKey = text;
				foreach (Transform item3 in _settingsGroup.transform)
				{
					Transform val = item3;
					if ((Object)(object)val != (Object)(object)((Component)_settingsNote).transform)
					{
						Object.Destroy((Object)(object)((Component)val).gameObject);
					}
				}
				_settingRows.Clear();
				foreach (Setting setting3 in v.Settings)
				{
					Setting setting = setting3;
					if (setting.Section != null && setting.Section != _settingRows.LastOrDefault().setting?.Section)
					{
						_settingRows.Add((null, Label(_settingsGroup.transform, Spaced(setting.Section), 13, GUIManager.Instance.ValheimOrange), null));
					}
					Text item = Label(_settingsGroup.transform, setting.Label, 15, Color.white);
					Toggle item2 = Check(_settingsGroup.transform, delegate(bool on)
					{
						setting.SetOn(on);
					});
					_settingRows.Add((setting, item, item2));
				}
			}
			float num = 460f;
			foreach (var (setting2, c, val2) in _settingRows)
			{
				if (setting2 == null)
				{
					Put((Component)(object)c, 20f, y, num, 22f);
					y -= 28f;
					continue;
				}
				Put((Component)(object)c, 20f, y, num - 40f, 34f);
				Put((Component)(object)val2, 20f + num - 28f, y - 3f, 28f, 28f);
				if (val2.isOn != setting2.On())
				{
					val2.SetIsOnWithoutNotify(setting2.On());
				}
				y -= 40f;
			}
			y -= 6f;
			y -= PutText(_settingsNote, 20f, y, num);
			return 0f - (y - 20f);
		}

		private float LayOutStatus(View v, float width)
		{
			//IL_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			float num = width - 40f;
			float num2 = -62f;
			_heading.text = v.Heading ?? "";
			((Graphic)_heading).color = ((v.Look == Look.Running) ? Color.white : instance.ValheimOrange);
			num2 -= PutText(_heading, 20f, num2, num) + 2f;
			((Component)_subject).gameObject.SetActive(!string.IsNullOrEmpty(v.Subject));
			if (!string.IsNullOrEmpty(v.Subject))
			{
				_subject.text = v.Subject;
				num2 -= PutText(_subject, 20f, num2, num);
			}
			num2 -= 10f;
			Put((Component)(object)_statusDivider, 20f, num2, num, 2f);
			num2 -= 14f;
			while (_facts.Count < v.Facts.Count)
			{
				_facts.Add((Label(_factsGroup.transform, "", 15, Color.white), Label(_factsGroup.transform, "", 15, Color.white)));
			}
			for (int i = 0; i < _facts.Count; i++)
			{
				(Text label, Text value) tuple = _facts[i];
				Text item = tuple.label;
				Text item2 = tuple.value;
				bool flag = i < v.Facts.Count;
				((Component)item).gameObject.SetActive(flag);
				((Component)item2).gameObject.SetActive(flag);
				if (flag)
				{
					item.text = v.Facts[i].Key;
					item2.text = v.Facts[i].Value;
					Put((Component)(object)item, 40f, num2, 117f, 26f);
					float num3 = Mathf.Max(26f, PutText(item2, 165f, num2 - 3f, width - 165f - 20f) + 6f);
					num2 -= num3;
				}
			}
			bool flag2 = v.Look != Look.Running;
			_left.SetActive(flag2);
			_right.SetActive(flag2);
			if (flag2)
			{
				num2 -= 16f;
				float num4 = (num - 12f) / 2f;
				SetText(_left, (v.Look == Look.Paused) ? "Resume" : (v.AgainButton ?? "New task"));
				SetText(_right, (v.Look == Look.Paused) ? "Stop" : "Close");
				Style(_left, marked: true);
				Put(_left, 20f, num2, num4, 40f);
				Put(_right, 20f + num4 + 12f, num2, num4, 40f);
				num2 -= 40f;
			}
			((Component)_footnote).gameObject.SetActive(!string.IsNullOrEmpty(v.Footnote));
			if (!string.IsNullOrEmpty(v.Footnote))
			{
				num2 -= 10f;
				_footnote.text = v.Footnote;
				num2 -= PutText(_footnote, 20f, num2, num);
			}
			return 0f - (num2 - 20f + 4f);
		}

		private void OnLeft()
		{
			if (_look == Look.Paused)
			{
				_actions.Resume?.Invoke();
			}
			else
			{
				_actions.Again?.Invoke();
			}
		}

		private void OnRight()
		{
			if (_look == Look.Paused)
			{
				_actions.Stop?.Invoke();
			}
			else
			{
				_actions.Close?.Invoke();
			}
		}

		private void Create()
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_009e: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_022b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0235: Expected O, but got Unknown
			//IL_0258: Unknown result type (might be due to invalid IL or missing references)
			//IL_029b: Unknown result type (might be due to invalid IL or missing references)
			//IL_02c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_0314: Unknown result type (might be due to invalid IL or missing references)
			//IL_038d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03da: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_047f: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			Transform val = ((instance != null) ? Canvas() : null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Vector2 val2 = CanvasSize();
			_corner.x = Mathf.Clamp(_corner.x, 0f - Math.Max(500f, val2.x) + 500f, 0f);
			_corner.y = Mathf.Clamp(_corner.y, 0f - Math.Max(400f, val2.y) + 60f, 0f);
			_panel = instance.CreateWoodpanel(val, new Vector2(1f, 1f), new Vector2(1f, 1f), _corner - new Vector2(500f, 400f) / 2f, 500f, 400f, true);
			((Object)_panel).name = "AutoVerkWindow";
			_compact = false;
			_paramsKey = null;
			_settingsKey = null;
			_settingRows.Clear();
			_sections.Clear();
			_facts.Clear();
			_title = Label(_panel.transform, "AutoVerk", 30, instance.ValheimOrange);
			_title.alignment = (TextAnchor)4;
			_formGroup = Group(_panel.transform, "Form");
			Transform transform = _formGroup.transform;
			string[] array = new string[2] { "Tasks", "Settings" };
			_tabs = (GameObject[])(object)new GameObject[array.Length];
			for (int i = 0; i < array.Length; i++)
			{
				Tab tab = (Tab)i;
				_tabs[i] = Button(transform, array[i], delegate
				{
					_tab = tab;
					_actions.Changed?.Invoke();
				});
			}
			_tasksGroup = Group(transform, "Tasks");
			Transform transform2 = _tasksGroup.transform;
			Dropdown val3 = Drop(transform2, 17);
			_taskRect = (RectTransform)((Component)val3).transform;
			_task = new Choice(val3, delegate(int index)
			{
				_form.Select(index);
				_actions.Changed?.Invoke();
			});
			_description = Label(transform2, "", 14, Grey);
			_description.alignment = (TextAnchor)0;
			_formDivider = Divider(transform2);
			_summaryBox = Box(transform2);
			_summary = Label((Transform)(object)_summaryBox, "", 15, Color.white);
			_summary.alignment = (TextAnchor)4;
			_warning = Label((Transform)(object)_summaryBox, "", 15, instance.ValheimOrange);
			_warning.alignment = (TextAnchor)4;
			_found = Label((Transform)(object)_summaryBox, "", 15, Grey);
			_found.alignment = (TextAnchor)4;
			_message = Label(transform2, "", 14, instance.ValheimOrange);
			_message.alignment = (TextAnchor)0;
			_preview = Button(transform, "Preview", delegate
			{
				_actions.Preview?.Invoke();
			});
			_start = Button(transform, "Start", delegate
			{
				_actions.Start?.Invoke();
			});
			_settingsGroup = Group(transform, "Settings");
			_settingsNote = Label(_settingsGroup.transform, "Interruptions step in during any run when something happens, then the run carries on. Without jumping, a walk that gets stuck gives up at once.", 14, Grey);
			_settingsNote.alignment = (TextAnchor)0;
			_statusGroup = Group(_panel.transform, "Status");
			Transform transform3 = _statusGroup.transform;
			_heading = Label(transform3, "", 20, Color.white);
			_heading.alignment = (TextAnchor)1;
			_subject = Label(transform3, "", 14, Grey);
			_subject.alignment = (TextAnchor)1;
			_statusDivider = Divider(transform3);
			_factsGroup = Group(transform3, "Facts");
			_left = Button(transform3, "Resume", OnLeft);
			_right = Button(transform3, "Stop", OnRight);
			_footnote = Label(transform3, "", 13, Dim);
			_footnote.alignment = (TextAnchor)1;
			_panel.SetActive(false);
		}

		private void Resize(Vector2 size, bool compact)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0091: 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_003a: 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_0045: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			RectTransform val = (RectTransform)_panel.transform;
			Vector2 val2 = (compact ? RunCorner() : _corner);
			if (compact == _compact && val.sizeDelta == size)
			{
				Vector2 val3 = val.anchoredPosition + size / 2f - val2;
				if (((Vector2)(ref val3)).sqrMagnitude < 1f)
				{
					return;
				}
			}
			if (compact && !_compact)
			{
				RememberCorner();
			}
			_compact = compact;
			val.sizeDelta = size;
			val.anchoredPosition = val2 - size / 2f;
			Put((Component)(object)_title, 20f, -12f, size.x - 40f, 36f);
		}

		private void RememberCorner()
		{
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Expected O, but got Unknown
			//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)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: 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_0069: Unknown result type (might be due to invalid IL or missing references)
			if (!_compact)
			{
				RectTransform val = (RectTransform)_panel.transform;
				Vector2 val2 = val.anchoredPosition + val.sizeDelta / 2f;
				Vector2 val3 = val2 - _corner;
				if (!(((Vector2)(ref val3)).sqrMagnitude < 1f))
				{
					_corner = val2;
					_actions.Moved?.Invoke(val2);
				}
			}
		}

		private static Vector2 RunCorner()
		{
			//IL_0036: 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_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = (((Object)(object)Minimap.instance != (Object)null) ? Minimap.instance.m_smallRoot : null);
			if ((Object)(object)val == (Object)null || !val.activeInHierarchy)
			{
				return new Vector2(-20f, -60f);
			}
			Vector3[] array = (Vector3[])(object)new Vector3[4];
			((RectTransform)val.transform).GetWorldCorners(array);
			float num = (float)Screen.width / CanvasSize().x;
			return new Vector2((array[2].x - (float)Screen.width) / num, (array[0].y - (float)Screen.height) / num - 8f);
		}

		private Transform Canvas()
		{
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Expected O, but got Unknown
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_0097: 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_00a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: 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)
			//IL_00b4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)_canvas != (Object)null)
			{
				return _canvas.transform;
			}
			GameObject customGUIFront = GUIManager.CustomGUIFront;
			if ((Object)(object)customGUIFront == (Object)null)
			{
				return null;
			}
			_canvas = new GameObject("AutoVerkCanvas", new Type[4]
			{
				typeof(RectTransform),
				typeof(Canvas),
				typeof(CanvasScaler),
				typeof(GraphicRaycaster)
			});
			RectTransform val = (RectTransform)_canvas.transform;
			((Transform)val).SetParent(customGUIFront.transform.parent, false);
			val.anchorMin = Vector2.zero;
			val.anchorMax = Vector2.one;
			Vector2 offsetMin = (val.offsetMax = Vector2.zero);
			val.offsetMin = offsetMin;
			Canvas component = _canvas.GetComponent<Canvas>();
			component.renderMode = (RenderMode)0;
			component.overrideSorting = true;
			component.sortingOrder = 2001;
			_canvas.GetComponent<CanvasScaler>().referencePixelsPerUnit = 50f;
			_canvas.AddComponent<GuiScaler>();
			return _canvas.transform;
		}

		private static Vector2 CanvasSize()
		{
			//IL_003a: 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)
			float val = Mathf.Min((float)Screen.width / 1920f, (float)Screen.height / 1080f) * PlatformPrefs.GetFloat("GuiScale", GuiScaler.PlatformDefaultScaling);
			return new Vector2((float)Screen.width, (float)Screen.height) / Math.Max(0.1f, val);
		}

		private void Block(bool state)
		{
			if (_blocking != state)
			{
				_blocking = state;
				GUIManager.BlockInput(state);
			}
		}

		private static string Spaced(string section)
		{
			return string.Join(" ", section.ToUpperInvariant().ToCharArray());
		}

		private static T Safe<T>(Func<T> read, T fallback)
		{
			try
			{
				return read();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("window: " + ex.Message));
				return fallback;
			}
		}

		private static GameObject Group(Transform parent, string name)
		{
			//IL_0014: 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_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: 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)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: 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_0042: 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_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Expected O, but got Unknown
			GameObject val = new GameObject(name, new Type[1] { typeof(RectTransform) });
			RectTransform val2 = (RectTransform)val.transform;
			((Transform)val2).SetParent(parent, false);
			val2.anchorMin = Vector2.zero;
			val2.anchorMax = Vector2.one;
			val2.offsetMin = Vector2.zero;
			val2.offsetMax = Vector2.zero;
			return val;
		}

		private static void Put(Component c, float x, float top, float width, float height)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: 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_0053: 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)
			RectTransform val = (RectTransform)c.transform;
			Vector2 val2 = default(Vector2);
			((Vector2)(ref val2))..ctor(0f, 1f);
			val.anchorMax = val2;
			val.anchorMin = val2;
			val.pivot = new Vector2(0.5f, 0.5f);
			val.anchoredPosition = new Vector2(x + width / 2f, top - height / 2f);
			val.sizeDelta = new Vector2(width, height);
		}

		private static void Put(GameObject go, float x, float top, float width, float height)
		{
			Put((Component)(object)go.transform, x, top, width, height);
		}

		private static float PutText(Text t, float x, float top, float width)
		{
			//IL_000a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			RectTransform rectTransform = ((Graphic)t).rectTransform;
			rectTransform.sizeDelta = new Vector2(width, rectTransform.sizeDelta.y);
			float num = Mathf.Max((float)t.fontSize + 6f, t.preferredHeight + 2f);
			Put((Component)(object)t, x, top, width, num);
			return num;
		}

		private static Text Label(Transform parent, string text, int size, Color color)
		{
			//IL_0013: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: 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_0049: Unknown result type (might be due to invalid IL or missing references)
			GUIManager instance = GUIManager.Instance;
			Text component = instance.CreateText(text, parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, instance.AveriaSerifBold, size, color, true, new Color(0f, 0f, 0f, 0.6f), 100f, 20f, false).GetComponent<Text>();
			component.alignment = (TextAnchor)3;
			component.horizontalOverflow = (HorizontalWrapMode)0;
			component.verticalOverflow = (VerticalWrapMode)1;
			component.supportRichText = true;
			return component;
		}

		private static Dropdown Drop(Transform parent, int fontSize = 15)
		{
			//IL_0010: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			return GUIManager.Instance.CreateDropDown(parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, fontSize, 200f, 34f).GetComponent<Dropdown>();
		}

		private static Toggle Check(Transform parent, Action<bool> changed)
		{
			GameObject val = GUIManager.Instance.CreateToggle(parent, 28f, 28f);
			Text[] componentsInChildren = val.GetComponentsInChildren<Text>(true);
			for (int i = 0; i < componentsInChildren.Length; i++)
			{
				componentsInChildren[i].text = "";
			}
			Toggle component = val.GetComponent<Toggle>();
			((UnityEvent<bool>)(object)component.onValueChanged).AddListener((UnityAction<bool>)delegate(bool on)
			{
				changed(on);
			});
			return component;
		}

		private static InputField Input(Transform parent, string value, ContentType content, Action<string> changed)
		{
			//IL_001d: 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)
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			InputField component = GUIManager.Instance.CreateInputField(parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, content, "", 16, 200f, 34f).GetComponent<InputField>();
			component.text = value;
			((UnityEvent<string>)(object)component.onValueChanged).AddListener((UnityAction<string>)delegate(string v)
			{
				changed(v);
			});
			return component;
		}

		private static GameObject Button(Transform parent, string text, Action onClick)
		{
			//IL_001e: 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_0032: 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_0062: Expected O, but got Unknown
			GameObject obj = GUIManager.Instance.CreateButton(text, parent, new Vector2(0f, 1f), new Vector2(0f, 1f), Vector2.zero, 100f, 40f);
			((UnityEvent)obj.GetComponent<Button>().onClick).AddListener((UnityAction)delegate
			{
				onClick?.Invoke();
			});
			Text componentInChildren = obj.GetComponentInChildren<Text>();
			componentInChildren.font = GUIManager.Instance.AveriaSerifBold;
			componentInChildren.fontSize = 18;
			return obj;
		}

		private static void SetText(GameObject button, string text)
		{
			Text componentInChildren = button.GetComponentInChildren<Text>();
			if (componentInChildren.text != text)
			{
				componentInChildren.text = text;
			}
		}

		private static void Style(GameObject button, bool marked)
		{
			//IL_0005: 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_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: 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)
			Color valheimOrange = GUIManager.Instance.ValheimOrange;
			((Graphic)button.GetComponentInChildren<Text>()).color = (marked ? valheimOrange : Color.white);
			Outline obj = button.GetComponent<Outline>() ?? button.AddComponent<Outline>();
			((Shadow)obj).effectColor = valheimOrange;
			((Shadow)obj).effectDistance = new Vector2(2f, -2f);
			((Behaviour)obj).enabled = marked;
		}

		private static RectTransform Divider(Transform parent)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0066: Expected O, but got Unknown
			GameObject val = new GameObject("Divider", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			((Graphic)val.GetComponent<Image>()).color = new Color(0f, 0f, 0f, 0.35f);
			return (RectTransform)val.transform;
		}

		private static RectTransform Box(Transform parent)
		{
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0051: 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_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Expected O, but got Unknown
			GameObject val = new GameObject("Box", new Type[2]
			{
				typeof(RectTransform),
				typeof(Image)
			});
			val.transform.SetParent(parent, false);
			((Graphic)val.GetComponent<Image>()).color = new Color(0.08f, 0.06f, 0.05f, 0.8f);
			((Shadow)val.AddComponent<Outline>()).effectColor = new Color(0f, 0f, 0f, 0.5f);
			return (RectTransform)val.transform;
		}
	}
}
namespace AutoVerk.Skills
{
	public sealed class BreakRock : Composite
	{
		private const int MaxTries = 3;

		private const float StandOff = 0.5f;

		private readonly Component _rock;

		private readonly Collider _part;

		public BreakRock(Component rock, Collider part = null)
		{
			_rock = rock;
			_part = part;
		}

		protected override IEnumerable<Step> Run()
		{
			if ((Object)(object)_rock == (Object)null)
			{
				yield break;
			}
			string name = Rocks.Name(_rock);
			int tier = Rocks.Tier(_rock);
			if (Senses.Pickaxe() == null)
			{
				yield return Composite.Fail("no_tool", "no pickaxe in the inventory");
			}
			ItemData pickaxe = Senses.Pickaxe(tier);
			if (pickaxe == null)
			{
				yield return Composite.Fail("no_tool", $"needs a tier {tier} pickaxe");
			}
			base.Status = "breaking " + name;
			yield return Composite.Do(new Equip(pickaxe));
			Vector3 position = ((Component)Senses.Player).transform.position;
			Vector3 val = Rocks.NearestSurface(Rocks.Colliders(_rock, _part), position);
			Vector3 val2 = position - val;
			val2.y = 0f;
			Result walk = Result.Success;
			if (((Vector3)(ref val2)).magnitude > 0.9f)
			{
				yield return Composite.Try(new MoveTo(val + ((Vector3)(ref val2)).normalized * 0.5f, 0.35f, run: false, name));
				walk = base.Last;
			}
			for (int i = 0; i < 3; i++)
			{
				if (!((Character)Senses.Player).HaveStamina(pickaxe.m_shared.m_attack.m_attackStamina))
				{
					yield return Composite.Try(new Rest());
				}
				yield return Composite.Try(new Mine(_rock, _part));
				if (base.Last.Code != "no_stamina")
				{
					break;
				}
			}
			if (base.Last.Code == "too_far" && walk.Failed)
			{
				yield return Composite.Fail(walk.Code, walk.Detail);
			}
			if (!base.Last.Ok && base.Last.Code != "gone")
			{
				yield return Composite.Fail(base.Last.Code, base.Last.Detail);
			}
		}

		public override string ToString()
		{
			return "break_rock " + Rocks.Name(_rock);
		}
	}
	internal static class Builtins
	{
		public static void Register()
		{
			Registry.Register(new SkillInfo
			{
				Id = "wait",
				Description = "Do nothing for some seconds.",
				Params = { Param.Number("seconds", "how long", 3.0) },
				Create = (Args args) => new Wait(args.Number("seconds")),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "move_to",
				Description = "Walk or run straight ahead some metres.",
				Params = 
				{
					Param.Number("ahead", "metres in front of you", 10.0),
					Param.Bool("run", "run instead of walking")
				},
				Create = (Args args) => new MoveTo(Ahead(args.Number("ahead")), 0.5f, args.Bool("run")),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "equip",
				Description = "Equip an item from the inventory.",
				Params = { Param.Item("item", "item id, like AxeStone") },
				Create = (Args args) => new Equip(args.Item("item")),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "rest",
				Description = "Stand still until stamina is full.",
				Create = (Args args) => new Rest(),
				ForDevelopers = true
			});
			SkillInfo skillInfo = new SkillInfo();
			skillInfo.Id = "strike";
			skillInfo.Description = "Swing the weapon in hand at the nearest enemy or tree in reach until it falls.";
			skillInfo.Params.Add(Param.Choice("target", "what to strike", "enemy", "tree"));
			skillInfo.Params.Add(Param.Number("radius", "metres", 4.0));
			skillInfo.Create = delegate(Args args)
			{
				float radius = args.Number("radius");
				return new Strike((Component)((args.Text("target") == "tree") ? ((object)Senses.Nearest<TreeBase>(radius, (Func<TreeBase, bool>)null)) : ((object)Senses.Nearest<Character>(radius, (Func<Character, bool>)Senses.IsEnemy))));
			};
			skillInfo.ForDevelopers = true;
			Registry.Register(skillInfo);
			Registry.Register(new SkillInfo
			{
				Id = "mine",
				Description = "Break the nearest rock in reach with the pickaxe in hand, one part of a big one.",
				Params = { Param.Number("radius", "metres", 4.0) },
				Create = (Args args) => new Mine(Rocks.Find(((Component)Senses.Player).transform.position, args.Number("radius"), out var part), part),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "place",
				Description = "Place a piece from the tool in hand a few metres ahead.",
				Params = 
				{
					Param.Text("piece", "piece id, like wood_floor"),
					Param.Number("ahead", "metres in front of you", 2.0)
				},
				Create = (Args args) => new Place(args.Text("piece"), Ahead(args.Number("ahead"))),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "collect",
				Title = "Pick up items",
				Doing = "Picking up",
				StartText = "Start picking up",
				Description = "Picks up the items lying around you: everything, or one kind.",
				Params = 
				{
					Param.Number("radius", "metres", 10.0).Shows("Radius", null, (FormValues _) => "metres around you"),
					Param.Item("item", "only this item, like Wood", "").WithSuggestions(() => from n in (from d in Senses.Around<ItemDrop>(30f)
							where !d.IsPiece()
							select Utils.GetPrefabName(((Component)d).gameObject)).Distinct()
						orderby n
						select n, "Anything").Shows("Item", null, (FormValues _) => "or one kind only")
				},
				Create = (Args args) => new Collect(args.Number("radius"), args.Item("item")),
				ForDevelopers = true
			});
			Registry.Register(new SkillInfo
			{
				Id = "gather",
				Title = "Gather plants",
				Doing = "Gathering",
				StartText = "Start gathering",
				StopNote = "Stop keeps what's gathered.",
				Description = "Picks what's ripe around you: everything you can plant, everything wild, or one kind.",
				Params = 
				{
					Param.Item("plants", "what the plants give, like Raspberry; @wild for every wild one", "").WithSuggestions(() => new string[1] { "@wild" }.Concat(PlantData.RipeAround(50f)), "Everything plantable").WithNames(Gather.What)
						.Shows("Plants", null, (FormValues v) => (!(v.Text("plants") == "")) ? ((!(v.Text("plants") == "@wild")) ? "only this kind" : "berries, mushrooms, thistle") : "crops and seeds"),
					Param.Number("radius", "metres", 20.0).Shows("Radius", null, (FormValues _) => "metres around you"),
					Param.Bool("loose", "Pick up stones and wood").Shows("Also", null, (FormValues _) => "lying around")
				},
				Summary = Gather.Summary,
				Create = (Args args) => new Gather(args.Item("plants"), args.Number("radius"), args.Bool("loose")),
				Preview = (Args args) => new Gather(args.Item("plants"), args.Number("radius"), args.Bool("loose")).Preview()
			});
			skillInfo = new SkillInfo();
			skillInfo.Id = "plant";
			skillInfo.Title = "Plant a field";
			skillInfo.Doing = "Planting";
			skillInfo.StartText = "Start planting";
			skillInfo.StopNote = "Stop keeps what's planted. You can fill the rest later.";
			skillInfo.Description = "Clears the ground, tills it with the Cultivator and sows your crop.";
			skillInfo.Params.Add(Param.Item("seed", "what to plant", "").WithSuggestions(PlantData.SeedsCarried).Shows("Seeds", "Crop", (FormValues v) => string.Format("{0} in your pack", Senses.Count(v.Item("seed"))))
				.ShownWhen(NewField));
			skillInfo.Params.Add(Param.Text("field", "or fill up a saved one", "").WithSuggestions(Fields.Names, "New field").Shows("Field", "Field", (FormValues v) => (!NewField(v)) ? "keeps its crop and size" : "or pick a saved one")
				.WithButton("Delete", (FormValues v) => Fields.Delete(v.Text("field")), (FormValues v) => !NewField(v), confirm: true, clears: true));
			skillInfo.Params.Add(Param.Number("count", "spots in a new field", 20.0).Shows("Spots", "Field", (FormValues _) => "plants in total").ShownWhen(NewField));
			skillInfo.Params.Add(Param.Number("line", "spots per line", 10.0).Shows("Per row", "Field", delegate(FormValues v)
			{
				int? num = PlantField.Rows(v);
				if (!num.HasValue)
				{
					return "";
				}
				int valueOrDefault = num.GetValueOrDefault();
				return string.Format("= {0} row{1}", valueOrDefault, (valueOrDefault == 1) ? "" : "s");
			}).ShownWhen(NewField));
			skillInfo.Params.Add(Param.Choice("layout", "how the lines sit", "staggered", "grid").Shows("Rows", "Field", (FormValues v) => (!(v.Text("layout") == "grid")) ? "every other row shifted half a spot" : "spots lined up across rows").ShownWhen(NewField));
			skillInfo.Params.Add(Param.Bool("stones", "Pick up loose stones", fallback: true).Shows("Stones", "Clear the ground first", (FormValues _) => "on each spot"));
			skillInfo.Params.Add(Param.Bool("rocks", "Break rocks in the way").Shows("Rocks", "Clear the ground first", (FormValues _) => "uses your pickaxe"));
			skillInfo.Summary = PlantField.Summary;
			skillInfo.Create = Plant;
			skillInfo.Preview = (Args args) => Plant(args).Preview();
			Registry.Register(skillInfo);
			Registry.Register(new FightBack());
		}

		private static bool NewField(FormValues v)
		{
			return v.Text("field") == "";
		}

		private static PlantField Plant(Args args)
		{
			return new PlantField(args.Item("seed"), args.Text("field"), (int)args.Number("count"), (int)args.Number("line"), args.Text("layout") == "staggered", args.Bool("stones"), args.Bool("rocks"));
		}

		private static Vector3 Ahead(float metres)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Player player = Senses.Player;
			return ((Component)player).transform.position + ((Component)player).transform.forward * metres;
		}
	}
	public sealed class Collect : Composite
	{
		private const int MaxDrops = 100;

		private readonly float _radius;

		private readonly HashSet<string> _items;

		private readonly HashSet<ItemDrop> _skipped = new HashSet<ItemDrop>();

		public Collect(float radius = 10f, string item = null)
			: this(radius, string.IsNullOrEmpty(item) ? null : new string[1] { item })
		{
		}

		public Collect(float radius, IEnumerable<string> items)
		{
			_radius = radius;
			_items = ((items != null) ? new HashSet<string>(items) : null);
		}

		private bool Wanted(ItemDrop d)
		{
			if (!d.IsPiece() && !_skipped.Contains(d))
			{
				if (_items != null)
				{
					return _items.Contains(Utils.GetPrefabName(((Component)d).gameObject));
				}
				return true;
			}
			return false;
		}

		private static int Carried()
		{
			return ((Humanoid)Senses.Player).GetInventory().GetAllItems().Sum((ItemData i) => i.m_stack);
		}

		protected override IEnumerable<Step> Run()
		{
			int before = Carried();
			base.Subject = string.Format("{0} · within {1:0} m", (_items == null) ? "Everything" : string.Join(", ", _items.Select(Senses.ItemName)), _radius);
			for (int i = 0; i < 100; i++)
			{
				SetFact("Picked up", (Carried() - before).ToString());
				if (_skipped.Count > 0)
				{
					SetFact("Skipped", _skipped.Count.ToString());
				}
				ItemDrop drop = Senses.Nearest<ItemDrop>(_radius, (Func<ItemDrop, bool>)Wanted);
				if ((Object)(object)drop == (Object)null)
				{
					break;
				}
				base.Status = "picking up " + Senses.ItemName(Utils.GetPrefabName(((Component)drop).gameObject));
				yield return Composite.Try(new MoveTo((Component)(object)drop, 1f));
				if (!((Object)(object)drop == (Object)null))
				{
					if (base.Last.Ok)
					{
						yield return Composite.Try(new Interact((Component)(object)drop));
					}
					if ((Object)(object)drop != (Object)null && !base.Last.Ok)
					{
						_skipped.Add(drop);
					}
				}
			}
			SetFact("Picked up", (Carried() - before).ToString());
			if (_skipped.Count > 0)
			{
				SetFact("Skipped", $"{_skipped.Count}, out of reach or too heavy");
			}
			base.Report = $"{Carried() - before} item(s) picked up" + ((_skipped.Count > 0) ? $", {_skipped.Count} skipped" : "");
		}

		public override string ToString()
		{
			if (_items != null)
			{
				return "collect " + string.Join(", ", _items);
			}
			return "collect";
		}
	}
	public sealed class FightBack : Reflex
	{
		public override string Description => "Fight back when a monster comes at you";

		public override Skill Check()
		{
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_007e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			Player player = Senses.Player;
			ItemData val = Senses.BestWeapon();
			if (val == null)
			{
				return null;
			}
			float attackRange = val.m_shared.m_attack.m_attackRange;
			foreach (BaseAI allInstance in BaseAI.GetAllInstances())
			{
				MonsterAI val2 = (MonsterAI)(object)((allInstance is MonsterAI) ? allInstance : null);
				if (val2 != null && (((BaseAI)val2).IsAlerted() || !((Object)(object)((BaseAI)val2).GetTargetCreature() != (Object)(object)player)))
				{
					Character component = ((Component)val2).GetComponent<Character>();
					if (Senses.IsEnemy(component) && Senses.FlatDistance(((Component)player).transform.position, Senses.NearestPoint((Component)(object)component, ((Component)player).transform.position)) <= attackRange)
					{
						return new Fight(component, val);
					}
				}
			}
			return null;
		}
	}
	public sealed class Fight : Composite
	{
		private readonly Character _enemy;

		private readonly ItemData _weapon;

		public Fight(Character enemy, ItemData weapon)
		{
			_enemy = enemy;
			_weapon = weapon;
		}

		protected override IEnumerable<Step> Run()
		{
			ItemData before = Senses.InHand();
			yield return Composite.Do(new Equip(_weapon));
			yield return Composite.Try(new Strike((Component)(object)_enemy));
			Result outcome = base.Last;
			if (before != null && before != _weapon)
			{
				yield return Composite.Try(new Equip(before));
			}
			base.Report = (outcome.Ok ? "it fell" : outcome.ToString());
		}

		public override string ToString()
		{
			return "fight " + (((Object)(object)_enemy != (Object)null) ? Utils.GetPrefabName(((Component)_enemy).gameObject) : "the monster");
		}
	}
}
namespace AutoVerk.Skills.Farm
{
	public sealed class ClearRocks : Composite
	{
		private const int MaxPasses = 200;

		private const int MaxTries = 3;

		private static readonly HashSet<string> Final = new HashSet<string> { "no_tool", "missed" };

		private readonly List<Vector3> _spots;

		private readonly float _radius;

		private readonly Dictionary<Collider, string> _skipped = new Dictionary<Collider, string>();

		private readonly Dictionary<Collider, string> _names = new Dictionary<Collider, string>();

		private readonly Dictionary<Collider, int> _tries = new Dictionary<Collider, int>();

		public ClearRocks(IEnumerable<Vector3> spots, float radius)
		{
			_spots = spots.ToList();
			_radius = radius;
		}

		protected override IEnumerable<Step> Run()
		{
			int broken = 0;
			for (int pass = 0; pass < 200; pass++)
			{
				Collider part;
				Component rock = Nearest(out part);
				if ((Object)(object)rock == (Object)null)
				{
					break;
				}
				string name = Rocks.Name(rock);
				_names[part] = name;
				if (Senses.Pickaxe() == null)
				{
					yield return Composite.Fail("no_tool", "no pickaxe in the inventory to break the " + name + "; take one, or uncheck rocks");
				}
				base.Status = $"breaking {name}, {broken} broken";
				yield return Composite.Try(new BreakRock(rock, part));
				if (base.Last.Ok)
				{
					broken++;
				}
				else
				{
					Refused(part, base.Last);
				}
				if (_skipped.ContainsKey(part) && Skips.IsWalk(base.Last))
				{
					Summarize(broken);
					yield return Composite.Fail(base.Last.Code, "can't get to the " + name + ": " + base.Last.Detail);
				}
				part = null;
			}
			Summarize(broken);
		}

		private void Summarize(int broken)
		{
			base.Report = string.Format("Broke {0} piece{1}", broken, (broken == 1) ? "" : "s") + ((_skipped.Count > 0) ? ("; left " + Skips.Grouped(_skipped, (Collider p) => _names[p])) : "");
		}

		private Component Nearest(out Collider part)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: 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_005e: Unknown result type (might be due to invalid IL or missing references)
			//IL_005f: Unknown result type (might be due to invalid IL or missing references)
			Component result = null;
			part = null;
			float num = float.MaxValue;
			Vector3 position = ((Component)Senses.Player).transform.position;
			foreach (Vector3 spot in _spots)
			{
				Collider part2;
				Component val = Rocks.Find(spot, _radius, out part2, _skipped.ContainsKey);
				if (!((Object)(object)val == (Object)null))
				{
					float num2 = Senses.FlatDistance(position, Rocks.ClosestPoint(part2, position));
					if (!(num2 >= num))
					{
						result = val;
						part = part2;
						num = num2;
					}
				}
			}
			return result;
		}

		private void Refused(Collider part, Result result)
		{
			_tries.TryGetValue(part, out var value);
			value = (_tries[part] = value + 1);
			if (Final.Contains(result.Code) || value >= 3)
			{
				_skipped[part] = Skips.Reason(result);
			}
		}

		public override string ToString()
		{
			return $"clear_rocks around {_spots.Count} spot(s)";
		}
	}
	public sealed class Field
	{
		public const int MaxCount = 999;

		private const double Start = 1.0;

		public string Name;

		public string Seed;

		public double X;

		public double Y;

		public double Z;

		public double ForwardX;

		public double ForwardZ;

		public int Count;

		public int LineLength;

		public double Spacing;

		public bool Staggered;

		public double LineSpacing
		{
			get
			{
				if (!Staggered)
				{
					return Spacing;
				}
				return Spacing * Math.Sqrt(3.0) / 2.0;
			}
		}

		public string Validate()
		{
			if (string.IsNullOrEmpty(Name))
			{
				return "no name";
			}
			if (string.IsNullOrEmpty(Seed))
			{
				return "no seed";
			}
			if (Count < 1 || Count > 999)
			{
				return $"count must be 1..{999}";
			}
			if (LineLength < 1)
			{
				return "line must be 1 or more";
			}
			if (!(Spacing > 0.2) || !(Spacing < 10.0))
			{
				return "spacing must be 0.2..10 m";
			}
			if (Math.Abs(Math.Sqrt(ForwardX * ForwardX + ForwardZ * ForwardZ) - 1.0) > 0.01)
			{
				return "forward must be unit length";
			}
			return null;
		}

		public List<Spot> Spots()
		{
			double forwardZ = ForwardZ;
			double num = 0.0 - ForwardX;
			int num2 = Math.Min(LineLength, Count);
			List<Spot> list = new List<Spot>(Count);
			for (int i = 0; i < Count; i++)
			{
				int num3 = i / num2;
				int num4 = i % num2;
				bool flag = num3 % 2 == 1;
				int num5 = (flag ? (num2 - 1 - num4) : num4);
				double num6 = 1.0 + (double)num5 * Spacing + ((Staggered && flag) ? (Spacing / 2.0) : 0.0);
				double num7 = (double)num3 * LineSpacing;
				double num8 = ((!flag) ? 1 : (-1));
				list.Add(new Spot
				{
					Index = i,
					X = X + ForwardX * num6 + forwardZ * num7,
					Z = Z + ForwardZ * num6 + num * num7,
					PathX = ForwardX * num8,
					PathZ = ForwardZ * num8
				});
			}
			return list;
		}

		public string ToLine()
		{
			return string.Join(" ", "field", "name=" + Name, "seed=" + Seed, "origin=" + N(X) + "," + N(Y) + "," + N(Z), "forward=" + N(ForwardX) + "," + N(ForwardZ), $"count={Count}", $"line={LineLength}", "spacing=" + N(Spacing), "layout=" + (Staggered ? "staggered" : "grid"));
		}

		public static Field FromLine(string line)
		{
			if (Args.ParseLine(line, out var values, out var _) != "field")
			{
				return null;
			}
			try
			{
				double[] array = Numbers(values["origin"]);
				double[] array2 = Numbers(values["forward"]);
				Field field = new Field
				{
					Name = values["name"],
					Seed = values["seed"],
					X = array[0],
					Y = array[1],
					Z = array[2],
					ForwardX = array2[0],
					ForwardZ = array2[1],
					Count = int.Parse(values["count"], CultureInfo.InvariantCulture),
					LineLength = int.Parse(values["line"], CultureInfo.InvariantCulture),
					Spacing = double.Parse(values["spacing"], CultureInfo.InvariantCulture),
					Staggered = (values["layout"] == "staggered")
				};
				return (field.Validate() == null) ? field : null;
			}
			catch (Exception ex) when (ex is KeyNotFoundException || ex is FormatException || ex is IndexOutOfRangeException)
			{
				return null;
			}
		}

		private static double[] Numbers(string text)
		{
			return (from s in text.Split(new char[1] { ',' })
				select double.Parse(s, CultureInfo.InvariantCulture)).ToArray();
		}

		private static string N(double d)
		{
			return d.ToString("0.###", CultureInfo.InvariantCulture);
		}
	}
	public struct Spot
	{
		public int Index;

		public double X;

		public double Z;

		public double PathX;

		public double PathZ;
	}
	public sealed class FieldBook
	{
		public List<Field> Fields = new List<Field>();

		public Field Find(string name)
		{
			return Fields.FirstOrDefault((Field f) => string.Equals(f.Name, name, StringComparison.OrdinalIgnoreCase));
		}

		public string ToText()
		{
			return string.Join("\n", Fields.Select((Field f) => f.ToLine())) + "\n";
		}

		public static FieldBook FromText(string text)
		{
			FieldBook fieldBook = new FieldBook();
			fieldBook.Fields = (from f in (text ?? "").Split(new char[1] { '\n' }).Select(Field.FromLine)
				where f != null
				select f).ToList();
			return fieldBook;
		}

		public string NextName(string crop)
		{
			string text = (crop ?? "field").ToLowerInvariant();
			if (!text.EndsWith("s"))
			{
				text += "s";
			}
			int num = 0;
			foreach (Field field in Fields)
			{
				if (field.Name.StartsWith(text + "-", StringComparison.OrdinalIgnoreCase) && int.TryParse(field.Name.Substring(text.Length + 1), NumberStyles.None, CultureInfo.InvariantCulture, out var result))
				{
					num = Math.Max(num, result);
				}
			}
			return $"{text}-{num + 1}";
		}
	}
	public static class Fields
	{
		private static string Folder => Path.Combine(Paths.ConfigPath, "AutoVerk");

		private static string WorldName
		{
			get
			{
				if (!((Object)(object)ZNet.instance != (Object)null))
				{
					return null;
				}
				return ZNet.instance.GetWorldName();
			}
		}

		private static string PathFor(string world)
		{
			return Path.Combine(Folder, new string(world.Select((char c) => (!char.IsLetterOrDigit(c) && c != '-' && c != '_') ? '_' : c).ToArray()) + ".fields.txt");
		}

		public static FieldBook Load(out string error)
		{
			error = null;
			string worldName = WorldName;
			if (worldName == null)
			{
				error = "not in a world";
				return null;
			}
			string text = PathFor(worldName);
			try
			{
				return File.Exists(text) ? FieldBook.FromText(File.ReadAllText(text)) : new FieldBook();
			}
			catch (Exception ex)
			{
				error = "can't read " + text + ": " + ex.Message;
				return null;
			}
		}

		public static void Save(FieldBook book)
		{
			string world = WorldName ?? throw new InvalidOperationException("not in a world");
			Directory.CreateDirectory(Folder);
			string text = PathFor(world);
			string text2 = text + ".tmp";
			File.WriteAllText(text2, book.ToText());
			if (File.Exists(text))
			{
				File.Replace(text2, text, null);
			}
			else
			{
				File.Move(text2, text);
			}
		}

		public static string Delete(string name)
		{
			string error;
			FieldBook fieldBook = Load(out error);
			if (fieldBook == null)
			{
				return error;
			}
			Field field = fieldBook.Find(name);
			if (field == null)
			{
				return "no field " + name + " in this world";
			}
			fieldBook.Fields.Remove(field);
			Save(fieldBook);
			return "Deleted the field " + name + "; its plants stay.";
		}

		public static IEnumerable<string> Names()
		{
			string error;
			return Load(out error)?.Fields.Select((Field f) => f.Name) ?? Enumerable.Empty<string>();
		}

		public static Field LayOut(string name, PlantData plant, int count, int lineLength, bool staggered)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: 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_0051: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			Transform transform = ((Component)Senses.Player).transform;
			Vector3 forward = transform.forward;
			forward.y = 0f;
			((Vector3)(ref forward)).Normalize();
			return new Field
			{
				Name = name,
				Seed = plant.Seed,
				X = transform.position.x,
				Y = transform.position.y,
				Z = transform.position.z,
				ForwardX = forward.x,
				ForwardZ = forward.z,
				Count = count,
				LineLength = lineLength,
				Spacing = plant.MinSpacing,
				Staggered = staggered
			};
		}

		public static Vector3 Ground(Field field, Spot spot)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = default(Vector3);
			((Vector3)(ref val))..ctor((float)spot.X, (float)field.Y, (float)spot.Z);
			if ((Object)(object)ZoneSystem.instance != (Object)null)
			{
				val.y = ZoneSystem.instance.GetGroundHeight(val);
			}
			return val;
		}
	}
	public sealed class Gather : Composite
	{
		private const int MaxPlants = 300;

		public const string Wild = "@wild";

		private readonly string _item;

		private readonly float _radius;

		private readonly bool _loose;

		private readonly HashSet<Pickable> _skipped = new HashSet<Pickable>();

		private readonly Dictionary<Pickable, string> _reasons = new Dictionary<Pickable, string>();

		public Gather(string item, float radius, bool loose = false)
		{
			_item = (string.IsNullOrEmpty(item) ? null : item);
			_radius = radius;
			_loose = loose;
		}

		private static bool Matches(Pickable p, string item, bool loose)
		{
			if ((Object)(object)p?.m_itemPrefab == (Object)null || !PlantData.Reachable((Component)(object)p))
			{
				return false;
			}
			if (loose && PlantData.IsLoose(p))
			{
				return true;
			}
			if (item == null)
			{
				if (p.CanBePicked())
				{
					return PlantData.IsPlantable(p);
				}
				return false;
			}
			if (item == "@wild")
			{
				return PlantData.IsWild(p);
			}
			if (PlantData.IsRipePlant(p))
			{
				return PlantData.Yield(p) == item;
			}
			return false;
		}

		private bool Wanted(Pickable p)
		{
			if (!_skipped.Contains(p))
			{
				return Matches(p, _item, _loose);
			}
			return false;
		}

		private static int Carried(string item)
		{
			return Senses.Count(item);
		}

		public static string What(string item)
		{
			if (!string.IsNullOrEmpty(item))
			{
				if (!(item == "@wild"))
				{
					return Senses.ItemName(item);
				}
				return "Everything wild";
			}
			return "Everything plantable";
		}

		protected override IEnumerable<Step> Run()
		{
			base.Subject = string.Format("{0}{1} · within {2:0} m", What(_item), _loose ? ", stones and wood" : "", _radius);
			base.AgainLine = string.Format("gather plants=\"{0}\" radius={1:0} loose={2}", _item ?? "", _radius, _loose ? "yes" : "no");
			base.AgainLabel = "Gather again";
			Dictionary<string, int> before = new Dictionary<string, int>();
			bool full = false;
			for (int i = 0; i < 300; i++)
			{
				SetFact("Gathered", Total(before).ToString());
				SetFact("Left", Senses.Around<Pickable>(_radius).Count(Wanted).ToString());
				if (_skipped.Count > 0)
				{
					SetFact("Skipped", _skipped.Count.ToString());
				}
				Pickable plant = Senses.Nearest<Pickable>(_radius, (Func<Pickable, bool>)Wanted);
				if ((Object)(object)plant == (Object)null)
				{
					break;
				}
				string text = PlantData.Yield(plant);
				string text2 = Senses.ItemName(text);
				if (!((Humanoid)Senses.Player).GetInventory().CanAddItem(plant.m_itemPrefab, plant.m_amount))
				{
					full = true;
					break;
				}
				if (!before.ContainsKey(text))
				{
					before[text] = Carried(text);
				}
				base.Status = (PlantData.IsLoose(plant) ? ("picking up " + text2) : ("gathering " + text2));
				yield return Composite.Try(new MoveTo((Component)(object)plant));
				if (base.Last.Ok && (Object)(object)plant != (Object)null)
				{
					yield return Composite.Try(new Interact((Component)(object)plant));
				}
				if ((Object)(object)plant != (Object)null && !base.Last.Ok)
				{
					_skipped.Add(plant);
					_reasons[plant] = Skips.Reason(base.Last);
				}
			}
			HashSet<string> hashSet = new HashSet<string>(before.Keys);
			if (_loose)
			{
				hashSet.UnionWith(PlantData.LooseItems);
			}
			if (!full && hashSet.Count > 0)
			{
				foreach (string item in hashSet.Where((string k) => !before.ContainsKey(k)).ToList())
				{
					before[item] = Carried(item);
				}
				base.Status = "picking up what's on the ground";
				yield return Composite.Try(new Collect(_radius, hashSet));
			}
			ClearFacts();
			int num = Total(before);
			SetFact("Gathered", (num == 0) ? "nothing" : string.Format("{0}: {1}", num, string.Join(", ", from k in before.Keys
				where Carried(k) > before[k]
				select $"{Senses.ItemName(k)} {Carried(k) - before[k]}")));
			if (_skipped.Count > 0)
			{
				SetFact("Skipped", string.Join(", ", from r in _reasons.Values
					group r by r into g
					select $"{g.Count()} {g.Key}"));
			}
			base.Headline = (full ? "Stopped: your pack is full" : ((num == 0 && _skipped.Count == 0) ? "Nothing ripe here" : null));
			base.Advice = (full ? "Empty your pack, then gather again." : null);
			base.Report = string.Join(" · ", new string[1] { base.Headline }.Where((string h) => h != null).Concat(base.Facts.Select((KeyValuePair<string, string> f) => f.Key + ": " + f.Value)));
		}

		private static int Total(Dictionary<string, int> before)
		{
			return before.Sum((KeyValuePair<string, int> b) => Math.Max(0, Carried(b.Key) - b.Value));
		}

		public string Preview()
		{
			//IL_0050: 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_0059: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cd: Unknown result type (might be due to invalid IL or missing references)
			Markers.Hide();
			List<Pickable> list = Senses.Around<Pickable>(_radius).Where(Wanted).ToList();
			int num = 0;
			foreach (Pickable item in list)
			{
				bool flag = PlantData.IsLoose(item);
				if (flag)
				{
					num++;
				}
				Markers.Pole(((Component)item).transform.position, flag ? Markers.Clear : Markers.Free, Utils.GetPrefabName(((Component)item).gameObject));
			}
			if (list.Count == 0)
			{
				return "Nothing ripe to gather here";
			}
			return $"<color=#{ColorUtility.ToHtmlStringRGB(Markers.Free)}>{list.Count - num} plants</color>" + ((num > 0) ? $" · <color=#{ColorUtility.ToHtmlStringRGB(Markers.Clear)}>{num} stones and branches</color>" : "");
		}

		public static FormSummary Summary(FormValues v)
		{
			string item = v.Item("plants");
			item = ((item == "") ? null : item);
			float valueOrDefault = v.Number("radius").GetValueOrDefault();
			bool loose = v.Bool("loose");
			List<Pickable> list = (from p in Senses.Around<Pickable>(valueOrDefault)
				where Matches(p, item, loose)
				select p).ToList();
			int num = list.Count(PlantData.IsLoose);
			string text = $"{list.Count - num} × {What(item)}" + (loose ? $" · {num} stones and branches" : "") + $" · within {valueOrDefault:0} m";
			string warning = null;
			if (list.Count == 0)
			{
				warning = "Nothing ripe to gather here";
			}
			else if (!((Humanoid)Senses.Player).GetInventory().CanAddItem(list[0].m_itemPrefab, list[0].m_amount))
			{
				warning = "Your pack is full";
			}
			return new FormSummary
			{
				Text = text,
				Warning = warning
			};
		}

		public override string ToString()
		{
			if (_item != null)
			{
				return "gather " + _item;
			}
			return "gather";
		}
	}
	public sealed class PlantData
	{
		private static readonly Dictionary<string, PlantData> Cache = new Dictionary<string, PlantData>(StringComparer.OrdinalIgnoreCase);

		private static HashSet<string> _cropPrefabs;

		private static ZNetScene _cachedFor;

		private const float LightHerb = 0.5f;

		public static readonly HashSet<string> LooseItems = new HashSet<string> { "Stone", "Wood" };

		public string Seed { get; private set; }

		public string Sapling { get; private set; }

		public string Crop { get; private set; }

		public float GrowRadius { get; private set; }

		public float MinSpacing { get; private set; }

		public HashSet<string> Grown { get; private set; }

		public static PlantData ForSeed(string seed)
		{
			if (string.IsNullOrEmpty(seed) || !Fresh())
			{
				return null;
			}
			if (Cache.TryGetValue(seed, out var value))
			{
				return value;
			}
			PlantData plantData = null;
			foreach (GameObject prefab in ZNetScene.instance.m_prefabs)
			{
				Plant val = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Plant>() : null);
				Piece val2 = (((Object)(object)prefab != (Object)null) ? prefab.GetComponent<Piece>() : null);
				if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
				{
					continue;
				}
				Requirement val3 = ((IEnumerable<Requirement>)val2.m_resources).FirstOrDefault((Func<Requirement, bool>)((Requirement r) => (Object)(object)r.m_resItem != (Object)null && string.Equals(((Object)((Component)r.m_resItem).gameObject).name, seed, StringComparison.OrdinalIgnoreCase)));
				if (val3 != null)
				{
					GameObject[] source = val.m_grownPrefabs.Where((GameObject g) => (Object)(object)g != (Object)null).ToArray();
					Pickable val4 = source.Select((GameObject g) => g.GetComponent<Pickable>()).FirstOrDefault((Func<Pickable, bool>)((Pickable p) => (Object)(object)p != (Object)null && (Object)(object)p.m_itemPrefab != (Object)null));
					float num = Mathf.Max(Reach(prefab), source.Select(Reach).DefaultIfEmpty(0f).Max());
					plantData = new PlantData
					{
						Seed = ((Object)((Component)val3.m_resItem).gameObject).name,
						Sapling = ((Object)prefab).name,
						Crop = (((Object)(object)val4 != (Object)null) ? ((Object)val4.m_itemPrefab).name : ((Object)((Component)val3.m_resItem).gameObject).name),
						GrowRadius = val.m_growRadius,
						MinSpacing = Mathf.Ceil((val.m_growRadius + num) * 20f) / 20f,
						Grown = new HashSet<string>(source.Select((GameObject g) => ((Object)g).name))
					};
					break;
				}
			}
			Cache[seed] = plantData;
			return plantData;
		}

		public static IEnumerable<string> SeedsCarried()
		{
			if ((Object)(object)Senses.Player == (Object)null)
			{
				return Enumerable.Empty<string>();
			}
			return (from id in (from id in ((Humanoid)Senses.Player).GetInventory().GetAllItems().Select(Senses.ItemId)
					where id != null
					select id).Distinct()
				where ForSeed(id) != null
				orderby id
				select id).ToList();
		}

		public static bool IsCrop(string prefab)
		{
			if (prefab == null || !Fresh())
			{
				return false;
			}
			if (_cropPrefabs == null)
			{
				_cropPrefabs = new HashSet<string>();
				foreach (GameObject prefab2 in ZNetScene.instance.m_prefabs)
				{
					Plant val = (((Object)(object)prefab2 != (Object)null) ? prefab2.GetComponent<Plant>() : null);
					if ((Object)(object)val == (Object)null)
					{
						continue;
					}
					GameObject[] grownPrefabs = val.m_grownPrefabs;
					foreach (GameObject val2 in grownPrefabs)
					{
						if ((Object)(object)val2 != (Object)null && (Object)(object)val2.GetComponent<Pickable>() != (Object)null)
						{
							_cropPrefabs.Add(((Object)val2).name);
						}
					}
				}
			}
			return _cropPrefabs.Contains(prefab);
		}

		public static bool IsRipePlant(Pickable p)
		{
			if ((Object)(object)p != (Object)null && (Object)(object)p.m_itemPrefab != (Object)null && p.CanBePicked())
			{
				if (!IsPlantable(p))
				{
					retu