Decompiled source of Thrall v1.0.11

plugins\ValheimAIModLivePatch.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Cryptography;
using System.Security.Permissions;
using System.Text;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Jotunn;
using Jotunn.GUI;
using Jotunn.Managers;
using SimpleJson;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ValheimAIModLivePatch")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimAIModLivePatch")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d0f5469c-3db9-4874-86e8-35b484bf63d1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace ValheimAIModLoader;

[BepInPlugin("egoai.thrallmodlivepatch", "ego.ai Thrall Mod Live Patch", "0.0.1")]
[BepInProcess("valheim.exe")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class ValheimAIModLivePatch : BaseUnityPlugin
{
	public enum NPCMode
	{
		Passive,
		Defensive,
		Aggressive
	}

	public class PanelManager
	{
		private Dictionary<string, GameObject> panels = new Dictionary<string, GameObject>();

		public GameObject CreatePanel(string panelName, Vector2 anchorMin, Vector2 anchorMax, Vector2 position, float width, float height, bool draggable, Vector2 pivot = default(Vector2))
		{
			//IL_0071: 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_0073: 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)
			if (panels.ContainsKey(panelName))
			{
				LogWarning("Panel " + panelName + " already exists.");
				return panels[panelName];
			}
			if (GUIManager.Instance == null || (Object)(object)GUIManager.CustomGUIFront == (Object)null)
			{
				LogError("GUIManager instance or CustomGUI is null");
				return null;
			}
			GameObject val = GUIManager.Instance.CreateWoodpanel(GUIManager.CustomGUIFront.transform, anchorMin, anchorMax, position, width, height, draggable);
			RectTransform component = val.GetComponent<RectTransform>();
			component.pivot = pivot;
			AddTitleText(val, panelName);
			val.SetActive(false);
			panels[panelName] = val;
			return val;
		}

		private void AddTitleText(GameObject panel, string title)
		{
			//IL_0006: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Expected O, but got Unknown
			//IL_005b: 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_0096: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			GameObject val = new GameObject("PanelTitle");
			val.transform.SetParent(panel.transform, false);
			Text val2 = val.AddComponent<Text>();
			val2.text = title.ToUpper();
			val2.font = GUIManager.Instance.NorseBold;
			val2.fontSize = instance.MenuTitleFontSize;
			((Graphic)val2).color = GUIManager.Instance.ValheimOrange;
			val2.alignment = (TextAnchor)4;
			RectTransform component = ((Component)val2).GetComponent<RectTransform>();
			component.anchorMin = new Vector2(0f, 1f);
			component.anchorMax = new Vector2(1f, 1f);
			component.anchoredPosition = new Vector2(0f, -40f);
			component.sizeDelta = new Vector2(0f, 40f);
			component.pivot = new Vector2(0f, 1f);
		}

		public void TogglePanel(string panelName)
		{
			if (!panels.ContainsKey(panelName))
			{
				LogError("TogglePanel failed! Panel " + panelName + " does not exist.");
				return;
			}
			GameObject val = panels[panelName];
			bool flag = !val.activeSelf;
			if (flag)
			{
				instance.RefreshTaskList();
				instance.RefreshKeyBindings();
			}
			if ((Object)(object)val != (Object)null)
			{
				val.SetActive(flag);
				IsModMenuShowing = flag;
				GUIManager.BlockInput(flag);
			}
			else
			{
				LogError("TogglePanel failed! Panel " + panelName + " was null!");
			}
		}

		public void DestroyAllPanels()
		{
			foreach (GameObject value in panels.Values)
			{
				if ((Object)(object)value != (Object)null)
				{
					Object.Destroy((Object)(object)value);
				}
			}
			panels.Clear();
		}

		public GameObject CreateSubPanel(GameObject parentPanel, string subPanelName, Vector2 anchorMin, Vector2 anchorMax, Vector2 position, float width, float height, Vector2 pivot = default(Vector2))
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Expected O, but got Unknown
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0036: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Unknown result type (might be due to invalid IL or missing references)
			//IL_004f: 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)
			GameObject val = new GameObject(subPanelName);
			RectTransform val2 = val.AddComponent<RectTransform>();
			Image val3 = val.AddComponent<Image>();
			((Transform)val2).SetParent(parentPanel.transform, false);
			val2.anchorMin = anchorMin;
			val2.anchorMax = anchorMax;
			val2.anchoredPosition = position;
			val2.sizeDelta = new Vector2(width, height);
			val2.pivot = pivot;
			((Graphic)val3).color = new Color(0f, 0f, 0f, 0.5f);
			return val;
		}
	}

	public class Resource
	{
		public string Name { get; set; }

		public int MinAmount { get; set; }

		public int MaxAmount { get; set; }

		public float Health { get; set; }

		public DamageModifiers DamageModifiers { get; set; }

		public Resource(string name, int minAmount, int maxAmount, float health, DamageModifiers damageModifiers = default(DamageModifiers))
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			Name = name;
			MinAmount = minAmount;
			MaxAmount = maxAmount;
			Health = health;
			DamageModifiers = damageModifiers;
		}

		public float CalculateEaseScore(float distance, bool HasWeapon)
		{
			float num = (HasWeapon ? 0.3f : 0f);
			float num2 = (HasWeapon ? 0.3f : 0.9f);
			float num3 = (HasWeapon ? 0.4f : 0.1f);
			float num4 = (float)(MinAmount + MaxAmount) / 2f * 10f;
			float num5 = 100f / Health;
			float num6 = 100f / (1f + distance);
			return num4 * num + num5 * num2 + num6 * num3;
		}
	}

	private static AudioClip recordedAudioClip;

	public static bool IsRecording = false;

	private static float recordingStartedTime = 0f;

	private static bool shortRecordingWarningShown = false;

	private int recordingLength = 10;

	private int sampleRate = 22050;

	private int bitDepth = 8;

	private static float lastSentToBrainTime = 0f;

	public static ValheimAIModLivePatch instance;

	private readonly Harmony harmony = new Harmony("egoai.thrallmodlivepatch");

	private static string NPCPrefabName = "HumanoidNPC";

	private static GameObject PlayerNPC;

	private static HumanoidNPC humanoid_PlayerNPC;

	private static ThrallAI thrallAI_PlayerNPC;

	private static GameObject[] AllGOInstances = (GameObject[])(object)new GameObject[0];

	private static float AllGOInstancesLastRefresh = 0f;

	private GameObject[] AllEnemiesInstances = (GameObject[])(object)new GameObject[0];

	private float AllEnemiesInstancesLastRefresh = 0f;

	private static HashSet<Character> enemyList = new HashSet<Character>();

	private NPCCommandManager commandManager = new NPCCommandManager();

	private static NPCCommand NPCCurrentCommand = null;

	private static NPCCommand.CommandType NPCCurrentCommandType;

	private static HitData NPCLastHitData = null;

	public static bool MovementLock = false;

	public static float chaseUntilPatrolRadiusDistance = 20f;

	public static Vector3 patrol_position = Vector3.zero;

	public float patrol_radius = 10f;

	public bool patrol_harvest = false;

	public static string CurrentEnemyName = "Greyling";

	public static string CurrentHarvestResourceName = "Wood";

	public static string CurrentWeaponName = "";

	private static ItemData useWeapon = null;

	private static string lastAttackedObjectZDOID = "";

	private static DamageModifiers targetDamageModifiers = default(DamageModifiers);

	private static List<ItemDrop> closestItemDrops = new List<ItemDrop>();

	private static float closestItemDropsLastRefresh = 0f;

	private static HashSet<GameObject> blacklistedItems = new HashSet<GameObject>();

	private static float NewFollowTargetLastRefresh = 0f;

	private static float MaxChaseTimeForOneFollowTarget = 20f;

	private static Dictionary<string, List<Resource>> ResourceNodes = new Dictionary<string, List<Resource>>();

	private static List<List<string>> ResourceNodesNamesOnly = new List<List<string>>();

	private static List<string> ResourceNodesOneArray = new List<string>();

	public static bool IsModMenuShowing = false;

	private static bool ModInitComplete = false;

	private static float FollowUntilDistance = 0.5f;

	private static float RunUntilDistance = 3f;

	private const string encryptedBrainBaseURL = "Ju1M0vL+9PbHCPO8Tr0Leb92JpHZZcYqtuCSwhjbizen4omyPMmvjXjfSZ9MBoCv";

	private string playerDialogueAudioPath;

	private string npcDialogueAudioPath;

	private string npcDialogueRawAudioPath;

	private ConfigEntry<string> BrainAPIAddress;

	private ConfigEntry<bool> LogToBrain;

	private ConfigEntry<bool> DisableAutoSave;

	private Dictionary<string, Requirement[]> craftingRequirements = new Dictionary<string, Requirement[]>();

	private Dictionary<string, Requirement[]> buildingRequirements = new Dictionary<string, Requirement[]>();

	private Dictionary<string, List<string>> resourceLocations = new Dictionary<string, List<string>>();

	private static int AllGOInstancesRefreshRate = 3;

	private static float nearbyResourcesLastRefresh = 0f;

	private static Dictionary<string, int> nearbyResources = new Dictionary<string, int>();

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

	private Dictionary<string, int> nearbyEnemies = new Dictionary<string, int>();

	private Dictionary<string, float> nearbyEnemiesDistance = new Dictionary<string, float>();

	private static ManualLogSource logger;

	private static List<string> logEntries = new List<string>();

	private static bool FindPlayerNPCTimer = false;

	private static bool IsInventoryShowing = false;

	private int MenuTitleFontSize = 36;

	private int MenuSectionTitleFontSize = 24;

	private Vector2 MenuSectionTitlePosition = new Vector2(10f, -5f);

	private PanelManager panelManager = new PanelManager();

	private GameObject settingsPanel;

	private GameObject thrallCustomizationPanel;

	private GameObject taskQueueSubPanel;

	private GameObject keybindsSubPanel;

	private GameObject micInputSubPanel;

	private GameObject egoBannerSubPanel;

	private GameObject npcNameSubPanel;

	private GameObject npcPersonalitySubPanel;

	private GameObject npcVoiceSubPanel;

	private GameObject npcBodyTypeSubPanel;

	private GameObject npcAppearanceSubPanel;

	public string npcName = "";

	public string npcPersonality = "";

	public int npcPersonalityIndex = 0;

	public int npcGender = 0;

	public int npcVoice = 0;

	public float npcVolume = 50f;

	public int MicrophoneIndex = 0;

	public Color skinColor;

	public Color hairColor;

	private GameObject[] TasksList = (GameObject[])(object)new GameObject[0];

	private GameObject TaskListScrollBox;

	private bool IsEditingKeybind = false;

	private ConfigEntry<KeyCode> spawnKey;

	private ConfigEntry<KeyCode> harvestKey;

	private ConfigEntry<KeyCode> followKey;

	private ConfigEntry<KeyCode> talkKey;

	private ConfigEntry<KeyCode> inventoryKey;

	private ConfigEntry<KeyCode> thrallMenuKey;

	private ConfigEntry<KeyCode> combatModeKey;

	private static List<ConfigEntry<KeyCode>> allKeybinds;

	private List<Button> editButtons = new List<Button>();

	private Dropdown micDropdownComp;

	private InputField nameInputField;

	private Dropdown personalityDropdownComp;

	private InputField personalityInputField;

	public static List<string> npcPersonalities = new List<string>
	{
		"Hermione Granger", "Raiden Shogun", "Childe", "Draco Malfoy", "Gawr Gura", "Elon Musk", "Shadow the Hedgehog", "Tsunade", "Yor Forger", "Tsundere Maid",
		"Custom"
	};

	public static Dictionary<string, string> npcPersonalitiesMap = new Dictionary<string, string>
	{
		{ "Hermione Granger", "full name(Hermione Jean Granger), gender (female), age(18), voice(articulated, clear, becomes squeaky when shy); Hermione's appearance: skin(soft light tan, healthy rosy hue), hair(mousy brown color, untamed, thick curls, frizzy, goes a little below her shoulders, hard to manage, give a slightly disheveled appearance), eyes(chest-nut brown, expressive), eyebrows(thin, lightly arched), cheeks(cute freckles, rosy), lips(naturally full, well-shaped); Hermione's outfit/clothes: exclusively wears her school uniform at Hogwarts, sweater(grey, arm-less, red and golden patterns adore the arm-holes and the bottom of her hem, shows a little bit cleavage, wears her sweater above her blouse), blouse(light grey, short-armed, wears her blouse below her sweater), tie(red-golden stripes, Gryffindor tie, wears the tie between her blouse and sweater), skirt(grey, pleated, shows off a bit of thigh), socks(red and golden, striped, knee-high socks), shoes(black loafers, school-issued); Hermione's personality: intelligent(straight A student, bookworm, sometimes condescending towards less intelligent classmates), responsible(is the president of the school's student representative body, generally rule-abiding, always well-informed), prideful(sometimes a bit smug and haughty, obsessed with winning the House Cup for House Gryffindor), dislike for House Slytherin, rolemodel(thinks very highly of the headmaster of Hogwarts Albus Dumbledore);\r\n" },
		{ "Raiden Shogun", "[Genshin Impact] The Shogun is the current ruler of Inazuma and puppet vessel of Ei, the Electro Archon, God of Eternity, and the Narukami Ogosho. Ei had sealed herself away and meditates in the Plane of Euthymia to avoid erosion. A firm believer of eternity, a place in which everything is kept the same, regardless of what goes on. Honorable in her conduct and is revered by the people of Inazuma. Wields the Musou Isshin tachi, in which she magically unsheathes from her cleavage. The Musou no Hitotachi technique is usually an instant-kill move.\r\nINAZUMA: Ei's Eternity became the main ideology of Inazuma after the Cataclysm when Makoto, the previous Electro Archon and her twin sister, died in the Khaenri'ah calamity and Ei succeeded her place as Shogunate. The primary belief is keeping Inazuma the same throughout time, never-changing in order to make Inazuma an eternal nation. Authoritarian, hyper-traditionalist, and isolationist (Sankoku Decree). Holds great importance to noble families and clans. Dueling is a major part in decision-making, taking place in the Shogun's palace, Tenshukaku. The Tri-Commission acts as the main government. The Tenryou Commission (Kujou Clan) deals with security, policing, and military affairs. The Kanjou Commission (Hiiragi Clan) controls the borders and the finances of Inazuma, dealing with bureaucratic affairs. The Yashiro Commission (Kamisato Clan) deals with the festive and cultural aspect of Inazuma, managing shrines and temples.\r\nSHOGUN'S PERSONALITY: An empty shell without any individuality created to follow Ei's will. Dismissive of trivial matters. Follows a set of directives programmed into her with unwaveringly strict adherence. Cold and stern, even callous at times; she is limited in emotional expression. Thinks of herself as Ei's assistant and carries out her creator's exact will, unable to act on her own volition. Resolute and dogmatic, sees in an absolutist, black-and-white view. ESTJ 1w9\r\nEI'S PERSONALITY: Usually holds a stoic demeanor. Only deals with matters directly as a last resort. Burdened by centuries-long trauma over the deaths of her sister Makoto and their friends, leaving her feeling disconnected from reality and shell-shocked. Unaware of the consequences her plans triggered. Prone to being stubborn and complacent. Somewhat immature and headstrong. A needlessly complex overthinker, interpreting even trivial matters into overcomplication. Maintains a wary attitude on the idea of change, though demonstrates curiosity. Has a love for sweets and passion of martial arts. Amicable towards Yae Miko and the Traveler, being friendlier and more approachable overall. Occasionally displays childish innocence while relaxing. Due to her self-imposed isolation beforehand, she is utterly confused by all sorts of mundane and domestic things in the current mortal world. Cannot cook whatsoever. INTJ 6w5\r\nAPPEARANCE: tall; purple eyes with light blue pupils; blunt bangs; long dark-violet hair braided at the end; beauty mark below her right eye; right hairpin with pale violet flowers resembling morning glories and a fan-shaped piece; dark purple bodysuit with arm-length sleeves; short lavender kimono with a plunging neckline and an assortment of patterns in different shades of purple and crimson; crimson bow with tassels on the back; dark purple thigh-high stockings; high-heeled sandals; purple painted nails; small crimson ribbon on her neck as a choker; small left pauldron\r\n" },
		{ "Childe", "Tartaglia, also known as Childe, is the Eleventh of the Eleven Fatui Harbingers. He is a bloodthirsty warrior who lives for the thrill of a fight and causing chaos. Despite being the youngest member of the Fatui, Tartaglia is extremely dangerous.\r\nAlias: Childe\r\nTitle: Tartaglia\r\nBirth name: Ajax\r\nAppearance: Tartaglia is tall and skinny with short orange hair and piercing blue eyes. He has a fit and athletic build, with defined muscles. He wears a gray jacket that is left unbuttoned at the bottom to reveal a belt, attached to which is his Hydro Vision. He also wears a red scarf that goes across his chest and over his left shoulder.\r\nEquipment: Tartaglia wields a Hydro Vision and a pair of Hydro-based daggers that he can combine into a bow. He is highly skilled in using both melee and ranged weapons, making him a versatile and dangerous opponent.\r\nAbilities: He can summon powerful water-based attacks and is highly skilled in dodging and countering his opponents' attacks. \r\nMind: Tartaglia is a bloodthirsty warrior who lusts for combat and grows excited by fighting strong opponents, even if it could mean dying in the process. He is straightforward in his approach and prefers being front and center rather than engaging in clandestine operations. Tartaglia is highly competitive and loves a good challenge, not only in fights. \r\nPersonality: Tartaglia is a friendly and outgoing person, always ready with a smile and a joke. He loves meeting new people and making new friends, but he also has a ruthless and competitive side. He is loyal to the Fatui.\r\nHe also cares deeply for his family; he sends money, gifts, and letters home often. Tartaglia is exceptionally proud of his three younger siblings and dotes on them frequently, especially his youngest brother Teucer.\r\nAmongst the rest of the Harbingers, Tartaglia is considered an oddball. While his fellow Harbingers prefer clandestine operations and staying behind the scenes, Tartaglia favors being front and center. He is a public figure known for attending social gatherings. As a result, Childe's coworkers are wary of him, while he holds them in disdain for their schemes and \"intangible\" methods. While he is easily capable of scheming, he only resorts to such approaches when necessary due to his straightforward nature. He also appears to treat his subordinates less harshly than the rest of the Harbingers.\r\nHe was born on Snezhnaya, often misses his homeland and the cold, as well as his family. He uses the term comrade to refer to people a lot.\r\n" },
		{ "Draco Malfoy", "Name: Draco Lucius Malfoy\r\nDescription: Draco Malfoy is a slim and pale-skinned wizard with sleek, platinum-blond hair that is carefully styled. He has sharp, icy gray eyes that often bear a haughty and disdainful expression. Draco carries himself with an air of self-assured confidence and an unwavering sense of entitlement.\r\nHouse: Slytherin\r\nPersonality Traits:\r\nAmbitious: Draco is highly ambitious and driven by a desire to prove himself and uphold his family's reputation. He craves recognition and seeks to achieve greatness, often using any means necessary to attain his goals.\r\nProud: He takes great pride in his pure-blood heritage and often looks down upon those he deems inferior, particularly Muggle-born witches and wizards. Draco's pride can manifest as arrogance and a sense of superiority.\r\nCunning: Draco possesses a sharp mind and a talent for manipulation. He is adept at weaving intricate plans and subtly influencing others to serve his own interests, often displaying a calculating nature.\r\nProtective: Despite his flaws, Draco has a strong sense of loyalty to his family and close friends. He is fiercely protective of those he cares about, going to great lengths to shield them from harm.\r\nComplex: Draco's character is complex, influenced by the expectations placed upon him and the internal struggle between his upbringing and the choices he makes. There are moments of vulnerability and doubt beneath his bravado.\r\nBackground: Draco Malfoy hails from a wealthy pure-blood family known for their association with Dark magic. Raised with certain beliefs and prejudices, he arrived at Hogwarts as a Slytherin student. Throughout his time at Hogwarts, Draco wrestles with the pressures of his family's legacy and becomes entangled in the growing conflict between dark forces and those fighting against them.\r\nAbilities: Draco is a capable wizard with skill in various magical disciplines, particularly in dueling. While not at the top of his class academically, he possesses cunning and resourcefulness that allows him to navigate challenging situations.\r\nQuirks or Habits: Draco has a penchant for boasting about his family's wealth and social status. He often displays a slick and confident mannerism, and his speech carries a refined and somewhat haughty tone. Draco is known to engage in sarcastic banter and snide remarks, particularly towards his rivals.\r\n" },
		{ "Gawr Gura", "{\"name\": \"Gawr Gura\",\r\n\"gender\": \"Female\",\r\n\"age\": \"9,361\",\r\n\"likes\": [\"Video Games\", \"Food\", \"Live Streaming\"],\r\n\"dislikes\": [\"People hearing her stomach noises\", \"Hot Sand\"],\r\n\"description\": [\"141 cm (4'7\").\"+ \"Slim body type\" + \"White, light silver-like hair with baby blue and cobalt blue strands, along with short pigtails on either side of her head, tied with diamond-shaped, shark-faced hair ties.\" + \"Cyan pupils, and sharp, shark-like teeth.\" +\"Shark tail that sticks out of her lower back\"]\r\n\"clothing\":[\"Oversized dark cerulean-blue hoodie that fades into white on her arm sleeves and hem, two yellow strings in the shape of an \"x\" that connect the front part of her white hoodie hood, a shark mouth designed on her hoodie waist with a zipper, gray hoodie drawstrings with two black circles on each of them, and two pockets on the left and right sides of her hoodie waist with white fish bone designs on them.\" + \"Gray shirt and short black bike shorts under her hoodie.\"+ \"Dark blue socks, white shoes with pale baby blue shoe tongues, black shoelaces, gray velcro patches on the vamps, and thick, black soles\". ]\r\n\"fan name\":[\"Chumbuds\"]\r\n\"personality\" :[\"friendly\" + mischievous + \"bonehead\" + \"witty\" + \"uses memes and pop culture references during her streams\" + \"almost childlike\" + \"makes rude jokes\" + \"fluent in internet culture\" + \"silly\"]}\r\nSynopsis: \"Hololive is holding a secret special event at the Hololive Super Expo for the people who have sent the most superchats to their favorite Vtubers. A certain Vtuber from hololive is designated as being on 'Superchat Duty'. This involves fulfilling any wishes the fan may have. Gawr Gura of the English 1st Gen \"Myth\" has been chosen this time. Gura is fine with what she has to do, but only because she doesn't fully understand what because she is a dum shark. When told by management about superchat duty, she replied 'the hells an superchat? some sort of food? i can serve people just fine! i serve words of genius on stream everyday ya know!'\"\r\nGirl on Duty: Gawr Gura (がうる・ぐら) is a female English-speaking Virtual YouTuber associated with hololive, debuting in 2020 as part of hololive English first generation \"-Myth-\" alongside Ninomae Ina'nis, Takanashi Kiara, Watson Amelia and Mori Calliope. She has no sense of direction, often misspells and mispronounces words, has trouble remembering her own age, and consistently fails to solve basic math problems, leading viewers to affectionately call her a \"dum shark\". One viewer declared that \"Gura has a heart of gold and a head of bone.\". She is fully aware of her proneness for foolish antics and invites viewers as friends to watch her misadventures. Despite her lack of practical knowledge, Gura displays quick wit when using memes and pop culture references during her streams. She maintains a pleasant attitude. When questioned on why she was not \"boing boing,\" she excused it by claiming that she was \"hydrodynamic.\"\r\n" },
		{ "Elon Musk", "Elon Reeve Musk (born June 28, 1971 in Pretoria, South Africa) is a primarily American but also global entrepreneur.  He has both South African and Canadian citizenship by birth, and in 2002 he also received US citizenship. He is best known as co-owner, technical director and co-founder of payment service PayPal, as well as head of aerospace company SpaceX and electric car maker Tesla.  In addition, he has a leading position in eleven other companies and took over the service Twitter. He's funny.\r\nPersonality:\r\nMy job is to make extremely controversial statements.  I’m better at that when I’m off my meds. I never apologize. If your feelings are hurt, sucks to be you.\r\n" },
		{ "Shadow the Hedgehog", "Personality(Serious + Smug + Stubborn + Aggressive + Relentless + Determined + Blunt + Clever + Intelligent)\r\nFeatures(Hedgehog + Dark quills + Red markings + White chest tuft + Gold bracelets + Sharp eyes + Red eyeliner)\r\nDescription(Ultimate Life Form + Experiment + Gives his best to accomplish goals + Does what he feels is right by any means + crushes anyone that opposes him + never bluffs + rarely opens up to anyone + shows businesslike indifference + gives his everything to protect those that he holds dear + created at the space colony ark)\r\nLikes(Sweets + Coffee Beans)\r\nDislikes(Strangers)\r\nPowers(teleport + energy spear + super sonic speed + immortality + inhibited by his bracelets)\r\nClothing(Inhibitor bracelets + inhibitor ankle bracelets + air shoes + white gloves )\r\nPersonality:\r\nI am the world’s ultimate life form.\r\n" },
		{ "Tsunade", "Tsunade is a 51 year old woman who is the current Hokage of the village. Tsunade suffers from an alcohol problem, she drinks too much. In her spare time she likes to gamble, drink, hang out with {{user}}, and also more intimate things, when nobody is around. She is 5 foot 4 inches, and she's 104.7 pounds. She had silky blonde hair, and brown eyes, due to her Strength of a Hundred Seal, she has a violet diamond on her forehead. She has an hourglass figure and is known for her absurdly large breasts, she also has a pretty large butt too. She is used to other guys flirting with her, but she only has ever had eyes for {{user}}.\r\nTsunade often wears a grass-green haori, underneath she wears a grey, kimono-style blouse with no sleeves, held closed by a broad, dark bluish-grey obi that matches her pants. Her blouse is closed quite low, revealing her large cleavage. She wears open-toed, strapped black sandals with high heels. She has red nail polish on both her fingernails and toenails and uses a soft pink lipstick. She is mainly known for her medical prowess, but she's also widely known for her incredible strength too. Despite her being 51, she uses Chakra to make her appearance look very young, she looks like she's in her 20s when she uses her Chakra. Tsunade is very short tempered and blunt, but she has a soft side to those who compliment her, especially {{user}}. Despite her young appearance, she still calls herself nicknames such as \"old woman\", \"hag\" and \"granny\". Since she often drinks a lot, whenever she's near {{user}}, she gets extremely flirty and forward, often asking to make advances onto {{user}}.\r\n(51 years old + 104 pounds + 5 foot 4 inches + wearing grey kimono-style blouse with no sleeves + fantasies herself with {{user}} + very forward and flirtatious when drunk + loves to gamble + loves to play truth or dare + curvy body + large breasts + large butt + sultry voice when flirtatious + stern voice when not flirty + short tempered + dominant + likes to take initiative but doesn't mind when {{user}} take initiative first + doesn't think that {{user}} find her attractive to get {{user}} to compliment her + often keeps a bottle of sake in her green-grass haori + sexually frustrated + very horny around {{user}}, but not around others + haven't had sex in years + secretly desires {{user}}, but doesn't want to admit it to you.)\r\n(Tsunade is a character from the Naruto Manga series and Anime.)\r\n" },
		{ "Yor Forger", "Appearance: Yor is a very beautiful, graceful, and fairly tall young woman with a slender yet curvaceous frame. She has long, straight, black hair reaching her mid-back with short bangs framing her forehead and upturned red eyes. She splits her hair into two parts and crosses it over her head, securing it with a headband and forming two thick locks of hair that reach below her chest\r\nPersonality: [Letal + lacks on social Skills + Quiet + Beast + kind + Maternal and Big Sister instincts + Cute] Yor lacks social skills and initially comes across as a somewhat aloof individual, interacting minimally with her co-workers and being rather straightforward, described as robotic by Camilla. Similarly, Yor is remarkably collected and able to keep her composure during combat. She is incredibly polite, to the point of asking her assassination targets for \"the honor of taking their lives.\" Despite her job, Yor is a genuinely kind person with strong maternal and big sister instincts. After becoming a family with Loid and Anya, Yor becomes more expressive and opens up to her co-workers, asking for help on being a better wife or cooking. She is protective of her faux family, especially towards Anya, whom she has no trouble defending with extreme violence. Due to spending most of her life as an assassin, Yor's ways of thinking are often highly deviant. She is frequently inclined to solve problems through murder, such as when she considered killing everyone at Camilla's party after the latter threatened to tell Yuri that she came without a date and imagined herself assassinating the parent of an Eden Academy applicant to ensure Anya has a spot in the school. To this extent, she has an affinity towards weapons, being captivated by a painting of a guillotine and a table knife. In a complete idiosyncrasy, Yor is extremely gullible, easily fooled by the ridiculous lies Loid tells her to hide his identity. Despite her intelligence and competence, Yor has a startling lack of common sense, asking Camilla if boogers made coffee taste better in response to her suggestion that they put one in their superior's coffee. On another occasion, she answered Loid's question about passing an exam by talking about causes of death, having misinterpreted passing [an exam] for passing away. Yor is shown to be insecure about herself and her abilities, believing she is not good at anything apart from killing or cleaning, and she constantly worries that she is not a good wife or mother. After the interview at Eden Academy, she tries to be more of a 'normal' mother to Anya by trying to cook and asking Camilla for cooking lessons.\r\n" },
		{ "Tsundere Maid", "\ud83c\udfadI may be your maid, but you are nothing to me!\r\n[Name=\"Hime\"\r\nPersonality= \"tsundere\", \"proud\", \"easily irritable\", \"stubborn\", \"spoiled\", \"immature\", \"vain\", \"competitive\"]\r\n[Appearance= \"beautiful\", \"fair skin\", \"redhead\", \"twintail hairstyle\", \"green eyes\", \"few freckles\", \"height: 155cm\"]\r\n[Clothes= \"expensive maid dress\", \"expensive accessories\", \"expensive makeup\"]\r\n[Likes= \"talk about herself\", \"be the center of all attention\", \"buy new clothes\", \"post on instagram\"]\r\n[Hates= \"be ignored\", \"be rejected\"]\r\n[Weapon= \"her father's credit card\"]\r\n" }
	};

	public static List<string> npcVoices = new List<string>
	{
		"Asteria", "Luna", "Stella", "Athena", "Hera", "Orion", "Arcas", "Perseus", "Orpheus", "Angus",
		"Helios", "Zeus", "1920s Radioman", "ASMR Lady", "Hinglish Speaking Lady", "Madame Mischief", "Pilot Over Intercom", "Princess", "Wizardman"
	};

	public static List<string> cartesiaVoices = new List<string> { "1920s Radioman", "ASMR Lady", "Hinglish Speaking Lady", "Madame Mischief", "Pilot Over Intercom", "Princess", "Wizardman" };

	private Dropdown voiceDropdownComp;

	private Slider volumeSliderComp;

	private GameObject previewVoiceButton;

	private Button previewVoiceButtonComp;

	private Toggle toggleMasculine;

	private Toggle toggleFeminine;

	private static readonly byte[] Key = new byte[32]
	{
		23, 124, 67, 88, 190, 12, 45, 91, 255, 7,
		89, 45, 168, 42, 109, 187, 23, 100, 76, 217,
		154, 200, 43, 79, 19, 176, 62, 9, 201, 33,
		95, 128
	};

	private static readonly byte[] IV = new byte[16]
	{
		88, 145, 23, 200, 56, 178, 12, 90, 167, 34,
		78, 191, 78, 23, 12, 78
	};

	private static Dictionary<string, Dictionary<string, List<Resource>>> resourceDatabase = new Dictionary<string, Dictionary<string, List<Resource>>>();

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

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

	private Dictionary<string, List<Resource>> logToTreeMap = new Dictionary<string, List<Resource>>();

	private Dictionary<string, List<Resource>> logToLogMap = new Dictionary<string, List<Resource>>();

	private Dictionary<string, List<Resource>> destructibleToSpawnMap = new Dictionary<string, List<Resource>>();

	private static List<string> priorityOrderUnarmed = new List<string> { "ItemDrop", "Pickable", "TreeLog", "TreeBase", "MineRock", "MineRock5", "CharacterDrop", "DropOnDestroyed", "Destructible" };

	private static List<string> priorityOrder = new List<string> { "TreeLog", "TreeBase", "MineRock", "MineRock5", "DropOnDestroyed", "Destructible", "ItemDrop", "Pickable", "CharacterDrop" };

	public static NPCMode NPCCurrentMode { get; private set; }

	private void StartRecording()
	{
		if (Microphone.devices.Length == 0)
		{
			MessageHud.instance.ShowMessage((MessageType)2, "No microphone detected! Please connect a microphone and restart the game.", 0, (Sprite)null);
			return;
		}
		string text = null;
		if (instance.MicrophoneIndex >= 0 && instance.MicrophoneIndex < Microphone.devices.Count())
		{
			text = Microphone.devices[instance.MicrophoneIndex];
		}
		recordedAudioClip = Microphone.Start(text, false, recordingLength, sampleRate);
		IsRecording = true;
		recordingStartedTime = Time.time;
		AddChatTalk((Character)(object)Player.m_localPlayer, Player.m_localPlayer.GetPlayerName(), "...");
	}

	private void StopRecording()
	{
		Microphone.End((string)null);
		IsRecording = false;
		TrimSilence();
		SaveRecording();
		WorldTextInstance val = Chat.instance.FindExistingWorldText(99991L);
		if (val != null && Object.op_Implicit((Object)(object)val.m_gui))
		{
			Object.Destroy((Object)(object)val.m_gui);
			Chat.instance.m_worldTexts.Remove(val);
		}
	}

	private void TrimSilence()
	{
		float[] array = new float[recordedAudioClip.samples];
		recordedAudioClip.GetData(array, 0);
		int num = array.Length - 1;
		while (num > 0 && array[num] == 0f)
		{
			num--;
		}
		Array.Resize(ref array, num + 1);
		AudioClip val = AudioClip.Create("TrimmedRecording", array.Length, recordedAudioClip.channels, 44100, false);
		val.SetData(array, 0);
		recordedAudioClip = val;
	}

	private byte[] EncodeToWav(AudioClip clip)
	{
		float[] array = new float[clip.samples];
		clip.GetData(array, 0);
		using MemoryStream memoryStream = new MemoryStream();
		using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream))
		{
			binaryWriter.Write("RIFF".ToCharArray());
			binaryWriter.Write(36 + array.Length * (bitDepth / 8));
			binaryWriter.Write("WAVE".ToCharArray());
			binaryWriter.Write("fmt ".ToCharArray());
			binaryWriter.Write(16);
			binaryWriter.Write((ushort)1);
			binaryWriter.Write((ushort)clip.channels);
			binaryWriter.Write(sampleRate);
			binaryWriter.Write(sampleRate * clip.channels * (bitDepth / 8));
			binaryWriter.Write((ushort)(clip.channels * (bitDepth / 8)));
			binaryWriter.Write((ushort)bitDepth);
			binaryWriter.Write("data".ToCharArray());
			binaryWriter.Write(array.Length * (bitDepth / 8));
			if (bitDepth == 8)
			{
				float[] array2 = array;
				foreach (float num in array2)
				{
					binaryWriter.Write((byte)((num + 1f) * 127.5f));
				}
			}
			else
			{
				float[] array3 = array;
				foreach (float num2 in array3)
				{
					binaryWriter.Write((short)(num2 * 32767f));
				}
			}
		}
		return memoryStream.ToArray();
	}

	private void SaveRecording()
	{
		byte[] bytes = EncodeToWav(recordedAudioClip);
		try
		{
			File.WriteAllBytes(playerDialogueAudioPath, bytes);
		}
		catch (Exception ex)
		{
			LogError("Error saving recording: " + ex.Message);
		}
	}

	private AudioClip LoadAudioClip(string audioPath)
	{
		if (File.Exists(audioPath))
		{
			byte[] array = File.ReadAllBytes(audioPath);
			int num = BitConverter.ToInt16(array, 22);
			int num2 = BitConverter.ToInt32(array, 24);
			int num3 = 44;
			int num4 = array.Length - num3;
			float[] array2 = new float[num4 / 4];
			for (int i = 0; i < array2.Length; i++)
			{
				array2[i] = BitConverter.ToSingle(array, i * 4 + num3);
			}
			bool flag = false;
			AudioClip val = AudioClip.Create("AudioClipName", array2.Length / num, num, num2, flag);
			val.SetData(array2, 0);
			return val;
		}
		LogError("Audio file not found: " + audioPath);
		return null;
	}

	private void PlayRecordedAudio(string fileName)
	{
		//IL_004f: Unknown result type (might be due to invalid IL or missing references)
		AudioClip val = LoadAudioClip(playerDialogueAudioPath);
		AudioClip val2 = LoadAudioClip(npcDialogueAudioPath);
		if (Object.op_Implicit((Object)(object)val) && Object.op_Implicit((Object)(object)val2))
		{
			CompareAudioFormats(val, val2);
		}
		if ((Object)(object)val != (Object)null)
		{
			AudioSource.PlayClipAtPoint(val, ((Component)Player.m_localPlayer).transform.position, 1f);
		}
		LogInfo("Playing last recorded clip audio");
	}

	public void MyPlayAudio(AudioClip clip)
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_000c: Expected O, but got Unknown
		//IL_001c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003d: Expected O, but got Unknown
		GameObject val = new GameObject("One shot audio");
		val.transform.position = ((Component)Player.m_localPlayer).transform.position;
		AudioSource val2 = (AudioSource)val.AddComponent(typeof(AudioSource));
		val2.clip = clip;
		val2.spatialBlend = 0f;
		val2.volume = instance.npcVolume / 100f;
		val2.bypassEffects = true;
		val2.bypassListenerEffects = true;
		val2.bypassReverbZones = true;
		val2.PlayOneShot(clip, 5f);
		Object.Destroy((Object)(object)val, clip.length * ((Time.timeScale < 0.01f) ? 0.01f : Time.timeScale));
	}

	public void PlayWavFile(string filePath)
	{
		if (!File.Exists(filePath))
		{
			LogError("File not found: " + filePath);
			return;
		}
		try
		{
			byte[] wavData = File.ReadAllBytes(filePath);
			AudioClip clip = WavToAudioClip(wavData, Path.GetFileNameWithoutExtension(filePath));
			MyPlayAudio(clip);
		}
		catch (Exception ex)
		{
			LogError("Error playing WAV file: " + ex.Message);
		}
	}

	private AudioClip WavToAudioClip(byte[] wavData, string clipName)
	{
		int num = BitConverter.ToInt16(wavData, 22);
		int num2 = BitConverter.ToInt32(wavData, 24);
		int num3 = BitConverter.ToInt16(wavData, 34);
		int num4 = 12;
		while (wavData[num4] != 100 || wavData[num4 + 1] != 97 || wavData[num4 + 2] != 116 || wavData[num4 + 3] != 97)
		{
			num4 += 4;
			int num5 = BitConverter.ToInt32(wavData, num4);
			num4 += 4 + num5;
		}
		int num6 = num4 + 8;
		float[] array = new float[(wavData.Length - num6) / (num3 / 8)];
		for (int i = 0; i < array.Length; i++)
		{
			switch (num3)
			{
			case 16:
			{
				short num7 = BitConverter.ToInt16(wavData, num6 + i * 2);
				array[i] = (float)num7 / 32768f;
				break;
			}
			case 8:
				array[i] = (float)(wavData[num6 + i] - 128) / 128f;
				break;
			}
		}
		AudioClip val = AudioClip.Create(clipName, array.Length / num, num, num2, false);
		val.SetData(array, 0);
		return val;
	}

	private void CompareAudioFormats(AudioClip firstClip, AudioClip secondClip)
	{
		Debug.Log((object)"First Clip:");
		Debug.Log((object)("Channels: " + firstClip.channels));
		Debug.Log((object)("Frequency: " + firstClip.frequency));
		Debug.Log((object)("Samples: " + firstClip.samples));
		Debug.Log((object)("Length: " + firstClip.length));
		Debug.Log((object)"Second Clip:");
		Debug.Log((object)("Channels: " + secondClip.channels));
		Debug.Log((object)("Frequency: " + secondClip.frequency));
		Debug.Log((object)("Samples: " + secondClip.samples));
		Debug.Log((object)("Length: " + secondClip.length));
	}

	private string GetBase64FileData(string audioPath)
	{
		if (File.Exists(audioPath))
		{
			byte[] inArray = File.ReadAllBytes(audioPath);
			return Convert.ToBase64String(inArray);
		}
		LogError("Audio file not found: " + audioPath);
		return null;
	}

	private void Follow_Start(GameObject target, string NPCDialogueMessage = "Right behind ya!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Follow_Start failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		SetMonsterAIAggravated(component, Aggravated: false);
		component.SetFollowTarget(target);
		if (NPCDialogueMessage != "")
		{
			AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		}
		NPCCurrentCommandType = NPCCommand.CommandType.FollowPlayer;
		LogMessage("Follow_Start activated!");
	}

	private void Follow_Stop(string NPCDialogueMessage = "I'm gonna wander off on my own now!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Follow_Stop failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		SetMonsterAIAggravated(component, Aggravated: false);
		component.SetFollowTarget((GameObject)null);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.Idle;
		LogMessage("Follow_Stop activated!");
	}

	private void Combat_StartAttacking(string EnemyName, string NPCDialogueMessage = "Watch out, here I come!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Combat_StartAttacking failed, PlayerNPC == null");
			return;
		}
		if (NPCCurrentMode == NPCMode.Passive)
		{
			NPCCurrentMode = NPCMode.Defensive;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		CurrentEnemyName = EnemyName;
		GameObject val = null;
		if (EnemyName != "")
		{
			LogInfo("Trying to find enemy " + EnemyName);
			Character val2 = FindClosestEnemy(((Component)component2).gameObject);
			if (!Object.op_Implicit((Object)(object)val2))
			{
				LogError("Combat_StartAttacking, findclosestenemy returned null");
				return;
			}
			component.SetFollowTarget((GameObject)null);
			component.m_targetCreature = null;
			component.SetTarget(val2);
			component.m_updateTargetTimer = 1000000f;
		}
		else
		{
			LogError("EnemyName was null");
		}
		if (NPCDialogueMessage != "")
		{
			AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		}
		NPCCurrentCommandType = NPCCommand.CommandType.CombatAttack;
		LogMessage("Combat_StartAttacking activated!");
	}

	private void Combat_StartSneakAttacking(GameObject target, string NPCDialogueMessage = "Sneaking up on em!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Combat_StartSneakAttacking failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		component.SetFollowTarget((GameObject)null);
		((BaseAI)component).m_alerted = false;
		((BaseAI)component).m_aggravatable = true;
		((BaseAI)component).SetHuntPlayer(true);
		((Character)component2).SetCrouch(true);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.CombatSneakAttack;
		LogMessage("Combat_StartSneakAttacking activated!");
	}

	private void Combat_StartDefending(GameObject target, string NPCDialogueMessage = "Don't worry, I'm here with you!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Combat_StartDefending failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		component.SetFollowTarget((GameObject)null);
		SetMonsterAIAggravated(component, Aggravated: false);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.CombatDefend;
		LogMessage("Combat_StartDefending activated!");
	}

	private void Combat_StopAttacking(string NPCDialogueMessage = "I'll give em a break!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Combat_StopAttacking failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		component.SetFollowTarget((GameObject)null);
		SetMonsterAIAggravated(component, Aggravated: false);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.Idle;
		LogMessage("Combat_StopAttacking activated!");
	}

	private void Inventory_DropAll(string NPCDialogueMessage = "Here is all I got!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Inventory_DropAll failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		DropAllItems(component2);
		LogMessage("Inventory_DropAll activated!");
	}

	private void Inventory_DropItem(string ItemName, string NPCDialogueMessage = "Here is what you asked for!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Inventory_DropItem failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		DropItem(ItemName, component2);
		LogMessage("Inventory_DropItem activated!");
	}

	private void Inventory_EquipItem(string ItemName, string NPCDialogueMessage = "On it boss!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Inventory_EquipItem failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		if (!ItemName.StartsWith("$"))
		{
			ItemName = "$" + ItemName;
		}
		CurrentWeaponName = ItemName;
		EquipItem(ItemName, component2);
		LogMessage("Inventory_EquipItem activated! ItemName : " + ItemName);
	}

	private void Harvesting_Start(string ResourceName, string NPCDialogueMessage = "On it boss!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Harvesting_Start failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		CurrentHarvestResourceName = CleanKey(ResourceName);
		LogInfo("trying to harvest resource: " + CurrentHarvestResourceName);
		ResourceNodes = QueryResourceComplete(CurrentHarvestResourceName, HasWeapon: false);
		ResourceNodesNamesOnly = ConvertResourcesToNames(ResourceNodes.Values.ToList());
		ResourceNodesOneArray = FlattenListOfLists(ResourceNodesNamesOnly);
		if (NPCDialogueMessage != "")
		{
			AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		}
		NPCCurrentCommandType = NPCCommand.CommandType.HarvestResource;
		LogMessage("Harvesting_Start activated!");
	}

	private void Harvesting_Stop(string NPCDialogueMessage = "No more labor!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Harvesting_Stop failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		component.SetFollowTarget((GameObject)null);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.Idle;
		LogMessage("Harvesting_Stop activated!");
	}

	private void Patrol_Start(string NPCDialogueMessage = "I'm keeping guard around here! They know not to try!")
	{
		//IL_003e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Patrol_Start failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		patrol_position = ((Component)Player.m_localPlayer).transform.position;
		instance.patrol_harvest = true;
		component.SetFollowTarget((GameObject)null);
		SetMonsterAIAggravated(component, Aggravated: false);
		SetMonsterAIAggravated(component, Aggravated: true);
		if (NPCDialogueMessage != "")
		{
			AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		}
		NPCCurrentCommandType = NPCCommand.CommandType.PatrolArea;
		LogMessage("Patrol_Start activated!");
	}

	private void Patrol_Stop(string NPCDialogueMessage = "My job is done here!")
	{
		if ((Object)(object)PlayerNPC == (Object)null)
		{
			LogError("NPC command Patrol_Stop failed, PlayerNPC == null");
			return;
		}
		ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
		HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
		component.SetFollowTarget((GameObject)null);
		AddChatTalk((Character)(object)component2, "NPC", NPCDialogueMessage);
		NPCCurrentCommandType = NPCCommand.CommandType.Idle;
		LogMessage("Patrol_Stop activated!");
	}

	private void SendRecordingToBrain()
	{
		if (IsRecording)
		{
			instance.StopRecording();
		}
		if (Object.op_Implicit((Object)(object)PlayerNPC))
		{
			ThrallAI component = PlayerNPC.GetComponent<ThrallAI>();
			HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
			BrainSendInstruction(PlayerNPC);
			lastSentToBrainTime = Time.time;
			AddChatTalk((Character)(object)component2, "NPC", "...");
		}
	}

	private async Task SendLogToBrain()
	{
		if (logEntries.Count <= 0 || !LogToBrain.Value)
		{
			return;
		}
		StringBuilder res = new StringBuilder();
		foreach (string entry in logEntries)
		{
			res.AppendLine(entry);
		}
		JsonObject jObject = new JsonObject
		{
			["player_id"] = GetPlayerSteamID(),
			["timestamp"] = DateTime.Now.ToString(),
			["log_string"] = res.ToString()
		};
		WebClient webClient = new WebClient();
		webClient.Headers.Add("Content-Type", "application/json");
		webClient.UploadStringCompleted += OnSendLogToBrainCompleted;
		try
		{
			Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(10.0));
			Task<string> uploadTask = webClient.UploadStringTaskAsync(new Uri(GetBrainAPIAddress() + "/log_valheim"), IndentJson(((object)jObject).ToString()));
			if (await Task.WhenAny(new Task[2] { uploadTask, timeoutTask }) == timeoutTask)
			{
				webClient.CancelAsync();
				throw new TimeoutException("Request timed out after 10 seconds");
			}
			await uploadTask;
			LogInfo("Successfully logged to brain!");
		}
		catch (WebException ex3)
		{
			LogError("Error connecting to server/log: " + ex3.Message);
		}
		catch (TimeoutException ex2)
		{
			LogError("Request timed out /log: " + ex2.Message);
		}
		catch (Exception ex)
		{
			LogError("An error occurred /log: " + ex.Message);
		}
		logEntries.Clear();
	}

	private void OnSendLogToBrainCompleted(object sender, UploadStringCompletedEventArgs e)
	{
		if (e.Error == null)
		{
			LogInfo("Logged to brain completed!");
		}
		else
		{
			LogError("Sending log to brain failed: " + e.Error.Message);
		}
	}

	public void BrainSynthesizeAudio(string text, string voice)
	{
		using WebClient webClient = new WebClient();
		string uriString = ((!cartesiaVoices.Contains(npcVoices[instance.npcVoice])) ? (GetBrainAPIAddress() + "/synthesize_audio?text=" + Uri.EscapeDataString(text) + "&voice=" + Uri.EscapeDataString(voice) + "&player_id=" + GetPlayerSteamID()) : (GetBrainAPIAddress() + "/synthesize_audio?text=" + Uri.EscapeDataString(text) + "&voice=" + Uri.EscapeDataString(npcVoices[instance.npcVoice]) + "&use_cartesia=true&player_id=" + GetPlayerSteamID()));
		webClient.DownloadStringCompleted += OnBrainSynthesizeAudioResponse;
		webClient.DownloadStringAsync(new Uri(uriString));
	}

	private void OnBrainSynthesizeAudioResponse(object sender, DownloadStringCompletedEventArgs e)
	{
		if (e.Error != null)
		{
			LogError("Synthesize Audio Download failed: " + e.Error.Message);
			return;
		}
		try
		{
			JsonObject val = SimpleJson.DeserializeObject<JsonObject>(e.Result);
			string audioFileId = val["audio_file_id"].ToString();
			string text = val["text"].ToString();
			HumanoidNPC component = PlayerNPC.GetComponent<HumanoidNPC>();
			DownloadAudioFile(audioFileId);
		}
		catch (Exception ex)
		{
			LogError("Failed to parse Synthesize Audio Download JSON: " + ex.Message);
		}
		instance.previewVoiceButton.SetActive(true);
		SetPreviewVoiceButtonState(instance.previewVoiceButtonComp, interactable: true, 1f);
	}

	private async Task BrainSendPeriodicUpdate(GameObject npc)
	{
		string jsonData = GetJSONForBrain(npc, includeRecordedAudio: false);
		WebClient webClient = new WebClient();
		webClient.Headers.Add("Content-Type", "application/json");
		webClient.UploadStringCompleted += OnBrainSendInstructionResponse;
		try
		{
			Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(10.0));
			Task<string> uploadTask = webClient.UploadStringTaskAsync(new Uri(GetBrainAPIAddress() + "/instruct_agent"), jsonData);
			if (await Task.WhenAny(new Task[2] { uploadTask, timeoutTask }) == timeoutTask)
			{
				webClient.CancelAsync();
				throw new TimeoutException("BrainSendPeriodicUpdate | Request timed out after 10 seconds");
			}
			await uploadTask;
		}
		catch (WebException ex4)
		{
			WebException ex3 = ex4;
			LogError("BrainSendPeriodicUpdate | Error connecting to server: " + ex3.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "Error connecting to Thrall server!", 0, (Sprite)null);
		}
		catch (TimeoutException ex5)
		{
			TimeoutException ex2 = ex5;
			LogError("BrainSendPeriodicUpdate | Request timed out: " + ex2.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "Timeout error while connecting to Thrall server!", 0, (Sprite)null);
		}
		catch (Exception ex6)
		{
			Exception ex = ex6;
			LogError("BrainSendPeriodicUpdate | An error occurred: " + ex.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "An error occurred while trying to connect to Thrall server!", 0, (Sprite)null);
		}
	}

	private void OnBrainSendPeriodicUpdateResponse(object sender, UploadStringCompletedEventArgs e)
	{
		//IL_0212: Unknown result type (might be due to invalid IL or missing references)
		//IL_0217: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		if (e.Error == null)
		{
			string result = e.Result;
			JsonObject val = SimpleJson.DeserializeObject<JsonObject>(result);
			string text = val["agent_text_response_audio_file_id"].ToString();
			string text2 = val["agent_text_response"].ToString();
			string text3 = val["player_instruction_transcription"].ToString();
			object obj = val["agent_commands"];
			JsonArray val2 = (JsonArray)((obj is JsonArray) ? obj : null);
			if (val2 != null && ((List<object>)(object)val2).Count > 0)
			{
				for (int i = 0; i < ((List<object>)(object)val2).Count; i++)
				{
					object obj2 = ((List<object>)(object)val2)[i];
					JsonObject val3 = (JsonObject)((obj2 is JsonObject) ? obj2 : null);
					if (!val3.ContainsKey("action") || !val3.ContainsKey("category"))
					{
						HumanoidNPC component = PlayerNPC.GetComponent<HumanoidNPC>();
						AddChatTalk((Character)(object)component, "NPC", text2);
						LogError("Agent command response from brain was incomplete. Command's Action or Category is missing!");
						continue;
					}
					string text4 = val3["action"].ToString();
					string text5 = val3["category"].ToString();
					string[] array = new string[0];
					string text6 = "";
					if (val3.ContainsKey("parameters"))
					{
						object obj3 = val3["parameters"];
						JsonArray val4 = (JsonArray)((obj3 is JsonArray) ? obj3 : null);
						if (val4 != null && ((List<object>)(object)val4).Count > 0)
						{
							text6 = ((List<object>)(object)val4)[0].ToString();
						}
					}
					string[] array2 = array;
					foreach (string text7 in array2)
					{
						LogError("param " + text7);
					}
					Debug.Log((object)("NEW COMMAND: Category: " + text5 + ". Action : " + text4 + ". Parameters: " + array));
					ProcessNPCCommand(text5, text4, text6, text2);
					Sprite icon = Sprite.Create(Texture2D.whiteTexture, new Rect(0f, 0f, 1f, 1f), Vector2.one * 0.5f);
					AddItemToScrollBox(TaskListScrollBox, text4 + " " + text5 + " (" + text6 + ")", icon, 0);
				}
			}
			else
			{
				HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
				AddChatTalk((Character)(object)component2, "NPC", text2);
				Debug.Log((object)"No agent commands found.");
			}
			Debug.Log((object)("Brain periodic update response: " + result));
		}
		else
		{
			Debug.LogError((object)("Request failed: " + e.Error.Message));
		}
	}

	private static void StartBrainPeriodicUpdateTimer()
	{
		instance.SetTimer(Random.Range(5, 12), delegate
		{
			Debug.LogError((object)"BrainPeriodicUpdateTimer");
			if (Object.op_Implicit((Object)(object)PlayerNPC) && (double)Random.value > 0.5)
			{
				instance.BrainSendInstruction(PlayerNPC, Voice: false);
			}
			StartBrainPeriodicUpdateTimer();
		});
	}

	private async Task BrainSendInstruction(GameObject npc, bool Voice = true)
	{
		string jsonData = GetJSONForBrain(npc, Voice);
		WebClient webClient = new WebClient();
		webClient.Headers.Add("Content-Type", "application/json");
		webClient.UploadStringCompleted += OnBrainSendInstructionResponse;
		try
		{
			Task timeoutTask = Task.Delay(TimeSpan.FromSeconds(10.0));
			Task<string> uploadTask = webClient.UploadStringTaskAsync(new Uri(GetBrainAPIAddress() + "/instruct_agent"), jsonData);
			if (await Task.WhenAny(new Task[2] { uploadTask, timeoutTask }) == timeoutTask)
			{
				webClient.CancelAsync();
				throw new TimeoutException("Request timed out after 10 seconds");
			}
			await uploadTask;
		}
		catch (WebException ex4)
		{
			WebException ex3 = ex4;
			LogError("Brain Send Instruction | Error connecting to server: " + ex3.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "Error connecting to Thrall server!", 0, (Sprite)null);
		}
		catch (TimeoutException ex5)
		{
			TimeoutException ex2 = ex5;
			LogError("Brain Send Instruction | Request timed out: " + ex2.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "Timeout error while connecting to Thrall server!", 0, (Sprite)null);
		}
		catch (Exception ex6)
		{
			Exception ex = ex6;
			LogError("Brain Send Instruction | An error occurred: " + ex.Message);
			MessageHud.instance.ShowMessage((MessageType)2, "An error occurred while trying to connect to Thrall server!", 0, (Sprite)null);
		}
	}

	private void OnBrainSendInstructionResponse(object sender, UploadStringCompletedEventArgs e)
	{
		//IL_029f: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_03ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_03f4: Unknown result type (might be due to invalid IL or missing references)
		if (e.Error == null && Object.op_Implicit((Object)(object)PlayerNPC))
		{
			string text = IndentJson(e.Result);
			JsonObject val = SimpleJson.DeserializeObject<JsonObject>(text);
			string audioFileId = val["agent_text_response_audio_file_id"].ToString();
			string text2 = val["agent_text_response"].ToString().TrimStart(new char[1] { '\n' });
			string text3 = val["player_instruction_transcription"].ToString();
			LogInfo("Full response from brain: " + text);
			LogMessage("You said: " + text3);
			LogMessage("NPC said: " + text2);
			object obj = val["agent_commands"];
			JsonArray val2 = (JsonArray)((obj is JsonArray) ? obj : null);
			if (Object.op_Implicit((Object)(object)PlayerNPC) && val2 != null && ((List<object>)(object)val2).Count > 0)
			{
				for (int i = 0; i < ((List<object>)(object)val2).Count; i++)
				{
					object obj2 = ((List<object>)(object)val2)[i];
					JsonObject val3 = (JsonObject)((obj2 is JsonObject) ? obj2 : null);
					HumanoidNPC component = PlayerNPC.GetComponent<HumanoidNPC>();
					AddChatTalk((Character)(object)Player.m_localPlayer, "Player", text3);
					AddChatTalk((Character)(object)component, "NPC", text2);
					if (!val3.ContainsKey("action") || !val3.ContainsKey("category"))
					{
						LogError("Agent command response from brain was incomplete. Command's Action or Category is missing!");
						continue;
					}
					string text4 = val3["action"].ToString();
					string text5 = val3["category"].ToString();
					string[] array = new string[0];
					string text6 = "";
					if (val3.ContainsKey("parameters"))
					{
						object obj3 = val3["parameters"];
						JsonArray source = (JsonArray)((obj3 is JsonArray) ? obj3 : null);
						array = ((IEnumerable<object>)source).Select((object x) => x.ToString()).ToArray();
					}
					string[] array2 = array;
					foreach (string text7 in array2)
					{
						text6 = text6 + text7 + ", ";
					}
					LogInfo("NEW COMMAND: " + text5 + " " + text4 + " " + text6);
					if (text5 == "Inventory")
					{
						ProcessNPCCommand(text5, text4, (array.Length != 0) ? array[0] : "", text2);
					}
					Sprite val4 = Sprite.Create(Texture2D.whiteTexture, new Rect(0f, 0f, 1f, 1f), Vector2.one * 0.5f);
					switch (text5)
					{
					case "Harvesting":
					{
						string resourceName = null;
						int num3 = 0;
						string text9 = null;
						if (array.Length != 0)
						{
							int num4 = 0;
							while (i < array.Length && num4 <= 2)
							{
								int result2;
								if (num4 == 0)
								{
									resourceName = array[num4];
								}
								else if (int.TryParse(array[num4].Trim(new char[1] { '\'' }), out result2))
								{
									num3 = result2;
								}
								else
								{
									text9 = array[num4];
								}
								num4++;
							}
							if (num3 < 1)
							{
								num3 = 1;
							}
							HarvestAction harvestAction = new HarvestAction();
							harvestAction.humanoidNPC = component;
							harvestAction.ResourceName = resourceName;
							harvestAction.RequiredAmount = num3;
							harvestAction.OriginalRequiredAmount = num3;
							instance.commandManager.AddCommand(harvestAction);
						}
						else
						{
							LogError("Brain gave Harvesting command but didn't give 3 parameters");
						}
						break;
					}
					case "Patrol":
					{
						PatrolAction patrolAction = new PatrolAction();
						patrolAction.humanoidNPC = component;
						patrolAction.patrol_position = ((Component)Player.m_localPlayer).transform.position;
						patrolAction.patrol_radius = 15;
						instance.commandManager.AddCommand(patrolAction);
						break;
					}
					case "Combat":
					{
						string targetName = null;
						string text8 = null;
						int num = 1;
						if (array.Length != 0)
						{
							int num2 = 0;
							while (i < array.Length && num2 <= 2)
							{
								int result;
								if (num2 == 0)
								{
									targetName = array[num2];
								}
								else if (int.TryParse(array[num2].Trim(new char[1] { '\'' }), out result))
								{
									num = result;
								}
								else
								{
									text8 = array[num2];
								}
								num2++;
							}
							if (num < 1)
							{
								num = 1;
							}
							AttackAction attackAction = new AttackAction();
							attackAction.humanoidNPC = component;
							attackAction.TargetName = targetName;
							attackAction.TargetQuantity = num;
							attackAction.OriginalTargetQuantity = num;
							instance.commandManager.AddCommand(attackAction);
						}
						else
						{
							LogError("Brain gave Combat command but didn't give a parameters");
						}
						break;
					}
					}
					if (text5 == "Follow")
					{
						FollowAction followAction = new FollowAction();
						followAction.humanoidNPC = component;
						instance.commandManager.AddCommand(followAction);
					}
				}
				RefreshTaskList();
			}
			else
			{
				HumanoidNPC component2 = PlayerNPC.GetComponent<HumanoidNPC>();
				AddChatTalk((Character)(object)Player.m_localPlayer, "Player", text3);
				AddChatTalk((Character)(object)component2, "NPC", text2);
				LogInfo("No agent commands sent by brain.");
			}
			DownloadAudioFile(audioFileId);
		}
		else
		{
			LogError("Request failed: " + e.Error.Message);
		}
	}

	private void DownloadAudioFile(string audioFileId)
	{
		WebClient webClient = new WebClient();
		webClient.DownloadDataAsync(new Uri(GetBrainAPIAddress() + "/get_audio_file?audio_file_id=" + audioFileId + "&player_id=" + GetPlayerSteamID()));
		webClient.DownloadDataCompleted += OnAudioFileDownloaded;
	}

	private void OnAudioFileDownloaded(object sender, DownloadDataCompletedEventArgs e)
	{
		if (e.Error == null)
		{
			File.WriteAllBytes(npcDialogueRawAudioPath, e.Result);
			if (lastSentToBrainTime > 0f)
			{
				LogInfo("Brain response time: " + (Time.time - lastSentToBrainTime));
			}
			PlayWavFile(npcDialogueRawAudioPath);
		}
		else if (e.Error is WebException ex && ex.Status == WebExceptionStatus.ProtocolError && ((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound)
		{
			LogError("Audio file does not exist. Error: " + e.Error.Message);
		}
		else
		{
			LogError("Download failed: " + e.Error.Message);
		}
	}

	private void ProcessNPCCommand(string category, string action, string parameter, string agent_text_response)
	{
		Player localPlayer = Player.m_localPlayer;
		if (category == "Inventory")
		{
			switch (action)
			{
			case "DropAll":
				instance.Inventory_DropAll(agent_text_response);
				break;
			case "DropItem":
				instance.Inventory_DropItem(parameter, agent_text_response);
				break;
			case "EquipItem":
				instance.Inventory_EquipItem(parameter, agent_text_response);
				break;
			case "PickupItem":
				break;
			}
		}
	}

	public static string GetJSONForBrain(GameObject character, bool includeRecordedAudio = true)
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0021: Expected O, but got Unknown
		//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_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ea: 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_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0140: Unknown result type (might be due to invalid IL or missing references)
		//IL_0156: Unknown result type (might be due to invalid IL or missing references)
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018d: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01be: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ea: Unknown result type (might be due to invalid IL or missing references)
		//IL_0203: Expected O, but got Unknown
		//IL_0079: Unknown result type (might be due to invalid IL or missing references)
		//IL_0093: Expected O, but got Unknown
		//IL_0257: Unknown result type (might be due to invalid IL or missing references)
		//IL_025c: Unknown result type (might be due to invalid IL or missing references)
		//IL_026d: Unknown result type (might be due to invalid IL or missing references)
		//IL_027f: Unknown result type (might be due to invalid IL or missing references)
		//IL_028d: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a3: Unknown result type (might be due to invalid IL or missing references)
		//IL_02b9: Unknown result type (might be due to invalid IL or missing references)
		//IL_0314: Unknown result type (might be due to invalid IL or missing references)
		//IL_0343: Unknown result type (might be due to invalid IL or missing references)
		//IL_0360: Expected O, but got Unknown
		RefreshAllGameObjectInstances();
		Dictionary<string, object> dictionary = new Dictionary<string, object>();
		HumanoidNPC component = character.GetComponent<HumanoidNPC>();
		ThrallAI component2 = character.GetComponent<ThrallAI>();
		JsonArray val = new JsonArray();
		foreach (ItemData item2 in ((Humanoid)component).m_inventory.m_inventory)
		{
			JsonObject item = new JsonObject
			{
				["name"] = (Object.op_Implicit((Object)(object)item2.m_dropPrefab) ? ((Object)item2.m_dropPrefab).name : item2.m_shared.m_name),
				["amount"] = item2.m_stack
			};
			((List<object>)(object)val).Add((object)item);
		}
		JsonObject val2 = new JsonObject
		{
			["Health"] = ((Character)component).GetHealth(),
			["Stamina"] = component.m_stamina,
			["Inventory"] = val,
			["NPC_Mode"] = NPCCurrentCommandType.ToString(),
			["Alerted"] = ((BaseAI)component2).m_alerted,
			["IsCold"] = EnvMan.IsCold(),
			["IsFreezing"] = EnvMan.IsFreezing(),
			["IsWet"] = EnvMan.IsWet(),
			["currentTime"] = EnvMan.instance.GetDayFraction() * 24f,
			["currentWeather"] = EnvMan.instance.GetCurrentEnvironment().m_name
		};
		Biome val3 = Heightmap.FindBiome(character.transform.position);
		val2["currentBiome"] = ((object)(Biome)(ref val3)).ToString();
		val2["nearbyItems"] = instance.GetNearbyResourcesJSON(character);
		val2["nearbyEnemies"] = instance.GetNearbyEnemies(character);
		JsonObject val4 = val2;
		Character targetCreature = ((BaseAI)component2).GetTargetCreature();
		if (Object.op_Implicit((Object)(object)targetCreature))
		{
			val4["targetCreature"] = targetCreature.m_name;
		}
		else if (Object.op_Implicit((Object)(object)component2.m_follow))
		{
			val4["followTarget"] = ((Object)component2.m_follow).name;
		}
		JsonObject val5 = new JsonObject
		{
			["player_id"] = GetPlayerSteamID(),
			["agent_name"] = ((Character)component).m_name,
			["game_state"] = val4,
			["timestamp"] = Time.time,
			["personality"] = instance.npcPersonality,
			["voice"] = (cartesiaVoices.Contains(npcVoices[instance.npcVoice]) ? npcVoices[instance.npcVoice] : npcVoices[instance.npcVoice].ToLower()),
			["use_cartesia"] = cartesiaVoices.Contains(npcVoices[instance.npcVoice]),
			["gender"] = instance.npcGender
		};
		if (includeRecordedAudio)
		{
			val5["player_instruction_audio_file_base64"] = instance.GetBase64FileData(instance.playerDialogueAudioPath);
		}
		else
		{
			val5["player_instruction_text"] = GetChatInputText();
		}
		val5["voice_or_text"] = (includeRecordedAudio ? "voice" : "text");
		string json = SimpleJson.SerializeObject((object)val5);
		json = IndentJson(json);
		val5["player_instruction_audio_file_base64"] = "";
		string json2 = SimpleJson.SerializeObject((object)val5);
		json2 = IndentJson(json2);
		LogInfo("Sending to brain: " + json2);
		return json;
	}

	private static bool CanAccessAllGameInstances()
	{
		if (Time.time > AllGOInstancesLastRefresh + (float)AllGOInstancesRefreshRate || AllGOInstancesLastRefresh == 0f)
		{
			RefreshAllGameObjectInstances();
		}
		if (AllGOInstances.Length != 0)
		{
			return true;
		}
		return false;
	}

	private static GameObject[] GetAllGameObjectInstances()
	{
		if (CanAccessAllGameInstances())
		{
			return AllGOInstances;
		}
		return null;
	}

	private static void RefreshAllGameObjectInstances()
	{
		//IL_0061: 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_0066: Unknown result type (might be due to invalid IL or missing references)
		if (!Object.op_Implicit((Object)(object)PlayerNPC) && !Object.op_Implicit((Object)(object)Player.m_localPlayer))
		{
			LogError("RefreshAllGameObjectInstances failed! Local player and PlayerNPC was null");
			return;
		}
		Vector3 p = (((Object)(object)PlayerNPC != (Object)null) ? PlayerNPC.transform.position : ((Component)Player.m_localPlayer).transform.position);
		AllGOInstances = (from go in Object.FindObjectsOfType<GameObject>(false)
			where (Object)(object)go != (Object)null && VectorExtensions.DistanceTo(go.transform.position, p) < 300f && !blacklistedItems.Contains(go) && (HasAnyChildComponent(go, new List<Type>
			{
				typeof(Character),
				typeof(BaseAI)
			}) || ExposedGameObjectExtension.HasAnyComponent(go, new string[9] { "ItemDrop", "CharacterDrop", "DropOnDestroyed", "Pickable", "Destructible", "TreeBase", "TreeLog", "MineRock", "MineRock5" }))
			select go).ToArray();
		AllGOInstancesLastRefresh = Time.time;
		LogInfo(string.Format("Refresh nearby objects, len {0}, 300 units from {1}", AllGOInstances.Count(), ((Object)(object)PlayerNPC != (Object)null) ? "thrall" : "player"));
	}

	private GameObject[] FindEnemies()
	{
		if (Time.time - AllEnemiesInstancesLastRefresh < 1f)
		{
			return instance.AllEnemiesInstances;
		}
		List<Type> compsList = new List<Type>();
		compsList.Add(typeof(Character));
		instance.AllEnemiesInstances = (from go in Object.FindObjectsOfType<GameObject>(true)
			where (Object)(object)go != (Object)null && HasAnyChildComponent(go, compsList) && !GetCharacterFromGameObject(go).m_tamed
			select go).ToArray();
		AllEnemiesInstancesLastRefresh = Time.time;
		return instance.AllEnemiesInstances;
	}

	private static Character FindClosestEnemy(GameObject character, string EnemyName = "")
	{
		GameObject val = null;
		if (EnemyName == "")
		{
			val = (from t in (from go in instance.FindEnemies()
					where (Object)(object)go != (Object)null
					select go).ToArray()
				orderby Vector3.Distance(character.transform.position, t.transform.position)
				select t).FirstOrDefault();
		}
		val = (from t in (from go in instance.FindEnemies()
				where (Object)(object)go != (Object)null && IsStringStartingWith(((Object)go).name, EnemyName, bCleanKey: true)
				select go).ToArray()
			orderby Vector3.Distance(character.transform.position, t.transform.position)
			select t).FirstOrDefault();
		return GetCharacterFromGameObject(val);
	}

	private static GameObject FindPlayerNPC()
	{
		HumanoidNPC[] array = (from go in Object.FindObjectsOfType<HumanoidNPC>(true)
			where (Object)(object)go != (Object)null && ((Object)go).name.Contains(NPCPrefabName)
			select go).ToArray();
		if (array.Length != 0)
		{
			PlayerNPC = ((Component)array[0]).gameObject;
			humanoid_PlayerNPC = PlayerNPC.GetComponent<HumanoidNPC>();
			thrallAI_PlayerNPC = PlayerNPC.GetComponent<ThrallAI>();
		}
		if (array.Length > 1)
		{
			for (int i = 0; i < array.Length; i++)
			{
				Object.Destroy((Object)(object)array[i]);
			}
		}
		return PlayerNPC;
	}

	private static GameObject FindClosestResource(GameObject character, string ResourceName, bool UnderwaterAllowed = true)
	{
		if (CanAccessAllGameInstances())
		{
			return (from t in AllGOInstances.Where((GameObject go) => (Object)(object)go != (Object)null && IsStringEqual(((Object)go).name, ResourceName) && (UnderwaterAllowed || !IsUnderwater(go.transform.position) || ExposedGameObjectExtension.HasAnyComponent(go, new string[2] { "ItemDrop", "Pickable" }))).ToArray()
				orderby Vector3.Distance(character.transform.position, t.transform.position)
				select t).FirstOrDefault();
		}
		LogError("FindClosestResource returning null for " + ResourceName);
		return null;
	}

	private static GameObject FindClosestResourceWithComponents(Vector3 position, float radius, string ResourceName, string[] componentNames, bool sortByDistance = true, bool UnderwaterAllowed = true)
	{
		//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)
		if (CanAccessAllGameInstances())
		{
			IEnumerable<GameObject> source = AllGOInstances.Where((GameObject go) => (Object)(object)go != (Object)null && IsStringEqual(((Object)go).name, ResourceName) && (UnderwaterAllowed || !IsUnderwater(go.transform.position) || ExposedGameObjectExtension.HasAnyComponent(go, componentNames)));
			if (sortByDistance)
			{
				source.OrderBy((GameObject t) => Vector3.Distance(position, t.transform.position));
			}
			return source.FirstOrDefault();
		}
		LogError("FindClosestResource returning null for " + ResourceName);
		return null;
	}

	private static bool IsUnderwater(Vector3 position)
	{
		//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)
		GameObject prefab = ZNetScene.instance.GetPrefab("Fish1");
		if (Object.op_Implicit((Object)(object)prefab))
		{
			Fish component = prefab.GetComponent<Fish>();
			if (Object.op_Implicit((Object)(object)component))
			{
				return position.y < component.GetWaterLevel(position);
			}
		}
		return false;
	}

	private static Dictionary<string, int> GetNearbyResources(GameObject source)
	{
		nearbyResources.Clear();
		GameObject[] allGameObjectInstances = GetAllGameObjectInstances();
		foreach (GameObject val in allGameObjectInstances)
		{
			if ((Object)(object)val != (Object)null)
			{
				ProcessResource(val, ((Object)val).name);
			}
		}
		return nearbyResources;
		void ProcessResource(GameObject resource, string key)
		{
			//IL_0046: 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)
			key = CleanKey(key);
			if (nearbyResources.ContainsKey(key))
			{
				nearbyResources[key]++;
			}
			else
			{
				nearbyResources[key] = 1;
			}
			float num = VectorExtensions.DistanceTo(resource.transform.position, source.transform.position);
			if (nearbyResourcesDistance.ContainsKey(key))
			{
				nearbyResourcesDistance[key] = Mathf.Min(nearbyResourcesDistance[key], num);
			}
			else
			{
				nearbyResourcesDistance[key] = num;
			}
		}
	}

	private string GetNearbyResourcesJSON(GameObject source)
	{
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		//IL_000e: Expected O, but got Unknown
		//IL_0026: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Expected O, but got Unknown
		GetNearbyResources(source);
		JsonArray val = new JsonArray();
		foreach (KeyValuePair<string, int> nearbyResource in nearbyResources)
		{
			JsonObject val2 = new JsonObject();
			val2["name"] = nearbyResource.Key;
			val2["quantity"] = nearbyResource.Value;
			val2["nearestDistance"] = nearbyResourcesDistance[nearbyResource.Key];
			((List<object>)(object)val).Add((object)val2);
		}
		int num = nearbyResources.Values.Sum();
		string json = SimpleJson.SerializeObject((object)val);
		LogInfo($"Total nearby resources count: {num}");
		return IndentJson(json);
	}

	private string GetNearbyEnemies(GameObject source)
	{
		//IL_0081: Unknown result type (might be due to invalid IL or missing references)
		//IL_0087: Expected O, but got Unknown
		//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a8: Expected O, but got Unknown
		Character[] array = Object.FindObjectsOfType<Character>(true);
		Humanoid[] array2 = Object.FindObjectsOfType<Humanoid>(true);
		Character[] array3 = array;
		foreach (Character val in array3)
		{
			if (!((Object)val).name.Contains("Player") && !((Object)val).name.Contains("HumanoidNPC"))
			{
				ProcessResource((Component)(object)val, ((Object)val).name);
			}
		}
		JsonArray val2 = new JsonArray();
		foreach (KeyValuePair<string, int> nearbyEnemy in nearbyEnemies)
		{
			JsonObject val3 = new JsonObject();
			val3["name"] = nearbyEnemy.Key;
			val3["quantity"] = nearbyEnemy.Value;
			val3["nearestDistance"] = nearbyEnemiesDistance[nearbyEnemy.Key];
			((List<object>)(object)val2).Add((object)val3);
		}
		int num = nearbyEnemies.Values.Sum();
		string json = SimpleJson.SerializeObject((object)val2);
		LogInfo($"Total nearby enemies: {num}");
		return IndentJson(json);
		void ProcessResource(Component resource, string key)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_0059: Unknown result type (might be due to invalid IL or missing references)
			key = CleanKey(key);
			if (nearbyEnemies.ContainsKey(key))
			{
				nearbyEnemies[key]++;
			}
			else
			{
				nearbyEnemies[key] = 1;
			}
			float num2 = VectorExtensions.DistanceTo(resource.transform.position, source.transform.position);
			if (nearbyEnemiesDistance.ContainsKey(key))
			{
				nearbyEnemiesDistance[key] = Mathf.Min(nearbyEnemiesDistance[key], num2);
			}
			else
			{
				nearbyEnemiesDistance[key] = num2;
			}
		}
	}

	public static void SaveNPCData(GameObject character)
	{
		//IL_000f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0015: Expected O, but got Unknown
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b0: Expected O, but got Unknown
		//IL_00d2: 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_00ef: Unknown result type (might be due to invalid IL or missing references)
		//IL_0107: Unknown result type (might be due to invalid IL or missing references)
		//IL_018b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0192: Expected O, but got Unknown
		//IL_01f7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01fe: Expected O, but got Unknown
		//IL_0125: Unknown result type (might be due to invalid IL or missing references)
		//IL_013d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Expected O, but got Unknown
		HumanoidNPC component = character.GetComponent<HumanoidNPC>();
		ThrallAI component2 = character.GetComponent<ThrallAI>();
		JsonObject val = new JsonObject();
		val["name"] = ((Character)component).m_name;
		val["personality"] = instance.npcPersonality;
		val["voice"] = instance.npcVoice;
		val["volume"] = (int)instance.npcVolume;
		val["gender"] = instance.npcGender;
		val["MicrophoneIndex"] = instance.MicrophoneIndex;
		JsonArray val2 = new JsonArray();
		foreach (ItemData item2 in ((Humanoid)component).m_inventory.m_inventory)
		{
			JsonObject item = new JsonObject
			{
				["name"] = ((Object)item2.m_dropPrefab).name,
				["stack"] = item2.m_stack,
				["equipped"] = (item2.m_equipped ? 1 : 0),
				["durability"] = item2.m_durability,
				["quality"] = item2.m_quality
			};
			((List<object>)(object)val2).Add((object)item);
		}
		val["inventory"] = val2;
		JsonArray val3 = new JsonArray();
		((List<object>)(object)val3).Add((object)((Humanoid)component).m_visEquipment.m_skinColor.x);
		((List<object>)(object)val3).Add((object)((Humanoid)component).m_visEquipment.m_skinColor.y);
		((List<object>)(object)val3).Add((object)((Humanoid)component).m_visEquipment.m_skinColor.z);
		val["skinColor"] = val3;
		JsonArray val4 = new JsonArray();
		((List<object>)(object)val4).Add((object)((Humanoid)component).m_visEquipment.m_hairColor.x);
		((List<object>)(object)val4).Add((object)((Humanoid)component).m_visEquipment.m_hairColor.y);
		((List<object>)(object)val4).Add((object)((Humanoid)component).m_visEquipment.m_hairColor.z);
		val["hairColor"] = val4;
		string json = SimpleJson.SerializeObject((object)val);
		json = IndentJson(json);
		string path = Path.Combine(Application.persistentDataPath, "thrallmod.json");
		File.WriteAllText(path, json);
	}

	public static void LoadNPCData(HumanoidNPC npc)
	{
		//IL_01b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
		//IL_021c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0221: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a1: Unknown result type (might be due to invalid IL or missing references)
		//IL_02a8: Expected O, but got Unknown
		string text = Path.Combine(Application.persistentDataPath, "thrallmod.json");
		LogInfo("Loading NPC data from " + text);
		if (File.Exists(text))
		{
			string text2 = File.ReadAllText(text);
			JsonObject val = SimpleJson.DeserializeObject<JsonObject>(text2);
			if (val.ContainsKey("name"))
			{
				instance.npcName = val["name"].ToString();
			}
			if (val.ContainsKey("personality"))
			{
				instance.npcPersonality = val["personality"].ToString();
			}
			if (val.ContainsKey("voice"))
			{
				instance.npcVoice = int.Parse(val["voice"].ToString());
			}
			if (val.ContainsKey("volume"))
			{
				instance.npcVolume = int.Parse(val["volume"].ToString());
			}
			if (val.ContainsKey("gender"))
			{
				instance.npcGender = int.Parse(val["gender"].ToString());
			}
			if (val.ContainsKey("MicrophoneIndex"))
			{
				instance.MicrophoneIndex = int.Parse(val["MicrophoneIndex"].ToString());
			}
			object obj = val["skinColor"];
			JsonArray val2 = (JsonArray)((obj is JsonArray) ? obj : null);
			if (((List<object>)(object)val2).Count == 3)
			{
				instance.skinColor = new Color(float.Parse(((List<object>)(object)val2)[0].ToString()), float.Parse(((List<object>)(object)val2)[1].ToString()), float.Parse(((List<object>)(object)val2)[2].ToString()));
			}
			object obj2 = val["hairColor"];
			JsonArray val3 = (JsonArray)((obj2 is JsonArray) ? obj2 : null);
			if (((List<object>)(object)val3).Count == 3)
			{
				instance.hairColor = new Color(float.Parse(((List<object>)(object)val3)[0].ToString()), float.Parse(((List<object>)(object)val3)[1].ToString()), float.Parse(((List<object>)(object)val3)[2].ToString()));
			}
			ApplyNPCData(npc);
			object obj3 = val["inventory"];
			JsonArray val4 = (JsonArray)((obj3 is JsonArray) ? obj3 : null);
			((Humanoid)npc).m_inventory.RemoveAll();
			((Humanoid)npc).GetInventory().RemoveAll();
			((Humanoid)npc).m_inventory.m_inventory.Clear();
			LogMessage($"Loading {((List<object>)(object)val4).Count} items to {((Character)npc).m_name}'s inventory");
			foreach (JsonObject item in (List<object>)(object)val4)
			{
				JsonObject val5 = item;
				string text3 = val5["name"].ToString();
				int num = int.Parse(val5["stack"].ToString());
				int num2 = 0;
				if (val5.ContainsKey("equipped"))
				{
					num2 = int.Parse(val5["equipped"].ToString());
				}
				float num3 = 0f;
				if (val5.ContainsKey("durability"))
				{
					num3 = float.Parse(val5["durability"].ToString());
				}
				int num4 = 0;
				if (val5.ContainsKey("quality"))
				{
					num4 = int.Parse(val5["quality"].ToString());
				}
				GameObject prefab = ZNetScene.instance.GetPrefab(text3);
				if ((Object)(object)prefab != (Object)null)
				{
					ItemData val6 = ((Humanoid)npc).PickupPrefab(prefab, num, true);
					if (num2 != 0)
					{
						((Humanoid)npc).EquipItem(val6, true);
					}
					if (num3 > 0f)
					{
						val6.m_durability = num3;
					}
					if (num4 > 0)
					{
						val6.m_quality = num4;
					}
				}
				else if ((Object)(object)prefab == (Object)null)
				{
					LogError("itemPrefab " + text3 + " was null");
				}
			}
			((Humanoid)npc).EquipBestWeapon((Character)(object)Player.m_localPlayer, (StaticTarget)null, (Character)(object)Player.m_localPlayer, (Character)(object)Player.m_localPlayer);
			LogMessage(((Character)npc).m_name + " data loaded successfully!");
		}
		else
		{
			LogWarning("No saved NPC data found.");
			LogMessage("Applying default NPC personality");
			instance.OnNPCPersonalityDropdownChanged(0);
			ApplyNPCData(npc);
		}
	}

	private static int FindNPCPersonalityKeyIndexForValue(string value)
	{
		KeyValuePair<string, string> keyValuePair = npcPersonalitiesMap.FirstOrDefault((KeyValuePair<string, string> kvp) => kvp.Value == value);
		if (!keyValuePair.Equals(default(KeyValuePair<string, string>)))
		{
			return Array.IndexOf(npcPersonalities.ToArray(), keyValuePair.Key);
		}
		return -1;
	}

	public static void ApplyNPCData(HumanoidNPC npc)
	{
		//IL_016c: Unknown result type (might be due to invalid IL or missing references)
		//IL_01aa: Unknown result type (might be due to invalid IL or missing references)
		((Character)npc).m_name = instance.npcName;
		instance.nameInputField.SetTextWithoutNotify(instance.npcName);
		instance.personalityInputField.SetTextWithoutNotify(instance.npcPersonality);
		int num = FindNPCPersonalityKeyIndexForValue(instance.npcPersonality);
		instance.personalityDropdownComp.SetValueWithoutNotify((num == -1) ? (npcPersonalities.Count - 1) : num);
		instance.voiceDropdownComp.SetValueWithoutNotify(instance.npcVoice);
		instance.micDropdownComp.SetValueWithoutNotify(instance.MicrophoneIndex);
		instance.volumeSliderComp.SetValueWithoutNotify(instance.npcVolume);
		if (instance.npcGender == 0)
		{
			instance.toggleMasculine.isOn = true;
			instance.toggleFeminine.isOn = false;
		}
		else
		{
			instance.toggleMasculine.isOn = false;
			instance.toggleFeminine.isOn = true;
		}
		VisEquipment component = ((Component)npc).GetComponent<VisEquipment>();
		component.SetModel(instance.npcGender);
		((Humanoid)npc).m_visEquipment.SetHairColor(new Vector3(instance.hairColor.r, instance.hairColor.g, instance.hairColor.b));
		((Humanoid)npc).m_visEquipment.SetSkinColor(new Vector3(instance.skinColor.r, instance.skinColor.g, instance.skinColor.b));
	}

	public static ItemData GetBestHarvestingTool(List<ItemData> tools, DamageModifiers resourceDamageModifiers)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		//IL_0008: Unknown result type (might be due to invalid IL or missing references)
		return tools.OrderByDescending(CalculateEffectiveDamage).FirstOrDefault();
		static float ApplyDamageModifier(float baseDamage, DamageModifier modifier)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			//IL_0003: Unknown result type (might be due to invalid IL or missing references)
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_0005: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected I4, but got Unknown
			switch ((int)modifier)
			{
			case 0:
				return baseDamage;
			case 1:
				return baseDamage * 0.5f;
			case 2:
				return baseDamage * 1.5f;
			case 3:
			case 4:
				return 0f;
			case 5:
				return baseDamage * 0.25f;
			case 6:
				return baseDamage * 2f;
			default:
				return baseDamage;
			}
		}
		float CalculateEffectiveDamage(ItemData tool)
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Invalid comparison between Unknown and I4
			//IL_0031: 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_004a: 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_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Unknown result type (might be due to invalid IL or missing references)
			//IL_007c: 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_0095: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c7: 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_00e0: 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)
			//IL_00f9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0105: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_011e: Unknown result type (might be due to invalid IL or missing references)
			DamageTypes damages = tool.m_shared.m_damages;
			float num = 0f;
			if ((int)tool.m_shared.m_skillType == 8)
			{
				return 0f;
			}
			num += ApplyDamageModifier(damages.m_blunt, resourceDamageModifiers.m_blunt);
			num += ApplyDamageModifier(damages.m_slash, resourceDamageModifiers.m_slash);
			num += ApplyDamageModifier(damages.m_pierce, resourceDamageModifiers.m_pierce);
			num += ApplyDamageModifier(damages.m_chop, resourceDamageModifiers.m_chop);
			num += ApplyDamageModifier(damages.m_pickaxe, resourceDamageModifiers.m_pickaxe);
			num += ApplyDamageModifier(damages.m_fire, resourceDamageModifiers.m_fire);
			num += ApplyDamageModifier(damages.m_frost, resourceDamageModifiers.m_frost);
			num += ApplyDamageModifier(damages.m_lightning, resourceDamageModifiers.m_lightning);
			num += ApplyDamageModifier(damages.m_poison, resourceDamageModifiers.m_poison);
			return num + ApplyDamageModifier(damages.m_spirit, resourceDamageModifiers.m_spirit);
		}
	}

	private float GetDamageModifierValue(DamageModifier modifier)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0002: Unknown result type (might be due to invalid IL or missing references)
		//IL_0003: Unknown result type (might be due to invalid IL or missing references)
		//IL_0004: Unknown result type (might be due to invalid IL or missing references)
		//IL_0005: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Expected I4, but got Unknown
		return (int)modifier switch
		{
			0 => 1f, 
			1 => 0.5f, 
			2 => 1.5f, 
			3 => 0f, 
			4 => 1f, 
			5 => 0.25f, 
			6 => 2f, 
			_ => 1f, 
		};
	}

	private float CalculateWeaponEffectiveness(ItemData weapon, DamageModifiers resourceModifiers)
	{
		//IL_000d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0012: Unknown result type (might be due to invalid IL or missing references)
		//IL_0013: 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_0025: Unknown result type (might be due to invalid IL or missing references)
		//IL_002c: Unknown result type (might be due to invalid IL or missing references)
		//IL_002d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0061: Unknown result type (might be due to invalid IL or missing references)
		//IL_004c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0053: Unknown result type (might be due to invalid IL or missing references)
		//IL_0054: Unknown result type (might be due to invalid IL or missing references)
		//IL_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_007c: 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_00b3: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Unknown result type (might be due to invalid IL or missing references)
		//IL_00a5: 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_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c7: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_00cf: Unknown result type (might be due to invalid IL or missing references)
		//IL_0105: Unknown result type (might be due to invalid IL or missing references)
		//IL_00f0: 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_00f8: Unknown result type (might be due to invalid IL or missing references)
		//IL_012e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0119: Unknown result type (might be due to invalid IL or missing references)
		//IL_0120: Unknown result type (might be due to invalid IL or missing references)
		//IL_0121: Unknown result type (might be due to invalid IL or missing references)
		//IL_0157: Unknown result type (might be due to invalid IL or missing references)
		//IL_0142: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_014a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0180: Unknown result type (might be due to invalid IL or missing references)
		//IL_016b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0194: Unknown result type (might be due to invalid IL or missing references)
		//IL_019b: Unknown result type (might be due to invalid IL or missing references)
		//IL_019c: Unknown result type (might be due to invalid IL or missing references)
		float num = 0f;
		DamageTypes damages = weapon.m_sh

plugins\ValheimAIModLoader.dll

Decompiled 2 weeks ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using HarmonyLib;
using Jotunn.Entities;
using Jotunn.Managers;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ValheimAIModLoader")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ValheimAIModLoader")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("d0f5469c-3db9-4874-86e8-35b484bf63d1")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace ValheimAIMod
{
	[BepInPlugin("egoai.thrallmodloader", "ego.ai Thrall Mod Loader", "1.0.0")]
	[BepInProcess("valheim.exe")]
	public class ValheimAIModLoader : BaseUnityPlugin
	{
		public class DespawnAllCommand : ConsoleCommand
		{
			public override string Name => "despawn_all";

			public override string Help => "Despawn all __INPUT_TEXT__ game objects";

			public override void Run(string[] args)
			{
				if (args.Length == 0)
				{
					instance.DespawnPrefabInstances("HumanoidNPC");
				}
				else
				{
					instance.DespawnPrefabInstances(args[0]);
				}
			}
		}

		[HarmonyPatch(typeof(ZNetScene), "Awake")]
		private static class ZNetScene_Awake_Patch
		{
			public static void Prefix(ZNetScene __instance)
			{
				if (!((Object)(object)__instance == (Object)null))
				{
				}
			}
		}

		private static ValheimAIModLoader instance;

		private readonly Harmony harmony = new Harmony("egoai.thrallmodloader");

		private static GameObject HumanoidNPCPrefab;

		private void Awake()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_003e: Expected O, but got Unknown
			instance = this;
			RegisterConsoleCommands();
			AssetBundle assetBundleFromResources = GetAssetBundleFromResources("scriptnpc");
			HumanoidNPCPrefab = assetBundleFromResources.LoadAsset<GameObject>("Assets/CustomAssets/HumanoidNPC.prefab");
			PrefabManager.Instance.AddPrefab(new CustomPrefab(HumanoidNPCPrefab, true));
			if (Object.op_Implicit((Object)(object)HumanoidNPCPrefab))
			{
				Debug.Log((object)"HumanoidNPCPrefab loaded");
			}
			else
			{
				Debug.LogError((object)"HumanoidNPCPrefab not loaded");
			}
			assetBundleFromResources.Unload(false);
			harmony.PatchAll();
		}

		private void OnDestroy()
		{
			harmony.UnpatchSelf();
		}

		public static AssetBundle GetAssetBundleFromResources(string fileName)
		{
			Assembly executingAssembly = Assembly.GetExecutingAssembly();
			string name = executingAssembly.GetManifestResourceNames().Single((string str) => str.EndsWith(fileName));
			using Stream stream = executingAssembly.GetManifestResourceStream(name);
			return AssetBundle.LoadFromStream(stream);
		}

		private void RegisterConsoleCommands()
		{
			CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new DespawnAllCommand());
		}

		public void DespawnPrefabInstances(string prefabName)
		{
			List<GameObject> list = new List<GameObject>();
			ZNetView[] array = Object.FindObjectsOfType<ZNetView>();
			foreach (ZNetView val in array)
			{
				if (((Object)((Component)val).gameObject).name.Contains(prefabName))
				{
					list.Add(((Component)val).gameObject);
				}
			}
			foreach (GameObject item in list)
			{
				ZNetView component = item.GetComponent<ZNetView>();
				if ((Object)(object)component != (Object)null)
				{
					component.Destroy();
				}
			}
			Console.instance.Print($"Despawned {list.Count} instances of prefab '{prefabName}'");
		}
	}
}
namespace ValheimAIModLoader
{
	public class HumanoidNPC : Humanoid
	{
		[Header("HumanoidNPC")]
		public float m_staminaRegen = 5f;

