Decompiled source of GK2 Zombie PlusPlus v0.1.0

GK2ZombiePlusPlus.dll

Decompiled 21 hours ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using GK2.Framework;
using HarmonyLib;
using LazyBearTechnology;
using Microsoft.CodeAnalysis;
using Pathfinding;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.AddressableAssets.ResourceLocators;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

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

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GK2ZombiePlusPlus
{
	internal static class Chores
	{
		private static readonly HashSet<string> HiveIds = new HashSet<string> { "honey_home", "honey_wild" };

		private static readonly HashSet<string> HarvestItems = new HashSet<string> { "honey", "beeswax", "apple", "berry", "berry_blue", "flower_rhod", "fireflight", "fertilizer:peat" };

		internal const string Leaf = "leaf";

		private static readonly FieldRef<WorldZoneData, List<OrderBase>> ZoneOrders = AccessTools.FieldRefAccess<WorldZoneData, List<OrderBase>>("orders");

		private static List<Item> _capture;

		private static readonly FieldInfo CurScene = AccessTools.Field(AccessTools.TypeByName("PlayerController"), "currentGameScene");

		private static readonly PropertyInfo PlayerCtl = AccessTools.Property(typeof(MainGame), "PlayerController");

		private static int _readyTicks;

		private static ZombieWgoData _collector;

		private static readonly FieldRef<ZombieWgoData, SGuid> GardenerTarget = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("gardenerCurrentTargetUniqueId");

		private static readonly MethodInfo GardenerArrived = AccessTools.Method(typeof(ZombieWgoData), "GardenerOnPathSuccess", (Type[])null, (Type[])null);

		private static readonly FieldRef<ZombieWgoData, SGuid> GardenerMoveTarget = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("gardenerCurrentMovementTargetUniqueId");

		private static readonly FieldRef<ZombieWgoData, SGuid> GardenerStationId = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("gardenerStation");

		private static readonly FieldRef<ZombieWgoData, ZombieGardenerState> GardenerPrevState = AccessTools.FieldRefAccess<ZombieWgoData, ZombieGardenerState>("gardenerPreviousState");

		private static readonly FieldRef<ZombieWgoData, float> GardenerRetryTimer = AccessTools.FieldRefAccess<ZombieWgoData, float>("gardenerTimeForCheckFailedPathAgain");

		private static readonly HashSet<Guid> OffRoad = new HashSet<Guid>();

		private static readonly Dictionary<Guid, int> WalkFails = new Dictionary<Guid, int>();

		private const int MaxWalkFails = 3;

		private static bool _hpTickWarned;

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

		private static readonly FieldRef<ZombieWgoData, Inventory> PorterInv = AccessTools.FieldRefAccess<ZombieWgoData, Inventory>("porterInventory");

		public static void TickPost()
		{
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Invalid comparison between Unknown and I4
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Invalid comparison between Unknown and I4
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			try
			{
				if (!IsHostOrSolo() || !SceneReady())
				{
					return;
				}
				ZombieSystemData zombieSystemData = MainGame.ZombieSystemData;
				if (zombieSystemData == null || MainGame.WorldData == null)
				{
					return;
				}
				Dictionary<WorldZoneData, List<ZombieWgoData>> dictionary = new Dictionary<WorldZoneData, List<ZombieWgoData>>();
				Dictionary<WorldZoneData, List<ZombieWgoData>> dictionary2 = new Dictionary<WorldZoneData, List<ZombieWgoData>>();
				List<ZombieWgoData> list = new List<ZombieWgoData>();
				foreach (SGuid item in new List<SGuid>(zombieSystemData.zombieOnSceneWgoIds))
				{
					ZombieWgoData zombie = zombieSystemData.GetZombie(item);
					WorldZoneData val = ((zombie != null) ? ((WgoData)zombie).WorldZoneData : null);
					if (val == null)
					{
						continue;
					}
					list.Add(zombie);
					Dictionary<WorldZoneData, List<ZombieWgoData>> dictionary3 = (((int)zombie.ZombieType == 2) ? dictionary : (((int)zombie.ZombieType == 6 && HasShovel(zombie)) ? dictionary2 : null));
					if (dictionary3 != null)
					{
						if (!dictionary3.TryGetValue(val, out var value))
						{
							value = (dictionary3[val] = new List<ZombieWgoData>());
						}
						value.Add(zombie);
					}
				}
				Errands.Watch(list);
				Errands.DescribeGardeners(list);
				bool value2 = Plugin.GardenerCompost.Value;
				bool value3 = Plugin.HelperCollects.Value;
				foreach (KeyValuePair<WorldZoneData, List<ZombieWgoData>> item2 in dictionary)
				{
					bool flag = value2 && !dictionary2.ContainsKey(item2.Key);
					if (value3 || flag)
					{
						Errands.Helpers(item2.Key, item2.Value, value3, flag);
					}
				}
				foreach (KeyValuePair<WorldZoneData, List<ZombieWgoData>> item3 in dictionary2)
				{
					if (value2)
					{
						Errands.Compost(item3.Key, item3.Value);
					}
					PlaceHarvestOrders(item3.Key, item3.Value);
				}
				Notify.Tick(list);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Tick failed: " + ex));
			}
		}

		private static bool SceneReady()
		{
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_0018: Invalid comparison between Unknown and I4
			bool flag = false;
			try
			{
				MainGame instance = MainGame.Instance;
				object obj = ((!((Object)(object)instance != (Object)null) || (int)instance.gameState != 1) ? null : PlayerCtl?.GetValue(null));
				flag = obj != null && (CurScene == null || CurScene.GetValue(obj) != null);
			}
			catch
			{
			}
			if (!flag)
			{
				_readyTicks = 0;
				return false;
			}
			return ++_readyTicks >= 2;
		}

		private static bool IsHostOrSolo()
		{
			try
			{
				return !LazyNetwork.IsInitialized || !LazyNetwork.NetworkManager.IsCoopGame || LazyNetwork.NetworkManager.IsHost;
			}
			catch
			{
				return true;
			}
		}

		private static bool HasShovel(ZombieWgoData z)
		{
			//IL_0020: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			Item hand = z.Hand;
			if (hand != null && !hand.IsEmpty && ((ObjectLinkedToDefinition<ItemDef>)(object)hand).Definition != null)
			{
				return (int)((ObjectLinkedToDefinition<ItemDef>)(object)hand).Definition.type == 2;
			}
			return false;
		}

		internal static IEnumerable<WgoData> ZoneObjects(WorldZoneData zone)
		{
			foreach (SGuid item in new List<SGuid>(zone.wgoDataList))
			{
				WgoData wgoData = MainGame.WorldData.GetWgoData(item);
				if (wgoData != null && ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).Definition != null)
				{
					yield return wgoData;
				}
			}
		}

		internal static bool IsCompost(WgoData w)
		{
			if (((ObjectLinkedToDefinition<WGODef>)(object)w).id != null)
			{
				return ((ObjectLinkedToDefinition<WGODef>)(object)w).id.StartsWith("compost_pile");
			}
			return false;
		}

		internal static List<Item> FinishCraft(WgoData w, ZombieWgoData by)
		{
			List<Item> result = (_capture = new List<Item>());
			_collector = by;
			try
			{
				w.ProcessReadyToFinishCraft();
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("finishing " + ((ObjectLinkedToDefinition<WGODef>)(object)w).id + " threw, keeping what came out: " + ex.Message));
			}
			finally
			{
				_capture = null;
				_collector = null;
			}
			return result;
		}

		public static bool DropTechPre(WgoData __instance)
		{
			ZombieWgoData collector = _collector;
			if (collector == null || _capture == null)
			{
				return true;
			}
			try
			{
				int gameResInt = __instance.GetGameResInt("game_res_tech_red");
				int gameResInt2 = __instance.GetGameResInt("game_res_tech_green");
				int gameResInt3 = __instance.GetGameResInt("game_res_tech_blue");
				__instance.SetGameRes("game_res_tech_red", 0);
				__instance.SetGameRes("game_res_tech_green", 0);
				__instance.SetGameRes("game_res_tech_blue", 0);
				if (gameResInt + gameResInt2 + gameResInt3 > 0)
				{
					collector.DoTechPointsReward(__instance, gameResInt, gameResInt2, gameResInt3);
					if (Plugin.Verbose.Value)
					{
						Plugin.Log.LogInfo((object)("tech points from " + ((ObjectLinkedToDefinition<WGODef>)(object)__instance).id + " to the zombie: " + gameResInt + "/" + gameResInt2 + "/" + gameResInt3));
					}
				}
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("tech points: " + ex.Message));
				return true;
			}
		}

		public static bool MakeDropPre(Item item)
		{
			if (_capture == null || item == null || item.IsEmpty)
			{
				return true;
			}
			_capture.Add(item);
			return false;
		}

		internal static void Store(List<Inventory> inventories, Item item)
		{
			int num = 0;
			while (item.Count > 0 && num < 64)
			{
				Inventory val = null;
				foreach (Inventory inventory in inventories)
				{
					if (((inventory != null) ? inventory.Data : null) != null && inventory.Data.CanAddItemCountToInventory(item, true, (Item)null, false) > 0)
					{
						if (inventory.Data.HasItemByItemId(((ObjectLinkedToDefinition<ItemDef>)(object)item).id, 1))
						{
							val = inventory;
							break;
						}
						if (val == null)
						{
							val = inventory;
						}
					}
				}
				if (val == null)
				{
					break;
				}
				if (((ObjectLinkedToDefinition<ItemDef>)(object)item).Definition.stackCount == 1 || val.Data.CanAddItemCountToInventory(item, true, (Item)null, false) >= item.Count)
				{
					int count = item.Count;
					val.AddItemToInventory(item, (Item)null, false);
					if (count - item.Count <= 0)
					{
						break;
					}
				}
				else
				{
					int num2 = Math.Min(val.Data.CanAddItemCountToInventory(item, true, (Item)null, false), item.Count);
					if (num2 <= 0)
					{
						break;
					}
					Item val2 = item.Split(num2, false);
					val.AddItemToInventory(val2, (Item)null, false);
					int num3 = num2 - val2.Count;
					if (val2.Count > 0)
					{
						item.Count += val2.Count;
					}
					if (num3 <= 0)
					{
						break;
					}
				}
				num++;
			}
		}

		internal static string ZoneName(WgoData w)
		{
			try
			{
				return ((BalanceBaseObject)(((ObjectLinkedToDefinition<WorldZoneDef>)(object)w.WorldZoneData)?.Definition?)).id ?? "?";
			}
			catch
			{
				return "?";
			}
		}

		internal static CraftDefBase CompostCanStart(WgoData w, MultiInventory chests)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Invalid comparison between Unknown and I4
			CraftComponent craftComponent = w.CraftComponent;
			if (craftComponent == null || craftComponent.IsStarted || craftComponent.HasCraftsInQueue || craftComponent.IsDestroyingCraftActive || (int)craftComponent.Status == 7)
			{
				return null;
			}
			CraftDefBase val = null;
			List<CraftDefBase> availableCrafts = craftComponent.AvailableCrafts;
			if (availableCrafts != null)
			{
				foreach (CraftDefBase item in availableCrafts)
				{
					if (item != null && item.isAuto)
					{
						val = item;
						break;
					}
				}
			}
			if (val == null || chests == null || chests.inventoryList.Count == 0)
			{
				return null;
			}
			int num = 0;
			foreach (NeedItemData needItem in val.needItems)
			{
				if (needItem.id == "leaf")
				{
					num += needItem.GetCount(w);
				}
			}
			if (num > 0 && chests.GetTotalCount("leaf") - Plugin.CompostKeepLeaves.Value < num)
			{
				return null;
			}
			return val;
		}

		private static bool IsHarvestTarget(WgoData w)
		{
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Invalid comparison between Unknown and I4
			WGODef definition = ((ObjectLinkedToDefinition<WGODef>)(object)w).Definition;
			if (definition == null || (int)definition.interactionType != 1)
			{
				return false;
			}
			if (HiveIds.Contains(((ObjectLinkedToDefinition<WGODef>)(object)w).id))
			{
				return Plugin.GardenerHives.Value;
			}
			if (((ObjectLinkedToDefinition<WGODef>)(object)w).id.StartsWith("tree_apple_"))
			{
				return Plugin.GardenerTreesBushes.Value;
			}
			if (definition.wgoGroup == "collectable_bushes")
			{
				return Plugin.GardenerTreesBushes.Value;
			}
			return false;
		}

		private static void PlaceHarvestOrders(WorldZoneData zone, List<ZombieWgoData> gardeners)
		{
			//IL_0198: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a2: Expected O, but got Unknown
			foreach (WgoData item in ZoneObjects(zone))
			{
				if (Plugin.Verbose.Value && ((ObjectLinkedToDefinition<WGODef>)(object)item).id != null && ((ObjectLinkedToDefinition<WGODef>)(object)item).id.EndsWith("_ready") && (((ObjectLinkedToDefinition<WGODef>)(object)item).id.StartsWith("garden_") || ((ObjectLinkedToDefinition<WGODef>)(object)item).id.StartsWith("vineyard_")) && zone.FindOrdersByTarget(item.UniqueId, typeof(GatherOrder)).Count == 0)
				{
					Why(item, "ripe bed with no crop sign on it: the game gives gardeners no order for it (put the crop's sign on the bed)");
				}
				if (!IsHarvestTarget(item))
				{
					continue;
				}
				if (item.HpComponent == null || item.HpComponent.Hp <= 0)
				{
					if (Plugin.Verbose.Value)
					{
						Why(item, "nothing to take yet (hp " + ((item.HpComponent == null) ? "none" : item.HpComponent.Hp.ToString()) + ")");
					}
				}
				else if (!AnyCanHarvest(gardeners, item))
				{
					if (!Plugin.Verbose.Value)
					{
						continue;
					}
					int val = 0;
					foreach (ZombieWgoData gardener in gardeners)
					{
						val = Math.Max(val, gardener.GetMasteryLevelForTalentBranch("talent_green", (CraftDefBase)null));
					}
					Why(item, "ready, but no gardener here has the green talent for it (best " + val + ")");
				}
				else if (zone.FindOrdersByTarget(item.UniqueId, typeof(GatherOrder)).Count <= 0)
				{
					zone.PlaceNewOrder((OrderBase)new GatherOrder(item.UniqueId, Item.Empty));
					if (Plugin.Verbose.Value)
					{
						Plugin.Log.LogInfo((object)("gather order for " + ((ObjectLinkedToDefinition<WGODef>)(object)item).id + " in " + ZoneName(item)));
					}
				}
			}
		}

		public static bool GardenerMovePre(ZombieWgoData __instance)
		{
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Invalid comparison between Unknown and I4
			//IL_025a: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value || GardenerArrived == null)
			{
				return true;
			}
			try
			{
				Guid guid = ((WgoData)__instance).UniqueId.Guid;
				SGuid val = GardenerTarget.Invoke(__instance);
				WgoData val2 = ((val == (SGuid)null) ? null : MainGame.WorldData.GetWgoData(val));
				if (val2 == null)
				{
					return true;
				}
				bool flag = IsHarvestTarget(val2) || Errands.IsGardenerErrand(__instance, val2);
				if (!flag && !OffRoad.Contains(guid))
				{
					return true;
				}
				if ((int)__instance.GardenerState == 8)
				{
					if (GardenerRetryTimer.Invoke(__instance) > 0f)
					{
						return false;
					}
					GardenerRetryTimer.Invoke(__instance) = 0f;
					__instance.GardenerState = GardenerPrevState.Invoke(__instance);
					WalkFails.TryGetValue(guid, out var value);
					value = (WalkFails[guid] = value + 1);
					if (value == 2 && flag)
					{
						if (Plugin.Verbose.Value)
						{
							Plugin.Log.LogInfo((object)("gardener finds no path to " + ((ObjectLinkedToDefinition<WGODef>)(object)val2).id + ", walks straight"));
						}
						if (((WgoData)__instance).MovementComponent.IsMoving)
						{
							((WgoData)__instance).MovementComponent.ForceStop();
						}
						if (StartWalk(__instance, val2, val, (Graph)(-1)))
						{
							return false;
						}
					}
					if (value >= 3)
					{
						Plugin.Log.LogWarning((object)("gardener can't walk to " + ((ObjectLinkedToDefinition<WGODef>)(object)val2).id + " in " + ZoneName(val2) + ", working it from where it stands"));
						OffRoad.Remove(guid);
						WalkFails.Remove(guid);
						if (!flag)
						{
							return true;
						}
						if (((WgoData)__instance).MovementComponent.IsMoving)
						{
							((WgoData)__instance).MovementComponent.ForceStop();
						}
						GardenerArrived.Invoke(__instance, null);
						return false;
					}
				}
				else
				{
					SGuid obj = GardenerMoveTarget.Invoke(__instance);
					if (((obj != null) ? new Guid?(obj.Guid) : ((Guid?)null)) == val.Guid)
					{
						return false;
					}
				}
				if (((WgoData)__instance).MovementComponent.IsMoving)
				{
					((WgoData)__instance).MovementComponent.ForceStop();
				}
				StartWalk(__instance, val2, val, WalkGraph(((WgoData)__instance).WorldZoneData));
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Gardener move: " + ex.Message));
				return true;
			}
		}

		private unsafe static bool StartWalk(ZombieWgoData z, WgoData target, SGuid targetId, Graph graph)
		{
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Invalid comparison between Unknown and I4
			//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_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: 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_009f: 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_00a4: Invalid comparison between Unknown and I4
			//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e6: Invalid comparison between Unknown and I4
			SGuid obj = GardenerStationId.Invoke(z);
			bool toStation = ((obj != null) ? new Guid?(obj.Guid) : ((Guid?)null)) == targetId.Guid;
			Vector3 val = WalkEnd(z, target, toStation);
			StartPathResult val2 = (((int)graph != -1) ? ((WgoData)z).MovementComponent.StartPath(val, graph, ((WgoData)z).WorldId, 1.5f, "", (Action)null, (DestinationType)0) : ((WgoData)z).MovementComponent.StartPath(val, ((WgoData)z).WorldId, ((WgoData)z).WorldId, (MovementType)1, 1.5f, "", (Action)null, (Seeker)null, (DestinationType)0));
			if ((int)val2 != 0)
			{
				if ((int)val2 == 1)
				{
					GardenerArrived.Invoke(z, null);
					return true;
				}
				GardenerRetryTimer.Invoke(z) = 1f;
				z.GardenerState = (ZombieGardenerState)8;
				return false;
			}
			GardenerMoveTarget.Invoke(z) = targetId;
			OffRoad.Add(((WgoData)z).UniqueId.Guid);
			if (Plugin.Verbose.Value)
			{
				Plugin.Log.LogInfo((object)("gardener walks (" + (((int)graph != -1) ? ("mesh " + ((object)(*(Graph*)(&graph))/*cast due to .constrained prefix*/).ToString()) : "straight") + ") to " + ((ObjectLinkedToDefinition<WGODef>)(object)target).id));
			}
			return true;
		}

		public static bool HpTickPre(Wgo __instance)
		{
			if ((Object)(object)__instance != (Object)null)
			{
				return (Object)(object)__instance.MainWgoPart != (Object)null;
			}
			return false;
		}

		public static Exception HpTickFin(Exception __exception, Wgo __instance)
		{
			if (__exception == null)
			{
				return null;
			}
			if (!_hpTickWarned)
			{
				_hpTickWarned = true;
				Plugin.Log.LogWarning((object)("the hit animation of " + (((__instance == null) ? null : ((ObjectLinkedToDefinition<WGODef>)(object)__instance.Data)?.id) ?? "?") + " failed (" + __exception.GetType().Name + "); skipped so the work goes on"));
			}
			return null;
		}

		public static bool GardenerArrivedPre(ZombieWgoData __instance)
		{
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			try
			{
				Guid guid = ((WgoData)__instance).UniqueId.Guid;
				WalkFails.Remove(guid);
				if ((int)__instance.GardenerState == 1)
				{
					OffRoad.Remove(guid);
				}
				return Errands.GardenerArrived(__instance);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Gardener arrival: " + ex.Message));
				return true;
			}
		}

		private static Graph WalkGraph(WorldZoneData zone)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Invalid comparison between Unknown and I4
			//IL_000d: 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_0034: 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_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Invalid comparison between Unknown and I4
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Invalid comparison between Unknown and I4
			//IL_0042: Unknown result type (might be due to invalid IL or missing references)
			//IL_0044: Invalid comparison between Unknown and I4
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			if (zone != null)
			{
				if ((int)zone.navigationGraph != -1)
				{
					return zone.navigationGraph;
				}
				if (ZoneNav.TryGet(zone, out var graph))
				{
					return graph;
				}
				List<Graph> movementGraphs = zone.MovementGraphs;
				if (movementGraphs != null)
				{
					foreach (Graph item in movementGraphs)
					{
						if ((int)item != -1 && (int)item != 2 && (int)item != 3)
						{
							return item;
						}
					}
				}
			}
			return (Graph)(-1);
		}

		private static Vector3 WalkEnd(ZombieWgoData z, WgoData target, bool toStation)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_0029: Unknown result type (might be due to invalid IL or missing references)
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: 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_0045: 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)
			Vector3 position = ((WgoData)z).Position;
			Vector3 result = default(Vector3);
			Direction val = default(Direction);
			if (toStation)
			{
				GDPointData gDPointData = target.GetGDPointData("zombie_garden_crafter_gd_point");
				if (gDPointData != null)
				{
					return gDPointData.Position;
				}
			}
			else if (GardenBedNavigation.IsGardenPlot(target) && GardenBedNavigation.TryGetOpenApproach(target, position, ref result, ref val))
			{
				return result;
			}
			if (target.GetNearestDockPointData(position, (Availability)0) != null)
			{
				return target.GetNearestDockPointDataWorldPositionOrMyPosition(position, (Availability)0, (Func<DockPointData, Vector3, bool>)null);
			}
			return StepShort(position, target);
		}

		internal static Vector3 StepShort(Vector3 from, WgoData target)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_0136: Unknown result type (might be due to invalid IL or missing references)
			//IL_0137: Unknown result type (might be due to invalid IL or missing references)
			//IL_0138: Unknown result type (might be due to invalid IL or missing references)
			//IL_013d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: 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_015e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0167: Unknown result type (might be due to invalid IL or missing references)
			//IL_016c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_005d: 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)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_0079: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_007b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
			//IL_009c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: 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_00de: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = target.Position;
			float num = 1.2f;
			try
			{
				Rect val2 = ((target.MainWgoPartData != null) ? target.MainWgoPartData.GetCollisionBoundsRect(target.Position) : Rect.zero);
				if (((Rect)(ref val2)).width > 0.01f && ((Rect)(ref val2)).height > 0.01f)
				{
					val = new Vector3(((Rect)(ref val2)).center.x, target.Position.y, ((Rect)(ref val2)).center.y);
					Vector3 val3 = from - val;
					val3.y = 0f;
					if (((Vector3)(ref val3)).sqrMagnitude < 0.01f)
					{
						val3 = Vector3.back;
					}
					((Vector3)(ref val3)).Normalize();
					float num2 = ((Mathf.Abs(val3.x) > 0.001f) ? (((Rect)(ref val2)).width * 0.5f / Mathf.Abs(val3.x)) : float.MaxValue);
					float num3 = ((Mathf.Abs(val3.z) > 0.001f) ? (((Rect)(ref val2)).height * 0.5f / Mathf.Abs(val3.z)) : float.MaxValue);
					num = Mathf.Clamp(Mathf.Min(num2, num3) + 0.4f, 0.5f, 2.5f);
				}
			}
			catch
			{
			}
			Vector3 val4 = from - val;
			val4.y = 0f;
			if (((Vector3)(ref val4)).sqrMagnitude < 0.01f)
			{
				val4 = Vector3.back;
			}
			return val + ((Vector3)(ref val4)).normalized * num;
		}

		private static bool CanHarvest(ZombieWgoData z, WgoData hive)
		{
			string talent = ((ObjectLinkedToDefinition<WGODef>)(object)hive).Definition.talent;
			if (string.IsNullOrEmpty(talent) || ((ObjectLinkedToDefinition<WGODef>)(object)hive).Definition.noMasteryLock)
			{
				return true;
			}
			return z.GetMasteryLevelForTalentBranch(talent, (CraftDefBase)null) >= ((ObjectLinkedToDefinition<WGODef>)(object)hive).Definition.MasteryLock;
		}

		private static void Why(WgoData w, string reason)
		{
			if (Told.Add(w.UniqueId.Guid.ToString() + reason))
			{
				Plugin.Log.LogInfo((object)(((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + ZoneName(w) + ": " + reason));
			}
		}

		private static bool AnyCanHarvest(List<ZombieWgoData> gardeners, WgoData hive)
		{
			foreach (ZombieWgoData gardener in gardeners)
			{
				if (CanHarvest(gardener, hive))
				{
					return true;
				}
			}
			return false;
		}

		public static void GardenerOrderPre(WorldZoneData __instance, ZombieWgoData orderTaker, ref List<OrderBase> __state)
		{
			__state = null;
			if (!Plugin.Enabled.Value || orderTaker == null)
			{
				return;
			}
			try
			{
				List<OrderBase> list = ZoneOrders.Invoke(__instance);
				if (list == null)
				{
					return;
				}
				foreach (OrderBase item in list)
				{
					if (item is GatherOrder && item.ExecutorUniqueId.IsEmpty)
					{
						WgoData wgoData = MainGame.WorldData.GetWgoData(item.TargetWgoUniqueId);
						if (wgoData != null && IsHarvestTarget(wgoData) && !CanHarvest(orderTaker, wgoData))
						{
							item.ExecutorUniqueId = ((WgoData)orderTaker).UniqueId;
							(__state ?? (__state = new List<OrderBase>())).Add(item);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Hive order filter: " + ex.Message));
			}
		}

		public static Exception GardenerOrderFin(Exception __exception, List<OrderBase> __state)
		{
			if (__state != null)
			{
				foreach (OrderBase item in __state)
				{
					item.ExecutorUniqueId = SGuid.Empty;
				}
			}
			return __exception;
		}

		public static void GardenerDepositPost(ZombieWgoData __instance)
		{
			//IL_00db: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Enabled.Value)
			{
				return;
			}
			try
			{
				Inventory workerInventory = __instance.WorkerInventory;
				object obj;
				if (workerInventory == null)
				{
					obj = null;
				}
				else
				{
					Item data = workerInventory.Data;
					obj = ((data != null) ? data.Inventory : null);
				}
				if (obj == null)
				{
					return;
				}
				List<string> list = null;
				foreach (Item item in workerInventory.Data.Inventory)
				{
					if (item != null && !item.IsEmpty && (Plugin.GardenerUnloadAll.Value ? IsCargo(__instance, item) : HarvestItems.Contains(((ObjectLinkedToDefinition<ItemDef>)(object)item).id)) && (list == null || !list.Contains(((ObjectLinkedToDefinition<ItemDef>)(object)item).id)))
					{
						(list ?? (list = new List<string>())).Add(((ObjectLinkedToDefinition<ItemDef>)(object)item).id);
					}
				}
				if (list == null)
				{
					return;
				}
				List<Inventory> inventoryList = new MultiInventory(((WgoData)__instance).WorldZoneData, (WgoData)null, false).inventoryList;
				foreach (string item2 in list)
				{
					foreach (Item item3 in workerInventory.RemoveItemById(item2, -1, (Item)null, (Item)null, false))
					{
						Store(inventoryList, item3);
						if (item3.Count > 0)
						{
							workerInventory.AddItemToInventory(item3, (Item)null, false);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Gardener unload: " + ex.Message));
			}
		}

		internal static bool IsCargo(ZombieWgoData z, Item it)
		{
			ItemDef definition = ((ObjectLinkedToDefinition<ItemDef>)(object)it).Definition;
			if (definition == null || ((ObjectLinkedToDefinition<ItemDef>)(object)it).id == "fake_porter_slot_filler")
			{
				return false;
			}
			if (definition.isMainOrgan || definition.isOrganMistake || definition.isTool || definition.isWeapon || definition.isBag)
			{
				return false;
			}
			if (definition.redSkulls != 0 || definition.whiteSkulls != 0)
			{
				return false;
			}
			List<string> itemGroupIds = definition.itemGroupIds;
			if (itemGroupIds != null && (itemGroupIds.Contains("bodypart") || itemGroupIds.Contains("burial_reward")))
			{
				return false;
			}
			SGuid uniqueId = it.UniqueId;
			if (uniqueId != (SGuid)null && (uniqueId == z.equippedHand || uniqueId == z.equippedArmor || uniqueId == z.equippedCollar))
			{
				return false;
			}
			return true;
		}

		public static void PorterCheckPre(ZombieWgoData __instance)
		{
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			if (!Plugin.Enabled.Value || (int)__instance.ZombieType != 5)
			{
				return;
			}
			try
			{
				Inventory val = PorterInv.Invoke(__instance);
				int value = Plugin.PorterSlots.Value;
				if (((val != null) ? val.Data : null) != null && val.Data.InventorySize != value && val.Data.InventoryFillSize <= 0 && ((WgoData)__instance).GetGameResInt("is_staying_at_porter_station") == 1)
				{
					PorterInv.Invoke(__instance) = Inventory.Create(value, false, (WhiteListItemFilter)null, (BlackListItemFilter)null, "");
					if (Plugin.Verbose.Value)
					{
						Plugin.Log.LogInfo((object)("porter backpack: " + val.Data.InventorySize + " -> " + value + " slots"));
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Porter backpack: " + ex.Message));
			}
		}

		public static void PorterUnloadPost(ZombieWgoData __instance)
		{
			try
			{
				Notify.PorterUnloaded(__instance, PorterInv.Invoke(__instance));
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Porter check: " + ex.Message));
			}
		}
	}
	internal static class Cosmetics
	{
		internal sealed class Item
		{
			public string Id;

			public string Folder;

			public readonly Dictionary<string, string> Names = new Dictionary<string, string>();

			public Sprite[] Frames = (Sprite[])(object)new Sprite[0];

			public Sprite[] Left;

			public Sprite[] Up;

			public float Sink = 10f;

			public float X;

			public float Y;

			public float Fps = 12f;

			public bool HideUp;

			public int Beard;

			public Sprite RefDown;

			public Sprite RefLeft;

			public string Name
			{
				get
				{
					if (Beard > 0)
					{
						return T.S("WardrobeBeard") + " " + (Beard - 9000);
					}
					string text = "en";
					try
					{
						text = (LLBase.CurrentLang ?? "en").ToLowerInvariant();
					}
					catch
					{
					}
					if (Names.TryGetValue(text, out var value) || (text.Length >= 2 && Names.TryGetValue(text.Substring(0, 2), out value)))
					{
						return value;
					}
					if (!Names.TryGetValue("en", out value))
					{
						return Path.GetFileName(Folder);
					}
					return value;
				}
			}
		}

		private static List<Item> _items;

		internal const string LayerName = "zpp_accessory";

		private static Material _plain;

		private static readonly Dictionary<Shader, Material> BeardMats = new Dictionary<Shader, Material>();

		private static Texture2D _beardPalette;

		private static float _beardPaletteAt = -100f;

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

		internal static List<Item> All
		{
			get
			{
				if (_items == null)
				{
					Load();
				}
				return _items;
			}
		}

		internal static Item Find(string id)
		{
			if (string.IsNullOrEmpty(id))
			{
				return null;
			}
			foreach (Item item in All)
			{
				if (item.Id == id)
				{
					return item;
				}
			}
			return null;
		}

		internal static void Reload()
		{
			_items = null;
		}

		private static void Load()
		{
			_items = new List<Item>();
			List<string> list = new List<string>();
			try
			{
				string[] directories = Directory.GetDirectories(Paths.PluginPath, "zombie_cosmetics", SearchOption.AllDirectories);
				foreach (string item in directories)
				{
					list.Add(item);
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("cosmetics: " + ex.Message));
			}
			foreach (string item3 in list)
			{
				string fileName = Path.GetFileName(Path.GetDirectoryName(item3));
				string[] directories = Directory.GetDirectories(item3);
				foreach (string text in directories)
				{
					try
					{
						Item item2 = LoadItem(fileName, text);
						if (item2 != null && item2.Frames.Length != 0)
						{
							_items.Add(item2);
						}
					}
					catch (Exception ex2)
					{
						Plugin.Log.LogWarning((object)("cosmetic " + text + ": " + ex2.Message));
					}
				}
			}
			_items.Sort((Item a, Item b) => string.CompareOrdinal(a.Id, b.Id));
			try
			{
				_items.InsertRange(0, GameBeards());
			}
			catch (Exception ex3)
			{
				Plugin.Log.LogWarning((object)("cosmetics: the game's beards: " + ex3.Message));
			}
			Plugin.Log.LogInfo((object)("cosmetics: " + _items.Count + " items from " + list.Count + " pack folder(s)"));
		}

		private static Item LoadItem(string pack, string dir)
		{
			Item item = new Item
			{
				Id = pack + "/" + Path.GetFileName(dir),
				Folder = dir
			};
			string path = Path.Combine(dir, "item.txt");
			if (File.Exists(path))
			{
				string[] array = File.ReadAllLines(path);
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					int num = text.IndexOf('#');
					if (num >= 0)
					{
						text = text.Substring(0, num).Trim();
					}
					int num2 = text.IndexOf('=');
					if (num2 <= 0)
					{
						continue;
					}
					string text2 = text.Substring(0, num2).Trim().ToLowerInvariant();
					string text3 = text.Substring(num2 + 1).Trim();
					if (text2 == "name")
					{
						item.Names["en"] = text3;
						continue;
					}
					if (text2.StartsWith("name."))
					{
						item.Names[text2.Substring(5)] = text3;
						continue;
					}
					switch (text2)
					{
					case "sink":
						item.Sink = F(text3, item.Sink);
						break;
					case "x":
						item.X = F(text3, 0f);
						break;
					case "y":
						item.Y = F(text3, 0f);
						break;
					case "fps":
						item.Fps = F(text3, item.Fps);
						break;
					case "hide.up":
						item.HideUp = text3.Equals("true", StringComparison.OrdinalIgnoreCase) || text3 == "1";
						break;
					}
				}
			}
			item.Frames = Frames(dir, "");
			Sprite[] array2 = Frames(dir, "left_");
			Sprite[] array3 = Frames(dir, "up_");
			if (array2.Length != 0)
			{
				item.Left = array2;
			}
			if (array3.Length != 0)
			{
				item.Up = array3;
			}
			return item;
		}

		private static List<Item> GameBeards()
		{
			List<Item> list = new List<Item>();
			EasySpritesCollection coll = LazySingletonSO<EasySpritesCollection>.Instance;
			Sprite val = Get("9001_hed_static_down");
			Sprite val2 = Get("9001_hed_static_left");
			if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null)
			{
				return list;
			}
			for (int i = 9001; i <= 9099; i++)
			{
				Sprite val3 = Get(i + "_brd_static_down");
				if (!((Object)(object)val3 == (Object)null))
				{
					Sprite val4 = Get(i + "_brd_static_left");
					list.Add(new Item
					{
						Id = "game/beard_" + i,
						Folder = "",
						Beard = i,
						HideUp = true,
						Sink = 0f,
						Frames = (Sprite[])(object)new Sprite[1] { val3 },
						Left = (Sprite[])(object)((!((Object)(object)val4 != (Object)null)) ? null : new Sprite[1] { val4 }),
						RefDown = val,
						RefLeft = val2
					});
				}
			}
			return list;
			Sprite Get(string n)
			{
				if (!coll.HasSprite(n))
				{
					return null;
				}
				return coll.GetSprite(n, (string)null);
			}
		}

		private static float F(string s, float def)
		{
			if (!float.TryParse(s, NumberStyles.Float, CultureInfo.InvariantCulture, out var result))
			{
				return def;
			}
			return result;
		}

		private static Sprite[] Frames(string dir, string prefix)
		{
			//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_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_007f: Unknown result type (might be due to invalid IL or missing references)
			List<Sprite> list = new List<Sprite>();
			int num = 0;
			while (true)
			{
				string path = Path.Combine(dir, prefix + num + ".png");
				if (!File.Exists(path))
				{
					break;
				}
				Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false)
				{
					filterMode = (FilterMode)0,
					wrapMode = (TextureWrapMode)1
				};
				if (!ImageConversion.LoadImage(val, File.ReadAllBytes(path)))
				{
					break;
				}
				((Texture)val).filterMode = (FilterMode)0;
				list.Add(Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0f), 50f));
				num++;
			}
			return list.ToArray();
		}

		internal static void Draw(Component view, Item item)
		{
			//IL_0383: Unknown result type (might be due to invalid IL or missing references)
			//IL_0388: Unknown result type (might be due to invalid IL or missing references)
			//IL_038c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0395: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03cd: Unknown result type (might be due to invalid IL or missing references)
			//IL_041e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0158: Unknown result type (might be due to invalid IL or missing references)
			//IL_015d: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0180: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ec: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_02f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_02fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_0303: Unknown result type (might be due to invalid IL or missing references)
			//IL_030a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0370: Unknown result type (might be due to invalid IL or missing references)
			//IL_0375: Unknown result type (might be due to invalid IL or missing references)
			//IL_0379: Unknown result type (might be due to invalid IL or missing references)
			//IL_037e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0338: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)view == (Object)null)
			{
				return;
			}
			SpriteRenderer val = null;
			SpriteRenderer[] componentsInChildren = view.GetComponentsInChildren<SpriteRenderer>(false);
			foreach (SpriteRenderer val2 in componentsInChildren)
			{
				if ((Object)(object)val2 != (Object)null && (Object)(object)val2.sprite != (Object)null && ((Object)val2).name != "zpp_accessory" && ((Object)val2).name != "zpp_hat" && ((Object)val2.sprite).name.Contains("_hed_"))
				{
					val = val2;
					break;
				}
			}
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform val3 = ((Component)val).transform.Find("zpp_accessory");
			if (item == null)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3).gameObject.SetActive(false);
				}
				return;
			}
			string name = ((Object)val.sprite).name;
			bool flag = name.Contains("_up");
			bool flag2 = name.Contains("_left") || name.Contains("_right");
			if (flag && item.HideUp)
			{
				if ((Object)(object)val3 != (Object)null)
				{
					((Component)val3).gameObject.SetActive(false);
				}
				return;
			}
			Sprite[] array = ((flag && item.Up != null) ? item.Up : ((flag2 && item.Left != null) ? item.Left : item.Frames));
			if (array.Length == 0)
			{
				return;
			}
			SpriteRenderer val5;
			if ((Object)(object)val3 == (Object)null)
			{
				GameObject val4 = new GameObject("zpp_accessory");
				val4.transform.SetParent(((Component)val).transform, false);
				val4.layer = ((Component)val).gameObject.layer;
				val5 = val4.AddComponent<SpriteRenderer>();
				if ((Object)(object)_plain == (Object)null)
				{
					_plain = ((Renderer)val5).sharedMaterial;
				}
				val3 = val4.transform;
			}
			else
			{
				val5 = ((Component)val3).GetComponent<SpriteRenderer>();
			}
			((Component)val3).gameObject.SetActive(true);
			Material val6 = ((item.Beard > 0) ? BeardMaterial(val) : null);
			Material val7 = (((Object)(object)val6 != (Object)null) ? val6 : _plain);
			if ((Object)(object)val7 != (Object)null && (Object)(object)((Renderer)val5).sharedMaterial != (Object)(object)val7)
			{
				((Renderer)val5).sharedMaterial = val7;
			}
			((Renderer)val5).sortingLayerID = ((Renderer)val).sortingLayerID;
			int sortingOrder = ((Renderer)val).sortingOrder;
			componentsInChildren = view.GetComponentsInChildren<SpriteRenderer>(false);
			foreach (SpriteRenderer val8 in componentsInChildren)
			{
				if ((Object)(object)val8 != (Object)null && (Object)(object)val8 != (Object)(object)val5 && ((Renderer)val8).sortingLayerID == ((Renderer)val).sortingLayerID && ((Renderer)val8).sortingOrder > sortingOrder)
				{
					sortingOrder = ((Renderer)val8).sortingOrder;
				}
			}
			((Renderer)val5).sortingOrder = sortingOrder + 1;
			val5.flipX = val.flipX;
			val5.sprite = ((array.Length == 1) ? array[0] : array[(int)(Time.time * Mathf.Max(0.1f, item.Fps)) % array.Length]);
			if (item.Beard > 0)
			{
				Sprite s = (flag2 ? item.RefLeft : item.RefDown);
				float mid;
				Vector2 val9 = Drawn(Still(val.sprite), out mid);
				float mid2;
				Vector2 val10 = Drawn(s, out mid2);
				float num = mid - mid2;
				float num2 = val9.y - val10.y;
				val3.localPosition = new Vector3(val.flipX ? (0f - num) : num, num2 + item.Y / 50f, 0f);
				return;
			}
			Sprite val11 = Still(val.sprite);
			float num3 = ((val11.pixelsPerUnit > 0f) ? val11.pixelsPerUnit : 50f);
			Vector2 val12;
			Rect val13;
			try
			{
				val12 = val11.textureRectOffset;
				val13 = val11.textureRect;
			}
			catch
			{
				val12 = Vector2.zero;
				val13 = val11.rect;
			}
			float num4 = (val12.y + ((Rect)(ref val13)).height - val11.pivot.y) / num3;
			float num5 = (val12.x + ((Rect)(ref val13)).width * 0.5f - val11.pivot.x) / num3 + (flag2 ? ((0f - item.X) / num3) : 0f);
			val3.localPosition = new Vector3(val.flipX ? (0f - num5) : num5, num4 - item.Sink / num3 + item.Y / num3, 0f);
		}

		private static Material BeardMaterial(SpriteRenderer head)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00c8: Unknown result type (might be due to invalid IL or missing references)
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			Material sharedMaterial = ((Renderer)head).sharedMaterial;
			if ((Object)(object)sharedMaterial == (Object)null || (Object)(object)sharedMaterial.shader == (Object)null || !sharedMaterial.HasProperty(SkinChangerGK2.shaderPaletteId))
			{
				return null;
			}
			if (Time.unscaledTime - _beardPaletteAt > 5f || (Object)(object)_beardPalette == (Object)null)
			{
				_beardPaletteAt = Time.unscaledTime;
				try
				{
					_beardPalette = PlayerSkinHelper.GetColorReplacementPalette(MainGame.PlayerData.customization)?.palette;
				}
				catch
				{
					_beardPalette = null;
				}
			}
			if ((Object)(object)_beardPalette == (Object)null)
			{
				return null;
			}
			if (!BeardMats.TryGetValue(sharedMaterial.shader, out var value) || (Object)(object)value == (Object)null)
			{
				value = new Material(sharedMaterial)
				{
					name = "zpp_beard"
				};
				value.SetColor(SkinChangerGK2.shaderColorId, Color.white);
				value.SetFloat(SkinChangerGK2.shaderHueShiftId, 0f);
				value.SetFloat(SkinChangerGK2.shaderSaturationId, 1f);
				value.SetFloat(SkinChangerGK2.shaderValueId, 1f);
				value.SetFloat(SkinChangerGK2.shaderBrightnessId, 0f);
				value.SetFloat(SkinChangerGK2.shaderContrastId, 0f);
				value.DisableKeyword(((object)(ColorReplaceType)0/*cast due to .constrained prefix*/).ToString());
				value.EnableKeyword(((object)(ColorReplaceType)1/*cast due to .constrained prefix*/).ToString());
				BeardMats[sharedMaterial.shader] = value;
			}
			if ((Object)(object)value.GetTexture(SkinChangerGK2.shaderPaletteId) != (Object)(object)_beardPalette)
			{
				value.SetTexture(SkinChangerGK2.shaderPaletteId, (Texture)(object)_beardPalette);
			}
			return value;
		}

		internal static Sprite Still(Sprite s)
		{
			string text = Outfits.Clean(((Object)s).name);
			int num = text.LastIndexOf('_');
			if (num < 0 || text.Length - num != 3 || !char.IsDigit(text[num + 1]) || !char.IsDigit(text[num + 2]) || text.IndexOf("_static_", StringComparison.Ordinal) < 0)
			{
				return s;
			}
			if (!StillFrames.TryGetValue(text, out var value))
			{
				EasySpritesCollection instance = LazySingletonSO<EasySpritesCollection>.Instance;
				string text2 = text.Substring(0, num);
				value = (instance.HasSprite(text2) ? instance.GetSprite(text2, (string)null) : null);
				StillFrames[text] = value;
			}
			if (!((Object)(object)value != (Object)null))
			{
				return s;
			}
			return value;
		}

		internal static Vector2 Drawn(Sprite s, out float mid)
		{
			//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_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_0038: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_007a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			float num = ((s.pixelsPerUnit > 0f) ? s.pixelsPerUnit : 50f);
			Vector2 val;
			Rect val2;
			try
			{
				val = s.textureRectOffset;
				val2 = s.textureRect;
			}
			catch
			{
				val = Vector2.zero;
				val2 = s.rect;
			}
			mid = (val.x + ((Rect)(ref val2)).width * 0.5f - s.pivot.x) / num;
			return new Vector2((val.x - s.pivot.x) / num, (val.y - s.pivot.y) / num);
		}
	}
	internal static class Errands
	{
		private class Errand
		{
			public SGuid Target;

			public float Since;

			public int Fails;
		}

		private static readonly Dictionary<Guid, Errand> ByZombie = new Dictionary<Guid, Errand>();

		private static readonly HashSet<Guid> Leftovers = new HashSet<Guid>();

		private static readonly HashSet<Guid> Stranded = new HashSet<Guid>();

		private const float Timeout = 180f;

		private const int MaxWalkFails = 3;

		private const ZombieCaretakerState HelperGoing = (ZombieCaretakerState)5;

		private const ZombieGardenerState GardenerGoing = (ZombieGardenerState)5;

		private static readonly FieldRef<ZombieWgoData, SGuid> HelperTarget = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("caretakerCurrentTargetUniqueId");

		private static readonly FieldRef<ZombieWgoData, SGuid> HelperMoveTarget = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("caretakerCurrentMovementTargetUniqueId");

		private static readonly FieldRef<ZombieWgoData, SGuid> HelperOrder = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("caretakerExecutingOrder");

		private static readonly FieldRef<ZombieWgoData, ZombieCaretakerState> HelperPrevState = AccessTools.FieldRefAccess<ZombieWgoData, ZombieCaretakerState>("caretakerPreviousState");

		private static readonly FieldRef<ZombieWgoData, float> HelperRetryTimer = AccessTools.FieldRefAccess<ZombieWgoData, float>("caretakerTimeForCheckFailedPathAgain");

		private static readonly MethodInfo HelperToChest = AccessTools.Method(typeof(ZombieWgoData), "CaretakerTryMoveToNearestInventoryToPutPickedUpOrderItem", (Type[])null, (Type[])null);

		private static readonly MethodInfo HelperNextOrHome = AccessTools.Method(typeof(ZombieWgoData), "CaretakerTryGetNewOrderOrMoveToStation", (Type[])null, (Type[])null);

		private static readonly FieldRef<ZombieWgoData, SGuid> GardenerTarget = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("gardenerCurrentTargetUniqueId");

		private static readonly FieldRef<ZombieWgoData, SGuid> GardenerOrder = AccessTools.FieldRefAccess<ZombieWgoData, SGuid>("gardenerExecutingOrder");

		private static readonly MethodInfo GardenerMove = AccessTools.Method(typeof(ZombieWgoData), "GardenerTryMoveToCurrentTarget", (Type[])null, (Type[])null);

		private static readonly MethodInfo GardenerHome = AccessTools.Method(typeof(ZombieWgoData), "GardenerTryMoveToStation", (Type[])null, (Type[])null);

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

		private static readonly Dictionary<Guid, float> PileCheckAt = new Dictionary<Guid, float>();

		private static float _describeAt;

		public static bool Ready
		{
			get
			{
				if (HelperToChest != null && HelperNextOrHome != null && GardenerMove != null)
				{
					return GardenerHome != null;
				}
				return false;
			}
		}

		public static void Reset()
		{
			ByZombie.Clear();
			Leftovers.Clear();
			Stranded.Clear();
		}

		private static bool Busy(WgoData w)
		{
			foreach (Errand value in ByZombie.Values)
			{
				if (value.Target.Guid == w.UniqueId.Guid)
				{
					return true;
				}
			}
			return false;
		}

		private static Errand Of(ZombieWgoData z, SGuid target)
		{
			if (!(target != (SGuid)null) || !ByZombie.TryGetValue(((WgoData)z).UniqueId.Guid, out var value) || !(value.Target.Guid == target.Guid))
			{
				return null;
			}
			return value;
		}

		private static void Call(MethodInfo m, ZombieWgoData z)
		{
			try
			{
				m.Invoke(z, null);
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)(m.Name + ": " + (ex.InnerException ?? ex).Message));
			}
		}

		public static void Watch(List<ZombieWgoData> zombies)
		{
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0037: Invalid comparison between Unknown and I4
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			//IL_0144: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Invalid comparison between Unknown and I4
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Invalid comparison between Unknown and I4
			//IL_0080: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Invalid comparison between Unknown and I4
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Invalid comparison between Unknown and I4
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Invalid comparison between Unknown and I4
			//IL_0072: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Invalid comparison between Unknown and I4
			HashSet<Guid> hashSet = new HashSet<Guid>();
			foreach (ZombieWgoData zombie in zombies)
			{
				Guid guid = ((WgoData)zombie).UniqueId.Guid;
				hashSet.Add(guid);
				bool flag = (int)zombie.ZombieType == 2;
				bool flag2 = (int)zombie.ZombieType == 6;
				if (!flag && !flag2)
				{
					continue;
				}
				if (ByZombie.TryGetValue(guid, out var value))
				{
					bool flag3 = ((!flag) ? ((int)zombie.GardenerState == 5 || (int)zombie.GardenerState == 8) : ((int)zombie.CaretakerState == 5 || (int)zombie.CaretakerState == 10));
					WgoData wgoData = MainGame.WorldData.GetWgoData(value.Target);
					if (!flag3 || wgoData == null || !(Time.time - value.Since < 180f))
					{
						ByZombie.Remove(guid);
						if (flag3)
						{
							Plugin.Log.LogWarning((object)((flag ? "helper" : "gardener") + " gave up on " + (((ObjectLinkedToDefinition<WGODef>)(object)wgoData)?.id ?? "a removed object")));
							Home(zombie);
						}
					}
					continue;
				}
				bool isEmpty;
				if (!flag)
				{
					if ((int)zombie.GardenerState == 5)
					{
						isEmpty = GardenerOrder.Invoke(zombie).IsEmpty;
						goto IL_0160;
					}
				}
				else if ((int)zombie.CaretakerState == 5)
				{
					isEmpty = HelperOrder.Invoke(zombie).IsEmpty;
					goto IL_0160;
				}
				goto IL_016f;
				IL_016f:
				Stranded.Remove(guid);
				continue;
				IL_0160:
				if (isEmpty && !((WgoData)zombie).MovementComponent.IsMoving)
				{
					if (!Stranded.Add(guid))
					{
						Stranded.Remove(guid);
						Home(zombie);
					}
					continue;
				}
				goto IL_016f;
			}
			List<Guid> list = new List<Guid>();
			foreach (Guid key in ByZombie.Keys)
			{
				if (!hashSet.Contains(key))
				{
					list.Add(key);
				}
			}
			foreach (Guid item in list)
			{
				ByZombie.Remove(item);
			}
		}

		private static void Home(ZombieWgoData z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			if ((int)z.ZombieType == 2)
			{
				Call(HelperNextOrHome, z);
			}
			else
			{
				Call(GardenerHome, z);
			}
		}

		private static bool HelperIdle(ZombieWgoData z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)z.CaretakerState == 0 && HelperOrder.Invoke(z).IsEmpty && (z.CaretakerPortableItem == null || z.CaretakerPortableItem.IsEmpty))
			{
				return !ByZombie.ContainsKey(((WgoData)z).UniqueId.Guid);
			}
			return false;
		}

		private static bool HasOutput(WgoData w)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			CraftComponent craftComponent = w.CraftComponent;
			if (craftComponent == null || craftComponent.IsDestroyingCraftActive)
			{
				return false;
			}
			if ((int)craftComponent.Status == 7)
			{
				return true;
			}
			if (!Leftovers.Contains(w.UniqueId.Guid))
			{
				return false;
			}
			Inventory craftableObjectCraftInventory = w.CraftableObjectCraftInventory;
			object obj;
			if (craftableObjectCraftInventory == null)
			{
				obj = null;
			}
			else
			{
				Item data = craftableObjectCraftInventory.Data;
				obj = ((data != null) ? data.Inventory : null);
			}
			if (obj != null)
			{
				foreach (Item item in craftableObjectCraftInventory.Data.Inventory)
				{
					if (item != null && !item.IsEmpty)
					{
						return true;
					}
				}
			}
			Leftovers.Remove(w.UniqueId.Guid);
			return false;
		}

		public static void Helpers(WorldZoneData zone, List<ZombieWgoData> helpers, bool furnaces, bool compost)
		{
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0033: Invalid comparison between Unknown and I4
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			List<Inventory> list = null;
			foreach (WgoData item in Chores.ZoneObjects(zone))
			{
				WGODef definition = ((ObjectLinkedToDefinition<WGODef>)(object)item).Definition;
				if (!definition.isAutoCrafter || (int)definition.interactionType != 2 || !(Chores.IsCompost(item) ? compost : furnaces) || item.Worker is ZombieWgoData || Busy(item) || !HasOutput(item))
				{
					continue;
				}
				if (list == null)
				{
					list = new MultiInventory(zone, (WgoData)null, false).inventoryList;
				}
				if (list.Count == 0)
				{
					break;
				}
				ZombieWgoData val = null;
				float num = float.MaxValue;
				foreach (ZombieWgoData helper in helpers)
				{
					if (HelperIdle(helper))
					{
						float num2 = Vector3.Distance(((WgoData)helper).Position, item.Position);
						if (num2 < num)
						{
							num = num2;
							val = helper;
						}
					}
				}
				if (val == null)
				{
					break;
				}
				ByZombie[((WgoData)val).UniqueId.Guid] = new Errand
				{
					Target = item.UniqueId,
					Since = Time.time
				};
				HelperTarget.Invoke(val) = item.UniqueId;
				val.CaretakerState = (ZombieCaretakerState)5;
				HelperWalk(val, item);
				if (Plugin.Verbose.Value)
				{
					Plugin.Log.LogInfo((object)("helper goes to " + ((ObjectLinkedToDefinition<WGODef>)(object)item).id + " in " + Chores.ZoneName(item)));
				}
			}
		}

		private static void HelperWalk(ZombieWgoData z, WgoData w)
		{
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: 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_0035: 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_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0086: Unknown result type (might be due to invalid IL or missing references)
			//IL_008b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0090: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a6: 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_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fa: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0100: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Invalid comparison between Unknown and I4
			Errand errand = Of(z, w.UniqueId);
			MovementComponent movementComponent = ((WgoData)z).MovementComponent;
			if (movementComponent.IsMoving)
			{
				movementComponent.ForceStop();
			}
			Vector3 position = ((WgoData)z).Position;
			DockPointData nearestDockPointData = w.GetNearestDockPointData(position, (Availability)0);
			Vector3 val = ((nearestDockPointData != null) ? w.GetNearestDockPointDataWorldPositionOrMyPosition(position, (Availability)0, (Func<DockPointData, Vector3, bool>)((DockPointData d, Vector3 p) => d.BakedData == null || !d.BakedData.DisableTargetingForCaretaker)) : Chores.StepShort(position, w));
			WorldZoneData worldZoneData = ((WgoData)z).WorldZoneData;
			GraphMask val2 = NavigationGraphMaskUtils.ToGraphMask((IEnumerable<Graph>)((worldZoneData != null) ? worldZoneData.MovementGraphs : null), (Graph)((worldZoneData == null) ? (-1) : ((int)worldZoneData.navigationGraph)));
			if (ZoneNav.TryGet(worldZoneData, out var graph))
			{
				val2 |= NavigationGraphMaskUtils.ToGraphMask(graph);
			}
			StartPathResult val3 = ((((nearestDockPointData != null) ? nearestDockPointData.BakedData : null) != null) ? movementComponent.StartPath(val, nearestDockPointData.BakedData, val2, ((WgoData)z).WorldId, 1.5f, "", (Action)null) : movementComponent.StartPath(val, val2, ((WgoData)z).WorldId, 1.5f, "", (Action)null, (DestinationType)0));
			if ((int)val3 != 0)
			{
				if ((int)val3 == 1)
				{
					HelperArrived(z, w);
				}
				else if (errand != null && ++errand.Fails >= 3)
				{
					Plugin.Log.LogWarning((object)("helper can't walk to " + ((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + Chores.ZoneName(w) + ", taking the work from where it stands"));
					HelperArrived(z, w);
				}
				else
				{
					HelperRetryTimer.Invoke(z) = 1f;
					z.CaretakerState = (ZombieCaretakerState)10;
				}
			}
			else
			{
				HelperMoveTarget.Invoke(z) = w.UniqueId;
			}
		}

		public static bool HelperMovePre(ZombieWgoData __instance)
		{
			//IL_003b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0042: Invalid comparison between Unknown and I4
			try
			{
				Errand errand = Of(__instance, HelperTarget.Invoke(__instance));
				if (errand == null)
				{
					return true;
				}
				WgoData wgoData = MainGame.WorldData.GetWgoData(errand.Target);
				if (wgoData == null)
				{
					return true;
				}
				if ((int)__instance.CaretakerState == 10)
				{
					if (HelperRetryTimer.Invoke(__instance) > 0f)
					{
						return false;
					}
					HelperRetryTimer.Invoke(__instance) = 0f;
					__instance.CaretakerState = HelperPrevState.Invoke(__instance);
					if (++errand.Fails >= 3)
					{
						Plugin.Log.LogWarning((object)("helper can't walk to " + ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id + " in " + Chores.ZoneName(wgoData) + ", taking the work from where it stands"));
						HelperArrived(__instance, wgoData);
						return false;
					}
				}
				else
				{
					SGuid obj = HelperMoveTarget.Invoke(__instance);
					if (((obj != null) ? new Guid?(obj.Guid) : ((Guid?)null)) == wgoData.UniqueId.Guid)
					{
						return false;
					}
				}
				HelperWalk(__instance, wgoData);
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Helper move: " + ex.Message));
				return true;
			}
		}

		public static bool HelperArrivedPre(ZombieWgoData __instance)
		{
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0009: Invalid comparison between Unknown and I4
			try
			{
				if ((int)__instance.CaretakerState != 5)
				{
					return true;
				}
				Errand errand = Of(__instance, HelperTarget.Invoke(__instance));
				if (errand == null)
				{
					return true;
				}
				WgoData wgoData = MainGame.WorldData.GetWgoData(errand.Target);
				if (wgoData == null)
				{
					return true;
				}
				HelperArrived(__instance, wgoData);
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Helper arrival: " + ex.Message));
				return true;
			}
		}

		private static void HelperArrived(ZombieWgoData z, WgoData w)
		{
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Invalid comparison between Unknown and I4
			ByZombie.Remove(((WgoData)z).UniqueId.Guid);
			MovementComponent movementComponent = ((WgoData)z).MovementComponent;
			if (movementComponent.IsMoving)
			{
				movementComponent.ForceStop();
			}
			List<Item> list = new List<Item>();
			if (!(w.Worker is ZombieWgoData) && HasOutput(w))
			{
				if ((int)w.CraftComponent.Status == 7)
				{
					list = Chores.FinishCraft(w, z);
				}
				else
				{
					list.AddRange(w.CraftableObjectCraftInventory.Data.RemoveAllItems());
				}
			}
			list.RemoveAll((Item i) => i == null || i.IsEmpty);
			if (list.Count == 0)
			{
				Call(HelperNextOrHome, z);
				return;
			}
			Item val = list[0];
			bool flag = false;
			Inventory craftableObjectCraftInventory = w.CraftableObjectCraftInventory;
			for (int num = 1; num < list.Count; num++)
			{
				Item val2 = list[num];
				if (((craftableObjectCraftInventory != null) ? craftableObjectCraftInventory.Data : null) != null && craftableObjectCraftInventory.CanAddItemToInventory(val2))
				{
					craftableObjectCraftInventory.AddItemToInventory(val2, (Item)null, false);
					flag = true;
				}
				if (val2.Count > 0)
				{
					w.MakeDrop(val2);
				}
			}
			if (flag)
			{
				Leftovers.Add(w.UniqueId.Guid);
			}
			else
			{
				Leftovers.Remove(w.UniqueId.Guid);
			}
			z.CaretakerPortableItem = val;
			z.CaretakerState = (ZombieCaretakerState)6;
			Call(HelperToChest, z);
			if (Plugin.Verbose.Value)
			{
				Plugin.Log.LogInfo((object)("helper took " + ((ObjectLinkedToDefinition<ItemDef>)(object)val).id + " x" + val.Count + " from " + ((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + Chores.ZoneName(w)));
			}
		}

		private static bool GardenerIdle(ZombieWgoData z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			if ((int)z.GardenerState == 0 && GardenerOrder.Invoke(z).IsEmpty)
			{
				return !ByZombie.ContainsKey(((WgoData)z).UniqueId.Guid);
			}
			return false;
		}

		private static bool PileWantsVisit(WgoData w, MultiInventory chests)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Invalid comparison between Unknown and I4
			CraftComponent craftComponent = w.CraftComponent;
			if (craftComponent == null || craftComponent.IsDestroyingCraftActive)
			{
				return false;
			}
			if ((int)craftComponent.Status == 7 || HasPeat(w))
			{
				return true;
			}
			return Chores.CompostCanStart(w, chests) != null;
		}

		private static bool HasPeat(WgoData w)
		{
			Inventory craftableObjectCraftInventory = w.CraftableObjectCraftInventory;
			object obj;
			if (craftableObjectCraftInventory == null)
			{
				obj = null;
			}
			else
			{
				Item data = craftableObjectCraftInventory.Data;
				obj = ((data != null) ? data.Inventory : null);
			}
			if (obj == null)
			{
				return false;
			}
			foreach (Item item in craftableObjectCraftInventory.Data.Inventory)
			{
				if (item != null && !item.IsEmpty && ((ObjectLinkedToDefinition<ItemDef>)(object)item).id != "leaf")
				{
					return true;
				}
			}
			return false;
		}

		private static void SayWhyNot(WgoData w, MultiInventory chests)
		{
			if (Plugin.Verbose.Value)
			{
				CraftComponent craftComponent = w.CraftComponent;
				string text;
				if (craftComponent == null)
				{
					text = "no craft component";
				}
				else if (craftComponent.IsDestroyingCraftActive)
				{
					text = "being destroyed";
				}
				else if (craftComponent.IsStarted || craftComponent.HasCraftsInQueue)
				{
					text = "composting, the peat isn't ready yet";
				}
				else
				{
					int totalCount = chests.GetTotalCount("leaf");
					int value = Plugin.CompostKeepLeaves.Value;
					text = "waiting for leaves: " + totalCount + " in the chests, " + value + " kept (CompostKeepLeaves), a batch needs more";
				}
				if (!Said.TryGetValue(w.UniqueId.Guid, out var value2) || !(value2 == text))
				{
					Said[w.UniqueId.Guid] = text;
					Plugin.Log.LogInfo((object)(((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + Chores.ZoneName(w) + ": no gardener sent, " + text));
				}
			}
		}

		public static void Compost(WorldZoneData zone, List<ZombieWgoData> gardeners)
		{
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Expected O, but got Unknown
			//IL_0097: Unknown result type (might be due to invalid IL or missing references)
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			MultiInventory val = null;
			foreach (WgoData item in Chores.ZoneObjects(zone))
			{
				if (!Chores.IsCompost(item) || item.Worker is ZombieWgoData || Busy(item))
				{
					continue;
				}
				if (val == null)
				{
					val = new MultiInventory(zone, (WgoData)null, false);
				}
				if (val.inventoryList.Count == 0)
				{
					break;
				}
				if (!PileWantsVisit(item, val))
				{
					SayWhyNot(item, val);
					continue;
				}
				ZombieWgoData val2 = null;
				float num = float.MaxValue;
				foreach (ZombieWgoData gardener in gardeners)
				{
					if (GardenerIdle(gardener))
					{
						float num2 = Vector3.Distance(((WgoData)gardener).Position, item.Position);
						if (num2 < num)
						{
							num = num2;
							val2 = gardener;
						}
					}
				}
				if (val2 == null)
				{
					SayBusy(item);
					break;
				}
				SendToPile(val2, item);
			}
		}

		private static void SayBusy(WgoData w)
		{
			if (Plugin.Verbose.Value && (!Said.TryGetValue(w.UniqueId.Guid, out var value) || !(value == "every gardener is busy; the first to come back to its station goes")))
			{
				Said[w.UniqueId.Guid] = "every gardener is busy; the first to come back to its station goes";
				Plugin.Log.LogInfo((object)(((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + Chores.ZoneName(w) + ": every gardener is busy; the first to come back to its station goes"));
			}
		}

		private static void SendToPile(ZombieWgoData z, WgoData w)
		{
			Said.Remove(w.UniqueId.Guid);
			ByZombie[((WgoData)z).UniqueId.Guid] = new Errand
			{
				Target = w.UniqueId,
				Since = Time.time
			};
			GardenerTarget.Invoke(z) = w.UniqueId;
			z.GardenerState = (ZombieGardenerState)5;
			Call(GardenerMove, z);
			if (Plugin.Verbose.Value)
			{
				Plugin.Log.LogInfo((object)("gardener goes to " + ((ObjectLinkedToDefinition<WGODef>)(object)w).id + " in " + Chores.ZoneName(w)));
			}
		}

		public static bool GardenerNewOrderPre(ZombieWgoData __instance)
		{
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Invalid comparison between Unknown and I4
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Invalid comparison between Unknown and I4
			//IL_012e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			try
			{
				if (!Plugin.Enabled.Value || !Plugin.GardenerCompost.Value || (int)__instance.ZombieType != 6)
				{
					return true;
				}
				if ((int)__instance.GardenerState != 0 || !GardenerOrder.Invoke(__instance).IsEmpty || ByZombie.ContainsKey(((WgoData)__instance).UniqueId.Guid))
				{
					return true;
				}
				Guid guid = ((WgoData)__instance).UniqueId.Guid;
				if (PileCheckAt.TryGetValue(guid, out var value) && Time.time < value)
				{
					return true;
				}
				PileCheckAt[guid] = Time.time + 2f;
				Item hand = __instance.Hand;
				if (hand == null || hand.IsEmpty || ((ObjectLinkedToDefinition<ItemDef>)(object)hand).Definition == null || (int)((ObjectLinkedToDefinition<ItemDef>)(object)hand).Definition.type != 2)
				{
					return true;
				}
				WorldZoneData worldZoneData = ((WgoData)__instance).WorldZoneData;
				if (worldZoneData == null)
				{
					return true;
				}
				MultiInventory val = null;
				foreach (WgoData item in Chores.ZoneObjects(worldZoneData))
				{
					if (Chores.IsCompost(item) && !(item.Worker is ZombieWgoData) && !Busy(item))
					{
						if (val == null)
						{
							val = new MultiInventory(worldZoneData, (WgoData)null, false);
						}
						if (val.inventoryList.Count == 0)
						{
							return true;
						}
						if (PileWantsVisit(item, val))
						{
							SendToPile(__instance, item);
							return false;
						}
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Gardener compost check: " + ex.Message));
			}
			return true;
		}

		public static void DescribeGardeners(List<ZombieWgoData> all)
		{
			//IL_0044: Unknown result type (might be due to invalid IL or missing references)
			//IL_004a: Invalid comparison between Unknown and I4
			//IL_0168: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			if (!Plugin.Verbose.Value || Time.unscaledTime < _describeAt)
			{
				return;
			}
			_describeAt = Time.unscaledTime + 15f;
			foreach (ZombieWgoData item in all)
			{
				if (item == null || (int)item.ZombieType != 6)
				{
					continue;
				}
				try
				{
					WorldZoneData worldZoneData = ((WgoData)item).WorldZoneData;
					int num = 0;
					int num2 = 0;
					int num3 = 0;
					List<OrderBase> list = ((worldZoneData != null) ? Traverse.Create((object)worldZoneData).Field("orders").GetValue<List<OrderBase>>() : null);
					if (list != null)
					{
						foreach (OrderBase item2 in list)
						{
							if (item2 is GatherOrder || item2 is PlantOrder)
							{
								if (!item2.ExecutorUniqueId.IsEmpty)
								{
									num3++;
								}
								else if (item2 is GatherOrder)
								{
									num++;
								}
								else
								{
									num2++;
								}
							}
						}
					}
					SGuid val = GardenerOrder.Invoke(item);
					OrderBase val2 = ((!val.IsEmpty && worldZoneData != null) ? worldZoneData.FindOrder(val) : null);
					WgoData wgoData = MainGame.WorldData.GetWgoData(GardenerTarget.Invoke(item));
					Item hand = item.Hand;
					Plugin.Log.LogInfo((object)("gardener in " + (((ObjectLinkedToDefinition<WorldZoneDef>)(object)worldZoneData)?.id ?? "no zone") + ": " + ((object)item.GardenerState/*cast due to .constrained prefix*/).ToString() + ", order " + (val.IsEmpty ? "none" : ((val2 == null) ? ("GONE " + (object)val) : ((object)val2).GetType().Name)) + ", target " + (((ObjectLinkedToDefinition<WGODef>)(object)wgoData)?.id ?? "none") + ", hand " + ((hand == null || hand.IsEmpty) ? "empty" : ((ObjectLinkedToDefinition<ItemDef>)(object)hand).id) + ", station " + (((ObjectLinkedToDefinition<WGODef>)(object)item.AttachedWgoData)?.id ?? "none") + ", our errand " + ByZombie.ContainsKey(((WgoData)item).UniqueId.Guid) + "; zone orders free: gather " + num + ", plant " + num2 + "; taken " + num3));
				}
				catch (Exception ex)
				{
					Plugin.Log.LogInfo((object)("gardener describe: " + ex.Message));
				}
			}
		}

		public static bool IsGardenerErrand(ZombieWgoData z, WgoData target)
		{
			if (target != null)
			{
				return Of(z, target.UniqueId) != null;
			}
			return false;
		}

		public static bool GardenerArrived(ZombieWgoData z)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0007: Invalid comparison between Unknown and I4
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Invalid comparison between Unknown and I4
			//IL_0201: Unknown result type (might be due to invalid IL or missing references)
			//IL_020b: Expected O, but got Unknown
			//IL_022f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0239: Expected O, but got Unknown
			//IL_0234: Unknown result type (might be due to invalid IL or missing references)
			//IL_023b: Expected O, but got Unknown
			if ((int)z.GardenerState != 5)
			{
				return true;
			}
			Errand errand = Of(z, GardenerTarget.Invoke(z));
			if (errand == null)
			{
				return true;
			}
			WgoData wgoData = MainGame.WorldData.GetWgoData(errand.Target);
			if (wgoData == null)
			{
				return true;
			}
			ByZombie.Remove(((WgoData)z).UniqueId.Guid);
			List<Item> list = new List<Item>();
			CraftComponent craftComponent = wgoData.CraftComponent;
			if (craftComponent != null && (int)craftComponent.Status == 7 && !craftComponent.IsDestroyingCraftActive)
			{
				list = Chores.FinishCraft(wgoData, z);
			}
			Inventory craftableObjectCraftInventory = wgoData.CraftableObjectCraftInventory;
			object obj;
			if (craftableObjectCraftInventory == null)
			{
				obj = null;
			}
			else
			{
				Item data = craftableObjectCraftInventory.Data;
				obj = ((data != null) ? data.Inventory : null);
			}
			if (obj != null)
			{
				foreach (Item item in new List<Item>(craftableObjectCraftInventory.Data.Inventory))
				{
					if (item != null && !item.IsEmpty && ((ObjectLinkedToDefinition<ItemDef>)(object)item).id != "leaf")
					{
						list.AddRange(craftableObjectCraftInventory.RemoveItemById(((ObjectLinkedToDefinition<ItemDef>)(object)item).id, item.Count, (Item)null, (Item)null, false));
					}
				}
			}
			Inventory workerInventory = z.WorkerInventory;
			int num = 0;
			foreach (Item item2 in list)
			{
				if (item2 == null || item2.IsEmpty)
				{
					continue;
				}
				int count = item2.Count;
				if (((workerInventory != null) ? workerInventory.Data : null) != null && workerInventory.CanAddItemToInventory(item2))
				{
					workerInventory.AddItemToInventory(item2, (Item)null, false);
				}
				num += count - item2.Count;
				if (item2.Count > 0)
				{
					Notify.Overflow(wgoData, ((ObjectLinkedToDefinition<ItemDef>)(object)item2).id);
					if (((craftableObjectCraftInventory != null) ? craftableObjectCraftInventory.Data : null) != null && craftableObjectCraftInventory.CanAddItemToInventory(item2))
					{
						craftableObjectCraftInventory.AddItemToInventory(item2, (Item)null, false);
					}
					if (item2.Count > 0)
					{
						wgoData.MakeDrop(item2);
					}
				}
			}
			string text = null;
			CraftDefBase val = Chores.CompostCanStart(wgoData, new MultiInventory(((WgoData)z).WorldZoneData, (WgoData)null, false));
			if (val != null)
			{
				CraftElement val2 = new CraftElement(((BalanceBaseObject)val).id, 1, new List<NeedItemData>(val.needItems), new CraftParamsData(((BalanceBaseObject)val).id, wgoData, (CraftParamsType)0, -1));
				if (wgoData.CraftComponent.TryStartCraft((CraftElementBase)(object)val2))
				{
					text = ((BalanceBaseObject)val).id;
				}
			}
			if (Plugin.Verbose.Value)
			{
				Plugin.Log.LogInfo((object)("gardener at " + ((ObjectLinkedToDefinition<WGODef>)(object)wgoData).id + " in " + Chores.ZoneName(wgoData) + ": took " + num + ((text != null) ? (", started " + text) : "")));
			}
			Call(GardenerHome, z);
			return false;
		}
	}
	internal static class Fishing
	{
		private enum Phase
		{
			Start,
			Cast,
			Wait,
			Pull,
			Catch,
			Release,
			Rest,
			Idle
		}

		private class Fisher
		{
			public SGuid Id;

			public Phase Phase = Phase.Rest;

			public float Left = 1f;

			public FishingDef Fish;

			public bool Hooked;

			public string Blocked;

			public bool Empty;

			public Direction Dir = (Direction)3;
		}

		private static readonly Dictionary<Guid, Fisher> Fishers = new Dictionary<Guid, Fisher>();

		private static float _scanAt;

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

		private static readonly Regex BodyFrame = new Regex("_bdy_fishing_(start|cast|idle|pull|catch)_(left|right|up|down)_(\\d+)$");

		private static readonly Dictionary<string, int> BodyFrames = new Dictionary<string, int>
		{
			{ "start", 7 },
			{ "cast", 12 },
			{ "idle", 4 },
			{ "pull", 7 },
			{ "catch", 10 }
		};

		private static readonly Dictionary<string, int> RodFrames = new Dictionary<string, int>
		{
			{ "start", 5 },
			{ "cast", 15 },
			{ "idle", 8 },
			{ "pull", 7 },
			{ "catch", 10 }
		};

		private const string ArmName = "zpp_fish_arm";

		private const string RodName = "zpp_fish_rod";

		private static bool _layersWarned;

		private static bool _rodLogged;

		private static Vector3? _playerRodOffset;

		private static bool _playerRodLooked;

		private const string BasketKey = "zpp_basket:";

		private static List<string> _fishIds;

		internal static List<string> FishIds
		{
			get
			{
				if (_fishIds == null)
				{
					_fishIds = new List<string>();
					foreach (FishingDef fishingDef in GameBalance.Me.fishingDefs)
					{
						if (fishingDef != null && !string.IsNullOrEmpty(fishingDef.fishId) && !_fishIds.Contains(fishingDef.fishId))
						{
							_fishIds.Add(fishingDef.fishId);
						}
					}
				}
				return _fishIds;
			}
		}

		public static bool ReservoirPre(object __instance, ref bool __result)
		{
			//IL_00fe: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0121: Unknown result type (might be due to invalid IL or missing references)
			//IL_0165: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_01c7: Expected I4, but got Unknown
			try
			{
				if (!Plugin.Enabled.Value || !Plugin.ZombieFishing.Value || !Yard.CarriedZombie(out var item))
				{
					return true;
				}
				Wgo value = Traverse.Create(__instance).Field("assignedWgo").GetValue<Wgo>();
				if ((Object)(object)value == (Object)null || value.Data == null)
				{
					return true;
				}
				__result = true;
				foreach (Fisher value2 in Fishers.Values)
				{
					ZombieWgoData zombie = MainGame.ZombieSystemData.GetZombie(value2.Id);
					if (zombie != null && ((WgoData)zombie).GameResStr.Get("zpp_fish", "") == value.Data.UniqueId.Guid.ToString())
					{
						Yard.Say(T.S("FishTaken"));
						return false;
					}
				}
				DockPoint val = value.TryGetDockPointForWorker(false, default(Vector3));
				if ((Object)(object)val == (Object)null)
				{
					val = value.TryGetDockPointForWorker(true, MainGame.PlayerData.position.Value);
				}
				if ((Object)(object)val == (Object)null)
				{
					Yard.Say(T.S("FishNoSpot"));
					return false;
				}
				PlayerData playerData = MainGame.PlayerData;
				ZombieWgoData val2 = MainGame.ZombieSystemData.PutZombieFromStoreToGameSceneAsCommon(playerData, item, playerData.currentGameSceneId, ((Component)val).transform.position, val.Direction);
				if (val2 == null)
				{
					return false;
				}
				((WgoData)val2).GameResStr.Set("zpp_fish", value.Data.UniqueId.Guid.ToString());
				((WgoData)val2).GameResStr.Set("zpp_fish_dir", ((int)val.Direction).ToString());
				Plugin.Log.LogInfo((object)("zombie " + ((ObjectLinkedToDefinition<WGODef>)(object)val2).id + " fishes at " + ((ObjectLinkedToDefinition<WGODef>)(object)value.Data).id + " (" + playerData.currentGameSceneId + ")"));
				Yard.Say(T.F("FishStart", Notify.ZombieName(val2)));
				return false;
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Fishing: " + ex));
				return true;
			}
		}

		internal static void Released(ZombieWgoData z)
		{
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			if (Fishers.TryGetValue(((WgoData)z).UniqueId.Guid, out var value))
			{
				Show(z, (AnimationState)0, value.Dir, rope: false);
				Fishers.Remove(((WgoData)z).UniqueId.Guid);
			}
		}

		public static void Tick()
		{
			//IL_002c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Invalid comparison between Unknown and I4
			if (!Plugin.Enabled.Value || !Plugin.ZombieFishing.Value)
			{
				return;
			}
			try
			{
				if ((Object)(object)MainGame.Instance == (Object)null || (int)MainGame.Instance.gameState != 1 || MainGame.WorldData == null)
				{
					return;
				}
				if (Time.unscaledTime >= _scanAt)
				{
					_scanAt = Time.unscaledTime + 1f;
					Scan();
				}
				float deltaTime = Time.deltaTime;
				foreach (Fisher item in new List<Fisher>(Fishers.Values))
				{
					ZombieWgoData zombie = MainGame.ZombieSystemData.GetZombie(item.Id);
					if (zombie == null)
					{
						Fishers.Remove(item.Id.Guid);
					}
					else
					{
						Step(zombie, item, deltaTime);
					}
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogWarning((object)("Fishing: " + ex.Message));
			}
		}

		private static void Scan()
		{
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			ZombieSystemData zombieSystemData = MainGame.ZombieSystemData;
			if (zombieSystemData == null)
			{
				return;
			}
			foreach (SGuid zombieOnSceneWgoId in zombieSystemData.zombieOnSceneWgoIds)
			{
				if (Fishers.ContainsKey(zombieOnSceneWgoId.Guid))
				{
					continue;
				}
				ZombieWgoData zombie = zombieSystemData.GetZombie(zombieOnSceneWgoId);
				if (zombie != null && ((WgoData)zombie).GameResStr.Has("zpp_fish") && Yard.IsLoose(zombie))
				{
					Fisher fisher = new Fisher
					{
						Id = zombieOnSceneWgoId
					};
					if (int.TryParse(((WgoData)zombie).GameResStr.Get("zpp_fish_dir", ""), out var result))
					{
						fisher.Dir = (Direction)result;
					}
					Fishers[zombieOnSceneWgoId.Guid] = fisher;
				}
			}
		}

		private static WgoData Spot(ZombieWgoData z)
		{
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Expected O, but got Unknown
			if (!Guid.TryParse(((WgoData)z).GameResStr.Get("zpp_fish", ""), out var result))
			{
				return null;
			}
			return MainGame.WorldData.GetWgoData(new SGuid(result));
		}

		private static void Step(ZombieWgoData z, Fisher f, float dt)
		{
			//IL_0015: 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_009d: Unknown result type (might be due to invalid IL or missing references)
			f.Left -= dt;
			Show(z, StateOf(f.Phase), f.Dir, f.Phase >= Phase.Cast && f.Phase <= Phase.Catch);
			if (f.Left > 0f)
			{
				return;
			}
			WgoData val = Spot(z);
			if (val == null)
			{
				Plugin.Log.LogWarning((object)("fishing spot of " + ((ObjectLinkedToDefinition<WGODef>)(object)z).id + " is gone"));
				((WgoData)z).GameResStr.Remove("zpp_fish");
				Fishers.Remove(f.Id.Guid);
				Show(z, (AnimationState)0, f.Dir, rope: false);
				return;
			}
			switch (f.Phase)
			{
			case Phase.Rest:
			case Phase.Idle:
				if (!Ready(z, val, f))
				{
					f.Phase = Phase.Idle;
					f.Left = 5f;
				}
				else if (!Choose(z, val, f))
				{
					f.Phase = Phase.Idle;
					f.Left = 5f;
				}
				else
				{
					f.Phase = Phase.Start;
					f.Left = 0.7f;
				}
				break;
			case Phase.Start:
				f.Phase = Phase.Cast;
				f.Left = 1.2f;
				break;
			case Phase.Cast:
				f.Phase = Phase.Wait;
				f.Left = Random.Range(Mathf.Max(1.5f, f.Fish.WaitTimeLeft), Mathf.Max(3f, f.Fish.WaitTimeRight));
				break;
			case Phase.Wait:
				f.Phase = Phase.Pull;
				f.Left = 2.5f;
				break;
			case Phase.Pull:
				f.Hooked = Random.value < HookChance(z, f.Fish);
				if (f.Hooked)
				{
					Land(z, val, f.Fish);
					f.Phase = Phase.Catch;
					f.Left = 1.5f;
					break;
				}
				f.Phase = Phase.Release;
				f.Left = 1.2f;
				if (Plugin.Verbose.Value)
				{
					Plugin.Log.LogInfo((object)(((ObjectLinkedToDefinition<WGODef>)(object)z).id + " lost a " + f.Fish.fishId));
				}
				break;
			default:
				f.Phase = Phase.Rest;
				f.Left = 1.5f;
				break;
			}
		}

		private static AnimationState StateOf(Phase p)
		{
			return (AnimationState)(p switch
			{
				Phase.Start => 201, 
				Phase.Cast => 202, 
				Phase.Wait => 203, 
				Phase.Pull => 204, 
				Phase.Catch => 206, 
				Phase.Release => 205, 
				Phase.Rest => 203, 
				_ => 0, 
			});
		}

		private static Vector3 PlayerRodOffset()
		{
			//IL_0033: Unknown result type (might be due to invalid IL or missing references)
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_0256: Unknown result type (might be due to invalid IL or missing references)
			//IL_025b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0260: Unknown result type (might be due to invalid IL or missing references)
			//IL_026e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			if (_playerRodLooked)
			{
				return (Vector3)(((??)_playerRodOffset) ?? Vector3.zero);
			}
			PlayerController playerController = MainGame.PlayerController;
			if ((Object)(object)playerController == (Object)null)
			{
				return Vector3.zero;
			}
			_playerRodLooked = true;
			try
			{
				Transform val = null;
				Transform val2 = null;
				Transform[] componentsInChildren = ((Component)playerController).GetComponentsInChildren<Transform>(true);
				foreach (Transform val3 in componentsInChildren)
				{
					if ((Object)(object)val3 != (Object)null && (Object)(object)val2 == (Object)null && ((Object)val3).name.StartsWith("bdy", StringComparison.OrdinalIgnoreCase) && (Object)(object)((Component)val3).GetComponent<SpriteRenderer>() != (Object)null)
					{
						val2 = val3;
					}
				}
				FishingContainer componentInChildren = ((Component)playerController).GetComponentInChildren<FishingContainer>(true);
				List<string> list = new List<string>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					SpriteRenderer[] componentsInChildren2 = ((Component)componentInChildren).GetComponentsInChildren<SpriteRenderer>(true);
					foreach (SpriteRenderer val4 in componentsInChildren2)
					{
						if (!((Object)(object)val4 == (Object)null))
						{
							string name = ((Object)val4).name;
							string obj = (((Object)(object)val4.sprite != (Object)null) ? ("=" + ((Object)val4.sprite).name) : "");
							object obj2;
							if (!((Object)(object)val2 != (Object)null))
							{
								obj2 = "?";
							}
							else
							{
								Vector3 val5 = val2.InverseTransformPoint(((Component)val4).transform.position);
								obj2 = ((Vector3)(ref val5)).ToString("F3");
							}
							list.Add(name + obj + "@" + (string?)obj2);
							if ((Object)(object)val == (Object)null && (((Object)val4).name.IndexOf("rod", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)(object)val4.sprite != (Object)null && ((Object)val4.sprite).name.Contains("_rod_"))))
							{
								val = ((Component)val4).transform;
							}
						}
					}
				}
				if ((Object)(object)val == (Object)null && (Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.AnimationComponent != (Object)null && (Object)(object)((AnimationComponentBase)componentInChildren.AnimationComponent).Animator != (Object)null)
				{
					val = ((Component)((AnimationComponentBase)componentInChildren.AnimationComponent).Animator).transform;
				}
				Plugin.Log.LogInfo((object)("fishing rod: player's FishingContainer " + (((Object)(object)componentInChildren != (Object)null) ? "found" : "missing") + ", renderers: " + string.Join(", ", list.ToArray())));
				if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null)
				{
					Vector3 value = val2.InverseTransformPoint(val.position);
					value.z = 0f;
					_playerRodOffset = value;
					Plugin.Log.LogInfo((object)("fishing rod offset from the player's prefab: " + ((Vector3)(ref value)).ToString("F3") + " (rod '" + ((Object)val).name + "' under '" + (((Object)(object)val.parent != (Object)null) ? ((Object)val.parent).name : "-") + "', body '" + ((Object)val2).name + "' under '" + (((Object)(object)val2.parent != (Object)null) ? ((Object)val2.parent).name : "-") + "')"));
				}
				else
				{
					Plugin.Log.LogInfo((object)("fishing rod offset: the player has no rod/bdy renderers (" + ((Object)(object)val != (Object)null) + "/" + ((Object)(object)val2 != (Object)null) + ")"));
				}
			}
			catch (Exception ex)
			{
				Plugin.Log.LogInfo((object)("fishing rod offset: " + ex.Message));
			}
			return (Vector3)(((??)_playerRodOffset) ?? Vector3.zero);
		}

		private static SpriteRenderer FindBody(Wgo view)
		{
			SpriteRenderer[] componentsInChildren = ((Component)view).GetComponentsInChildren<SpriteRenderer>(false);
			foreach (SpriteRenderer val in componentsInChildren)
			{
				if ((Object)(object)val != (Object)null && (Object)(object)val.sprite != (Object)null && ((Object)val.sprite).name.Contains("_bdy_") && ((Object)val).name != "zpp_fish_arm" && ((Object)val).name != "zpp_fish_rod")
				{
					return val;
				}
			}
			return null;
		}

		private static SpriteRenderer Layer(SpriteRenderer body, string name, int above, bool bodyMaterial)
		{
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: Unknown result type (might be due to invalid IL or missing references)
			Transform val = ((Component)body).transform.Find(name);
			SpriteRenderer val3;
			if ((Object)(object)val == (Object)null)
			{
				GameObject val2 = new GameObject(name);
				val2.transform.SetParent(((Component)body).transform, false);
				val2.layer = ((Component)body).gameObject.layer;
				val3 = val2.AddComponent<SpriteRenderer>();
				if (bodyMaterial)
				{
					((Renderer)val3).sharedMaterial = ((Renderer)body).sharedMaterial;
				}
			}
			else
			{
				val3 = ((Component)val).GetComponent<SpriteRenderer>();
			}
			((Renderer)val3).sortingLayerID = ((Renderer)body).sortingLayerID;
			((Renderer)val3).sortingOrder = ((Renderer)body).sortingOrder + above;
			val3.flipX = body.flipX;
			if (bodyMaterial)
			{
				val3.color = body.color;
			}
			val3.flipY = body.flipY;
			return val3;
		}

		private static Sprite Frame(string name)
		{
			try
			{
				return LazySingletonSO<EasySpritesCollection>.Instance.GetSprite(name, (string)null);
			}
			catch
			{
				return null;
			}
		}

		private static void Layers(ZombieWgoData z, bool fishing)
		{
			//IL_027b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0292: Unknown result type (might be due to invalid IL or missing references)
			//IL_02ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_0341: Unknown result type (might be due to invalid IL or missing references)
			//IL_0346: Unknown result type (might be due to invalid IL or missing references)
			//IL_0366: Unknown result type (might be due to invalid IL or missing references)
			//IL_036b: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
			//IL_03d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_03fb: Unknown result type (might be due to invalid IL or missing references)
			//IL_0453: Unknown result type (might be due to invalid IL or missing references)
			//IL_0458: Unknown result type (might be due to invalid IL or missing references)
			//IL_0479: Unknown result type (might be due to invalid IL or missing references)
			//IL_047e: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_04c7: Unknown result type (might be due to invalid IL or missing references)
			Wgo wgoViewGlobal = GameScene.GetWgoViewGlobal(((WgoData)z).UniqueId);
			if ((Object)(object)wgoViewGlobal == (Object)null)
			{
				return;
			}
			SpriteRenderer val = FindBody(wgoViewGlobal);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Match match = ((fishing && (Object)(object)val.sprite != (Object)null) ? BodyFrame.Match(((Object)val.sprite).name.Replace("(Clone)", "")) : null);
			if (match == null || !match.Success)
			{
				string[] array = new string[2] { "zpp_fish_arm", "zpp_fish_rod" };
				foreach (string text in array)
				{
					Transform val2 = ((Component)val).transform.Find(text);
					if ((Object)(object)val2 != (Object)null)
					{
						((Renderer)((Component)val2).GetComponent<SpriteRenderer>()).enabled = false;
					}
				}
				return;
			}
			string value = match.Groups