Decompiled source of NPCLaunderers v1.0.3

IL2CPP/Mods/NPCLaunderers_IL2CPP.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using HarmonyLib;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.Injection;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppNewtonsoft.Json.Linq;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.GameTime;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.Persistence;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.Quests;
using Il2CppScheduleOne.UI;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Il2CppSystem.IO;
using Il2CppTMPro;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using NPCLaunderers;
using NPCLaunderers.LaundererSaveManager;
using NPCLaunderers.NPCScripts;
using NPCLaunderers.UI;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UIElements;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "NPCLaunderers", "1.0.3", "weedeej", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("NPCLaunderers_IL2CPP")]
[assembly: AssemblyConfiguration("IL2CPP")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: AssemblyInformationalVersion("1.0.0+61985eb8d7b4c751f4ff59154fa080438265035e")]
[assembly: AssemblyProduct("NPCLaunderers_IL2CPP")]
[assembly: AssemblyTitle("NPCLaunderers_IL2CPP")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NPCLaunderers
{
	public class Core : MelonMod
	{
		[CompilerGenerated]
		private sealed class <DelayedStart>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 <DelayedStart>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 WaitForSecondsRealtime(5f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					Action action = delegate
					{
						foreach (Launderer item in Object.FindObjectsOfType<Launderer>())
						{
							item.laundererData.Save();
						}
					};
					Action action2 = delegate
					{
						foreach (Launderer item2 in Object.FindObjectsOfType<Launderer>())
						{
							item2.WeekPass();
						}
					};
					Singleton<SaveManager>.Instance.onSaveStart.AddListener(UnityAction.op_Implicit(action));
					TimeManager instance = NetworkSingleton<TimeManager>.Instance;
					instance.onWeekPass += Action.op_Implicit(action2);
					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 Il2CppAssetBundle bundle;

		public override void OnInitializeMelon()
		{
			//IL_00a8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			MelonPreferences.CreateCategory("NPCLaunderers", "NPCLaunderers Settings");
			MelonPreferences.CreateEntry<bool>("NPCLaunderers", "EnableEnvy", true, "Enable Envy", "Allows your launderers to get envy of what you earn and request more cut.", false, false, (ValueValidator)null);
			MelonPreferences.CreateEntry<bool>("NPCLaunderers", "EnableCutDecreaseEvent", true, "Enable Request Product", "Allows your launderers to request a product to reduce cut", false, false, (ValueValidator)null);
			MelonPreferences.Save();
			ClassInjector.RegisterTypeInIl2Cpp<Launderer>();
			ClassInjector.RegisterTypeInIl2Cpp<LaundererData>();
			try
			{
				Stream manifestResourceStream = ((MelonBase)this).MelonAssembly.Assembly.GetManifestResourceStream("NPCLaunderers.Assets.launderers.assetbundle");
				if (manifestResourceStream == null)
				{
					((MelonBase)this).Unregister("AssetBundle stream not found", false);
					return;
				}
				byte[] array;
				using (MemoryStream memoryStream = new MemoryStream())
				{
					manifestResourceStream.CopyTo(memoryStream);
					array = memoryStream.ToArray();
				}
				Stream val = (Stream)new MemoryStream(Il2CppStructArray<byte>.op_Implicit(array));
				bundle = Il2CppAssetBundleManager.LoadFromStream(val);
			}
			catch (Exception value)
			{
				((MelonBase)this).Unregister($"Failed to load AssetBundle. Please report to dev: {value}", false);
				return;
			}
			((MelonBase)this).LoggerInstance.Msg("Initialized.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
			if (sceneName == "Main")
			{
				MelonCoroutines.Start(DelayedStart());
			}
		}

		[IteratorStateMachine(typeof(<DelayedStart>d__3))]
		private IEnumerator DelayedStart()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedStart>d__3(0);
		}
	}
}
namespace NPCLaunderers.UI
{
	public class LaundererUI
	{
		private bool isOpen;

		private Launderer launderer;

		public GameObject gameObject;

		private Il2CppAssetBundle bundle;

		public LaundererUI(Launderer launderer)
		{
			this.launderer = launderer;
			Il2CppAssetBundle[] array = Il2CppAssetBundleManager.GetAllLoadedAssetBundles().ToArray();
			if (array.Length == 1)
			{
				bundle = array[0];
				return;
			}
			Il2CppAssetBundle[] array2 = array;
			foreach (Il2CppAssetBundle val in array2)
			{
				if (val.Contains("assets/laundererui.prefab"))
				{
					bundle = val;
					break;
				}
			}
		}

		public void SetLaunderer(Launderer launderer)
		{
			this.launderer = launderer;
		}

		public void Open()
		{
			if (!isOpen)
			{
				Show();
				isOpen = true;
			}
		}

		public void Close()
		{
			if (isOpen)
			{
				Hide();
				isOpen = false;
			}
		}

		private void Show()
		{
			gameObject = bundle.LoadAsset<GameObject>("assets/laundererui.prefab");
			gameObject = Object.Instantiate<GameObject>(gameObject);
			VisualElement val = UQueryExtensions.Q<VisualElement>(gameObject.GetComponent<UIDocument>().rootVisualElement, "LaundererContent", (string)null);
			((TextElement)UQueryExtensions.Q<Label>(UQueryExtensions.Q<VisualElement>(val, "Header", (string)null), "Version", (string)null)).text = ((MelonBase)MelonAssembly.FindMelonInstance<Core>()).Info.Version;
			VisualElement obj = UQueryExtensions.Q<VisualElement>(val, "buttons", (string)null);
			Button val2 = UQueryExtensions.Q<Button>(obj, "btn_close", (string)null);
			Button obj2 = UQueryExtensions.Q<Button>(obj, "btn_submit", (string)null);
			IntegerField amountField = UQueryExtensions.Q<IntegerField>(val, "NumberInput", (string)null);
			Label obj3 = UQueryExtensions.Q<Label>((VisualElement)(object)amountField, "NpcName", (string)null);
			((BaseField<int>)(object)amountField).label = ((BaseField<int>)(object)amountField).label.Replace("<MaxLaunder>", $"{launderer.laundererData.InstanceMaxLaunderAmount}");
			((TextElement)obj3).text = ((TextElement)obj3).text.Replace("<NPCNAME>", launderer.nPC.fullName);
			((CallbackEventHandler)obj2).RegisterCallback<ClickEvent>(EventCallback<ClickEvent>.op_Implicit((Action<ClickEvent>)delegate
			{
				MoneyManager instance = NetworkSingleton<MoneyManager>.Instance;
				try
				{
					float num = ((BaseField<int>)(object)amountField).value;
					if (!(num < 1f))
					{
						if (instance.cashBalance < num)
						{
							MelonLogger.Error($"Input value {num} exceeds cash balance {instance.cashBalance}");
							Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, "<color=#f54c4c>You don't have enough money</color>", launderer.nPC.MugshotSprite, 5f, true);
						}
						else if (num > launderer.laundererData.InstanceMaxLaunderAmount)
						{
							MelonLogger.Error($"Input value {num} exceeds max launder amount {launderer.laundererData.InstanceMaxLaunderAmount}");
							Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, $"<color=#f54c4c>Max of ${launderer.laundererData.InstanceMaxLaunderAmount}</color>", launderer.nPC.MugshotSprite, 5f, true);
						}
						else
						{
							instance.ChangeCashBalance(0f - num, true, true);
							launderer.laundererData.CurrentLaunderAmount = num;
							launderer.laundererData.CurrentTimeLeftSeconds = 720f;
							string text = $"Laundering <color=#16F01C>${num}</color>.I will transfer <color=#6b9cff>${launderer.laundererData.ReturnLaunderAmount}</color> to your account in 12 hours.";
							launderer.nPC.SendTextMessage(text);
							Close();
						}
					}
				}
				catch (Exception ex)
				{
					MelonLogger.Error($"Failed to load LaundererUI: {ex}");
					if (ex is FormatException)
					{
						Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, "<color=#f54c4c>Invalid input value</color>", launderer.nPC.MugshotSprite, 5f, true);
					}
				}
			}), (TrickleDown)0);
			((CallbackEventHandler)val2).RegisterCallback<ClickEvent>(EventCallback<ClickEvent>.op_Implicit((Action<ClickEvent>)delegate
			{
				Close();
			}), (TrickleDown)0);
			PlayerSingleton<PlayerCamera>.Instance.AddActiveUIElement(((Object)gameObject).name);
			Player.Deactivate(true);
		}

		private void Hide()
		{
			PlayerSingleton<PlayerCamera>.Instance.RemoveActiveUIElement(((Object)gameObject).name);
			Player.Activate();
			Object.Destroy((Object)(object)gameObject);
		}
	}
}
namespace NPCLaunderers.LaundererSaveManager
{
	[Serializable]
	public class LaundererData : Object
	{
		public NPC NPC;

		public float MinLaunderAmount;

		public float MaxLaunderAmount;

		public LaundererTier LaundererTier;

		public double CutPercentage;

		public bool isUnlocked;

		public float CurrentTimeLeftSeconds;

		public float CurrentLaunderAmount;

		public float WeekLaunderReturn;

		public float WeekCutAmount;

		public string RequiredProductID;

		public float InstanceMaxLaunderAmount;

		private string SaveFilePath;