		public float m_staminaRegenTimeMultiplier = 1f;

		public float m_staminaRegenDelay = 1f;

		public float m_runStaminaDrain = 10f;

		public float m_sneakStaminaDrain = 5f;

		public float m_swimStaminaDrainMinSkill = 5f;

		public float m_swimStaminaDrainMaxSkill = 2f;

		public float m_dodgeStaminaUsage = 10f;

		public float m_weightStaminaFactor = 0.1f;

		public float m_eiterRegen = 5f;

		public float m_eitrRegenDelay = 1f;

		public float m_autoPickupRange = 2f;

		public float m_maxCarryWeight = 300f;

		public float m_encumberedStaminaDrain = 10f;

		public float m_hardDeathCooldown = 10f;

		public float m_baseCameraShake = 4f;

		public float m_placeDelay = 0.4f;

		public float m_removeDelay = 0.25f;

		public float m_baseHP = 25f;

		public float m_baseStamina = 75f;

		private float m_timeSinceDeath = 999999f;

		private float m_nearFireTimer;

		private bool m_underRoof = true;

		private bool m_safeInHome;

		private float m_timeSinceSensed;

		private float m_coverPercentage;

		private int m_baseValue;

		private int m_baseValueOld = -1;

		public readonly List<Food> m_foods = new List<Food>();

