Decompiled source of MurderItemSpawner v1.1.1
MurderItemSpawner.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
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; using System.Text.Json; using BepInEx; using BepInEx.Configuration; using BepInEx.Core.Logging.Interpolation; using BepInEx.Logging; using HarmonyLib; using Il2CppSystem; using Il2CppSystem.Collections.Generic; using Il2CppSystem.IO; using SOD.Common; using SOD.Common.BepInEx; using UnityEngine; using UniverseLib; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")] [assembly: AssemblyCompany("MurderItemSpawner")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fd18034234b1bc5b3744e48ee190066c38503ea8")] [assembly: AssemblyProduct("MurderItemSpawner")] [assembly: AssemblyTitle("MurderItemSpawner")] [assembly: AssemblyVersion("1.0.0.0")] namespace MurderItemSpawner; public class ConfigManager { private static ConfigManager _instance; private Dictionary<string, bool> triggeredRules = new Dictionary<string, bool>(); private Dictionary<string, bool> spawnedItems = new Dictionary<string, bool>(); private Dictionary<string, string> itemSpawnEvents = new Dictionary<string, string>(); private Dictionary<string, int> triggerCounts = new Dictionary<string, int>(); private string currentCaseId = ""; public static ConfigManager Instance { get { if (_instance == null) { _instance = new ConfigManager(); } return _instance; } } public List<ModConfig> Configs { get; private set; } = new List<ModConfig>(); private string ConfigFolderPath => Path.Combine(Paths.PluginPath, "ShaneeexD-MurderItemSpawner"); private ConfigManager() { LoadConfig(); LoadTrackingData(); } public void ResetTracking() { Plugin.LogDebug("Resetting item spawn tracking for new murder case"); triggeredRules.Clear(); spawnedItems.Clear(); itemSpawnEvents.Clear(); triggerCounts.Clear(); SaveTrackingData(); } private string GetCurrentSaveFileName() { if ((Object)(object)RestartSafeController.Instance != (Object)null && RestartSafeController.Instance.saveStateFileInfo != null) { return ((FileSystemInfo)RestartSafeController.Instance.saveStateFileInfo).Name; } return "DEFAULT_SAVE"; } private List<string> GetAllSaveFileNames() { List<string> list = new List<string>(); list.Add(GetCurrentSaveFileName()); if (GetCurrentSaveFileName() != "DEFAULT_SAVE") { list.Add("DEFAULT_SAVE"); } return list; } public void SaveTrackingData() { //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02ce: Expected O, but got Unknown try { string text = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { text = ((Object)MurderController.Instance.chosenMO).name; } StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, bool> spawnedItem in spawnedItems) { stringBuilder.Append(spawnedItem.Key).Append(":").Append(spawnedItem.Value ? "1" : "0") .Append(","); } StringBuilder stringBuilder2 = new StringBuilder(); foreach (KeyValuePair<string, string> itemSpawnEvent in itemSpawnEvents) { stringBuilder2.Append(itemSpawnEvent.Key).Append(":").Append(itemSpawnEvent.Value) .Append(","); } StringBuilder stringBuilder3 = new StringBuilder(); foreach (KeyValuePair<string, bool> triggeredRule in triggeredRules) { stringBuilder3.Append(triggeredRule.Key).Append(":").Append(triggeredRule.Value ? "1" : "0") .Append(","); } StringBuilder stringBuilder4 = new StringBuilder(); foreach (KeyValuePair<string, int> triggerCount in triggerCounts) { stringBuilder4.Append(triggerCount.Key).Append(":").Append(triggerCount.Value) .Append(","); } string currentSaveFileName = GetCurrentSaveFileName(); PlayerPrefs.SetString("MIS_" + currentSaveFileName + "_CurrentCaseId", text); PlayerPrefs.SetString("MIS_" + currentSaveFileName + "_SpawnedItems", stringBuilder.ToString()); PlayerPrefs.SetString("MIS_" + currentSaveFileName + "_ItemSpawnEvents", stringBuilder2.ToString()); PlayerPrefs.SetString("MIS_" + currentSaveFileName + "_TriggeredRules", stringBuilder3.ToString()); PlayerPrefs.SetString("MIS_" + currentSaveFileName + "_TriggerCounts", stringBuilder4.ToString()); Plugin.LogDebug("Saved tracking data for save file: " + currentSaveFileName + ", case ID: " + text); PlayerPrefs.Save(); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(28, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error saving tracking data: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } public void LoadTrackingData() { //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0494: Expected O, but got Unknown try { string currentSaveFileName = GetCurrentSaveFileName(); string text = null; if (PlayerPrefs.HasKey("MIS_" + currentSaveFileName + "_CurrentCaseId")) { text = currentSaveFileName; Plugin.LogDebug("Found tracking data for current save file: " + currentSaveFileName); } else if (currentSaveFileName != "DEFAULT_SAVE" && PlayerPrefs.HasKey("MIS_DEFAULT_SAVE_CurrentCaseId")) { text = "DEFAULT_SAVE"; Plugin.LogDebug("No data for current save file, using DEFAULT_SAVE as fallback"); } if (text == null) { Plugin.LogDebug("No saved tracking data found for save file: " + currentSaveFileName); ResetTracking(); return; } string @string = PlayerPrefs.GetString("MIS_" + text + "_CurrentCaseId"); string text2 = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { text2 = ((Object)MurderController.Instance.chosenMO).name; } if (!string.IsNullOrEmpty(text2) && @string != text2) { Plugin.LogDebug($"New case detected (old: {@string}, new: {text2}). Resetting tracking."); ResetTracking(); return; } spawnedItems.Clear(); itemSpawnEvents.Clear(); triggeredRules.Clear(); triggerCounts.Clear(); if (PlayerPrefs.HasKey("MIS_" + text + "_SpawnedItems")) { string string2 = PlayerPrefs.GetString("MIS_" + text + "_SpawnedItems"); string[] array = string2.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = array; foreach (string text3 in array2) { string[] array3 = text3.Split(':'); if (array3.Length == 2) { spawnedItems[array3[0]] = array3[1] == "1"; } } } if (PlayerPrefs.HasKey("MIS_" + text + "_ItemSpawnEvents")) { string string3 = PlayerPrefs.GetString("MIS_" + text + "_ItemSpawnEvents"); string[] array4 = string3.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array5 = array4; foreach (string text4 in array5) { string[] array6 = text4.Split(':'); if (array6.Length == 2) { itemSpawnEvents[array6[0]] = array6[1]; } } } if (PlayerPrefs.HasKey("MIS_" + text + "_TriggeredRules")) { string string4 = PlayerPrefs.GetString("MIS_" + text + "_TriggeredRules"); string[] array7 = string4.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array8 = array7; foreach (string text5 in array8) { string[] array9 = text5.Split(':'); if (array9.Length == 2) { triggeredRules[array9[0]] = array9[1] == "1"; } } } if (PlayerPrefs.HasKey("MIS_" + text + "_TriggerCounts")) { string string5 = PlayerPrefs.GetString("MIS_" + text + "_TriggerCounts"); string[] array10 = string5.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries); string[] array11 = array10; foreach (string text6 in array11) { string[] array12 = text6.Split(':'); if (array12.Length == 2 && int.TryParse(array12[1], out var result)) { triggerCounts[array12[0]] = result; } } } currentCaseId = text2; string currentSaveFileName2 = GetCurrentSaveFileName(); if (text != currentSaveFileName2) { Plugin.LogDebug("Migrating tracking data from " + text + " to " + currentSaveFileName2); SaveTrackingData(); text = currentSaveFileName2; } Plugin.LogDebug("Loaded tracking data for save file: " + text + ", case ID: " + currentCaseId); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error loading tracking data: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); ResetTracking(); } } public void LoadConfig() { //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Expected O, but got Unknown //IL_0288: Unknown result type (might be due to invalid IL or missing references) //IL_028f: Expected O, but got Unknown //IL_01f5: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Expected O, but got Unknown //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Expected O, but got Unknown //IL_03ce: Unknown result type (might be due to invalid IL or missing references) //IL_03d5: Expected O, but got Unknown Configs.Clear(); if (!Directory.Exists(ConfigFolderPath)) { Directory.CreateDirectory(ConfigFolderPath); } string pluginPath = Paths.PluginPath; List<string> list = new List<string>(); string[] files = Directory.GetFiles(ConfigFolderPath, "*MIS.json"); if (files.Length != 0) { list.AddRange(files); } else { string text = Path.Combine(ConfigFolderPath, "DefaultMIS.json"); ModConfig modConfig = new ModConfig(); modConfig.SaveToFile(text); list.Add(text); PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"Created default configuration file: DefaultMIS.json"); } bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val; try { string[] directories = Directory.GetDirectories(pluginPath, "*", SearchOption.AllDirectories); string[] array = directories; foreach (string text2 in array) { if (text2.Equals(ConfigFolderPath, StringComparison.OrdinalIgnoreCase)) { continue; } string[] files2 = Directory.GetFiles(text2, "*MIS.json"); if (files2.Length != 0) { list.AddRange(files2); ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; val = new BepInExInfoLogInterpolatedStringHandler(32, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Found "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(files2.Length); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" additional config(s) in: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(text2); } log.LogInfo(val); } } } catch (Exception ex) { ManualLogSource log2 = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error searching for config files: "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex.Message); } log2.LogError(val2); } foreach (string item in list) { try { ModConfig modConfig2 = ModConfig.LoadFromFile(item); if (modConfig2 != null) { Configs.Add(modConfig2); ManualLogSource log3 = PluginController<Plugin, IEmptyBindings>.Log; val = new BepInExInfoLogInterpolatedStringHandler(39, 3, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded configuration from "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Path.GetFileName(Path.GetDirectoryName(item))); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("/"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(Path.GetFileName(item)); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" with "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(modConfig2.SpawnRules.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" rules"); } log3.LogInfo(val); } } catch (Exception ex2) { ManualLogSource log4 = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val2 = new BepInExErrorLogInterpolatedStringHandler(28, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("Error loading config file "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(item); ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(ex2.Message); } log4.LogError(val2); } } triggeredRules.Clear(); foreach (ModConfig config in Configs) { foreach (SpawnRule spawnRule in config.SpawnRules) { triggeredRules[spawnRule.Name] = false; } } int num = 0; foreach (ModConfig config2 in Configs) { num += config2.SpawnRules.Count; } ManualLogSource log5 = PluginController<Plugin, IEmptyBindings>.Log; val = new BepInExInfoLogInterpolatedStringHandler(45, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Loaded "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(Configs.Count); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" configuration files with "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(" total rules"); } log5.LogInfo(val); } public void SaveConfig(ModConfig config, string fileName) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown string filePath = Path.Combine(ConfigFolderPath, fileName); config.SaveToFile(filePath); ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(23, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Configuration saved to "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(fileName); } log.LogInfo(val); } public void SaveDefaultConfig() { if (Configs.Count > 0) { SaveConfig(Configs[0], "DefaultMIS.json"); return; } ModConfig config = new ModConfig(); SaveConfig(config, "DefaultMIS.json"); } public void CheckRulesForEvent(string eventName, string murderType) { //IL_0258: Unknown result type (might be due to invalid IL or missing references) //IL_025f: Expected O, but got Unknown //IL_0793: Unknown result type (might be due to invalid IL or missing references) //IL_079a: Expected O, but got Unknown bool flag2 = default(bool); foreach (ModConfig config in Configs) { if (!config.Enabled) { continue; } foreach (SpawnRule item in config.SpawnRules.Where((SpawnRule r) => !r.RequiresPriorItem)) { if (!item.Enabled) { continue; } if (item.OnlySpawnOnce && spawnedItems.ContainsKey(item.Name) && spawnedItems[item.Name]) { Plugin.LogDebug($"Skipping rule '{item.Name}' for event '{eventName}' because the item has already been spawned (OnlySpawnOnce=true)"); continue; } if (item.OnlySpawnOnce) { bool flag = false; foreach (string triggerEvent in item.TriggerEvents) { string key = item.Name + "_" + triggerEvent; if (triggeredRules.ContainsKey(key) && triggeredRules[key]) { flag = true; break; } } if (flag) { Plugin.LogDebug($"Skipping rule '{item.Name}' for event '{eventName}' because it has already been triggered (OnlySpawnOnce=true)"); continue; } } if (!item.TriggerEvents.Contains(eventName) || (!string.IsNullOrEmpty(item.MurderMO) && !(item.MurderMO == murderType))) { continue; } if (config.ShowDebugMessages) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(49, 3, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' triggered by event '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(eventName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' with murder type '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(murderType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } log.LogInfo(val); } bool flag3 = true; if (item.RequiresMultipleTriggers && item.RequiredTriggerCount > 1) { string key2 = item.Name + "_" + eventName; int num = 0; if (triggerCounts.ContainsKey(key2)) { num = triggerCounts[key2]; } num++; triggerCounts[key2] = num; if (num < item.RequiredTriggerCount) { Plugin.LogDebug($"Rule '{item.Name}' for event '{eventName}' has been triggered {num}/{item.RequiredTriggerCount} times"); flag3 = false; } else { Plugin.LogDebug($"Rule '{item.Name}' for event '{eventName}' has reached required trigger count ({num}/{item.RequiredTriggerCount})"); } } bool flag4 = false; if (flag3) { flag4 = SpawnItem(item, eventName); } if (!flag4) { continue; } string key3 = item.Name + "_" + eventName; triggeredRules[key3] = true; Plugin.LogDebug($"Rule '{item.Name}' marked as triggered for event '{eventName}'"); if (!item.OnlySpawnOnce) { continue; } foreach (string triggerEvent2 in item.TriggerEvents) { if (!(triggerEvent2 == eventName)) { string key4 = item.Name + "_" + triggerEvent2; triggeredRules[key4] = true; Plugin.LogDebug($"Rule '{item.Name}' marked as triggered for event '{triggerEvent2}' (due to OnlySpawnOnce=true)"); } } } foreach (SpawnRule item2 in config.SpawnRules.Where((SpawnRule r) => r.RequiresPriorItem)) { if (!item2.Enabled) { continue; } if (item2.OnlySpawnOnce) { bool flag5 = false; foreach (string triggerEvent3 in item2.TriggerEvents) { string key5 = item2.Name + "_" + triggerEvent3; if (triggeredRules.ContainsKey(key5) && triggeredRules[key5]) { flag5 = true; break; } } if (flag5) { Plugin.LogDebug($"Skipping rule '{item2.Name}' for event '{eventName}' because it has already been triggered (OnlySpawnOnce=true)"); continue; } } if (!item2.TriggerEvents.Contains(eventName) || (!string.IsNullOrEmpty(item2.MurderMO) && !(item2.MurderMO == murderType))) { continue; } if (config.ShowDebugMessages) { ManualLogSource log2 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(49, 3, ref flag2); if (flag2) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(item2.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' triggered by event '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(eventName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' with murder type '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(murderType); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } log2.LogInfo(val); } bool flag6 = true; if (item2.RequiresMultipleTriggers && item2.RequiredTriggerCount > 1) { string key6 = item2.Name + "_" + eventName; int num2 = 0; if (triggerCounts.ContainsKey(key6)) { num2 = triggerCounts[key6]; } num2++; triggerCounts[key6] = num2; if (num2 < item2.RequiredTriggerCount) { Plugin.LogDebug($"Rule '{item2.Name}' for event '{eventName}' has been triggered {num2}/{item2.RequiredTriggerCount} times"); flag6 = false; } else { Plugin.LogDebug($"Rule '{item2.Name}' for event '{eventName}' has reached required trigger count ({num2}/{item2.RequiredTriggerCount})"); } } bool flag7 = false; if (flag6) { flag7 = SpawnItem(item2, eventName); } if (!flag7) { continue; } string key7 = item2.Name + "_" + eventName; triggeredRules[key7] = true; Plugin.LogDebug($"Rule '{item2.Name}' marked as triggered for event '{eventName}'"); if (!item2.OnlySpawnOnce) { continue; } foreach (string triggerEvent4 in item2.TriggerEvents) { if (!(triggerEvent4 == eventName)) { string key8 = item2.Name + "_" + triggerEvent4; triggeredRules[key8] = true; Plugin.LogDebug($"Rule '{item2.Name}' marked as triggered for event '{triggerEvent4}' (due to OnlySpawnOnce=true)"); } } } } } private bool SpawnItem(SpawnRule rule, string eventName = "") { //IL_0e64: Unknown result type (might be due to invalid IL or missing references) //IL_0e6b: Expected O, but got Unknown //IL_024d: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Expected O, but got Unknown //IL_02b9: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Expected O, but got Unknown //IL_08e4: Unknown result type (might be due to invalid IL or missing references) //IL_08eb: Expected O, but got Unknown //IL_0d07: Unknown result type (might be due to invalid IL or missing references) //IL_0d0e: Expected O, but got Unknown //IL_0d8f: Unknown result type (might be due to invalid IL or missing references) //IL_0d96: Expected O, but got Unknown //IL_0dfc: Unknown result type (might be due to invalid IL or missing references) //IL_0e03: Expected O, but got Unknown //IL_0aaf: Unknown result type (might be due to invalid IL or missing references) //IL_0ab6: Expected O, but got Unknown //IL_0b35: Unknown result type (might be due to invalid IL or missing references) //IL_0b3c: Expected O, but got Unknown bool flag = default(bool); try { if (rule.OnlySpawnOnce && spawnedItems.ContainsKey(rule.Name) && spawnedItems[rule.Name]) { Plugin.LogDebug("Skipping spawn for rule '" + rule.Name + "': Item has already been spawned once"); return false; } if (rule.RequiresPriorItem && !string.IsNullOrEmpty(rule.RequiredPriorItem)) { if (!spawnedItems.ContainsKey(rule.RequiredPriorItem) || !spawnedItems[rule.RequiredPriorItem]) { Plugin.LogDebug($"Skipping spawn for rule '{rule.Name}': Required prior item '{rule.RequiredPriorItem}' has not been spawned yet"); return false; } if (rule.RequiresSeparateTrigger && !string.IsNullOrEmpty(eventName) && itemSpawnEvents.ContainsKey(rule.RequiredPriorItem) && itemSpawnEvents[rule.RequiredPriorItem] == eventName) { Plugin.LogDebug($"Skipping spawn for rule '{rule.Name}': Required prior item '{rule.RequiredPriorItem}' was spawned in the same event ('{eventName}') and RequiresSeparateTrigger is true"); return false; } Plugin.LogDebug($"Required prior item '{rule.RequiredPriorItem}' found, proceeding with spawn for rule '{rule.Name}'"); } Human owner = GetOwner(rule.BelongsTo); if ((Object)(object)owner == (Object)null) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(51, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cannot spawn item for rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': No valid owner found"); } log.LogInfo(val); return false; } Human recipient = GetRecipient(rule.Recipient); if ((Object)(object)recipient == (Object)null) { ManualLogSource log2 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(55, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cannot spawn item for rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': No valid recipient found"); } log2.LogInfo(val); return false; } if (rule.UseTraits && rule.TraitModifiers != null && rule.TraitModifiers.Count > 0) { Plugin.LogDebug("Checking trait matching for rule '" + rule.Name + "'..."); bool flag2 = true; foreach (TraitModifier traitModifier in rule.TraitModifiers) { Human val2 = null; switch (traitModifier.Who) { case BelongsTo.Murderer: { MurderController instance2 = MurderController.Instance; val2 = ((instance2 != null) ? instance2.currentMurderer : null); break; } case BelongsTo.Victim: { MurderController instance6 = MurderController.Instance; val2 = ((instance6 != null) ? instance6.currentVictim : null); break; } case BelongsTo.Player: val2 = (Human)(object)Player.Instance; break; case BelongsTo.MurdererDoctor: { MurderController instance3 = MurderController.Instance; if ((Object)(object)((instance3 != null) ? instance3.currentMurderer : null) != (Object)null) { val2 = MurderController.Instance.currentMurderer.GetDoctor(); } break; } case BelongsTo.VictimDoctor: { MurderController instance4 = MurderController.Instance; if ((Object)(object)((instance4 != null) ? instance4.currentVictim : null) != (Object)null) { val2 = MurderController.Instance.currentVictim.GetDoctor(); } break; } case BelongsTo.MurdererLandlord: { MurderController instance5 = MurderController.Instance; if ((Object)(object)((instance5 != null) ? instance5.currentMurderer : null) != (Object)null) { val2 = MurderController.Instance.currentMurderer.GetLandlord(); } break; } case BelongsTo.VictimLandlord: { MurderController instance = MurderController.Instance; if ((Object)(object)((instance != null) ? instance.currentVictim : null) != (Object)null) { val2 = MurderController.Instance.currentVictim.GetLandlord(); } break; } default: Plugin.LogDebug($"Unknown trait modifier Who value: {traitModifier.Who}"); break; } if ((Object)(object)val2 == (Object)null) { Plugin.LogDebug($"Cannot check traits: Human not found for {traitModifier.Who}"); flag2 = false; break; } if (!CheckTraitMatch(val2, traitModifier)) { Plugin.LogDebug($"Trait matching failed for {traitModifier.Who}"); flag2 = false; break; } } if (!flag2) { Plugin.LogDebug("Skipping spawn for rule '" + rule.Name + "': Trait matching failed"); return false; } Plugin.LogDebug("All trait modifiers matched for rule '" + rule.Name + "', proceeding with spawn"); } if (rule.UseJobModifiers && rule.JobModifiers != null && rule.JobModifiers.Count > 0) { Plugin.LogDebug("Checking job matching for rule '" + rule.Name + "'..."); bool flag3 = true; foreach (JobModifier jobModifier in rule.JobModifiers) { Human val3 = null; switch (jobModifier.Who) { case BelongsTo.Murderer: { MurderController instance8 = MurderController.Instance; val3 = ((instance8 != null) ? instance8.currentMurderer : null); break; } case BelongsTo.Victim: { MurderController instance12 = MurderController.Instance; val3 = ((instance12 != null) ? instance12.currentVictim : null); break; } case BelongsTo.Player: val3 = (Human)(object)Player.Instance; break; case BelongsTo.MurdererDoctor: { MurderController instance9 = MurderController.Instance; if ((Object)(object)((instance9 != null) ? instance9.currentMurderer : null) != (Object)null) { val3 = MurderController.Instance.currentMurderer.GetDoctor(); } break; } case BelongsTo.VictimDoctor: { MurderController instance10 = MurderController.Instance; if ((Object)(object)((instance10 != null) ? instance10.currentVictim : null) != (Object)null) { val3 = MurderController.Instance.currentVictim.GetDoctor(); } break; } case BelongsTo.MurdererLandlord: { MurderController instance11 = MurderController.Instance; if ((Object)(object)((instance11 != null) ? instance11.currentMurderer : null) != (Object)null) { val3 = MurderController.Instance.currentMurderer.GetLandlord(); } break; } case BelongsTo.VictimLandlord: { MurderController instance7 = MurderController.Instance; if ((Object)(object)((instance7 != null) ? instance7.currentVictim : null) != (Object)null) { val3 = MurderController.Instance.currentVictim.GetLandlord(); } break; } default: Plugin.LogDebug($"Unknown job modifier Who value: {jobModifier.Who}"); break; } if ((Object)(object)val3 == (Object)null) { Plugin.LogDebug($"Cannot check job: Human not found for {jobModifier.Who}"); flag3 = false; break; } if (!CheckJobMatch(val3, jobModifier)) { Plugin.LogDebug($"Job matching failed for {jobModifier.Who}"); flag3 = false; break; } } if (!flag3) { Plugin.LogDebug("Skipping spawn for rule '" + rule.Name + "': Job matching failed"); return false; } Plugin.LogDebug("All job modifiers matched for rule '" + rule.Name + "', proceeding with spawn"); } Interactable spawnLocation = GetSpawnLocation(rule, owner, recipient); if (spawnLocation == null && rule.SpawnLocation == SpawnLocationType.Mailbox) { ManualLogSource log3 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(60, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Cannot spawn item for rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("': No valid spawn location found"); } log3.LogInfo(val); return false; } if (rule.SpawnLocation == SpawnLocationType.HomeBuildingEntrance) { } switch (rule.SpawnLocation) { case SpawnLocationType.Mailbox: SpawnItemMailbox.SpawnItemAtLocation(owner, recipient, spawnLocation, GetRandomItemToSpawn(rule), rule.UnlockMailbox, rule.SpawnChance); break; case SpawnLocationType.Doormat: SpawnItemDoormat.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.UseMultipleOwners, rule.Owners); break; case SpawnLocationType.HomeLobby: SpawnItemLobbyHome.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.UseMultipleOwners, rule.Owners); break; case SpawnLocationType.WorkplaceLobby: SpawnItemLobbyWork.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.SubLocationTypeBuildingEntrances, rule.UseMultipleOwners, rule.Owners); break; case SpawnLocationType.HomeBuildingEntrance: SpawnItemBuildingEntranceHome.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.SubLocationTypeBuildingEntrances); break; case SpawnLocationType.WorkplaceBuildingEntrance: SpawnItemBuildingEntranceWorkplace.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.SubLocationTypeBuildingEntrances); break; case SpawnLocationType.HotelRooftopBar: SpawnItemHotelRooftopBar.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.HotelRooftopBarSubLocations); break; case SpawnLocationType.Random: { if (rule.RandomSpawnLocations == null || rule.RandomSpawnLocations.Count == 0) { ManualLogSource log5 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(93, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[ConfigManager] Random spawn location selected but no RandomSpawnLocations defined in rule '"); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("'"); } log5.LogWarning(val4); return false; } int index = Random.Range(0, rule.RandomSpawnLocations.Count); string text = rule.RandomSpawnLocations[index]; if (!Enum.TryParse<SpawnLocationType>(text, out var result)) { ManualLogSource log6 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val4 = new BepInExWarningLogInterpolatedStringHandler(58, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[ConfigManager] Invalid random location name '"); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(text); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("' in rule '"); ((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("'"); } log6.LogWarning(val4); return false; } SpawnRule rule2 = new SpawnRule { Name = rule.Name + "_Random", ItemsToSpawn = rule.ItemsToSpawn, BelongsTo = rule.BelongsTo, Recipient = rule.Recipient, SpawnLocation = result, SpawnChance = rule.SpawnChance, UnlockMailbox = rule.UnlockMailbox, SubLocationTypeBuildingEntrances = rule.SubLocationTypeBuildingEntrances }; return SpawnItem(rule2); } case SpawnLocationType.CityHallBathroom: SpawnItemCityHallBathroom.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance); break; case SpawnLocationType.Custom: SpawnItemCustomBuilding.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.CustomRoomName, rule.CustomBuildingPreset, rule.CustomFloorNames, rule.CustomSubRoomName, rule.CustomRoomPreset, rule.CustomSubRoomPreset, rule.CustomRoomNames, rule.CustomRoomPresets, rule.CustomSubRoomNames, rule.CustomSubRoomPresets, rule.UseFurniture, rule.FurniturePresets); break; case SpawnLocationType.Home: SpawnItemHome.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.CustomRoomName, rule.UseFurniture, rule.FurniturePresets); break; case SpawnLocationType.Workplace: SpawnItemWork.SpawnItemAtLocation(owner, recipient, GetRandomItemToSpawn(rule), rule.SpawnChance, rule.CustomRoomName, rule.UseFurniture, rule.FurniturePresets, rule.UseMultipleOwners, rule.Owners); break; default: { ManualLogSource log4 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(52, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Using mailbox spawner for location type by default: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<SpawnLocationType>(rule.SpawnLocation); } log4.LogInfo(val); if (spawnLocation != null) { SpawnItemMailbox.SpawnItemAtLocation(owner, recipient, spawnLocation, GetRandomItemToSpawn(rule), rule.UnlockMailbox, rule.SpawnChance); } break; } } if (rule.OnlySpawnOnce) { spawnedItems[rule.Name] = true; ManualLogSource log7 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(56, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Marked item from rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' as spawned (OnlySpawnOnce=true)"); } log7.LogInfo(val); } if (!string.IsNullOrEmpty(eventName)) { itemSpawnEvents[rule.Name] = eventName; ManualLogSource log8 = PluginController<Plugin, IEmptyBindings>.Log; BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(41, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Item from rule '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(rule.Name); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' was spawned by event '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(eventName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("'"); } log8.LogInfo(val); } return true; } catch (Exception ex) { ManualLogSource log9 = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val5 = new BepInExErrorLogInterpolatedStringHandler(21, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("Error spawning item: "); ((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(ex.Message); } log9.LogError(val5); return false; } } private Human GetOwner(BelongsTo belongsTo) { return GetOwnerForFingerprint(belongsTo); } public Human GetOwnerForFingerprint(BelongsTo belongsTo) { switch (belongsTo) { case BelongsTo.Murderer: return MurderController.Instance.currentMurderer; case BelongsTo.Victim: return MurderController.Instance.currentVictim; case BelongsTo.Player: return (Human)(object)Player.Instance; case BelongsTo.MurdererDoctor: return MurderController.Instance.currentMurderer.GetDoctor(); case BelongsTo.VictimDoctor: return MurderController.Instance.currentVictim.GetDoctor(); case BelongsTo.MurdererLandlord: return MurderController.Instance.currentMurderer.GetLandlord(); case BelongsTo.VictimLandlord: return MurderController.Instance.currentVictim.GetLandlord(); case BelongsTo.Random: if (Random.Range(0f, 1f) > 0.5f) { return MurderController.Instance.currentMurderer; } return MurderController.Instance.currentVictim; default: return MurderController.Instance.currentMurderer; } } private Human GetRecipient(Recipient recipient) { switch (recipient) { case Recipient.Murderer: return MurderController.Instance.currentMurderer; case Recipient.Victim: return MurderController.Instance.currentVictim; case Recipient.Player: return (Human)(object)Player.Instance; case Recipient.MurdererDoctor: return MurderController.Instance.currentMurderer.GetDoctor(); case Recipient.VictimDoctor: return MurderController.Instance.currentVictim.GetDoctor(); case Recipient.MurdererLandlord: return MurderController.Instance.currentMurderer.GetLandlord(); case Recipient.VictimLandlord: return MurderController.Instance.currentVictim.GetLandlord(); case Recipient.Random: if (Random.Range(0f, 1f) > 0.5f) { return MurderController.Instance.currentMurderer; } return MurderController.Instance.currentVictim; default: return MurderController.Instance.currentMurderer; } } private Interactable GetSpawnLocation(SpawnRule rule, Human belongsTo, Human recipient) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown switch (rule.SpawnLocation) { case SpawnLocationType.Mailbox: return Toolbox.Instance.GetMailbox(recipient); case SpawnLocationType.Doormat: { if ((Object)(object)recipient != (Object)null && (Object)(object)recipient.home != (Object)null) { return null; } ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(84, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[ConfigManager] Cannot spawn item in doormat: Recipient or home address is null for "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>((recipient != null) ? ((Object)recipient).name : null); } log.LogWarning(val); return null; } case SpawnLocationType.HomeLobby: if ((Object)(object)recipient != (Object)null && (Object)(object)recipient.home != (Object)null) { return null; } return null; case SpawnLocationType.HomeBuildingEntrance: if ((Object)(object)recipient != (Object)null && (Object)(object)recipient.home != (Object)null) { return null; } return null; case SpawnLocationType.WorkplaceBuildingEntrance: if ((Object)(object)belongsTo != (Object)null && belongsTo.job != null && belongsTo.job.employer != null && (Object)(object)belongsTo.job.employer.address != (Object)null) { return null; } return null; case SpawnLocationType.CityHallBathroom: if ((Object)(object)belongsTo != (Object)null) { return null; } return null; case SpawnLocationType.HotelRooftopBar: if ((Object)(object)belongsTo != (Object)null) { return null; } return null; case SpawnLocationType.Random: return null; default: return null; } } public void ResetTriggeredRules() { triggeredRules.Clear(); foreach (ModConfig config in Configs) { foreach (SpawnRule spawnRule in config.SpawnRules) { triggeredRules[spawnRule.Name] = false; } } } private bool CheckTraitMatch(Human human, TraitModifier traitModifier) { if ((Object)(object)human == (Object)null || human.characterTraits == null || human.characterTraits.Count == 0) { Plugin.LogDebug("Cannot check traits: Human is null or has no traits"); return false; } Plugin.LogDebug("Checking traits for " + ((Object)human).name + ":"); Enumerator<Trait> enumerator = human.characterTraits.GetEnumerator(); while (enumerator.MoveNext()) { Trait current = enumerator.Current; if (current != null) { Plugin.LogDebug("- " + current.name); } } List<string> list = new List<string>(); Enumerator<Trait> enumerator2 = human.characterTraits.GetEnumerator(); while (enumerator2.MoveNext()) { Trait current2 = enumerator2.Current; if (current2 != null) { list.Add(current2.name); } } if (traitModifier.Rule == TraitRule.IfAnyOfThese) { foreach (string trait in traitModifier.TraitList) { if (list.Contains(trait)) { Plugin.LogDebug("Found matching trait: " + trait); return true; } } Plugin.LogDebug("No matching traits found for IfAnyOfThese rule"); return false; } if (traitModifier.Rule == TraitRule.IfAllOfThese) { foreach (string trait2 in traitModifier.TraitList) { if (!list.Contains(trait2)) { Plugin.LogDebug("Missing required trait: " + trait2); return false; } } Plugin.LogDebug("All required traits found for IfAllOfThese rule"); return true; } if (traitModifier.Rule == TraitRule.IfNoneOfThese) { foreach (string trait3 in traitModifier.TraitList) { if (list.Contains(trait3)) { Plugin.LogDebug("Found excluded trait: " + trait3); return false; } } Plugin.LogDebug("No excluded traits found for IfNoneOfThese rule"); return true; } Plugin.LogDebug($"Unknown trait rule: {traitModifier.Rule}"); return false; } private string GetRandomItemToSpawn(SpawnRule rule) { if (rule == null || rule.ItemsToSpawn == null || rule.ItemsToSpawn.Count == 0) { return string.Empty; } if (rule.ItemsToSpawn.Count == 1) { return rule.ItemsToSpawn[0]; } int index = Random.Range(0, rule.ItemsToSpawn.Count); string text = rule.ItemsToSpawn[index]; Plugin.LogDebug($"Randomly selected item '{text}' from {rule.ItemsToSpawn.Count} possible items for rule '{rule.Name}'"); return text; } private bool CheckJobMatch(Human human, JobModifier jobModifier) { if ((Object)(object)human == (Object)null || human.job == null) { Plugin.LogDebug("Cannot check job: Human is null or has no job"); return false; } string name = human.job.name; string text = (((SoCustomComparison)(object)human.job.preset != (SoCustomComparison)null) ? ((Object)human.job.preset).name : ""); Plugin.LogDebug("Checking job for " + ((Object)human).name + ":"); Plugin.LogDebug("- Job name: " + name); Plugin.LogDebug("- Job preset name: " + text); if (jobModifier.Rule == JobRule.IfAnyOfThese) { foreach (string job in jobModifier.JobList) { if (name == job || text == job) { Plugin.LogDebug("Found matching job: " + job); return true; } } Plugin.LogDebug("No matching jobs found for IfAnyOfThese rule"); return false; } if (jobModifier.Rule == JobRule.IfNoneOfThese) { foreach (string job2 in jobModifier.JobList) { if (name == job2 || text == job2) { Plugin.LogDebug("Found excluded job: " + job2); return false; } } Plugin.LogDebug("No excluded jobs found for IfNoneOfThese rule"); return true; } Plugin.LogDebug($"Unknown job rule: {jobModifier.Rule}"); return false; } } public static class CoroutineHelper { public static void StartCoroutine(IEnumerator routine) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown try { RuntimeHelper.StartCoroutine(routine); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error starting coroutine: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } public static IEnumerator WaitForSeconds(float seconds) { float startTime = Time.time; while (Time.time - startTime < seconds) { yield return null; } } public static IEnumerator DelayedAction(float seconds, Action action) { yield return WaitForSeconds(seconds); action?.Invoke(); } } public class ModConfig { public static ModConfig Instance { get; set; } public bool Enabled { get; set; } = true; public bool ShowDebugMessages { get; set; } = true; public List<SpawnRule> SpawnRules { get; set; } = new List<SpawnRule>(); public ModConfig() { SpawnRules.Add(new SpawnRule { Name = "Default Pencil in Mailbox", Enabled = true, MurderMO = "ExampleMO", TriggerEvents = new List<string> { "OnVictimKilled" }, ItemToSpawn = "Pencil", SpawnLocation = SpawnLocationType.Mailbox, BelongsTo = BelongsTo.Murderer, Recipient = Recipient.Victim, SpawnChance = 1f, UnlockMailbox = true, SubLocationTypeBuildingEntrances = SubLocationTypeBuildingEntrances.Inside, RandomSpawnLocations = new List<string> { "Doormat", "Lobby", "BuildingEntrance", "WorkplaceBuildingEntrance" }, HotelRooftopBarSubLocations = new List<string> { "RooftopBar", "BarDiningRoom" } }); } public void SaveToFile(string filePath) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown try { JsonSerializerOptions options = new JsonSerializerOptions { WriteIndented = true }; string contents = JsonSerializer.Serialize(this, options); File.WriteAllText(filePath, contents); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to save configuration: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } public static ModConfig LoadFromFile(string filePath) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown try { if (File.Exists(filePath)) { string json = File.ReadAllText(filePath); return JsonSerializer.Deserialize<ModConfig>(json); } } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Failed to load configuration: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } return new ModConfig(); } } [Serializable] public class Vector3Serializable { public float X { get; set; } public float Y { get; set; } public float Z { get; set; } public Vector3Serializable() { } public Vector3Serializable(float x, float y, float z) { X = x; Y = y; Z = z; } public Vector3 ToVector3() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) return new Vector3(X, Y, Z); } public static Vector3Serializable FromVector3(Vector3 vector) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) return new Vector3Serializable(vector.x, vector.y, vector.z); } } public enum SpawnLocationType { Mailbox, Doormat, HomeLobby, WorkplaceLobby, HomeBuildingEntrance, WorkplaceBuildingEntrance, CityHallBathroom, HotelRooftopBar, Home, Workplace, Random, Custom } public enum SubLocationTypeBuildingEntrances { Inside, Outside } public enum BelongsTo { Murderer, Victim, Player, MurdererDoctor, VictimDoctor, MurdererLandlord, VictimLandlord, Random } public enum Recipient { Murderer, Victim, Player, MurdererDoctor, VictimDoctor, MurdererLandlord, VictimLandlord, Random } public enum TraitRule { IfAnyOfThese, IfAllOfThese, IfNoneOfThese } public enum JobRule { IfAnyOfThese, IfNoneOfThese } [Serializable] public class TraitModifier { public BelongsTo Who { get; set; } = BelongsTo.Victim; public TraitRule Rule { get; set; } = TraitRule.IfAnyOfThese; public List<string> TraitList { get; set; } = new List<string>(); } [Serializable] public class JobModifier { public BelongsTo Who { get; set; } = BelongsTo.Victim; public JobRule Rule { get; set; } = JobRule.IfAnyOfThese; public List<string> JobList { get; set; } = new List<string>(); } [Serializable] public class SpawnRule { public string Name { get; set; } = "Unnamed Rule"; public bool Enabled { get; set; } = true; public List<string> TriggerEvents { get; set; } = new List<string>(); public string MurderMO { get; set; } = "ExampleMO"; public List<string> ItemsToSpawn { get; set; } = new List<string> { "Pencil" }; public string ItemToSpawn { get { if (ItemsToSpawn == null || ItemsToSpawn.Count == 0) { return "Pencil"; } return ItemsToSpawn[0]; } set { if (ItemsToSpawn == null) { ItemsToSpawn = new List<string>(); } ItemsToSpawn.Clear(); if (!string.IsNullOrEmpty(value)) { ItemsToSpawn.Add(value); } } } public SpawnLocationType SpawnLocation { get; set; } = SpawnLocationType.Mailbox; public BelongsTo BelongsTo { get; set; } = BelongsTo.Murderer; public Recipient Recipient { get; set; } = Recipient.Murderer; public int SpawnCount { get; set; } = 1; public float SpawnChance { get; set; } = 1f; public bool UnlockMailbox { get; set; } = true; public SubLocationTypeBuildingEntrances SubLocationTypeBuildingEntrances { get; set; } = SubLocationTypeBuildingEntrances.Inside; public List<string> RandomSpawnLocations { get; set; } = new List<string>(); public List<string> HotelRooftopBarSubLocations { get; set; } = new List<string>(); public string CustomBuildingPreset { get; set; } = ""; public string CustomRoomName { get; set; } = ""; public string CustomRoomPreset { get; set; } = ""; public string CustomSubRoomName { get; set; } = ""; public string CustomSubRoomPreset { get; set; } = ""; public List<string> CustomRoomNames { get; set; } = new List<string>(); public List<string> CustomRoomPresets { get; set; } = new List<string>(); public List<string> CustomSubRoomNames { get; set; } = new List<string>(); public List<string> CustomSubRoomPresets { get; set; } = new List<string>(); public List<string> CustomFloorNames { get; set; } = new List<string>(); public bool UseFurniture { get; set; } = false; public List<string> FurniturePresets { get; set; } = new List<string>(); public bool UseMultipleOwners { get; set; } = false; public List<BelongsTo> Owners { get; set; } = new List<BelongsTo>(); public bool OnlySpawnOnce { get; set; } = false; public bool RequiresPriorItem { get; set; } = false; public string RequiredPriorItem { get; set; } = ""; public bool RequiresSeparateTrigger { get; set; } = true; public bool RequiresMultipleTriggers { get; set; } = false; public int RequiredTriggerCount { get; set; } = 1; public bool UseTraits { get; set; } = false; public List<TraitModifier> TraitModifiers { get; set; } = new List<TraitModifier>(); public bool UseJobModifiers { get; set; } = false; public List<JobModifier> JobModifiers { get; set; } = new List<JobModifier>(); } [HarmonyPatch(typeof(MurderController), "OnVictimKilled")] public class OnVictimKilledPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("OnVictimKilled", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(30, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in OnVictimKilledPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "PickNewVictim")] public class PickNewVictimPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("PickNewVictim", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(29, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in PickNewVictimPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "OnVictimDiscovery")] public class OnVictimDiscoveryPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("OnVictimDiscovery", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in OnVictimDiscoveryPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "TriggerCoverUpTelephoneCall")] public class TriggerCoverUpTelephoneCallPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("TriggerCoverUpTelephoneCall", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(43, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in TriggerCoverUpTelephoneCallPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "OnCoverUpAccept")] public class OnCoverUpAcceptPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("OnCoverUpAccept", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(31, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in OnCoverUpAcceptPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "OnCoverUpReject")] public class OnCoverUpRejectPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("OnCoverUpReject", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(31, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in OnCoverUpRejectPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "TriggerKidnappingCase")] public class TriggerKidnappingCasePatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("TriggerKidnappingCase", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in TriggerKidnappingCasePatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "TriggerRansomDelivery")] public class TriggerRansomDeliveryPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("TriggerRansomDelivery", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(37, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in TriggerRansomDeliveryPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "KidnapperCollectsRansom")] public class KidnapperCollectsRansomPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("KidnapperCollectsRansom", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(39, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in KidnapperCollectsRansomPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "KidnapperCollectedRansom")] public class KidnapperCollectedRansomPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("KidnapperCollectedRansom", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in KidnapperCollectedRansomPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "TriggerRansomFail")] public class TriggerRansomFailPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("TriggerRansomFail", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(33, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in TriggerRansomFailPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "VictimFreed")] public class VictimFreedPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("VictimFreed", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in VictimFreedPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "OnCaseSolved")] public class OnCaseSolvedPatch { public static void Postfix() { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("OnCaseSolved", murderType); ConfigManager.Instance.ResetTracking(); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(28, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in OnCaseSolvedPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "CitizenHasSeenBody", new Type[] { typeof(Human), typeof(Human) })] public class CitizenHasSeenBodyPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("CitizenHasSeenBody", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(34, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in CitizenHasSeenBodyPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "CoverUpFailCheck", new Type[] { typeof(Human) })] public class CoverUpFailCheckPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("CoverUpFailCheck", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(32, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in CoverUpFailCheckPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [HarmonyPatch(typeof(MurderController), "TriggerSuccessfulCoverUp", new Type[] { typeof(Evidence) })] public class TriggerSuccessfulCoverUpPatch { public static void Postfix() { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown try { string murderType = ""; if ((Object)(object)MurderController.Instance != (Object)null && (SoCustomComparison)(object)MurderController.Instance.chosenMO != (SoCustomComparison)null) { murderType = ((Object)MurderController.Instance.chosenMO).name; } ConfigManager.Instance.CheckRulesForEvent("TriggerSuccessfulCoverUp", murderType); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(40, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in TriggerSuccessfulCoverUpPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } [BepInPlugin("ShaneeexD.MurderItemSpawner", "MurderItemSpawner", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : PluginController<Plugin> { public const string PLUGIN_GUID = "ShaneeexD.MurderItemSpawner"; public const string PLUGIN_NAME = "MurderItemSpawner"; public const string PLUGIN_VERSION = "1.0.0"; public static ConfigEntry<bool> showDebugLogs; public override void Load() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown ((PluginController<Plugin, IEmptyBindings>)(object)this).Harmony.PatchAll(Assembly.GetExecutingAssembly()); SaveGamerHandlers saveGamerHandlers = new SaveGamerHandlers(); PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"MurderItemSpawner plugin is patched."); showDebugLogs = base.Config.Bind<bool>("General", "ShowDebugLogs", false, new ConfigDescription("Show debug logs.", (AcceptableValueBase)null, Array.Empty<object>())); } public static void LogDebug(string message) { if (showDebugLogs != null && showDebugLogs.Value) { PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)message); } } } [HarmonyPatch(typeof(SessionData))] [HarmonyPatch("PauseGame")] public class PauseManager { public static void Prefix(ref bool showPauseText, ref bool delayOverride, ref bool openDesktopMode) { } } [HarmonyPatch(typeof(SessionData))] [HarmonyPatch("ResumeGame")] public class ResumeGameManager { public static void Prefix() { } } [Serializable] public class MurderItemSpawnerSaveData { public List<SavedItem> SpawnedItems = new List<SavedItem>(); public List<SavedItemEvent> ItemSpawnEvents = new List<SavedItemEvent>(); public List<SavedTriggeredRule> TriggeredRules = new List<SavedTriggeredRule>(); public string CurrentCaseId = ""; public void SetFromDictionaries(Dictionary<string, bool> spawnedItems, Dictionary<string, string> itemSpawnEvents, Dictionary<string, bool> triggeredRules, string caseId) { SpawnedItems.Clear(); foreach (KeyValuePair<string, bool> spawnedItem in spawnedItems) { SpawnedItems.Add(new SavedItem { RuleName = spawnedItem.Key, IsSpawned = spawnedItem.Value }); } ItemSpawnEvents.Clear(); foreach (KeyValuePair<string, string> itemSpawnEvent in itemSpawnEvents) { ItemSpawnEvents.Add(new SavedItemEvent { RuleName = itemSpawnEvent.Key, EventName = itemSpawnEvent.Value }); } TriggeredRules.Clear(); foreach (KeyValuePair<string, bool> triggeredRule in triggeredRules) { TriggeredRules.Add(new SavedTriggeredRule { RuleEventKey = triggeredRule.Key, IsTriggered = triggeredRule.Value }); } CurrentCaseId = caseId; } public void GetDictionaries(out Dictionary<string, bool> spawnedItems, out Dictionary<string, string> itemSpawnEvents, out Dictionary<string, bool> triggeredRules, out string caseId) { spawnedItems = new Dictionary<string, bool>(); foreach (SavedItem spawnedItem in SpawnedItems) { spawnedItems[spawnedItem.RuleName] = spawnedItem.IsSpawned; } itemSpawnEvents = new Dictionary<string, string>(); foreach (SavedItemEvent itemSpawnEvent in ItemSpawnEvents) { itemSpawnEvents[itemSpawnEvent.RuleName] = itemSpawnEvent.EventName; } triggeredRules = new Dictionary<string, bool>(); foreach (SavedTriggeredRule triggeredRule in TriggeredRules) { triggeredRules[triggeredRule.RuleEventKey] = triggeredRule.IsTriggered; } caseId = CurrentCaseId; } } [Serializable] public class SavedItem { public string RuleName; public bool IsSpawned; } [Serializable] public class SavedItemEvent { public string RuleName; public string EventName; } [Serializable] public class SavedTriggeredRule { public string RuleEventKey; public bool IsTriggered; } public class SaveGamerHandlers : MonoBehaviour { public SaveGamerHandlers() { Lib.SaveGame.OnAfterLoad += HandleGameLoaded; Lib.SaveGame.OnAfterNewGame += HandleNewGameStarted; Lib.SaveGame.OnBeforeNewGame += HandleGameBeforeNewGame; Lib.SaveGame.OnBeforeLoad += HandleGameBeforeLoad; Lib.SaveGame.OnBeforeDelete += HandleGameBeforeDelete; Lib.SaveGame.OnAfterDelete += HandleGameAfterDelete; Lib.SaveGame.OnAfterSave += HandleGameSaved; } private void HandleNewGameStarted(object sender, EventArgs e) { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown try { PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"[HandleNewGameStarted] New game started, resetting configuration"); ConfigManager.Instance.ResetTriggeredRules(); ConfigManager.Instance.ResetTracking(); ConfigManager.Instance.LoadConfig(); ConfigManager.Instance.SaveTrackingData(); PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"[HandleNewGameStarted] New game tracking data initialized"); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(31, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in HandleNewGameStarted: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } private void HandleGameLoaded(object sender, EventArgs e) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown try { ConfigManager.Instance.LoadConfig(); ConfigManager.Instance.LoadTrackingData(); PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"[HandleGameLoaded] Game loaded, tracking data loaded"); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(27, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in HandleGameLoaded: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } private void HandleGameBeforeNewGame(object sender, EventArgs e) { } private void HandleGameBeforeLoad(object sender, EventArgs e) { } private void HandleGameBeforeDelete(object sender, EventArgs e) { } private void HandleGameAfterDelete(object sender, EventArgs e) { } private void HandleGameSaved(object sender, EventArgs e) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown try { ConfigManager.Instance.SaveTrackingData(); PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"[HandleGameSaved] Game saved, tracking data saved"); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(26, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in HandleGameSaved: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } private void HandleConfig(object sender, EventArgs e) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Expected O, but got Unknown try { PluginController<Plugin, IEmptyBindings>.Log.LogInfo((object)"[HandleConfig] New game started, resetting configuration"); ConfigManager.Instance.ResetTriggeredRules(); ConfigManager.Instance.LoadConfig(); } catch (Exception ex) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; bool flag = default(bool); BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(25, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Error in GameStartPatch: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log.LogError(val); } } } public class SpawnItemBuildingEntranceHome : MonoBehaviour { private static SpawnItemBuildingEntranceHome _instance; private static Vector3 spawnPosition; private static SpawnItemBuildingEntranceHome Instance { get { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)_instance == (Object)null) { GameObject val = new GameObject("SpawnItemBuildingEntranceHome_Instance"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent<SpawnItemBuildingEntranceHome>(); } return _instance; } } public static void SpawnItemAtLocation(Human owner, Human recipient, string presetName, float spawnChance, SubLocationTypeBuildingEntrances subLocationTypeBuildingEntrances, bool useMultipleOwners = false, List<BelongsTo> owners = null) { //IL_03b2: Unknown result type (might be due to invalid IL or missing references) //IL_03b9: Expected O, but got Unknown //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Expected O, but got Unknown //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_0109: Unknown result type (might be due to invalid IL or missing references) //IL_0110: Expected O, but got Unknown //IL_0364: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Expected O, but got Unknown //IL_033c: Unknown result type (might be due to invalid IL or missing references) bool flag = default(bool); try { float num = Random.Range(0f, 1f); if (num > spawnChance) { Plugin.LogDebug($"[SpawnItemBuildingEntrance] Skipping spawn of {presetName} due to chance (roll: {num}, needed: <= {spawnChance})"); return; } InteractablePreset interactablePreset = Toolbox.Instance.GetInteractablePreset(presetName); if ((SoCustomComparison)(object)interactablePreset == (SoCustomComparison)null) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(73, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Could not find interactable preset with name "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(presetName); } log.LogError(val); return; } if ((Object)(object)recipient == (Object)null || (Object)(object)recipient.home == (Object)null) { ManualLogSource log2 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val2 = new BepInExWarningLogInterpolatedStringHandler(73, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("[SpawnItemBuildingEntrance] Recipient has no valid address. Cannot spawn "); ((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>(presetName); } log2.LogWarning(val2); return; } NewAddress home = recipient.home; Plugin.LogDebug($"[SpawnItemBuildingEntrance] Owner: {((Object)owner).name}, Recipient: {((Object)recipient).name}, Address: {((Object)home).name}"); Interactable val3 = SpawnItemAtBuildingEntrance(home, interactablePreset, owner, recipient, presetName, spawnChance, subLocationTypeBuildingEntrances); if (val3 != null) { if (useMultipleOwners && owners != null && owners.Count > 0) { val3.SetOwner(owner, true); foreach (BelongsTo owner2 in owners) { Human ownerForFingerprint = ConfigManager.Instance.GetOwnerForFingerprint(owner2); if ((Object)(object)ownerForFingerprint != (Object)null) { Plugin.LogDebug($"[SpawnItemBuildingEntrance] Adding fingerprint for {owner2}"); val3.AddNewDynamicFingerprint(ownerForFingerprint, (PrintLife)0); } else { Plugin.LogDebug($"[SpawnItemBuildingEntrance] Could not add fingerprint for {owner2} - Human not found"); } } Plugin.LogDebug("[SpawnItemBuildingEntrance] Successfully added multiple owners to '" + presetName + "'"); } else { val3.SetOwner(owner, true); } Plugin.LogDebug("[SpawnItemBuildingEntrance] Successfully spawned '" + presetName + "' at building entrance. Item node: " + ((val3.node != null) ? ((Object)val3.node).ToString() : "null")); Plugin.LogDebug($"[SpawnItemBuildingEntrance] Item '{presetName}' final world position: {val3.wPos}"); } else { ManualLogSource log3 = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(74, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Failed to create item '"); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(presetName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("' at building entrance."); } log3.LogError(val); } } catch (Exception ex) { ManualLogSource log4 = PluginController<Plugin, IEmptyBindings>.Log; BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(50, 2, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Error spawning item "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(presetName); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral(": "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message); } log4.LogError(val); ManualLogSource log5 = PluginController<Plugin, IEmptyBindings>.Log; val = new BepInExErrorLogInterpolatedStringHandler(41, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Stack trace: "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.StackTrace); } log5.LogError(val); } } private static Interactable SpawnItemAtBuildingEntrance(NewAddress address, InteractablePreset itemPreset, Human owner, Human recipient, string itemNameForLog, float spawnChance, SubLocationTypeBuildingEntrances subLocationTypeBuildingEntrances) { //IL_0a1e: Unknown result type (might be due to invalid IL or missing references) //IL_0a25: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0a5b: Unknown result type (might be due to invalid IL or missing references) //IL_0a62: Expected O, but got Unknown //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Expected O, but got Unknown //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_0502: Expected O, but got Unknown //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Expected O, but got Unknown //IL_04ba: Unknown result type (might be due to invalid IL or missing references) //IL_04c1: Expected O, but got Unknown //IL_06cf: Unknown result type (might be due to invalid IL or missing references) //IL_0703: Unknown result type (might be due to invalid IL or missing references) //IL_0708: Unknown result type (might be due to invalid IL or missing references) //IL_0710: Unknown result type (might be due to invalid IL or missing references) //IL_0716: Unknown result type (might be due to invalid IL or missing references) //IL_071b: Unknown result type (might be due to invalid IL or missing references) //IL_0720: Unknown result type (might be due to invalid IL or missing references) //IL_0724: Unknown result type (might be due to invalid IL or missing references) //IL_0729: Unknown result type (might be due to invalid IL or missing references) //IL_072b: Unknown result type (might be due to invalid IL or missing references) //IL_072d: Unknown result type (might be due to invalid IL or missing references) //IL_067d: Unknown result type (might be due to invalid IL or missing references) //IL_0684: Expected O, but got Unknown //IL_073e: Unknown result type (might be due to invalid IL or missing references) //IL_0743: Unknown result type (might be due to invalid IL or missing references) //IL_0759: Unknown result type (might be due to invalid IL or missing references) //IL_075b: Unknown result type (might be due to invalid IL or missing references) //IL_075f: Unknown result type (might be due to invalid IL or missing references) //IL_0764: Unknown result type (might be due to invalid IL or missing references) //IL_0769: Unknown result type (might be due to invalid IL or missing references) //IL_084d: Unknown result type (might be due to invalid IL or missing references) //IL_0864: Unknown result type (might be due to invalid IL or missing references) //IL_0892: Unknown result type (might be due to invalid IL or missing references) //IL_08c1: Unknown result type (might be due to invalid IL or missing references) //IL_08cb: Expected O, but got Unknown //IL_07d1: Unknown result type (might be due to invalid IL or missing references) //IL_07d3: Unknown result type (might be due to invalid IL or missing references) //IL_07d7: Unknown result type (might be due to invalid IL or missing references) //IL_07dc: Unknown result type (might be due to invalid IL or missing references) //IL_07e1: Unknown result type (might be due to invalid IL or missing references) //IL_090a: Unknown result type (might be due to invalid IL or missing references) //IL_0928: Unknown result type (might be due to invalid IL or missing references) //IL_092d: Unknown result type (might be due to invalid IL or missing references) //IL_09e5: Unknown result type (might be due to invalid IL or missing references) //IL_09ec: Expected O, but got Unknown //IL_095a: Unknown result type (might be due to invalid IL or missing references) //IL_0986: Unknown result type (might be due to invalid IL or missing references) bool flag = default(bool); if ((Object)(object)address == (Object)null) { ManualLogSource log = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(49, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Address is null for "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(itemNameForLog); ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("."); } log.LogWarning(val); return null; } NewBuilding building = ((NewGameLocation)address).building; if ((Object)(object)building != (Object)null) { Plugin.LogDebug("[SpawnItemBuildingEntrance] Found building directly from address: " + ((Object)building).name); } else { Plugin.LogDebug("[SpawnItemBuildingEntrance] No building found directly from address, trying floor"); if (!((Object)(object)((NewGameLocation)address).floor != (Object)null)) { ManualLogSource log2 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(61, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Could not find floor for address "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)address).name); } log2.LogWarning(val); return null; } Plugin.LogDebug("[SpawnItemBuildingEntrance] Found floor for address " + ((Object)address).name); } NewWall val2 = null; NewWall val3 = null; if ((Object)(object)building != (Object)null && building.mainEntrance != null) { val3 = building.mainEntrance; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found main entrance directly from building"); } else if ((Object)(object)building != (Object)null && building.additionalEntrances != null && building.additionalEntrances.Count > 0) { Plugin.LogDebug($"[SpawnItemBuildingEntrance] Checking {building.additionalEntrances.Count} additional entrances from building"); Enumerator<NewWall> enumerator = building.additionalEntrances.GetEnumerator(); while (enumerator.MoveNext()) { NewWall current = enumerator.Current; if (current != null) { NewNode node = current.otherWall.node; if (node != null && (Object)(object)node.gameLocation != (Object)null && (Object)(object)node.gameLocation.thisAsStreet != (Object)null) { val3 = current; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found street entrance in building's additional entrances"); break; } } } } if (val3 == null && (Object)(object)((NewGameLocation)address).floor != (Object)null && ((NewGameLocation)address).floor.buildingEntrances != null && ((NewGameLocation)address).floor.buildingEntrances.Count > 0) { Plugin.LogDebug($"[SpawnItemBuildingEntrance] Checking {((NewGameLocation)address).floor.buildingEntrances.Count} entrances from floor"); Enumerator<NewWall> enumerator2 = ((NewGameLocation)address).floor.buildingEntrances.GetEnumerator(); while (enumerator2.MoveNext()) { NewWall current2 = enumerator2.Current; if (current2 != null) { NewNode node2 = current2.otherWall.node; if (node2 != null && (Object)(object)node2.gameLocation != (Object)null && (Object)(object)node2.gameLocation.thisAsStreet != (Object)null) { val3 = current2; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found street entrance in building entrances"); break; } } } } if (val3 == null) { List<NodeAccess> entrances = ((NewGameLocation)address).entrances; if (entrances == null || entrances.Count == 0) { ManualLogSource log3 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(51, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] No entrances found for "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)address).name); } log3.LogWarning(val); return null; } Enumerator<NodeAccess> enumerator3 = entrances.GetEnumerator(); while (enumerator3.MoveNext()) { NodeAccess current3 = enumerator3.Current; if (current3.wall != null) { NewNode node3 = current3.wall.otherWall.node; if (node3 != null && (Object)(object)node3.gameLocation != (Object)null && (Object)(object)node3.gameLocation.thisAsStreet != (Object)null) { val3 = current3.wall; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found street entrance from address entrances for " + ((Object)address).name); break; } } } } if (val3 != null) { val2 = val3; Plugin.LogDebug("[SpawnItemBuildingEntrance] Using main entrance to street for building"); } else { if (((NewGameLocation)address).entrances == null || ((NewGameLocation)address).entrances.Count <= 0) { ManualLogSource log4 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(70, 0, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] No entrances found for building or address"); } log4.LogWarning(val); return null; } val2 = ((NewGameLocation)address).entrances[0].wall; Plugin.LogDebug("[SpawnItemBuildingEntrance] No street entrance found, using first address entrance for " + ((Object)address).name); } if (val2 == null) { ManualLogSource log5 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(54, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Entrance wall is null for "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)address).name); } log5.LogWarning(val); return null; } Plugin.LogDebug("[SpawnItemBuildingEntrance] Using entrance for " + ((Object)address).name); NewNode node4 = val2.otherWall.node; bool flag2 = false; if (node4 != null && (Object)(object)node4.gameLocation != (Object)null) { if ((Object)(object)node4.gameLocation.thisAsStreet != (Object)null) { flag2 = true; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found street node on otherWall side for " + ((Object)address).name); } else if ((Object)(object)node4.gameLocation != (Object)(object)address) { flag2 = true; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found outside node on otherWall side for " + ((Object)address).name); } } if (!flag2) { node4 = val2.node; if (node4 != null && (Object)(object)node4.gameLocation != (Object)null) { if ((Object)(object)node4.gameLocation.thisAsStreet != (Object)null) { flag2 = true; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found street node on wall side for " + ((Object)address).name); } else if ((Object)(object)node4.gameLocation != (Object)(object)address) { flag2 = true; Plugin.LogDebug("[SpawnItemBuildingEntrance] Found outside node on wall side for " + ((Object)address).name); } } } if (!flag2) { ManualLogSource log6 = PluginController<Plugin, IEmptyBindings>.Log; BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(83, 1, ref flag); if (flag) { ((BepInExLogInterpolatedStringHandler)val).AppendLiteral("[SpawnItemBuildingEntrance] Could not find a valid street node for the entrance of "); ((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)address).name); } log6.LogWarning(val); return null; } Plugin.LogDebug($"[SpawnItemBuildingEntrance] Found entrance node at {node4.nodeCoord} for {((Object)address).name}"); Vector3 position = node4.position; Vector3 val4 = val2.otherWall.position - val2.position; Vector3 val5 = ((Vector3)(ref val4)).normalized; if (val5 == Vector3.zero) { val5 = Vector3.forward; } switch (subLocationTypeBuildingEntrances) { case SubLocationTypeBuildingEntrances.Inside: { float num2 = -2f; spawnPosition = position + val5 * num2; spawnPosition.y += 0f; spawnPosition.z += Random.Range(-0.5f, 0.5f); spawnPosition.x += Random.Range(-0.5f, 0.5f); break; } case SubLocationTypeBuildingEntrances.Outside: { float num = 1f; spawnPosition = position + val5 * num; spawnPosition.y += 0.05f; spawnPosition.z += Random.Range(-0.5f, 0.5f); spawnPosition.x += Random.Range(-0.5f, 0.3f); break; } } Plugin.LogDebug($"[SpawnItemBuildingEntrance] Entrance position: {position}, Wall direction: {val5}"); Plugin.LogDebug($"[SpawnItemBuildingEntrance] Calculated spawn position: {spawnPosition}"); List<Passed> val6 = new List<Passed>(); val6.Add(new Passed((PassedVarType)3, (float)node4.room.roomID, (string)null)); try { float num3 = Random.Range(0f, 360f); Vector3 val7 = default(Vector3); ((Vector3)(ref val7))..ctor(0f, num3, 0f); Plugin.LogDebug($"[SpawnItemBuildingEntrance] Using random rotation: {val7}"); Interactable val8 = InteractableCreator.Instance.CreateWorldInteractable(itemPreset, owner, owner, recipient, spawnPosition, val7, val6, (Object)null, ""); if (val8 != null) { val8.node = node4; val8.UpdateWorldPositionAndNode(true, true); Plugin.LogDebug("[SpawnItemBuildingEntrance] Successfully created item at building entrance"); Plugin.LogDebug($"[SpawnItemBuildingEntrance] Item position: {val8.wPos}, node: {((val8.node != null