Some mods target the Mono version of the game, which is available by opting into the Steam beta branch "alternate"
Decompiled source of LateShiftMono v1.0.3
Mods\LateShiftMono.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using FishNet; using HarmonyLib; using LateShift; using MelonLoader; using MelonLoader.Preferences; using Microsoft.CodeAnalysis; using ScheduleOne.DevUtilities; using ScheduleOne.Dialogue; using ScheduleOne.Employees; using ScheduleOne.GameTime; using ScheduleOne.Money; using ScheduleOne.NPCs; using UnityEngine; using UnityEngine.Events; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: MelonInfo(typeof(LateShiftMod), "LateShift", "1.0.3", "lasersquid", null)] [assembly: MelonGame("TVGS", "Schedule I")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("LateShiftMono")] [assembly: AssemblyConfiguration("Mono")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3+c026bf6ff69403e58e296f8ec642daf1cfee309b")] [assembly: AssemblyProduct("LateShiftMono")] [assembly: AssemblyTitle("LateShiftMono")] [assembly: NeutralResourcesLanguage("en-US")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace LateShift { public class LateShiftMod : MelonMod { private bool needsReset = false; public MelonPreferences_Category melonPrefs; public Harmony harmony = new Harmony("com.lasersquid.lateshift"); public override void OnInitializeMelon() { CreateMelonPreferences(); SetMod(); ((MelonBase)this).LoggerInstance.Msg("Initialized."); } public override void OnSceneWasLoaded(int buildIndex, string sceneName) { if (sceneName.ToLower().Contains("main") || sceneName.ToLower().Contains("tutorial")) { needsReset = true; } if (sceneName.ToLower().Contains("menu") && needsReset) { ((MelonBase)this).LoggerInstance.Msg("Menu loaded, resetting state."); ResetState(); } } private void ResetState() { RestoreDefaults(); needsReset = false; } private void CreateMelonPreferences() { melonPrefs = MelonPreferences.CreateCategory("LateShift"); melonPrefs.SetFilePath("UserData/LateShift.cfg"); melonPrefs.CreateEntry<bool>("employeesAlwaysWork", true, "Employees always work", "Employees keep working at 4am", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("workWithoutBeds", true, "Employees work without beds", "Employees work without beds or lockers", false, false, (ValueValidator)null, (string)null); melonPrefs.CreateEntry<bool>("payEmployeesFromBank", false, "Autopay employees from bank account", "Autopay employees from bank account if true; otherwise pay with cash", false, false, (ValueValidator)null, (string)null); melonPrefs.SaveToFile(true); } private List<Type> GetPatchTypes() { return (from t in Assembly.GetExecutingAssembly().GetTypes() where t.Name.EndsWith("Patches") select t).ToList(); } private void SetMod() { foreach (Type patchType in GetPatchTypes()) { MethodInfo method = patchType.GetMethod("SetMod", BindingFlags.Static | BindingFlags.Public | BindingFlags.FlattenHierarchy); method.Invoke(null, new object[1] { this }); } } public void RestoreDefaults() { foreach (Type patchType in GetPatchTypes()) { try { MethodInfo method = patchType.GetMethod("RestoreDefaults", BindingFlags.Static | BindingFlags.Public); method.Invoke(null, null); } catch (Exception ex) { ((MelonBase)this).LoggerInstance.Warning("Couldn't restore defaults for class " + patchType.Name + ": " + ex.GetType().Name + " - " + ex.Message); ((MelonBase)this).LoggerInstance.Warning("Source: " + ex.Source); ((MelonBase)this).LoggerInstance.Warning(ex.StackTrace ?? ""); } } } } public class Sched1PatchesBase { protected static LateShiftMod Mod; public static object GetField(Type type, string fieldName, object target) { return AccessTools.Field(type, fieldName).GetValue(target); } public static void SetField(Type type, string fieldName, object target, object value) { AccessTools.Field(type, fieldName).SetValue(target, value); } public static object GetProperty(Type type, string fieldName, object target) { return AccessTools.Property(type, fieldName).GetValue(target); } public static void SetProperty(Type type, string fieldName, object target, object value) { AccessTools.Property(type, fieldName).SetValue(target, value); } public static object CallMethod(Type type, string methodName, object target, object[] args) { return AccessTools.Method(type, methodName, (Type[])null, (Type[])null).Invoke(target, args); } public static void SetMod(LateShiftMod mod) { Mod = mod; } public static T CastTo<T>(object o) where T : class { if (!(o is T result)) { return null; } return result; } public static bool Is<T>(object o) { return o is T; } public static UnityAction ToUnityAction(Action action) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown return new UnityAction(action.Invoke); } public static UnityAction<T> ToUnityAction<T>(Action<T> action) { return action.Invoke; } public static void Log(string message) { ((MelonBase)Mod).LoggerInstance.Msg(message); } public static void Warn(string message) { ((MelonBase)Mod).LoggerInstance.Warning(message); } public static void RestoreDefaults() { throw new NotImplementedException(); } } [HarmonyPatch] public class NoBedsPatches : Sched1PatchesBase { [HarmonyPatch(typeof(Employee), "IsPayAvailable")] [HarmonyPrefix] public static bool IsPayAvailablePrefix(Employee __instance, ref bool __result) { MoneyManager instance = NetworkSingleton<MoneyManager>.Instance; if (Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("workWithoutBeds").Value) { if (Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("payEmployeesFromBank").Value) { __result = instance.onlineBalance >= __instance.DailyWage; return false; } __result = instance.cashBalance >= __instance.DailyWage; return false; } EmployeeHome home = __instance.GetHome(); if ((Object)(object)home == (Object)null) { __result = false; return false; } __result = home.GetCashSum() >= __instance.DailyWage; return false; } [HarmonyPatch(typeof(Employee), "RemoveDailyWage")] [HarmonyPrefix] public static bool RemoveDailyWagePrefix(Employee __instance) { MoneyManager instance = NetworkSingleton<MoneyManager>.Instance; if (Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("workWithoutBeds").Value) { if (Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("payEmployeesFromBank").Value) { if (instance.onlineBalance >= __instance.DailyWage) { instance.CreateOnlineTransaction("Employee Pay", __instance.DailyWage, 1f, ((NPC)__instance).fullName + ", employeetype, location"); } } else if (instance.cashBalance >= __instance.DailyWage) { instance.ChangeCashBalance(0f - __instance.DailyWage, true, false); } } else { EmployeeHome home = __instance.GetHome(); if ((Object)(object)home == (Object)null) { return false; } if (home.GetCashSum() >= __instance.DailyWage) { home.RemoveCash(__instance.DailyWage); } } return false; } [HarmonyPatch(typeof(Employee), "GetWorkIssue")] [HarmonyPrefix] public static bool GetWorkIssuePrefix(Employee __instance, ref bool __result, ref DialogueContainer notWorkingReason) { if ((Object)(object)__instance.GetHome() == (Object)null && !Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("workWithoutBeds").Value) { notWorkingReason = __instance.BedNotAssignedDialogue; __result = true; return false; } if (!__instance.PaidForToday) { notWorkingReason = __instance.NotPaidDialogue; __result = true; return false; } List<NoWorkReason> list = Sched1PatchesBase.CastTo<List<NoWorkReason>>(Sched1PatchesBase.GetField(typeof(Employee), "WorkIssues", __instance)); if (__instance.TimeSinceLastWorked >= 5 && list.Count > 0) { notWorkingReason = Object.Instantiate<DialogueContainer>(__instance.WorkIssueDialogueTemplate); notWorkingReason.GetDialogueNodeByLabel("ENTRY").DialogueText = list[0].Reason; if (!string.IsNullOrEmpty(list[0].Fix)) { notWorkingReason.GetDialogueNodeByLabel("FIX").DialogueText = list[0].Fix; } else { notWorkingReason.GetDialogueNodeByLabel("ENTRY").choices = (DialogueChoiceData[])(object)new DialogueChoiceData[0]; } __result = true; return false; } notWorkingReason = null; __result = false; return false; } [HarmonyPatch(typeof(Employee), "CanWork")] [HarmonyPrefix] public static bool CanWorkPrefix(Employee __instance, ref bool __result) { __result = ((Object)(object)__instance.GetHome() != (Object)null || Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("workWithoutBeds").Value) && (!NetworkSingleton<TimeManager>.Instance.IsEndOfDay || Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("employeesAlwaysWork").Value) && __instance.PaidForToday; return false; } [HarmonyPatch(typeof(Employee), "UpdateBehaviour")] [HarmonyPrefix] public static bool UpdateBehaviourPrefix(Employee __instance) { if (__instance.Fired) { return false; } if ((Object)(object)((NPC)__instance).Behaviour.activeBehaviour == (Object)null || (Object)(object)((NPC)__instance).Behaviour.activeBehaviour == (Object)(object)__instance.WaitOutside) { bool flag = false; bool flag2 = false; if ((Object)(object)__instance.GetHome() == (Object)null && !Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("workWithoutBeds").Value) { flag = true; __instance.SubmitNoWorkReason("I haven't been assigned a locker", "You can use your management clipboard to assign me a locker.", 0); } else if (NetworkSingleton<TimeManager>.Instance.IsEndOfDay && !Sched1PatchesBase.Mod.melonPrefs.GetEntry<bool>("employeesAlwaysWork").Value) { flag = true; __instance.SubmitNoWorkReason("Sorry boss, my shift ends at 4AM.", string.Empty, 0); } else if (!__instance.PaidForToday) { if (__instance.IsPayAvailable()) { flag2 = true; } else { flag = true; __instance.SubmitNoWorkReason("I haven't been paid yet", "You can place cash in my locker.", 0); } } if (flag) { Sched1PatchesBase.CallMethod(typeof(Employee), "SetWaitOutside", __instance, new object[1] { true }); return false; } if (InstanceFinder.IsServer && flag2 && __instance.IsPayAvailable()) { __instance.RemoveDailyWage(); __instance.SetIsPaid(); } } return false; } public new static void RestoreDefaults() { } } }