Decompiled source of BetterFiends v1.1.1

BetterFiends - Il2Cpp.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BetterFiends;
using BetterFiends.Configuration;
using BetterFiends.Services;
using ExampleMod.Objects;
using ExampleMod.Services;
using HarmonyLib;
using Il2CppFishNet.Connection;
using Il2CppFishNet.Object;
using Il2CppScheduleOne.DevUtilities;
using Il2CppScheduleOne.Dialogue;
using Il2CppScheduleOne.Economy;
using Il2CppScheduleOne.ItemFramework;
using Il2CppScheduleOne.Law;
using Il2CppScheduleOne.NPCs;
using Il2CppScheduleOne.NPCs.Behaviour;
using Il2CppScheduleOne.PlayerScripts;
using Il2CppScheduleOne.Product;
using Il2CppScheduleOne.UI;
using Il2CppScheduleOne.UI.Handover;
using Il2CppScheduleOne.VoiceOver;
using Il2CppSystem.Collections.Generic;
using MelonLoader;
using MelonLoader.Utils;
using Newtonsoft.Json;
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(global::BetterFiends.BetterFiends), "BetterFiends", "1.0", "EndureBlackout", "https://thunderstore.io/c/schedule-i/p/EndureBlackout/BetterFiends/")]
[assembly: MelonColor]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BetterFiends")]
[assembly: AssemblyConfiguration("Il2Cpp")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+aa2b1bc4fe173ba1028a6e35360273f49e46ced2")]
[assembly: AssemblyProduct("BetterFiends")]
[assembly: AssemblyTitle("BetterFiends")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ExampleMod.Services
{
	public class JsonDataStoreService<T> where T : class
	{
		private readonly string filePath;

		private List<T> items;

		public JsonDataStoreService(string filePath)
		{
			this.filePath = filePath;
			LoadData();
		}

		private void LoadData()
		{
			try
			{
				if (File.Exists(filePath))
				{
					string text = File.ReadAllText(filePath);
					items = JsonConvert.DeserializeObject<List<T>>(text);
				}
				else
				{
					items = new List<T>();
					SaveData();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error loading data from " + filePath + ": " + ex.Message);
				items = new List<T>();
			}
		}

		public void SaveData()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(filePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				string contents = JsonConvert.SerializeObject((object)items, (Formatting)1);
				File.WriteAllText(filePath, contents);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Failed to save data: " + ex.Message);
			}
		}

		public void Add(T item)
		{
			items.Add(item);
			SaveData();
		}

		public void AddRange(IEnumerable<T> newItems)
		{
			items.AddRange(newItems);
			SaveData();
		}

		public bool Remove(T item)
		{
			bool flag = items.Remove(item);
			if (flag)
			{
				SaveData();
			}
			return flag;
		}

		public void Clear()
		{
			items.Clear();
			SaveData();
		}

		public List<T> GetAll()
		{
			return new List<T>(items);
		}

		public T FindFirst(Func<T, bool> predicate)
		{
			return items.FirstOrDefault(predicate);
		}

		public List<T> FindAll(Func<T, bool> predicate)
		{
			return items.Where(predicate).ToList();
		}

		public void Update(Func<T, bool> predicate, Action<T> updateAction)
		{
			foreach (T item in items.Where(predicate))
			{
				updateAction(item);
			}
			SaveData();
		}
	}
}
namespace ExampleMod.Objects
{
	public class Fiend
	{
		public string Id { get; set; }

		public string Name { get; set; }

		public Product LastConsumed { get; set; }
	}
	public class Product
	{
		public string Id { get; set; }

		public string Name { get; set; }

		public float Addictiveness { get; set; }

		public int Quality { get; set; }
	}
}
namespace BetterFiends
{
	public static class BuildInfo
	{
		public const string Name = "BetterFiends";

		public const string Description = "Makes NPCs fiend for your products or become narcs";

		public const string Author = "EndureBlackout";

		public const string Company = null;

		public const string Version = "1.0";

		public const string DownloadLink = "https://thunderstore.io/c/schedule-i/p/EndureBlackout/BetterFiends/";
	}
	public class BetterFiends : MelonMod
	{
		public static Harmony harmony;

		public static bool appUpdate = false;

		public static AssetBundle testAppBundle;

		public static Object test;

		public static GameObject mainCanvasPrefab;

		private string fiendDataPath;

		public static JsonDataStoreService<Fiend> fiendData;

		private static string configPath;

		public static Config config;

		public static List<NPC> fiendList = new List<NPC>();

		public override void OnInitializeMelon()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			((MelonBase)this).OnInitializeMelon();
			if (harmony == null)
			{
				harmony = new Harmony("com.endureblackout.betterfiends");
				try
				{
					fiendDataPath = Path.Combine(MelonEnvironment.UserDataDirectory, "fiend_data.json");
					fiendData = new JsonDataStoreService<Fiend>(fiendDataPath);
					LoadConfig();
					MelonLogger.Msg("BetterFiends: Patches applied successfully.");
				}
				catch (Exception arg)
				{
					MelonLogger.Error($"BetterFiends: Failed to apply patches. Error: {arg}");
				}
			}
		}

		private void LoadConfig()
		{
			configPath = Path.Combine(MelonEnvironment.UserDataDirectory, "better-fiends-config.json");
			if (File.Exists(configPath))
			{
				string text = File.ReadAllText(configPath);
				config = JsonConvert.DeserializeObject<Config>(text);
				MelonLogger.Msg("[BetterFiends]: Config loaded successfully.");
			}
			else
			{
				Config newConfig = new Config();
				SaveConfig(newConfig);
			}
		}

		private static void SaveConfig(Config newConfig)
		{
			try
			{
				string contents = JsonConvert.SerializeObject((object)newConfig, (Formatting)1);
				File.WriteAllText(configPath, contents);
				MelonLogger.Msg("[BetterFiends]: New config filed created!");
				config = newConfig;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BetterFiends]: There was an issue saving the config file: " + ex.Message);
			}
		}
	}
}
namespace BetterFiends.Services
{
	public static class RenderService
	{
		public static void SetWorldspaceDialogueRenderer(NPC npc, string message)
		{
			Transform val = FindChildRecursive(((Component)npc.Avatar.BodyContainer).transform, "mixamorig:Spine2");
			if ((Object)(object)val != (Object)null)
			{
				WorldspaceDialogueRenderer worldspaceDialogueRenderer = GetWorldspaceDialogueRenderer(npc);
				if ((Object)(object)worldspaceDialogueRenderer != (Object)null)
				{
					Object.Destroy((Object)(object)worldspaceDialogueRenderer);
				}
			}
		}

