Decompiled source of EmployeeManager v1.5.4

EmployeeManager.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Employees;
using Il2CppScheduleOne.Messaging;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.ObjectScripts;
using Il2CppScheduleOne.Property;
using Il2CppScheduleOne.Storage;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Phone.ContactsApp;
using Il2CppScheduleOne.UI.Phone.Messages;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using Newtonsoft.Json;
using SharedModUtils;
using TestBot;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Mod), "Employee Manager", "1.5.4", "Akermi", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("EmployeeManager")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+288f51365ff6c248a4c8d2c77ae4305de84aec86")]
[assembly: AssemblyProduct("EmployeeManager")]
[assembly: AssemblyTitle("EmployeeManager")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
public static class BotManagerStaticUtils
{
	public static Transform[] GetIdleTransformsForProperty(string propertyName, int count)
	{
		//IL_0097: Unknown result type (might be due to invalid IL or missing references)
		//IL_009e: Expected O, but got Unknown
		//IL_00aa: Unknown result type (might be due to invalid IL or missing references)
		Transform[] array = (Transform[])(object)new Transform[count];
		if (propertyName.Contains("Barn"))
		{
			float num = 176.6752f;
			float num2 = -18f;
			float num3 = 0.5f;
			float num4 = 1.2f;
			int num5 = 5;
			for (int i = 0; i < count; i++)
			{
				int num6 = i / num5;
				int num7 = i % num5;
				float num8 = num + (float)num7 * num4;
				float num9 = num2 + (float)num6 * num4;
				GameObject val = new GameObject($"IdlePoint_{i}_{propertyName}");
				val.transform.position = new Vector3(num8, num3, num9);
				array[i] = val.transform;
			}
		}
		return array;
	}
}
public static class EmployeeConfigManager
{
	public static Dictionary<string, int> PropertyCapacities = new Dictionary<string, int>();

	private static readonly string ConfigPath = Path.Combine(MelonEnvironment.UserDataDirectory, "Mods", "Configs", "employee_config.json");

	private static string NormalizeName(string name)
	{
		return name?.Replace(" ", "").Trim().ToLowerInvariant();
	}

	public static void LoadConfig()
	{
		try
		{
			if (!File.Exists(ConfigPath))
			{
				Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath));
				MelonLogger.Msg("[EmployeeManager] No config found. Starting fresh. " + ConfigPath);
				return;
			}
			Dictionary<string, int> obj = JsonConvert.DeserializeObject<Dictionary<string, int>>(File.ReadAllText(ConfigPath)) ?? new Dictionary<string, int>();
			PropertyCapacities = new Dictionary<string, int>();
			foreach (KeyValuePair<string, int> item in obj)
			{
				string key = NormalizeName(item.Key);
				if (!PropertyCapacities.ContainsKey(key))
				{
					PropertyCapacities[key] = item.Value;
				}
			}
			MelonLogger.Msg($"[EmployeeManager] Loaded {PropertyCapacities.Count} capacities.");
		}
		catch (Exception ex)
		{
			MelonLogger.Msg("[EmployeeManager] Failed to load config: " + ex.Message);
			PropertyCapacities = new Dictionary<string, int>();
		}
	}

	public static void SaveConfig()
	{
		try
		{
			Directory.CreateDirectory(Path.GetDirectoryName(ConfigPath));
			string contents = JsonConvert.SerializeObject((object)PropertyCapacities, (Formatting)1);
			File.WriteAllText(ConfigPath, contents);
			MelonLogger.Msg("[EmployeeManager] Config saved.");
		}
		catch (Exception ex)
		{
			MelonLogger.Error("[EmployeeManager] Failed to save config: " + ex.Message);
		}
	}

	public static int GetCapacity(string propertyName, int fallback = 10)
	{
		string key = NormalizeName(propertyName);
		if (!PropertyCapacities.TryGetValue(key, out var value))
		{
			return fallback;
		}
		return value;
	}

	public static void SetCapacity(string propertyName, int value)
	{
		string text = NormalizeName(propertyName);
		if (string.IsNullOrWhiteSpace(text))
		{
			MelonLogger.Msg("[EmployeeManager] Skipped saving capacity for unnamed property.");
			return;
		}
		PropertyCapacities[text] = value;
		MelonLogger.Msg($"[EmployeeManager] Saved capacity for {propertyName}: {value}");
	}

	public static bool HasCapacity(string propertyName)
	{
		string text = NormalizeName(propertyName);
		if (!string.IsNullOrWhiteSpace(text))
		{
			return PropertyCapacities.ContainsKey(text);
		}
		return false;
	}
}
namespace SharedModUtils
{
	public static class WageUtils
	{
		public static bool TryPayAllUnpaidEmployees(EmployeeManager employeeManager, out float totalCost, out string error)
		{
			totalCost = 0f;
			error = null;
			if ((Object)(object)employeeManager == (Object)null)
			{
				error = "Employee manager is not available.";
				return false;
			}
			for (int i = 0; i < employeeManager.AllEmployees._size; i++)
			{
				Employee val = employeeManager.AllEmployees[i];
				if (!val.PaidForToday)
				{
					totalCost += val.DailyWage;
				}
			}
			float cashBalance = NetworkSingleton<MoneyManager>.instance.cashBalance;
			if (totalCost > cashBalance)
			{
				error = $"Wages (${totalCost}) exceed bank balance (${cashBalance}).";
				return false;
			}
			for (int j = 0; j < employeeManager.AllEmployees._size; j++)
			{
				employeeManager.AllEmployees[j].PaidForToday = true;
			}
			NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - totalCost, true, false);
			return true;
		}