		public float ReturnLaunderAmount => Mathf.Floor(CurrentLaunderAmount - CurrentLaunderAmount * (float)(CutPercentage / 100.0));

		public float CutAmount => Mathf.Floor(CurrentLaunderAmount * (float)(CutPercentage / 100.0));

		public LaundererData(IntPtr ptr)
			: base(ptr)
		{
		}

		public LaundererData(NPC nPC)
		{
			NPC = nPC;
			LaundererTier = Launderers.TierOf[nPC.FirstName];
			float[] array = Launderers.LaunderAmountRanges[LaundererTier];
			MinLaunderAmount = array[0];
			MaxLaunderAmount = array[1];
			WeekLaunderReturn = 0f;
			WeekCutAmount = 0f;
			CurrentLaunderAmount = 0f;
			CurrentTimeLeftSeconds = 0f;
			isUnlocked = false;
			InstanceMaxLaunderAmount = 0f;
			RequiredProductID = "";
			CutPercentage = 10.0;
			string loadedGameFolderPath = Singleton<LoadManager>.Instance.LoadedGameFolderPath;
			int startIndex = loadedGameFolderPath.IndexOf("Saves\\") + 5;
			string[] array2 = loadedGameFolderPath.Substring(startIndex).Split(new char[1] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
			SaveFilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers", $"{array2[0]}_{array2[1]}_{nPC.ID}.json");
			if (!Directory.Exists(Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers")))
			{
				Directory.CreateDirectory(Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers"));
			}
		}

		public void Save()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_001c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Expected O, but got Unknown
			//IL_003c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Expected O, but got Unknown
			//IL_005c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0066: Expected O, but got Unknown
			//IL_0082: Unknown result type (might be due to invalid IL or missing references)
			//IL_008c: Expected O, but got Unknown
			//IL_009d: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a7: Expected O, but got Unknown
			//IL_00b8: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c2: Expected O, but got Unknown
			//IL_00d3: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dd: Expected O, but got Unknown
			//IL_00ee: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f8: Expected O, but got Unknown
			//IL_0109: Unknown result type (might be due to invalid IL or missing references)
			//IL_0113: Expected O, but got Unknown
			//IL_0124: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_013f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0149: Expected O, but got Unknown
			//IL_015a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0164: Expected O, but got Unknown
			//IL_0175: Unknown result type (might be due to invalid IL or missing references)
			//IL_017f: Expected O, but got Unknown
			//IL_0190: Unknown result type (might be due to invalid IL or missing references)
			//IL_019a: Expected O, but got Unknown
			JObject val = new JObject();
			((JContainer)val).Add((Object)new JProperty("FirstName", Object.op_Implicit(NPC.FirstName)));
			((JContainer)val).Add((Object)new JProperty("LastName", Object.op_Implicit(NPC.LastName)));
			((JContainer)val).Add((Object)new JProperty("ID", Object.op_Implicit(NPC.ID)));
			((JContainer)val).Add((Object)new JProperty("Tier", Object.op_Implicit(LaundererTier.ToString())));
			((JContainer)val).Add((Object)new JProperty("MinLaunderAmount", Object.op_Implicit(MinLaunderAmount)));
			((JContainer)val).Add((Object)new JProperty("MaxLaunderAmount", Object.op_Implicit(MaxLaunderAmount)));
			((JContainer)val).Add((Object)new JProperty("isUnlocked", Object.op_Implicit(isUnlocked)));
			((JContainer)val).Add((Object)new JProperty("CutPercentage", Object.op_Implicit(CutPercentage)));
			((JContainer)val).Add((Object)new JProperty("CurrentTimeLeftSeconds", Object.op_Implicit(CurrentTimeLeftSeconds)));
			((JContainer)val).Add((Object)new JProperty("CurrentLaunderAmount", Object.op_Implicit(CurrentLaunderAmount)));
			((JContainer)val).Add((Object)new JProperty("WeekLaunderReturn", Object.op_Implicit(WeekLaunderReturn)));
			((JContainer)val).Add((Object)new JProperty("WeekCutAmount", Object.op_Implicit(WeekCutAmount)));
			((JContainer)val).Add((Object)new JProperty("RequiredProductID", Object.op_Implicit(RequiredProductID)));
			((JContainer)val).Add((Object)new JProperty("InstanceMaxLaunderAmount", Object.op_Implicit(InstanceMaxLaunderAmount)));
			File.WriteAllText(SaveFilePath, ((Object)val).ToString());
			Debug.Log(Object.op_Implicit(NPC.FirstName + " - Saved to: " + SaveFilePath));
		}

		public LaundererData Load()
		{
			if (!File.Exists(SaveFilePath))
			{
				return this;
			}
			JObject val = JObject.Parse(File.ReadAllText(SaveFilePath));
			MinLaunderAmount = ((JToken)val).Value<float>(Object.op_Implicit("MinLaunderAmount"));
			MaxLaunderAmount = ((JToken)val).Value<float>(Object.op_Implicit("MaxLaunderAmount"));
			CutPercentage = ((JToken)val).Value<double>(Object.op_Implicit("CutPercentage"));
			isUnlocked = ((JToken)val).Value<bool>(Object.op_Implicit("isUnlocked"));
			CurrentTimeLeftSeconds = ((JToken)val).Value<float>(Object.op_Implicit("CurrentTimeLeftSeconds"));
			CurrentLaunderAmount = ((JToken)val).Value<float>(Object.op_Implicit("CurrentLaunderAmount"));
			LaundererTier = (LaundererTier)Enum.Parse(typeof(LaundererTier), ((JToken)val).Value<string>(Object.op_Implicit("Tier")));
			WeekLaunderReturn = ((JToken)val).Value<float>(Object.op_Implicit("WeekLaunderReturn"));
			WeekCutAmount = ((JToken)val).Value<float>(Object.op_Implicit("WeekCutAmount"));
			InstanceMaxLaunderAmount = ((JToken)val).Value<float>(Object.op_Implicit("InstanceMaxLaunderAmount"));
			RequiredProductID = ((JToken)val).Value<string>(Object.op_Implicit("RequiredProductID"));
			return this;
		}
	}
	public enum LaundererTier
	{
		Low,
		Medium,
		High,
		Highest
	}
	public static class Launderers
	{
		public static Dictionary<string, LaundererTier> TierOf = new Dictionary<string, LaundererTier>
		{
			{
				"Donna",
				LaundererTier.Low
			},
			{
				"Dean",
				LaundererTier.Low
			},
			{
				"Jeff",
				LaundererTier.Medium
			},
			{
				"Marco",
				LaundererTier.Medium
			},
			{
				"Jeremy",
				LaundererTier.High
			},
			{
				"Fiona",
				LaundererTier.High
			},
			{
				"Ray",
				LaundererTier.Highest
			},
			{
				"Herbert",
				LaundererTier.Highest
			}
		};

		public static Dictionary<LaundererTier, float[]> LaunderAmountRanges = new Dictionary<LaundererTier, float[]>
		{
			{
				LaundererTier.Low,
				new float[2] { 1000f, 3500f }
			},
			{
				LaundererTier.Medium,
				new float[2] { 5500f, 7500f }
			},
			{
				LaundererTier.High,
				new float[2] { 9500f, 11000f }
			},
			{
				LaundererTier.Highest,
				new float[2] { 11500f, 13500f }
			}
		};
	}
}
namespace NPCLaunderers.Patches
{
	[HarmonyPatch(typeof(NPC))]
	internal class NPCPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		public static void AddComponent(NPC __instance)
		{
			if (Launderers.TierOf.ContainsKey(__instance.FirstName))
			{
				((Component)__instance).gameObject.AddComponent<Launderer>();
			}
		}
	}
}
namespace NPCLaunderers.NPCScripts
{
	public class Launderer : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass21_0
		{
			public Launderer <>4__this;

			public Contract contract;