		public static Transform FindChildRecursive(Transform parent, string name)
		{
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (((Object)child).name == name)
				{
					return child;
				}
				Transform val = FindChildRecursive(child, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		public static WorldspaceDialogueRenderer GetWorldspaceDialogueRenderer(NPC npc)
		{
			Transform val = FindChildRecursive(((Component)npc.Avatar.BodyContainer).transform, "mixamorig:Spine2");
			if ((Object)(object)val != (Object)null)
			{
				WorldspaceDialogueRenderer componentInChildren = ((Component)val).GetComponentInChildren<WorldspaceDialogueRenderer>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					return componentInChildren;
				}
				MelonLogger.Warning("No WorldspaceDialogueRenderer found under Spine2 on " + ((Object)npc).name);
			}
			return null;
		}
	}
}
namespace BetterFiends.Patching
{
	[HarmonyPatch(typeof(RequestProductBehaviour))]
	public static class NPC_Request_Product_Patch
	{
		[HarmonyPatch("Begin")]
		[HarmonyPostfix]
		public static void BeginPostfix(RequestProductBehaviour __instance)
		{
			try
			{
				if (BetterFiends.fiendList.Contains(((Behaviour)__instance).Npc))
				{
					GreetingOverride requestGreeting = __instance.requestGreeting;
					string text = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == ((Behaviour)__instance).Npc.BakedGUID)?.LastConsumed?.Name ?? null;
					if (requestGreeting != null)
					{
						requestGreeting.Greeting = ((text != null) ? ("Yo I need more of that " + text + "... NOW!") : "Yo I need more of your shit... NOW!");
						requestGreeting.PlayVO = true;
						requestGreeting.VOType = (EVOLineType)4;
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error in Begin Postfix: " + ex.Message);
			}
		}

		[HarmonyPatch("RequestRejected")]
		[HarmonyPostfix]
		public static void RequestRejectedPostFix(RequestProductBehaviour __instance)
		{
			NPC npc = ((Behaviour)__instance).Npc;
			if (BetterFiends.fiendList.Contains(npc))
			{
				Customer component = ((Component)npc).GetComponent<Customer>();
				float num = CalculateNarcProbability(component, npc);
				if (Random.value < num)
				{
					DoNarcBehavior(npc, __instance.TargetPlayer, "Better get me that product next time!");
				}
				else
				{
					DoRejectBehavior(npc, "I really needed that shit!");
				}
				BetterFiends.fiendList.Remove(npc);
			}
		}

		[HarmonyPatch("RequestAccepted")]
		[HarmonyPostfix]
		public static void RequestAcceptedPostFix(RequestProductBehaviour __instance)
		{
			NPC npc = ((Behaviour)__instance).Npc;
			if (BetterFiends.fiendList.Contains(npc))
			{
				Customer component = ((Component)npc).GetComponent<Customer>();
				float num = CalculateNarcProbability(component, npc);
				if (Random.value < num)
				{
					DoNarcBehavior(npc, __instance.TargetPlayer, "No hard feelings man, they said I would do hard time!");
				}
				BetterFiends.fiendList.Remove(npc);
			}
		}

		[HarmonyPatch("HandoverClosed")]
		[HarmonyPrefix]
		public static bool HandoverClosedPrefix(RequestProductBehaviour __instance, EHandoverOutcome outcome, List<ItemInstance> items, float askingPrice)
		{
			if (BetterFiends.fiendList.Contains(((Behaviour)__instance).Npc))
			{
				NPC npc = ((Behaviour)__instance).Npc;
				Customer component = ((Component)npc).GetComponent<Customer>();
				Fiend fiend = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == npc.BakedGUID);
				if (fiend != null && fiend.LastConsumed != null)
				{
					ItemInstance val = null;
					Enumerator<ItemInstance> enumerator = items.GetEnumerator();
					while (enumerator.MoveNext())
					{
						ItemInstance current = enumerator.Current;
						if (current.ID == fiend.LastConsumed.Id)
						{
							val = current;
						}
					}
					if (val == null)
					{
						DoRejectBehavior(npc, "This ain't the shit I was looking for!");
						Singleton<HandoverScreen>.Instance.ClearCustomerSlots(true);
						return false;
					}
				}
			}
			return true;
		}

