diff --git a/1.2/Assemblies/PrisonLabor.dll b/1.2/Assemblies/PrisonLabor.dll index 5e82cbdb..e66eb78b 100644 Binary files a/1.2/Assemblies/PrisonLabor.dll and b/1.2/Assemblies/PrisonLabor.dll differ diff --git a/About/About.xml b/About/About.xml index c16c9449..caed7958 100644 --- a/About/About.xml +++ b/About/About.xml @@ -23,7 +23,7 @@ - Version 1.2.2 + Version 1.2.3 This mod force prisoners to work. To enable this feature prisoners must have "Force to work" option checked ("Prisoner" tab). Prison labor needs management that consist: - Motivation - prisoners need to be motivated by presence of colonists. Wardens have new job - supervising prisoners. Low motivation can lead to revolts. diff --git a/Defs/ThinkTreeDef.xml b/Defs/ThinkTreeDef.xml index 18571ade..91d01f4d 100644 --- a/Defs/ThinkTreeDef.xml +++ b/Defs/ThinkTreeDef.xml @@ -12,7 +12,13 @@
  • -
  • +
  • + ChangingApparel + +
  • + +
  • +
  • diff --git a/Languages/English/Keyed/Keys.xml b/Languages/English/Keyed/Keys.xml index f7f8c219..73c65cdb 100644 --- a/Languages/English/Keyed/Keys.xml +++ b/Languages/English/Keyed/Keys.xml @@ -91,4 +91,7 @@ Remove/put handcuffs Remove/put legscuffs + + Enable Debug Logs + Turning on this option may spam log diff --git a/README.md b/README.md index 28fa8244..8d7500b0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

    - v1.2.2 + v1.2.3

    diff --git a/Source/CompatibilityPatches/Initialization.cs b/Source/CompatibilityPatches/Initialization.cs index 03a22e49..83fdd8a4 100644 --- a/Source/CompatibilityPatches/Initialization.cs +++ b/Source/CompatibilityPatches/Initialization.cs @@ -12,6 +12,7 @@ internal static void Run() //NoWaterNoLife.Init(); WorkTab.Init(); Quarry.Init(); + Kajin2.Init(); } } } diff --git a/Source/CompatibilityPatches/Kajin2.cs b/Source/CompatibilityPatches/Kajin2.cs new file mode 100644 index 00000000..b88fc6ea --- /dev/null +++ b/Source/CompatibilityPatches/Kajin2.cs @@ -0,0 +1,64 @@ +using HarmonyLib; +using PrisonLabor.Core.Other; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.CompatibilityPatches +{ + static class Kajin2 + { + private static ModSearcher modSeeker; + internal static void Init() + { + ModSearcher modSeeker = new ModSearcher("Kijin Race 2.0"); + if (modSeeker.LookForMod()) + { + Patch(); + } + } + + private static void Patch() + { + try + { + MethodBase methodBase = getTargetMethod(); + if (methodBase != null) + { + var harmony = new Harmony("Harmony_PrisonLabor_Kajin2"); + harmony.Patch(methodBase, postfix: new HarmonyMethod(typeof(Kajin2).GetMethod("postfix_Job"))); + } + } + catch (Exception e) + { + Log.Error($"PrisonLaborException: failed to proceed Kijin Race 2.0 mod patches: {e.ToString()}"); + } + + } + + public static Pawn postfix_Job( Pawn __result, IntVec3 c, Map map) + { + if (__result == null) + { + foreach(Thing thing in GridsUtility.GetThingList(c, map) ) + { + Pawn val = thing as Pawn; + if (val != null && !val.Dead && !val.Downed && val.IsPrisonerOfColony) + { + return val; + } + } + } + return __result; + } + private static MethodBase getTargetMethod() + { + return AccessTools.Method("Kijin2.Kijin2PlantCollectedPatch:GetFirstPawnNotDeadOrDowned"); + } + } +} diff --git a/Source/Core/AI/JobGivers/JobGiver_BedTime.cs b/Source/Core/AI/JobGivers/JobGiver_BedTime.cs index 30977965..de152d51 100644 --- a/Source/Core/AI/JobGivers/JobGiver_BedTime.cs +++ b/Source/Core/AI/JobGivers/JobGiver_BedTime.cs @@ -19,6 +19,10 @@ public override ThinkNode DeepCopy(bool resolve = true) public override float GetPriority(Pawn pawn) { + if (pawn.needs.rest == null) + { + return 0f; + } if (HealthAIUtility.ShouldHaveSurgeryDoneNow(pawn)) return 15f; if (pawn.timetable != null && pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Sleep) @@ -28,6 +32,10 @@ public override float GetPriority(Pawn pawn) protected override Job TryGiveJob(Pawn pawn) { + if(pawn.needs.rest == null) + { + return null; + } if (pawn.timetable == null || pawn.timetable.CurrentAssignment != TimeAssignmentDefOf.Sleep) return null; if (RestUtility.DisturbancePreventsLyingDown(pawn)) diff --git a/Source/Core/Incidents/IncidentWorker_ResocializationOffer.cs b/Source/Core/Incidents/IncidentWorker_ResocializationOffer.cs index 1a059a0e..a969f1b0 100644 --- a/Source/Core/Incidents/IncidentWorker_ResocializationOffer.cs +++ b/Source/Core/Incidents/IncidentWorker_ResocializationOffer.cs @@ -18,7 +18,7 @@ protected override bool CanFireNowSub(IncidentParms parms) foreach (var pawn in map.mapPawns.PrisonersOfColony) { - if (pawn.IsColonist) + if (pawn.IsColonist || !pawn.Spawned) continue; var treatment = pawn.needs.TryGetNeed(); @@ -39,7 +39,7 @@ protected override bool TryExecuteWorker(IncidentParms parms) var affectedPawns = new List(map.mapPawns.PrisonersOfColony); foreach (var pawn in map.mapPawns.PrisonersOfColony) { - if (pawn.IsColonist) + if (pawn.IsColonist || !pawn.Spawned) continue; var treatment = pawn.needs.TryGetNeed(); @@ -58,8 +58,14 @@ protected override bool TryExecuteWorker(IncidentParms parms) return false; Tutorials.Treatment(); - - SendStandardLetter(parms, prisoner, prisoner.Name.ToStringShort, prisoner.Faction.Name); + if (prisoner.Faction == null) + { + SendStandardLetter(parms, prisoner, prisoner.Name.ToStringShort); + } + else + { + SendStandardLetter(parms, prisoner, prisoner.Name.ToStringShort, prisoner.Faction.Name); + } return true; } } diff --git a/Source/Core/Incidents/IncidentWorker_Suicide.cs b/Source/Core/Incidents/IncidentWorker_Suicide.cs index a78551b6..daa2d4cf 100644 --- a/Source/Core/Incidents/IncidentWorker_Suicide.cs +++ b/Source/Core/Incidents/IncidentWorker_Suicide.cs @@ -21,7 +21,7 @@ protected override bool CanFireNowSub(IncidentParms parms) foreach (var pawn in map.mapPawns.PrisonersOfColony) { - if (pawn.IsColonist || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation) == 0f || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness) == 0f) + if (pawn.IsColonist || !pawn.Spawned || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation) == 0f || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness) == 0f) { continue; } @@ -42,7 +42,7 @@ protected override bool TryExecuteWorker(IncidentParms parms) var affectedPawns = new List(map.mapPawns.PrisonersOfColony); foreach (var pawn in map.mapPawns.PrisonersOfColony) { - if (pawn.IsColonist) + if (pawn.IsColonist || !pawn.Spawned || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Manipulation) == 0f || pawn.health.capacities.GetLevel(PawnCapacityDefOf.Consciousness) == 0f) continue; var need = pawn.needs.TryGetNeed(); diff --git a/Source/Core/Meta/Prefs.cs b/Source/Core/Meta/Prefs.cs index 78fb1e20..9d55d141 100644 --- a/Source/Core/Meta/Prefs.cs +++ b/Source/Core/Meta/Prefs.cs @@ -15,6 +15,18 @@ public static class PrisonLaborPrefs private static readonly string prefsFilePath = Path.Combine(GenFilePaths.ConfigFolderPath, "PrisonLabor_Prefs.xml"); + public static bool DebugLogs + { + get + { + return data.enable_debug_logging; + } + set + { + data.enable_debug_logging = value; + Apply(); + } + } public static Version Version { get { return data.version; } @@ -209,6 +221,7 @@ public static void RestoreToDefault() data.version = version; data.last_version = last_version; data.tutorials_flags = tutorials; + data.enable_debug_logging = false; Apply(); } diff --git a/Source/Core/Meta/PrefsData.cs b/Source/Core/Meta/PrefsData.cs index cbdcfb35..0ec8eb8b 100644 --- a/Source/Core/Meta/PrefsData.cs +++ b/Source/Core/Meta/PrefsData.cs @@ -15,6 +15,7 @@ public class PrisonLaborPrefsData public bool show_treatment_happiness = false; public bool enable_suicide = true; public bool enable_full_heal_rest = true; + public bool enable_debug_logging = false; public Version last_version = Version.v0_0; public bool show_news = true; diff --git a/Source/Core/Meta/Version.cs b/Source/Core/Meta/Version.cs index 84bbf79d..47a8c096 100644 --- a/Source/Core/Meta/Version.cs +++ b/Source/Core/Meta/Version.cs @@ -64,6 +64,7 @@ public enum Version v1_1_11, v1_2_0, v1_2_1, - v1_2_2 + v1_2_2, + v1_2_3 } } diff --git a/Source/Core/Meta/VersionUtility.cs b/Source/Core/Meta/VersionUtility.cs index 4d8242ae..8d7da64a 100644 --- a/Source/Core/Meta/VersionUtility.cs +++ b/Source/Core/Meta/VersionUtility.cs @@ -5,8 +5,8 @@ namespace PrisonLabor.Core.Meta { class VersionUtility { - public const Version versionNumber = Version.v1_2_2; - public const string versionString = "1.2.2"; + public const Version versionNumber = Version.v1_2_3; + public const string versionString = "1.2.3"; public static Version VersionOfSaveFile { get; set; } diff --git a/Source/Core/Needs/Need_Motivation.cs b/Source/Core/Needs/Need_Motivation.cs index a2ae7275..e9ae8d63 100644 --- a/Source/Core/Needs/Need_Motivation.cs +++ b/Source/Core/Needs/Need_Motivation.cs @@ -85,7 +85,11 @@ private float GetChangePoints() value -= BGP.Laziness_LazyRate; if (HealthAIUtility.ShouldSeekMedicalRest(pawn)) value -= BGP.Laziness_HealthRate; - value -= (int)pawn.needs.food.CurCategory * BGP.Laziness_HungryRate; + if (pawn.needs.food != null) + { + //warforged + value -= (int)pawn.needs.food.CurCategory * BGP.Laziness_HungryRate; + } // Some pawns have no rest need (e.g. Pawns with Circadian Half Cycler or androids from other mods) if (pawn.needs.rest != null) { diff --git a/Source/Core/Needs/Need_Treatment.cs b/Source/Core/Needs/Need_Treatment.cs index b036eb8d..f1a77b5e 100644 --- a/Source/Core/Needs/Need_Treatment.cs +++ b/Source/Core/Needs/Need_Treatment.cs @@ -85,18 +85,21 @@ public override void NeedInterval() CurLevel += BGP.JoyRate; // Status - var hunger = pawn.needs.TryGetNeed(); - - int statusScore = 0; - if (hunger.CurCategory < HungerCategory.UrgentlyHungry) - statusScore += 5; - if (hunger.CurCategory < HungerCategory.Hungry) - statusScore += 5; - statusScore -= (int)pawn.health.hediffSet.PainTotal / 10; - if (pawn.health.HasHediffsNeedingTend()) - statusScore -= 7; - - CurLevel += statusScore * BGP.StatusMultiplier; + if (pawn.needs.food != null) + { + var hunger = pawn.needs.TryGetNeed(); + + int statusScore = 0; + if (hunger.CurCategory < HungerCategory.UrgentlyHungry) + statusScore += 5; + if (hunger.CurCategory < HungerCategory.Hungry) + statusScore += 5; + statusScore -= (int)pawn.health.hediffSet.PainTotal / 10; + if (pawn.health.HasHediffsNeedingTend()) + statusScore -= 7; + + CurLevel += statusScore * BGP.StatusMultiplier; + } // Labor diff --git a/Source/Core/Other/CleanPrisonersStatus.cs b/Source/Core/Other/CleanPrisonersStatus.cs new file mode 100644 index 00000000..1be2e40c --- /dev/null +++ b/Source/Core/Other/CleanPrisonersStatus.cs @@ -0,0 +1,31 @@ +using PrisonLabor.Constants; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Other +{ + public static class CleanPrisonersStatus + { + + static public void Clean(Pawn prisoner) + { + prisoner.workSettings = new Pawn_WorkSettings(prisoner); + Hediff legs = prisoner.health.hediffSet.GetFirstHediffOfDef(PL_DefOf.PrisonLabor_RemovedLegscuffs, false); + if (legs != null) + { + prisoner.health.hediffSet.hediffs.Remove(legs); + } + Hediff hands = prisoner.health.hediffSet.GetFirstHediffOfDef(PL_DefOf.PrisonLabor_RemovedHandscuffs, false); + if (hands != null) + { + prisoner.health.hediffSet.hediffs.Remove(hands); + } + prisoner.playerSettings.AreaRestriction = null; + } + } +} diff --git a/Source/Core/Other/CustomForbidenUtil.cs b/Source/Core/Other/CustomForbidenUtil.cs index ffb69956..dc170536 100644 --- a/Source/Core/Other/CustomForbidenUtil.cs +++ b/Source/Core/Other/CustomForbidenUtil.cs @@ -10,70 +10,74 @@ namespace PrisonLabor.Core.Other { - public static class CustomForbidenUtil + public static class CustomForbidenUtil { - public static bool PrisonerCaresAboutForbidden(Pawn pawn, bool cellTarget) - { - if (!pawn.Spawned || !pawn.IsPrisonerOfColony && pawn.timetable.CurrentAssignment != TimeAssignmentDefOf.Work) - { - return false; - } - if (pawn.InMentalState) - { - return false; - } - if (cellTarget && ThinkNode_ConditionalShouldFollowMaster.ShouldFollowMaster(pawn)) - { - return false; - } - return true; - } + public static bool PrisonerCaresAboutForbidden(Pawn pawn, bool cellTarget) + { + if (!pawn.Spawned || !pawn.IsPrisonerOfColony && pawn.timetable.CurrentAssignment != TimeAssignmentDefOf.Work) + { + return false; + } + if (pawn.InMentalState) + { + return false; + } + if (cellTarget && ThinkNode_ConditionalShouldFollowMaster.ShouldFollowMaster(pawn)) + { + return false; + } + return true; + } - public static bool IsFoodForbiden(this Thing t, Pawn pawn) + public static bool IsFoodForbiden(this Thing t, Pawn pawn) { - return PrisonerFoodReservation.IsReserved(t) && !pawn.IsPrisoner; - } + if (pawn.IsPrisonerOfColony) + { + DebugLogger.debug($"[PL] Pawn {pawn.LabelShort} checking null object"); + } + return t != null && PrisonerFoodReservation.IsReserved(t) && !pawn.IsPrisoner; + } - public static bool IsForbiddenForPrisoner(this Thing t, Pawn pawn) - { + public static bool IsForbiddenForPrisoner(this Thing t, Pawn pawn) + { - if (pawn.IsWatched() && ForbidUtility.IsForbidden(t, Faction.OfPlayer)) - { - return true; - } - if (!PrisonerCaresAboutForbidden(pawn, cellTarget: false)) - { - return false; - } - if (t.Spawned && t.Position.IsForbiddenForPrisoner(pawn)) - { - return true; - } - Lord lord = pawn.GetLord(); - if (lord != null && lord.extraForbiddenThings.Contains(t)) - { - return true; - } - return false; - } + if (pawn.IsWatched() && ForbidUtility.IsForbidden(t, Faction.OfPlayer)) + { + return true; + } + if (!PrisonerCaresAboutForbidden(pawn, cellTarget: false)) + { + return false; + } + if (t != null && t.Spawned && t.Position.IsForbiddenForPrisoner(pawn)) + { + return true; + } + Lord lord = pawn.GetLord(); + if (lord != null && lord.extraForbiddenThings.Contains(t)) + { + return true; + } + return false; + } - public static bool IsForbiddenForPrisoner(this IntVec3 c, Pawn pawn) - { - if (!PrisonerCaresAboutForbidden(pawn, cellTarget: true)) - { - return false; - } - if (!c.InAllowedArea(pawn)) - { - return true; - } - if (pawn.mindState.maxDistToSquadFlag > 0f && !c.InHorDistOf(pawn.DutyLocation(), pawn.mindState.maxDistToSquadFlag)) - { - return true; - } - return false; - } - } + public static bool IsForbiddenForPrisoner(this IntVec3 c, Pawn pawn) + { + if (!PrisonerCaresAboutForbidden(pawn, cellTarget: true)) + { + return false; + } + if (!c.InAllowedArea(pawn)) + { + return true; + } + if (pawn.mindState.maxDistToSquadFlag > 0f && !c.InHorDistOf(pawn.DutyLocation(), pawn.mindState.maxDistToSquadFlag)) + { + return true; + } + return false; + } + } } diff --git a/Source/Core/Other/DebugLogger.cs b/Source/Core/Other/DebugLogger.cs new file mode 100644 index 00000000..c454f972 --- /dev/null +++ b/Source/Core/Other/DebugLogger.cs @@ -0,0 +1,26 @@ +using PrisonLabor.Core.Meta; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Other +{ + public static class DebugLogger + { + public static void debug(string msg) + { + if (PrisonLaborPrefs.DebugLogs) + { + Log.Message(msg); + } + } + + public static void info(string msg) + { + Log.Message(msg); + } + } +} diff --git a/Source/Core/PrisonLaborUtility.cs b/Source/Core/PrisonLaborUtility.cs index aacf2db2..dc544f0a 100644 --- a/Source/Core/PrisonLaborUtility.cs +++ b/Source/Core/PrisonLaborUtility.cs @@ -30,8 +30,8 @@ public static bool RecruitInLaborEnabled(Pawn pawn) public static bool WorkTime(Pawn pawn) { - if (pawn.needs == null || pawn.needs.food == null || pawn.needs.rest == null) - return false; +/* if (pawn.needs == null || pawn.needs.food == null || pawn.needs.rest == null) + return false;*/ if (pawn.timetable == null) return true; if (pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Work) diff --git a/Source/Core/Settings/SettingsMenu.cs b/Source/Core/Settings/SettingsMenu.cs index b50e5991..4839ef73 100644 --- a/Source/Core/Settings/SettingsMenu.cs +++ b/Source/Core/Settings/SettingsMenu.cs @@ -22,6 +22,7 @@ internal class SettingsMenu : Mod private static bool enableFullHealRest; private static bool advancedGrowing; private static int defaultInteractionMode; + private static bool enableDebbuging; private static List interactionModeList; @@ -40,6 +41,7 @@ public static void Init() enableSuicide = PrisonLaborPrefs.EnableSuicide; showTreatmentHappiness = PrisonLaborPrefs.ShowTreatmentHappiness; enableFullHealRest = PrisonLaborPrefs.EnableFullHealRest; + enableDebbuging = PrisonLaborPrefs.DebugLogs; interactionModeList = new List(DefDatabase.AllDefs); defaultInteractionMode = interactionModeList.IndexOf(DefDatabase.GetNamed(PrisonLaborPrefs.DefaultInteractionMode)); @@ -107,6 +109,9 @@ public override void DoSettingsWindowContents(Rect inRect) listing_options.CheckboxLabeled("PrisonLabor_EnableFullHealRest".Translate(), ref enableFullHealRest, "PrisonLabor_EnableFullHealRestDesc".Translate()); + listing_options.CheckboxLabeled("PrisonLabor_EnableDebugLogs".Translate(), ref enableDebbuging, + "PrisonLabor_EnableDebugLogsDesc".Translate()); + listing_options.GapLine(); @@ -177,6 +182,7 @@ public override void WriteSettings() PrisonLaborPrefs.EnableSuicide = enableSuicide; PrisonLaborPrefs.EnableFullHealRest = enableFullHealRest; PrisonLaborPrefs.DefaultInteractionMode = interactionModeList[defaultInteractionMode].defName; + PrisonLaborPrefs.DebugLogs = enableDebbuging; PrisonLaborPrefs.Save(); Log.Message("Prison Labor settings saved"); } diff --git a/Source/HarmonyPatches/Patches_BillAssignation/Patch_Bill_ProductionWithUft.cs b/Source/HarmonyPatches/Patches_BillAssignation/Patch_Bill_ProductionWithUft.cs new file mode 100644 index 00000000..8f1440db --- /dev/null +++ b/Source/HarmonyPatches/Patches_BillAssignation/Patch_Bill_ProductionWithUft.cs @@ -0,0 +1,69 @@ +using HarmonyLib; +using PrisonLabor.Core.Other; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.HarmonyPatches.Patches_BillAssignation +{ + [HarmonyPatch(typeof(Bill_ProductionWithUft), "get_BoundWorker")] + class Patch_Bill_ProductionWithUft + { + + static void Prefix(Bill_ProductionWithUft __instance, out UnfinishedThing __state) + { + UnfinishedThing unfinishedThing = Traverse.Create(__instance).Field("boundUftInt").GetValue(); + + if(unfinishedThing != null && unfinishedThing.Creator != null && unfinishedThing.Creator.IsPrisonerOfColony) + { + DebugLogger.debug($"[PL] Saving unfinished thing to state pawn: {unfinishedThing.Creator.LabelShort}, bill: {unfinishedThing.LabelShort}"); + __state = unfinishedThing; + } + else + { + __state = null; + } + + } + + static Pawn Postfix(Pawn __result, Bill_ProductionWithUft __instance, UnfinishedThing __state) + { + + if (__result == null && __state != null) + { + Pawn creator = __state.Creator; + if (creator == null || creator.Downed || creator.Destroyed || !creator.Spawned) + { + return __result; + } + Thing thing = __instance.billStack.billGiver as Thing; + if (thing != null) + { + WorkTypeDef workTypeDef = null; + List allDefsListForReading = DefDatabase.AllDefsListForReading; + for (int i = 0; i < allDefsListForReading.Count; i++) + { + if (allDefsListForReading[i].fixedBillGiverDefs != null && allDefsListForReading[i].fixedBillGiverDefs.Contains(thing.def)) + { + workTypeDef = allDefsListForReading[i].workType; + break; + } + } + if (workTypeDef != null && !creator.workSettings.WorkIsActive(workTypeDef)) + { + return __result; + } + } + Traverse.Create(__instance).Field("boundUftInt").SetValue(__state); + DebugLogger.debug($"Returning creator {creator.LabelShort}, value override"); + return creator; + } + + return __result; + } + } +} diff --git a/Source/HarmonyPatches/Patches_Food/ReservedByPrisonerPatch.cs b/Source/HarmonyPatches/Patches_Food/ReservedByPrisonerPatch.cs index 19ea7c32..6da5d673 100644 --- a/Source/HarmonyPatches/Patches_Food/ReservedByPrisonerPatch.cs +++ b/Source/HarmonyPatches/Patches_Food/ReservedByPrisonerPatch.cs @@ -33,6 +33,10 @@ static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase public static bool CanHaulAndInPrisonCell(Pawn p, Thing t, bool forced) { + if (p.IsPrisonerOfColony) + { + DebugLogger.debug($"Prisoner {p.LabelShort} call: {t}"); + } var unfinishedThing = t as UnfinishedThing; if (unfinishedThing != null && unfinishedThing.BoundBill != null) return false; diff --git a/Source/HarmonyPatches/Patches_ForbidUtil/Patch_ForbidUtility.cs b/Source/HarmonyPatches/Patches_ForbidUtil/Patch_ForbidUtility.cs index 2c7d229a..f7bd4297 100644 --- a/Source/HarmonyPatches/Patches_ForbidUtil/Patch_ForbidUtility.cs +++ b/Source/HarmonyPatches/Patches_ForbidUtil/Patch_ForbidUtility.cs @@ -18,13 +18,19 @@ class Patch_ForbidUtility [HarmonyPatch(new[] { typeof(Thing), typeof(Pawn) })] static bool isForbidPostfix(bool __result, Thing t, Pawn pawn) { + if (pawn.IsPrisonerOfColony) + { + DebugLogger.debug($"Prisoner {pawn.LabelShort}, forbid result: {__result} for {t}"); + } if (t.IsFoodForbiden(pawn)) { + DebugLogger.debug($"Forbid postfix food return true for {t}"); return true; } if (pawn.IsPrisonerOfColony) { + DebugLogger.debug($"Forbid postfix return { t.IsForbiddenForPrisoner(pawn)} for {t}"); return t.IsForbiddenForPrisoner(pawn); } diff --git a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs index e1adfe2d..49c9249f 100644 --- a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs +++ b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs @@ -14,80 +14,80 @@ namespace PrisonLabor.HarmonyPatches.Patches_GUI.GUI_Bill [HarmonyPatch("GeneratePawnRestrictionOptions")] class Patch_RestrictBillToPrisoner { - static IEnumerable> Postfix(IEnumerable> values, Dialog_BillConfig __instance) - { - foreach (Widgets.DropdownMenuElement value in values) + static IEnumerable> Postfix(IEnumerable> values, Dialog_BillConfig __instance) + { + foreach (Widgets.DropdownMenuElement value in values) { - yield return value; + yield return value; } Bill_Production bill = Traverse.Create(__instance).Field("bill").GetValue(); - WorkGiverDef workGiver = bill.billStack.billGiver.GetWorkgiver(); + WorkGiverDef workGiver = bill.billStack.billGiver.GetWorkgiver(); List allPrisonersOfColony = PawnsFinder.AllMaps_PrisonersOfColony; - Widgets.DropdownMenuElement dropdownMenuElement; - foreach (Pawn pawn in allPrisonersOfColony) - { - if (PrisonLaborUtility.LaborEnabled(pawn)) - { - if (pawn.WorkTypeIsDisabled(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("{0} ({1})", pawn.LabelShortCap, "WillNever".Translate(workGiver.verb)), null), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (bill.recipe.workSkill != null && !pawn.workSettings.WorkIsActive(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("{0} ({1} {2}, {3})", pawn.LabelShortCap, pawn.skills.GetSkill(bill.recipe.workSkill).Level, bill.recipe.workSkill.label, "NotAssigned".Translate()), delegate - { - bill.pawnRestriction = pawn; - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (!pawn.workSettings.WorkIsActive(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("{0} ({1})", pawn.LabelShortCap, "NotAssigned".Translate()), delegate - { - bill.pawnRestriction = pawn; - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (bill.recipe.workSkill != null) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption($"{pawn.LabelShortCap} ({pawn.skills.GetSkill(bill.recipe.workSkill).Level} {bill.recipe.workSkill.label})", delegate - { - bill.pawnRestriction = pawn; - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption($"{pawn.LabelShortCap}", delegate - { - bill.pawnRestriction = pawn; - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - } - } - } - } + Widgets.DropdownMenuElement dropdownMenuElement; + foreach (Pawn pawn in allPrisonersOfColony) + { + if (PrisonLaborUtility.LaborEnabled(pawn)) + { + if (pawn.WorkTypeIsDisabled(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption(string.Format("{0} ({1})", pawn.LabelShortCap, "WillNever".Translate(workGiver.verb)), null), + payload = pawn + }; + yield return dropdownMenuElement; + } + else if (bill.recipe.workSkill != null && !pawn.workSettings.WorkIsActive(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption(string.Format("{0} ({1} {2}, {3})", pawn.LabelShortCap, pawn.skills.GetSkill(bill.recipe.workSkill).Level, bill.recipe.workSkill.label, "NotAssigned".Translate()), delegate + { + bill.pawnRestriction = pawn; + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else if (!pawn.workSettings.WorkIsActive(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption(string.Format("{0} ({1})", pawn.LabelShortCap, "NotAssigned".Translate()), delegate + { + bill.pawnRestriction = pawn; + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else if (bill.recipe.workSkill != null) + { + dropdownMenuElement = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption($"{pawn.LabelShortCap} ({pawn.skills.GetSkill(bill.recipe.workSkill).Level} {bill.recipe.workSkill.label})", delegate + { + bill.pawnRestriction = pawn; + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else + { + dropdownMenuElement = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption($"{pawn.LabelShortCap}", delegate + { + bill.pawnRestriction = pawn; + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + } + } + } + } } diff --git a/Source/HarmonyPatches/Patches_GUI/GUI_PrisonerTab/Patch_PrisonerTab.cs b/Source/HarmonyPatches/Patches_GUI/GUI_PrisonerTab/Patch_PrisonerTab.cs index 38ab4eb6..21de5b95 100644 --- a/Source/HarmonyPatches/Patches_GUI/GUI_PrisonerTab/Patch_PrisonerTab.cs +++ b/Source/HarmonyPatches/Patches_GUI/GUI_PrisonerTab/Patch_PrisonerTab.cs @@ -1,5 +1,7 @@ using HarmonyLib; +using PrisonLabor.Constants; using PrisonLabor.Core.Needs; +using PrisonLabor.Core.Other; using PrisonLabor.Core.Trackers; using RimWorld; using System; @@ -74,8 +76,10 @@ public static void AddRecruitButton(Listing_Standard listingStandard) { if (listingStandard.ButtonTextLabeled("PrisonLabor_RecruitButtonDesc".Translate(), "PrisonLabor_RecruitButtonLabel".Translate())) { + CleanPrisonersStatus.Clean(pawn); pawn.guest.SetGuestStatus(null); pawn.SetFaction(Faction.OfPlayer); + } } } diff --git a/Source/HarmonyPatches/Patches_Work/Patch_JobGiver_Repair.cs b/Source/HarmonyPatches/Patches_Work/Patch_JobGiver_Repair.cs new file mode 100644 index 00000000..1774d0a7 --- /dev/null +++ b/Source/HarmonyPatches/Patches_Work/Patch_JobGiver_Repair.cs @@ -0,0 +1,65 @@ +using HarmonyLib; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using Verse.AI; + +namespace PrisonLabor.HarmonyPatches.Patches_Work +{ + [HarmonyPatch(typeof(WorkGiver_Repair))] + class Patch_JobGiver_Repair + { + [HarmonyPrefix] + [HarmonyPatch("ShouldSkip")] + static bool shouldSkipPrefix(ref bool __result, Pawn pawn, bool forced) + { + if (pawn != null && pawn.IsPrisonerOfColony) + { + __result = pawn.Map.listerBuildingsRepairable.RepairableBuildings(Faction.OfPlayer).Count == 0; + return false; + } + + return true; + } + + [HarmonyPrefix] + [HarmonyPatch("PotentialWorkThingsGlobal")] + static bool PotentialWorkThingsGlobalPrefix(ref IEnumerable __result, Pawn pawn) + { + if (pawn != null && pawn.IsPrisonerOfColony) + { + __result = pawn.Map.listerBuildingsRepairable.RepairableBuildings(Faction.OfPlayer); + return false; + } + + return true; + } + + [HarmonyPrefix] + [HarmonyPatch("HasJobOnThing")] + static bool HasJobOnThingPrefix(ref bool __result, Pawn pawn, Thing t, bool forced) + { + if(pawn != null && pawn.IsPrisonerOfColony) + { + Building building = t as Building; + // Fuckin monster yeah I know. All negated values from oryginal method only for prisoners + if (building != null && pawn.Map.listerBuildingsRepairable.Contains(Faction.OfPlayer, building) + && building.def.building.repairable && (t.def.useHitPoints || t.HitPoints != t.MaxHitPoints) && pawn.Map.areaManager.Home[t.Position] + && pawn.CanReserveAndReach(t, PathEndMode.ClosestTouch, pawn.NormalMaxDanger(), 1, -1, null, forced) + && building.Map.designationManager.DesignationOn(building, DesignationDefOf.Deconstruct) == null + && (!building.def.mineable && building.Map.designationManager.DesignationAt(building.Position, DesignationDefOf.Mine) == null) + && building.IsBurning() + ) + { + __result = true; + return false; + } + } + return true; + } + } +} diff --git a/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_RescueDowned.cs b/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_RescueDowned.cs new file mode 100644 index 00000000..46b1fb5f --- /dev/null +++ b/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_RescueDowned.cs @@ -0,0 +1,36 @@ +using HarmonyLib; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.HarmonyPatches.Patches_Work +{ + [HarmonyPatch(typeof(WorkGiver_RescueDowned), "ShouldSkip")] + + class Patch_WorkGiver_RescueDowned + { + static bool Prefix(ref bool __result, Pawn pawn, bool forced) + { + if(pawn != null && pawn.IsPrisonerOfColony) + { + List list = pawn.Map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer); + for (int i = 0; i < list.Count; i++) + { + if (list[i].Downed && !list[i].InBed()) + { + __result = false; + return false; + } + } + __result = true; + return false; + } + + return true; + } + } +} diff --git a/Source/HarmonyPatches/Patches_WorkSettings/Patch_ResetWorktableWhenRecruited.cs b/Source/HarmonyPatches/Patches_WorkSettings/Patch_ResetWorktableWhenRecruited.cs index c5c391f4..cb9b3bf1 100644 --- a/Source/HarmonyPatches/Patches_WorkSettings/Patch_ResetWorktableWhenRecruited.cs +++ b/Source/HarmonyPatches/Patches_WorkSettings/Patch_ResetWorktableWhenRecruited.cs @@ -1,5 +1,6 @@ using HarmonyLib; using PrisonLabor.Constants; +using PrisonLabor.Core.Other; using RimWorld; using System; using System.Collections.Generic; @@ -11,28 +12,20 @@ namespace PrisonLabor.HarmonyPatches.Patches_WorkSettings { - [HarmonyPatch(typeof(Pawn))] - [HarmonyPatch("SetFaction")] - [HarmonyPatch(new[] { typeof(Faction), typeof(Pawn) })] + [HarmonyPatch(typeof(InteractionWorker_RecruitAttempt))] + [HarmonyPatch("DoRecruit")] + [HarmonyPatch(new Type[] { typeof(Pawn), typeof(Pawn), typeof(float), typeof(string), typeof(string), typeof(bool), typeof(bool) }, + new ArgumentType[] { ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Out, ArgumentType.Normal, ArgumentType.Normal })] class Patch_ResetWorktableWhenRecruited { - private static void Prefix(Pawn __instance, Faction newFaction, Pawn recruiter) - { - if (__instance.RaceProps.Humanlike && newFaction == Faction.OfPlayer) + static void Prefix(Pawn recruiter, Pawn recruitee) + { + if(recruitee != null && recruitee.IsPrisonerOfColony && recruiter != null && recruiter.Faction == Faction.OfPlayer) { - __instance.workSettings = new Pawn_WorkSettings(__instance); - Hediff legs = __instance.health.hediffSet.GetFirstHediffOfDef(PL_DefOf.PrisonLabor_RemovedLegscuffs, false); - if (legs != null) - { - __instance.health.hediffSet.hediffs.Remove(legs); - } - Hediff hands = __instance.health.hediffSet.GetFirstHediffOfDef(PL_DefOf.PrisonLabor_RemovedHandscuffs, false); - if (hands != null) - { - __instance.health.hediffSet.hediffs.Remove(hands); - } - __instance.playerSettings.AreaRestriction = null; + CleanPrisonersStatus.Clean(recruitee); + Log.Message($"[PrisonLabor] Removed prisoners effects from {recruitee.LabelShort}"); } } + } } diff --git a/Source/HarmonyPatches/Patches_WorkSettings/Patch_RespectAllowedArea.cs b/Source/HarmonyPatches/Patches_WorkSettings/Patch_RespectAllowedArea.cs index 2ff4db45..36b7dc7d 100644 --- a/Source/HarmonyPatches/Patches_WorkSettings/Patch_RespectAllowedArea.cs +++ b/Source/HarmonyPatches/Patches_WorkSettings/Patch_RespectAllowedArea.cs @@ -16,7 +16,7 @@ class Patch_RespectAllowedArea static bool Postfix(bool __result, Pawn_PlayerSettings __instance) { Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue(); - if (!__result && pawn.IsPrisonerOfColony ) + if (!__result && pawn != null && pawn.IsPrisonerOfColony ) { return true; } diff --git a/Source/PrisonLabor.csproj b/Source/PrisonLabor.csproj index 42935158..54ceea07 100644 --- a/Source/PrisonLabor.csproj +++ b/Source/PrisonLabor.csproj @@ -70,6 +70,7 @@ + @@ -91,7 +92,9 @@ + + @@ -102,6 +105,7 @@ + @@ -154,9 +158,11 @@ + + diff --git a/Source/WorkUtils/ConstructionUtils.cs b/Source/WorkUtils/ConstructionUtils.cs index 98d8ccbd..74229fd4 100644 --- a/Source/WorkUtils/ConstructionUtils.cs +++ b/Source/WorkUtils/ConstructionUtils.cs @@ -20,7 +20,7 @@ public static bool HasJobOnThingFixed(Pawn pawn, Thing t, bool forced) { return false; } - if (!pawn.Map.listerBuildingsRepairable.Contains(pawn.Faction, building)) + if (!pawn.Map.listerBuildingsRepairable.Contains(Faction.OfPlayer, building)) { return false; } @@ -36,7 +36,7 @@ public static bool HasJobOnThingFixed(Pawn pawn, Thing t, bool forced) { return false; } - if (pawn.Faction == Faction.OfPlayer && !pawn.Map.areaManager.Home[t.Position]) + if (pawn.IsPrisonerOfColony && !pawn.Map.areaManager.Home[t.Position]) { JobFailReason.Is(WorkGiver_FixBrokenDownBuilding.NotInHomeAreaTrans); return false; diff --git a/changelog.txt b/changelog.txt index a135c878..f4808427 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,14 @@ Changelog: +1.2.3 +- Fixing issue with faction set (animal and recruiting) from 1.2.1 and 1.2.2 +- Prisoners without food and/or sleep needs should work normally +- Lots of null objects checks - it should reduce amount of errors +- Suicide and resocialization event condition update. Those events should not trigger when a pawn is not spawned +- Added logic for prisoners to search for appeal before work start. Put appeal in their cell and naked prisoners should wear it +- Compatibility with "Kijin Race 2.0". Prisoners should drop hay when research is done, and they cut plants +- More fixes for construction jobs. Pawn without faction should not spam errors +- Improved continuation of unfinished bills. With that improvement mod human resources should be compatible +- Update Chinese translation 1.2.2 - NPE fix for drawning icon - Fix issue with animal taming