Decompiled source of Heisenberg v2.1.0

Mod/Heisenberg.dll

Decompiled a day ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using HarmonyLib;
using HeisenbergMod;
using Il2CppFishNet.Object;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppScheduleOne;
using Il2CppScheduleOne.AvatarFramework;
using Il2CppScheduleOne.Clothing;
using Il2CppScheduleOne.Core.Items.Framework;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.Employees;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Money;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.ObjectScripts;
using Il2CppScheduleOne.Persistence.Loaders;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: MelonInfo(typeof(Mod), "Heisenberg", "1.0.0", "neato", null)]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("Heisenberg")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("Heisenberg")]
[assembly: AssemblyTitle("Heisenberg")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
	internal sealed class NullableAttribute : Attribute
	{
		public readonly byte[] NullableFlags;

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

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

		public NullableContextAttribute(byte P_0)
		{
			Flag = P_0;
		}
	}
}
namespace HeisenbergMod
{
	public class Mod : MelonMod
	{
		[HarmonyPatch(typeof(DialogueController_Fixer), "ModifyChoiceList")]
		private static class Patch_AddHeisenbergChoice
		{
			private static void Postfix(string dialogueLabel, ref List<DialogueChoiceData> existingChoices)
			{
				//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_0083: Unknown result type (might be due to invalid IL or missing references)
				//IL_008f: Unknown result type (might be due to invalid IL or missing references)
				//IL_00f7: Expected O, but got Unknown
				if (existingChoices == null)
				{
					return;
				}
				DialogueChoiceData val = null;
				Enumerator<DialogueChoiceData> enumerator = existingChoices.GetEnumerator();
				while (enumerator.MoveNext())
				{
					DialogueChoiceData current = enumerator.Current;
					if (current.ChoiceLabel == "Chemist")
					{
						val = current;
					}
					if (current.ChoiceLabel == "Heisenberg")
					{
						return;
					}
				}
				if (val != null)
				{
					existingChoices.Add(new DialogueChoiceData
					{
						Guid = val.Guid,
						ChoiceLabel = "Heisenberg",
						ChoiceText = $"Heisenberg (like a chemist, but everything he makes is Heavenly) - ${4000f:N0} signing bonus, ${600f:N0}/day"
					});
				}
			}
		}

		[HarmonyPatch(typeof(DialogueHandler), "ChoiceSelected")]
		private static class Patch_RelabelHeisenbergChoice
		{
			private static void Prefix(DialogueHandler __instance, int choiceIndex)
			{
				bool flag = false;
				List<DialogueChoiceData> finalChoices = __instance.finalChoices;
				if (finalChoices != null && choiceIndex >= 0 && choiceIndex < finalChoices.Count)
				{
					DialogueChoiceData val = finalChoices[choiceIndex];
					if (val != null && val.ChoiceLabel == "Heisenberg")
					{
						val.ChoiceLabel = "Chemist";
						flag = true;
					}
				}
				List<DialogueChoiceData> currentChoices = __instance.CurrentChoices;
				if (currentChoices != null && choiceIndex >= 0 && choiceIndex < currentChoices.Count)
				{
					DialogueChoiceData val2 = currentChoices[choiceIndex];
					if (val2 != null && val2.ChoiceLabel == "Heisenberg")
					{
						val2.ChoiceLabel = "Chemist";
						flag = true;
					}
				}
				if (flag)
				{
					MelonLogger.Msg("Heisenberg selected - continuing as a standard Chemist hire.");
					_hiringHeisenberg = true;
					_hiringHeisenbergArmedAtTicks = Environment.TickCount64;
				}
			}
		}