		private static float CalculateNarcProbability(Customer customer, NPC npc)
		{
			float num = 0.05f;
			float num2 = Mathf.Clamp01(customer.CurrentAddiction);
			float num3 = 1f - num2 * 0.8f;
			float num4 = 100f / (100f + customer.CustomerData.MaxWeeklySpend);
			float num5 = num * num3 * num4;
			MelonLogger.Msg($"Narc chance: {num5}");
			return Mathf.Clamp01(num5 * BetterFiends.config.FiendProbabilityMultiplier);
		}

		private static void DoNarcBehavior(NPC npc, Player player, string message)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			npc.PlayVO((EVOLineType)10);
			npc.dialogueHandler.ShowWorldspaceDialogue(npc.dialogueHandler.Database.GetLine((EDialogueModule)3, "sample_offer_rejected_police"), 5f);
			npc.actions.SetCallPoliceBehaviourCrime((Crime)new AttemptingToSell());
			npc.actions.CallPolice_Networked(player);
			WorldspaceDialogueRenderer worldspaceDialogueRenderer = RenderService.GetWorldspaceDialogueRenderer(npc);
			worldspaceDialogueRenderer.ShowText(message, 0f);
			try
			{
				npc.PlayVO((EVOLineType)14);
			}
			catch
			{
			}
		}

