Decompiled source of VikingAI v0.1.1

VikingAI.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.AI;
using VikingAI.Configuration;
using VikingAI.Core;
using VikingAI.FlowField;
using VikingAI.Locomotion;
using VikingAI.NPC.Affordances;
using VikingAI.NPC.Prefabs;
using VikingAI.NPC.Utility;
using VikingAI.Navigation;
using VikingAI.Patches;
using VikingAI.Profiles;
using VikingAI.Simulation;
using VikingAI.Tactics;
using VikingAI.Telemetry;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("DigitalVikings")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Foundational 2.5D navigation graph, flow-field steering, tactical pack coordination, smart-object affordances, and virtual NPC simulation framework for Valheim.")]
[assembly: AssemblyFileVersion("0.1.1.0")]
[assembly: AssemblyInformationalVersion("0.1.1+1819713a0086c92118d209a9c814ec4b38edc8fc")]
[assembly: AssemblyProduct("VikingAI")]
[assembly: AssemblyTitle("VikingAI")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.1.1.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

		public NullableAttribute(byte P_0)
		{
			NullableFlags = new byte[1] { P_0 };
		}

		public NullableAttribute(byte[] P_0)
		{
			NullableFlags = P_0;
		}
	}
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableContextAttribute : Attribute
	{
		public readonly byte Flag;

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
	[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 VikingAI
{
	[BepInPlugin("com.digitalvikings.vikingai", "VikingAI", "0.1.1")]
	[BepInDependency(/*Could not decode attribute arguments.*/)]
	public class VikingAIPlugin : BaseUnityPlugin
	{
		public const string ModGuid = "com.digitalvikings.vikingai";

		public const string ModName = "VikingAI";

		public const string ModVersion = "0.1.1";

		private Harmony _harmony;

		public static VikingAIPlugin Instance { get; private set; }

		public static ManualLogSource Log { get; internal set; }

		private void Awake()
		{
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Expected O, but got Unknown
			Instance = this;
			Log = ((BaseUnityPlugin)this).Logger;
			Log.LogInfo((object)"VikingAI v0.1.1 initializing...");
			ModConfig.Init(((BaseUnityPlugin)this).Config);
			BrainPipeline.RegisterModule(new PackFlankBrainModule());
			BrainPipeline.RegisterModule(new InvestigateBrainModule());
			BrainPipeline.RegisterModule(new SmartAffordanceBrainModule());
			((Component)this).gameObject.AddComponent<NavDebugOverlay>();
			VikingAIConsoleCommand.Register();
			_harmony = new Harmony("com.digitalvikings.vikingai");
			_harmony.PatchAll();
			Log.LogInfo((object)"VikingAI v0.1.1 loaded successfully.");
			if (Chainloader.PluginInfos.ContainsKey("com.jotunn.jotunn"))
			{
				HookJotunnSync();
			}
		}

		private void Update()
		{
			if (ModConfig.ModEnabled.Value)
			{
				VirtualAgentDirector.UpdateDirector(Time.deltaTime);
				if (NavDebugOverlay.ActiveMode != DebugDrawMode.Off)
				{
					NavGraphManager.DrawDebugTelemetry();
					TacticalFlowField.DrawDebugTelemetry();
					AffordanceRegistry.DrawDebugTelemetry();
				}
			}
		}

		[MethodImpl(MethodImplOptions.NoInlining)]
		private void HookJotunnSync()
		{
			SynchronizationManager.OnConfigurationSynchronized += delegate
			{
				Log.LogInfo((object)"Server configuration synchronized successfully.");
			};
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}
	}
}
namespace VikingAI.Telemetry
{
	[Flags]
	public enum DebugDrawMode
	{
		Off = 0,
		Grid = 1,
		Flow = 2,
		Steering = 4,
		Tokens = 8,
		Affordances = 0x10,
		Senses = 0x20,
		All = 0x3F
	}
	public struct DebugLineSegment
	{
		public Vector3 Start;

		public Vector3 End;

		public Color Color;
	}
	public struct DebugWorldLabel
	{
		public Vector3 WorldPos;

		public string Text;

		public Color Color;
	}
	public sealed class NavDebugOverlay : MonoBehaviour
	{
		private static readonly List<DebugLineSegment> _frameLines = new List<DebugLineSegment>(512);

		private static readonly List<DebugWorldLabel> _frameLabels = new List<DebugWorldLabel>(128);

		private static Material? _lineMaterial;

		private static int _lastClearedFrame = -1;

		public static DebugDrawMode ActiveMode { get; set; } = DebugDrawMode.Off;

		public static bool IsModeActive(DebugDrawMode mode)
		{
			return (ActiveMode & mode) != 0;
		}

		public static void AddLine(Vector3 start, Vector3 end, Color color)
		{
			//IL_002d: 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_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (ActiveMode != DebugDrawMode.Off)
			{
				EnsureFrameCleared();
				if (_frameLines.Count < 4096)
				{
					_frameLines.Add(new DebugLineSegment
					{
						Start = start,
						End = end,
						Color = color
					});
				}
			}
		}

		public static void AddLabel(Vector3 worldPos, string text, Color color)
		{
			//IL_002d: 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_003d: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (ActiveMode != DebugDrawMode.Off)
			{
				EnsureFrameCleared();
				if (_frameLabels.Count < 256)
				{
					_frameLabels.Add(new DebugWorldLabel
					{
						WorldPos = worldPos,
						Text = text,
						Color = color
					});
				}
			}
		}

		private static void EnsureFrameCleared()
		{
			int frameCount = Time.frameCount;
			if (_lastClearedFrame != frameCount)
			{
				_lastClearedFrame = frameCount;
				_frameLines.Clear();
				_frameLabels.Clear();
			}
		}

		private static void EnsureMaterial()
		{
			//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_0035: Expected O, but got Unknown
			if (!((Object)(object)_lineMaterial != (Object)null))
			{
				Shader val = Shader.Find("Hidden/Internal-Colored");
				if ((Object)(object)val != (Object)null)
				{
					_lineMaterial = new Material(val)
					{
						hideFlags = (HideFlags)61
					};
					_lineMaterial.SetInt("_SrcBlend", 5);
					_lineMaterial.SetInt("_DstBlend", 10);
					_lineMaterial.SetInt("_Cull", 0);
					_lineMaterial.SetInt("_ZWrite", 0);
				}
			}
		}

		private void OnRenderObject()
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_005a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0065: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0080: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			if (ActiveMode == DebugDrawMode.Off || _frameLines.Count == 0)
			{
				return;
			}
			EnsureMaterial();
			if (!((Object)(object)_lineMaterial == (Object)null))
			{
				_lineMaterial.SetPass(0);
				GL.PushMatrix();
				GL.Begin(1);
				for (int i = 0; i < _frameLines.Count; i++)
				{
					DebugLineSegment debugLineSegment = _frameLines[i];
					GL.Color(debugLineSegment.Color);
					GL.Vertex3(debugLineSegment.Start.x, debugLineSegment.Start.y, debugLineSegment.Start.z);
					GL.Vertex3(debugLineSegment.End.x, debugLineSegment.End.y, debugLineSegment.End.z);
				}
				GL.End();
				GL.PopMatrix();
			}
		}

		private void OnGUI()
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: 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_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			if (ActiveMode == DebugDrawMode.Off)
			{
				return;
			}
			Camera mainCamera = Utils.GetMainCamera();
			if ((Object)(object)mainCamera == (Object)null)
			{
				return;
			}
			GUI.color = Color.cyan;
			GUI.Label(new Rect(16f, 16f, 480f, 26f), $"[VikingAI Telemetry] Active Modes: {ActiveMode}");
			for (int i = 0; i < _frameLabels.Count; i++)
			{
				DebugWorldLabel debugWorldLabel = _frameLabels[i];
				Vector3 val = mainCamera.WorldToScreenPoint(debugWorldLabel.WorldPos);
				if (!(val.z <= 0f))
				{
					float num = (float)Screen.height - val.y;
					GUI.color = Color.black;
					GUI.Label(new Rect(val.x + 1f, num + 1f, 260f, 44f), debugWorldLabel.Text);
					GUI.color = debugWorldLabel.Color;
					GUI.Label(new Rect(val.x, num, 260f, 44f), debugWorldLabel.Text);
				}
			}
		}
	}
	public sealed class VikingAIConsoleCommand : ConsoleCommand
	{
		public override string Name => "vikingai";

		public override string Help => "VikingAI diagnostic telemetry and debug visualization (subcommands: debug, stats)";

		public override bool IsCheat => false;

		public static void Register()
		{
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new VikingAIConsoleCommand());
		}

		public override void Run(string[] args)
		{
			if (args == null || args.Length == 0)
			{
				Console.instance.Print("Usage: vikingai debug [grid|flow|steering|tokens|affordances|senses|all|off] | vikingai stats");
				return;
			}
			string text = args[0].ToLowerInvariant();
			if (text == "debug")
			{
				string text2 = ((args.Length > 1) ? args[1].ToLowerInvariant() : "all");
				switch (text2)
				{
				case "off":
				case "none":
					NavDebugOverlay.ActiveMode = DebugDrawMode.Off;
					break;
				case "grid":
					ToggleFlag(DebugDrawMode.Grid);
					break;
				case "flow":
					ToggleFlag(DebugDrawMode.Flow);
					break;
				case "steering":
					ToggleFlag(DebugDrawMode.Steering);
					break;
				case "tokens":
					ToggleFlag(DebugDrawMode.Tokens);
					break;
				case "affordances":
					ToggleFlag(DebugDrawMode.Affordances);
					break;
				case "senses":
					ToggleFlag(DebugDrawMode.Senses);
					break;
				case "all":
					NavDebugOverlay.ActiveMode = DebugDrawMode.All;
					break;
				default:
					Console.instance.Print("Unknown debug mode '" + text2 + "'. Valid modes: grid, flow, steering, tokens, affordances, senses, all, off");
					return;
				}
				Console.instance.Print($"[VikingAI] Debug overlay mode: {NavDebugOverlay.ActiveMode}");
			}
			else if (text == "stats")
			{
				Console.instance.Print($"[VikingAI] Tracked pieces — Doors: {PieceRegistry.Doors.Count}, " + $"Smelters: {PieceRegistry.Smelters.Count}, Containers: {PieceRegistry.Containers.Count}, " + $"Fireplaces: {PieceRegistry.Fireplaces.Count}, Plants: {PieceRegistry.Plants.Count}, " + $"Pickables: {PieceRegistry.Pickables.Count}, Beds: {PieceRegistry.Beds.Count}, Chairs: {PieceRegistry.Chairs.Count}");
			}
			else
			{
				Console.instance.Print("Unknown subcommand. Usage: vikingai debug [mode] | vikingai stats");
			}
		}

		public override List<string> CommandOptionList()
		{
			return new List<string> { "debug", "stats" };
		}

		private static void ToggleFlag(DebugDrawMode flag)
		{
			if ((NavDebugOverlay.ActiveMode & flag) != DebugDrawMode.Off)
			{
				NavDebugOverlay.ActiveMode &= ~flag;
			}
			else
			{
				NavDebugOverlay.ActiveMode |= flag;
			}
		}
	}
}
namespace VikingAI.Tactics
{
	public static class BrainPipeline
	{
		private static readonly List<IAIBrainModule> _modules = new List<IAIBrainModule>(8);

		private static readonly ConditionalWeakTable<BaseAI, IAIBrainModule> _activeModuleByAi = new ConditionalWeakTable<BaseAI, IAIBrainModule>();

		public static void RegisterModule(IAIBrainModule module)
		{
			if (module != null)
			{
				_modules.RemoveAll((IAIBrainModule m) => m.Id == module.Id);
				_modules.Add(module);
			}
		}