		[HarmonyPatch(typeof(EmployeeManager), "CreateEmployee_Server")]
		private static class Patch_TagHeisenberg
		{
			private static void Postfix(Employee __result)
			{
				if (!_hiringHeisenberg)
				{
					return;
				}
				_hiringHeisenberg = false;
				if (Environment.TickCount64 - _hiringHeisenbergArmedAtTicks >= 60000)
				{
					return;
				}
				if ((Object)(object)__result == (Object)null)
				{
					MelonLogger.Error("CreateEmployee_Server returned null - Heisenberg was not created.");
					return;
				}
				float signingFee = __result.SigningFee;
				float num = 4000f - signingFee;
				if (num != 0f)
				{
					NetworkSingleton<MoneyManager>.Instance.ChangeCashBalance(0f - num, true, true);
				}
				ApplyHeisenbergIdentity(__result);
				StartLookEnforcer(__result);
				MelonLogger.Msg("Heisenberg hired!");
			}
		}

		[HarmonyPatch(typeof(DialogueController_Fixer), "ModifyDialogueText")]
		private static class Patch_HeisenbergPriceText
		{
			private static void Postfix(ref string __result)
			{
				if (_hiringHeisenberg && Environment.TickCount64 - _hiringHeisenbergArmedAtTicks < 60000 && !string.IsNullOrEmpty(__result) && Regex.IsMatch(__result, "\\$\\s?\\d"))
				{
					__result = $"Heisenberg doesn't come cheap: ${4000f:N0} up front and ${600f:N0} a day, cash. But everything he cooks comes out Heavenly. Where do you want him?";
				}
			}
		}

		[HarmonyPatch(typeof(EmployeeLoader), "CreateAndLoadEmployee")]
		private static class Patch_RestoreHeisenbergOnLoad
		{
			private static void Postfix(Employee __result)
			{
				StartLookEnforcer(__result);
			}
		}

		[HarmonyPatch(typeof(Employee), "InitializeAppearance")]
		private static class Patch_ReassertLookAfterVanillaAppearance
		{
			private static void Postfix(Employee __instance)
			{
				if (!((Object)(object)__instance == (Object)null) && (!(((NPC)__instance).ID != "heisenberg_chemist") || !(((NPC)__instance).FirstName != "Heisenberg")))
				{
					ApplyHeisenbergIdentity(__instance);
					StartLookEnforcer(__instance);
				}
			}
		}

		[HarmonyPatch(typeof(Chemist), "StartChemistryStation")]
		private static class Patch_ArmChemistryStation
		{
			private static void Postfix(Chemist __instance, ChemistryStation station)
			{
				if (IsHeisenberg((NPC)(object)__instance) && (Object)(object)station != (Object)null)
				{
					_armedStations.Add(((Il2CppObjectBase)station).Pointer.ToInt64());
				}
			}
		}

		[HarmonyPatch(typeof(Chemist), "StartLabOven")]
		private static class Patch_ArmLabOven
		{
			private static void Postfix(Chemist __instance, LabOven oven)
			{
				if (IsHeisenberg((NPC)(object)__instance) && (Object)(object)oven != (Object)null)
				{
					_armedStations.Add(((Il2CppObjectBase)oven).Pointer.ToInt64());
				}
			}
		}

		[HarmonyPatch(typeof(Chemist), "StartCauldron")]
		private static class Patch_ArmCauldron
		{
			private static void Postfix(Chemist __instance, Cauldron cauldron)
			{
				if (IsHeisenberg((NPC)(object)__instance) && (Object)(object)cauldron != (Object)null)
				{
					_armedStations.Add(((Il2CppObjectBase)cauldron).Pointer.ToInt64());
				}
			}
		}

		[HarmonyPatch(typeof(Chemist), "StartMixingStation")]
		private static class Patch_ArmMixingStation
		{
			private static void Postfix(Chemist __instance, MixingStation station)
			{
				if (IsHeisenberg((NPC)(object)__instance) && (Object)(object)station != (Object)null)
				{
					_armedStations.Add(((Il2CppObjectBase)station).Pointer.ToInt64());
				}
			}
		}