		private static void DoRejectBehavior(NPC npc, string message)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (BetterFiends.config.EnableAggressiveBehavior)
			{
				float num = default(float);
				npc.behaviour.CombatBehaviour.SetTarget((NetworkConnection)null, ((NetworkBehaviour)Player.GetClosestPlayer(((Component)npc).transform.position, ref num, (List<Player>)null)).NetworkObject);
				((Behaviour)npc.behaviour.CombatBehaviour).Enable_Networked((NetworkConnection)null);
			}
			WorldspaceDialogueRenderer worldspaceDialogueRenderer = RenderService.GetWorldspaceDialogueRenderer(npc);
			worldspaceDialogueRenderer.ShowText(message, 0f);
		}
	}
	[HarmonyPatch(typeof(ConsumeProductBehaviour), "TryConsume")]
	public static class NPC_ConsumeProduct_Patch
	{
		[CompilerGenerated]
		private sealed class <HandlePlayerInteraction>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public NPC npc;

			public Player player;

			private List<Behaviour> <existing>5__1;

			private Enumerator<Behaviour> <>s__2;

			private Behaviour <behaviour>5__3;

			private Enumerator<Behaviour> <>s__4;

			private Behaviour <beh>5__5;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<existing>5__1 = null;
				<>s__2 = null;
				<behaviour>5__3 = null;
				<>s__4 = null;
				<beh>5__5 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(90f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					PauseBehaviors(npc);
					((Behaviour)npc.behaviour.RequestProductBehaviour).Enabled = true;
					((Behaviour)npc.behaviour.RequestProductBehaviour).SendEnable();
					npc.behaviour.RequestProductBehaviour.TargetPlayer = player;
					npc.behaviour.AddEnabledBehaviour((Behaviour)(object)npc.behaviour.RequestProductBehaviour);
					<existing>5__1 = npc.behaviour.enabledBehaviours;
					<>s__2 = <existing>5__1.GetEnumerator();
					while (<>s__2.MoveNext())
					{
						<behaviour>5__3 = <>s__2.Current;
						if (!<behaviour>5__3.Active)
						{
							<behaviour>5__3.Active = true;
							if (((NetworkBehaviour)npc).LocalConnection != (NetworkConnection)null)
							{
								<behaviour>5__3.Enable_Networked(((NetworkBehaviour)npc).LocalConnection);
								<behaviour>5__3.Begin_Networked(((NetworkBehaviour)npc).LocalConnection);
								BetterFiends.fiendList.Add(npc);
							}
						}
						<behaviour>5__3 = null;
					}
					<>s__2 = null;
					if (<existing>5__1.Count > 0)
					{
						<>s__4 = <existing>5__1.GetEnumerator();
						while (<>s__4.MoveNext())
						{
							<beh>5__5 = <>s__4.Current;
							if (<beh>5__5 is RequestProductBehaviour)
							{
								npc.behaviour.activeBehaviour = <beh>5__5;
							}
							<beh>5__5 = null;
						}
						<>s__4 = null;
					}
					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 static void Postfix(ConsumeProductBehaviour __instance)
		{
			//IL_013c: Unknown result type (might be due to invalid IL or missing references)
			//IL_0146: Expected I4, but got Unknown
			//IL_00d2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00dc: Expected I4, but got Unknown
			try
			{
				ProductItemInstance product = __instance.product;
				string pattern = "\\s*\\(.*[uU]npackaged\\)";
				if (product == null)
				{
					return;
				}
				Player local = Player.Local;
				NPC npc = ((Behaviour)__instance).Npc;
				Fiend fiendData = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == npc.BakedGUID);
				if (fiendData == null)
				{
					MelonLogger.Msg("[BetterFiends]: Fiend data not found, creating new fiend data");
					fiendData = new Fiend
					{
						Id = npc.BakedGUID,
						Name = ((Object)npc).name,
						LastConsumed = new Product
						{
							Id = ((ItemInstance)product).ID,
							Name = Regex.Replace(((ItemInstance)product).Name, pattern, ""),
							Addictiveness = product.GetAddictiveness(),
							Quality = (int)((QualityItemInstance)product).Quality
						}
					};
					BetterFiends.fiendData.Add(fiendData);
				}
				else
				{
					fiendData.LastConsumed = new Product
					{
						Id = ((ItemInstance)product).ID,
						Name = Regex.Replace(((ItemInstance)product).Name, pattern, ""),
						Addictiveness = product.GetAddictiveness(),
						Quality = (int)((QualityItemInstance)product).Quality
					};
					BetterFiends.fiendData.Update((Fiend x) => x.Id == npc.BakedGUID, delegate(Fiend y)
					{
						y.LastConsumed = fiendData.LastConsumed;
					});
				}
				if (local.IsLocalPlayer)
				{
					Customer component = ((Component)npc).GetComponent<Customer>();
					float currentAddiction = component.CurrentAddiction;
					float addictiveness = product.GetAddictiveness();
					float num = CalculateFiendProbability(currentAddiction, addictiveness);
					MelonLogger.Msg($"[BetterFiends]: {((Object)npc).name} has a {num} chance to fiend for more product.");
					if (Random.value < num)
					{
						MelonLogger.Msg("[BetterFiends]: " + ((Object)npc).name + " is fiending for more product. If denied, they will act out in violence or narc on you.");
						MelonCoroutines.Start(HandlePlayerInteraction(npc, local));
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BetterFiends]: Error in TryConsume Postfix: " + ex.Message);
			}
		}

		[IteratorStateMachine(typeof(<HandlePlayerInteraction>d__1))]
		private static IEnumerator HandlePlayerInteraction(NPC npc, Player player)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <HandlePlayerInteraction>d__1(0)
			{
				npc = npc,
				player = player
			};
		}

		private static void PauseBehaviors(NPC npc)
		{
			List<Behaviour> enabledBehaviours = npc.behaviour.enabledBehaviours;
			Enumerator<Behaviour> enumerator = enabledBehaviours.GetEnumerator();
			while (enumerator.MoveNext())
			{
				Behaviour current = enumerator.Current;
				if (current.Active)
				{
					current.Active = false;
					current.BehaviourUpdate();
					if (((NetworkBehaviour)npc).LocalConnection != (NetworkConnection)null)
					{
						current.End_Networked(((NetworkBehaviour)npc).LocalConnection);
					}
				}
			}
		}

		private static float CalculateFiendProbability(float currentAddiction, float productAddictiveness)
		{
			float num = Mathf.Pow(currentAddiction, 1.5f) * (1f + Random.Range(-0.1f, 0.1f));
			float num2 = productAddictiveness * (1f + num);
			float num3 = 1f / (1f + Mathf.Exp(0f - num2 + 3f)) * 0.5f;
			return Mathf.Clamp01(num3 * BetterFiends.config.FiendProbabilityMultiplier);
		}
	}
}
namespace BetterFiends.Configuration
{
	public class Config
	{
		public bool EnableAggressiveBehavior { get; set; } = true;


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


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

	}
}

BetterFiends - Mono.dll