		public static IAIBrainModule? GetActiveModule(BaseAI ai)
		{
			if ((Object)(object)ai != (Object)null && _activeModuleByAi.TryGetValue(ai, out IAIBrainModule value))
			{
				return value;
			}
			return null;
		}

		public static bool TryExecuteModules(BaseAI ai, Character character, float dt)
		{
			if (!ModConfig.ModEnabled.Value || _modules.Count == 0)
			{
				return false;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(character);
			IAIBrainModule iAIBrainModule = null;
			float num = 0f;
			for (int i = 0; i < _modules.Count; i++)
			{
				IAIBrainModule iAIBrainModule2 = _modules[i];
				float num2 = iAIBrainModule2.EvaluateUtility(ai, character, profile);
				if (num2 > num)
				{
					num = num2;
					iAIBrainModule = iAIBrainModule2;
				}
			}
			_activeModuleByAi.Remove(ai);
			if (iAIBrainModule == null)
			{
				return false;
			}
			_activeModuleByAi.Add(ai, iAIBrainModule);
			return iAIBrainModule.Tick(ai, character, profile, dt);
		}
	}
	public static class CombatPackCoordinator
	{
		private sealed class TokenAllocation
		{
			public Character Holder;

			public float Weight;

			public float GrantedAtTime;

			public float ExpiresAtTime;
		}

		private static readonly List<ITargetScorer> _scorers = new List<ITargetScorer>
		{
			new ProximityThreatScorer()
		};

		private static readonly Dictionary<Character, List<TokenAllocation>> _tokensByTarget = new Dictionary<Character, List<TokenAllocation>>(8);

		private static readonly List<Character> _nearbyPackTemp = new List<Character>(16);

		public static void RegisterTargetScorer(ITargetScorer scorer)
		{
			if (scorer != null)
			{
				_scorers.RemoveAll((ITargetScorer s) => s.Id == scorer.Id);
				_scorers.Add(scorer);
			}
		}

		public static float EvaluateTotalTargetScore(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidate)
		{
			float num = 0f;
			for (int i = 0; i < _scorers.Count; i++)
			{
				num += _scorers[i].ScoreTarget(ai, agent, profile, candidate);
			}
			return num;
		}

		public static bool RequestOrHoldAttackToken(Character attacker, AgentBehaviorProfile profile, Character target)
		{
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_0131: 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_013b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_0189: Unknown result type (might be due to invalid IL or missing references)
			if (!profile.UsePackAttackTokens)
			{
				return true;
			}
			float time = Time.time;
			if (!_tokensByTarget.TryGetValue(target, out List<TokenAllocation> value))
			{
				value = new List<TokenAllocation>(6);
				_tokensByTarget[target] = value;
			}
			float num = 0f;
			TokenAllocation tokenAllocation = null;
			for (int num2 = value.Count - 1; num2 >= 0; num2--)
			{
				TokenAllocation tokenAllocation2 = value[num2];
				if ((Object)(object)tokenAllocation2.Holder == (Object)null || tokenAllocation2.Holder.IsDead() || time > tokenAllocation2.ExpiresAtTime)
				{
					value.RemoveAt(num2);
				}
				else if ((Object)(object)tokenAllocation2.Holder == (Object)(object)attacker)
				{
					tokenAllocation = tokenAllocation2;
				}
				else
				{
					num += tokenAllocation2.Weight;
				}
			}
			if (tokenAllocation != null)
			{
				tokenAllocation.ExpiresAtTime = time + 2.8f;
				return true;
			}
			float value2 = ModConfig.MaxSimultaneousAttackTokens.Value;
			float num3 = Mathf.Max(0.5f, profile.AttackTokenWeight);
			if (num + num3 <= value2 + 0.01f || value.Count == 0)
			{
				value.Add(new TokenAllocation
				{
					Holder = attacker,
					Weight = num3,
					GrantedAtTime = time,
					ExpiresAtTime = time + 2.8f
				});
				return true;
			}
			Vector3 val = ((Component)attacker).transform.position - ((Component)target).transform.position;
			float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude;
			for (int i = 0; i < value.Count; i++)
			{
				TokenAllocation tokenAllocation3 = value[i];
				if (!(time - tokenAllocation3.GrantedAtTime < 1.8f))
				{
					val = ((Component)tokenAllocation3.Holder).transform.position - ((Component)target).transform.position;
					float sqrMagnitude2 = ((Vector3)(ref val)).sqrMagnitude;
					if (sqrMagnitude + 9f < sqrMagnitude2)
					{
						value[i] = new TokenAllocation
						{
							Holder = attacker,
							Weight = num3,
							GrantedAtTime = time,
							ExpiresAtTime = time + 2.8f
						};
						return true;
					}
				}
			}
			return false;
		}