		public static float GetTotalUnpaidWages(EmployeeManager employeeMgr)
		{
			if ((Object)(object)employeeMgr == (Object)null || employeeMgr.AllEmployees == null)
			{
				return 0f;
			}
			float num = 0f;
			for (int i = 0; i < employeeMgr.AllEmployees._size; i++)
			{
				Employee val = employeeMgr.AllEmployees[i];
				if ((Object)(object)val != (Object)null && !val.PaidForToday)
				{
					num += val.DailyWage;
				}
			}
			return num;
		}

		public static float GetTotalUnpaidWagesForProperty(Property prop)
		{
			float num = 0f;
			Enumerator<Employee> enumerator = prop.Employees.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Employee current = enumerator.Current;
				if (!current.PaidForToday)
				{
					num += current.DailyWage;
				}
			}
			return num;
		}

		public static bool TryPayUnpaidEmployeesForProperty(Property prop, out float cost, out string error)
		{
			cost = GetTotalUnpaidWagesForProperty(prop);
			error = "";
			if (cost <= 0f)
			{
				return true;
			}
			if (NetworkSingleton<MoneyManager>.Instance.cashBalance < cost)
			{
				error = "Not enough cash.";
				return false;
			}
			NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - cost, true, false);
			Enumerator<Employee> enumerator = prop.Employees.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Employee current = enumerator.Current;
				if (!current.PaidForToday)
				{
					current.SetIsPaid();
				}
			}
			return true;
		}
	}
}
namespace Testbot
{
	public class Property
	{
		public static IntPtr NativeFieldInfoPtr_EmployeeCapacity;

		static Property()
		{
			NativeFieldInfoPtr_EmployeeCapacity = IL2CPP.GetIl2CppField(Il2CppClassPointerStore<Property>.NativeClassPtr, "EmployeeCapacity");
		}
	}
}
namespace TestBot
{
	public class BotManager
	{
		[CompilerGenerated]
		private sealed class <WaitForSystems>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForSystems>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(3f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private TestDialogue _dialogue;

		private GameObject _npcObject;

		private NPC _npc;

		private Mod _mod;

		private const int EmployeesPerPage = 6;

		[IteratorStateMachine(typeof(<WaitForSystems>d__3))]
		public static IEnumerator WaitForSystems()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForSystems>d__3(0);
		}

		public static BotManager Create(Mod mod)
		{
			BotManager botManager = new BotManager();
			botManager.Init();
			botManager._mod = mod;
			return botManager;
		}