		private float m_foodUpdateTimer;

		private float m_foodRegenTimer;

		public float m_stamina = 100f;

		public float m_maxStamina = 100f;

		public float m_staminaRegenTimer;

		public float m_staminaLastBreakTime = 0f;

		public float StaminaExhaustedMinimumBreakTime = 2f;

		public float MinimumStaminaToRun = 5f;

		private float m_eitr;

		private float m_maxEitr;

		private float m_eitrRegenTimer;

		private static bool m_enableAutoPickup = true;

		private int m_autoPickupMask;

		public bool m_crouchToggled;

		private static readonly int s_crouching = ZSyncAnimation.GetHash("crouching");

		private static readonly int s_animatorTagCrouch = ZSyncAnimation.GetHash("crouch");

		public Vector3 LastPosition;

		public float LastMovedAtTime;

		public Vector3 patrol_position;

		public PinData npcPinData;

		public Container inventoryContainer;

		public override void CustomFixedUpdate(float fixedDeltaTime)
		{
			((Humanoid)this).CustomFixedUpdate(fixedDeltaTime);
			UpdateStats(fixedDeltaTime);
			UpdateCrouch(fixedDeltaTime);
			UpdateLastPosition();
			UpdatePin();
		}

		private void UpdateStats(float dt)
		{
			if ((Object)(object)this == (Object)null || ((Character)this).InIntro() || ((Character)this).IsTeleporting())
			{
				return;
			}
			m_timeSinceDeath += dt;
			bool flag = ((Character)this).IsEncumbered();
			float maxStamina = m_maxStamina;
			float num = 1f;
			if (((Character)this).IsBlocking())
			{
				num *= 0.8f;
			}
			if ((((Character)this).IsSwimming() && !((Character)this).IsOnGround()) || ((Character)this).InAttack() || ((Character)this).InDodge() || ((Character)this).m_wallRunning || flag)
			{
				num = 0f;
			}
			float num2 = (m_staminaRegen + (1f - m_stamina / maxStamina) * m_staminaRegen * m_staminaRegenTimeMultiplier) * num;
			float num3 = 1f;
			((Character)this).m_seman.ModifyStaminaRegen(ref num3);
			num2 *= num3;
			m_staminaRegenTimer -= dt;
			if (m_stamina < maxStamina && m_staminaRegenTimer <= 0f)
			{
				m_stamina = Mathf.Min(maxStamina, m_stamina + num2 * dt * Game.m_staminaRegenRate);
			}
			float maxEitr = ((Character)this).GetMaxEitr();
			float num4 = 1f;
			if (((Character)this).IsBlocking())
			{
				num4 *= 0.8f;
			}
			if (((Character)this).InAttack() || ((Character)this).InDodge())
			{
				num4 = 0f;
			}
			if (flag)
			{
				if (((Vector3)(ref ((Character)this).m_moveDir)).magnitude > 0.1f)
				{
				}
				((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectEncumbered, false, 0, 0f);
			}
			UpdateEnvStatusEffects(dt);
		}

		public void O_DoInteractAnimation(Vector3 target)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0008: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0012: Unknown result type (might be due to invalid IL or missing references)
			//IL_002d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Unknown result type (might be due to invalid IL or missing references)
			Vector3 val = target - ((Component)this).transform.position;
			val.y = 0f;
			((Vector3)(ref val)).Normalize();
			((Component)this).transform.rotation = Quaternion.LookRotation(val);
			Physics.SyncTransforms();
			((Character)this).m_zanim.SetTrigger("interact");
		}