			internal void <AddContractListener>b__0(EQuestState result)
			{
				//IL_0000: 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_0014: Expected I4, but got Unknown
				//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
				switch (result - 2)
				{
				case 2:
				{
					double num2 = Mathf.Floor((float)Random.Range(1, 10));
					string text;
					if (<>4__this.laundererData.CutPercentage >= 60.0)
					{
						text = ".";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage + num2 > 60.0)
					{
						num2 = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage += num2;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"Ignoring me huh. I'm increasing my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				case 1:
				{
					double num2 = Mathf.Floor((float)Random.Range(1, 5));
					string text;
					if (<>4__this.laundererData.CutPercentage >= 60.0)
					{
						text = "Sometimes, I don't feel like working with you at all.";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage + num2 > 60.0)
					{
						num2 = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage += num2;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"I don't like the way you acted earlier. I'm increasing my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				case 0:
				{
					double num = Mathf.Floor((float)Random.Range(1, 10));
					string text;
					if (<>4__this.laundererData.CutPercentage == 5.0)
					{
						text = "Thanks!";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage - num < 5.0)
					{
						num = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage -= num;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"Hey, I appreciate you bringing me the goods. I'll reduce my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>.";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				default:
					MelonLogger.Msg((object)result);
					break;
				}
				<>4__this.laundererData.RequiredProductID = "";
				((UnityEventBase)((Quest)contract).onQuestEnd).RemoveAllListeners();
				<>4__this.withContract = false;
			}
		}

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

			private object <>2__current;

			public Launderer <>4__this;

			public Contract contract;

			private <>c__DisplayClass21_0 <>8__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass21_0();
					<>8__1.<>4__this = <>4__this;
					<>8__1.contract = contract;
					<>2__current = (object)new WaitForSecondsRealtime(3f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if (launderer.withContract)
					{
						return false;
					}
					_ = "Deal for " + launderer.nPC.FirstName;
					Action<EQuestState> action = delegate(EQuestState result)
					{
						//IL_0000: 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_0014: Expected I4, but got Unknown
						//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
						switch (result - 2)
						{
						case 2:
						{
							double num3 = Mathf.Floor((float)Random.Range(1, 10));
							if (<>8__1.<>4__this.laundererData.CutPercentage >= 60.0)
							{
								string text = ".";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage + num3 > 60.0)
								{
									num3 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage += num3;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"Ignoring me huh. I'm increasing my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						case 1:
						{
							double num3 = Mathf.Floor((float)Random.Range(1, 5));
							if (<>8__1.<>4__this.laundererData.CutPercentage >= 60.0)
							{
								string text = "Sometimes, I don't feel like working with you at all.";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage + num3 > 60.0)
								{
									num3 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage += num3;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"I don't like the way you acted earlier. I'm increasing my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						case 0:
						{
							double num2 = Mathf.Floor((float)Random.Range(1, 10));
							if (<>8__1.<>4__this.laundererData.CutPercentage == 5.0)
							{
								string text = "Thanks!";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage - num2 < 5.0)
								{
									num2 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage -= num2;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"Hey, I appreciate you bringing me the goods. I'll reduce my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>.";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						default:
							MelonLogger.Msg((object)result);
							break;
						}
						<>8__1.<>4__this.laundererData.RequiredProductID = "";
						((UnityEventBase)((Quest)<>8__1.contract).onQuestEnd).RemoveAllListeners();
						<>8__1.<>4__this.withContract = false;
					};
					((Quest)<>8__1.contract).onQuestEnd.AddListener(UnityAction<EQuestState>.op_Implicit(action));
					launderer.withContract = true;
					QuestHUDUI hudUI = ((Quest)<>8__1.contract).hudUI;
					if (!((TMP_Text)hudUI.MainLabel).text.Contains("EVENT"))
					{
						((TMP_Text)hudUI.MainLabel).text = "<color=#16F01C>[EVENT]</color> " + ((TMP_Text)hudUI.MainLabel).text;
					}
					MelonLogger.Msg(launderer.nPC.FirstName + ": Added active contract listner");
					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 <StartDialougeCheck>d__26 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
				//IL_00ce: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Debug.Log(Object.op_Implicit($"{launderer.nPC.FirstName} - Unlocked: {launderer.laundererData.isUnlocked}, Init Ready: {launderer.isDialogueInitReady}, Is Friendly: {launderer.isFriendly}, Main Ready: {launderer.isMainDialogueReady}"));
					launderer.isCheckingDialouge = true;
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)launderer.dialogueController == (Object)null)
					{
						launderer.dialogueController = ((Component)launderer.nPC.dialogueHandler).GetComponent<DialogueController>();
					}
					if (!launderer.laundererData.isUnlocked && !launderer.isDialogueInitReady && launderer.isFriendly)
					{
						launderer.nPC.SendTextMessage("Hey, Let me know if you need a partnership.");
						launderer.upfrontInstance = Mathf.Floor(Random.Range(launderer.laundererData.MinLaunderAmount, launderer.laundererData.MaxLaunderAmount));
						launderer.AddInitChoice();
					}
					if (launderer.laundererData.isUnlocked && !launderer.isMainDialogueReady && launderer.isFriendly)
					{
						Debug.Log(Object.op_Implicit("Setting up launder"));
						launderer.SetupLaunderDialog();
						Debug.Log(Object.op_Implicit("DONE????"));
					}
					launderer.isCheckingDialouge = false;
					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 <StartLaundryCheck>d__25 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isCheckingLaundry = true;
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (launderer.laundererData.isUnlocked && launderer.laundererData.CurrentLaunderAmount > 0f)
					{
						if (launderer.laundererData.CurrentTimeLeftSeconds > 0f)
						{
							launderer.laundererData.CurrentTimeLeftSeconds -= 1f;
							launderer.isCheckingLaundry = false;
							return false;
						}
						launderer.GiveLaunderedPay();
					}
					launderer.isCheckingLaundry = false;
					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 <StartSavedLaundryCheck>d__27 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isCheckingSavedLaundry = true;
					<>2__current = (object)new WaitForSecondsRealtime(3f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					bool entryValue = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableCutDecreaseEvent");
					if (launderer.laundererData.isUnlocked && launderer.laundererData.RequiredProductID != "" && !launderer.withContract && entryValue)
					{
						launderer.LoadLaundererData();
					}
					launderer.isCheckingSavedLaundry = false;
					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 <UpdateFriendlyState>d__28 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isUpdatingFriendly = true;
					<>2__current = (object)new WaitForSecondsRealtime(5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					launderer.isFriendly = launderer.nPC.RelationData.RelationDelta >= 4f;
					launderer.isUpdatingFriendly = false;
					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();
			}
		}

		public LaundererData laundererData;

		public bool isMainDialogueReady;

		public bool isDialogueInitReady;

		public NPC nPC;

		public DialogueController dialogueController;

		private LaundererUI laundererUI;

		private float upfrontInstance;

		public bool withContract;

		private bool isCheckingLaundry;

		private bool isCheckingDialouge;

		private bool isCheckingSavedLaundry;

		private bool isUpdatingFriendly;

		private bool isFriendly;

		public Launderer(IntPtr pointer)
			: base(pointer)
		{
		}

		public void Awake()
		{
			NPC component = ((Component)this).GetComponent<NPC>();
			if ((Object)(object)component == (Object)null)
			{
				MelonLogger.Error("Launderer component is not attached to an NPC.");
				return;
			}
			laundererData = new LaundererData(component).Load();
			nPC = component;
		}

		private void AddInitChoice()
		{
			//IL_000e: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			DialogueChoice newChoice = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = "How about a partnership?"
			};
			DialogueNodeData val = NPCUtilities.CreateDialogueInitNodeData(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount, laundererData.CutPercentage, upfrontInstance, this);
			List<DialogueNodeData> val2 = new List<DialogueNodeData>();
			val2.Add(val);
			newChoice.Conversation = new DialogueContainer
			{
				DialogueNodeData = val2,
				name = "LAUNDER_INIT_CONTAINER"
			};
			newChoice.onChoosen.AddListener(UnityAction.op_Implicit((Action)delegate
			{
				nPC.dialogueHandler.InitializeDialogue(newChoice.Conversation, true, "LAUNDER_INIT_NODE");
				nPC.dialogueHandler.onDialogueChoiceChosen.AddListener(UnityAction<string>.op_Implicit((Action<string>)delegate(string label)
				{
					if (label == "ACCEPT_LAUNDER_TERMS")
					{
						laundererData.isUnlocked = true;
						dialogueController.Choices.Remove(newChoice);
						laundererData.CutPercentage = 10.0;
						SendInitialMessage();
					}
				}));
			}));
			dialogueController.AddDialogueChoice(newChoice, 0);
			isDialogueInitReady = true;
		}

		private void SendInitialMessage()
		{
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				string text = $"I can help you launder your money. I'll take a cut of <color=#ff6b6b>{laundererData.CutPercentage}%</color> of the amount for this week.";
				nPC.SendTextMessage(text);
				SetupLaunderDialog();
			}
		}

		private void SetupLaunderDialog()
		{
			//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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			if (laundererUI == null)
			{
				laundererUI = new LaundererUI(this);
			}
			DialogueChoice val = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = "Launder Dirties"
			};
			val.onChoosen.AddListener(UnityAction.op_Implicit((Action)delegate
			{
				if (laundererData.CurrentLaunderAmount > 0f || laundererData.CurrentTimeLeftSeconds > 0f)
				{
					Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, $"Laundering <color=#16F01C>${laundererData.CurrentLaunderAmount}</color>", nPC.MugshotSprite, 5f, true);
				}
				else
				{
					laundererData.InstanceMaxLaunderAmount = Mathf.Floor(Random.Range(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount));
					laundererUI.Open();
				}
			}));
			dialogueController.AddDialogueChoice(val, 0);
			isMainDialogueReady = true;
		}

		public void GiveLaunderedPay()
		{
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				NetworkSingleton<MoneyManager>.Instance.CreateOnlineTransaction($"Launderer_${nPC.FirstName}_${laundererData.CurrentLaunderAmount}_${laundererData.CutPercentage}", laundererData.ReturnLaunderAmount, 1f, "");
				string text = $"Hey, I sent <color=#2e75d9>${laundererData.ReturnLaunderAmount}</color> to your bank. \n\nMy Cut: <color=#eb4034>${laundererData.CutAmount}</color>";
				nPC.SendTextMessage(text);
				Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, $"<color=#16F01C>${laundererData.CurrentLaunderAmount}</color> Laundered", nPC.MugshotSprite, 5f, true);
				laundererData.WeekLaunderReturn += laundererData.ReturnLaunderAmount;
				laundererData.WeekCutAmount += laundererData.CutAmount;
				laundererData.CurrentLaunderAmount = 0f;
				laundererData.CurrentTimeLeftSeconds = 0f;
				laundererData.InstanceMaxLaunderAmount = 0f;
			}
		}

		public void RandomizeCut()
		{
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			double num = Random.Range(0f, 100f);
			if (laundererData.WeekLaunderReturn - laundererData.WeekCutAmount > Mathf.Floor(Random.Range(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount)) && num < 30.0 && laundererData.CutPercentage <= 30.0)
			{
				double num2 = Mathf.Floor((float)Random.Range(1, 10));
				while (laundererData.CutPercentage + num2 > 60.0)
				{
					num2 = Mathf.Floor((float)Random.Range(1, 10));
				}
				laundererData.CutPercentage += num2;
				string text = $"Hey, You seem to be doing so well. To make things fair, I'm changing my cut to <color=#ff6b6b>{laundererData.CutPercentage}%</color>.";
				nPC.SendTextMessage(text);
			}
		}

		public void RequireMix(string productId = null)
		{
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_0106: 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_0114: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Invalid comparison between Unknown and I4
			//IL_0125: Unknown result type (might be due to invalid IL or missing references)
			//IL_012d: Expected O, but got Unknown
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0139: Unknown result type (might be due to invalid IL or missing references)
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Unknown result type (might be due to invalid IL or missing references)
			//IL_0174: Unknown result type (might be due to invalid IL or missing references)
			//IL_0179: Unknown result type (might be due to invalid IL or missing references)
			//IL_0184: Unknown result type (might be due to invalid IL or missing references)
			//IL_018f: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a3: Expected O, but got Unknown
			//IL_01a3: Expected O, but got Unknown
			//IL_019e: Unknown result type (might be due to invalid IL or missing references)
			//IL_01a5: Expected O, but got Unknown
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			//IL_01e5: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			ProductDefinition val;
			if (productId == null)
			{
				int num = Random.Range(0, ProductManager.DiscoveredProducts.Count - 1);
				val = ProductManager.DiscoveredProducts[num];
			}
			else
			{
				val = ((IEnumerable<ProductDefinition>)ProductManager.DiscoveredProducts._items).FirstOrDefault((Func<ProductDefinition, bool>)((ProductDefinition p) => ((ItemDefinition)p).ID == productId));
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Error("Product with ID " + productId + " not found.");
					Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, "<color=#f54c4c>Product not found. Launderers Mod disabled</color>", nPC.MugshotSprite, 5f, true);
					MelonBase.FindMelon("NPCLaunderers", "weedeej").Unregister("Product not found. Launderers Mod disabled", false);
					return;
				}
			}
			laundererData.RequiredProductID = ((ItemDefinition)val).ID;
			List<Entry> val2 = new List<Entry>();
			Entry val3 = new Entry
			{
				ProductID = ((ItemDefinition)val).ID,
				Quality = (EQuality)(((int)val.DrugType == 1) ? 3 : 4),
				Quantity = 3
			};
			val2.Add(val3);
			new ProductList().entries = val2;
			DeliveryLocation[] array = Il2CppArrayBase<DeliveryLocation>.op_Implicit(Object.FindObjectsOfType<DeliveryLocation>());
			DeliveryLocation val4 = array[Random.Range(0, array.Length)];
			ContractInfo val5 = new ContractInfo(0f, new ProductList
			{
				entries = val2
			}, val4.StaticGUID, new QuestWindowConfig
			{
				WindowStartTime = 600,
				WindowEndTime = 1200,
				IsEnabled = true
			}, false, 1300, 0, false);
			NetworkSingleton<QuestManager>.Instance.CreateContract_Networked(Player.Local.Connection, Guid.NewGuid().ToString(), true, ((NetworkBehaviour)nPC).NetworkObject, val5, new GameDateTime(1300), NetworkSingleton<TimeManager>.Instance.GetDateTime(), (NetworkObject)null);
			string text = $"Hey, I wanna strengthen our partnership. How about we do a session.\n\nI need you to bring me <color=#6b9cff>3x {((ItemDefinition)val).Name}</color> in <b>BEST</b> quality you can get at <color=#6b9cff>6:00am to 12:00pm</color>.\nMeet me <color=#6b9cff>{val4.LocationDescription}</color>.";
			nPC.SendTextMessage(text);
		}

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

		public void WeekPass()
		{
			bool entryValue = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableEnvy");
			bool entryValue2 = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableCutDecreaseEvent");
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				if (entryValue)
				{
					RandomizeCut();
				}
				if (Random.Range(0, 100) >= 60 && entryValue2)
				{
					RequireMix();
				}
			}
		}

		public void OnDestroy()
		{
			laundererData = null;
			isMainDialogueReady = false;
			isDialogueInitReady = false;
			nPC = null;
			dialogueController = null;
			laundererUI = null;
			upfrontInstance = 0f;
			withContract = false;
		}

		private void Update()
		{
			if (!isCheckingLaundry)
			{
				MelonCoroutines.Start(StartLaundryCheck());
			}
			if (!isCheckingDialouge)
			{
				MelonCoroutines.Start(StartDialougeCheck());
			}
			if (!isCheckingSavedLaundry)
			{
				MelonCoroutines.Start(StartSavedLaundryCheck());
			}
			if (!isUpdatingFriendly)
			{
				MelonCoroutines.Start(UpdateFriendlyState());
			}
		}

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

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

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

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

		private void LoadLaundererData()
		{
			if (laundererData != null && !(laundererData.RequiredProductID == ""))
			{
				Contract val = ((IEnumerable<Contract>)Object.FindObjectsOfType<Contract>()).FirstOrDefault((Contract c) => (int)((Quest)c).QuestState == 1 && ((Quest)c).GetQuestTitle().Contains(nPC.FirstName), null);
				if ((Object)(object)val != (Object)null && !withContract && ((IEnumerable<Entry>)val.ProductList.entries._items).Any((Entry e) => e.ProductID == laundererData.RequiredProductID))
				{
					MelonCoroutines.Start(AddContractListener(val));
				}
				if ((Object)(object)val == (Object)null && !withContract && laundererData.RequiredProductID != "")
				{
					RequireMix(laundererData.RequiredProductID);
				}
			}
		}
	}
	public static class NPCUtilities
	{
		public static DialogueNodeData CreateDialogueInitNodeData(float amount_min, float amount_max, double cut, float upfront, Launderer launderer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_008f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0094: Unknown result type (might be due to invalid IL or missing references)
			//IL_009f: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ab: Expected O, but got Unknown
			//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			DialogueNodeData val = new DialogueNodeData();
			val.DialogueNodeLabel = "LAUNDER_INIT_NODE";
			val.DialogueText = $"Alright, I can wash around <color=#16F01C>${amount_min} - ${amount_max}</color> of your dirties. But there will be some cuts, of course. I'll let you know how much every week. But for now, Let us start with <color=#6b9cff>{cut}%</color> and an upfront of <color=#16F01C>${upfront}</color>";
			DialogueChoiceData[] array = (DialogueChoiceData[])(object)new DialogueChoiceData[2]
			{
				new DialogueChoiceData
				{
					ChoiceLabel = "ACCEPT_LAUNDER_TERMS",
					ChoiceText = "Sure, Let's do it."
				},
				new DialogueChoiceData
				{
					ChoiceLabel = "DECLINE_LAUNDER_TERMS",
					ChoiceText = "Nevermind"
				}
			};
			val.choices = Il2CppReferenceArray<DialogueChoiceData>.op_Implicit(array);
			return val;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}

MONO/Mods/NPCLaunderers_MONO.dll

Decompiled 4 months ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using FishNet.Object;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Preferences;
using MelonLoader.Utils;
using Microsoft.CodeAnalysis;
using NPCLaunderers;
using NPCLaunderers.LaundererSaveManager;
using NPCLaunderers.NPCScripts;
using NPCLaunderers.UI;
using Newtonsoft.Json.Linq;
using ScheduleOne.DevUtilities;
using ScheduleOne.Dialogue;
using ScheduleOne.Economy;
using ScheduleOne.GameTime;
using ScheduleOne.ItemFramework;
using ScheduleOne.Money;
using ScheduleOne.NPCs;
using ScheduleOne.Persistence;
using ScheduleOne.PlayerScripts;
using ScheduleOne.Product;
using ScheduleOne.Quests;
using ScheduleOne.UI;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UIElements;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "NPCLaunderers", "1.0.3", "weedeej", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: IgnoresAccessChecksTo("Assembly-CSharp")]
[assembly: AssemblyCompany("NPCLaunderers_MONO")]
[assembly: AssemblyConfiguration("MONO")]
[assembly: AssemblyFileVersion("1.0.3")]
[assembly: AssemblyInformationalVersion("1.0.0+61985eb8d7b4c751f4ff59154fa080438265035e")]
[assembly: AssemblyProduct("NPCLaunderers_MONO")]
[assembly: AssemblyTitle("NPCLaunderers_MONO")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.3.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace NPCLaunderers
{
	public class Core : MelonMod
	{
		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static UnityAction <>9__3_0;

			public static Action <>9__3_1;

			internal void <DelayedStart>b__3_0()
			{
				Launderer[] array = Object.FindObjectsOfType<Launderer>();
				for (int i = 0; i < array.Length; i++)
				{
					array[i].laundererData.Save();
				}
			}

			internal void <DelayedStart>b__3_1()
			{
				Launderer[] array = Object.FindObjectsOfType<Launderer>();
				for (int i = 0; i < array.Length; i++)
				{
					array[i].WeekPass();
				}
			}
		}

		[CompilerGenerated]
		private sealed class <DelayedStart>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 <DelayedStart>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
				//IL_004b: 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_0056: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSecondsRealtime(5f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					object obj = <>c.<>9__3_0;
					if (obj == null)
					{
						UnityAction val = delegate
						{
							Launderer[] array2 = Object.FindObjectsOfType<Launderer>();
							for (int j = 0; j < array2.Length; j++)
							{
								array2[j].laundererData.Save();
							}
						};
						<>c.<>9__3_0 = val;
						obj = (object)val;
					}
					UnityAction val2 = (UnityAction)obj;
					Action b = delegate
					{
						Launderer[] array = Object.FindObjectsOfType<Launderer>();
						for (int i = 0; i < array.Length; i++)
						{
							array[i].WeekPass();
						}
					};
					Singleton<SaveManager>.Instance.onSaveStart.AddListener(val2);
					TimeManager instance = NetworkSingleton<TimeManager>.Instance;
					instance.onWeekPass = (Action)Delegate.Combine(instance.onWeekPass, b);
					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 AssetBundle bundle;

		public override void OnInitializeMelon()
		{
			MelonPreferences.CreateCategory("NPCLaunderers", "NPCLaunderers Settings");
			MelonPreferences.CreateEntry<bool>("NPCLaunderers", "EnableEnvy", true, "Enable Envy", "Allows your launderers to get envy of what you earn and request more cut.", false, false, (ValueValidator)null);
			MelonPreferences.CreateEntry<bool>("NPCLaunderers", "EnableCutDecreaseEvent", true, "Enable Request Product", "Allows your launderers to request a product to reduce cut", false, false, (ValueValidator)null);
			MelonPreferences.Save();
			try
			{
				Stream manifestResourceStream = ((MelonBase)this).MelonAssembly.Assembly.GetManifestResourceStream("NPCLaunderers.Assets.launderers.assetbundle");
				if (manifestResourceStream == null)
				{
					((MelonBase)this).Unregister("AssetBundle stream not found", false);
					return;
				}
				bundle = AssetBundle.LoadFromStream(manifestResourceStream);
			}
			catch (Exception arg)
			{
				((MelonBase)this).Unregister($"Failed to load AssetBundle. Please report to dev: {arg}", false);
				return;
			}
			((MelonBase)this).LoggerInstance.Msg("Initialized.");
		}

		public override void OnSceneWasLoaded(int buildIndex, string sceneName)
		{
			((MelonMod)this).OnSceneWasLoaded(buildIndex, sceneName);
			if (sceneName == "Main")
			{
				MelonCoroutines.Start(DelayedStart());
			}
		}

		[IteratorStateMachine(typeof(<DelayedStart>d__3))]
		private IEnumerator DelayedStart()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedStart>d__3(0);
		}
	}
}
namespace NPCLaunderers.UI
{
	public class LaundererUI
	{
		private bool isOpen;

