using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime;
using Il2CppInterop.Runtime.InteropTypes;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("SoDBackToWork")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("0.5.0.0")]
[assembly: AssemblyInformationalVersion("0.5.0")]
[assembly: AssemblyProduct("SoDBackToWork")]
[assembly: AssemblyTitle("SoDBackToWork")]
[assembly: AssemblyVersion("0.5.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[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 SoDBackToWork
{
[BepInPlugin("sm3gm.sod.backtowork", "BACK TO WORK!", "1.0.0")]
public sealed class Plugin : BasePlugin
{
public const string VER = "1.0.0";
internal static ManualLogSource L;
internal static ConfigEntry<bool> StaffStalls;
internal static ConfigEntry<bool> AllowHomeless;
internal static ConfigEntry<bool> ManagerBooking;
internal static ConfigEntry<bool> FillVacantJobs;
internal static ConfigEntry<int> KeepUnemployed;
internal static ConfigEntry<bool> ToiletOnlyWhenUrgent;
internal static ConfigEntry<float> UrgentBladder;
internal static ConfigEntry<string> StayAtWorkJobs;
internal static ConfigEntry<string> StayAtWorkCompanies;
internal static ConfigEntry<string> AllowedDuringShift;
internal static ConfigEntry<string> AlwaysOpenCompanies;
public override void Load()
{
//IL_0185: 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_019a: Unknown result type (might be due to invalid IL or missing references)
//IL_01d1: Unknown result type (might be due to invalid IL or missing references)
//IL_01d7: Expected O, but got Unknown
L = ((BasePlugin)this).Log;
StaffStalls = ((BasePlugin)this).Config.Bind<bool>("Stalls", "StaffStalls", true, "Give every street food stall a seller you can buy from.");
AllowHomeless = ((BasePlugin)this).Config.Bind<bool>("Stalls", "AllowHomeless", true, "Homeless citizens may run a stall when there are not enough unemployed citizens with a home.");
ManagerBooking = ((BasePlugin)this).Config.Bind<bool>("Hotel", "ManagerBooking", true, "Everyone working at a hotel (manager, bar staff, cooks) can also rent you a room, take payment and check you out, like the porter at the desk.");
FillVacantJobs = ((BasePlugin)this).Config.Bind<bool>("Jobs", "FillVacantJobs", true, "Fill job posts the game left empty (laundries, offices, plants, hospitals and so on) with unemployed citizens.");
KeepUnemployed = ((BasePlugin)this).Config.Bind<int>("Jobs", "KeepUnemployed", 10, "Leave at least this many citizens unemployed, so the streets keep some idle and homeless people.");
ToiletOnlyWhenUrgent = ((BasePlugin)this).Config.Bind<bool>("Jobs", "ToiletOnlyWhenUrgent", true, "During their shift, workers only leave for the toilet when they really need to. Night staff in particular otherwise wander off early and often, leaving desks and counters empty.");
UrgentBladder = ((BasePlugin)this).Config.Bind<float>("Jobs", "UrgentBladder", 0.1f, "How urgent it must be: bladder at or below this (0 = bursting, 1 = fine).");
StayAtWorkJobs = ((BasePlugin)this).Config.Bind<string>("Jobs", "StayAtWorkJobs", "BlackmarketDoctor", "Job types (internal names, comma separated) that never leave their post during their shift, except for an urgent toilet trip. Empty = off.");
StayAtWorkCompanies = ((BasePlugin)this).Config.Bind<string>("Jobs", "StayAtWorkCompanies", "Blackmarket,WeaponsDealer", "Every worker at a business whose type contains one of these words (comma separated, any case) stays at their post during the shift, like StayAtWorkJobs. The default covers all black market staff and weapons dealers. Empty = off.");
AllowedDuringShift = ((BasePlugin)this).Config.Bind<string>("Jobs", "AllowedDuringShift", "AnswerDoor,Flee,Attack,Panic,Combat,Arrest,Investigate", "Things staff kept at their post may still do (goal names, a part of the name is enough). AnswerDoor must stay: the black market trader has to open the door for the password.");
AlwaysOpenCompanies = ((BasePlugin)this).Config.Bind<string>("Jobs", "AlwaysOpenCompanies", "Blackmarket,WeaponsDealer,SyncClinic", "Businesses whose type contains one of these words (comma separated, any case) are manned around the clock, every day: extra citizens are hired for the night and for the regular staff's days off, so everyone keeps a normal schedule. Needs FillVacantJobs. Empty = off.");
Harmony val = new Harmony("sm3gm.sod.backtowork");
val.PatchAll(typeof(GameStartedPatch));
val.PatchAll(typeof(StallNamePatch));
val.PatchAll(typeof(ToiletPatch));
((BasePlugin)this).AddComponent<ToiletWatch>();
((BasePlugin)this).AddComponent<StayAtWork>();
ManualLogSource l = L;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val2 = new BepInExInfoLogInterpolatedStringHandler(21, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral("BACK TO WORK! ");
((BepInExLogInterpolatedStringHandler)val2).AppendFormatted<string>("1.0.0");
((BepInExLogInterpolatedStringHandler)val2).AppendLiteral(" loaded");
}
l.LogInfo(val2);
}
}
[HarmonyPatch(typeof(MurderController), "OnStartGame")]
internal static class GameStartedPatch
{
private static void Postfix()
{
if (Plugin.StaffStalls.Value)
{
try
{
Stalls.StaffAll();
}
catch (Exception ex)
{
Plugin.L.LogError((object)("[STALLS] " + ex));
}
}
try
{
AlwaysOpen.Apply();
}
catch (Exception ex2)
{
Plugin.L.LogError((object)("[OPEN] " + ex2));
}
if (Plugin.FillVacantJobs.Value)
{
try
{
Vacancies.FillAll();
}
catch (Exception ex3)
{
Plugin.L.LogError((object)("[JOBS] " + ex3));
}
}
if (Plugin.ManagerBooking.Value)
{
try
{
Hotels.ManagerBooking();
}
catch (Exception ex4)
{
Plugin.L.LogError((object)("[HOTEL] " + ex4));
}
}
}
}
[HarmonyPatch(typeof(Company), "UpdateName")]
internal static class StallNamePatch
{
internal static bool Active;
private static Exception? Finalizer(Exception? __exception, Company __instance)
{
if (__exception == null || !Active)
{
return __exception;
}
try
{
if (string.IsNullOrEmpty(__instance.name))
{
Human director = __instance.director;
string text = ((director != null) ? director.GetSurName() : null) ?? "Corner";
__instance.name = text + "'s Snacks";
__instance.shortName = text;
}
}
catch
{
}
return null;
}
}
internal static class Stalls
{
private static AIGoalPreset? workGoal;
private static void Log(string s)
{
Plugin.L.LogInfo((object)("[STALLS] " + s));
}
internal static void StaffAll()
{
List<Interactable> list = new List<Interactable>();
List<Interactable> interactableDirectory = CityData.Instance.interactableDirectory;
for (int i = 0; i < interactableDirectory.Count; i++)
{
Interactable val = interactableDirectory[i];
object obj;
if (val == null)
{
obj = null;
}
else
{
InteractablePreset preset = val.preset;
obj = ((preset != null) ? ((Object)preset).name : null);
}
if ((string?)obj == "StreetVendor")
{
FurnitureLocation furnitureParent = val.furnitureParent;
object obj2;
if (furnitureParent == null)
{
obj2 = null;
}
else
{
FurniturePreset furniture = furnitureParent.furniture;
obj2 = ((furniture != null) ? furniture.createSelfEmployed : null);
}
if ((SoCustomComparison)obj2 != (SoCustomComparison)null)
{
list.Add(val);
}
}
}
list.Sort((Interactable a, Interactable b) => a.id.CompareTo(b.id));
List<Citizen> list2 = Candidates();
int num = 0;
int num2 = 0;
int num3 = 0;
int num4 = 0;
foreach (Interactable item in list)
{
if (HasSeller(item))
{
num2++;
continue;
}
bool flag = false;
for (int num5 = 0; num5 < 3; num5++)
{
if (flag)
{
break;
}
if (num4 >= list2.Count)
{
break;
}
flag = Staff(item, list2[num4++]);
if (!flag)
{
num3++;
}
}
if (flag)
{
num++;
}
if (num4 < list2.Count || flag)
{
continue;
}
break;
}
int value = list.Count - num - num2;
Log($"{list.Count} stalls: {num} staffed now, {num2} already had a seller, {num3} failed attempts, {value} still empty (unemployed citizens left: {list2.Count - num4})");
}
private static List<Citizen> Candidates()
{
List<Citizen> list = new List<Citizen>();
List<Citizen> list2 = new List<Citizen>();
List<Citizen> citizenDirectory = CityData.Instance.citizenDirectory;
for (int i = 0; i < citizenDirectory.Count; i++)
{
Citizen val = citizenDirectory[i];
if (!((Object)(object)val == (Object)null) && !((Actor)val).isDead && !((Actor)val).isEnforcer && (((Human)val).job == null || ((Human)val).job.employer == null))
{
(((Object)(object)((Human)val).home != (Object)null) ? list : list2).Add(val);
}
}
list.Sort((Citizen a, Citizen b) => ((Human)a).humanID.CompareTo(((Human)b).humanID));
list2.Sort((Citizen a, Citizen b) => ((Human)a).humanID.CompareTo(((Human)b).humanID));
if (Plugin.AllowHomeless.Value)
{
list.AddRange(list2);
}
return list;
}
private static bool HasSeller(Interactable spot)
{
Human belongsTo = spot.belongsTo;
if ((Object)(object)belongsTo != (Object)null)
{
Occupation job = belongsTo.job;
if (((job != null) ? job.employer : null) != null && (SoCustomComparison)(object)belongsTo.job.preset != (SoCustomComparison)null)
{
return belongsTo.job.preset.selfEmployed;
}
}
return false;
}
private static bool Staff(Interactable spot, Citizen who)
{
//IL_0195: Unknown result type (might be due to invalid IL or missing references)
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler;
try
{
CityConstructor.Instance.CreateSelfEmployed(spot.furnitureParent.furniture.createSelfEmployed, (Human)(object)who, spot);
}
catch (Exception ex)
{
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(33, 3);
defaultInterpolatedStringHandler.AppendLiteral("could not open a stall on ");
NewNode node = spot.node;
object value;
if (node == null)
{
value = null;
}
else
{
NewGameLocation gameLocation = node.gameLocation;
value = ((gameLocation != null) ? ((Object)gameLocation).name : null);
}
defaultInterpolatedStringHandler.AppendFormatted((string?)value);
defaultInterpolatedStringHandler.AppendLiteral(" for ");
defaultInterpolatedStringHandler.AppendFormatted(((Human)who).GetCitizenName());
defaultInterpolatedStringHandler.AppendLiteral(": ");
defaultInterpolatedStringHandler.AppendFormatted(ex.Message.Split('\n')[0]);
Log(defaultInterpolatedStringHandler.ToStringAndClear());
return false;
}
try
{
((Human)who).SetWorkFurniture(spot);
}
catch (Exception ex2)
{
Log("SetWorkFurniture: " + ex2.Message);
}
EnsureWorkGoal((Human)(object)who);
AddJobDialogs((Human)(object)who);
Occupation job = ((Human)who).job;
Company val = ((job != null) ? job.employer : null);
defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(13, 5);
defaultInterpolatedStringHandler.AppendFormatted((val != null) ? val.name : null);
defaultInterpolatedStringHandler.AppendLiteral(" on ");
NewNode node2 = spot.node;
object value2;
if (node2 == null)
{
value2 = null;
}
else
{
NewGameLocation gameLocation2 = node2.gameLocation;
value2 = ((gameLocation2 != null) ? ((Object)gameLocation2).name : null);
}
defaultInterpolatedStringHandler.AppendFormatted((string?)value2);
defaultInterpolatedStringHandler.AppendLiteral(": ");
defaultInterpolatedStringHandler.AppendFormatted(((Human)who).GetCitizenName());
defaultInterpolatedStringHandler.AppendFormatted(((Object)(object)((Human)who).home == (Object)null) ? " (homeless)" : "");
defaultInterpolatedStringHandler.AppendLiteral(", open ");
defaultInterpolatedStringHandler.AppendFormatted((val != null) ? new Vector2?(val.retailOpenHours) : ((Vector2?)null));
Log(defaultInterpolatedStringHandler.ToStringAndClear());
return true;
}
internal static void EnsureWorkGoal(Human who)
{
try
{
NewAIController ai = ((Actor)who).ai;
if ((Object)(object)ai == (Object)null)
{
return;
}
for (int i = 0; i < ai.goals.Count; i++)
{
NewAIGoal obj = ai.goals[i];
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
AIGoalPreset preset = obj.preset;
obj2 = ((preset != null) ? ((Object)preset).name : null);
}
if ((string?)obj2 == "Work")
{
return;
}
}
if ((SoCustomComparison)(object)workGoal == (SoCustomComparison)null)
{
foreach (Object item in (Il2CppArrayBase<Object>)(object)Resources.FindObjectsOfTypeAll(Il2CppType.Of<AIGoalPreset>()))
{
AIGoalPreset val = ((Il2CppObjectBase)item).TryCast<AIGoalPreset>();
if ((SoCustomComparison)(object)val != (SoCustomComparison)null && ((Object)val).name == "Work")
{
workGoal = val;
break;
}
}
}
if ((SoCustomComparison)(object)workGoal != (SoCustomComparison)null)
{
ai.CreateNewGoal(workGoal, 0f, 0f, (NewNode)null, (Interactable)null, (NewGameLocation)null, (SocialGroup)null, (Murder)null, -2);
}
}
catch (Exception ex)
{
Log("Work goal: " + ex.Message);
}
}
internal static void AddJobDialogs(Human who)
{
try
{
Occupation job = who.job;
object obj;
if (job == null)
{
obj = null;
}
else
{
OccupationPreset preset = job.preset;
obj = ((preset != null) ? preset.addDialog : null);
}
List<DialogPreset> val = (List<DialogPreset>)obj;
if (val == null || ((Actor)who).evidenceEntry == null)
{
return;
}
for (int i = 0; i < val.Count; i++)
{
if ((SoCustomComparison)(object)val[i] != (SoCustomComparison)null)
{
((Actor)who).evidenceEntry.AddDialogOption((DataKey)1, val[i], (SideJob)null, (NewRoom)null, (InteractionDialogInstance)null, false, false);
}
}
}
catch (Exception ex)
{
Log("talk options: " + ex.Message);
}
}
}
internal static class Hotels
{
internal static void ManagerBooking()
{
//IL_01d6: Unknown result type (might be due to invalid IL or missing references)
//IL_01dd: Expected O, but got Unknown
OccupationPreset val = null;
foreach (Object item in (Il2CppArrayBase<Object>)(object)Resources.FindObjectsOfTypeAll(Il2CppType.Of<OccupationPreset>()))
{
OccupationPreset val2 = ((Il2CppObjectBase)item).TryCast<OccupationPreset>();
if ((SoCustomComparison)(object)val2 != (SoCustomComparison)null && ((Object)val2).name == "Porter")
{
val = val2;
break;
}
}
List<DialogPreset> val3 = ((val != null) ? val.addDialog : null);
if (val3 == null || val3.Count == 0)
{
Plugin.L.LogInfo((object)"[HOTEL] porter talk options not found");
return;
}
List<Company> companyDirectory = CityData.Instance.companyDirectory;
bool flag = default(bool);
for (int i = 0; i < companyDirectory.Count; i++)
{
Company val4 = companyDirectory[i];
if ((SoCustomComparison)(object)((val4 != null) ? val4.preset : null) == (SoCustomComparison)null || !val4.preset.isHotel)
{
continue;
}
List<Human> list = new List<Human>();
if ((Object)(object)val4.director != (Object)null)
{
list.Add(val4.director);
}
List<Occupation> companyRoster = val4.companyRoster;
int num = 0;
while (companyRoster != null && num < companyRoster.Count)
{
Occupation obj = companyRoster[num];
if ((Object)(object)((obj != null) ? obj.employee : null) != (Object)null && !list.Contains(companyRoster[num].employee))
{
list.Add(companyRoster[num].employee);
}
num++;
}
foreach (Human item2 in list)
{
if (((Actor)item2).evidenceEntry == null)
{
continue;
}
for (int j = 0; j < val3.Count; j++)
{
if ((SoCustomComparison)(object)val3[j] != (SoCustomComparison)null)
{
((Actor)item2).evidenceEntry.AddDialogOption((DataKey)1, val3[j], (SideJob)null, (NewRoom)null, (InteractionDialogInstance)null, false, false);
}
}
}
ManualLogSource l = Plugin.L;
BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(35, 2, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[HOTEL] ");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<string>(val4.name);
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(list.Count);
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" staff can now rent rooms");
}
l.LogInfo(val5);
}
}
}
internal static class Vacancies
{
private static void Log(string s)
{
Plugin.L.LogInfo((object)("[JOBS] " + s));
}
internal static void FillAll()
{
HashSet<int> hashSet = new HashSet<int>();
try
{
MurderController instance = MurderController.Instance;
if ((Object)(object)((instance != null) ? instance.currentMurderer : null) != (Object)null)
{
hashSet.Add(instance.currentMurderer.humanID);
}
if ((Object)(object)((instance != null) ? instance.currentVictim : null) != (Object)null)
{
hashSet.Add(instance.currentVictim.humanID);
}
List<Human> val = ((instance != null) ? instance.previousMurderers : null);
int num = 0;
while (val != null && num < val.Count)
{
if ((Object)(object)val[num] != (Object)null)
{
hashSet.Add(val[num].humanID);
}
num++;
}
}
catch (Exception ex)
{
Log("murder check: " + ex.Message);
}
List<Citizen> list = new List<Citizen>();
List<Citizen> list2 = new List<Citizen>();
List<Citizen> citizenDirectory = CityData.Instance.citizenDirectory;
for (int i = 0; i < citizenDirectory.Count; i++)
{
Citizen val2 = citizenDirectory[i];
if (!((Object)(object)val2 == (Object)null) && !((Actor)val2).isDead && !((Human)val2).removedFromWorld && !hashSet.Contains(((Human)val2).humanID) && !((Actor)val2).isEnforcer && (((Human)val2).job == null || ((Human)val2).job.employer == null))
{
(((Object)(object)((Human)val2).home != (Object)null) ? list : list2).Add(val2);
}
}
list.Sort((Citizen a, Citizen b) => ((Human)a).humanID.CompareTo(((Human)b).humanID));
list2.Sort((Citizen a, Citizen b) => ((Human)a).humanID.CompareTo(((Human)b).humanID));
list.AddRange(list2);
int num2 = Math.Max(0, list.Count - Math.Max(0, Plugin.KeepUnemployed.Value));
List<Occupation> list3 = new List<Occupation>();
List<Company> companyDirectory = CityData.Instance.companyDirectory;
for (int num3 = 0; num3 < companyDirectory.Count; num3++)
{
Company obj = companyDirectory[num3];
List<Occupation> val3 = ((obj != null) ? obj.companyRoster : null);
int num4 = 0;
while (val3 != null && num4 < val3.Count)
{
if (val3[num4] != null && (Object)(object)val3[num4].employee == (Object)null)
{
list3.Add(val3[num4]);
}
num4++;
}
}
list3.Sort((Occupation a, Occupation b) => a.id.CompareTo(b.id));
SortedDictionary<string, int> sortedDictionary = new SortedDictionary<string, int>();
int num5 = 0;
int num6 = 0;
int num7 = 0;
foreach (Occupation item in list3)
{
if (num7 >= num2)
{
break;
}
Citizen val4 = list[num7++];
try
{
((Human)val4).SetJob(item);
}
catch (Exception ex2)
{
num6++;
DefaultInterpolatedStringHandler defaultInterpolatedStringHandler = new DefaultInterpolatedStringHandler(21, 3);
defaultInterpolatedStringHandler.AppendLiteral("could not hire ");
defaultInterpolatedStringHandler.AppendFormatted(((Human)val4).GetCitizenName());
defaultInterpolatedStringHandler.AppendLiteral(" as ");
OccupationPreset preset = item.preset;
defaultInterpolatedStringHandler.AppendFormatted((preset != null) ? ((Object)preset).name : null);
defaultInterpolatedStringHandler.AppendLiteral(": ");
defaultInterpolatedStringHandler.AppendFormatted(ex2.Message.Split('\n')[0]);
Log(defaultInterpolatedStringHandler.ToStringAndClear());
continue;
}
Stalls.EnsureWorkGoal((Human)(object)val4);
Stalls.AddJobDialogs((Human)(object)val4);
num5++;
Company employer = item.employer;
object obj2;
if (employer == null)
{
obj2 = null;
}
else
{
CompanyPreset preset2 = employer.preset;
obj2 = ((preset2 != null) ? ((Object)preset2).name : null);
}
OccupationPreset preset3 = item.preset;
string key = (string?)obj2 + " / " + ((preset3 != null) ? ((Object)preset3).name : null);
sortedDictionary[key] = ((!sortedDictionary.TryGetValue(key, out var value)) ? 1 : (value + 1));
}
foreach (KeyValuePair<string, int> item2 in sortedDictionary)
{
Log($" {item2.Key}: {item2.Value}");
}
Log($"{list3.Count} empty posts: {num5} filled, {num6} failed, {list3.Count - num5 - num6} still empty; unemployed left {list.Count - num7} (keeping {Plugin.KeepUnemployed.Value})");
}
}
[HarmonyPatch(typeof(NewAIGoal), "UpdatePriority")]
internal static class ToiletPatch
{
private static readonly Dictionary<IntPtr, bool> isToilet = new Dictionary<IntPtr, bool>();
private static void Postfix(NewAIGoal __instance)
{
if (!Plugin.ToiletOnlyWhenUrgent.Value)
{
return;
}
try
{
AIGoalPreset preset = __instance.preset;
if ((SoCustomComparison)(object)preset == (SoCustomComparison)null)
{
return;
}
if (!isToilet.TryGetValue(((Il2CppObjectBase)preset).Pointer, out var value))
{
value = (isToilet[((Il2CppObjectBase)preset).Pointer] = ((Object)preset).name.IndexOf("Toilet", StringComparison.OrdinalIgnoreCase) >= 0);
}
if (!value)
{
return;
}
NewAIController aiController = __instance.aiController;
Human val = ((aiController != null) ? aiController.human : null);
Occupation val2 = ((val != null) ? val.job : null);
if (((val2 != null) ? val2.employer : null) == null || val.bladder <= Plugin.UrgentBladder.Value)
{
return;
}
float decimalClock = SessionData.Instance.decimalClock;
float startTimeDecimalHour = val2.startTimeDecimalHour;
float endTimeDecialHour = val2.endTimeDecialHour;
bool num;
if (!(startTimeDecimalHour <= endTimeDecialHour))
{
if (decimalClock >= startTimeDecimalHour)
{
goto IL_00ee;
}
num = decimalClock < endTimeDecialHour;
}
else
{
if (!(decimalClock >= startTimeDecimalHour))
{
return;
}
num = decimalClock < endTimeDecialHour;
}
if (!num)
{
return;
}
goto IL_00ee;
IL_00ee:
__instance.priority = 0f;
}
catch
{
}
}
}
public class ToiletWatch : MonoBehaviour
{
private float next;
private float nextLog;
private int sent;
public ToiletWatch(IntPtr ptr)
: base(ptr)
{
}
private void Update()
{
//IL_01b8: Unknown result type (might be due to invalid IL or missing references)
//IL_01bf: Expected O, but got Unknown
if (!Plugin.ToiletOnlyWhenUrgent.Value || Time.unscaledTime < next)
{
return;
}
next = Time.unscaledTime + 1f;
try
{
if ((Object)(object)CityData.Instance == (Object)null || (Object)(object)SessionData.Instance == (Object)null)
{
return;
}
float decimalClock = SessionData.Instance.decimalClock;
List<Company> companyDirectory = CityData.Instance.companyDirectory;
for (int i = 0; i < companyDirectory.Count; i++)
{
Company obj = companyDirectory[i];
List<Occupation> val = ((obj != null) ? obj.companyRoster : null);
for (int j = 0; val != null && j < val.Count; j++)
{
Occupation val2 = val[j];
Human val3 = ((val2 != null) ? val2.employee : null);
if ((Object)(object)val3 == (Object)null || ((Actor)val3).isDead || val3.bladder <= Plugin.UrgentBladder.Value)
{
continue;
}
NewAIController ai = ((Actor)val3).ai;
NewAIGoal val4 = ((ai != null) ? ai.currentGoal : null);
object obj2;
if (val4 == null)
{
obj2 = null;
}
else
{
AIGoalPreset preset = val4.preset;
obj2 = ((preset != null) ? ((Object)preset).name : null);
}
string text = (string)obj2;
if (text == null || text.IndexOf("Toilet", StringComparison.OrdinalIgnoreCase) < 0)
{
continue;
}
float startTimeDecimalHour = val2.startTimeDecimalHour;
float endTimeDecialHour = val2.endTimeDecialHour;
bool num;
if (!(startTimeDecimalHour <= endTimeDecialHour))
{
if (decimalClock >= startTimeDecimalHour)
{
goto IL_0147;
}
num = decimalClock < endTimeDecialHour;
}
else
{
if (!(decimalClock >= startTimeDecimalHour))
{
continue;
}
num = decimalClock < endTimeDecialHour;
}
if (!num)
{
continue;
}
goto IL_0147;
IL_0147:
val4.OnDeactivate(1f);
sent++;
}
}
if (Time.unscaledTime > nextLog && sent > 0)
{
nextLog = Time.unscaledTime + 60f;
ManualLogSource l = Plugin.L;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val5 = new BepInExInfoLogInterpolatedStringHandler(48, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral("[JOBS] toilet: sent ");
((BepInExLogInterpolatedStringHandler)val5).AppendFormatted<int>(sent);
((BepInExLogInterpolatedStringHandler)val5).AppendLiteral(" workers back to work so far");
}
l.LogInfo(val5);
}
}
catch
{
}
}
}
public class StayAtWork : MonoBehaviour
{
private float next;
private readonly HashSet<string> seen = new HashSet<string>();
private readonly HashSet<int> rosterLogged = new HashSet<int>();
private float nextDealerLog;
private readonly Dictionary<int, string> lastGoal = new Dictionary<int, string>();
private HashSet<string>? jobs;
private string[]? words;
private string[]? allowed;
public StayAtWork(IntPtr ptr)
: base(ptr)
{
}
private void Update()
{
//IL_0260: Unknown result type (might be due to invalid IL or missing references)
//IL_0267: Expected I4, but got Unknown
//IL_02c3: Unknown result type (might be due to invalid IL or missing references)
//IL_02ca: Expected O, but got Unknown
//IL_0464: Unknown result type (might be due to invalid IL or missing references)
//IL_046b: Expected O, but got Unknown
//IL_05ff: Unknown result type (might be due to invalid IL or missing references)
//IL_0606: Expected O, but got Unknown
//IL_0778: Unknown result type (might be due to invalid IL or missing references)
//IL_077f: Expected O, but got Unknown
if (Time.unscaledTime < next)
{
return;
}
next = Time.unscaledTime + 1f;
try
{
if (jobs == null)
{
jobs = new HashSet<string>(from x in Plugin.StayAtWorkJobs.Value.Split(',')
select x.Trim() into x
where x.Length > 0
select x);
}
if (words == null)
{
words = (from x in Plugin.StayAtWorkCompanies.Value.Split(',')
select x.Trim() into x
where x.Length > 0
select x).ToArray();
}
if ((jobs.Count == 0 && words.Length == 0) || (Object)(object)CityData.Instance == (Object)null || (Object)(object)SessionData.Instance == (Object)null)
{
return;
}
float decimalClock = SessionData.Instance.decimalClock;
List<Company> companyDirectory = CityData.Instance.companyDirectory;
bool flag2 = default(bool);
for (int num = 0; num < companyDirectory.Count; num++)
{
Company obj = companyDirectory[num];
object obj2;
if (obj == null)
{
obj2 = null;
}
else
{
CompanyPreset preset = obj.preset;
obj2 = ((preset != null) ? ((Object)preset).name : null);
}
if (obj2 == null)
{
obj2 = "";
}
string cname = (string)obj2;
bool flag = words.Any((string w) => cname.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0);
Company obj3 = companyDirectory[num];
List<Occupation> val = ((obj3 != null) ? obj3.companyRoster : null);
for (int num2 = 0; val != null && num2 < val.Count; num2++)
{
Occupation val2 = val[num2];
Human val3 = ((val2 != null) ? val2.employee : null);
if ((Object)(object)val3 == (Object)null || ((Actor)val3).isDead || (SoCustomComparison)(object)val2.preset == (SoCustomComparison)null || (!flag && !jobs.Contains(((Object)val2.preset).name)))
{
continue;
}
float startTimeDecimalHour = val2.startTimeDecimalHour;
float endTimeDecialHour = val2.endTimeDecialHour;
bool num3;
if (!(startTimeDecimalHour <= endTimeDecialHour))
{
if (decimalClock >= startTimeDecimalHour)
{
goto IL_025b;
}
num3 = decimalClock < endTimeDecialHour;
}
else
{
if (!(decimalClock >= startTimeDecimalHour))
{
continue;
}
num3 = decimalClock < endTimeDecialHour;
}
if (!num3)
{
continue;
}
goto IL_025b;
IL_025b:
int num4 = (int)SessionData.Instance.day;
if (startTimeDecimalHour > endTimeDecialHour && decimalClock < endTimeDecialHour)
{
num4 = (num4 + 6) % 7;
}
List<WeekDay> workDaysList = val2.workDaysList;
if (workDaysList != null && workDaysList.Count > 0 && !workDaysList.Contains((WeekDay)num4))
{
continue;
}
if (rosterLogged.Add(((Object)val2).GetHashCode()) && flag)
{
ManualLogSource l = Plugin.L;
BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(43, 7, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[JOBS] ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(cname);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)val2.preset).name);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(val3.GetCitizenName());
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(": shift ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(startTimeDecimalHour, "0.#");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("-");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(endTimeDecialHour, "0.#");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<int>(workDaysList?.Count ?? 0);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" work days, goal now '");
BepInExInfoLogInterpolatedStringHandler obj4 = val4;
NewAIController ai = ((Actor)val3).ai;
object obj5;
if (ai == null)
{
obj5 = null;
}
else
{
NewAIGoal currentGoal = ai.currentGoal;
if (currentGoal == null)
{
obj5 = null;
}
else
{
AIGoalPreset preset2 = currentGoal.preset;
obj5 = ((preset2 != null) ? ((Object)preset2).name : null);
}
}
if (obj5 == null)
{
obj5 = "none";
}
((BepInExLogInterpolatedStringHandler)obj4).AppendFormatted<string>((string)obj5);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("'");
}
l.LogInfo(val4);
}
NewAIController ai2 = ((Actor)val3).ai;
NewAIGoal val5 = ((ai2 != null) ? ai2.currentGoal : null);
object obj6;
if (val5 == null)
{
obj6 = null;
}
else
{
AIGoalPreset preset3 = val5.preset;
obj6 = ((preset3 != null) ? ((Object)preset3).name : null);
}
if (obj6 == null)
{
obj6 = "none";
}
string name = (string)obj6;
if (flag && (!lastGoal.TryGetValue(((Object)val2).GetHashCode(), out string value) || value != name))
{
lastGoal[((Object)val2).GetHashCode()] = name;
ManualLogSource l2 = Plugin.L;
BepInExDebugLogInterpolatedStringHandler val6 = new BepInExDebugLogInterpolatedStringHandler(18, 5, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("[GOAL] ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(cname);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(val3.GetCitizenName());
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(": ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(value ?? "start");
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(" -> ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(name);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(" at ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<float>(decimalClock, "0.00");
}
l2.LogDebug(val6);
}
if (name == "Work")
{
continue;
}
if (allowed == null)
{
allowed = (from x in Plugin.AllowedDuringShift.Value.Split(',')
select x.Trim() into x
where x.Length > 0
select x).ToArray();
}
if (allowed.Any((string x) => name.IndexOf(x, StringComparison.OrdinalIgnoreCase) >= 0) || (name.IndexOf("Toilet", StringComparison.OrdinalIgnoreCase) >= 0 && val3.bladder <= Plugin.UrgentBladder.Value))
{
continue;
}
if (seen.Add(((Object)val2.preset).name + "/" + name))
{
ManualLogSource l3 = Plugin.L;
BepInExInfoLogInterpolatedStringHandler val4 = new BepInExInfoLogInterpolatedStringHandler(65, 6, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("[JOBS] ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(((Object)val2.preset).name);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(val3.GetCitizenName());
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(" was leaving for '");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<string>(name);
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("' during the shift (");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(startTimeDecimalHour, "0.#");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("-");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(endTimeDecialHour, "0.#");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral(", now ");
((BepInExLogInterpolatedStringHandler)val4).AppendFormatted<float>(decimalClock, "0.0");
((BepInExLogInterpolatedStringHandler)val4).AppendLiteral("); sent back");
}
l3.LogInfo(val4);
}
Stalls.EnsureWorkGoal(val3);
if (cname == "WeaponsDealer" && Time.unscaledTime > nextDealerLog)
{
nextDealerLog = Time.unscaledTime + 60f;
try
{
List<string> list = new List<string>();
int num5 = 0;
while ((Object)(object)((Actor)val3).ai != (Object)null && num5 < ((Actor)val3).ai.goals.Count)
{
NewAIGoal obj7 = ((Actor)val3).ai.goals[num5];
object obj8;
if (obj7 == null)
{
obj8 = null;
}
else
{
AIGoalPreset preset4 = obj7.preset;
obj8 = ((preset4 != null) ? ((Object)preset4).name : null);
}
if (obj8 == null)
{
obj8 = "?";
}
list.Add((string)obj8);
num5++;
}
ManualLogSource l4 = Plugin.L;
BepInExDebugLogInterpolatedStringHandler val6 = new BepInExDebugLogInterpolatedStringHandler(65, 6, ref flag2);
if (flag2)
{
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("[JOBS] dealer check ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(val3.GetCitizenName());
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(": at '");
BepInExDebugLogInterpolatedStringHandler obj9 = val6;
NewGameLocation currentGameLocation = ((Actor)val3).currentGameLocation;
((BepInExLogInterpolatedStringHandler)obj9).AppendFormatted<string>((currentGameLocation != null) ? ((Object)currentGameLocation).name : null);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("', job at '");
BepInExDebugLogInterpolatedStringHandler obj10 = val6;
NewAddress address = companyDirectory[num].address;
((BepInExLogInterpolatedStringHandler)obj10).AppendFormatted<string>((address != null) ? ((Object)address).name : null);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("', ");
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("work spot ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<bool>(val3.workPosition != null);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(", ai ");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<bool>((Object)(object)((Actor)val3).ai != (Object)null);
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral(", goals [");
((BepInExLogInterpolatedStringHandler)val6).AppendFormatted<string>(string.Join(", ", list));
((BepInExLogInterpolatedStringHandler)val6).AppendLiteral("]");
}
l4.LogDebug(val6);
}
catch (Exception ex)
{
Plugin.L.LogInfo((object)("[JOBS] dealer check failed: " + ex.Message));
}
}
if (val5 != null)
{
val5.OnDeactivate(1f);
}
}
}
}
catch
{
}
}
}
internal static class AlwaysOpen
{
internal static void Apply()
{
//IL_0344: Unknown result type (might be due to invalid IL or missing references)
//IL_034b: Expected O, but got Unknown
//IL_02be: Unknown result type (might be due to invalid IL or missing references)
//IL_02c5: Expected O, but got Unknown
string[] array = (from x in Plugin.AlwaysOpenCompanies.Value.Split(',')
select x.Trim() into x
where x.Length > 0
select x).ToArray();
if (array.Length == 0 || (Object)(object)CityData.Instance == (Object)null)
{
return;
}
int num = 0;
List<Company> companyDirectory = CityData.Instance.companyDirectory;
bool flag = default(bool);
BepInExInfoLogInterpolatedStringHandler val3;
for (int num2 = 0; num2 < companyDirectory.Count; num2++)
{
Company val = companyDirectory[num2];
object obj;
if (val == null)
{
obj = null;
}
else
{
CompanyPreset preset = val.preset;
obj = ((preset != null) ? ((Object)preset).name : null);
}
if (obj == null)
{
obj = "";
}
string cname = (string)obj;
if (!array.Any((string w) => cname.IndexOf(w, StringComparison.OrdinalIgnoreCase) >= 0))
{
continue;
}
List<Occupation> companyRoster = val.companyRoster;
if (companyRoster == null)
{
continue;
}
List<Occupation> list = new List<Occupation>();
for (int num3 = 0; num3 < companyRoster.Count; num3++)
{
if (companyRoster[num3] != null && (SoCustomComparison)(object)companyRoster[num3].preset != (SoCustomComparison)null)
{
list.Add(companyRoster[num3]);
}
}
if (list.Count == 0)
{
continue;
}
bool[,] c = new bool[7, 24];
foreach (Occupation item in list)
{
Mark(c, item.startTimeDecimalHour, item.endTimeDecialHour, Days(item));
}
Occupation val2 = (from j in list
group j by ((Object)j.preset).name into g
orderby g.Count() descending
select g).First().First();
float startTimeDecimalHour = val2.startTimeDecimalHour;
float endTimeDecialHour = val2.endTimeDecialHour;
List<WeekDay> list2 = new List<WeekDay>();
List<WeekDay> list3 = new List<WeekDay>();
for (int num4 = 0; num4 < 7; num4++)
{
if (Gap(c, num4, startTimeDecimalHour, endTimeDecialHour))
{
list2.Add((WeekDay)num4);
}
if (Math.Abs(endTimeDecialHour - startTimeDecimalHour) < 23.5f && Gap(c, num4, endTimeDecialHour, startTimeDecimalHour))
{
list3.Add((WeekDay)num4);
}
}
int count = companyRoster.Count;
if (list2.Count > 0)
{
companyRoster.Add(Copy(val2, startTimeDecimalHour, endTimeDecialHour, list2));
num++;
}
if (list3.Count > 0)
{
companyRoster.Add(Copy(val2, endTimeDecialHour, startTimeDecimalHour, list3));
num++;
}
if (companyRoster.Count != count)
{
ManualLogSource l = Plugin.L;
val3 = new BepInExInfoLogInterpolatedStringHandler(18, 3, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[OPEN] ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(val.name);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" (");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<string>(cname);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("): ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(companyRoster.Count);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" posts");
}
l.LogInfo(val3);
}
}
ManualLogSource l2 = Plugin.L;
val3 = new BepInExInfoLogInterpolatedStringHandler(26, 1, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("[OPEN] ");
((BepInExLogInterpolatedStringHandler)val3).AppendFormatted<int>(num);
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral(" extra shifts added");
}
l2.LogInfo(val3);
}
private static List<WeekDay> Days(Occupation j)
{
//IL_0012: Unknown result type (might be due to invalid IL or missing references)
List<WeekDay> list = new List<WeekDay>();
int num = 0;
while (j.workDaysList != null && num < j.workDaysList.Count)
{
list.Add(j.workDaysList[num]);
num++;
}
if (list.Count == 0)
{
for (int i = 0; i < 7; i++)
{
list.Add((WeekDay)i);
}
}
return list;
}
private static IEnumerable<(int d, int h)> Hours(float start, float end, int day)
{
int h0 = (int)Math.Floor(start);
int len = (int)Math.Ceiling((end > start) ? (end - start) : (end + 24f - start));
for (int k = 0; k < len; k++)
{
yield return (d: (day + (h0 + k) / 24) % 7, h: (h0 + k) % 24);
}
}
private static void Mark(bool[,] c, float start, float end, List<WeekDay> days)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Expected I4, but got Unknown
foreach (WeekDay day in days)
{
foreach (var (num, num2) in Hours(start, end, (int)day))
{
c[num, num2] = true;
}
}
}
private static bool Gap(bool[,] c, int day, float start, float end)
{
int num = 0;
int num2 = 0;
foreach (var item3 in Hours(start, end, day))
{
int item = item3.d;
int item2 = item3.h;
num2++;
if (!c[item, item2])
{
num++;
}
}
if (num2 > 0)
{
return num * 2 >= num2;
}
return false;
}
private static Occupation Copy(Occupation src, float start, float end, List<WeekDay> days)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Expected O, but got Unknown
//IL_0063: Unknown result type (might be due to invalid IL or missing references)
//IL_00e0: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
Occupation val = new Occupation();
int idAssign = Occupation.idAssign;
Occupation.idAssign = idAssign + 1;
val.id = idAssign;
val.preset = src.preset;
val.name = src.name;
val.employer = src.employer;
val.boss = src.boss;
val.paygrade = src.paygrade;
val.teamID = src.teamID;
val.work = src.work;
val.tags = src.tags;
val.shift = src.shift;
val.salary = src.salary;
val.salaryString = src.salaryString;
val.startTimeDecimalHour = start;
val.endTimeDecialHour = end;
val.workHours = ((end > start) ? (end - start) : (end + 24f - start));
val.lunchBreak = false;
val.workDaysList = new List<WeekDay>();
foreach (WeekDay day in days)
{
val.workDaysList.Add(day);
}
return val;
}
}
}