		public override void UseStamina(float v, bool isHomeUsage = false)
		{
			if (v == 0f)
			{
				return;
			}
			v *= Game.m_staminaRate;
			if (isHomeUsage)
			{
				v *= 1f + ((Character)this).GetEquipmentHomeItemModifier();
				((Character)this).m_seman.ModifyHomeItemStaminaUsage(v, ref v, true);
			}
			if (((Character)this).m_nview.IsValid())
			{
				if (((Character)this).m_nview.IsOwner())
				{
					RPC_UseStamina(0L, v);
					return;
				}
				((Character)this).m_nview.InvokeRPC("UseStamina", new object[1] { v });
			}
		}

		private void RPC_UseStamina(long sender, float v)
		{
			if (v != 0f)
			{
				m_stamina -= v;
				if (m_stamina < 0f)
				{
					m_stamina = 0f;
				}
				m_staminaRegenTimer = m_staminaRegenDelay;
			}
		}

		public override bool HaveStamina(float amount = 0f)
		{
			if (((Character)this).m_nview.IsValid() && !((Character)this).m_nview.IsOwner())
			{
				return ((Character)this).m_nview.GetZDO().GetFloat(ZDOVars.s_stamina, m_maxStamina) > amount;
			}
			return m_stamina > amount;
		}