		private Launderer launderer;

		public GameObject gameObject;

		private AssetBundle bundle;

		public LaundererUI(Launderer launderer)
		{
			this.launderer = launderer;
			List<AssetBundle> list = AssetBundle.GetAllLoadedAssetBundles().ToList();
			if (list.Count == 1)
			{
				bundle = list[0];
				return;
			}
			foreach (AssetBundle item in list)
			{
				if (((Object)item).name == "launderers.assetbundle")
				{
					bundle = item;
					break;
				}
			}
		}

		public void SetLaunderer(Launderer launderer)
		{
			this.launderer = launderer;
		}

		public void Open()
		{
			if (!isOpen)
			{
				Show();
				isOpen = true;
			}
		}

		public void Close()
		{
			if (isOpen)
			{
				Hide();
				isOpen = false;
			}
		}

		private void Show()
		{
			gameObject = bundle.LoadAsset<GameObject>("assets/laundererui.prefab");
			gameObject = Object.Instantiate<GameObject>(gameObject);
			VisualElement val = UQueryExtensions.Q<VisualElement>(gameObject.GetComponent<UIDocument>().rootVisualElement, "LaundererContent", (string)null);
			((TextElement)UQueryExtensions.Q<Label>(UQueryExtensions.Q<VisualElement>(val, "Header", (string)null), "Version", (string)null)).text = ((MelonBase)MelonAssembly.FindMelonInstance<Core>()).Info.Version;
			VisualElement obj = UQueryExtensions.Q<VisualElement>(val, "buttons", (string)null);
			Button val2 = UQueryExtensions.Q<Button>(obj, "btn_close", (string)null);
			Button obj2 = UQueryExtensions.Q<Button>(obj, "btn_submit", (string)null);
			IntegerField amountField = UQueryExtensions.Q<IntegerField>(val, "NumberInput", (string)null);
			Label obj3 = UQueryExtensions.Q<Label>((VisualElement)(object)amountField, "NpcName", (string)null);
			((BaseField<int>)(object)amountField).label = ((BaseField<int>)(object)amountField).label.Replace("<MaxLaunder>", $"{launderer.laundererData.InstanceMaxLaunderAmount}");
			((TextElement)obj3).text = ((TextElement)obj3).text.Replace("<NPCNAME>", launderer.nPC.fullName);
			((CallbackEventHandler)obj2).RegisterCallback<ClickEvent>((EventCallback<ClickEvent>)delegate
			{
				MoneyManager instance = NetworkSingleton<MoneyManager>.Instance;
				try
				{
					float num = ((BaseField<int>)(object)amountField).value;
					if (!(num < 1f))
					{
						if (instance.cashBalance < num)
						{
							MelonLogger.Error($"Input value {num} exceeds cash balance {instance.cashBalance}");
							Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, "<color=#f54c4c>You don't have enough money</color>", launderer.nPC.MugshotSprite, 5f, true);
						}
						else if (num > launderer.laundererData.InstanceMaxLaunderAmount)
						{
							MelonLogger.Error($"Input value {num} exceeds max launder amount {launderer.laundererData.InstanceMaxLaunderAmount}");
							Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, $"<color=#f54c4c>Max of ${launderer.laundererData.InstanceMaxLaunderAmount}</color>", launderer.nPC.MugshotSprite, 5f, true);
						}
						else
						{
							instance.ChangeCashBalance(0f - num, true, true);
							launderer.laundererData.CurrentLaunderAmount = num;
							launderer.laundererData.CurrentTimeLeftSeconds = 720f;
							string text = $"Laundering <color=#16F01C>${num}</color>.I will transfer <color=#6b9cff>${launderer.laundererData.ReturnLaunderAmount}</color> to your account in 12 hours.";
							launderer.nPC.SendTextMessage(text);
							Close();
						}
					}
				}
				catch (Exception ex)
				{
					MelonLogger.Error($"Failed to load LaundererUI: {ex}");
					if (ex is FormatException)
					{
						Singleton<NotificationsManager>.Instance.SendNotification(launderer.nPC.FirstName, "<color=#f54c4c>Invalid input value</color>", launderer.nPC.MugshotSprite, 5f, true);
					}
				}
			}, (TrickleDown)0);
			((CallbackEventHandler)val2).RegisterCallback<ClickEvent>((EventCallback<ClickEvent>)delegate
			{
				Close();
			}, (TrickleDown)0);
			PlayerSingleton<PlayerCamera>.Instance.AddActiveUIElement(((Object)gameObject).name);
			Player.Deactivate(true);
		}