		public static Vector3 GetFlankingRingPosition(Character attacker, Character target)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: 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_00e0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
			Vector3 position = ((Component)target).transform.position;
			_nearbyPackTemp.Clear();
			SpatialCharacterGrid.QueryRadius(position, 18f, _nearbyPackTemp, target);
			int num = 0;
			int instanceID = ((Object)attacker).GetInstanceID();
			for (int i = 0; i < _nearbyPackTemp.Count; i++)
			{
				Character val = _nearbyPackTemp[i];
				if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)attacker && ((Object)val).GetInstanceID() < instanceID)
				{
					num++;
				}
			}
			float num2 = (float)(num % 8) * 45f;
			float num3 = Mathf.Sin(Time.time * 0.65f + (float)num * 1.3f) * 22f;
			float num4 = (num2 + num3) * (MathF.PI / 180f);
			float num5 = 4.4f + (float)(num / 8) * 1.5f + target.GetRadius();
			return position + new Vector3(Mathf.Sin(num4) * num5, 0f, Mathf.Cos(num4) * num5);
		}
	}
	public sealed class PackFlankBrainModule : IAIBrainModule
	{
		private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null);

		private static readonly MethodInfo _havePathMethod = AccessTools.Method(typeof(BaseAI), "HavePath", (Type[])null, (Type[])null);

		public string Id => "VikingAI.PackFlankAndAntiPerch";

		public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile)
		{
			//IL_0074: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0103: Unknown result type (might be due to invalid IL or missing references)
			//IL_0108: Unknown result type (might be due to invalid IL or missing references)
			//IL_0126: Unknown result type (might be due to invalid IL or missing references)
			//IL_011f: Unknown result type (might be due to invalid IL or missing references)
			MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (val == null)
			{
				return 0f;
			}
			Character targetCreature = ((BaseAI)val).GetTargetCreature();
			if ((Object)(object)targetCreature == (Object)null || targetCreature.IsDead() || !ai.IsAlerted())
			{
				return 0f;
			}
			Humanoid val2 = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (val2 != null)
			{
				ItemData currentWeapon = val2.GetCurrentWeapon();
				if (currentWeapon != null && currentWeapon.m_shared != null && currentWeapon.m_shared.m_aiAttackRange > 5f)
				{
					return 0f;
				}
			}
			if (((Component)targetCreature).transform.position.y - ((Component)character).transform.position.y > 2.2f && _havePathMethod != null && !(bool)_havePathMethod.Invoke(ai, new object[1] { ((Component)targetCreature).transform.position }))
			{
				return 75f;
			}
			if (!profile.UsePackAttackTokens)
			{
				return 0f;
			}
			bool flag = CombatPackCoordinator.RequestOrHoldAttackToken(character, profile, targetCreature);
			if (NavDebugOverlay.IsModeActive(DebugDrawMode.Tokens))
			{
				NavDebugOverlay.AddLabel(character.GetTopPoint() + Vector3.up * 0.25f, flag ? "[TOKEN: ENGAGE]" : "[FLANKING RING]", flag ? Color.green : Color.cyan);
			}
			if (flag)
			{
				return 0f;
			}
			return 70f;
		}

		public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt)
		{
			//IL_0031: 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_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0088: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e8: 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)
			MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (val == null || _moveToMethod == null)
			{
				return false;
			}
			Character targetCreature = ((BaseAI)val).GetTargetCreature();
			if ((Object)(object)targetCreature == (Object)null)
			{
				return false;
			}
			Vector3 val2 = ((Component)targetCreature).transform.position - ((Component)character).transform.position;
			val2.y = 0f;
			Vector3 val3 = ((((Vector3)(ref val2)).sqrMagnitude > 0.01f) ? ((Vector3)(ref val2)).normalized : ((Component)character).transform.forward);
			LocomotionPatches.ActiveLookDirOverride = val3;
			try
			{
				Vector3 flankingRingPosition = CombatPackCoordinator.GetFlankingRingPosition(character, targetCreature);
				if (Utils.DistanceXZ(((Component)character).transform.position, flankingRingPosition) > 1.1f)
				{
					_moveToMethod.Invoke(ai, new object[4] { dt, flankingRingPosition, 0.5f, false });
				}
				else
				{
					ai.StopMoving();
					ai.LookTowards(val3);
				}
			}
			finally
			{
				LocomotionPatches.ActiveLookDirOverride = null;
			}
			return true;
		}
	}
	public sealed class TargetCoverState
	{
		public float IlluminationFactor = 1f;

		public float FoliageConcealment;

		public float AcousticRadius = 5f;

		public float LastSampleTime = -999f;
	}
	public static class EnvironmentCoverSampler
	{
		private static readonly ConditionalWeakTable<Character, TargetCoverState> _states = new ConditionalWeakTable<Character, TargetCoverState>();

		private static readonly Collider[] _overlapBuffer = (Collider[])(object)new Collider[48];

		private static int _shadowLayerMask;

		public static TargetCoverState GetOrSample(Character target)
		{
			if (!_states.TryGetValue(target, out TargetCoverState value))
			{
				value = new TargetCoverState();
				_states.Add(target, value);
			}
			float time = Time.time;
			if (time - value.LastSampleTime >= 0.25f)
			{
				value.LastSampleTime = time;
				UpdateTargetCover(target, value);
			}
			return value;
		}

		private static void UpdateTargetCover(Character target, TargetCoverState state)
		{
			//IL_0040: 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_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
			//IL_016d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0270: Unknown result type (might be due to invalid IL or missing references)
			//IL_0275: Unknown result type (might be due to invalid IL or missing references)
			if (_shadowLayerMask == 0)
			{
				_shadowLayerMask = LayerMask.GetMask(new string[5] { "terrain", "Default", "static_solid", "piece", "piece_nonsolid" });
			}
			Vector3 centerPoint = target.GetCenterPoint();
			float num = 1f;
			if ((Object)(object)EnvMan.instance != (Object)null)
			{
				if (EnvMan.IsNight())
				{
					num = 0.42f;
				}
				else if (EnvMan.IsAfternoon())
				{
					num = 0.82f;
				}
			}
			Light sun = RenderSettings.sun;
			if ((Object)(object)sun != (Object)null)
			{
				Vector3 val = -((Component)sun).transform.forward;
				if (val.y > 0.05f && Physics.Raycast(centerPoint, val, 80f, _shadowLayerMask))
				{
					num *= 0.65f;
				}
			}
			foreach (Fireplace fireplace in PieceRegistry.Fireplaces)
			{
				if (!((Object)(object)fireplace == (Object)null) && fireplace.IsBurning())
				{
					Vector3 val2 = ((Component)fireplace).transform.position - centerPoint;
					float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude;
					if (sqrMagnitude < 81f)
					{
						float num2 = (1f - Mathf.Sqrt(sqrMagnitude) / 9f) * 0.55f;
						num = Mathf.Min(1.25f, num + num2);
					}
				}
			}
			state.IlluminationFactor = Mathf.Clamp(num, 0.2f, 1.25f);
			float foliageConcealment = 0f;
			int num3 = Mathf.Min(Physics.OverlapSphereNonAlloc(centerPoint, 1.85f, _overlapBuffer, _shadowLayerMask), 12);
			for (int i = 0; i < num3; i++)
			{
				Collider val3 = _overlapBuffer[i];
				if (!((Object)(object)val3 == (Object)null) && IsFoliageColliderName(((Object)((Component)val3).gameObject).name))
				{
					foliageConcealment = (target.IsCrouching() ? 0.48f : 0.22f);
					break;
				}
			}
			state.FoliageConcealment = foliageConcealment;
			float num4 = 0f;
			Humanoid val4 = (Humanoid)(object)((target is Humanoid) ? target : null);
			if (val4 != null)
			{
				Inventory inventory = val4.GetInventory();
				if (inventory != null)
				{
					List<ItemData> allItems = inventory.GetAllItems();
					for (int j = 0; j < allItems.Count; j++)
					{
						ItemData val5 = allItems[j];
						if (val5 != null && val5.m_equipped && val5.m_shared != null)
						{
							num4 += val5.GetWeight(-1);
						}
					}
				}
			}
			float num5 = 1f + Mathf.Clamp01((num4 - 8f) / 36f) * 0.45f;
			Vector3 velocity = target.GetVelocity();
			velocity.y = 0f;
			float magnitude = ((Vector3)(ref velocity)).magnitude;
			float num6 = (target.InAttack() ? 18f : ((magnitude < 0.25f) ? 0.5f : (target.IsCrouching() ? (2.2f * num5) : ((!target.IsRunning() && !(magnitude > 5f)) ? (6.5f * num5) : (14f * num5)))));
			state.AcousticRadius = Mathf.Max(num6, target.GetNoiseRange() * 0.35f);
		}

		private static bool IsFoliageColliderName(string name)
		{
			if (string.IsNullOrEmpty(name))
			{
				return false;
			}
			if (name.IndexOf("Bush", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Shrub", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Fern", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Raspberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Blueberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Cloudberry", StringComparison.OrdinalIgnoreCase) < 0 && name.IndexOf("Sapling", StringComparison.OrdinalIgnoreCase) < 0)
			{
				return name.IndexOf("Thistle", StringComparison.OrdinalIgnoreCase) >= 0;
			}
			return true;
		}
	}
	public interface IAIBrainModule
	{
		string Id { get; }

		float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile);

		bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt);
	}
	public interface ITargetScorer
	{
		string Id { get; }

		float ScoreTarget(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidateTarget);
	}
	public sealed class ProximityThreatScorer : ITargetScorer
	{
		public string Id => "VikingAI.ProximityThreat";

		public float ScoreTarget(BaseAI ai, Character agent, AgentBehaviorProfile profile, Character candidateTarget)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)candidateTarget == (Object)null || candidateTarget.IsDead())
			{
				return -1000f;
			}
			float num = Vector3.Distance(((Component)agent).transform.position, ((Component)candidateTarget).transform.position);
			float num2 = Mathf.Max(0f, 60f - num);
			MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (val != null && (Object)(object)((BaseAI)val).GetTargetCreature() == (Object)(object)candidateTarget)
			{
				num2 += 12f;
			}
			if (candidateTarget.GetHealthPercentage() < 0.25f)
			{
				num2 += 8f;
			}
			return num2;
		}
	}
	public enum DetectionStage : byte
	{
		Unaware,
		Suspicious,
		Alerted,
		Engaged
	}
	public sealed class SensoryTrack
	{
		public Character? Target;

		public float DetectionLevel;

		public DetectionStage Stage;

		public Vector3 LastKnownPos;

		public float LastStimulusTime;

		public float SearchTimeRemaining;
	}
	public static class SensoryMemoryController
	{
		private struct PendingAllyCall
		{
			public Character Caller;

			public Character Target;

			public Vector3 KnownPos;

			public float Radius;
		}

		private static readonly ConditionalWeakTable<BaseAI, SensoryTrack> _tracks = new ConditionalWeakTable<BaseAI, SensoryTrack>();

		private static readonly PendingAllyCall[] _allyCallRing = new PendingAllyCall[32];

		private static int _ringHead;

		private static int _ringTail;

		private static int _ringCount;

		private static readonly List<Character> _allyQueryTemp = new List<Character>(16);

		private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character");

		private static readonly FieldRef<int>? _viewBlockMask = ((AccessTools.Field(typeof(BaseAI), "m_viewBlockMask") != null) ? AccessTools.StaticFieldRefAccess<int>(AccessTools.Field(typeof(BaseAI), "m_viewBlockMask")) : null);

		private static int _fallbackViewBlockMask;

		private static int GetViewBlockMask()
		{
			if (_viewBlockMask != null)
			{
				int num = _viewBlockMask.Invoke();
				if (num != 0)
				{
					return num;
				}
			}
			if (_fallbackViewBlockMask == 0)
			{
				_fallbackViewBlockMask = LayerMask.GetMask(new string[7] { "Default", "static_solid", "Default_small", "piece", "terrain", "viewblock", "vehicle" });
			}
			return _fallbackViewBlockMask;
		}

		public static SensoryTrack GetOrCreateTrack(BaseAI ai)
		{
			if (!_tracks.TryGetValue(ai, out SensoryTrack value))
			{
				value = new SensoryTrack();
				_tracks.Add(ai, value);
			}
			return value;
		}

		public static bool ShouldUseSensoryEngine(BaseAI ai, out Character? observer, out AgentBehaviorProfile profile)
		{
			observer = _aiCharacter.Invoke(ai);
			if ((Object)(object)observer == (Object)null || !ModConfig.ModEnabled.Value || !ModConfig.EnableSensoryPerceptionEngine.Value)
			{
				profile = new AgentBehaviorProfile();
				return false;
			}
			if (AgentProfileRegistry.IsPerceptionExempt(observer))
			{
				profile = new AgentBehaviorProfile();
				return false;
			}
			profile = AgentProfileRegistry.GetProfile(observer);
			return profile.UseSensoryEngine;
		}

		public static bool EvaluateVisualStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character target)
		{
			//IL_004b: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0050: Unknown result type (might be due to invalid IL or missing references)
			//IL_007d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0083: Unknown result type (might be due to invalid IL or missing references)
			//IL_0084: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_008a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0075: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d7: 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_014f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ec: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null || target.IsDead())
			{
				return false;
			}
			Player val = (Player)(object)((target is Player) ? target : null);
			if (val != null && (val.InDebugFlyMode() || ((Character)val).InGhostMode()))
			{
				return false;
			}
			Vector3 val2 = (((Object)(object)observer.m_eye != (Object)null) ? observer.m_eye.position : observer.GetCenterPoint());
			Vector3 val3 = (target.IsCrouching() ? target.GetCenterPoint() : (((Object)(object)target.m_eye != (Object)null) ? target.m_eye.position : target.GetCenterPoint()));
			Vector3 val4 = val3 - val2;
			float magnitude = ((Vector3)(ref val4)).magnitude;
			float num = Mathf.Min(ai.m_viewRange, ModConfig.MaxVisualRange.Value);
			if (magnitude > num)
			{
				return false;
			}
			SensoryTrack orCreateTrack = GetOrCreateTrack(ai);
			if (orCreateTrack.Stage != DetectionStage.Engaged || !((Object)(object)orCreateTrack.Target == (Object)(object)target))
			{
				float num2 = Vector3.Angle(val4, ((Component)observer).transform.forward);
				float num3 = (((int)orCreateTrack.Stage >= 1) ? Mathf.Min(135f, ModConfig.VisionConeHalfAngle.Value * 1.45f) : ModConfig.VisionConeHalfAngle.Value);
				if (num2 > num3)
				{
					return false;
				}
			}
			int viewBlockMask = GetViewBlockMask();
			if (Physics.Raycast(val2, val4 / Mathf.Max(0.01f, magnitude), magnitude, viewBlockMask))
			{
				return false;
			}
			if (!ai.m_mistVision && ParticleMist.IsMistBlocked(val2, val3))
			{
				return false;
			}
			TargetCoverState orSample = EnvironmentCoverSampler.GetOrSample(target);
			float num4 = target.GetStealthFactor() * orSample.IlluminationFactor * (1f - orSample.FoliageConcealment);
			float num5 = num * Mathf.Clamp(num4, 0.15f, 1.3f);
			if (magnitude > num5)
			{
				return false;
			}
			float num6 = Mathf.Clamp01(1.15f - magnitude / Mathf.Max(1f, num5));
			float num7 = ModConfig.AlertGainRate.Value * num6 * 0.25f;
			if (magnitude < 4f)
			{
				num7 *= 2.5f;
			}
			ApplyStimulus(ai, observer, profile, target, ((Component)target).transform.position, num7);
			return (int)orCreateTrack.Stage >= 3;
		}

		public static bool EvaluateAuditoryStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character target)
		{
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)target == (Object)null || target.IsDead())
			{
				return false;
			}
			Player val = (Player)(object)((target is Player) ? target : null);
			if (val != null && (val.InDebugFlyMode() || ((Character)val).InGhostMode()))
			{
				return false;
			}
			float num = Vector3.Distance(((Component)observer).transform.position, ((Component)target).transform.position);
			float num2 = Mathf.Min(ai.m_hearRange, ModConfig.MaxHearingRange.Value);
			if (Character.InInterior(((Component)observer).transform))
			{
				num2 = Mathf.Min(12f, num2);
			}
			if (num > num2)
			{
				return false;
			}
			TargetCoverState orSample = EnvironmentCoverSampler.GetOrSample(target);
			if (num > orSample.AcousticRadius)
			{
				return false;
			}
			float num3 = Mathf.Clamp01(1f - num / Mathf.Max(1f, orSample.AcousticRadius));
			float deltaDetection = ModConfig.SuspicionGainRate.Value * num3 * 0.2f;
			ApplyStimulus(ai, observer, profile, target, ((Component)target).transform.position, deltaDetection);
			return (int)GetOrCreateTrack(ai).Stage >= 3;
		}

		public static void NotifyDamaged(BaseAI ai, Character? attacker)
		{
			//IL_004e: 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_007a: Unknown result type (might be due to invalid IL or missing references)
			if (!((Object)(object)attacker == (Object)null))
			{
				Character val = _aiCharacter.Invoke(ai);
				if (!((Object)(object)val == (Object)null))
				{
					AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val);
					SensoryTrack orCreateTrack = GetOrCreateTrack(ai);
					orCreateTrack.Target = attacker;
					orCreateTrack.DetectionLevel = 1f;
					orCreateTrack.Stage = DetectionStage.Engaged;
					orCreateTrack.LastKnownPos = ((Component)attacker).transform.position;
					orCreateTrack.LastStimulusTime = Time.time;
					orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value;
					EnqueueAllyCall(val, attacker, ((Component)attacker).transform.position, profile.CallForHelpRadius);
				}
			}
		}

		public static void NotifySoundImpulse(BaseAI ai, Character? source, Vector3 soundPosition, float impulseAmount)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			Character val = _aiCharacter.Invoke(ai);
			if (!((Object)(object)val == (Object)null))
			{
				AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val);
				ApplyStimulus(ai, val, profile, source, soundPosition, impulseAmount);
			}
		}

		public static void TickAgentMemory(BaseAI ai, Character observer, AgentBehaviorProfile profile, float dt)
		{
			//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00eb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0104: Unknown result type (might be due to invalid IL or missing references)
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_0143: Unknown result type (might be due to invalid IL or missing references)
			//IL_00fb: 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)
			ProcessOneQueuedAllyCall();
			if (profile.UseSensoryEngine && ModConfig.EnableSensoryPerceptionEngine.Value && _tracks.TryGetValue(ai, out SensoryTrack value))
			{
				if (Time.time - value.LastStimulusTime > 1.25f && value.DetectionLevel > 0f)
				{
					value.DetectionLevel = Mathf.Max(0f, value.DetectionLevel - ModConfig.DetectionDecayRate.Value * dt);
					UpdateStageFromLevel(ai, observer, profile, value);
				}
				if (value.SearchTimeRemaining > 0f)
				{
					value.SearchTimeRemaining = Mathf.Max(0f, value.SearchTimeRemaining - dt);
				}
				if (NavDebugOverlay.IsModeActive(DebugDrawMode.Senses) && value.DetectionLevel > 0.01f)
				{
					Color color = (Color)(value.Stage switch
					{
						DetectionStage.Engaged => Color.red, 
						DetectionStage.Alerted => new Color(1f, 0.55f, 0f), 
						DetectionStage.Suspicious => Color.yellow, 
						_ => Color.white, 
					});
					NavDebugOverlay.AddLabel(observer.GetTopPoint() + Vector3.up * 0.45f, $"{value.Stage} ({value.DetectionLevel * 100f:F0}%)", color);
				}
			}
		}

		private static void ApplyStimulus(BaseAI ai, Character observer, AgentBehaviorProfile profile, Character? target, Vector3 stimulusPos, float deltaDetection)
		{
			//IL_0037: 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_0099: Unknown result type (might be due to invalid IL or missing references)
			SensoryTrack orCreateTrack = GetOrCreateTrack(ai);
			float time = Time.time;
			if (!(time - orCreateTrack.LastStimulusTime < 0.12f) || !(deltaDetection < 0.5f))
			{
				if ((Object)(object)target != (Object)null)
				{
					orCreateTrack.Target = target;
				}
				orCreateTrack.LastKnownPos = stimulusPos;
				orCreateTrack.LastStimulusTime = time;
				orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value;
				orCreateTrack.DetectionLevel = Mathf.Clamp01(orCreateTrack.DetectionLevel + deltaDetection);
				DetectionStage stage = orCreateTrack.Stage;
				UpdateStageFromLevel(ai, observer, profile, orCreateTrack);
				if ((int)stage < 3 && orCreateTrack.Stage == DetectionStage.Engaged && (Object)(object)orCreateTrack.Target != (Object)null)
				{
					EnqueueAllyCall(observer, orCreateTrack.Target, stimulusPos, profile.CallForHelpRadius);
				}
			}
		}

		private static void UpdateStageFromLevel(BaseAI ai, Character observer, AgentBehaviorProfile profile, SensoryTrack track)
		{
			if (track.DetectionLevel >= 0.85f)
			{
				track.Stage = DetectionStage.Engaged;
			}
			else if (track.DetectionLevel >= 0.5f)
			{
				track.Stage = DetectionStage.Alerted;
			}
			else if (track.DetectionLevel >= 0.2f)
			{
				track.Stage = DetectionStage.Suspicious;
			}
			else
			{
				track.Stage = DetectionStage.Unaware;
			}
		}

		private static void EnqueueAllyCall(Character caller, Character target, Vector3 pos, float radius)
		{
			//IL_003b: 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)
			if (!(radius <= 0.5f) && _ringCount < _allyCallRing.Length)
			{
				_allyCallRing[_ringTail] = new PendingAllyCall
				{
					Caller = caller,
					Target = target,
					KnownPos = pos,
					Radius = radius
				};
				_ringTail = (_ringTail + 1) % _allyCallRing.Length;
				_ringCount++;
			}
		}

		private static void ProcessOneQueuedAllyCall()
		{
			//IL_0078: Unknown result type (might be due to invalid IL or missing references)
			//IL_010e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Unknown result type (might be due to invalid IL or missing references)
			if (_ringCount <= 0)
			{
				return;
			}
			PendingAllyCall pendingAllyCall = _allyCallRing[_ringHead];
			_ringHead = (_ringHead + 1) % _allyCallRing.Length;
			_ringCount--;
			if ((Object)(object)pendingAllyCall.Caller == (Object)null || pendingAllyCall.Caller.IsDead() || (Object)(object)pendingAllyCall.Target == (Object)null)
			{
				return;
			}
			_allyQueryTemp.Clear();
			SpatialCharacterGrid.QueryRadius(((Component)pendingAllyCall.Caller).transform.position, pendingAllyCall.Radius, _allyQueryTemp, pendingAllyCall.Caller);
			for (int i = 0; i < _allyQueryTemp.Count; i++)
			{
				Character val = _allyQueryTemp[i];
				if ((Object)(object)val == (Object)null || val.IsDead() || !BaseAI.IsEnemy(val, pendingAllyCall.Target) || BaseAI.IsEnemy(pendingAllyCall.Caller, val))
				{
					continue;
				}
				BaseAI baseAI = val.GetBaseAI();
				if (!((Object)(object)baseAI == (Object)null))
				{
					SensoryTrack orCreateTrack = GetOrCreateTrack(baseAI);
					if ((int)orCreateTrack.Stage < 2)
					{
						orCreateTrack.Target = pendingAllyCall.Target;
						orCreateTrack.LastKnownPos = pendingAllyCall.KnownPos;
						orCreateTrack.LastStimulusTime = Time.time;
						orCreateTrack.SearchTimeRemaining = ModConfig.SearchDurationSeconds.Value;
						orCreateTrack.DetectionLevel = Mathf.Max(orCreateTrack.DetectionLevel, 0.65f);
						orCreateTrack.Stage = DetectionStage.Alerted;
					}
				}
			}
		}
	}
	public sealed class InvestigateBrainModule : IAIBrainModule
	{
		private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null);

		private static readonly MethodInfo _lookAtMethod = AccessTools.Method(typeof(BaseAI), "LookAt", (Type[])null, (Type[])null);

		private static readonly MethodInfo _randomMovementMethod = AccessTools.Method(typeof(BaseAI), "RandomMovement", (Type[])null, (Type[])null);

		public string Id => "VikingAI.SensoryInvestigate";

		public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile)
		{
			if (!ModConfig.EnableSensoryPerceptionEngine.Value || !profile.UseSensoryEngine)
			{
				return 0f;
			}
			if (ai.IsAlerted())
			{
				MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
				if (val != null && (Object)(object)((BaseAI)val).GetTargetCreature() != (Object)null && SensoryMemoryController.GetOrCreateTrack(ai).Stage == DetectionStage.Engaged)
				{
					return 0f;
				}
			}
			SensoryTrack orCreateTrack = SensoryMemoryController.GetOrCreateTrack(ai);
			if ((orCreateTrack.Stage == DetectionStage.Suspicious || orCreateTrack.Stage == DetectionStage.Alerted) && orCreateTrack.SearchTimeRemaining > 0.1f)
			{
				return 55f;
			}
			return 0f;
		}

		public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt)
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_003a: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: 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_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
			SensoryTrack orCreateTrack = SensoryMemoryController.GetOrCreateTrack(ai);
			if (orCreateTrack.Stage == DetectionStage.Suspicious)
			{
				ai.StopMoving();
				_lookAtMethod?.Invoke(ai, new object[1] { orCreateTrack.LastKnownPos + Vector3.up * 1.2f });
				return true;
			}
			if (orCreateTrack.Stage == DetectionStage.Alerted && _moveToMethod != null)
			{
				if (Utils.DistanceXZ(((Component)character).transform.position, orCreateTrack.LastKnownPos) > 2.2f)
				{
					_moveToMethod.Invoke(ai, new object[4] { dt, orCreateTrack.LastKnownPos, 1.5f, false });
				}
				else
				{
					_randomMovementMethod?.Invoke(ai, new object[3] { dt, orCreateTrack.LastKnownPos, true });
				}
				return true;
			}
			return false;
		}
	}
}
namespace VikingAI.Simulation
{
	public interface IVirtualAgentTask
	{
		string Id { get; }