		[HarmonyPatch(typeof(ChemistryStation), "SendCookOperation")]
		private static class Patch_ChemStation_Send
		{
			private static void Prefix(ChemistryStation __instance, ChemistryCookOperation op)
			{
				if (op != null && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "chemistry station"))
				{
					op.ProductQuality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(ChemistryStation), "SetCookOperation")]
		private static class Patch_ChemStation_Set
		{
			private static void Prefix(ChemistryStation __instance, ChemistryCookOperation operation)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				if (operation != null && (int)operation.ProductQuality != 4 && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "chemistry station"))
				{
					operation.ProductQuality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(LabOven), "SendCookOperation")]
		private static class Patch_LabOven_Send
		{
			private static void Prefix(LabOven __instance, OvenCookOperation operation)
			{
				if (operation != null && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "lab oven"))
				{
					operation.IngredientQuality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(LabOven), "SetCookOperation")]
		private static class Patch_LabOven_Set
		{
			private static void Prefix(LabOven __instance, OvenCookOperation operation)
			{
				//IL_0005: Unknown result type (might be due to invalid IL or missing references)
				//IL_000b: Invalid comparison between Unknown and I4
				if (operation != null && (int)operation.IngredientQuality != 4 && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "lab oven"))
				{
					operation.IngredientQuality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(MixingStation), "SendMixingOperation")]
		private static class Patch_MixStation_Send
		{
			private static void Prefix(MixingStation __instance, MixOperation operation)
			{
				if (operation != null && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "mixing station"))
				{
					operation.ProductQuality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(Cauldron), "SendCookOperation")]
		private static class Patch_Cauldron_Send
		{
			private static void Prefix(Cauldron __instance, ref EQuality quality)
			{
				if ((int)quality != 4 && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "cauldron"))
				{
					quality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(Cauldron), "StartCookOperation")]
		private static class Patch_Cauldron_Start
		{
			private static void Prefix(Cauldron __instance, ref EQuality quality)
			{
				if ((int)quality != 4 && IsHeisenbergWorking(__instance.NPCUserObject, (Component)(object)__instance, "cauldron"))
				{
					quality = (EQuality)4;
				}
			}
		}

		[HarmonyPatch(typeof(Chemist), "FinishLabOven")]
		private static class Patch_Chemist_FinishLabOven
		{
			private static void Postfix(Chemist __instance, LabOven oven)
			{
				if (!IsHeisenberg((NPC)(object)__instance) || ((oven != null) ? oven.OutputSlots : null) == null)
				{
					return;
				}
				Enumerator<ItemSlot> enumerator = oven.OutputSlots.GetEnumerator();
				while (enumerator.MoveNext())
				{
					ItemSlot current = enumerator.Current;
					ItemInstance obj = ((current != null) ? current.ItemInstance : null);
					QualityItemInstance val = (QualityItemInstance)(object)((obj is QualityItemInstance) ? obj : null);
					if (val != null)
					{
						val.SetQuality((EQuality)4);
					}
				}
			}
		}

		private const string BillyId = "billy_kramer";

		private const string HeisenbergId = "heisenberg_chemist";

		private const string HeisenbergChoiceLabel = "Heisenberg";

		private const float SigningFee = 4000f;

		private const float DailyWage = 600f;

		private static bool _hiringHeisenberg;

		private static long _hiringHeisenbergArmedAtTicks;

		private const long ArmedTimeoutMs = 60000L;

		private static readonly HashSet<long> _armedStations = new HashSet<long>();

		private static readonly Color SuitRed = new Color(0.55f, 0.07f, 0.07f);

		private static readonly Color FedoraBlack = new Color(0.12f, 0.12f, 0.12f);

		private static readonly string[] SuitKeywords = new string[10] { "shirt", "top", "coat", "jacket", "vest", "suit", "sweater", "hoodie", "polo", "apron" };

		private static readonly HashSet<long> _lookEnforcersRunning = new HashSet<long>();

		private static string _fedoraPath;

		private static bool _loggedAccessories;

		public override void OnInitializeMelon()
		{
			((MelonBase)this).LoggerInstance.Msg("Say my name.");
			((MelonBase)this).HarmonyInstance.PatchAll();
		}

		private static bool IsHeisenberg(NPC npc)
		{
			return (Object)(object)npc != (Object)null && npc.ID == "heisenberg_chemist";
		}

		private static bool HeisenbergExists()
		{
			return (Object)(object)NPCManager.GetNPC("heisenberg_chemist") != (Object)null;
		}