		private void Init()
		{
			NPC val = null;
			List<NPC> nPCRegistry = NPCManager.NPCRegistry;
			for (int i = 0; i < nPCRegistry.Count; i++)
			{
				NPC val2 = nPCRegistry[i];
				if ((Object)(object)val2 != (Object)null && val2.FirstName == "Beth")
				{
					val = val2;
					break;
				}
			}
			if (!((Object)(object)val == (Object)null))
			{
				_npcObject = Object.Instantiate<GameObject>(((Component)val).gameObject);
				_npc = _npcObject.GetComponent<NPC>();
				_npc.FirstName = "Employee";
				_npc.LastName = "Manager";
				_npc.BakedGUID = Guid.NewGuid().ToString();
				_npc.IsImportant = true;
				_npc.ConversationCanBeHidden = false;
				_npc.ShowRelationshipInfo = false;
				_npc.MSGConversation = null;
				_npc.ConversationCategories = new List<EConversationCategory>();
				_npc.dialogueHandler = null;
				_npc.MugshotSprite = ((App<ContactsApp>)(object)PlayerSingleton<ContactsApp>.Instance).AppIcon;
				_npcObject.SetActive(true);
				((Component)_npc).gameObject.SetActive(true);
				_npc.Awake();
				((NetworkBehaviour)_npc).NetworkInitializeIfDisabled();
				NPCManager.NPCRegistry.Add(_npc);
				_npc.InitializeSaveable();
				_dialogue = new TestDialogue(_npc);
				Run();
			}
		}

		private void Run()
		{
			_dialogue.SendNPCMessage("Hello!");
			_dialogue.SendNPCMessage("I'm here to help you manage your employees");
			_dialogue.ShowResponses(new DialogueResponse[2]
			{
				new DialogueResponse("Manage properties", "Manage properties", ShowOwnedPropertiesMenu),
				new DialogueResponse("Pay employees", "Pay employees", ShowPayOptions)
			}, 0.5f);
		}

		private Transform[] GetIdleTransformsForProperty(string propertyName, int count)
		{
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012c: Expected O, but got Unknown
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			Transform[] array = (Transform[])(object)new Transform[count];
			string text = propertyName.Replace(" ", "").ToLowerInvariant();
			Property val = null;
			Enumerator<Property> enumerator = Property.Properties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property current = enumerator.Current;
				if (current.PropertyName != null && current.PropertyName.Replace(" ", "").ToLowerInvariant() == text)
				{
					val = current;
					break;
				}
			}
			if ((Object)(object)val == (Object)null || (Object)(object)val.SpawnPoint == (Object)null)
			{
				MelonLogger.Warning("[EmployeeManager] Couldn't find spawn point for property: " + propertyName);
				return array;
			}
			Vector3 position = val.SpawnPoint.position;
			float num = 1.2f;
			int num2 = 5;
			for (int i = 0; i < count; i++)
			{
				int num3 = i / num2;
				int num4 = i % num2;
				float num5 = position.x + (float)num4 * num;
				float num6 = position.z + (float)num3 * num;
				float y = position.y;
				GameObject val2 = new GameObject($"IdlePoint_{i}_{propertyName}");
				val2.transform.position = new Vector3(num5, y, num6);
				array[i] = val2.transform;
			}
			return array;
		}