		NpcRoleFlags RequiredRole { get; }

		void TickUnloadedZdo(ZDO agentZdo, NpcRoleFlags roles, float dtSeconds);

		void ApplyCatchUpOnLoad(Character agent, AgentBehaviorProfile profile, double elapsedOfflineSeconds);
	}
	public sealed class PatrolVirtualTask : IVirtualAgentTask
	{
		private static readonly int _zdoPatrolCenter = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPos");

		private static readonly int _zdoPatrolPhase = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPhase");

		public string Id => "VikingAI.VirtualPatrol";

		public NpcRoleFlags RequiredRole => NpcRoleFlags.Guard;

		public void TickUnloadedZdo(ZDO agentZdo, NpcRoleFlags roles, float dtSeconds)
		{
			//IL_0018: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_0064: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0072: 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)
			if (agentZdo.IsValid() && agentZdo.IsOwner())
			{
				Vector3 vec = agentZdo.GetVec3(_zdoPatrolCenter, agentZdo.GetPosition());
				float num = agentZdo.GetFloat(_zdoPatrolPhase, 0f) + dtSeconds * 0.25f;
				agentZdo.Set(_zdoPatrolPhase, num);
				float num2 = Mathf.Sin(num) * 6f;
				float num3 = Mathf.Cos(num) * 6f;
				Vector3 position = default(Vector3);
				((Vector3)(ref position))..ctor(vec.x + num2, vec.y, vec.z + num3);
				agentZdo.SetPosition(position);
			}
		}

		public void ApplyCatchUpOnLoad(Character agent, AgentBehaviorProfile profile, double elapsedOfflineSeconds)
		{
			if (elapsedOfflineSeconds > 30.0 && !agent.IsDead() && agent.GetHealthPercentage() < 1f)
			{
				agent.Heal(agent.GetMaxHealth() * 0.25f, true);
			}
		}
	}
	[HarmonyPatch]
	public static class VirtualAgentDirector
	{
		public static readonly int ZdoKeyLastSimTicks = StringExtensionMethods.GetStableHashCode("VAI_v1_LastTicks");

		public static readonly int ZdoKeyPatrolAnchor = StringExtensionMethods.GetStableHashCode("VAI_v1_PatrolPos");

		private static readonly List<IVirtualAgentTask> _tasks = new List<IVirtualAgentTask>
		{
			new PatrolVirtualTask()
		};

		private static readonly HashSet<ZDO> _trackedNpcZdos = new HashSet<ZDO>();

		private static readonly List<Character> _portalFollowersTemp = new List<Character>(8);

		private static float _virtualTickTimer;

		private static readonly FieldRef<ZDOMan, Dictionary<ZDOID, ZDO>> _zdoObjectsById = AccessTools.FieldRefAccess<ZDOMan, Dictionary<ZDOID, ZDO>>("m_objectsByID");

		public static event Action<ZDO>? OnAgentRestored;

		public static void RegisterTask(IVirtualAgentTask task)
		{
			if (task != null)
			{
				_tasks.RemoveAll((IVirtualAgentTask t) => t.Id == task.Id);
				_tasks.Add(task);
			}
		}