		private static bool IsHeisenbergWorking(NetworkObject npcUser, Component station, string stationName)
		{
			if ((Object)(object)npcUser != (Object)null)
			{
				NPC componentInParent = ((Component)npcUser).GetComponentInParent<NPC>();
				if (IsHeisenberg(componentInParent))
				{
					MelonLogger.Msg("Heisenberg is working the " + stationName + " (user check) - forcing Heavenly.");
					return true;
				}
			}
			long item = ((Il2CppObjectBase)station).Pointer.ToInt64();
			if (_armedStations.Remove(item))
			{
				MelonLogger.Msg("Heisenberg is working the " + stationName + " (armed check) - forcing Heavenly.");
				return true;
			}
			return false;
		}

		private static bool ApplyHeisenbergIdentity(Employee employee)
		{
			employee.SigningFee = 4000f;
			employee.DailyWage = 600f;
			((NPC)employee).ID = "heisenberg_chemist";
			((NPC)employee).FirstName = "Heisenberg";
			((NPC)employee).LastName = "";
			((NPC)employee).hasLastName = false;
			return ApplyHeisenbergLook(employee);
		}

		private static bool ApplyHeisenbergLook(Employee employee)
		{
			//IL_0162: Unknown result type (might be due to invalid IL or missing references)
			//IL_00f2: Unknown result type (might be due to invalid IL or missing references)
			//IL_031c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0321: Unknown result type (might be due to invalid IL or missing references)
			//IL_032a: Unknown result type (might be due to invalid IL or missing references)
			//IL_032b: Unknown result type (might be due to invalid IL or missing references)
			//IL_033b: Expected O, but got Unknown
			NPC nPC = NPCManager.GetNPC("billy_kramer");
			object obj;
			if (nPC == null)
			{
				obj = null;
			}
			else
			{
				Avatar avatar = nPC.Avatar;
				obj = ((avatar != null) ? avatar.CurrentSettings : null);
			}
			if ((Object)obj == (Object)null || (Object)(object)((NPC)employee).Avatar == (Object)null)
			{
				return false;
			}
			List<LayerSetting> bodyLayerSettings = nPC.Avatar.CurrentSettings.BodyLayerSettings;
			if (bodyLayerSettings == null || bodyLayerSettings.Count == 0)
			{
				return false;
			}
			AvatarSettings val = Object.Instantiate<AvatarSettings>(nPC.Avatar.CurrentSettings);
			val.UseCombinedLayer = false;
			List<LayerSetting> bodyLayerSettings2 = val.BodyLayerSettings;
			int num = 0;
			for (int i = 0; i < bodyLayerSettings2.Count; i++)
			{
				LayerSetting val2 = bodyLayerSettings2[i];
				string text = val2.layerPath?.ToLowerInvariant() ?? "";
				string[] suitKeywords = SuitKeywords;
				foreach (string value in suitKeywords)
				{
					if (text.Contains(value))
					{
						val2.layerTint = SuitRed;
						bodyLayerSettings2[i] = val2;
						num++;
						break;
					}
				}
			}
			if (num == 0 && bodyLayerSettings2.Count > 0)
			{
				LayerSetting val3 = bodyLayerSettings2[bodyLayerSettings2.Count - 1];
				val3.layerTint = SuitRed;
				bodyLayerSettings2[bodyLayerSettings2.Count - 1] = val3;
			}
			if (_fedoraPath == null)
			{
				_fedoraPath = FindAccessoryPath("fedora") ?? FindAccessoryPath("porkpie") ?? FindAccessoryPath("pork pie");
			}
			string fedoraPath = _fedoraPath;
			List<AccessorySetting> accessorySettings = val.AccessorySettings;
			if (fedoraPath != null && accessorySettings != null)
			{
				for (int num2 = accessorySettings.Count - 1; num2 >= 0; num2--)
				{
					AccessorySetting obj2 = accessorySettings[num2];
					string text2 = ((obj2 == null) ? null : obj2.path?.ToLowerInvariant()) ?? "";
					if (!_loggedAccessories)
					{
						DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(29, 2);
						defaultInterpolatedStringHandler.AppendLiteral("[DIAG] Billy accessory [");
						defaultInterpolatedStringHandler.AppendFormatted(num2);
						defaultInterpolatedStringHandler.AppendLiteral("]: '");
						AccessorySetting obj3 = accessorySettings[num2];
						defaultInterpolatedStringHandler.AppendFormatted((obj3 != null) ? obj3.path : null);
						defaultInterpolatedStringHandler.AppendLiteral("'");
						MelonLogger.Msg(defaultInterpolatedStringHandler.ToStringAndClear());
					}
					if (text2.Contains("/head/") || text2.Contains("hood") || text2.Contains("hat") || text2.Contains("helmet") || text2.Contains("mask") || text2.Contains("goggle") || text2.Contains("respirator"))
					{
						accessorySettings.RemoveAt(num2);
					}
				}
				_loggedAccessories = true;
				accessorySettings.Insert(0, new AccessorySetting
				{
					path = fedoraPath,
					color = FedoraBlack
				});
			}
			((NPC)employee).Avatar.LoadAvatarSettings(val);
			int value2 = ((Il2CppArrayBase<Accessory>)(object)((NPC)employee).Avatar.appliedAccessories)?.Length ?? (-1);
			MelonLogger.Msg($"[DIAG] Look applied: layers={bodyLayerSettings2.Count} tinted={num} hatPath={fedoraPath ?? "NONE"} accessoriesInSettings={val.AccessorySettings?.Count ?? (-1)} appliedAccessories={value2}");
			return true;
		}