		private void ShowOwnedPropertiesMenu()
		{
			List<DialogueResponse> list = new List<DialogueResponse>();
			Enumerator<Property> enumerator = Property.Properties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property prop = enumerator.Current;
				if (prop.IsOwned && prop.PropertyName != null)
				{
					int capacity = EmployeeConfigManager.GetCapacity(prop.PropertyName);
					if (prop.EmployeeCapacity < capacity)
					{
						prop.EmployeeCapacity = capacity;
					}
					prop.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(GetIdleTransformsForProperty(prop.PropertyName, prop.EmployeeCapacity));
					list.Add(new DialogueResponse($"{prop.PropertyName} (Cap: {prop.EmployeeCapacity})", $"{prop.PropertyName} (Cap: {prop.EmployeeCapacity})", delegate
					{
						ShowPropertyActions(prop);
					}));
				}
			}
			if (list.Count == 0)
			{
				_dialogue.SendNPCMessage("You don't own any properties yet.");
				return;
			}
			list.Add(new DialogueResponse("BACK", "Back", Run));
			_dialogue.ShowResponses(list.ToArray(), 0.5f);
		}

		private void ShowPropertyEmployeesWithBeds(Property prop, int page = 0)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			Property prop2 = prop;
			List<Employee> employees = prop2.Employees;
			if (employees == null || employees.Count == 0)
			{
				_dialogue.SendNPCMessage("No employees found in " + prop2.PropertyName + ".");
				return;
			}
			List<DialogueResponse> list = new List<DialogueResponse>();
			int count = employees.Count;
			int num = Mathf.CeilToInt((float)count / 6f);
			int num2 = page * 6;
			int num3 = Mathf.Min(num2 + 6, count);
			for (int i = num2; i < num3; i++)
			{
				Employee emp = employees[i];
				if (!((Object)(object)emp == (Object)null))
				{
					BedItem bed = emp.GetBed();
					string value = (((Object)(object)bed != (Object)null) ? $"→ Bed at {((Component)bed).transform.position}" : "→ No bed assigned");
					list.Add(new DialogueResponse($"{((NPC)emp).FirstName} {((NPC)emp).LastName} ({((Object)emp).name})", $"{((NPC)emp).FirstName} {((NPC)emp).LastName} {value}", delegate
					{
						OpenEmployeeBed(emp);
					}));
				}
			}
			if (page > 0)
			{
				list.Add(new DialogueResponse("← Previous", "Previous Page", delegate
				{
					ShowPropertyEmployeesWithBeds(prop2, page - 1);
				}));
			}
			if (page < num - 1)
			{
				list.Add(new DialogueResponse("→ Next", "Next Page", delegate
				{
					ShowPropertyEmployeesWithBeds(prop2, page + 1);
				}));
			}
			list.Add(new DialogueResponse("↩ Back", "Back", delegate
			{
				ShowPropertyActions(prop2);
			}));
			_dialogue.SendNPCMessage($"Showing employees in {prop2.PropertyName} (Page {page + 1} of {num})");
			_dialogue.ShowResponses(list.ToArray(), 0.5f);
		}

		private void OpenEmployeeBed(Employee employee)
		{
			BedItem bed = employee.GetBed();
			if ((Object)(object)bed == (Object)null)
			{
				_dialogue.SendNPCMessage(((NPC)employee).FirstName + " has no assigned bed.");
				return;
			}
			StorageEntity storageEntity = ((PlaceableStorageEntity)bed).StorageEntity;
			if ((Object)(object)storageEntity == (Object)null)
			{
				_dialogue.SendNPCMessage("Bed found, but not a valid storage.");
				return;
			}
			GameplayMenu val = Object.FindObjectOfType<GameplayMenu>();
			if ((Object)(object)val != (Object)null)
			{
				val.SetIsOpen(false);
			}
			_dialogue.SendPlayerMessage("Opened bed storage for " + ((NPC)employee).FirstName);
			Singleton<StorageMenu>.Instance.Open(storageEntity);
		}

		private void ShowPayOptions()
		{
			List<DialogueResponse> list = new List<DialogueResponse>
			{
				new DialogueResponse("Pay all employees", "Pay all", delegate
				{
					EmployeeManager employeeManager = Object.FindObjectOfType<EmployeeManager>();
					float totalUnpaidWages = WageUtils.GetTotalUnpaidWages(employeeManager);
					if (totalUnpaidWages <= 0f)
					{
						_dialogue.SendNPCMessage("All employees are already paid for today.");
					}
					else
					{
						_dialogue.SendNPCMessage($"Pay total wages for ${totalUnpaidWages}?");
						_dialogue.ShowResponses(new DialogueResponse[2]
						{
							new DialogueResponse("Yes", "Confirm", delegate
							{
								if (WageUtils.TryPayAllUnpaidEmployees(employeeManager, out float totalCost, out string error))
								{
									_dialogue.SendPlayerMessage($"Paid ${totalCost} in wages.");
									_dialogue.SendNPCMessage("All employees are now paid.");
								}
								else
								{
									_dialogue.SendNPCMessage("Payment failed: " + error);
								}
								ShowPayOptions();
							}),
							new DialogueResponse("Back", "Back", ShowPayOptions)
						}, 0.3f);
					}
				}),
				new DialogueResponse("Pay by property", "Per property", ShowPropertyPayList),
				new DialogueResponse("Back", "Back", Run)
			};
			_dialogue.ShowResponses(list.ToArray(), 0.4f);
		}

		private void ShowPropertyPayList()
		{
			List<DialogueResponse> list = new List<DialogueResponse>();
			Enumerator<Property> enumerator = Property.OwnedProperties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property prop = enumerator.Current;
				if (prop.PropertyName == null || prop.Employees == null || prop.Employees.Count == 0)
				{
					continue;
				}
				float propWages = WageUtils.GetTotalUnpaidWagesForProperty(prop);
				string text = $"{prop.PropertyName} (${propWages})";
				list.Add(new DialogueResponse(text, text, delegate
				{
					if (propWages <= 0f)
					{
						_dialogue.SendNPCMessage("All employees at " + prop.PropertyName + " are paid.");
						ShowPropertyPayList();
					}
					else
					{
						_dialogue.SendNPCMessage($"Pay ${propWages} for {prop.PropertyName}?");
						_dialogue.ShowResponses(new DialogueResponse[2]
						{
							new DialogueResponse("Yes", "Confirm", delegate
							{
								if (WageUtils.TryPayUnpaidEmployeesForProperty(prop, out float cost, out string error))
								{
									_dialogue.SendPlayerMessage($"Paid ${cost} for {prop.PropertyName}.");
									_dialogue.SendNPCMessage("Done.");
								}
								else
								{
									_dialogue.SendNPCMessage("Failed: " + error);
								}
								ShowPropertyPayList();
							}),
							new DialogueResponse("Back", "Back", ShowPropertyPayList)
						}, 0.3f);
					}
				}));
			}
			list.Add(new DialogueResponse("Back", "Back", ShowPayOptions));
			_dialogue.ShowResponses(list.ToArray(), 0.4f);
		}

		private void ShowPropertyActions(Property prop)
		{
			Property prop2 = prop;
			List<DialogueResponse> list = new List<DialogueResponse>();
			list.Add(new DialogueResponse("Increase capacity", "Increase capacity", delegate
			{
				Property obj = prop2;
				obj.EmployeeCapacity += 1;
				EmployeeConfigManager.SetCapacity(prop2.PropertyName, prop2.EmployeeCapacity);
				prop2.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(GetIdleTransformsForProperty(prop2.PropertyName, prop2.EmployeeCapacity));
				_dialogue.SendPlayerMessage($"Increased capacity of {prop2.PropertyName} to {prop2.EmployeeCapacity}");
				_dialogue.SendNPCMessage($"Capacity is now {prop2.EmployeeCapacity}");
				EmployeeConfigManager.SaveConfig();
				ShowPropertyActions(prop2);
			}));
			list.Add(new DialogueResponse("List beds", "List beds", delegate
			{
				ShowPropertyEmployeesWithBeds(prop2);
			}));
			AddHireOption("Hire Cleaner ($1,500)", 1500, "cleaner", prop2, list);
			AddHireOption("Hire Botanist ($1,500)", 1500, "botanist", prop2, list);
			AddHireOption("Hire Handler ($1,500)", 1500, "handler", prop2, list);
			AddHireOption("Hire Chemist ($2,000)", 2000, "chemist", prop2, list);
			list.Add(new DialogueResponse("Back", "Back", ShowOwnedPropertiesMenu));
			_dialogue.ShowResponses(list.ToArray(), 0.5f);
		}

		private void AddHireOption(string label, int fee, string employeeType, Property prop, List<DialogueResponse> responses)
		{
			string employeeType2 = employeeType;
			Property prop2 = prop;
			responses.Add(new DialogueResponse(label, label, delegate
			{
				_dialogue.SendNPCMessage($"Hiring a {employeeType2} at {prop2.PropertyName} will cost you ${fee}. Do you want to proceed?");
				_dialogue.ShowResponses(new DialogueResponse[2]
				{
					new DialogueResponse("Yes, hire", "Confirm hire", delegate
					{
						if (NetworkSingleton<MoneyManager>.Instance.cashBalance < (float)fee)
						{
							_dialogue.SendNPCMessage($"You don't have enough money. Required: ${fee}");
						}
						else
						{
							NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance((float)(-fee), true, false);
							string text = prop2.PropertyName.Replace(" ", "").ToLowerInvariant();
							Console.SubmitCommand("addemployee " + employeeType2 + " " + text);
							_dialogue.SendPlayerMessage($"Hired new {employeeType2} at {prop2.PropertyName} for ${fee}");
							_dialogue.SendNPCMessage("The employee is on their way.");
							ShowPropertyActions(prop2);
						}
					}),
					new DialogueResponse("No", "Cancel", delegate
					{
						_dialogue.SendPlayerMessage("Cancelled hiring.");
						ShowPropertyActions(prop2);
					})
				}, 0.3f);
			}));
		}

		public void Cleanup()
		{
			if ((Object)(object)_npcObject != (Object)null)
			{
				Object.Destroy((Object)(object)_npcObject);
			}
			if ((Object)(object)_npc != (Object)null && NPCManager.NPCRegistry.Contains(_npc))
			{
				NPCManager.NPCRegistry.Remove(_npc);
			}
		}
	}
	public class DialogueResponse
	{
		public string Id;

		public string Text;

		public Action Action;

		public DialogueResponse[] NextResponses;

		public bool DisableDefaultBehavior;

		public DialogueResponse(string id, string text, Action action, bool disableDefaultBehavior = true, DialogueResponse[] next = null)
		{
			Id = id;
			Text = text;
			Action = action;
			DisableDefaultBehavior = disableDefaultBehavior;
			NextResponses = next;
		}
	}
	public class Mod : MelonMod
	{
		[CompilerGenerated]
		private sealed class <Initialize>d__3 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Mod <>4__this;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <Initialize>d__3(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				Mod mod = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = BotManager.WaitForSystems();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					((MelonBase)mod).LoggerInstance.Msg("[Employee_Manager] BotManager...");
					mod._botManager = BotManager.Create(mod);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <WaitForPropertyRestoreThenPatch>d__4 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private bool <hasTargetProps>5__2;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <WaitForPropertyRestoreThenPatch>d__4(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					goto IL_003b;
				case 1:
					<>1__state = -1;
					goto IL_003b;
				case 2:
					{
						<>1__state = -1;
						break;
					}
					IL_003b:
					if (Property.Properties == null || Property.Properties.Count == 0)
					{
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					<hasTargetProps>5__2 = false;
					break;
				}
				Enumerator<Property> enumerator;
				while (!<hasTargetProps>5__2)
				{
					enumerator = Property.Properties.GetEnumerator();
					while (enumerator.MoveNext())
					{
						Property current = enumerator.Current;
						if ((current.IsOwned || EmployeeConfigManager.HasCapacity(current.PropertyName)) && current.PropertyName != null)
						{
							<hasTargetProps>5__2 = true;
							break;
						}
					}
					if (!<hasTargetProps>5__2)
					{
						<>2__current = null;
						<>1__state = 2;
						return true;
					}
				}
				enumerator = Property.Properties.GetEnumerator();
				while (enumerator.MoveNext())
				{
					Property current2 = enumerator.Current;
					if (string.IsNullOrWhiteSpace(current2.PropertyName))
					{
						MelonLogger.Warning("[EmployeeManager] Skipping unnamed property.");
						continue;
					}
					if (!current2.IsOwned && !EmployeeConfigManager.HasCapacity(current2.PropertyName))
					{
						MelonLogger.Msg("[EmployeeManager] Skipping " + current2.PropertyName + " — not owned and not saved.");
						continue;
					}
					int capacity = EmployeeConfigManager.GetCapacity(current2.PropertyName);
					current2.EmployeeCapacity = capacity;
					current2.EmployeeIdlePoints = Il2CppReferenceArray<Transform>.op_Implicit(BotManagerStaticUtils.GetIdleTransformsForProperty(current2.PropertyName, current2.EmployeeCapacity));
					MelonLogger.Msg($"[✔] Patched {current2.PropertyName} → capacity: {current2.EmployeeCapacity}, idlePoints: {((Il2CppArrayBase<Transform>)(object)current2.EmployeeIdlePoints)?.Length}");
				}
				return false;
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private BotManager _botManager;

		public override void OnInitializeMelon()
		{
			EmployeeConfigManager.LoadConfig();
			MelonLogger.Msg("[Employee_Manager] Config loaded.");
		}

		public override void OnSceneWasInitialized(int buildIndex, string sceneName)
		{
			((MelonBase)this).LoggerInstance.Msg("Scene loaded: " + sceneName);
			if (sceneName == "Main")
			{
				MelonCoroutines.Start(Initialize());
				MelonCoroutines.Start(WaitForPropertyRestoreThenPatch());
			}
		}

		[IteratorStateMachine(typeof(<Initialize>d__3))]
		private IEnumerator Initialize()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <Initialize>d__3(0)
			{
				<>4__this = this
			};
		}

		[IteratorStateMachine(typeof(<WaitForPropertyRestoreThenPatch>d__4))]
		private IEnumerator WaitForPropertyRestoreThenPatch()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <WaitForPropertyRestoreThenPatch>d__4(0);
		}

		public override void OnSceneWasUnloaded(int buildIndex, string sceneName)
		{
			if (!(sceneName == "Main"))
			{
				return;
			}
			Enumerator<Property> enumerator = Property.Properties.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Property current = enumerator.Current;
				if (current.IsOwned && current.PropertyName != null)
				{
					EmployeeConfigManager.SetCapacity(current.PropertyName, current.EmployeeCapacity);
					MelonLogger.Msg($"[\ud83d\udcbe] Saved {current.PropertyName} = {current.EmployeeCapacity}");
				}
			}
			EmployeeConfigManager.SaveConfig();
			_botManager?.Cleanup();
			_botManager = null;
		}
	}
	public class TestDialogue
	{
		[CompilerGenerated]
		private sealed class <DelayedShowResponses>d__0 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public float delay;

			public TestDialogue <>4__this;

			public DialogueResponse[] next;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedShowResponses>d__0(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0025: Unknown result type (might be due to invalid IL or missing references)
				//IL_002f: Expected O, but got Unknown
				int num = <>1__state;
				TestDialogue testDialogue = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(delay);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					testDialogue.ShowResponses(next, 0.1f);
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		private readonly NPC _npc;

		private readonly MSGConversation _conversation;

		[IteratorStateMachine(typeof(<DelayedShowResponses>d__0))]
		private IEnumerator DelayedShowResponses(float delay, DialogueResponse[] next)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedShowResponses>d__0(0)
			{
				<>4__this = this,
				delay = delay,
				next = next
			};
		}

		public TestDialogue(NPC npc)
		{
			//IL_0015: Unknown result type (might be due to invalid IL or missing references)
			//IL_001f: Expected O, but got Unknown
			_npc = npc;
			_conversation = new MSGConversation(npc, npc.fullName);
			_npc.MSGConversation = _conversation;
			_conversation.messageHistory = new List<Message>();
			_conversation.messageChainHistory = new List<MessageChain>();
			_conversation.bubbles = new List<MessageBubble>();
			_conversation.EntryVisible = true;
			if (_npc.ConversationCategories == null)
			{
				_npc.ConversationCategories = new List<EConversationCategory>();
				_npc.ConversationCategories.Add((EConversationCategory)0);
			}
			_conversation.SetCategories(_npc.ConversationCategories);
		}

		public void SendNPCMessage(string text)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			Message val = new Message(text, (ESenderType)1, true, -1);
			_conversation.SendMessage(val, true, false);
		}

		public void SendPlayerMessage(string text)
		{
			//IL_0004: Unknown result type (might be due to invalid IL or missing references)
			//IL_000a: Expected O, but got Unknown
			Message val = new Message(text, (ESenderType)0, true, -1);
			_conversation.SendMessage(val, true, false);
		}

		public void ShowResponses(DialogueResponse[] responses, float v)
		{
			//IL_006a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0074: Expected O, but got Unknown
			List<Response> val = new List<Response>();
			foreach (DialogueResponse response in responses)
			{
				Action action = response.Action;
				Action action2 = delegate
				{
					action?.Invoke();
					if (response.NextResponses != null && response.NextResponses.Length != 0)
					{
						MelonCoroutines.Start(DelayedShowResponses(0.5f, response.NextResponses));
					}
				};
				val.Add(new Response(response.Id, response.Text, Action.op_Implicit(action2), response.DisableDefaultBehavior));
			}
			_conversation.ClearResponses(false);
			_conversation.ShowResponses(val, 0f, false);
		}
	}
}