using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
using BepInEx;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem.Collections.Generic;
using Rewired;
using SOD.Common;
using SOD.Common.BepInEx;
using SOD.Common.BepInEx.Configuration;
using SOD.Common.Extensions;
using SOD.Common.Helpers;
using SOD.QoL.Objects;
using SOD.QoL.Patches;
using UnityEngine;
using UnityEngine.UI;
using UniverseLib;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SOD.QoL")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+9e4b5c64ffebce151406b3e28ce732d42c57bdc4")]
[assembly: AssemblyProduct("SOD.QoL")]
[assembly: AssemblyTitle("SOD.QoL")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace SOD.QoL
{
public interface IPluginBindings : IConversationBindings, IMainMenuBindings, IMapBindings, IGameplayPatchBindings, IJobExpirationBindings
{
}
public interface IGameplayPatchBindings
{
[Binding(true, "Fixes the player never getting tired.", "QoL.Gameplay.FixTiredness")]
bool FixTiredness { get; set; }
[Binding(12, "The percentage that is taken of alertness and added to energy restore for caffeine items. (12 seems balanced)", "QoL.Gameplay.PercentageEnergyRestore")]
int PercentageEnergyRestore { get; set; }
}
public interface IJobExpirationBindings
{
[Binding(true, "Side jobs and LostAndFound jobs will automatically expire after some in-game hours to prevent stale evidence. (accepted side jobs are excluded)", "QoL.Gameplay.AutoExpireJobs")]
bool AutoExpireJobs { get; set; }
[Binding(true, "Should the expire time be randomized for more immersion in the game world? (If false, it will take ExpireTimeMax)", "QoL.Gameplay.RandomizeExpireTime")]
bool RandomizeExpireTime { get; set; }
[Binding(24, "The minimum time for expiration to occur.", "QoL.Gameplay.ExpireTimeMin")]
int ExpireTimeMin { get; set; }
[Binding(48, "The maximum time for expiration to occur.", "QoL.Gameplay.ExpireTimeMax")]
int ExpireTimeMax { get; set; }
}
public interface IConversationBindings
{
[Binding(true, "Allow ending conversations with menu key", "QoL.Conversations.CanEndWithMenuKey")]
bool EndConversationPatch { get; set; }
}
public interface IMainMenuBindings
{
[Binding(true, "Resume the game from paused state when exiting the mainmenu with menu key", "QoL.MainMenu.UnpauseGameWithMenuKey")]
bool UnpauseGameOnMainMenuExit { get; set; }
[Binding(true, "Skips the press any key screen at the start of the game if no joysticks are connected.", "QoL.MainMenu.SkipPressAnyKeyScreenIfNotUsingJoysticks")]
bool SkipPressAnyKeyScreenIfNotUsingJoysticks { get; set; }
}
public interface IMapBindings
{
[Binding(true, "Fixes the center on player after zooming and moving the camera.", "QoL.Map.FixCenterOnPlayer")]
bool FixCenterOnPlayer { get; set; }
[Binding(true, "Zooms the minimap out by default?", "QoL.Map.ZoomOutOnStart")]
bool ZoomOutOnStart { get; set; }
[Binding(true, "Enlarge player marker?", "QoL.Map.EnlargePlayerMarker")]
bool EnlargePlayerMarker { get; set; }
[Binding("(2.5, 2.5)", "Player marker size. Game default: (1,1)", "QoL.Map.PlayerMarkerSize")]
string PlayerMarkerSize { get; set; }
[Binding(true, "Change player marker color?", "QoL.Map.ChangePlayerMarkerColor")]
bool ChangePlayerMarkerColor { get; set; }
[Binding("#008000", "The hex color code for the player marker, default: Green", "QoL.Map.PlayerMarkerColor")]
string PlayerMarkerColor { get; set; }
}
[BepInPlugin("Venomaus.SOD.QoL", "QoL", "1.1.5")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : PluginController<Plugin, IPluginBindings>
{
public const string PLUGIN_GUID = "Venomaus.SOD.QoL";
public const string PLUGIN_NAME = "QoL";
public const string PLUGIN_VERSION = "1.1.5";
internal static Random Random { get; } = new Random(1337);
public override void Load()
{
base.Harmony.PatchAll(Assembly.GetExecutingAssembly());
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Plugin is patched.");
Lib.SaveGame.OnBeforeLoad += SaveGame_OnBeforeLoad;
Lib.SaveGame.OnBeforeNewGame += SaveGame_OnBeforeNewGame;
Lib.SaveGame.OnAfterNewGame += SaveGame_OnAfterNewGame;
Lib.SaveGame.OnBeforeSave += SaveGame_OnBeforeSave;
Lib.SaveGame.OnAfterDelete += SaveGame_OnAfterDelete;
if (base.Config.AutoExpireJobs)
{
Lib.Time.OnMinuteChanged += Time_OnMinuteChanged;
}
}
private void SaveGame_OnAfterDelete(object sender, SaveGameArgs e)
{
SideJobPatches.DeleteSaveData(e.FilePath);
LostAndFoundPatches.DeleteSaveData(e.FilePath);
}
private void SaveGame_OnBeforeSave(object sender, SaveGameArgs e)
{
SideJobPatches.SaveExpireTimes(e.FilePath);
LostAndFoundPatches.SaveExpireTimes(e.FilePath);
}
private void SaveGame_OnBeforeNewGame(object sender, EventArgs e)
{
SideJobPatches.InitializeExpireTimes(null);
LostAndFoundPatches.InitializeExpireTimes(null);
}
private void SaveGame_OnBeforeLoad(object sender, SaveGameArgs e)
{
SideJobPatches.InitializeExpireTimes(e.FilePath);
LostAndFoundPatches.InitializeExpireTimes(e.FilePath);
}
private void Time_OnMinuteChanged(object sender, TimeChangedArgs e)
{
SideJobPatches.ExpireTimedOutJobs();
LostAndFoundPatches.ExpireTimedOutLafs();
}
private void SaveGame_OnAfterNewGame(object sender, EventArgs e)
{
UnlockBusinessDoors();
}
private static void UnlockBusinessDoors()
{
//IL_00da: Unknown result type (might be due to invalid IL or missing references)
//IL_00e1: Expected O, but got Unknown
int num = 0;
Enumerator<Company> enumerator = CityData.Instance.companyDirectory.GetEnumerator();
while (enumerator.MoveNext())
{
Company current = enumerator.Current;
if (!((Object)(object)current.placeOfBusiness.thisAsAddress != (Object)null) || !current.IsOpenAtThisTime(SessionData.Instance.gameTime))
{
continue;
}
Enumerator<NodeAccess> enumerator2 = ((NewGameLocation)current.address).entrances.GetEnumerator();
while (enumerator2.MoveNext())
{
NodeAccess current2 = enumerator2.Current;
if ((Object)(object)current2.door != (Object)null)
{
current2.door.SetLocked(false, (Actor)null, false);
}
}
Enumerator<NewRoom> enumerator3 = ((NewGameLocation)current.address).rooms.GetEnumerator();
while (enumerator3.MoveNext())
{
enumerator3.Current.SetMainLights(true, "SOD.QoL: Unlock business door on new game.", (Actor)null, true, true);
}
current.SetOpen(true, true);
num++;
}
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(27, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unlocked \"");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" business doors.");
}
log.LogInfo(val);
}
}
}
namespace SOD.QoL.Patches
{
internal class CitizenBehaviourPatches
{
[HarmonyPatch(typeof(CitizenBehaviour), "GameWorldCheck")]
internal class CitizenBehaviour_GameWorldCheck
{
internal readonly struct PlayerState
{
public float Energy { get; }
public float WellRested { get; }
public float Alertness { get; }
public float TickChange { get; }
public PlayerState(float energy, float wellRested, float alertness, float tickChange)
{
Energy = energy;
WellRested = wellRested;
Alertness = alertness;
TickChange = tickChange;
}
}
[HarmonyPrefix]
internal static void Prefix(CitizenBehaviour __instance, ref PlayerState __state)
{
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness)
{
float tickChange = SessionData.Instance.gameTime - __instance.timeOnLastGameWorldUpdate;
__state = new PlayerState(((Human)Player.Instance).energy, ((Human)Player.Instance).wellRested, ((Human)Player.Instance).alertness, tickChange);
}
}
[HarmonyPostfix]
internal static void Postfix(ref PlayerState __state)
{
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Invalid comparison between Unknown and I4
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness)
{
return;
}
((Human)Player.Instance).energy = __state.Energy;
((Human)Player.Instance).alertness = __state.Alertness;
((Human)Player.Instance).wellRested = __state.WellRested;
if (Player.Instance.spendingTimeMode && InteractionController.Instance.lockedInInteraction != null && (int)InteractionController.Instance.lockedInInteraction.preset.specialCaseFlag == 1)
{
if (((Human)Player.Instance).energy >= 0.8f)
{
((Human)Player.Instance).AddWellRested(__state.TickChange / 2f);
}
((Human)Player.Instance).AddEnergy(__state.TickChange / 4f);
return;
}
Chapter val = default(Chapter);
int num = default(int);
if (!Game.Instance.disableSurvivalStatusesInStory || !Toolbox.Instance.IsStoryMissionActive(ref val, ref num))
{
Player instance = Player.Instance;
((Human)instance).alertness = ((Human)instance).alertness + GameplayControls.Instance.playerTirednessRate * (0f - __state.TickChange);
((Human)Player.Instance).alertness = Mathf.Clamp01(((Human)Player.Instance).alertness);
Player.Instance.StatusCheckEndOfFrame();
((Human)Player.Instance).AddEnergy(GameplayControls.Instance.playerTirednessRate * (0f - __state.TickChange));
}
((Human)Player.Instance).AddWellRested(__state.TickChange * -0.5f);
}
}
}
internal class ControlDetectControllerPatches
{
[HarmonyPatch(typeof(ControlDetectController), "Start")]
internal class ControlDetectController_Start
{
[HarmonyPrefix]
private static void Prefix(ControlDetectController __instance)
{
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.SkipPressAnyKeyScreenIfNotUsingJoysticks)
{
Il2CppStringArray joystickNames = Input.GetJoystickNames();
if (joystickNames != null && ((Il2CppArrayBase<string>)(object)joystickNames).Length > 0)
{
__instance.loadSceneTriggered = false;
return;
}
PlayerPrefs.SetInt("controlMethod", 1);
__instance.loadSceneTriggered = true;
}
}
}
}
internal class FirstPersonItemControllerPatches
{
[HarmonyPatch(typeof(FirstPersonItemController), "Update")]
internal class FirstPersonItemController_Update
{
internal readonly struct PlayerState
{
public float Alertness { get; }
public float Energy { get; }
public Interactable Interactable { get; }
public PlayerState(float alertness, float energy, Interactable interactable)
{
Alertness = alertness;
Energy = energy;
Interactable = interactable;
}
}
[HarmonyPrefix]
internal static void Prefix(FirstPersonItemController __instance, ref PlayerState __state)
{
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness || (Object)(object)Player.Instance == (Object)null || (Object)(object)BioScreenController.Instance == (Object)null)
{
return;
}
if (__instance.isConsuming && !__instance.takeOneActive && BioScreenController.Instance.selectedSlot != null && BioScreenController.Instance.selectedSlot.interactableID > -1)
{
Interactable interactable = BioScreenController.Instance.selectedSlot.GetInteractable();
if (interactable != null && interactable.cs > 0f)
{
__state = new PlayerState(((Human)Player.Instance).alertness, ((Human)Player.Instance).energy, interactable);
}
}
else
{
__state = new PlayerState(((Human)Player.Instance).alertness, ((Human)Player.Instance).energy, null);
}
}
[HarmonyPostfix]
internal static void Postfix(ref PlayerState __state)
{
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00f0: Invalid comparison between Unknown and I4
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness || (Object)(object)Player.Instance == (Object)null)
{
return;
}
((Human)Player.Instance).alertness = __state.Alertness;
((Human)Player.Instance).energy = __state.Energy;
if (__state.Interactable == null || !(__state.Interactable.cs > 0f))
{
return;
}
Interactable interactable = __state.Interactable;
object obj;
if (interactable == null)
{
obj = null;
}
else
{
InteractablePreset preset = interactable.preset;
obj = ((preset != null) ? preset.retailItem : null);
}
if ((SoCustomComparison)obj != (SoCustomComparison)null)
{
Player instance = Player.Instance;
((Human)instance).alertness = ((Human)instance).alertness + interactable.preset.retailItem.alertness / interactable.preset.consumableAmount * Time.deltaTime;
((Human)Player.Instance).alertness = Mathf.Clamp01(((Human)Player.Instance).alertness);
Player.Instance.StatusCheckEndOfFrame();
if ((int)interactable.preset.retailItem.desireCategory == 2 && interactable.preset.retailItem.energy <= 0f)
{
interactable.preset.retailItem.energy = (float)Math.Round(interactable.preset.retailItem.alertness / 100f * (float)((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PercentageEnergyRestore, 2);
}
Player instance2 = Player.Instance;
((Human)instance2).energy = ((Human)instance2).energy + interactable.preset.retailItem.energy / interactable.preset.consumableAmount * Time.deltaTime;
((Human)Player.Instance).energy = Mathf.Clamp01(((Human)Player.Instance).energy);
Player.Instance.StatusCheckEndOfFrame();
}
}
}
[HarmonyPatch(typeof(FirstPersonItemController), "TakeOne")]
internal class FirstPersonItemController_TakeOne
{
[HarmonyPrefix]
internal static bool Prefix(FirstPersonItemController __instance)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness)
{
return true;
}
if (BioScreenController.Instance.selectedSlot != null && BioScreenController.Instance.selectedSlot.interactableID > -1)
{
Interactable interactable = BioScreenController.Instance.selectedSlot.GetInteractable();
if (interactable != null)
{
InteractablePreset preset = interactable.preset;
if ((SoCustomComparison)(object)((preset != null) ? preset.takeOneEvent : null) != (SoCustomComparison)null)
{
AudioController.Instance.Play2DSound(interactable.preset.takeOneEvent, (List<FMODParam>)null, 1f);
}
}
}
if (!__instance.takeOneActive)
{
RuntimeHelper.StartCoroutine(TakeOneExecute(__instance));
}
return false;
}
private static IEnumerator TakeOneExecute(FirstPersonItemController __instance)
{
float progress = 0f;
__instance.takeOneActive = true;
__instance.SetConsuming(true);
Interactable consumable = null;
if (BioScreenController.Instance.selectedSlot != null && BioScreenController.Instance.selectedSlot.interactableID > -1)
{
consumable = BioScreenController.Instance.selectedSlot.GetInteractable();
}
while (progress < 1f && consumable != null && consumable.cs > 0f)
{
float num = Time.deltaTime / 1.8f;
if ((SoCustomComparison)(object)consumable.preset.retailItem != (SoCustomComparison)null)
{
((Human)Player.Instance).AddNourishment(consumable.preset.retailItem.nourishment * num);
((Human)Player.Instance).AddHydration(consumable.preset.retailItem.hydration * num);
HandleEnergyAndAlertness(consumable, num);
((Human)Player.Instance).AddExcitement(consumable.preset.retailItem.excitement * num);
((Human)Player.Instance).AddChores(consumable.preset.retailItem.chores * num);
((Human)Player.Instance).AddHygiene(consumable.preset.retailItem.hygiene * num);
((Human)Player.Instance).AddBladder(consumable.preset.retailItem.bladder * num);
((Human)Player.Instance).AddHeat(consumable.preset.retailItem.heat * num);
((Human)Player.Instance).AddDrunk(consumable.preset.retailItem.drunk * num);
((Human)Player.Instance).AddSick(consumable.preset.retailItem.sick * num);
((Human)Player.Instance).AddHeadache(consumable.preset.retailItem.headache * num);
((Human)Player.Instance).AddWet(consumable.preset.retailItem.wet * num);
((Human)Player.Instance).AddBrokenLeg(consumable.preset.retailItem.brokenLeg * num);
((Human)Player.Instance).AddBruised(consumable.preset.retailItem.bruised * num);
((Human)Player.Instance).AddBlackEye(consumable.preset.retailItem.blackEye * num);
((Human)Player.Instance).AddBlackedOut(consumable.preset.retailItem.blackedOut * num);
((Human)Player.Instance).AddNumb(consumable.preset.retailItem.numb * num);
((Human)Player.Instance).AddBleeding(consumable.preset.retailItem.bleeding * num);
((Human)Player.Instance).AddBreath(consumable.preset.retailItem.breath * num);
((Human)Player.Instance).AddStarchAddiction(consumable.preset.retailItem.starchAddiction * num);
((Human)Player.Instance).AddPoisoned(consumable.preset.retailItem.poisoned * num, (Human)null);
((Actor)Player.Instance).AddHealth(consumable.preset.retailItem.health * num, true, false);
}
progress += num;
yield return null;
}
if (consumable != null)
{
Interactable obj = consumable;
obj.cs -= 1f;
if (consumable.cs <= 0f)
{
__instance.OnConsumableFinished(consumable);
if (consumable.preset.destroyWhenAllConsumed)
{
__instance.EmptySlot(BioScreenController.Instance.selectedSlot, false, true, true, false);
int childCount = __instance.rightHandObjectParent.GetChildCount();
List<Transform> list = new List<Transform>();
for (int i = 0; i < childCount; i++)
{
list.Add(__instance.rightHandObjectParent.GetChild(i));
}
foreach (Transform item in list)
{
Object.Destroy((Object)(object)((Component)item).gameObject);
}
}
}
}
__instance.takeOneActive = false;
__instance.SetConsuming(false);
if (consumable.cs <= 0f)
{
__instance.RefreshHeldObjects();
}
}
private static void HandleEnergyAndAlertness(Interactable consumable, float num)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Invalid comparison between Unknown and I4
Player instance = Player.Instance;
((Human)instance).alertness = ((Human)instance).alertness + consumable.preset.retailItem.alertness * num;
((Human)Player.Instance).alertness = Mathf.Clamp01(((Human)Player.Instance).alertness);
Player.Instance.StatusCheckEndOfFrame();
if ((int)consumable.preset.retailItem.desireCategory == 2 && consumable.preset.retailItem.energy <= 0f)
{
consumable.preset.retailItem.energy = (float)Math.Round(consumable.preset.retailItem.alertness / 100f * (float)((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PercentageEnergyRestore, 2);
}
Player instance2 = Player.Instance;
((Human)instance2).energy = ((Human)instance2).energy + consumable.preset.retailItem.energy * num;
((Human)Player.Instance).energy = Mathf.Clamp01(((Human)Player.Instance).energy);
Player.Instance.StatusCheckEndOfFrame();
}
}
}
internal class InputPatches
{
[HarmonyPatch(typeof(InputController), "Update")]
internal class InputController_Update
{
[HarmonyPrefix]
internal static bool Prefix(InputController __instance)
{
try
{
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.EndConversationPatch && !((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.UnpauseGameOnMainMenuExit)
{
return true;
}
if (!((Behaviour)__instance).enabled || !ReInput.isReady || PopupMessageController.Instance.active)
{
return true;
}
if (__instance.player != null && __instance.player.GetButtonDown("Menu"))
{
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.EndConversationPatch && SessionData.Instance.startedGame && SessionData.Instance.play && !MainMenuController.Instance.mainMenuActive && ((Actor)Player.Instance).interactingWith != null && ((Actor)Player.Instance).interactingWith.objectRef != null && TypeExtensions.IsAssignableFrom(((Actor)Player.Instance).interactingWith.objectRef, typeof(Actor)))
{
ActionController.Instance.Return((Interactable)null, (NewNode)null, (Actor)(object)Player.Instance);
return false;
}
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.UnpauseGameOnMainMenuExit && SessionData.Instance.startedGame && !SessionData.Instance.play && MainMenuController.Instance.mainMenuActive && ((Object)(object)CityConstructor.Instance == (Object)null || !CityConstructor.Instance.preSimActive))
{
SessionData.Instance.ResumeGame();
MainMenuController.Instance.EnableMainMenu(false, true, true, (Component)1);
return false;
}
}
return true;
}
catch (Exception)
{
return true;
}
}
}
}
internal class LostAndFoundPatches
{
private const string _expirationSaveFile = "LostAndFoundSaveData_{0}.json";
private static ExpirationSaveData _expirationSaveData;
private static readonly List<(NewBuilding, LostAndFound)> _toBeDeleted = new List<(NewBuilding, LostAndFound)>();
internal static void ExpireTimedOutLafs()
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_0093: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_011b: Unknown result type (might be due to invalid IL or missing references)
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
if (!Lib.Time.IsInitialized || _expirationSaveData == null)
{
return;
}
CityBuildings instance = HighlanderSingleton<CityBuildings>.Instance;
if ((Object)(object)instance == (Object)null || instance.buildingDirectory == null)
{
return;
}
TimeData currentDateTime = Lib.Time.CurrentDateTime;
Enumerator<NewBuilding> enumerator = instance.buildingDirectory.GetEnumerator();
while (enumerator.MoveNext())
{
NewBuilding current = enumerator.Current;
if (current.lostAndFound == null)
{
continue;
}
Enumerator<LostAndFound> enumerator2 = current.lostAndFound.GetEnumerator();
while (enumerator2.MoveNext())
{
LostAndFound current2 = enumerator2.Current;
string uniqueId = GetUniqueId(current2);
if (_expirationSaveData.Expirations.TryGetValue(uniqueId, out var value))
{
if (value <= currentDateTime)
{
ExpireLostAndFound(current, current2);
_expirationSaveData.Expirations.Remove(uniqueId);
}
}
else
{
int num = (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.RandomizeExpireTime ? Plugin.Random.Next(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMin, ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMax + 1) : ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMax);
Dictionary<string, TimeData> expirations = _expirationSaveData.Expirations;
TimeData currentDateTime2 = Lib.Time.CurrentDateTime;
expirations[uniqueId] = ((TimeData)(ref currentDateTime2)).AddHours(num);
}
}
}
foreach (var item in _toBeDeleted)
{
item.Item1.lostAndFound.Remove(item.Item2);
if (item.Item1.preset.maxLostAndFound - item.Item1.lostAndFound.Count > 0)
{
item.Item1.TriggerNewLostAndFound();
}
}
_toBeDeleted.Clear();
}
internal static void InitializeExpireTimes(string saveFilePath)
{
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Expected O, but got Unknown
Lazy<string> lazy = new Lazy<string>(delegate
{
string text = $"LostAndFoundSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
return Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
});
if (saveFilePath == null || !File.Exists(lazy.Value))
{
_expirationSaveData = new ExpirationSaveData
{
Expirations = new Dictionary<string, TimeData>()
};
return;
}
try
{
new JsonSerializerOptions
{
Converters = { (JsonConverter)new TimeDataJsonConverter() },
WriteIndented = true
};
_expirationSaveData = ExpirationSaveData.Deserialize(File.ReadAllText(lazy.Value));
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Loaded LostAndFoundSaveData from file.");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(55, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to read LostAndFoundSaveData file (corrupted?): ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
_expirationSaveData = new ExpirationSaveData
{
Expirations = new Dictionary<string, TimeData>()
};
}
}
internal static void SaveExpireTimes(string saveFilePath)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
if (_expirationSaveData == null || _expirationSaveData.Expirations.Count <= 0)
{
return;
}
string text = $"LostAndFoundSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
string savestoreDirectoryPath = Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
try
{
string contents = _expirationSaveData.Serialize();
File.WriteAllText(savestoreDirectoryPath, contents);
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Saved LostAndFoundSaveData to file.");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(45, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to save LostAndFoundSaveData to file: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
}
}
internal static void DeleteSaveData(string saveFilePath)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
string text = $"LostAndFoundSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
string savestoreDirectoryPath = Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
if (!File.Exists(savestoreDirectoryPath))
{
return;
}
try
{
File.Delete(savestoreDirectoryPath);
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Deleted LostAndFoundSaveData file");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to delete LostAndFoundSaveData file: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogInfo(val);
}
}
internal static string GetUniqueId(LostAndFound laf)
{
string text = laf.preset + "|" + laf.buildingID + "|" + laf.ownerID + "|" + laf.spawnedItem + "|" + laf.spawnedNote;
return Lib.SaveGame.GetUniqueString(text);
}
internal static void ExpireLostAndFound(NewBuilding building, LostAndFound laf)
{
Interactable val = default(Interactable);
if (CityData.Instance.savableInteractableDictionary.TryGetValue(laf.spawnedNote, ref val))
{
val.MarkAsTrash(true, false, 0f);
val.SafeDelete(false);
}
if (CityData.Instance.savableInteractableDictionary.TryGetValue(laf.spawnedItem, ref val))
{
val.MarkAsTrash(true, false, 0f);
}
_toBeDeleted.Add((building, laf));
}
}
internal class MapPatches
{
[HarmonyPatch(typeof(MapController), "Setup")]
internal class MapController_Setup
{
[HarmonyPrefix]
internal static void Prefix()
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_002b: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ChangePlayerMarkerColor)
{
Color color = GetColor(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PlayerMarkerColor);
PrefabControls.Instance.characterMarkerColor = color;
}
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.EnlargePlayerMarker)
{
var (num, num2) = ExtractFloats(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.PlayerMarkerSize);
PrefabControls.Instance.playerMarker.transform.localScale = new Vector3(num, num2, 1f);
}
}
[HarmonyPostfix]
internal static void Postfix(MapController __instance)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ZoomOutOnStart)
{
float x = __instance.zoomController.zoomLimit.x;
__instance.zoomController.SetPivotPoint(0f, (ZoomPivot)1);
__instance.zoomController.SetZoom(x);
((Transform)((Component)__instance.zoomController).GetComponent<RectTransform>()).localScale = new Vector3(x, x, 1f);
}
}
private static Color GetColor(string hexColor)
{
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
hexColor = hexColor.TrimStart('#');
if (hexColor.Length != 6)
{
PluginController<Plugin, IPluginBindings>.Log.LogWarning((object)"Invalid hex color code in configuration, it should be in the format #RRGGBB. Falling back to default green color.");
hexColor = "008000";
}
int num = int.Parse(hexColor.Substring(0, 2), NumberStyles.HexNumber);
int num2 = int.Parse(hexColor.Substring(2, 2), NumberStyles.HexNumber);
int num3 = int.Parse(hexColor.Substring(4, 2), NumberStyles.HexNumber);
return new Color((float)num, (float)num2, (float)num3);
}
private static (float x, float y) ExtractFloats(string input)
{
string pattern = "\\((-?\\d+(\\.\\d+)?), (-?\\d+(\\.\\d+)?)\\)";
Match match = Regex.Match(input, pattern);
if (match.Success)
{
float item = float.Parse(match.Groups[1].Value, CultureInfo.InvariantCulture);
float item2 = float.Parse(match.Groups[3].Value, CultureInfo.InvariantCulture);
return (item, item2);
}
PluginController<Plugin, IPluginBindings>.Log.LogWarning((object)"Invalid player marker size configuration, using the default value (2.5, 2.5)");
return (2.5f, 2.5f);
}
}
[HarmonyPatch(typeof(MapController), "CentreOnObject")]
internal class MapController_CentreOnObject
{
private static bool _calledBefore;
[HarmonyPostfix]
internal static void Postfix(MapController __instance, RectTransform mapObj, bool instant, bool showPointer)
{
if (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixCenterOnPlayer)
{
if (_calledBefore)
{
_calledBefore = false;
return;
}
_calledBefore = true;
__instance.CentreOnObject(mapObj, instant, showPointer);
}
}
}
}
internal class RoutePlotPatches
{
[HarmonyPatch(typeof(EvidenceLocationalControls), "OnPlotRoute")]
internal class EvidenceLocationalControls_OnPlotRoute
{
[HarmonyPrefix]
internal static bool Prefix(EvidenceLocationalControls __instance)
{
//IL_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_009e: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_00ad: Unknown result type (might be due to invalid IL or missing references)
//IL_00b0: Unknown result type (might be due to invalid IL or missing references)
Vector3Int? val = null;
if (MapController.Instance.playerRoute != null)
{
val = MapController.Instance.playerRoute.end.nodeCoord;
MapController.Instance.playerRoute.Remove();
if ((Object)(object)__instance.plotRouteButton != (Object)null)
{
((Graphic)((Selectable)__instance.plotRouteButton.button).image).color = __instance.plotRouteButton.baseColour;
}
}
MapController.Instance.PlotPlayerRoute(__instance.parentWindow.passedEvidence);
if (val.HasValue)
{
Vector3Int nodeCoord = MapController.Instance.playerRoute.end.nodeCoord;
Vector3Int? val2 = val;
if (val2.HasValue && nodeCoord == val2.GetValueOrDefault())
{
MapController.Instance.playerRoute.Remove();
}
}
return false;
}
}
}
internal class SideJobPatches
{
private const string _expirationSaveFile = "SideJobSaveData_{0}.json";
private static ExpirationSaveData _expirationSaveData;
internal static void ExpireTimedOutJobs()
{
//IL_0028: Unknown result type (might be due to invalid IL or missing references)
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_00b6: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Invalid comparison between Unknown and I4
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e6: Unknown result type (might be due to invalid IL or missing references)
//IL_018a: Unknown result type (might be due to invalid IL or missing references)
//IL_018f: Unknown result type (might be due to invalid IL or missing references)
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
SideJobController instance = SideJobController.Instance;
if (!Lib.Time.IsInitialized || (Object)(object)instance == (Object)null || _expirationSaveData == null)
{
return;
}
TimeData currentDateTime = Lib.Time.CurrentDateTime;
for (int i = 0; i < instance.jobTracking.Count; i++)
{
JobTracking val = instance.jobTracking[i];
for (int j = 0; j < val.activeJobs.Count; j++)
{
SideJob val2 = val.activeJobs[j];
if (_expirationSaveData.Expirations.ContainsKey(val2.jobID.ToString()) && val2.accepted)
{
_expirationSaveData.Expirations.Remove(val2.jobID.ToString());
}
else
{
if (val2.accepted || (int)val2.state != 1)
{
continue;
}
if (_expirationSaveData.Expirations.TryGetValue(val2.jobID.ToString(), out var value))
{
if (value <= currentDateTime)
{
val2.End();
_expirationSaveData.Expirations.Remove(val2.jobID.ToString());
}
}
else
{
int num = (((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.RandomizeExpireTime ? Plugin.Random.Next(((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMin, ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMax + 1) : ((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.ExpireTimeMax);
Dictionary<string, TimeData> expirations = _expirationSaveData.Expirations;
string key = val2.jobID.ToString();
TimeData currentDateTime2 = Lib.Time.CurrentDateTime;
expirations[key] = ((TimeData)(ref currentDateTime2)).AddHours(num);
}
}
}
}
}
internal static void InitializeExpireTimes(string saveFilePath)
{
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_009d: Expected O, but got Unknown
Lazy<string> lazy = new Lazy<string>(delegate
{
string text = $"SideJobSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
return Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
});
if (saveFilePath == null || !File.Exists(lazy.Value))
{
_expirationSaveData = new ExpirationSaveData
{
Expirations = new Dictionary<string, TimeData>()
};
return;
}
try
{
new JsonSerializerOptions
{
Converters = { (JsonConverter)new TimeDataJsonConverter() },
WriteIndented = true
};
_expirationSaveData = ExpirationSaveData.Deserialize(File.ReadAllText(lazy.Value));
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Loaded SideJobSaveData from file.");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(50, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to read SideJobSaveData file (corrupted?): ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
_expirationSaveData = new ExpirationSaveData
{
Expirations = new Dictionary<string, TimeData>()
};
}
}
internal static void SaveExpireTimes(string saveFilePath)
{
//IL_0074: Unknown result type (might be due to invalid IL or missing references)
//IL_007b: Expected O, but got Unknown
if (_expirationSaveData == null || _expirationSaveData.Expirations.Count <= 0)
{
return;
}
string text = $"SideJobSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
string savestoreDirectoryPath = Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
try
{
string contents = _expirationSaveData.Serialize();
File.WriteAllText(savestoreDirectoryPath, contents);
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Saved SideJobSaveData to file.");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExErrorLogInterpolatedStringHandler val = new BepInExErrorLogInterpolatedStringHandler(51, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to save side job expiration timers to file: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogError(val);
}
}
internal static void DeleteSaveData(string saveFilePath)
{
//IL_0051: Unknown result type (might be due to invalid IL or missing references)
//IL_0057: Expected O, but got Unknown
string text = $"SideJobSaveData_{Lib.SaveGame.GetUniqueString(saveFilePath)}.json";
string savestoreDirectoryPath = Lib.SaveGame.GetSavestoreDirectoryPath(Assembly.GetExecutingAssembly(), text);
if (!File.Exists(savestoreDirectoryPath))
{
return;
}
try
{
File.Delete(savestoreDirectoryPath);
PluginController<Plugin, IPluginBindings>.Log.LogInfo((object)"Deleted SideJobSaveData file");
}
catch (Exception ex)
{
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(39, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Unable to delete SideJobSaveData file: ");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(ex.Message);
}
log.LogInfo(val);
}
}
}
internal class ToolboxPatches
{
[HarmonyPatch(typeof(Toolbox), "LoadAll")]
internal static class Toolbox_LoadAll
{
[HarmonyPostfix]
internal static void Postfix(Toolbox __instance)
{
//IL_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Expected O, but got Unknown
if (!((PluginController<Plugin, IPluginBindings>)PluginController<Plugin, IPluginBindings>.Instance).Config.FixTiredness)
{
return;
}
bool flag = default(bool);
foreach (RetailItemPreset item in EnumerableExtensions.Where<RetailItemPreset>(__instance.allItems, (Func<RetailItemPreset, bool>)((RetailItemPreset a) => (int)a.desireCategory == 2)))
{
if (item.energy <= 0f)
{
item.energy = (float)Math.Round(item.alertness / 100f * 12f, 2);
ManualLogSource log = PluginController<Plugin, IPluginBindings>.Log;
BepInExInfoLogInterpolatedStringHandler val = new BepInExInfoLogInterpolatedStringHandler(44, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Adjusted energy restore amount for \"");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<string>(((Object)item).name);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\" to \"");
((BepInExLogInterpolatedStringHandler)val).AppendFormatted<float>(item.energy);
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("\".");
}
log.LogInfo(val);
}
}
}
}
}
}
namespace SOD.QoL.Objects
{
internal class ExpirationSaveData
{
public Dictionary<string, TimeData> Expirations { get; set; }
public string Serialize()
{
JsonSerializerOptions options = new JsonSerializerOptions
{
Converters = { (JsonConverter)new TimeDataJsonConverter() },
WriteIndented = true
};
return JsonSerializer.Serialize(this, options);
}
public static ExpirationSaveData Deserialize(string json)
{
JsonSerializerOptions options = new JsonSerializerOptions
{
Converters = { (JsonConverter)new TimeDataJsonConverter() },
WriteIndented = true
};
return JsonSerializer.Deserialize<ExpirationSaveData>(json, options);
}
}
internal class TimeDataJsonConverter : JsonConverter<TimeData>
{
public override TimeData Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
//IL_000f: Unknown result type (might be due to invalid IL or missing references)
if (reader.TokenType == JsonTokenType.String)
{
return TimeData.Deserialize(reader.GetString());
}
throw new JsonException("Expected a string for TimeData.");
}
public override void Write(Utf8JsonWriter writer, TimeData value, JsonSerializerOptions options)
{
writer.WriteStringValue(((TimeData)(ref value)).Serialize());
}
}
}