		public static ZDO? SpawnVirtualAgentZdo(string prefabName, Vector3 position, Quaternion rotation, NpcRoleFlags roles, bool isCustomNpc = true)
		{
			//IL_001d: 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_005f: Unknown result type (might be due to invalid IL or missing references)
			if (ZDOMan.instance == null || string.IsNullOrEmpty(prefabName))
			{
				return null;
			}
			int stableHashCode = StringExtensionMethods.GetStableHashCode(prefabName);
			ZDO val = ZDOMan.instance.CreateNewZDO(position, stableHashCode);
			if (val == null)
			{
				return null;
			}
			val.SetPrefab(stableHashCode);
			val.SetRotation(rotation);
			val.Persistent = true;
			val.Set(AgentProfileRegistry.ZdoKeyCustomNpc, isCustomNpc);
			val.Set(AgentProfileRegistry.ZdoKeyRoleFlags, (int)roles, false);
			val.Set(ZdoKeyPatrolAnchor, position);
			if ((Object)(object)ZNet.instance != (Object)null)
			{
				val.Set(ZdoKeyLastSimTicks, ZNet.instance.GetTime().Ticks);
			}
			if (isCustomNpc)
			{
				int seed = (int)(((ZDOID)(ref val.m_uid)).ID ^ ((ZDOID)(ref val.m_uid)).UserID) ^ Environment.TickCount;
				HumanoidPrefabBuilder.ApplyDeterministicAppearanceToZdo(val, seed);
			}
			_trackedNpcZdos.Add(val);
			return val;
		}

		public static void TrackZdoDirectly(ZDO zdo)
		{
			if (zdo != null && zdo.IsValid())
			{
				_trackedNpcZdos.Add(zdo);
			}
		}

		public static int RestoreTrackedAgents()
		{
			_trackedNpcZdos.Clear();
			if (ZDOMan.instance == null)
			{
				return 0;
			}
			int num = 0;
			foreach (ZDO value in _zdoObjectsById.Invoke(ZDOMan.instance).Values)
			{
				if (value != null && value.GetInt(AgentProfileRegistry.ZdoKeyRoleFlags, 0) != 0)
				{
					_trackedNpcZdos.Add(value);
					num++;
					try
					{
						VirtualAgentDirector.OnAgentRestored?.Invoke(value);
					}
					catch (Exception arg)
					{
						VikingAIPlugin.Log.LogError((object)$"[VirtualAgentDirector] OnAgentRestored handler failed: {arg}");
					}
				}
			}
			VikingAIPlugin.Log.LogInfo((object)$"[VirtualAgentDirector] Restored {num} persisted agent ZDO(s) after world load.");
			return num;
		}

		[HarmonyPatch(typeof(ZNet), "ServerLoadWorld")]
		[HarmonyPostfix]
		private static void ZNet_ServerLoadWorld_Postfix()
		{
			if (ModConfig.ModEnabled.Value)
			{
				RestoreTrackedAgents();
			}
		}

		public static bool MoveZdoAlongTerrain(ZDO zdo, Vector3 targetPos, float speedMetersPerSec, float dtSeconds, float arrivalRadius = 3f)
		{
			//IL_0016: 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_001c: 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_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0056: Unknown result type (might be due to invalid IL or missing references)
			//IL_005b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0060: Unknown result type (might be due to invalid IL or missing references)
			//IL_009a: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_00cb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
			if (zdo == null || !zdo.IsValid() || !zdo.IsOwner())
			{
				return false;
			}
			Vector3 position = zdo.GetPosition();
			Vector3 val = targetPos - position;
			val.y = 0f;
			float magnitude = ((Vector3)(ref val)).magnitude;
			if (magnitude <= arrivalRadius)
			{
				return true;
			}
			Vector3 val2 = val / magnitude;
			float num = Mathf.Min(magnitude, speedMetersPerSec * dtSeconds);
			Vector3 val3 = position + val2 * num;
			if (WorldGenerator.instance != null)
			{
				float height = WorldGenerator.instance.GetHeight(val3.x, val3.z);
				val3.y = Mathf.Max(30f, height);
			}
			else
			{
				val3.y = Mathf.Lerp(position.y, targetPos.y, num / magnitude);
			}
			zdo.SetPosition(val3);
			if (((Vector3)(ref val2)).sqrMagnitude > 0.01f)
			{
				zdo.SetRotation(Quaternion.LookRotation(val2, Vector3.up));
			}
			return magnitude - num <= arrivalRadius;
		}

		public static void TrackNpcZdo(Character npc, AgentBehaviorProfile profile)
		{
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0052: Unknown result type (might be due to invalid IL or missing references)
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)npc == (Object)null)
			{
				return;
			}
			ZNetView nView = AgentProfileRegistry.GetNView(npc);
			if ((Object)(object)nView == (Object)null || !nView.IsValid())
			{
				return;
			}
			ZDO zDO = nView.GetZDO();
			if (zDO != null)
			{
				_trackedNpcZdos.Add(zDO);
				if (nView.IsOwner() && zDO.GetVec3(ZdoKeyPatrolAnchor, Vector3.zero) == Vector3.zero)
				{
					zDO.Set(ZdoKeyPatrolAnchor, ((Component)npc).transform.position);
				}
			}
		}

		public static void UpdateDirector(float dt)
		{
			if (!ModConfig.ModEnabled.Value || !ModConfig.EnableUnloadedZoneSimulation.Value)
			{
				return;
			}
			float num = Mathf.Max(0.25f, ModConfig.VirtualTickIntervalSeconds.Value);
			_virtualTickTimer += dt;
			if (_virtualTickTimer < num)
			{
				return;
			}
			float virtualTickTimer = _virtualTickTimer;
			_virtualTickTimer = 0f;
			if ((Object)(object)ZNetScene.instance == (Object)null || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			long ticks = ZNet.instance.GetTime().Ticks;
			bool flag = false;
			foreach (ZDO trackedNpcZdo in _trackedNpcZdos)
			{
				if (trackedNpcZdo == null || !trackedNpcZdo.IsValid())
				{
					flag = true;
					continue;
				}
				if ((Object)(object)ZNetScene.instance.FindInstance(trackedNpcZdo) != (Object)null)
				{
					if (trackedNpcZdo.IsOwner())
					{
						trackedNpcZdo.Set(ZdoKeyLastSimTicks, ticks);
					}
					continue;
				}
				NpcRoleFlags npcRoleFlags = (NpcRoleFlags)trackedNpcZdo.GetInt(AgentProfileRegistry.ZdoKeyRoleFlags, 0);
				if (npcRoleFlags == NpcRoleFlags.None)
				{
					continue;
				}
				for (int i = 0; i < _tasks.Count; i++)
				{
					IVirtualAgentTask virtualAgentTask = _tasks[i];
					if ((npcRoleFlags & virtualAgentTask.RequiredRole) != NpcRoleFlags.None)
					{
						virtualAgentTask.TickUnloadedZdo(trackedNpcZdo, npcRoleFlags, virtualTickTimer);
					}
				}
				if (trackedNpcZdo.IsOwner())
				{
					trackedNpcZdo.Set(ZdoKeyLastSimTicks, ticks);
				}
			}
			if (flag)
			{
				_trackedNpcZdos.RemoveWhere((ZDO z) => z == null || !z.IsValid());
			}
		}

		[HarmonyPatch(typeof(Character), "Start")]
		[HarmonyPostfix]
		private static void Character_Start_Postfix(Character __instance)
		{
			if (!ModConfig.ModEnabled.Value || (Object)(object)__instance == (Object)null || __instance.IsPlayer())
			{
				return;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(__instance);
			if (!profile.IsCustomNpc && profile.Roles == NpcRoleFlags.None)
			{
				return;
			}
			TrackNpcZdo(__instance, profile);
			if (!ModConfig.EnableUnloadedZoneSimulation.Value || (Object)(object)ZNet.instance == (Object)null)
			{
				return;
			}
			ZNetView nView = AgentProfileRegistry.GetNView(__instance);
			if ((Object)(object)nView == (Object)null || !nView.IsValid())
			{
				return;
			}
			ZDO zDO = nView.GetZDO();
			long num = zDO.GetLong(ZdoKeyLastSimTicks, 0L);
			long ticks = ZNet.instance.GetTime().Ticks;
			if (num > 0 && ticks > num)
			{
				double totalSeconds = TimeSpan.FromTicks(ticks - num).TotalSeconds;
				if (totalSeconds >= 2.0)
				{
					for (int i = 0; i < _tasks.Count; i++)
					{
						IVirtualAgentTask virtualAgentTask = _tasks[i];
						if ((profile.Roles & virtualAgentTask.RequiredRole) != NpcRoleFlags.None)
						{
							virtualAgentTask.ApplyCatchUpOnLoad(__instance, profile, totalSeconds);
						}
					}
				}
			}
			if (nView.IsOwner())
			{
				zDO.Set(ZdoKeyLastSimTicks, ticks);
			}
		}

		[HarmonyPatch(typeof(Player), "TeleportTo")]
		[HarmonyPostfix]
		private static void Player_TeleportTo_Postfix(Player __instance, Vector3 pos, Quaternion rot, bool __result)
		{
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_0128: Unknown result type (might be due to invalid IL or missing references)
			//IL_0129: Unknown result type (might be due to invalid IL or missing references)
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0130: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Unknown result type (might be due to invalid IL or missing references)
			//IL_013e: Unknown result type (might be due to invalid IL or missing references)
			//IL_014b: 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)
			if (!__result || !ModConfig.ModEnabled.Value || !ModConfig.EnableFollowerPortalTransit.Value || (Object)(object)__instance == (Object)null)
			{
				return;
			}
			_portalFollowersTemp.Clear();
			SpatialCharacterGrid.QueryRadius(((Component)__instance).transform.position, 20f, _portalFollowersTemp, (Character?)(object)__instance);
			int num = 0;
			Vector3 val3 = default(Vector3);
			for (int i = 0; i < _portalFollowersTemp.Count; i++)
			{
				Character val = _portalFollowersTemp[i];
				if ((Object)(object)val == (Object)null || val.IsDead() || val.IsPlayer())
				{
					continue;
				}
				BaseAI baseAI = val.GetBaseAI();
				MonsterAI val2 = (MonsterAI)(object)((baseAI is MonsterAI) ? baseAI : null);
				if (val2 == null || (Object)(object)val2.GetFollowTarget() != (Object)(object)((Component)__instance).gameObject || !AgentProfileRegistry.GetProfile(val).CanTraversePortals)
				{
					continue;
				}
				ZNetView nView = AgentProfileRegistry.GetNView(val);
				if (!((Object)(object)nView == (Object)null) && nView.IsValid())
				{
					if (!nView.IsOwner())
					{
						nView.ClaimOwnership();
					}
					float num2 = (150f + (float)num * 30f) * (MathF.PI / 180f);
					((Vector3)(ref val3))..ctor(Mathf.Sin(num2) * 1.8f, 0.25f, Mathf.Cos(num2) * 1.8f);
					Vector3 position = pos + rot * val3;
					nView.GetZDO().SetPosition(position);
					((Component)val).transform.position = position;
					((Component)val).transform.rotation = rot;
					num++;
				}
			}
		}
	}
}
namespace VikingAI.Profiles
{
	[Flags]
	public enum NpcRoleFlags : uint
	{
		None = 0u,
		Companion = 1u,
		Guard = 2u,
		SmelterTender = 4u,
		Lumberjack = 8u,
		Farmer = 0x10u,
		Builder = 0x20u,
		Hauler = 0x40u,
		AllSettlement = 0x7Eu
	}
	public sealed class AgentBehaviorProfile
	{
		public string PrefabName { get; set; } = "";

		public bool IsCustomNpc { get; set; }

		public NpcRoleFlags Roles { get; set; }

		public bool CanOpenDoors { get; set; }

		public bool AutoCloseDoors { get; set; }

		public float MaxJumpUpHeight { get; set; }

		public float MaxDropDownHeight { get; set; }

		public bool AllowSiegeBreachPathing { get; set; }

		public float StructuralDpsEstimate { get; set; } = 25f;

		public bool StrafeInCombat { get; set; }