		private void Hide()
		{
			PlayerSingleton<PlayerCamera>.Instance.RemoveActiveUIElement(((Object)gameObject).name);
			Player.Activate();
			Object.Destroy((Object)(object)gameObject);
		}
	}
}
namespace NPCLaunderers.LaundererSaveManager
{
	[Serializable]
	public class LaundererData
	{
		public NPC NPC;

		public float MinLaunderAmount;

		public float MaxLaunderAmount;

		public LaundererTier LaundererTier;

		public double CutPercentage;

		public bool isUnlocked;

		public float CurrentTimeLeftSeconds;

		public float CurrentLaunderAmount;

		public float WeekLaunderReturn;

		public float WeekCutAmount;

		public string RequiredProductID;

		public float InstanceMaxLaunderAmount;

		private string SaveFilePath;

		public float ReturnLaunderAmount => Mathf.Floor(CurrentLaunderAmount - CurrentLaunderAmount * (float)(CutPercentage / 100.0));

		public float CutAmount => Mathf.Floor(CurrentLaunderAmount * (float)(CutPercentage / 100.0));

		public LaundererData(NPC nPC)
		{
			NPC = nPC;
			LaundererTier = Launderers.TierOf[nPC.FirstName];
			float[] array = Launderers.LaunderAmountRanges[LaundererTier];
			MinLaunderAmount = array[0];
			MaxLaunderAmount = array[1];
			WeekLaunderReturn = 0f;
			WeekCutAmount = 0f;
			CurrentLaunderAmount = 0f;
			CurrentTimeLeftSeconds = 0f;
			isUnlocked = false;
			InstanceMaxLaunderAmount = 0f;
			RequiredProductID = "";
			CutPercentage = 10.0;
			string loadedGameFolderPath = Singleton<LoadManager>.Instance.LoadedGameFolderPath;
			int startIndex = loadedGameFolderPath.IndexOf("Saves\\") + 5;
			string[] array2 = loadedGameFolderPath.Substring(startIndex).Split(new char[1] { '\\' }, StringSplitOptions.RemoveEmptyEntries);
			SaveFilePath = Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers", array2[0] + "_" + array2[1] + "_" + nPC.ID + ".json");
			if (!Directory.Exists(Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers")))
			{
				Directory.CreateDirectory(Path.Combine(MelonEnvironment.UserDataDirectory, "Launderers"));
			}
		}

		public void Save()
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			//IL_003c: Expected O, but got Unknown
			//IL_004d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0057: Expected O, but got Unknown
			//IL_006e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0078: Expected O, but got Unknown
			//IL_0089: Unknown result type (might be due to invalid IL or missing references)
			//IL_0093: Expected O, but got Unknown
			//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ae: Expected O, but got Unknown
			//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
			//IL_00c9: Expected O, but got Unknown
			//IL_00da: Unknown result type (might be due to invalid IL or missing references)
			//IL_00e4: Expected O, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected O, but got Unknown
			//IL_0110: Unknown result type (might be due to invalid IL or missing references)
			//IL_011a: Expected O, but got Unknown
			//IL_012b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0135: Expected O, but got Unknown
			//IL_0146: Unknown result type (might be due to invalid IL or missing references)
			//IL_0150: Expected O, but got Unknown
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0166: Expected O, but got Unknown
			//IL_0177: Unknown result type (might be due to invalid IL or missing references)
			//IL_0181: Expected O, but got Unknown
			JObject val = new JObject();
			((JContainer)val).Add((object)new JProperty("FirstName", (object)NPC.FirstName));
			((JContainer)val).Add((object)new JProperty("LastName", (object)NPC.LastName));
			((JContainer)val).Add((object)new JProperty("ID", (object)NPC.ID));
			((JContainer)val).Add((object)new JProperty("Tier", (object)LaundererTier.ToString()));
			((JContainer)val).Add((object)new JProperty("MinLaunderAmount", (object)MinLaunderAmount));
			((JContainer)val).Add((object)new JProperty("MaxLaunderAmount", (object)MaxLaunderAmount));
			((JContainer)val).Add((object)new JProperty("isUnlocked", (object)isUnlocked));
			((JContainer)val).Add((object)new JProperty("CutPercentage", (object)CutPercentage));
			((JContainer)val).Add((object)new JProperty("CurrentTimeLeftSeconds", (object)CurrentTimeLeftSeconds));
			((JContainer)val).Add((object)new JProperty("CurrentLaunderAmount", (object)CurrentLaunderAmount));
			((JContainer)val).Add((object)new JProperty("WeekLaunderReturn", (object)WeekLaunderReturn));
			((JContainer)val).Add((object)new JProperty("WeekCutAmount", (object)WeekCutAmount));
			((JContainer)val).Add((object)new JProperty("RequiredProductID", (object)RequiredProductID));
			((JContainer)val).Add((object)new JProperty("InstanceMaxLaunderAmount", (object)InstanceMaxLaunderAmount));
			File.WriteAllText(SaveFilePath, ((object)val).ToString());
			Debug.Log((object)(NPC.FirstName + " - Saved to: " + SaveFilePath));
		}

		public LaundererData Load()
		{
			if (!File.Exists(SaveFilePath))
			{
				return this;
			}
			JObject val = JObject.Parse(File.ReadAllText(SaveFilePath));
			MinLaunderAmount = ((JToken)val).Value<float>((object)"MinLaunderAmount");
			MaxLaunderAmount = ((JToken)val).Value<float>((object)"MaxLaunderAmount");
			CutPercentage = ((JToken)val).Value<double>((object)"CutPercentage");
			isUnlocked = ((JToken)val).Value<bool>((object)"isUnlocked");
			CurrentTimeLeftSeconds = ((JToken)val).Value<float>((object)"CurrentTimeLeftSeconds");
			CurrentLaunderAmount = ((JToken)val).Value<float>((object)"CurrentLaunderAmount");
			LaundererTier = (LaundererTier)Enum.Parse(typeof(LaundererTier), ((JToken)val).Value<string>((object)"Tier"));
			WeekLaunderReturn = ((JToken)val).Value<float>((object)"WeekLaunderReturn");
			WeekCutAmount = ((JToken)val).Value<float>((object)"WeekCutAmount");
			InstanceMaxLaunderAmount = ((JToken)val).Value<float>((object)"InstanceMaxLaunderAmount");
			RequiredProductID = ((JToken)val).Value<string>((object)"RequiredProductID");
			return this;
		}
	}
	public enum LaundererTier
	{
		Low,
		Medium,
		High,
		Highest
	}
	public static class Launderers
	{
		public static Dictionary<string, LaundererTier> TierOf = new Dictionary<string, LaundererTier>
		{
			{
				"Donna",
				LaundererTier.Low
			},
			{
				"Dean",
				LaundererTier.Low
			},
			{
				"Jeff",
				LaundererTier.Medium
			},
			{
				"Marco",
				LaundererTier.Medium
			},
			{
				"Jeremy",
				LaundererTier.High
			},
			{
				"Fiona",
				LaundererTier.High
			},
			{
				"Ray",
				LaundererTier.Highest
			},
			{
				"Herbert",
				LaundererTier.Highest
			}
		};