		private static void StartLookEnforcer(Employee employee)
		{
			if (!((Object)(object)employee == (Object)null))
			{
				long num = ((Il2CppObjectBase)employee).Pointer.ToInt64();
				if (_lookEnforcersRunning.Add(num))
				{
					MelonCoroutines.Start(EnforceLook(employee, num));
				}
			}
		}

		private static IEnumerator EnforceLook(Employee employee, long key)
		{
			try
			{
				int applied = 0;
				for (int attempt = 0; attempt < 15; attempt++)
				{
					yield return (object)new WaitForSeconds(2f);
					if ((Object)(object)employee == (Object)null || (((NPC)employee).ID != "heisenberg_chemist" && ((NPC)employee).FirstName != "Heisenberg"))
					{
						break;
					}
					if (ApplyHeisenbergIdentity(employee))
					{
						applied++;
					}
					if (applied == 1)
					{
						MelonLogger.Msg("Heisenberg look applied (red suit + porkpie hat).");
					}
					if (applied >= 5)
					{
						break;
					}
				}
			}
			finally
			{
				_lookEnforcersRunning.Remove(key);
			}
		}

		private static string FindAccessoryPath(string nameFragment)
		{
			//IL_006d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: Invalid comparison between Unknown and I4
			Registry instance = Singleton<Registry>.Instance;
			if (((instance != null) ? instance.ItemRegistry : null) == null)
			{
				return null;
			}
			Enumerator<ItemRegister> enumerator = instance.ItemRegistry.GetEnumerator();
			while (enumerator.MoveNext())
			{
				ItemRegister current = enumerator.Current;
				object obj;
				if (current == null)
				{
					obj = null;
				}
				else
				{
					ItemDefinition definition = current.Definition;
					obj = ((definition != null) ? ((Il2CppObjectBase)definition).TryCast<ClothingDefinition>() : null);
				}
				ClothingDefinition val = (ClothingDefinition)obj;
				if (!((Object)(object)val == (Object)null) && (int)val.ApplicationType == 2)
				{
					string text = current.ID?.ToLowerInvariant() ?? "";
					string text2 = ((BaseItemDefinition)val).Name?.ToLowerInvariant() ?? "";
					if (text.Contains(nameFragment) || text2.Contains(nameFragment))
					{
						MelonLogger.Msg($"Found hat '{current.ID}' -> asset path '{val.ClothingAssetPath}'");
						return val.ClothingAssetPath;
					}
				}
			}
			MelonLogger.Msg("No accessory matching '" + nameFragment + "' found in item registry.");
			return null;
		}
	}
}