		public bool YieldToPlayers { get; set; }

		public bool UseFormationFollowing { get; set; }

		public bool CanTraversePortals { get; set; }

		public bool UsePackAttackTokens { get; set; }

		public float AttackTokenWeight { get; set; } = 1f;

		public bool UseSensoryEngine { get; set; }

		public float CallForHelpRadius { get; set; } = 20f;

		public AgentBehaviorProfile Clone()
		{
			return (AgentBehaviorProfile)MemberwiseClone();
		}

		public static AgentBehaviorProfile CreateCompanionDefault(string prefabName = "")
		{
			return new AgentBehaviorProfile
			{
				PrefabName = prefabName,
				IsCustomNpc = true,
				Roles = (NpcRoleFlags.Companion | NpcRoleFlags.Guard),
				CanOpenDoors = true,
				AutoCloseDoors = true,
				MaxJumpUpHeight = 1.5f,
				MaxDropDownHeight = 3f,
				AllowSiegeBreachPathing = false,
				StrafeInCombat = true,
				YieldToPlayers = true,
				UseFormationFollowing = true,
				CanTraversePortals = true,
				UsePackAttackTokens = true,
				AttackTokenWeight = 1f,
				UseSensoryEngine = true,
				CallForHelpRadius = 25f
			};
		}

		public static AgentBehaviorProfile CreateVillagerDefault(string prefabName = "", NpcRoleFlags roles = NpcRoleFlags.AllSettlement)
		{
			return new AgentBehaviorProfile
			{
				PrefabName = prefabName,
				IsCustomNpc = true,
				Roles = roles,
				CanOpenDoors = true,
				AutoCloseDoors = true,
				MaxJumpUpHeight = 1.2f,
				MaxDropDownHeight = 2.5f,
				AllowSiegeBreachPathing = false,
				StrafeInCombat = true,
				YieldToPlayers = true,
				UseFormationFollowing = true,
				CanTraversePortals = false,
				UsePackAttackTokens = true,
				AttackTokenWeight = 1f,
				UseSensoryEngine = true,
				CallForHelpRadius = 30f
			};
		}
	}
	public static class AgentProfileRegistry
	{
		public static readonly int ZdoKeyRoleFlags = StringExtensionMethods.GetStableHashCode("VAI_v1_Roles");

		public static readonly int ZdoKeyCustomNpc = StringExtensionMethods.GetStableHashCode("VAI_v1_IsNpc");

		public static readonly int ZdoKeyPerceptionExempt = StringExtensionMethods.GetStableHashCode("VAI_PerceptionExempt");

		public static readonly int ZdoKeySoMExempt = StringExtensionMethods.GetStableHashCode("SoMStealthExempt");

		private static readonly FieldRef<Character, ZNetView> _charNView = AccessTools.FieldRefAccess<Character, ZNetView>("m_nview");

		private static readonly Dictionary<string, AgentBehaviorProfile> _prefabProfiles = new Dictionary<string, AgentBehaviorProfile>(StringComparer.OrdinalIgnoreCase);

		private static readonly ConditionalWeakTable<Character, AgentBehaviorProfile> _instanceProfiles = new ConditionalWeakTable<Character, AgentBehaviorProfile>();

		public static ZNetView? GetNView(Character? character)
		{
			if (!((Object)(object)character != (Object)null))
			{
				return null;
			}
			return _charNView.Invoke(character);
		}

		public static void RegisterPrefabProfile(string prefabName, AgentBehaviorProfile profile)
		{
			if (!string.IsNullOrEmpty(prefabName) && profile != null)
			{
				profile.PrefabName = prefabName;
				_prefabProfiles[CleanName(prefabName)] = profile;
			}
		}

		public static void SetInstanceProfile(Character character, AgentBehaviorProfile profile, bool persistRoleToZdo = false)
		{
			if (!((Object)(object)character == (Object)null) && profile != null)
			{
				_instanceProfiles.Remove(character);
				_instanceProfiles.Add(character, profile);
				ZNetView nView = GetNView(character);
				if (persistRoleToZdo && (Object)(object)nView != (Object)null && nView.IsValid() && nView.IsOwner())
				{
					ZDO zDO = nView.GetZDO();
					zDO.Set(ZdoKeyCustomNpc, profile.IsCustomNpc);
					zDO.Set(ZdoKeyRoleFlags, (int)profile.Roles, false);
				}
			}
		}

		public static AgentBehaviorProfile GetProfile(Character character)
		{
			if ((Object)(object)character == (Object)null)
			{
				return new AgentBehaviorProfile();
			}
			if (_instanceProfiles.TryGetValue(character, out AgentBehaviorProfile value))
			{
				SyncDynamicTamedFlags(character, value);
				return value;
			}
			string text = CleanName(((Object)((Component)character).gameObject).name);
			AgentBehaviorProfile value2;
			AgentBehaviorProfile agentBehaviorProfile = ((!_prefabProfiles.TryGetValue(text, out value2)) ? BuildDynamicDefaultProfile(character, text) : value2.Clone());
			ZNetView nView = GetNView(character);
			if ((Object)(object)nView != (Object)null && nView.IsValid())
			{
				ZDO zDO = nView.GetZDO();
				if (zDO != null && zDO.GetBool(ZdoKeyCustomNpc, false))
				{
					int roles = zDO.GetInt(ZdoKeyRoleFlags, 0);
					agentBehaviorProfile = AgentBehaviorProfile.CreateVillagerDefault(text, (NpcRoleFlags)roles);
					if ((agentBehaviorProfile.Roles & NpcRoleFlags.Companion) != NpcRoleFlags.None)
					{
						agentBehaviorProfile.CanTraversePortals = true;
					}
				}
			}
			SyncDynamicTamedFlags(character, agentBehaviorProfile);
			_instanceProfiles.Add(character, agentBehaviorProfile);
			return agentBehaviorProfile;
		}

		public static bool IsPerceptionExempt(Character character)
		{
			ZNetView nView = GetNView(character);
			if ((Object)(object)nView == (Object)null || !nView.IsValid())
			{
				return false;
			}
			ZDO zDO = nView.GetZDO();
			if (zDO == null)
			{
				return false;
			}
			if (zDO.GetInt(ZdoKeyPerceptionExempt, 0) == 0)
			{
				return zDO.GetInt(ZdoKeySoMExempt, 0) != 0;
			}
			return true;
		}

		private static AgentBehaviorProfile BuildDynamicDefaultProfile(Character character, string prefabName)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0023: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Invalid comparison between Unknown and I4
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002b: Invalid comparison between Unknown and I4
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Invalid comparison between Unknown and I4
			//IL_0031: Unknown result type (might be due to invalid IL or missing references)
			//IL_0034: Invalid comparison between Unknown and I4
			bool flag = character is Humanoid;
			BaseAI baseAI = character.GetBaseAI();
			AgentType val = (AgentType)((!((Object)(object)baseAI != (Object)null)) ? 1 : ((int)baseAI.m_pathAgentType));
			float attackTokenWeight = (((int)val == 2 || (int)val == 12 || (int)val == 3 || (int)val == 10) ? 1.5f : 1f);
			return new AgentBehaviorProfile
			{
				PrefabName = prefabName,
				IsCustomNpc = false,
				Roles = NpcRoleFlags.None,
				CanOpenDoors = false,
				AutoCloseDoors = false,
				MaxJumpUpHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 1.4f : 0f),
				MaxDropDownHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 2.5f : 0f),
				AllowSiegeBreachPathing = ModConfig.VanillaEnemiesBreachWeakWalls.Value,
				StrafeInCombat = (flag && ModConfig.VanillaHumanoidsStrafeInCombat.Value),
				YieldToPlayers = character.IsTamed(),
				UseFormationFollowing = character.IsTamed(),
				CanTraversePortals = false,
				UsePackAttackTokens = ModConfig.VanillaEnemiesUsePackTokens.Value,
				AttackTokenWeight = attackTokenWeight,
				UseSensoryEngine = ModConfig.VanillaEnemiesUseSensoryEngine.Value,
				CallForHelpRadius = 20f
			};
		}

		private static void SyncDynamicTamedFlags(Character character, AgentBehaviorProfile profile)
		{
			if (character.IsTamed())
			{
				profile.YieldToPlayers = ModConfig.EnablePlayerYieldOnApproach.Value;
				profile.UseFormationFollowing = ModConfig.EnableFollowerFormations.Value;
			}
			else if (!profile.IsCustomNpc)
			{
				profile.UsePackAttackTokens = ModConfig.VanillaEnemiesUsePackTokens.Value;
				profile.StrafeInCombat = character is Humanoid && ModConfig.VanillaHumanoidsStrafeInCombat.Value;
				profile.MaxJumpUpHeight = (ModConfig.VanillaEnemiesJumpLedges.Value ? 1.4f : 0f);
				profile.AllowSiegeBreachPathing = ModConfig.VanillaEnemiesBreachWeakWalls.Value;
				profile.UseSensoryEngine = ModConfig.VanillaEnemiesUseSensoryEngine.Value;
			}
		}

		private static string CleanName(string name)
		{
			int num = name.IndexOf('(');
			if (num <= 0)
			{
				return name.Trim();
			}
			return name.Substring(0, num).Trim();
		}
	}
}
namespace VikingAI.Patches
{
	[HarmonyPatch]
	public static class LocomotionPatches
	{
		private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character");

		private static readonly FieldRef<BaseAI, List<Vector3>> _aiPath = AccessTools.FieldRefAccess<BaseAI, List<Vector3>>("m_path");

		private static readonly FieldRef<BaseAI, float> _aiJumpTimer = AccessTools.FieldRefAccess<BaseAI, float>("m_jumpTimer");

		private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null);

		public static Vector3? ActiveLookDirOverride { get; set; }