		public static Dictionary<LaundererTier, float[]> LaunderAmountRanges = new Dictionary<LaundererTier, float[]>
		{
			{
				LaundererTier.Low,
				new float[2] { 1000f, 3500f }
			},
			{
				LaundererTier.Medium,
				new float[2] { 5500f, 7500f }
			},
			{
				LaundererTier.High,
				new float[2] { 9500f, 11000f }
			},
			{
				LaundererTier.Highest,
				new float[2] { 11500f, 13500f }
			}
		};
	}
}
namespace NPCLaunderers.Patches
{
	[HarmonyPatch(typeof(NPC))]
	internal class NPCPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		public static void AddComponent(NPC __instance)
		{
			if (Launderers.TierOf.ContainsKey(__instance.FirstName))
			{
				((Component)__instance).gameObject.AddComponent<Launderer>();
			}
		}
	}
}
namespace NPCLaunderers.NPCScripts
{
	public class Launderer : MonoBehaviour
	{
		[CompilerGenerated]
		private sealed class <>c__DisplayClass20_0
		{
			public Launderer <>4__this;

			public Contract contract;

			internal void <AddContractListener>b__0(EQuestState result)
			{
				//IL_0000: 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_0014: Expected I4, but got Unknown
				//IL_029a: Unknown result type (might be due to invalid IL or missing references)
				switch (result - 2)
				{
				case 2:
				{
					double num2 = Mathf.Floor((float)Random.Range(1, 10));
					string text;
					if (<>4__this.laundererData.CutPercentage >= 60.0)
					{
						text = ".";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage + num2 > 60.0)
					{
						num2 = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage += num2;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"Ignoring me huh. I'm increasing my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				case 1:
				{
					double num2 = Mathf.Floor((float)Random.Range(1, 5));
					string text;
					if (<>4__this.laundererData.CutPercentage >= 60.0)
					{
						text = "Sometimes, I don't feel like working with you at all.";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage + num2 > 60.0)
					{
						num2 = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage += num2;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"I don't like the way you acted earlier. I'm increasing my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				case 0:
				{
					double num = Mathf.Floor((float)Random.Range(1, 10));
					string text;
					if (<>4__this.laundererData.CutPercentage == 5.0)
					{
						text = "Thanks!";
						<>4__this.nPC.SendTextMessage(text);
						break;
					}
					while (<>4__this.laundererData.CutPercentage - num < 5.0)
					{
						num = Mathf.Floor((float)Random.Range(1, 10));
					}
					<>4__this.laundererData.CutPercentage -= num;
					<>4__this.laundererData.RequiredProductID = "";
					text = $"Hey, I appreciate you bringing me the goods. I'll reduce my cut to <color=#ff6b6b>{<>4__this.laundererData.CutPercentage}%</color>.";
					<>4__this.nPC.SendTextMessage(text);
					break;
				}
				default:
					MelonLogger.Msg((object)result);
					break;
				}
				<>4__this.laundererData.RequiredProductID = "";
				((UnityEventBase)((Quest)contract).onQuestEnd).RemoveAllListeners();
				<>4__this.withContract = false;
			}
		}

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

			private object <>2__current;

			public Launderer <>4__this;

			public Contract contract;

			private <>c__DisplayClass20_0 <>8__1;

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

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

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

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

			private bool MoveNext()
			{
				//IL_0051: Unknown result type (might be due to invalid IL or missing references)
				//IL_005b: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass20_0();
					<>8__1.<>4__this = <>4__this;
					<>8__1.contract = contract;
					<>2__current = (object)new WaitForSecondsRealtime(3f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if (launderer.withContract)
					{
						return false;
					}
					_ = "Deal for " + launderer.nPC.FirstName;
					UnityAction<EQuestState> val = delegate(EQuestState result)
					{
						//IL_0000: 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_0014: Expected I4, but got Unknown
						//IL_029a: Unknown result type (might be due to invalid IL or missing references)
						switch (result - 2)
						{
						case 2:
						{
							double num3 = Mathf.Floor((float)Random.Range(1, 10));
							if (<>8__1.<>4__this.laundererData.CutPercentage >= 60.0)
							{
								string text = ".";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage + num3 > 60.0)
								{
									num3 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage += num3;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"Ignoring me huh. I'm increasing my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						case 1:
						{
							double num3 = Mathf.Floor((float)Random.Range(1, 5));
							if (<>8__1.<>4__this.laundererData.CutPercentage >= 60.0)
							{
								string text = "Sometimes, I don't feel like working with you at all.";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage + num3 > 60.0)
								{
									num3 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage += num3;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"I don't like the way you acted earlier. I'm increasing my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						case 0:
						{
							double num2 = Mathf.Floor((float)Random.Range(1, 10));
							if (<>8__1.<>4__this.laundererData.CutPercentage == 5.0)
							{
								string text = "Thanks!";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							else
							{
								while (<>8__1.<>4__this.laundererData.CutPercentage - num2 < 5.0)
								{
									num2 = Mathf.Floor((float)Random.Range(1, 10));
								}
								<>8__1.<>4__this.laundererData.CutPercentage -= num2;
								<>8__1.<>4__this.laundererData.RequiredProductID = "";
								string text = $"Hey, I appreciate you bringing me the goods. I'll reduce my cut to <color=#ff6b6b>{<>8__1.<>4__this.laundererData.CutPercentage}%</color>.";
								<>8__1.<>4__this.nPC.SendTextMessage(text);
							}
							break;
						}
						default:
							MelonLogger.Msg((object)result);
							break;
						}
						<>8__1.<>4__this.laundererData.RequiredProductID = "";
						((UnityEventBase)((Quest)<>8__1.contract).onQuestEnd).RemoveAllListeners();
						<>8__1.<>4__this.withContract = false;
					};
					((Quest)<>8__1.contract).onQuestEnd.AddListener(val);
					launderer.withContract = true;
					QuestHUDUI hudUI = ((Quest)<>8__1.contract).hudUI;
					if (!((TMP_Text)hudUI.MainLabel).text.Contains("EVENT"))
					{
						((TMP_Text)hudUI.MainLabel).text = "<color=#16F01C>[EVENT]</color> " + ((TMP_Text)hudUI.MainLabel).text;
					}
					MelonLogger.Msg(launderer.nPC.FirstName + ": Added active contract listner");
					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 <StartDialougeCheck>d__25 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_008e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0098: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					Debug.Log((object)$"{launderer.nPC.FirstName} - Unlocked: {launderer.laundererData.isUnlocked}, Init Ready: {launderer.isDialogueInitReady}, Is Friendly: {launderer.isFriendly}, Main Ready: {launderer.isMainDialogueReady}");
					launderer.isCheckingDialouge = true;
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if ((Object)(object)launderer.dialogueController == (Object)null)
					{
						launderer.dialogueController = ((Component)launderer.nPC.dialogueHandler).GetComponent<DialogueController>();
					}
					if (!launderer.laundererData.isUnlocked && !launderer.isDialogueInitReady && launderer.isFriendly)
					{
						launderer.nPC.SendTextMessage("Hey, Let me know if you need a partnership.");
						launderer.upfrontInstance = Mathf.Floor(Random.Range(launderer.laundererData.MinLaunderAmount, launderer.laundererData.MaxLaunderAmount));
						launderer.AddInitChoice();
					}
					if (launderer.laundererData.isUnlocked && !launderer.isMainDialogueReady && launderer.isFriendly)
					{
						Debug.Log((object)"Setting up launder");
						launderer.SetupLaunderDialog();
						Debug.Log((object)"DONE????");
					}
					launderer.isCheckingDialouge = false;
					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 <StartLaundryCheck>d__24 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isCheckingLaundry = true;
					<>2__current = (object)new WaitForSecondsRealtime(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (launderer.laundererData.isUnlocked && launderer.laundererData.CurrentLaunderAmount > 0f)
					{
						if (launderer.laundererData.CurrentTimeLeftSeconds > 0f)
						{
							launderer.laundererData.CurrentTimeLeftSeconds -= 1f;
							launderer.isCheckingLaundry = false;
							return false;
						}
						launderer.GiveLaunderedPay();
					}
					launderer.isCheckingLaundry = false;
					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 <StartSavedLaundryCheck>d__26 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isCheckingSavedLaundry = true;
					<>2__current = (object)new WaitForSecondsRealtime(3f);
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					bool entryValue = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableCutDecreaseEvent");
					if (launderer.laundererData.isUnlocked && launderer.laundererData.RequiredProductID != "" && !launderer.withContract && entryValue)
					{
						launderer.LoadLaundererData();
					}
					launderer.isCheckingSavedLaundry = false;
					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 <UpdateFriendlyState>d__27 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public Launderer <>4__this;

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

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

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

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

			private bool MoveNext()
			{
				//IL_002b: Unknown result type (might be due to invalid IL or missing references)
				//IL_0035: Expected O, but got Unknown
				int num = <>1__state;
				Launderer launderer = <>4__this;
				switch (num)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					launderer.isUpdatingFriendly = true;
					<>2__current = (object)new WaitForSecondsRealtime(5f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					launderer.isFriendly = launderer.nPC.RelationData.RelationDelta >= 4f;
					launderer.isUpdatingFriendly = false;
					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();
			}
		}

		public LaundererData laundererData;

		public bool isMainDialogueReady;

		public bool isDialogueInitReady;

		public NPC nPC;

		public DialogueController dialogueController;

		private LaundererUI laundererUI;

		private float upfrontInstance;

		public bool withContract;

		private bool isCheckingLaundry;

		private bool isCheckingDialouge;

		private bool isCheckingSavedLaundry;

		private bool isUpdatingFriendly;

		private bool isFriendly;

		public void Awake()
		{
			NPC component = ((Component)this).GetComponent<NPC>();
			if ((Object)(object)component == (Object)null)
			{
				MelonLogger.Error("Launderer component is not attached to an NPC.");
				return;
			}
			laundererData = new LaundererData(component).Load();
			nPC = component;
		}

		private void AddInitChoice()
		{
			//IL_000e: 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_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002a: Expected O, but got Unknown
			//IL_006b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0070: Unknown result type (might be due to invalid IL or missing references)
			//IL_0077: Unknown result type (might be due to invalid IL or missing references)
			//IL_0087: Expected O, but got Unknown
			//IL_0099: Unknown result type (might be due to invalid IL or missing references)
			//IL_00a3: Expected O, but got Unknown
			DialogueChoice newChoice = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = "How about a partnership?"
			};
			DialogueNodeData item = NPCUtilities.CreateDialogueInitNodeData(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount, laundererData.CutPercentage, upfrontInstance, this);
			List<DialogueNodeData> list = new List<DialogueNodeData>();
			list.Add(item);
			newChoice.Conversation = new DialogueContainer
			{
				DialogueNodeData = list,
				name = "LAUNDER_INIT_CONTAINER"
			};
			newChoice.onChoosen.AddListener((UnityAction)delegate
			{
				nPC.dialogueHandler.InitializeDialogue(newChoice.Conversation, true, "LAUNDER_INIT_NODE");
				nPC.dialogueHandler.onDialogueChoiceChosen.AddListener((UnityAction<string>)delegate(string label)
				{
					if (label == "ACCEPT_LAUNDER_TERMS")
					{
						NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - upfrontInstance, true, true);
						laundererData.isUnlocked = true;
						dialogueController.Choices.Remove(newChoice);
						laundererData.CutPercentage = 10.0;
						SendInitialMessage();
					}
				});
			});
			dialogueController.AddDialogueChoice(newChoice, 0);
			isDialogueInitReady = true;
		}

		private void SendInitialMessage()
		{
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				string text = $"I can help you launder your money. I'll take a cut of <color=#ff6b6b>{laundererData.CutPercentage}%</color> of the amount for this week.";
				nPC.SendTextMessage(text);
				SetupLaunderDialog();
			}
		}

		private void SetupLaunderDialog()
		{
			//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)
			//IL_004a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0056: Expected O, but got Unknown
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006d: Expected O, but got Unknown
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			if (laundererUI == null)
			{
				laundererUI = new LaundererUI(this);
			}
			DialogueChoice val = new DialogueChoice
			{
				Enabled = true,
				ChoiceText = "Launder Dirties"
			};
			val.onChoosen.AddListener((UnityAction)delegate
			{
				if (laundererData.CurrentLaunderAmount > 0f || laundererData.CurrentTimeLeftSeconds > 0f)
				{
					Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, $"Laundering <color=#16F01C>${laundererData.CurrentLaunderAmount}</color>", nPC.MugshotSprite, 5f, true);
				}
				else
				{
					laundererData.InstanceMaxLaunderAmount = Mathf.Floor(Random.Range(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount));
					laundererUI.Open();
				}
			});
			dialogueController.AddDialogueChoice(val, 0);
			isMainDialogueReady = true;
		}

		public void GiveLaunderedPay()
		{
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				NetworkSingleton<MoneyManager>.Instance.CreateOnlineTransaction($"Launderer_${nPC.FirstName}_${laundererData.CurrentLaunderAmount}_${laundererData.CutPercentage}", laundererData.ReturnLaunderAmount, 1f, "");
				string text = $"Hey, I sent <color=#2e75d9>${laundererData.ReturnLaunderAmount}</color> to your bank. \n\nMy Cut: <color=#eb4034>${laundererData.CutAmount}</color>";
				nPC.SendTextMessage(text);
				Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, $"<color=#16F01C>${laundererData.CurrentLaunderAmount}</color> Laundered", nPC.MugshotSprite, 5f, true);
				laundererData.WeekLaunderReturn += laundererData.ReturnLaunderAmount;
				laundererData.WeekCutAmount += laundererData.CutAmount;
				laundererData.CurrentLaunderAmount = 0f;
				laundererData.CurrentTimeLeftSeconds = 0f;
				laundererData.InstanceMaxLaunderAmount = 0f;
			}
		}

		public void RandomizeCut()
		{
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			double num = Random.Range(0f, 100f);
			if (laundererData.WeekLaunderReturn - laundererData.WeekCutAmount > Mathf.Floor(Random.Range(laundererData.MinLaunderAmount, laundererData.MaxLaunderAmount)) && num < 30.0 && laundererData.CutPercentage <= 30.0)
			{
				double num2 = Mathf.Floor((float)Random.Range(1, 10));
				while (laundererData.CutPercentage + num2 > 60.0)
				{
					num2 = Mathf.Floor((float)Random.Range(1, 10));
				}
				laundererData.CutPercentage += num2;
				string text = $"Hey, You seem to be doing so well. To make things fair, I'm changing my cut to <color=#ff6b6b>{laundererData.CutPercentage}%</color>.";
				nPC.SendTextMessage(text);
			}
		}

		public void RequireMix(string productId = null)
		{
			//IL_00fc: Unknown result type (might be due to invalid IL or missing references)
			//IL_0101: Unknown result type (might be due to invalid IL or missing references)
			//IL_010d: Unknown result type (might be due to invalid IL or missing references)
			//IL_010f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0115: Invalid comparison between Unknown and I4
			//IL_011b: 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_0128: Expected O, but got Unknown
			//IL_012f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0134: Unknown result type (might be due to invalid IL or missing references)
			//IL_0157: Unknown result type (might be due to invalid IL or missing references)
			//IL_015c: Unknown result type (might be due to invalid IL or missing references)
			//IL_016a: Unknown result type (might be due to invalid IL or missing references)
			//IL_016f: Unknown result type (might be due to invalid IL or missing references)
			//IL_017a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0185: Unknown result type (might be due to invalid IL or missing references)
			//IL_0199: Expected O, but got Unknown
			//IL_0199: Expected O, but got Unknown
			//IL_0194: Unknown result type (might be due to invalid IL or missing references)
			//IL_019b: Expected O, but got Unknown
			//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
			//IL_01db: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)nPC == (Object)null || (Object)(object)dialogueController == (Object)null || !laundererData.isUnlocked)
			{
				return;
			}
			ProductDefinition val;
			if (productId == null)
			{
				int index = Random.Range(0, ProductManager.DiscoveredProducts.Count - 1);
				val = ProductManager.DiscoveredProducts[index];
			}
			else
			{
				val = ProductManager.DiscoveredProducts.Find((ProductDefinition p) => ((ItemDefinition)p).ID == productId);
				if ((Object)(object)val == (Object)null)
				{
					MelonLogger.Error("Product with ID " + productId + " not found.");
					Singleton<NotificationsManager>.Instance.SendNotification(nPC.fullName, "<color=#f54c4c>Product not found. Launderers Mod disabled</color>", nPC.MugshotSprite, 5f, true);
					MelonBase.FindMelon("NPCLaunderers", "weedeej").Unregister("Product not found. Launderers Mod disabled", false);
					return;
				}
			}
			laundererData.RequiredProductID = ((ItemDefinition)val).ID;
			List<Entry> list = new List<Entry>();
			Entry item = new Entry
			{
				ProductID = ((ItemDefinition)val).ID,
				Quality = (EQuality)(((int)val.DrugType == 1) ? 3 : 4),
				Quantity = 3
			};
			list.Add(item);
			new ProductList().entries = list;
			DeliveryLocation[] array = Object.FindObjectsOfType<DeliveryLocation>();
			DeliveryLocation val2 = array[Random.Range(0, array.Length)];
			ContractInfo val3 = new ContractInfo(0f, new ProductList
			{
				entries = list
			}, val2.StaticGUID, new QuestWindowConfig
			{
				WindowStartTime = 600,
				WindowEndTime = 1200,
				IsEnabled = true
			}, false, 1300, 0, false);
			NetworkSingleton<QuestManager>.Instance.CreateContract_Networked(Player.Local.Connection, Guid.NewGuid().ToString(), true, ((NetworkBehaviour)nPC).NetworkObject, val3, new GameDateTime(1300), NetworkSingleton<TimeManager>.Instance.GetDateTime(), (NetworkObject)null);
			string text = "Hey, I wanna strengthen our partnership. How about we do a session.\n\nI need you to bring me <color=#6b9cff>3x " + ((ItemDefinition)val).Name + "</color> in <b>BEST</b> quality you can get at <color=#6b9cff>6:00am to 12:00pm</color>.\nMeet me <color=#6b9cff>" + val2.LocationDescription + "</color>.";
			nPC.SendTextMessage(text);
		}

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

		public void WeekPass()
		{
			bool entryValue = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableEnvy");
			bool entryValue2 = MelonPreferences.GetEntryValue<bool>("NPCLaunderers", "EnableCutDecreaseEvent");
			if (!((Object)(object)nPC == (Object)null) && !((Object)(object)dialogueController == (Object)null) && laundererData.isUnlocked)
			{
				if (entryValue)
				{
					RandomizeCut();
				}
				if (Random.Range(0, 100) >= 60 && entryValue2)
				{
					RequireMix();
				}
			}
		}

		public void OnDestroy()
		{
			laundererData = null;
			isMainDialogueReady = false;
			isDialogueInitReady = false;
			nPC = null;
			dialogueController = null;
			laundererUI = null;
			upfrontInstance = 0f;
			withContract = false;
		}

		private void Update()
		{
			if (!isCheckingLaundry)
			{
				MelonCoroutines.Start(StartLaundryCheck());
			}
			if (!isCheckingDialouge)
			{
				MelonCoroutines.Start(StartDialougeCheck());
			}
			if (!isCheckingSavedLaundry)
			{
				MelonCoroutines.Start(StartSavedLaundryCheck());
			}
			if (!isUpdatingFriendly)
			{
				MelonCoroutines.Start(UpdateFriendlyState());
			}
		}

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

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

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

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

		private void LoadLaundererData()
		{
			if (laundererData != null && !(laundererData.RequiredProductID == ""))
			{
				Contract val = ((IEnumerable<Contract>)Object.FindObjectsOfType<Contract>()).FirstOrDefault((Func<Contract, bool>)((Contract c) => (int)((Quest)c).QuestState == 1 && ((Quest)c).GetQuestTitle().Contains(nPC.FirstName)));
				if ((Object)(object)val != (Object)null && !withContract && val.ProductList.entries.Any((Entry e) => e.ProductID == laundererData.RequiredProductID))
				{
					MelonCoroutines.Start(AddContractListener(val));
				}
				if ((Object)(object)val == (Object)null && !withContract && laundererData.RequiredProductID != "")
				{
					RequireMix(laundererData.RequiredProductID);
				}
			}
		}
	}
	public static class NPCUtilities
	{
		public static DialogueNodeData CreateDialogueInitNodeData(float amount_min, float amount_max, double cut, float upfront, Launderer launderer)
		{
			//IL_0000: Unknown result type (might be due to invalid IL or missing references)
			//IL_0006: Expected O, but got Unknown
			//IL_0053: Unknown result type (might be due to invalid IL or missing references)
			//IL_0058: Unknown result type (might be due to invalid IL or missing references)
			//IL_0063: Unknown result type (might be due to invalid IL or missing references)
			//IL_006f: Expected O, but got Unknown
			//IL_0071: Unknown result type (might be due to invalid IL or missing references)
			//IL_0076: Unknown result type (might be due to invalid IL or missing references)
			//IL_0081: Unknown result type (might be due to invalid IL or missing references)
			//IL_008d: Expected O, but got Unknown
			DialogueNodeData val = new DialogueNodeData();
			val.DialogueNodeLabel = "LAUNDER_INIT_NODE";
			val.DialogueText = $"Alright, I can wash around <color=#16F01C>${amount_min} - ${amount_max}</color> of your dirties. But there will be some cuts, of course. I'll let you know how much every week. But for now, Let us start with <color=#6b9cff>{cut}%</color> and an upfront of <color=#16F01C>${upfront}</color>";
			DialogueChoiceData[] choices = (DialogueChoiceData[])(object)new DialogueChoiceData[2]
			{
				new DialogueChoiceData
				{
					ChoiceLabel = "ACCEPT_LAUNDER_TERMS",
					ChoiceText = "Sure, Let's do it."
				},
				new DialogueChoiceData
				{
					ChoiceLabel = "DECLINE_LAUNDER_TERMS",
					ChoiceText = "Nevermind"
				}
			};
			val.choices = choices;
			return val;
		}
	}
}
namespace System.Runtime.CompilerServices
{
	[AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)]
	internal sealed class IgnoresAccessChecksToAttribute : Attribute
	{
		internal IgnoresAccessChecksToAttribute(string assemblyName)
		{
		}
	}
}