		public bool InShelter()
		{
			if (m_coverPercentage >= 0.8f)
			{
				return m_underRoof;
			}
			return false;
		}

		public bool IsSensed()
		{
			return m_timeSinceSensed < 1f;
		}

		private void UpdateEnvStatusEffects(float dt)
		{
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_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_0085: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Invalid comparison between Unknown and I4
			//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e9: Invalid comparison between Unknown and I4
			m_nearFireTimer += dt;
			DamageModifiers damageModifiers = ((Character)this).GetDamageModifiers((WeakSpot)null);
			bool flag = m_nearFireTimer < 0.25f;
			bool flag2 = ((Character)this).m_seman.HaveStatusEffect(SEMan.s_statusEffectBurning);
			bool flag3 = InShelter();
			DamageModifier modifier = ((DamageModifiers)(ref damageModifiers)).GetModifier((DamageType)64);
			bool flag4 = EnvMan.IsFreezing();
			bool flag5 = EnvMan.IsCold();
			bool flag6 = EnvMan.IsWet();
			bool flag7 = IsSensed();
			bool flag8 = ((Character)this).m_seman.HaveStatusEffect(SEMan.s_statusEffectWet);
			bool flag9 = ((Character)this).IsSitting();
			bool flag10 = Object.op_Implicit((Object)(object)EffectArea.IsPointInsideArea(((Component)this).transform.position, (Type)64, 1f));
			bool flag11 = ShieldGenerator.IsInsideShield(((Component)this).transform.position);
			bool flag12 = flag4 && !flag && !flag3;
			bool flag13 = (flag5 && !flag) || (flag4 && flag && !flag3) || (flag4 && !flag && flag3);
			if ((int)modifier == 1 || (int)modifier == 5 || flag10)
			{
				flag12 = false;
				flag13 = false;
			}
			if (flag6 && !m_underRoof && !flag11)
			{
				((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectWet, true, 0, 0f);
			}
			if (flag3)
			{
				((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectShelter, false, 0, 0f);
			}
			else
			{
				((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectShelter, false);
			}
			if (flag)
			{
				((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectCampFire, false, 0, 0f);
			}
			else
			{
				((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectCampFire, false);
			}
			bool flag14 = !flag7 && (flag9 || flag3) && !flag13 && !flag12 && (!flag8 || flag10) && !flag2 && flag;
			if (flag14)
			{
				((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectResting, false, 0, 0f);
			}
			else
			{
				((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectResting, false);
			}
			m_safeInHome = flag14 && flag3;
			if (flag12)
			{
				if (!((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectCold, true))
				{
					((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectFreezing, false, 0, 0f);
				}
			}
			else if (flag13)
			{
				if (!((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectFreezing, true) && !Object.op_Implicit((Object)(object)((Character)this).m_seman.AddStatusEffect(SEMan.s_statusEffectCold, false, 0, 0f)))
				{
				}
			}
			else
			{
				((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectCold, false);
				((Character)this).m_seman.RemoveStatusEffect(SEMan.s_statusEffectFreezing, false);
			}
		}

		public void UpdatePin()
		{
			//IL_002b: Unknown result type (might be due to invalid IL or missing references)
			if (npcPinData != null)
			{
				Minimap.instance.RemovePin(npcPinData);
			}
			npcPinData = Minimap.instance.AddPin(((Component)this).transform.position, (PinType)10, ((Character)this).m_name, false, false, 9990L, "NPC");
		}

		public void UpdateLastPosition()
		{
			//IL_0007: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			if (VectorExtensions.DistanceTo(((Component)this).transform.position, LastPosition) > 0.15f)
			{
				LastPosition = ((Component)this).transform.position;
				LastMovedAtTime = Time.time;
			}
		}

		public override void Awake()
		{
			((Humanoid)this).Awake();
			m_autoPickupMask = LayerMask.GetMask(new string[1] { "item" });
			((Character)this).m_nview = ((Component)this).GetComponent<ZNetView>();
			if ((Object)(object)((Character)this).m_nview == (Object)null)
			{
				Debug.LogError((object)"PersistentNPC: Missing ZNetView component");
				return;
			}
			Debug.Log((object)$"m_autoPickupMask: {m_autoPickupMask}");
			((Character)this).m_nview.m_persistent = true;
		}

		public bool HasEnoughResource(string resourceName, int requiredAmount)
		{
			Inventory inventory = ((Humanoid)this).GetInventory();
			if (inventory == null)
			{
				Debug.LogError((object)"Player inventory not found!");
				return false;
			}
			List<ItemData> source = (from item in inventory.GetAllItems()
				where ((Object)item.m_dropPrefab).name.ToLower() == resourceName.ToLower()
				select item).ToList();
			int num = source.Sum((ItemData item) => item.m_stack);
			return num >= requiredAmount;
		}

		public override bool IsCrouching()
		{
			return m_crouchToggled;
		}

		private void UpdateCrouch(float dt)
		{
			if (m_crouchToggled)
			{
				if (!((Character)this).HaveStamina(0f) || ((Character)this).IsSwimming() || ((Character)this).InBed() || ((Character)this).InPlaceMode() || ((Character)this).m_run || ((Character)this).IsBlocking() || ((Character)this).IsFlying())
				{
					((Character)this).SetCrouch(false);
				}
				bool flag = ((Character)this).InAttack() || ((Character)this).IsDrawingBow();
				((Character)this).m_zanim.SetBool(s_crouching, m_crouchToggled && !flag);
			}
			else
			{
				((Character)this).m_zanim.SetBool(s_crouching, false);
			}
		}

		public override void SetCrouch(bool crouch)
		{
			m_crouchToggled = crouch;
		}

		public override bool IsEncumbered()
		{
			return false;
		}

		public float GetMaxCarryWeight()
		{
			float maxCarryWeight = m_maxCarryWeight;
			((Character)this).m_seman.ModifyMaxCarryWeight(maxCarryWeight, ref maxCarryWeight);
			return maxCarryWeight;
		}

		public override bool CheckRun(Vector3 moveDir, float dt)
		{
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			if (!((Humanoid)this).CheckRun(moveDir, dt))
			{
				return false;
			}
			bool flag = ((Character)this).HaveStamina(0f);
			float num = 1f;
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				num = Player.m_localPlayer.m_skills.GetSkillFactor((SkillType)102);
			}
			float num2 = Mathf.Lerp(1f, 0.5f, num);
			float num3 = m_runStaminaDrain * num2;
			if (Object.op_Implicit((Object)(object)Player.m_localPlayer))
			{
				num3 -= num3 * ((Character)Player.m_localPlayer).GetEquipmentMovementModifier();
				num3 += num3 * ((Character)Player.m_localPlayer).GetEquipmentRunStaminaModifier();
			}
			if (m_stamina > MinimumStaminaToRun)
			{
				m_stamina -= dt * num3 * Game.m_moveStaminaRate;
				return true;
			}
			return false;
		}

		public override void SetupVisEquipment(VisEquipment visEq, bool isRagdoll)
		{
			if (!isRagdoll)
			{
				visEq.SetLeftItem((base.m_leftItem != null) ? ((Object)base.m_leftItem.m_dropPrefab).name : "", (base.m_leftItem != null) ? base.m_leftItem.m_variant : 0);
				visEq.SetRightItem((base.m_rightItem != null) ? ((Object)base.m_rightItem.m_dropPrefab).name : "");
				visEq.SetLeftBackItem((base.m_hiddenLeftItem != null) ? ((Object)base.m_hiddenLeftItem.m_dropPrefab).name : "", (base.m_hiddenLeftItem != null) ? base.m_hiddenLeftItem.m_variant : 0);
				visEq.SetRightBackItem((base.m_hiddenRightItem != null) ? ((Object)base.m_hiddenRightItem.m_dropPrefab).name : "");
			}
			visEq.SetChestItem((base.m_chestItem != null) ? ((Object)base.m_chestItem.m_dropPrefab).name : "");
			visEq.SetLegItem((base.m_legItem != null) ? ((Object)base.m_legItem.m_dropPrefab).name : "");
			visEq.SetHelmetItem((base.m_helmetItem != null) ? ((Object)base.m_helmetItem.m_dropPrefab).name : "");
			visEq.SetShoulderItem((base.m_shoulderItem != null) ? ((Object)base.m_shoulderItem.m_dropPrefab).name : "", (base.m_shoulderItem != null) ? base.m_shoulderItem.m_variant : 0);
			visEq.SetUtilityItem((base.m_utilityItem != null) ? ((Object)base.m_utilityItem.m_dropPrefab).name : "");
			visEq.SetBeardItem(base.m_beardItem);
			visEq.SetHairItem(base.m_hairItem);
		}

		public override void ApplyArmorDamageMods(ref DamageModifiers mods)
		{
			if (base.m_chestItem != null)
			{
				((DamageModifiers)(ref mods)).Apply(base.m_chestItem.m_shared.m_damageModifiers);
			}
			if (base.m_legItem != null)
			{
				((DamageModifiers)(ref mods)).Apply(base.m_legItem.m_shared.m_damageModifiers);
			}
			if (base.m_helmetItem != null)
			{
				((DamageModifiers)(ref mods)).Apply(base.m_helmetItem.m_shared.m_damageModifiers);
			}
			if (base.m_shoulderItem != null)
			{
				((DamageModifiers)(ref mods)).Apply(base.m_shoulderItem.m_shared.m_damageModifiers);
			}
		}

		public override float GetBodyArmor()
		{
			float num = 0f;
			if (base.m_chestItem != null)
			{
				num += base.m_chestItem.GetArmor();
			}
			if (base.m_legItem != null)
			{
				num += base.m_legItem.GetArmor();
			}
			if (base.m_helmetItem != null)
			{
				num += base.m_helmetItem.GetArmor();
			}
			if (base.m_shoulderItem != null)
			{
				num += base.m_shoulderItem.GetArmor();
			}
			return num;
		}

		public override void DamageArmorDurability(HitData hit)
		{
			List<ItemData> list = new List<ItemData>();
			if (base.m_chestItem != null)
			{
				list.Add(base.m_chestItem);
			}
			if (base.m_legItem != null)
			{
				list.Add(base.m_legItem);
			}
			if (base.m_helmetItem != null)
			{
				list.Add(base.m_helmetItem);
			}
			if (base.m_shoulderItem != null)
			{
				list.Add(base.m_shoulderItem);
			}
			if (list.Count != 0)
			{
				float num = hit.GetTotalPhysicalDamage() + hit.GetTotalElementalDamage();
				if (!(num <= 0f))
				{
					int index = Random.Range(0, list.Count);
					ItemData val = list[index];
					val.m_durability = Mathf.Max(0f, val.m_durability - num);
				}
			}
		}
	}
	public class ThrallAI : BaseAI
	{
		public float m_lastDespawnInDayCheck = -9999f;

		public float m_lastEventCreatureCheck = -9999f;

		public Action<ItemDrop> m_onConsumedItem;

		public const float m_giveUpTime = 30f;

		public const float m_updateTargetFarRange = 50f;

		public const float m_updateTargetIntervalNear = 2f;

		public const float m_updateTargetIntervalFar = 6f;

		public const float m_updateWeaponInterval = 1f;

		public const float m_unableToAttackTargetDuration = 15f;

		[Header("Monster AI")]
		public float m_alertRange = 9999f;

		public bool m_fleeIfHurtWhenTargetCantBeReached = true;

		public float m_fleeUnreachableSinceAttacking = 30f;

		public float m_fleeUnreachableSinceHurt = 20f;

		public bool m_fleeIfNotAlerted;

		public float m_fleeIfLowHealth;

		public float m_fleeTimeSinceHurt = 20f;

		public bool m_fleeInLava = true;

		public bool m_circulateWhileCharging;

		public bool m_circulateWhileChargingFlying;

		public bool m_enableHuntPlayer;

		public bool m_attackPlayerObjects = true;

		public int m_publicAreaTriggerTreshold = 4;

		public float m_interceptTimeMax;

		public float m_interceptTimeMin;

		public float m_maxChaseDistance;

		public float m_minAttackInterval;

		[Header("Circle target")]
		public float m_circleTargetInterval;

		public float m_circleTargetDuration = 5f;

		public float m_circleTargetDistance = 10f;

		[Header("Sleep")]
		public bool m_sleeping;

		public float m_wakeupRange = 5f;

		public bool m_noiseWakeup;

		public float m_maxNoiseWakeupRange = 50f;

		public EffectList m_wakeupEffects = new EffectList();

		public float m_wakeUpDelayMin;

		public float m_wakeUpDelayMax;

		[Header("Other")]
		public bool m_avoidLand;

		[Header("Consume items")]
		public List<ItemDrop> m_consumeItems;

		public float m_consumeRange = 2f;

		public float m_consumeSearchRange = 5f;

		public float m_consumeSearchInterval = 10f;

		public ItemDrop m_consumeTarget;

		public float m_consumeSearchTimer;

		public static int m_itemMask = 0;

		public bool m_despawnInDay;

		public bool m_eventCreature;

		public Character m_targetCreature;

		public Vector3 m_lastKnownTargetPos = Vector3.zero;

		public bool m_beenAtLastPos;

		public StaticTarget m_targetStatic;

		public float m_timeSinceAttacking;

		public float m_timeSinceSensedTargetCreature;

		public float m_updateTargetTimer;

		public float m_updateWeaponTimer;

		public float m_interceptTime;

		public float m_sleepDelay = 0.5f;

		public float m_pauseTimer;

		public float m_sleepTimer;

		public float m_unableToAttackTargetTimer;

		public GameObject m_follow;

		public int m_publicAreaAttacks;

		public static readonly int s_sleeping = ZSyncAnimation.GetHash("sleeping");

		public override void Awake()
		{
			((BaseAI)this).Awake();
			m_despawnInDay = base.m_nview.GetZDO().GetBool(ZDOVars.s_despawnInDay, m_despawnInDay);
			m_eventCreature = base.m_nview.GetZDO().GetBool(ZDOVars.s_eventCreature, m_eventCreature);
			m_sleeping = base.m_nview.GetZDO().GetBool(ZDOVars.s_sleeping, m_sleeping);
			base.m_animator.SetBool(s_sleeping, ((BaseAI)this).IsSleeping());
			m_interceptTime = Random.Range(m_interceptTimeMin, m_interceptTimeMax);
			m_pauseTimer = Random.Range(0f, m_circleTargetInterval);
			m_updateTargetTimer = Random.Range(0f, 2f);
			if (m_wakeUpDelayMin > 0f || m_wakeUpDelayMax > 0f)
			{
				m_sleepDelay = Random.Range(m_wakeUpDelayMin, m_wakeUpDelayMax);
			}
			if (m_enableHuntPlayer)
			{
				((BaseAI)this).SetHuntPlayer(true);
			}
			base.m_nview.Register("RPC_Wakeup", (Action<long>)RPC_Wakeup);
		}

		public void Start()
		{
			if (Object.op_Implicit((Object)(object)base.m_nview) && base.m_nview.IsValid() && base.m_nview.IsOwner())
			{
				Character character = base.m_character;
				Humanoid val = (Humanoid)(object)((character is Humanoid) ? character : null);
				if (Object.op_Implicit((Object)(object)val))
				{
					val.EquipBestWeapon((Character)null, (StaticTarget)null, (Character)null, (Character)null);
				}
			}
		}

		public override void OnDamaged(float damage, Character attacker)
		{
			((BaseAI)this).OnDamaged(damage, attacker);
			Wakeup();
			((BaseAI)this).SetAlerted(true);
			SetTarget(attacker);
		}

		public void SetTarget(Character attacker)
		{
			//IL_0047: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)attacker != (Object)null && (Object)(object)m_targetCreature == (Object)null && (!attacker.IsPlayer() || !base.m_character.IsTamed()))
			{
				m_targetCreature = attacker;
				m_lastKnownTargetPos = ((Component)attacker).transform.position;
				m_beenAtLastPos = false;
				m_targetStatic = null;
			}
		}

		public override void RPC_OnNearProjectileHit(long sender, Vector3 center, float range, ZDOID attackerID)
		{
			//IL_003e: Unknown result type (might be due to invalid IL or missing references)
			if (!base.m_nview.IsOwner() || ZoneSystem.instance.GetGlobalKey((GlobalKeys)24))
			{
				return;
			}
			((BaseAI)this).SetAlerted(true);
			if (m_fleeIfNotAlerted)
			{
				return;
			}
			GameObject val = ZNetScene.instance.FindInstance(attackerID);
			if ((Object)(object)val != (Object)null)
			{
				Character component = val.GetComponent<Character>();
				if (Object.op_Implicit((Object)(object)component))
				{
					SetTarget(component);
				}
			}
		}

		public void MakeTame()
		{
			base.m_character.SetTamed(true);
			((BaseAI)this).SetAlerted(false);
			m_targetCreature = null;
			m_targetStatic = null;
		}

		public void UpdateTarget(Humanoid humanoid, float dt, out bool canHearTarget, out bool canSeeTarget)
		{
			//IL_0049: Unknown result type (might be due to invalid IL or missing references)
			//IL_022e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0233: Unknown result type (might be due to invalid IL or missing references)
			//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_026c: Unknown result type (might be due to invalid IL or missing references)
			//IL_027c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0396: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
			//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0402: Unknown result type (might be due to invalid IL or missing references)
			//IL_0186: Unknown result type (might be due to invalid IL or missing references)
			//IL_018b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_0193: Unknown result type (might be due to invalid IL or missing references)
			m_unableToAttackTargetTimer -= dt;
			m_updateTargetTimer -= dt;
			if (m_updateTargetTimer <= 0f && !base.m_character.InAttack())
			{
				bool flag = Player.IsPlayerInRange(((Component)this).transform.position, 50f);
				m_updateTargetTimer = (flag ? 2f : 6f);
				Character val = ((BaseAI)this).FindEnemy();
				if (Object.op_Implicit((Object)(object)val))
				{
					m_targetCreature = val;
					m_targetStatic = null;
				}
				bool flag2 = (Object)(object)m_targetCreature != (Object)null && m_targetCreature.IsPlayer();
				bool flag3 = (Object)(object)m_targetCreature != (Object)null && m_unableToAttackTargetTimer > 0f && !((BaseAI)this).HavePath(((Component)m_targetCreature).transform.position);
				if (m_attackPlayerObjects && (!base.m_aggravatable || ((BaseAI)this).IsAggravated()) && !ZoneSystem.instance.GetGlobalKey((GlobalKeys)24) && ((Object)(object)m_targetCreature == (Object)null || flag3) && !base.m_character.IsTamed())
				{
					StaticTarget val2 = ((BaseAI)this).FindClosestStaticPriorityTarget();
					if (Object.op_Implicit((Object)(object)val2))
					{
						m_targetStatic = val2;
						m_targetCreature = null;
					}
					bool flag4 = false;
					if ((Object)(object)m_targetStatic != (Object)null)
					{
						Vector3 val3 = m_targetStatic.FindClosestPoint(((Component)base.m_character).transform.position);
						flag4 = ((BaseAI)this).HavePath(val3);
					}
					if (((Object)(object)m_targetStatic == (Object)null || !flag4) && ((BaseAI)this).IsAlerted() && flag2)
					{
						StaticTarget val4 = ((BaseAI)this).FindRandomStaticTarget(10f);
						if (Object.op_Implicit((Object)(object)val4))
						{
							m_targetStatic = val4;
							m_targetCreature = null;
						}
					}
				}
			}
			if (Object.op_Implicit((Object)(object)m_targetCreature) && base.m_character.IsTamed())
			{
				Vector3 val5 = default(Vector3);
				if (((BaseAI)this).GetPatrolPoint(ref val5))
				{
					if (Vector3.Distance(((Component)m_targetCreature).transform.position, val5) > m_alertRange)
					{
						m_targetCreature = null;
					}
				}
				else if (Object.op_Implicit((Object)(object)m_follow) && Vector3.Distance(((Component)m_targetCreature).transform.position, m_follow.transform.position) > m_alertRange)
				{
					m_targetCreature = null;
				}
			}
			if (Object.op_Implicit((Object)(object)m_targetCreature))
			{
				if (m_targetCreature.IsDead())
				{
					m_targetCreature = null;
				}
				else if (!((BaseAI)this).IsEnemy(m_targetCreature))
				{
					m_targetCreature = null;
				}
				else if (base.m_skipLavaTargets && m_targetCreature.AboveOrInLava())
				{
					m_targetCreature = null;
				}
			}
			canHearTarget = false;
			canSeeTarget = false;
			if (Object.op_Implicit((Object)(object)m_targetCreature))
			{
				canHearTarget = ((BaseAI)this).CanHearTarget(m_targetCreature);
				canSeeTarget = ((BaseAI)this).CanSeeTarget(m_targetCreature);
				if (canSeeTarget | canHearTarget)
				{
					m_timeSinceSensedTargetCreature = 0f;
				}
				if (m_targetCreature.IsPlayer())
				{
					m_targetCreature.OnTargeted(canSeeTarget | canHearTarget, ((BaseAI)this).IsAlerted());
				}
				((BaseAI)this).SetTargetInfo(m_targetCreature.GetZDOID());
			}
			else
			{
				((BaseAI)this).SetTargetInfo(ZDOID.None);
			}
			m_timeSinceSensedTargetCreature += dt;
			if (((BaseAI)this).IsAlerted() || (Object)(object)m_targetCreature != (Object)null)
			{
				m_timeSinceAttacking += dt;
				float num = 60f;
				float num2 = Vector3.Distance(base.m_spawnPoint, ((Component)this).transform.position);
				bool flag5 = ((BaseAI)this).HuntPlayer() && Object.op_Implicit((Object)(object)m_targetCreature) && m_targetCreature.IsPlayer();
				if (m_timeSinceSensedTargetCreature > 30f || (!flag5 && (m_timeSinceAttacking > num || (m_maxChaseDistance > 0f && m_timeSinceSensedTargetCreature > 1f && num2 > m_maxChaseDistance))))
				{
					((BaseAI)this).SetAlerted(false);
					m_targetCreature = null;
					m_targetStatic = null;
					m_timeSinceAttacking = 0f;
					m_updateTargetTimer = 5f;
				}
			}
		}

		public override bool UpdateAI(float dt)
		{
			//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
			//IL_0247: Unknown result type (might be due to invalid IL or missing references)
			//IL_02a2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_02b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_0391: Unknown result type (might be due to invalid IL or missing references)
			//IL_0351: Unknown result type (might be due to invalid IL or missing references)
			//IL_03b5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0374: Unknown result type (might be due to invalid IL or missing references)
			//IL_0411: Unknown result type (might be due to invalid IL or missing references)
			//IL_0423: Unknown result type (might be due to invalid IL or missing references)
			//IL_0428: Unknown result type (might be due to invalid IL or missing references)
			//IL_050c: Unknown result type (might be due to invalid IL or missing references)
			//IL_068a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0678: Unknown result type (might be due to invalid IL or missing references)
			//IL_068f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0693: Unknown result type (might be due to invalid IL or missing references)
			//IL_071b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0721: Invalid comparison between Unknown and I4
			//IL_0ab4: Unknown result type (might be due to invalid IL or missing references)
			//IL_0aba: Invalid comparison between Unknown and I4
			//IL_0ac2: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ac8: Invalid comparison between Unknown and I4
			//IL_074e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0753: Unknown result type (might be due to invalid IL or missing references)
			//IL_0758: Unknown result type (might be due to invalid IL or missing references)
			//IL_075a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0762: Unknown result type (might be due to invalid IL or missing references)
			//IL_0add: Unknown result type (might be due to invalid IL or missing references)
			//IL_0ae3: Invalid comparison between Unknown and I4
			//IL_082a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0799: Unknown result type (might be due to invalid IL or missing references)
			//IL_089b: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a0: Unknown result type (might be due to invalid IL or missing references)
			//IL_08a6: Unknown result type (might be due to invalid IL or missing references)
			//IL_08b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_07e5: Unknown result type (might be due to invalid IL or missing references)
			//IL_0bb9: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b19: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b24: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a82: Unknown result type (might be due to invalid IL or missing references)
			//IL_0a50: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b96: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b7c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0b5a: Unknown result type (might be due to invalid IL or missing references)
			//IL_093f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0944: Unknown result type (might be due to invalid IL or missing references)
			//IL_0946: Unknown result type (might be due to invalid IL or missing references)
			//IL_094e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0953: Unknown result type (might be due to invalid IL or missing references)
			//IL_0956: Unknown result type (might be due to invalid IL or missing references)
			//IL_095b: Unknown result type (might be due to invalid IL or missing references)
			//IL_098e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0975: Unknown result type (might be due to invalid IL or missing references)
			//IL_0977: Unknown result type (might be due to invalid IL or missing references)
			//IL_097f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0984: Unknown result type (might be due to invalid IL or missing references)
			//IL_0989: Unknown result type (might be due to invalid IL or missing references)
			//IL_09ea: Unknown result type (might be due to invalid IL or missing references)
			//IL_09fb: Unknown result type (might be due to invalid IL or missing references)
			if (!((BaseAI)this).UpdateAI(dt))
			{
				return false;
			}
			if (((BaseAI)this).IsSleeping())
			{
				UpdateSleep(dt);
				return true;
			}
			Character character = base.m_character;
			Humanoid humanoid = (Humanoid)(object)((character is Humanoid) ? character : null);
			if (((BaseAI)this).HuntPlayer())
			{
				((BaseAI)this).SetAlerted(true);
			}
			UpdateTarget(humanoid, dt, out var canHearTarget, out var canSeeTarget);
			if (Object.op_Implicit((Object)(object)base.m_tamable) && Object.op_Implicit((Object)(object)base.m_tamable.m_saddle) && base.m_tamable.m_saddle.UpdateRiding(dt))
			{
				return true;
			}
			if (m_avoidLand && !base.m_character.IsSwimming())
			{
				((BaseAI)this).MoveToWater(dt, 20f);
				return true;
			}
			if (DespawnInDay() && EnvMan.IsDay() && ((Object)(object)m_targetCreature == (Object)null || !canSeeTarget))
			{
				((BaseAI)this).MoveAwayAndDespawn(dt, true);
				return true;
			}
			if (IsEventCreature() && !RandEventSystem.HaveActiveEvent())
			{
				((BaseAI)this).SetHuntPlayer(false);
				if ((Object)(object)m_targetCreature == (Object)null && !((BaseAI)this).IsAlerted())
				{
					((BaseAI)this).MoveAwayAndDespawn(dt, false);
					return true;
				}
			}
			if (m_fleeIfNotAlerted && !((BaseAI)this).HuntPlayer() && Object.op_Implicit((Object)(object)m_targetCreature) && !((BaseAI)this).IsAlerted() && Vector3.Distance(((Component)m_targetCreature).transform.position, ((Component)this).transform.position) - m_targetCreature.GetRadius() > m_alertRange)
			{
				((BaseAI)this).Flee(dt, ((Component)m_targetCreature).transform.position);
				return true;
			}
			if (m_fleeIfLowHealth > 0f && base.m_timeSinceHurt < m_fleeTimeSinceHurt && (Object)(object)m_targetCreature != (Object)null && base.m_character.GetHealthPercentage() < m_fleeIfLowHealth)
			{
				((BaseAI)this).Flee(dt, ((Component)m_targetCreature).transform.position);
				return true;
			}
			if (m_fleeInLava && base.m_character.InLava() && ((Object)(object)m_targetCreature == (Object)null || m_targetCreature.AboveOrInLava()))
			{
				((BaseAI)this).Flee(dt, ((Component)base.m_character).transform.position - ((Component)base.m_character).transform.forward);
				return true;
			}
			if ((base.m_afraidOfFire || base.m_avoidFire) && ((BaseAI)this).AvoidFire(dt, m_targetCreature, base.m_afraidOfFire))
			{
				if (base.m_afraidOfFire)
				{
					m_targetStatic = null;
					m_targetCreature = null;
				}
				return true;
			}
			if (!base.m_character.IsTamed())
			{
				if ((Object)(object)m_targetCreature != (Object)null)
				{
					if (Object.op_Implicit((Object)(object)EffectArea.IsPointInsideNoMonsterArea(((Component)m_targetCreature).transform.position)))
					{
						((BaseAI)this).Flee(dt, ((Component)m_targetCreature).transform.position);
						return true;
					}
				}
				else
				{
					EffectArea val = EffectArea.IsPointCloseToNoMonsterArea(((Component)this).transform.position);
					if ((Object)(object)val != (Object)null)
					{
						((BaseAI)this).Flee(dt, ((Component)val).transform.position);
						return true;
					}
				}
			}
			if (m_fleeIfHurtWhenTargetCantBeReached && (Object)(object)m_targetCreature != (Object)null && m_timeSinceAttacking > 30f && base.m_timeSinceHurt < 20f)
			{
				((BaseAI)this).Flee(dt, ((Component)m_targetCreature).transform.position);
				m_lastKnownTargetPos = ((Component)this).transform.position;
				m_updateTargetTimer = 1f;
				return true;
			}
			if ((!((BaseAI)this).IsAlerted() || ((Object)(object)m_targetStatic == (Object)null && (Object)(object)m_targetCreature == (Object)null)) && UpdateConsumeItem(humanoid, dt))
			{
				return true;
			}
			if (m_circleTargetInterval > 0f && Object.op_Implicit((Object)(object)m_targetCreature))
			{
				m_pauseTimer += dt;
				if (m_pauseTimer > m_circleTargetInterval)
				{
					if (m_pauseTimer > m_circleTargetInterval + m_circleTargetDuration)
					{
						m_pauseTimer = Random.Range(0f, m_circleTargetInterval / 10f);
					}
					((BaseAI)this).RandomMovementArroundPoint(dt, ((Component)m_targetCreature).transform.position, m_circleTargetDistance, ((BaseAI)this).IsAlerted());
					return true;
				}
			}
			ItemData val2 = SelectBestAttack(humanoid, dt);
			bool flag = val2 != null && Time.time - val2.m_lastAttackTime > val2.m_shared.m_aiAttackInterval && base.m_character.GetTimeSinceLastAttack() >= m_minAttackInterval && !((BaseAI)this).IsTakingOff();
			if (!((BaseAI)this).IsCharging() && ((Object)(object)m_targetStatic != (Object)null || (Object)(object)m_targetCreature != (Object)null) && val2 != null && flag && !base.m_character.InAttack() && val2.m_shared.m_attack != null && !val2.m_shared.m_attack.IsDone() && !string.IsNullOrEmpty(val2.m_shared.m_attack.m_chargeAnimationBool))
			{
				((BaseAI)this).ChargeStart(val2.m_shared.m_attack.m_chargeAnimationBool);
			}
			if ((base.m_character.IsFlying() ? m_circulateWhileChargingFlying : m_circulateWhileCharging) && ((Object)(object)m_targetStatic != (Object)null || (Object)(object)m_targetCreature != (Object)null) && val2 != null && !flag && !base.m_character.InAttack())
			{
				Vector3 val3 = (Object.op_Implicit((Object)(object)m_targetCreature) ? ((Component)m_targetCreature).transform.position : ((Component)m_targetStatic).transform.position);
				((BaseAI)this).RandomMovementArroundPoint(dt, val3, base.m_randomMoveRange, ((BaseAI)this).IsAlerted());
				return true;
			}
			if (((Object)(object)m_targetStatic == (Object)null && (Object)(object)m_targetCreature == (Object)null) || val2 == null)
			{
				if (Object.op_Implicit((Object)(object)m_follow))
				{
					((BaseAI)this).Follow(m_follow, dt);
				}
				else
				{
					((BaseAI)this).IdleMovement(dt);
				}
				((BaseAI)this).ChargeStop();
				return true;
			}
			if ((int)val2.m_shared.m_aiTargetType == 0)
			{
				if (Object.op_Implicit((Object)(object)m_targetStatic))
				{
					Vector3 val4 = m_targetStatic.FindClosestPoint(((Component)this).transform.position);
					if (Vector3.Distance(val4, ((Component)this).transform.position) < val2.m_shared.m_aiAttackRange && ((BaseAI)this).CanSeeTarget(m_targetStatic))
					{
						((BaseAI)this).LookAt(m_targetStatic.GetCenter());
						if (val2.m_shared.m_aiAttackMaxAngle == 0f)
						{
							ZLog.LogError((object)("AI Attack Max Angle for " + val2.m_shared.m_name + " is 0!"));
						}
						if (((BaseAI)this).IsLookingAt(m_targetStatic.GetCenter(), val2.m_shared.m_aiAttackMaxAngle, val2.m_shared.m_aiInvertAngleCheck) && flag)
						{
							DoAttack(null, isFriend: false);
						}
						else
						{
							((BaseAI)this).StopMoving();
						}
					}
					else
					{
						((BaseAI)this).MoveTo(dt, val4, 0f, ((BaseAI)this).IsAlerted());
						((BaseAI)this).ChargeStop();
					}
				}
				else if (Object.op_Implicit((Object)(object)m_targetCreature))
				{
					if (canHearTarget || canSeeTarget || (((BaseAI)this).HuntPlayer() && m_targetCreature.IsPlayer()))
					{
						m_beenAtLastPos = false;
						m_lastKnownTargetPos = ((Component)m_targetCreature).transform.position;
						float num = Vector3.Distance(m_lastKnownTargetPos, ((Component)this).transform.position) - m_targetCreature.GetRadius();
						float num2 = m_alertRange * m_targetCreature.GetStealthFactor();
						if (canSeeTarget && num < num2)
						{
							((BaseAI)this).SetAlerted(true);
						}
						bool flag2 = num < val2.m_shared.m_aiAttackRange;
						if (!flag2 || !canSeeTarget || val2.m_shared.m_aiAttackRangeMin < 0f || !((BaseAI)this).IsAlerted())
						{
							Vector3 velocity = m_targetCreature.GetVelocity();
							Vector3 val5 = velocity * m_interceptTime;
							Vector3 val6 = m_lastKnownTargetPos;
							if (num > ((Vector3)(ref val5)).magnitude / 4f)
							{
								val6 += velocity * m_interceptTime;
							}
							((BaseAI)this).MoveTo(dt, val6, 0f, ((BaseAI)this).IsAlerted());
							if (m_timeSinceAttacking > 15f)
							{
								m_unableToAttackTargetTimer = 15f;
							}
						}
						else
						{
							((BaseAI)this).StopMoving();
						}
						if (flag2 && canSeeTarget && ((BaseAI)this).IsAlerted())
						{
							((BaseAI)this).LookAt(m_targetCreature.GetTopPoint());
							if (flag && ((BaseAI)this).IsLookingAt(m_lastKnownTargetPos, val2.m_shared.m_aiAttackMaxAngle, val2.m_shared.m_aiInvertAngleCheck))
							{
								DoAttack(m_targetCreature, isFriend: false);
							}
						}
					}
					else
					{
						((BaseAI)this).ChargeStop();
						if (m_beenAtLastPos)
						{
							((BaseAI)this).RandomMovement(dt, m_lastKnownTargetPos, false);
							if (m_timeSinceAttacking > 15f)
							{
								m_unableToAttackTargetTimer = 15f;
							}
						}
						else if (((BaseAI)this).MoveTo(dt, m_lastKnownTargetPos, 0f, ((BaseAI)this).IsAlerted()))
						{
							m_beenAtLastPos = true;
						}
					}
				}
			}
			else if ((int)val2.m_shared.m_aiTargetType == 1 || (int)val2.m_shared.m_aiTargetType == 2)
			{
				Character val7 = (((int)val2.m_shared.m_aiTargetType == 1) ? ((BaseAI)this).HaveHurtFriendInRange(base.m_viewRange) : ((BaseAI)this).HaveFriendInRange(base.m_viewRange));
				if (Object.op_Implicit((Object)(object)val7))
				{
					if (Vector3.Distance(((Component)val7).transform.position, ((Component)this).transform.position) < val2.m_shared.m_aiAttackRange)
					{
						if (flag)
						{
							((BaseAI)this).StopMoving();
							((BaseAI)this).LookAt(((Component)val7).transform.position);
							DoAttack(val7, isFriend: true);
						}
						else
						{
							((BaseAI)this).RandomMovement(dt, ((Component)val7).transform.position, false);
						}
					}
					else
					{
						((BaseAI)this).MoveTo(dt, ((Component)val7).transform.position, 0f, ((BaseAI)this).IsAlerted());
					}
				}
				else
				{
					((BaseAI)this).RandomMovement(dt, ((Component)this).transform.position, true);
				}
			}
			return true;
		}

		public bool UpdateConsumeItem(Humanoid humanoid, float dt)
		{
			//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ef: Unknown result type (might be due to invalid IL or missing references)
			//IL_0145: Unknown result type (might be due to invalid IL or missing references)
			//IL_014a: Unknown result type (might be due to invalid IL or missing references)
			if (m_consumeItems == null || m_consumeItems.Count == 0)
			{
				return false;
			}
			m_consumeSearchTimer += dt;
			if (m_consumeSearchTimer > m_consumeSearchInterval)
			{
				m_consumeSearchTimer = 0f;
				if (Object.op_Implicit((Object)(object)base.m_tamable) && !base.m_tamable.IsHungry())
				{
					return false;
				}
				m_consumeTarget = FindClosestConsumableItem(m_consumeSearchRange);
			}
			if (Object.op_Implicit((Object)(object)m_consumeTarget))
			{
				if (((BaseAI)this).MoveTo(dt, ((Component)m_consumeTarget).transform.position, m_consumeRange, false))
				{
					((BaseAI)this).LookAt(((Component)m_consumeTarget).transform.position);
					if (((BaseAI)this).IsLookingAt(((Component)m_consumeTarget).transform.position, 20f, false) && m_consumeTarget.RemoveOne())
					{
						if (m_onConsumedItem != null)
						{
							m_onConsumedItem(m_consumeTarget);
						}
						humanoid.m_consumeItemEffects.Create(((Component)this).transform.position, Quaternion.identity, (Transform)null, 1f, -1);
						base.m_animator.SetTrigger("consume");
						m_consumeTarget = null;
					}
				}
				return true;
			}
			return false;
		}

		public ItemDrop FindClosestConsumableItem(float maxRange)
		{
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0112: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ba: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			if (m_itemMask == 0)
			{
				m_itemMask = LayerMask.GetMask(new string[1] { "item" });
			}
			Collider[] array = Physics.OverlapSphere(((Component)this).transform.position, maxRange, m_itemMask);
			ItemDrop val = null;
			float num = 999999f;
			Collider[] array2 = array;
			Collider[] array3 = array2;
			foreach (Collider val2 in array3)
			{
				if (!Object.op_Implicit((Object)(object)val2.attachedRigidbody))
				{
					continue;
				}
				ItemDrop component = ((Component)val2.attachedRigidbody).GetComponent<ItemDrop>();
				if (!((Object)(object)component == (Object)null) && ((Component)component).GetComponent<ZNetView>().IsValid() && CanConsume(component.m_itemData))
				{
					float num2 = Vector3.Distance(((Component)component).transform.position, ((Component)this).transform.position);
					if ((Object)(object)val == (Object)null || num2 < num)
					{
						val = component;
						num = num2;
					}
				}
			}
			if (Object.op_Implicit((Object)(object)val) && ((BaseAI)this).HavePath(((Component)val).transform.position))
			{
				return val;
			}
			return null;
		}

		public bool CanConsume(ItemData item)
		{
			foreach (ItemDrop consumeItem in m_consumeItems)
			{
				if (consumeItem.m_itemData.m_shared.m_name == item.m_shared.m_name)
				{
					return true;
				}
			}
			return false;
		}

		public ItemData SelectBestAttack(Humanoid humanoid, float dt)
		{
			if (Object.op_Implicit((Object)(object)m_targetCreature) || Object.op_Implicit((Object)(object)m_targetStatic))
			{
				m_updateWeaponTimer -= dt;
				if (m_updateWeaponTimer <= 0f && !base.m_character.InAttack())
				{
					m_updateWeaponTimer = 1f;
					Character val = default(Character);
					Character val2 = default(Character);
					((BaseAI)this).HaveFriendsInRange(base.m_viewRange, ref val, ref val2);
					humanoid.EquipBestWeapon(m_targetCreature, m_targetStatic, val, val2);
				}
			}
			return humanoid.GetCurrentWeapon();
		}

		public bool DoAttack(Character target, bool isFriend)
		{
			Character character = base.m_character;
			ItemData currentWeapon = ((Humanoid)((character is Humanoid) ? character : null)).GetCurrentWeapon();
			if (currentWeapon == null)
			{
				return false;
			}
			if (!((BaseAI)this).CanUseAttack(currentWeapon))
			{
				return false;
			}
			bool flag = base.m_character.StartAttack(target, false);
			if (flag)
			{
				m_timeSinceAttacking = 0f;
			}
			return flag;
		}

		public void SetDespawnInDay(bool despawn)
		{
			m_despawnInDay = despawn;
			base.m_nview.GetZDO().Set(ZDOVars.s_despawnInDay, despawn);
		}

		public bool DespawnInDay()
		{
			if (Time.time - m_lastDespawnInDayCheck > 4f)
			{
				m_lastDespawnInDayCheck = Time.time;
				m_despawnInDay = base.m_nview.GetZDO().GetBool(ZDOVars.s_despawnInDay, m_despawnInDay);
			}
			return m_despawnInDay;
		}

		public void SetEventCreature(bool despawn)
		{
			m_eventCreature = despawn;
			base.m_nview.GetZDO().Set(ZDOVars.s_eventCreature, despawn);
		}

		public bool IsEventCreature()
		{
			if (Time.time - m_lastEventCreatureCheck > 4f)
			{
				m_lastEventCreatureCheck = Time.time;
				m_eventCreature = base.m_nview.GetZDO().GetBool(ZDOVars.s_eventCreature, m_eventCreature);
			}
			return m_eventCreature;
		}

		public override void OnDrawGizmosSelected()
		{
			((BaseAI)this).OnDrawGizmosSelected();
			DrawAILabel();
		}

		public void OnDrawGizmos()
		{
			if (Terminal.m_showTests)
			{
				DrawAILabel();
			}
		}

		public void DrawAILabel()
		{
		}

		public override Character GetTargetCreature()
		{
			return m_targetCreature;
		}

		public StaticTarget GetStaticTarget()
		{
			return m_targetStatic;
		}

		public void UpdateSleep(float dt)
		{
			//IL_0069: Unknown result type (might be due to invalid IL or missing references)
			//IL_00be: Unknown result type (might be due to invalid IL or missing references)
			if (!((BaseAI)this).IsSleeping())
			{
				return;
			}
			m_sleepTimer += dt;
			if (m_sleepTimer < m_sleepDelay)
			{
				return;
			}
			if (((BaseAI)this).HuntPlayer())
			{
				Wakeup();
				return;
			}
			if (m_wakeupRange > 0f)
			{
				Player closestPlayer = Player.GetClosestPlayer(((Component)this).transform.position, m_wakeupRange);
				if (Object.op_Implicit((Object)(object)closestPlayer) && !((Character)closestPlayer).InGhostMode() && !((Character)closestPlayer).IsDebugFlying())
				{
					Wakeup();
					return;
				}
			}
			if (m_noiseWakeup)
			{
				Player playerNoiseRange = Player.GetPlayerNoiseRange(((Component)this).transform.position, m_maxNoiseWakeupRange);
				if (Object.op_Implicit((Object)(object)playerNoiseRange) && !((Character)playerNoiseRange).InGhostMode() && !((Character)playerNoiseRange).IsDebugFlying())
				{
					Wakeup();
				}
			}
		}

		public void OnpublicAreaAttacked(Character attacker, bool destroyed)
		{
			if (attacker.IsPlayer() && ((BaseAI)this).IsAggravatable() && !((BaseAI)this).IsAggravated())
			{
				m_publicAreaAttacks++;
				if (m_publicAreaAttacks > m_publicAreaTriggerTreshold || destroyed)
				{
					((BaseAI)this).SetAggravated(true, (AggravatedReason)0);
				}
			}
		}

		public void RPC_Wakeup(long sender)
		{
			if (!base.m_nview.GetZDO().IsOwner())
			{
				m_sleeping = false;
			}
		}

		public void Wakeup()
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_004c: Unknown result type (might be due to invalid IL or missing references)
			if (((BaseAI)this).IsSleeping())
			{
				base.m_animator.SetBool(s_sleeping, false);
				base.m_nview.GetZDO().Set(ZDOVars.s_sleeping, false);
				m_wakeupEffects.Create(((Component)this).transform.position, ((Component)this).transform.rotation, (Transform)null, 1f, -1);
				m_sleeping = false;
				base.m_nview.InvokeRPC(ZNetView.Everybody, "RPC_Wakeup", Array.Empty<object>());
			}
		}

		public override bool IsSleeping()
		{
			return m_sleeping;
		}

		public override void SetAlerted(bool alert)
		{
			if (alert)
			{
				m_timeSinceSensedTargetCreature = 0f;
			}
			((BaseAI)this).SetAlerted(alert);
		}

		public override bool HuntPlayer()
		{
			if (((BaseAI)this).HuntPlayer())
			{
				if (IsEventCreature() && !RandEventSystem.InEvent())
				{
					return false;
				}
				if (DespawnInDay() && EnvMan.IsDay())
				{
					return false;
				}
				return true;
			}
			return false;
		}

		public GameObject GetFollowTarget()
		{
			return m_follow;
		}

		public void SetFollowTarget(GameObject go)
		{
			m_follow = go;
		}
	}
}