		[HarmonyPatch(typeof(BaseAI), "MoveTowards")]
		[HarmonyPrefix]
		private static bool BaseAI_MoveTowards_Prefix(BaseAI __instance, ref Vector3 dir, bool run, bool __runOriginal)
		{
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_0048: Unknown result type (might be due to invalid IL or missing references)
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_0068: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_0159: 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_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bb: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c0: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				return false;
			}
			if (!ModConfig.ModEnabled.Value)
			{
				return true;
			}
			Character val = _aiCharacter.Invoke(__instance);
			if ((Object)(object)val == (Object)null || val.IsFlying() || __instance.m_serpentMovement)
			{
				return true;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val);
			Vector3 val2 = ((Vector3)(ref dir)).normalized;
			if (profile.CanOpenDoors)
			{
				DoorTraversalController.CheckAndActuateDoors(val, profile, val2);
			}
			if (ModConfig.EnableContextSteering.Value)
			{
				val2 = SteeringPipeline.Evaluate(val, profile, val2);
			}
			Vector3? val3 = ActiveLookDirOverride;
			if (!val3.HasValue && profile.StrafeInCombat)
			{
				MonsterAI val4 = (MonsterAI)(object)((__instance is MonsterAI) ? __instance : null);
				if (val4 != null)
				{
					Character targetCreature = ((BaseAI)val4).GetTargetCreature();
					if ((Object)(object)targetCreature != (Object)null)
					{
						Vector3 val5 = ((Component)targetCreature).transform.position - ((Component)val).transform.position;
						val5.y = 0f;
						if (((Vector3)(ref val5)).sqrMagnitude > 0.04f && ((Vector3)(ref val5)).sqrMagnitude <= 144f)
						{
							val3 = ((Vector3)(ref val5)).normalized;
						}
					}
				}
			}
			if (val3.HasValue)
			{
				__instance.LookTowards(val3.Value);
				val.SetMoveDir(val2);
				val.SetRun(run);
				if (__instance.m_jumpInterval > 0f && _aiJumpTimer.Invoke(__instance) >= __instance.m_jumpInterval)
				{
					_aiJumpTimer.Invoke(__instance) = 0f;
					val.Jump(false);
				}
				return false;
			}
			dir = val2;
			return true;
		}

		[HarmonyPatch(typeof(BaseAI), "MoveTo")]
		[HarmonyPostfix]
		private static void BaseAI_MoveTo_Postfix(BaseAI __instance)
		{
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0067: Unknown result type (might be due to invalid IL or missing references)
			//IL_006c: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: 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_007c: Unknown result type (might be due to invalid IL or missing references)
			if (!ModConfig.ModEnabled.Value)
			{
				return;
			}
			Character val = _aiCharacter.Invoke(__instance);
			if ((Object)(object)val == (Object)null || val.IsFlying())
			{
				return;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val);
			if (profile.MaxJumpUpHeight <= 0.01f)
			{
				return;
			}
			List<Vector3> list = _aiPath.Invoke(__instance);
			if (list != null && list.Count != 0)
			{
				Vector3 val2 = list[0];
				Vector3 position = ((Component)val).transform.position;
				float num = val2.y - position.y;
				float num2 = Utils.DistanceXZ(val2, position);
				if (num > 0.55f && num <= profile.MaxJumpUpHeight && num2 < 1.9f && val.IsOnGround())
				{
					val.Jump(false);
				}
			}
		}

		[HarmonyPatch(typeof(BaseAI), "Follow")]
		[HarmonyPrefix]
		private static bool BaseAI_Follow_Prefix(BaseAI __instance, GameObject go, float dt, bool __runOriginal)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_009b: 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_00ed: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				return false;
			}
			if (!ModConfig.ModEnabled.Value || (Object)(object)go == (Object)null)
			{
				return true;
			}
			Character val = _aiCharacter.Invoke(__instance);
			if ((Object)(object)val == (Object)null)
			{
				return true;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val);
			if (SteeringPipeline.TryGetPlayerYieldStep(val, profile, out var yieldDir))
			{
				__instance.MoveTowards(yieldDir, false);
				return false;
			}
			if (ModConfig.EnableFollowerFormations.Value && profile.UseFormationFollowing && _moveToMethod != null)
			{
				Vector3 val2 = SteeringPipeline.ComputeFollowerSlotPosition(val, go);
				float num = Utils.DistanceXZ(val2, ((Component)val).transform.position);
				bool flag = Vector3.Distance(go.transform.position, ((Component)val).transform.position) > 9.5f || num > 7.5f;
				if (num < 1.15f)
				{
					__instance.StopMoving();
				}
				else
				{
					_moveToMethod.Invoke(__instance, new object[4] { dt, val2, 0.5f, flag });
				}
				return false;
			}
			return true;
		}
	}
	[HarmonyPatch]
	public static class PathfindingPatches
	{
		private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character");

		private static readonly FieldRef<Pathfinding, NavMeshPath> _pfPath = AccessTools.FieldRefAccess<Pathfinding, NavMeshPath>("m_path");

		private static readonly FieldRef<Pathfinding, AsyncOperation> _pfBuildOp = AccessTools.FieldRefAccess<Pathfinding, AsyncOperation>("m_buildOperation");

		private static readonly MethodInfo _buildTilesMethod = AccessTools.Method(typeof(Pathfinding), "Buildtiles", (Type[])null, (Type[])null);

		[HarmonyPatch(typeof(Pathfinding), "Awake")]
		[HarmonyPostfix]
		private static void Pathfinding_Awake_Postfix(Pathfinding __instance)
		{
			if (ModConfig.ModEnabled.Value && ModConfig.EnableTileSeamCostFix.Value)
			{
				__instance.m_linkCost = ModConfig.TileSeamCostModifier.Value;
			}
		}

		[HarmonyPatch(typeof(Pathfinding), "ConnectAlongEdge")]
		[HarmonyPrefix]
		private static void Pathfinding_ConnectAlongEdge_Prefix(Pathfinding __instance)
		{
			if (ModConfig.ModEnabled.Value)
			{
				__instance.m_linkCost = (ModConfig.EnableTileSeamCostFix.Value ? ModConfig.TileSeamCostModifier.Value : 10f);
			}
		}

		[HarmonyPatch(typeof(Pathfinding), "UpdatePathfinding")]
		[HarmonyPostfix]
		private static void Pathfinding_UpdatePathfinding_Postfix(Pathfinding __instance)
		{
			if (!ModConfig.ModEnabled.Value || _buildTilesMethod == null)
			{
				return;
			}
			int num = ModConfig.MaxAsyncTileBuildsPerTick.Value - 1;
			for (int i = 0; i < num; i++)
			{
				AsyncOperation val = _pfBuildOp.Invoke(__instance);
				if (val == null || val.isDone)
				{
					_buildTilesMethod.Invoke(__instance, null);
					continue;
				}
				break;
			}
		}

		[HarmonyPatch(typeof(BaseAI), "FindPath")]
		[HarmonyPrefix]
		private static void BaseAI_FindPath_Prefix(BaseAI __instance)
		{
			NavGraphManager.CurrentPathingCharacter = _aiCharacter.Invoke(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "FindPath")]
		[HarmonyFinalizer]
		private static void BaseAI_FindPath_Finalizer()
		{
			NavGraphManager.CurrentPathingCharacter = null;
		}

		[HarmonyPatch(typeof(BaseAI), "HavePath")]
		[HarmonyPrefix]
		private static void BaseAI_HavePath_Prefix(BaseAI __instance)
		{
			NavGraphManager.CurrentPathingCharacter = _aiCharacter.Invoke(__instance);
		}

		[HarmonyPatch(typeof(BaseAI), "HavePath")]
		[HarmonyFinalizer]
		private static void BaseAI_HavePath_Finalizer()
		{
			NavGraphManager.CurrentPathingCharacter = null;
		}

		[HarmonyPatch(typeof(Pathfinding), "GetPath")]
		[HarmonyPostfix]
		private static void Pathfinding_GetPath_Postfix(Pathfinding __instance, Vector3 from, Vector3 to, List<Vector3>? path, AgentType agentType, ref bool __result)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Invalid comparison between Unknown and I4
			//IL_003f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0040: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			if (ModConfig.ModEnabled.Value && ModConfig.EnableUnifiedNavGraph.Value)
			{
				NavMeshPath val = _pfPath.Invoke(__instance);
				if ((!__result || (val != null && (int)val.status > 0)) && NavGraphManager.TrySolvePath(from, to, agentType, path))
				{
					__result = true;
				}
			}
		}

		[HarmonyPatch(typeof(Piece), "SetCreator")]
		[HarmonyPostfix]
		private static void Piece_SetCreator_Postfix(Piece __instance)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)null)
			{
				NavGraphManager.InvalidatePosition(((Component)__instance).transform.position);
			}
		}

		[HarmonyPatch(typeof(WearNTear), "OnDestroy")]
		[HarmonyPostfix]
		private static void WearNTear_OnDestroy_Postfix(WearNTear __instance)
		{
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)__instance != (Object)null)
			{
				NavGraphManager.InvalidatePosition(((Component)__instance).transform.position);
			}
		}
	}
	[HarmonyPatch]
	public static class TacticsPatches
	{
		private static readonly FieldRef<BaseAI, Character> _aiCharacter = AccessTools.FieldRefAccess<BaseAI, Character>("m_character");

		private static readonly FieldRef<BaseAI, ZNetView> _aiNView = AccessTools.FieldRefAccess<BaseAI, ZNetView>("m_nview");

		private static readonly MethodInfo _updateSleepMethod = AccessTools.Method(typeof(MonsterAI), "UpdateSleep", (Type[])null, (Type[])null);

		private static readonly MethodInfo _updateTargetMethod = AccessTools.Method(typeof(MonsterAI), "UpdateTarget", (Type[])null, (Type[])null);

		[HarmonyPatch(typeof(BaseAI), "CanSeeTarget", new Type[] { typeof(Character) })]
		[HarmonyPrefix]
		private static bool BaseAI_CanSeeTarget_Prefix(BaseAI __instance, Character target, ref bool __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null)
			{
				return true;
			}
			__result = SensoryMemoryController.EvaluateVisualStimulus(__instance, observer, profile, target);
			return false;
		}

		[HarmonyPatch(typeof(BaseAI), "CanHearTarget", new Type[] { typeof(Character) })]
		[HarmonyPrefix]
		private static bool BaseAI_CanHearTarget_Prefix(BaseAI __instance, Character target, ref bool __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null)
			{
				return true;
			}
			__result = SensoryMemoryController.EvaluateAuditoryStimulus(__instance, observer, profile, target);
			return false;
		}

		[HarmonyPatch(typeof(BaseAI), "CanSenseTarget", new Type[]
		{
			typeof(Character),
			typeof(bool)
		})]
		[HarmonyPrefix]
		private static bool BaseAI_CanSenseTarget_Prefix(BaseAI __instance, Character target, bool passiveAggresive, ref bool __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			if (!SensoryMemoryController.ShouldUseSensoryEngine(__instance, out Character observer, out AgentBehaviorProfile profile) || (Object)(object)observer == (Object)null)
			{
				return true;
			}
			if (!passiveAggresive && (Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30) && (!observer.IsTamed() || !target.GetBaseAI().IsAlerted()))
			{
				__result = false;
				return false;
			}
			bool flag = SensoryMemoryController.EvaluateAuditoryStimulus(__instance, observer, profile, target);
			bool flag2 = SensoryMemoryController.EvaluateVisualStimulus(__instance, observer, profile, target);
			__result = flag || flag2;
			return false;
		}

		[HarmonyPatch(typeof(MonsterAI), "OnDamaged")]
		[HarmonyPostfix]
		private static void MonsterAI_OnDamaged_Postfix(MonsterAI __instance, Character attacker)
		{
			if (ModConfig.ModEnabled.Value)
			{
				SensoryMemoryController.NotifyDamaged((BaseAI)(object)__instance, attacker);
			}
		}

		[HarmonyPatch(typeof(MonsterAI), "RPC_OnNearProjectileHit")]
		[HarmonyPrefix]
		private static bool MonsterAI_RPC_OnNearProjectileHit_Prefix(MonsterAI __instance, Vector3 center, ZDOID attackerID, bool __runOriginal)
		{
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			if (!__runOriginal)
			{
				return false;
			}
			if (!SensoryMemoryController.ShouldUseSensoryEngine((BaseAI)(object)__instance, out Character observer, out AgentBehaviorProfile _) || (Object)(object)observer == (Object)null)
			{
				return true;
			}
			ZNetView val = _aiNView.Invoke((BaseAI)(object)__instance);
			if ((Object)(object)val == (Object)null || !val.IsOwner())
			{
				return false;
			}
			if ((Object)(object)ZoneSystem.instance != (Object)null && ZoneSystem.instance.GetGlobalKey((GlobalKeys)30))
			{
				return false;
			}
			Character source = null;
			if ((Object)(object)ZNetScene.instance != (Object)null)
			{
				GameObject val2 = ZNetScene.instance.FindInstance(attackerID);
				if ((Object)(object)val2 != (Object)null)
				{
					source = val2.GetComponent<Character>();
				}
			}
			SensoryMemoryController.NotifySoundImpulse((BaseAI)(object)__instance, source, center, 0.55f);
			return false;
		}

		[HarmonyPatch(typeof(MonsterAI), "UpdateAI")]
		[HarmonyPrefix]
		private static bool MonsterAI_UpdateAI_Prefix(MonsterAI __instance, float dt, ref bool __result, bool __runOriginal)
		{
			if (!__runOriginal)
			{
				return false;
			}
			if (!ModConfig.ModEnabled.Value)
			{
				return true;
			}
			ZNetView val = _aiNView.Invoke((BaseAI)(object)__instance);
			if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner())
			{
				return true;
			}
			DoorTraversalController.UpdatePendingAutoCloses();
			Character val2 = _aiCharacter.Invoke((BaseAI)(object)__instance);
			if ((Object)(object)val2 == (Object)null || val2.IsDead())
			{
				return true;
			}
			AgentBehaviorProfile profile = AgentProfileRegistry.GetProfile(val2);
			SensoryMemoryController.TickAgentMemory((BaseAI)(object)__instance, val2, profile, dt);
			if (((BaseAI)__instance).IsSleeping())
			{
				return true;
			}
			if (BrainPipeline.TryExecuteModules((BaseAI)(object)__instance, val2, dt))
			{
				if (_updateTargetMethod != null)
				{
					object[] parameters = new object[4]
					{
						(val2 is Humanoid) ? val2 : null,
						dt,
						false,
						false
					};
					_updateTargetMethod.Invoke(__instance, parameters);
				}
				__result = true;
				return false;
			}
			return true;
		}
	}
}
namespace VikingAI.NPC.Utility
{
	public sealed class SmartAffordanceBrainModule : IAIBrainModule
	{
		private sealed class AgentWorkState
		{
			public AffordanceCandidate CurrentCandidate;