Decompiled 3 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.RegularExpressions;
using BetterFiends;
using BetterFiends.Configuration;
using BetterFiends.Services;
using ExampleMod.Objects;
using ExampleMod.Services;
using FishNet.Connection;
using FishNet.Object;
using HarmonyLib;
using MelonLoader;
using MelonLoader.Utils;
using Newtonsoft.Json;
using ScheduleOne.DevUtilities;
using ScheduleOne.Dialogue;
using ScheduleOne.Economy;
using ScheduleOne.ItemFramework;
using ScheduleOne.Law;
using ScheduleOne.NPCs;
using ScheduleOne.NPCs.Behaviour;
using ScheduleOne.PlayerScripts;
using ScheduleOne.Product;
using ScheduleOne.UI;
using ScheduleOne.UI.Handover;
using ScheduleOne.VoiceOver;
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(global::BetterFiends.BetterFiends), "BetterFiends", "1.0", "EndureBlackout", "https://thunderstore.io/c/schedule-i/p/EndureBlackout/BetterFiends/")]
[assembly: MelonColor]
[assembly: MelonGame("TVGS", "Schedule I")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("BetterFiends")]
[assembly: AssemblyConfiguration("Mono")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+aa2b1bc4fe173ba1028a6e35360273f49e46ced2")]
[assembly: AssemblyProduct("BetterFiends")]
[assembly: AssemblyTitle("BetterFiends")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ExampleMod.Services
{
	public class JsonDataStoreService<T> where T : class
	{
		private readonly string filePath;

		private List<T> items;

		public JsonDataStoreService(string filePath)
		{
			this.filePath = filePath;
			LoadData();
		}

		private void LoadData()
		{
			try
			{
				if (File.Exists(filePath))
				{
					string text = File.ReadAllText(filePath);
					items = JsonConvert.DeserializeObject<List<T>>(text);
				}
				else
				{
					items = new List<T>();
					SaveData();
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error loading data from " + filePath + ": " + ex.Message);
				items = new List<T>();
			}
		}

		public void SaveData()
		{
			try
			{
				string directoryName = Path.GetDirectoryName(filePath);
				if (!Directory.Exists(directoryName))
				{
					Directory.CreateDirectory(directoryName);
				}
				string contents = JsonConvert.SerializeObject((object)items, (Formatting)1);
				File.WriteAllText(filePath, contents);
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Failed to save data: " + ex.Message);
			}
		}

		public void Add(T item)
		{
			items.Add(item);
			SaveData();
		}

		public void AddRange(IEnumerable<T> newItems)
		{
			items.AddRange(newItems);
			SaveData();
		}

		public bool Remove(T item)
		{
			bool flag = items.Remove(item);
			if (flag)
			{
				SaveData();
			}
			return flag;
		}

		public void Clear()
		{
			items.Clear();
			SaveData();
		}

		public List<T> GetAll()
		{
			return new List<T>(items);
		}

		public T FindFirst(Func<T, bool> predicate)
		{
			return items.FirstOrDefault(predicate);
		}

		public List<T> FindAll(Func<T, bool> predicate)
		{
			return items.Where(predicate).ToList();
		}

		public void Update(Func<T, bool> predicate, Action<T> updateAction)
		{
			foreach (T item in items.Where(predicate))
			{
				updateAction(item);
			}
			SaveData();
		}
	}
}
namespace ExampleMod.Objects
{
	public class Fiend
	{
		public string Id { get; set; }

		public string Name { get; set; }

		public Product LastConsumed { get; set; }
	}
	public class Product
	{
		public string Id { get; set; }

		public string Name { get; set; }

		public float Addictiveness { get; set; }

		public int Quality { get; set; }
	}
}
namespace BetterFiends
{
	public static class BuildInfo
	{
		public const string Name = "BetterFiends";

		public const string Description = "Makes NPCs fiend for your products or become narcs";

		public const string Author = "EndureBlackout";

		public const string Company = null;

		public const string Version = "1.0";

		public const string DownloadLink = "https://thunderstore.io/c/schedule-i/p/EndureBlackout/BetterFiends/";
	}
	public class BetterFiends : MelonMod
	{
		public static Harmony harmony;

		public static bool appUpdate = false;

		public static AssetBundle testAppBundle;

		public static Object test;

		public static GameObject mainCanvasPrefab;

		private string fiendDataPath;

		public static JsonDataStoreService<Fiend> fiendData;

		private static string configPath;

		public static Config config;

		public static List<NPC> fiendList = new List<NPC>();

		public override void OnInitializeMelon()
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			((MelonBase)this).OnInitializeMelon();
			if (harmony == null)
			{
				harmony = new Harmony("com.endureblackout.betterfiends");
				try
				{
					fiendDataPath = Path.Combine(MelonEnvironment.UserDataDirectory, "fiend_data.json");
					fiendData = new JsonDataStoreService<Fiend>(fiendDataPath);
					LoadConfig();
					MelonLogger.Msg("BetterFiends: Patches applied successfully.");
				}
				catch (Exception arg)
				{
					MelonLogger.Error($"BetterFiends: Failed to apply patches. Error: {arg}");
				}
			}
		}

		private void LoadConfig()
		{
			configPath = Path.Combine(MelonEnvironment.UserDataDirectory, "better-fiends-config.json");
			if (File.Exists(configPath))
			{
				string text = File.ReadAllText(configPath);
				config = JsonConvert.DeserializeObject<Config>(text);
				MelonLogger.Msg("[BetterFiends]: Config loaded successfully.");
			}
			else
			{
				Config newConfig = new Config();
				SaveConfig(newConfig);
			}
		}

		private static void SaveConfig(Config newConfig)
		{
			try
			{
				string contents = JsonConvert.SerializeObject((object)newConfig, (Formatting)1);
				File.WriteAllText(configPath, contents);
				MelonLogger.Msg("[BetterFiends]: New config filed created!");
				config = newConfig;
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BetterFiends]: There was an issue saving the config file: " + ex.Message);
			}
		}
	}
}
namespace BetterFiends.Services
{
	public static class RenderService
	{
		public static void SetWorldspaceDialogueRenderer(NPC npc, string message)
		{
			Transform val = FindChildRecursive(((Component)npc.Avatar.BodyContainer).transform, "mixamorig:Spine2");
			if ((Object)(object)val != (Object)null)
			{
				WorldspaceDialogueRenderer worldspaceDialogueRenderer = GetWorldspaceDialogueRenderer(npc);
				if ((Object)(object)worldspaceDialogueRenderer != (Object)null)
				{
					Object.Destroy((Object)(object)worldspaceDialogueRenderer);
				}
			}
		}

		public static Transform FindChildRecursive(Transform parent, string name)
		{
			for (int i = 0; i < parent.childCount; i++)
			{
				Transform child = parent.GetChild(i);
				if (((Object)child).name == name)
				{
					return child;
				}
				Transform val = FindChildRecursive(child, name);
				if ((Object)(object)val != (Object)null)
				{
					return val;
				}
			}
			return null;
		}

		public static WorldspaceDialogueRenderer GetWorldspaceDialogueRenderer(NPC npc)
		{
			Transform val = FindChildRecursive(((Component)npc.Avatar.BodyContainer).transform, "mixamorig:Spine2");
			if ((Object)(object)val != (Object)null)
			{
				WorldspaceDialogueRenderer componentInChildren = ((Component)val).GetComponentInChildren<WorldspaceDialogueRenderer>();
				if ((Object)(object)componentInChildren != (Object)null)
				{
					MelonLogger.Msg("Found WorldspaceDialogueRenderer on " + npc.fullName);
					return componentInChildren;
				}
				MelonLogger.Warning("No WorldspaceDialogueRenderer found under Spine2 on " + npc.fullName);
			}
			return null;
		}
	}
}
namespace BetterFiends.Patching
{
	[HarmonyPatch(typeof(RequestProductBehaviour))]
	public static class NPC_Request_Product_Patch
	{
		[HarmonyPatch("Begin")]
		[HarmonyPostfix]
		public static void BeginPostfix(RequestProductBehaviour __instance)
		{
			//IL_00c2: Unknown result type (might be due to invalid IL or missing references)
			try
			{
				if (BetterFiends.fiendList.Contains(((Behaviour)__instance).Npc))
				{
					FieldInfo fieldInfo = AccessTools.Field(typeof(RequestProductBehaviour), "requestGreeting");
					object? value = fieldInfo.GetValue(__instance);
					GreetingOverride val = (GreetingOverride)((value is GreetingOverride) ? value : null);
					string text = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == ((Behaviour)__instance).Npc.BakedGUID)?.LastConsumed?.Name ?? null;
					if (val != null)
					{
						val.Greeting = ((text != null) ? ("Yo I need more of that " + text + "... NOW!") : "Yo I need more of your shit... NOW!");
						val.PlayVO = true;
						val.VOType = (EVOLineType)4;
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("Error in Begin Postfix: " + ex.Message);
			}
		}

		[HarmonyPatch("RequestRejected")]
		[HarmonyPostfix]
		public static void RequestRejectedPostFix(RequestProductBehaviour __instance)
		{
			NPC npc = ((Behaviour)__instance).Npc;
			if (BetterFiends.fiendList.Contains(npc))
			{
				Customer component = ((Component)npc).GetComponent<Customer>();
				float num = CalculateNarcProbability(component, npc);
				if (Random.value < num)
				{
					DoNarcBehavior(npc, __instance.TargetPlayer, "Better get me that product next time!");
				}
				else
				{
					DoRejectBehavior(npc, "I really needed that shit!");
				}
				BetterFiends.fiendList.Remove(npc);
			}
		}

		[HarmonyPatch("RequestAccepted")]
		[HarmonyPostfix]
		public static void RequestAcceptedPostFix(RequestProductBehaviour __instance)
		{
			NPC npc = ((Behaviour)__instance).Npc;
			if (BetterFiends.fiendList.Contains(npc))
			{
				Customer component = ((Component)npc).GetComponent<Customer>();
				float num = CalculateNarcProbability(component, npc);
				if (Random.value < num)
				{
					DoNarcBehavior(npc, __instance.TargetPlayer, "No hard feelings man, they said I would do hard time!");
				}
				BetterFiends.fiendList.Remove(npc);
			}
		}

		[HarmonyPatch("HandoverClosed")]
		[HarmonyPrefix]
		public static bool HandoverClosedPrefix(RequestProductBehaviour __instance, EHandoverOutcome outcome, List<ItemInstance> items, float askingPrice)
		{
			if (BetterFiends.fiendList.Contains(((Behaviour)__instance).Npc))
			{
				NPC npc = ((Behaviour)__instance).Npc;
				Customer component = ((Component)npc).GetComponent<Customer>();
				Fiend fiend = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == npc.BakedGUID);
				if (fiend != null && fiend.LastConsumed != null)
				{
					ItemInstance val = ((IEnumerable<ItemInstance>)items).FirstOrDefault((Func<ItemInstance, bool>)((ItemInstance x) => x.ID == fiend.LastConsumed.Id));
					if (val == null)
					{
						DoRejectBehavior(npc, "This ain't the shit I was looking for!");
						Singleton<HandoverScreen>.Instance.ClearCustomerSlots(true);
						return false;
					}
				}
			}
			return true;
		}

		private static float CalculateNarcProbability(Customer customer, NPC npc)
		{
			float num = 0.05f;
			float num2 = Mathf.Clamp01(customer.CurrentAddiction);
			float num3 = 1f - num2 * 0.8f;
			float num4 = 100f / (100f + customer.CustomerData.MaxWeeklySpend);
			float num5 = num * num3 * num4;
			MelonLogger.Msg($"Narc chance: {num5}");
			return Mathf.Clamp01(num5 * BetterFiends.config.FiendProbabilityMultiplier);
		}

		private static void DoNarcBehavior(NPC npc, Player player, string message)
		{
			//IL_0037: Unknown result type (might be due to invalid IL or missing references)
			//IL_0041: Expected O, but got Unknown
			npc.PlayVO((EVOLineType)10);
			npc.dialogueHandler.ShowWorldspaceDialogue(npc.dialogueHandler.Database.GetLine((EDialogueModule)3, "sample_offer_rejected_police"), 5f);
			npc.actions.SetCallPoliceBehaviourCrime((Crime)new AttemptingToSell());
			npc.actions.CallPolice_Networked(player);
			WorldspaceDialogueRenderer worldspaceDialogueRenderer = RenderService.GetWorldspaceDialogueRenderer(npc);
			worldspaceDialogueRenderer.ShowText(message, 0f);
			try
			{
				npc.PlayVO((EVOLineType)14);
			}
			catch
			{
			}
		}

		private static void DoRejectBehavior(NPC npc, string message)
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			if (BetterFiends.config.EnableAggressiveBehavior)
			{
				float num = default(float);
				npc.behaviour.CombatBehaviour.SetTarget((NetworkConnection)null, ((NetworkBehaviour)Player.GetClosestPlayer(((Component)npc).transform.position, ref num, (List<Player>)null)).NetworkObject);
				((Behaviour)npc.behaviour.CombatBehaviour).Enable_Networked((NetworkConnection)null);
			}
			WorldspaceDialogueRenderer worldspaceDialogueRenderer = RenderService.GetWorldspaceDialogueRenderer(npc);
			worldspaceDialogueRenderer.ShowText(message, 0f);
			try
			{
				npc.PlayVO((EVOLineType)14);
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ConsumeProductBehaviour), "TryConsume")]
	public static class NPC_ConsumeProduct_Patch
	{
		[CompilerGenerated]
		private sealed class <HandlePlayerInteraction>d__1 : IEnumerator<object>, IDisposable, IEnumerator
		{
			private int <>1__state;

			private object <>2__current;

			public NPC npc;

			public Player player;

			private PropertyInfo <enabledProp>5__1;

			private PropertyInfo <targetProp>5__2;

			private MethodInfo <addEnabled>5__3;

			private FieldInfo <field>5__4;

			private List<Behaviour> <existing>5__5;

			private List<Behaviour>.Enumerator <>s__6;

			private Behaviour <behaviour>5__7;

			private PropertyInfo <activeField>5__8;

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

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

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

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<enabledProp>5__1 = null;
				<targetProp>5__2 = null;
				<addEnabled>5__3 = null;
				<field>5__4 = null;
				<existing>5__5 = null;
				<>s__6 = default(List<Behaviour>.Enumerator);
				<behaviour>5__7 = null;
				<activeField>5__8 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0026: Unknown result type (might be due to invalid IL or missing references)
				//IL_0030: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(90f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					PauseBehaviors(npc);
					<enabledProp>5__1 = AccessTools.Property(typeof(RequestProductBehaviour), "Enabled");
					<enabledProp>5__1.SetValue(npc.behaviour.RequestProductBehaviour, true);
					((Behaviour)npc.behaviour.RequestProductBehaviour).SendEnable();
					<targetProp>5__2 = AccessTools.Property(typeof(RequestProductBehaviour), "TargetPlayer");
					<targetProp>5__2.SetValue(npc.behaviour.RequestProductBehaviour, player);
					<addEnabled>5__3 = AccessTools.Method(typeof(NPCBehaviour), "AddEnabledBehaviour", (Type[])null, (Type[])null);
					<addEnabled>5__3.Invoke(npc.behaviour, new object[1] { npc.behaviour.RequestProductBehaviour });
					<field>5__4 = AccessTools.Field(typeof(NPCBehaviour), "enabledBehaviours");
					<existing>5__5 = <field>5__4.GetValue(npc.behaviour) as List<Behaviour>;
					<>s__6 = <existing>5__5.GetEnumerator();
					try
					{
						while (<>s__6.MoveNext())
						{
							<behaviour>5__7 = <>s__6.Current;
							if (!<behaviour>5__7.Active)
							{
								<activeField>5__8 = AccessTools.Property(typeof(Behaviour), "Active");
								<activeField>5__8.SetValue(<behaviour>5__7, true);
								if (((NetworkBehaviour)npc).LocalConnection != (NetworkConnection)null)
								{
									<behaviour>5__7.Enable_Networked(((NetworkBehaviour)npc).LocalConnection);
									<behaviour>5__7.Begin_Networked(((NetworkBehaviour)npc).LocalConnection);
									BetterFiends.fiendList.Add(npc);
								}
								<activeField>5__8 = null;
							}
							<behaviour>5__7 = null;
						}
					}
					finally
					{
						((IDisposable)<>s__6).Dispose();
					}
					<>s__6 = default(List<Behaviour>.Enumerator);
					if (<existing>5__5.Count > 0)
					{
						npc.behaviour.activeBehaviour = <existing>5__5.Where((Behaviour x) => x is RequestProductBehaviour).First();
					}
					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 static void Postfix(ConsumeProductBehaviour __instance)
		{
			//IL_0161: Unknown result type (might be due to invalid IL or missing references)
			//IL_016b: Expected I4, but got Unknown
			//IL_00f5: Unknown result type (might be due to invalid IL or missing references)
			//IL_00ff: Expected I4, but got Unknown
			try
			{
				FieldInfo fieldInfo = AccessTools.Field(typeof(ConsumeProductBehaviour), "product");
				object? value = fieldInfo.GetValue(__instance);
				ProductItemInstance val = (ProductItemInstance)((value is ProductItemInstance) ? value : null);
				string pattern = "\\s*\\(.*[uU]npackaged\\)";
				if (val == null)
				{
					return;
				}
				Player local = Player.Local;
				NPC npc = ((Behaviour)__instance).Npc;
				Fiend fiendData = BetterFiends.fiendData.FindFirst((Fiend x) => x.Id == npc.BakedGUID);
				if (fiendData == null)
				{
					MelonLogger.Msg("[BetterFiends]: Fiend data not found, creating new fiend data");
					fiendData = new Fiend
					{
						Id = npc.BakedGUID,
						Name = ((Object)npc).name,
						LastConsumed = new Product
						{
							Id = ((ItemInstance)val).ID,
							Name = Regex.Replace(((ItemInstance)val).Name, pattern, ""),
							Addictiveness = val.GetAddictiveness(),
							Quality = (int)((QualityItemInstance)val).Quality
						}
					};
					BetterFiends.fiendData.Add(fiendData);
				}
				else
				{
					fiendData.LastConsumed = new Product
					{
						Id = ((ItemInstance)val).ID,
						Name = Regex.Replace(((ItemInstance)val).Name, pattern, ""),
						Addictiveness = val.GetAddictiveness(),
						Quality = (int)((QualityItemInstance)val).Quality
					};
					BetterFiends.fiendData.Update((Fiend x) => x.Id == npc.BakedGUID, delegate(Fiend y)
					{
						y.LastConsumed = fiendData.LastConsumed;
					});
				}
				if (local.IsLocalPlayer)
				{
					Customer component = ((Component)npc).GetComponent<Customer>();
					float currentAddiction = component.CurrentAddiction;
					float addictiveness = val.GetAddictiveness();
					float num = CalculateFiendProbability(currentAddiction, addictiveness);
					MelonLogger.Msg($"[BetterFiends]: {((Object)npc).name} has a {num} chance to fiend for more product.");
					if (Random.value < num)
					{
						MelonLogger.Msg("[BetterFiends]: " + ((Object)npc).name + " is fiending for more product. If denied, they will act out in violence or narc on you.");
						MelonCoroutines.Start(HandlePlayerInteraction(npc, local));
					}
				}
			}
			catch (Exception ex)
			{
				MelonLogger.Error("[BetterFiends]: Error in TryConsume Postfix: " + ex.Message);
			}
		}

		[IteratorStateMachine(typeof(<HandlePlayerInteraction>d__1))]
		private static IEnumerator HandlePlayerInteraction(NPC npc, Player player)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <HandlePlayerInteraction>d__1(0)
			{
				npc = npc,
				player = player
			};
		}

		private static void PauseBehaviors(NPC npc)
		{
			FieldInfo fieldInfo = AccessTools.Field(typeof(NPCBehaviour), "enabledBehaviours");
			List<Behaviour> list = fieldInfo.GetValue(npc.behaviour) as List<Behaviour>;
			foreach (Behaviour item in list)
			{
				if (item.Active)
				{
					PropertyInfo propertyInfo = AccessTools.Property(typeof(Behaviour), "Active");
					propertyInfo.SetValue(item, false);
					item.BehaviourUpdate();
					if (((NetworkBehaviour)npc).LocalConnection != (NetworkConnection)null)
					{
						item.End_Networked(((NetworkBehaviour)npc).LocalConnection);
					}
				}
			}
		}

		private static float CalculateFiendProbability(float currentAddiction, float productAddictiveness)
		{
			float num = Mathf.Pow(currentAddiction, 1.5f) * (1f + Random.Range(-0.1f, 0.1f));
			float num2 = productAddictiveness * (1f + num);
			float num3 = 1f / (1f + Mathf.Exp(0f - num2 + 3f)) * 0.5f;
			return Mathf.Clamp01(num3 * BetterFiends.config.FiendProbabilityMultiplier);
		}
	}
}
namespace BetterFiends.Configuration
{
	public class Config
	{
		public bool EnableAggressiveBehavior { get; set; } = true;


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


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

	}
}