			public bool HasActiveTask;

			public float WorkProgressSeconds;

			public float NextScanTime;
		}

		private static readonly ConditionalWeakTable<Character, AgentWorkState> _workStates = new ConditionalWeakTable<Character, AgentWorkState>();

		private static readonly MethodInfo _moveToMethod = AccessTools.Method(typeof(BaseAI), "MoveTo", (Type[])null, (Type[])null);

		private static readonly MethodInfo _lookAtMethod = AccessTools.Method(typeof(BaseAI), "LookAt", (Type[])null, (Type[])null);

		public string Id => "VikingAI.SmartAffordanceWork";

		public float EvaluateUtility(BaseAI ai, Character character, AgentBehaviorProfile profile)
		{
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_005e: Unknown result type (might be due to invalid IL or missing references)
			if (profile.Roles == NpcRoleFlags.None)
			{
				return 0f;
			}
			if (ai.IsAlerted())
			{
				return 0f;
			}
			MonsterAI val = (MonsterAI)(object)((ai is MonsterAI) ? ai : null);
			if (val != null)
			{
				if ((Object)(object)((BaseAI)val).GetTargetCreature() != (Object)null)
				{
					return 0f;
				}
				GameObject followTarget = val.GetFollowTarget();
				if ((Object)(object)followTarget != (Object)null && Vector3.Distance(followTarget.transform.position, ((Component)character).transform.position) > 6.5f)
				{
					return 0f;
				}
			}
			if (!_workStates.TryGetValue(character, out AgentWorkState value))
			{
				value = new AgentWorkState();
				_workStates.Add(character, value);
			}
			float time = Time.time;
			if (value.HasActiveTask)
			{
				if (!((Object)(object)value.CurrentCandidate.TargetComponent == (Object)null) && !AffordanceRegistry.IsReservedByOther(value.CurrentCandidate.TargetComponent, character))
				{
					return 35f;
				}
				value.HasActiveTask = false;
			}
			if (time < value.NextScanTime)
			{
				return 0f;
			}
			value.NextScanTime = time + 2.5f;
			if (AffordanceRegistry.TrySelectBestTask(character, profile, 28f, out var bestCandidate) && AffordanceRegistry.TryReserve(bestCandidate.TargetComponent, character, 15f))
			{
				value.CurrentCandidate = bestCandidate;
				value.HasActiveTask = true;
				value.WorkProgressSeconds = 0f;
				return 35f;
			}
			return 0f;
		}

		public bool Tick(BaseAI ai, Character character, AgentBehaviorProfile profile, float dt)
		{
			//IL_004f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0055: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0085: Unknown result type (might be due to invalid IL or missing references)
			if (!_workStates.TryGetValue(character, out AgentWorkState value) || !value.HasActiveTask)
			{
				return false;
			}
			AffordanceCandidate candidate = value.CurrentCandidate;
			if ((Object)(object)candidate.TargetComponent == (Object)null)
			{
				value.HasActiveTask = false;
				return false;
			}
			AffordanceRegistry.TryReserve(candidate.TargetComponent, character, 10f);
			if (Utils.DistanceXZ(((Component)character).transform.position, candidate.InteractionPoint) > 2.1f)
			{
				_moveToMethod?.Invoke(ai, new object[4] { dt, candidate.InteractionPoint, 1.5f, false });
				return true;
			}
			ai.StopMoving();
			_lookAtMethod?.Invoke(ai, new object[1] { candidate.InteractionPoint });
			value.WorkProgressSeconds += dt;
			if (value.WorkProgressSeconds >= candidate.WorkDurationSeconds)
			{
				AffordanceRegistry.GetProvider(candidate.ProviderId)?.CompleteInteraction(character, profile, in candidate);
				AffordanceRegistry.ReleaseReservation(candidate.TargetComponent, character);
				value.HasActiveTask = false;
				value.NextScanTime = Time.time + 2f;
			}
			return true;
		}
	}
}
namespace VikingAI.NPC.Prefabs
{
	public sealed class HumanoidPrefabConfig
	{
		public string PrefabName { get; set; } = "VAI_HumanoidNpc";

		public string DisplayName { get; set; } = "Wayfarer";

		public Faction Faction { get; set; }

		public string Group { get; set; } = "VAI_Exiles";

		public float MaxHealth { get; set; } = 120f;

		public bool IsAggravatable { get; set; } = true;

		public bool AttackPlayerObjects { get; set; }

		public string[] DefaultItemNames { get; set; } = new string[2] { "ArmorRagsChest", "ArmorRagsLegs" };

		public string[] RandomWeaponNames { get; set; } = Array.Empty<string>();

		public string[] RandomShieldNames { get; set; } = Array.Empty<string>();

		public AgentBehaviorProfile? BehaviorProfile { get; set; }
	}
	public static class HumanoidPrefabBuilder
	{
		private static readonly FieldRef<CharacterAnimEvent, Character> _animEventChar = AccessTools.FieldRefAccess<CharacterAnimEvent, Character>("m_character");

		private static readonly Vector3[] _skinTones = (Vector3[])(object)new Vector3[4]
		{
			new Vector3(1f, 0.92f, 0.84f),
			new Vector3(0.95f, 0.85f, 0.74f),
			new Vector3(0.88f, 0.76f, 0.65f),
			new Vector3(0.76f, 0.64f, 0.54f)
		};

		private static readonly Vector3[] _hairTones = (Vector3[])(object)new Vector3[5]
		{
			new Vector3(0.9f, 0.78f, 0.45f),
			new Vector3(0.75f, 0.36f, 0.18f),
			new Vector3(0.38f, 0.26f, 0.16f),
			new Vector3(0.16f, 0.14f, 0.12f),
			new Vector3(0.78f, 0.78f, 0.8f)
		};

		public static GameObject? CreateHumanoidNpcPrefab(HumanoidPrefabConfig config)
		{
			//IL_0118: Unknown result type (might be due to invalid IL or missing references)
			//IL_011d: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_03c1: Expected O, but got Unknown
			if (config == null || string.IsNullOrEmpty(config.PrefabName))
			{
				return null;
			}
			GameObject prefab = PrefabManager.Instance.GetPrefab(config.PrefabName);
			if ((Object)(object)prefab != (Object)null)
			{
				return prefab;
			}
			GameObject prefab2 = PrefabManager.Instance.GetPrefab("Player");
			GameObject prefab3 = PrefabManager.Instance.GetPrefab("Dverger");
			if ((Object)(object)prefab2 == (Object)null || (Object)(object)prefab3 == (Object)null)
			{
				VikingAIPlugin.Log.LogError((object)("[HumanoidPrefabBuilder] Cannot build '" + config.PrefabName + "': Player or Dverger template missing."));
				return null;
			}
			GameObject val = PrefabManager.Instance.CreateClonedPrefab(config.PrefabName, prefab2);
			val.tag = "Untagged";
			Player component = val.GetComponent<Player>();
			CapsuleCollider component2 = val.GetComponent<CapsuleCollider>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.radius = Mathf.Min(component2.radius, 0.35f);
			}
			Humanoid val2 = val.AddComponent<Humanoid>();
			if ((Object)(object)component != (Object)null)
			{
				CopyDeclaredFields(component, val2, typeof(Character));
				CopyDeclaredFields(component, val2, typeof(Humanoid));
			}
			((Character)val2).m_name = config.DisplayName;
			((Character)val2).m_faction = config.Faction;
			((Character)val2).m_group = config.Group;
			((Character)val2).m_health = config.MaxHealth;
			((Character)val2).m_boss = false;
			val2.m_defaultItems = ResolvePrefabs(config.DefaultItemNames);
			val2.m_randomWeapon = ResolvePrefabs(config.RandomWeaponNames);
			val2.m_randomShield = ResolvePrefabs(config.RandomShieldNames);
			val2.m_randomArmor = Array.Empty<GameObject>();
			val2.m_randomSets = Array.Empty<ItemSet>();
			val2.m_randomItems = Array.Empty<RandomItem>();
			CharacterAnimEvent componentInChildren = val.GetComponentInChildren<CharacterAnimEvent>();
			if ((Object)(object)componentInChildren != (Object)null)
			{
				_animEventChar.Invoke(componentInChildren) = (Character)(object)val2;
			}
			MonsterAI val3 = val.AddComponent<MonsterAI>();
			MonsterAI component3 = prefab3.GetComponent<MonsterAI>();
			if ((Object)(object)component3 != (Object)null)
			{
				CopyDeclaredFields(component3, val3, typeof(BaseAI));
				CopyDeclaredFields(component3, val3, typeof(MonsterAI));
			}
			val3.m_attackPlayerObjects = config.AttackPlayerObjects;
			((BaseAI)val3).m_aggravatable = config.IsAggravatable;
			val3.m_enableHuntPlayer = false;
			val3.m_sleeping = false;
			val3.m_fallAsleepDistance = 0f;
			val3.m_wakeupRange = 0f;
			val3.m_consumeItems = new List<ItemDrop>();
			((BaseAI)val3).m_randomMoveRange = 6f;
			((BaseAI)val3).m_randomMoveInterval = 8f;
			((BaseAI)val3).m_viewRange = 28f;
			((BaseAI)val3).m_hearRange = 18f;
			val3.m_alertRange = 14f;
			val3.m_fleeIfLowHealth = 0f;
			((BaseAI)val3).m_avoidWater = true;
			((BaseAI)val3).m_avoidFire = false;
			((BaseAI)val3).m_smoothMovement = true;
			((BaseAI)val3).m_spawnMessage = "";
			((BaseAI)val3).m_deathMessage = "";
			((BaseAI)val3).m_alertedMessage = "";
			NpcTalk val4 = val.GetComponent<NpcTalk>() ?? val.AddComponent<NpcTalk>();
			NpcTalk component4 = prefab3.GetComponent<NpcTalk>();
			if ((Object)(object)component4 != (Object)null)
			{
				CopyDeclaredFields(component4, val4, typeof(NpcTalk));
			}
			val4.m_name = config.DisplayName;
			val4.m_maxRange = 12f;
			val4.m_greetRange = 6f;
			val4.m_byeRange = 10f;
			val4.m_minTalkInterval = 8f;
			val4.m_randomTalkInterval = 25f;
			Dest