diff --git a/1.4/Assemblies/PrisonLabor.dll b/1.4/Assemblies/PrisonLabor.dll index 49ff026..df47e9d 100644 Binary files a/1.4/Assemblies/PrisonLabor.dll and b/1.4/Assemblies/PrisonLabor.dll differ diff --git a/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll b/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll index ed4cd19..e08b25a 100644 Binary files a/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll and b/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll differ diff --git a/1.4/CleaningArea/Assemblies/PrisonLaborCleaningAreaCompatibility.dll b/1.4/CleaningArea/Assemblies/PrisonLaborCleaningAreaCompatibility.dll index eac3a85..553835b 100644 Binary files a/1.4/CleaningArea/Assemblies/PrisonLaborCleaningAreaCompatibility.dll and b/1.4/CleaningArea/Assemblies/PrisonLaborCleaningAreaCompatibility.dll differ diff --git a/1.4/ColonyGroups/Assemblies/PrisonLaborColonyGroupsCompatibility.dll b/1.4/ColonyGroups/Assemblies/PrisonLaborColonyGroupsCompatibility.dll index b0d7ad8..e937cdd 100644 Binary files a/1.4/ColonyGroups/Assemblies/PrisonLaborColonyGroupsCompatibility.dll and b/1.4/ColonyGroups/Assemblies/PrisonLaborColonyGroupsCompatibility.dll differ diff --git a/1.4/Defs/Hediffs.xml b/1.4/Defs/Hediffs.xml index 9adf6c0..f0fee53 100644 --- a/1.4/Defs/Hediffs.xml +++ b/1.4/Defs/Hediffs.xml @@ -4,13 +4,14 @@ PrisonLabor_PrisonerChains This pawn has prisoners chains. Note: it is default Vanilla mechanics, but in hediff state + false
  • false
  • - + false 0.01
  • @@ -57,6 +58,7 @@ PrisonLabor_RemovedHandscuffs Prisoner has removed handscuffs + false
  • @@ -73,6 +75,7 @@ PrisonLabor_RemovedLegscuffs Prisoner has removed legscuffs + false
  • diff --git a/1.4/Defs/Interrogation/InterrogationDefs.xml b/1.4/Defs/Interrogation/InterrogationDefs.xml new file mode 100644 index 0000000..94d27e1 --- /dev/null +++ b/1.4/Defs/Interrogation/InterrogationDefs.xml @@ -0,0 +1,67 @@ + + + + PL_GenQuest + +
  • OpportunitySite_ItemStash
  • +
  • OpportunitySite_WorkSite
  • + + + + PL_InterrogationChair + + Not comfortable chair used to interrogate prisoners. + + Things/Building/Furniture/DiningChair + Graphic_Multi + (1,1) + + (0.25,0.234375,0.5,0.28125) + (0.25,0.234375,0.5,0.28125) + (0.28125,0.25,0.453125,0.25) + (0.28125,0.25,0.453125,0.25) + + + (0.23, 0.26, 0.23) + + + Building + + 100 + 8000 + 5 + 1.0 + 1 + 0.30 + 5 + + true + +
  • Metallic
  • +
  • Woody
  • +
    + 45 + 30 + Misc7 + 0.35 + South + 2410 + + true + true + + 4 + +
  • ComplexFurniture
  • +
    + +
  • +
  • + + + + PL_InterrogationRoom + + PrisonLabor.Core.Interrogation.RoomRoleWorker_InterrogationRoom + + \ No newline at end of file diff --git a/1.4/Defs/Interrogation/InterrogationInteractionsDefs.xml b/1.4/Defs/Interrogation/InterrogationInteractionsDefs.xml new file mode 100644 index 0000000..e94b6e2 --- /dev/null +++ b/1.4/Defs/Interrogation/InterrogationInteractionsDefs.xml @@ -0,0 +1,36 @@ + + + + PL_InterrogateInteraction + + InteractionWorker + True + UI/Icons/Rituals/Trial + + +
  • r_logentry->[INITIATOR_nameDef] asked [RECIPIENT_nameDef] [askPart].
  • +
  • r_logentry->[INITIATOR_nameDef] ordered [RECIPIENT_nameDef] to told about [askPart].
  • +
  • askPart->where is the loot
  • +
  • askPart->why is Gamora
  • +
  • askPart->when finally starts talking
  • +
  • askPart->where is their base
  • + + + + + PL_BeIntrrogatedInteraction + + InteractionWorker + True + UI/Icons/Rituals/TrialDefend + + +
  • r_logentry->[INITIATOR_nameDef] called for mercy.
  • +
  • r_logentry->[INITIATOR_nameDef] begged to spare the face.
  • +
  • r_logentry->[INITIATOR_nameDef] kept silence.
  • +
  • r_logentry->[INITIATOR_nameDef] has no idea.
  • +
  • r_logentry->[INITIATOR_nameDef] told everything.
  • +
    +
    +
    + \ No newline at end of file diff --git a/1.4/Defs/Interrogation/InterrogationPatterns.xml b/1.4/Defs/Interrogation/InterrogationPatterns.xml new file mode 100644 index 0000000..cbe8b30 --- /dev/null +++ b/1.4/Defs/Interrogation/InterrogationPatterns.xml @@ -0,0 +1,160 @@ + + + + PL_Interrogation + + Initiate a prisoner interrogation. Warden will take prisoner and try to get usefull information. Depends on warden's traits and abilities prisoner may end up pretty beat up. + PL_Interrogation + Things/Mote/SpeechSymbols/Speech + Ritual + Precept_Ritual + false + true + false + 1.0 + true + false + true + false + false + + + PL_Interrogation + false + PL_Interrogation + SelectedThing + PL_InterrogationRoom + PL_Interrogation + false + true + + + PL_Interrogation + PrisonLabor.Core.Interrogation.Ritual.RitualOutcomeEffectWorker_Interrogation + false + false + +
  • + + + + PL_InterrogationRoom + PrisonLabor.Core.Interrogation.Ritual.RitualObligationTargetWorker_Interrogation + + + PL_Interrogation + PrisonLabor.Core.Interrogation.Ritual.RitualBehaviorWorker_Interrogation + 5000 + + Spectators are not needed + + +
  • + + an warden + warden + 1 + True + False + false + True +
  • +
  • + + a prisoner + prisoner + 1 + True + False + false +
  • + + +
  • + false + +
  • + warden + prisoner + Convicted prisoner is not reachable. +
  • +
  • + escort asleep + warden +
  • + + +
  • + +
  • prisoner
  • + + +
    + +
  • + warden + DeliverPawnToCell + +
  • + +
  • +
  • + prisoner + Idle +
  • +
    + +
  • + false + +
  • + 1 +
  • + + +
  • + warden + PL_Interrogate + +
  • + false +
  • + + +
  • + prisoner + StandOnCell +
  • +
    + +
    + + + PL_Interrogate + HighPriority + Off + true + + +
  • + 0.6 + +
  • + 50~250 +
  • +
    + +
  • + Speech_Ideoligious_Male + Speech_Ideoligious_Female +
  • + +
    +
    + + PL_Interrogate + PrisonLabor.Core.Interrogation.Ritual.JobDriver_Interrogate + talking. + false + +
    \ No newline at end of file diff --git a/1.4/Defs/Interrogation/InterrogationThoughtDefs.xml b/1.4/Defs/Interrogation/InterrogationThoughtDefs.xml new file mode 100644 index 0000000..2dd2e79 --- /dev/null +++ b/1.4/Defs/Interrogation/InterrogationThoughtDefs.xml @@ -0,0 +1,66 @@ + + + + PL_BitMe + Thought_MemorySocial + 10 + 300 + 1 + Baby, Child, Adult + +
  • + + this fricking lunatic bit me during interrogation + -7 +
  • +
    +
    + + PL_KindInterrogation + Thought_MemorySocial + 10 + 300 + 1 + Baby, Child, Adult + +
  • + + Interrogation was kind of... nice? + 2 +
  • +
    +
    + + PL_Interrogated + Thought_MemorySocial + 10 + 300 + 1 + Baby, Child, Adult + +
  • + + -7 +
  • +
    +
    + + PL_BrutallyInterrogated + Thought_MemorySocial + 10 + 300 + 1 + Baby, Child, Adult + +
  • Masochist
  • +
    + +
  • + + they beat me up during interrogation + -7 + -7 +
  • +
    +
    +
    \ No newline at end of file diff --git a/1.4/Defs/MainButton.xml b/1.4/Defs/MainButton.xml index 4c10254..6578d9a 100644 --- a/1.4/Defs/MainButton.xml +++ b/1.4/Defs/MainButton.xml @@ -1,147 +1,158 @@ - - PL_Prisoners_Menu - - Manage your faction prisoners - PrisonLabor.Core.MainButton_Window.PrisonerButtonWindow - PL_TabIcon - 35 - true - - - - - PL_Overview - - PrisonLabor.Core.MainButton_Window.MainTabWindow_Overview - 10 - - - - PL_LaborWindow - - PrisonLabor.Core.MainButton_Window.MainTabWindow_Labor - 20 - - - - PL_ScheduleWindow - - PrisonLabor.Core.MainButton_Window.MainTabWindow_Schedule - 30 - - - - PL_AssignWindow - - PrisonLabor.Core.MainButton_Window.MainTabWindow_Assign - 40 - - - - PL_DevWindow - - PrisonLabor.Core.MainButton_Window.MainTabWindow_Dev - true - 100 - - - - - PL_Assign - PawnTable_PlayerPawns - -
  • Label
  • -
  • MedicalCare
  • -
  • GapTiny
  • -
  • FoodRestriction
  • -
  • GapTiny
  • -
  • DrugPolicy
  • -
  • RemainingSpace
  • -
    -
    - - - PL_Overview - PawnTable_PlayerPawns - -
  • Label
  • -
  • GapTiny
  • -
  • PL_InteractionColumn
  • -
  • GapTiny
  • -
  • PL_MotivationColumn
  • -
  • GapTiny
  • -
  • PL_HasLegcuffs
  • -
  • GapTiny
  • -
  • PL_HasHandcuffs
  • -
  • GapTiny
  • -
  • PL_Resocialization
  • -
  • RemainingSpace
  • -
    -
    - - - PL_DevTable - PawnTable_PlayerPawns - -
  • Label
  • -
  • GapTiny
  • -
  • PL_EscapeColumn
  • -
  • GapTiny
  • -
  • PL_TreatmentColumn
  • -
  • RemainingSpace
  • -
    -
    - - - - PL_InteractionColumn - - Interaction mode - PrisonLabor.Core.MainButton_Window.ColumnWorker_Interaction - true - - - - PL_Resocialization - - Prisoner wants to join to your colony - PrisonLabor.Core.MainButton_Window.ColumnWorker_Resocialization - - - - PL_HasLegcuffs - - PrisonLabor.Core.MainButton_Window.ColumnWorker_HasLegcuffs - true - - - - PL_HasHandcuffs - - PrisonLabor.Core.MainButton_Window.ColumnWorker_HasHandscuffs - true - - - - PL_EscapeColumn - - PrisonLabor.Core.MainButton_Window.ColumnWorker_EscapeTracker - - - - PL_MotivationColumn - - PrisonLabor.Core.MainButton_Window.ColumnWorker_Motivation - true - - - - PL_TreatmentColumn - - PrisonLabor.Core.MainButton_Window.ColumnWorker_Treatment - true - + + PL_Prisoners_Menu + + Manage your faction prisoners + PrisonLabor.Core.MainButton_Window.PrisonerButtonWindow + PL_TabIcon + 35 + true + + + + + PL_Overview + + PrisonLabor.Core.MainButton_Window.MainTabWindow_Overview + 10 + + + + PL_LaborWindow + + PrisonLabor.Core.MainButton_Window.MainTabWindow_Labor + 20 + + + + PL_ScheduleWindow + + PrisonLabor.Core.MainButton_Window.MainTabWindow_Schedule + 30 + + + + PL_AssignWindow + + PrisonLabor.Core.MainButton_Window.MainTabWindow_Assign + 40 + + + + PL_DevWindow + + PrisonLabor.Core.MainButton_Window.MainTabWindow_Dev + true + 100 + + + + + PL_Assign + PawnTable_PlayerPawns + +
  • Label
  • +
  • MedicalCare
  • +
  • GapTiny
  • +
  • Outfit
  • +
  • GapTiny
  • +
  • FoodRestriction
  • +
  • GapTiny
  • +
  • DrugPolicy
  • +
  • RemainingSpace
  • +
    +
    + + + PL_Overview + PawnTable_PlayerPawns + +
  • Label
  • +
  • GapTiny
  • +
  • PL_InteractionColumn
  • +
  • GapTiny
  • +
  • PL_MotivationColumn
  • +
  • GapTiny
  • +
  • PL_HasLegcuffs
  • +
  • GapTiny
  • +
  • PL_HasHandcuffs
  • +
  • GapTiny
  • +
  • PL_Resocialization
  • +
  • GapTiny
  • +
  • PL_HasIntel
  • +
  • RemainingSpace
  • +
    +
    + + + PL_DevTable + PawnTable_PlayerPawns + +
  • Label
  • +
  • GapTiny
  • +
  • PL_EscapeColumn
  • +
  • GapTiny
  • +
  • PL_TreatmentColumn
  • +
  • RemainingSpace
  • +
    +
    + + + + PL_InteractionColumn + + Interaction mode + PrisonLabor.Core.MainButton_Window.ColumnWorker_Interaction + true + + + + PL_Resocialization + + Prisoner wants to join to your colony + PrisonLabor.Core.MainButton_Window.ColumnWorker_Resocialization + + + + PL_HasLegcuffs + + PrisonLabor.Core.MainButton_Window.ColumnWorker_HasLegcuffs + true + + + + PL_HasHandcuffs + + PrisonLabor.Core.MainButton_Window.ColumnWorker_HasHandscuffs + true + + + + PL_EscapeColumn + + PrisonLabor.Core.MainButton_Window.ColumnWorker_EscapeTracker + + + + PL_MotivationColumn + + PrisonLabor.Core.MainButton_Window.ColumnWorker_Motivation + true + + + + PL_TreatmentColumn + + PrisonLabor.Core.MainButton_Window.ColumnWorker_Treatment + true + + + + PL_HasIntel + + PrisonLabor.Core.MainButton_Window.ColumnWorker_HasIntel + true +
    \ No newline at end of file diff --git a/1.4/Defs/ThinkTreeDef.xml b/1.4/Defs/ThinkTreeDef.xml index 0fffd87..3903781 100644 --- a/1.4/Defs/ThinkTreeDef.xml +++ b/1.4/Defs/ThinkTreeDef.xml @@ -20,7 +20,7 @@
  • ChangingApparel -
  • +
  • diff --git a/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll b/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll index 13f3575..6880cbb 100644 Binary files a/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll and b/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll differ diff --git a/1.4/Kijin/Assemblies/PrisonLaborKijinCompatibility.dll b/1.4/Kijin/Assemblies/PrisonLaborKijinCompatibility.dll index efd8f46..d750c5b 100644 Binary files a/1.4/Kijin/Assemblies/PrisonLaborKijinCompatibility.dll and b/1.4/Kijin/Assemblies/PrisonLaborKijinCompatibility.dll differ diff --git a/1.4/Quarry/Assemblies/PrisonLaborQuarryCompatibility.dll b/1.4/Quarry/Assemblies/PrisonLaborQuarryCompatibility.dll index 93ca79a..381ffd8 100644 Binary files a/1.4/Quarry/Assemblies/PrisonLaborQuarryCompatibility.dll and b/1.4/Quarry/Assemblies/PrisonLaborQuarryCompatibility.dll differ diff --git a/1.4/Therapy/Assemblies/PrisonLaborTherapyCompatibility.dll b/1.4/Therapy/Assemblies/PrisonLaborTherapyCompatibility.dll index 851cc60..a6d894a 100644 Binary files a/1.4/Therapy/Assemblies/PrisonLaborTherapyCompatibility.dll and b/1.4/Therapy/Assemblies/PrisonLaborTherapyCompatibility.dll differ diff --git a/About/About.xml b/About/About.xml index 7266209..1762220 100644 --- a/About/About.xml +++ b/About/About.xml @@ -35,7 +35,7 @@ - Version 1.4.7 + Version 1.4.8 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/Languages/English/Keyed/Keys.xml b/Languages/English/Keyed/Keys.xml index 8d30f20..d5f8131 100644 --- a/Languages/English/Keyed/Keys.xml +++ b/Languages/English/Keyed/Keys.xml @@ -100,4 +100,15 @@ Cannot take to bed Take {0} to bed + + {0} must be a non player faction prisoner. + {0} doesn't have any more intel. + {0} needs some time before next interrogation. + Something goes wrong, pawn is missing important component. + + Prisoner {0} + + Mech can work in prison area + When disabled mechs will not work in prison labor area + diff --git a/README.md b/README.md index c722975..64640f4 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

    - v1.4.7 + v1.4.8

    diff --git a/Source/CompatibilityProjects/TeraphyCompatibility/Patches/Patch_WorkGIver_ReceiveTherapy.cs b/Source/CompatibilityProjects/TeraphyCompatibility/Patches/Patch_WorkGIver_ReceiveTherapy.cs index 33638ee..42f5959 100644 --- a/Source/CompatibilityProjects/TeraphyCompatibility/Patches/Patch_WorkGIver_ReceiveTherapy.cs +++ b/Source/CompatibilityProjects/TeraphyCompatibility/Patches/Patch_WorkGIver_ReceiveTherapy.cs @@ -24,7 +24,7 @@ static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase { if (i > 0 && ShouldPatch(codes[i], codes[i - 1])) { - DebugLogger.debug($"[PL] Therapy HasJobOnThing patch: {mBase.ReflectedType.Name}.{mBase.Name}"); + DebugLogger.debug($"Therapy HasJobOnThing patch: {mBase.ReflectedType.Name}.{mBase.Name}"); yield return new CodeInstruction(OpCodes.Call, typeof(PrisonLaborUtility).GetMethod(nameof(PrisonLaborUtility.GetPawnFaction))); } else diff --git a/Source/Core/AI/JobGivers/JobGiver_Labor.cs b/Source/Core/AI/JobGivers/JobGiver_Labor.cs index 4eb6512..4c35987 100644 --- a/Source/Core/AI/JobGivers/JobGiver_Labor.cs +++ b/Source/Core/AI/JobGivers/JobGiver_Labor.cs @@ -28,15 +28,15 @@ public override float GetPriority(Pawn pawn) TimeAssignmentDef timeAssignmentDef = (pawn.timetable == null) ? TimeAssignmentDefOf.Anything : pawn.timetable.CurrentAssignment; if (timeAssignmentDef == TimeAssignmentDefOf.Joy) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} labor piority: 0"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} labor piority: 0"); return 0f; } if (timeAssignmentDef == TimeAssignmentDefOf.Work) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} labor piority: 10"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} labor piority: 10"); return 10f; } - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} labor piority: 8"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} labor piority: 8"); return 8f; } diff --git a/Source/Core/AI/JobGivers/JobGiver_Prisoner_OptimizeApparel.cs b/Source/Core/AI/JobGivers/JobGiver_Prisoner_OptimizeApparel.cs new file mode 100644 index 0000000..da0eabb --- /dev/null +++ b/Source/Core/AI/JobGivers/JobGiver_Prisoner_OptimizeApparel.cs @@ -0,0 +1,143 @@ +using HarmonyLib; +using PrisonLabor.Core.Needs; +using PrisonLabor.Core.Other; +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.Core.AI.JobGivers +{ + public class JobGiver_Prisoner_OptimizeApparel : JobGiver_OptimizeApparel + { + private static StringBuilder debugSb; + private static List wornApparelScores = new List(); + + protected override Job TryGiveJob(Pawn pawn) + { + if (!pawn.IsPrisonerOfColony) + { + return null; + } + if (pawn.IsQuestLodger()) + { + return null; + } + if (pawn.outfits == null) + { + pawn.outfits = new Pawn_OutfitTracker(pawn); + } + + if (!DebugViewSettings.debugApparelOptimize) + { + if (Find.TickManager.TicksGame < pawn.mindState.nextApparelOptimizeTick) + { + return null; + } + } + else + { + debugSb = new StringBuilder(); + debugSb.AppendLine($"Scanning for {pawn} at {pawn.Position}"); + } + + Outfit currentOutfit = pawn.outfits.CurrentOutfit; + List wornApparel = pawn.apparel.WornApparel; + + if (pawn.IsMotivated()) + { + for (int num = wornApparel.Count - 1; num >= 0; num--) + { + if (!currentOutfit.filter.Allows(wornApparel[num]) && pawn.outfits.forcedHandler.AllowedToAutomaticallyDrop(wornApparel[num]) && !pawn.apparel.IsLocked(wornApparel[num])) + { + Job job2 = JobMaker.MakeJob(JobDefOf.RemoveApparel, wornApparel[num]); + job2.haulDroppedApparel = true; + DebugLogger.debug($"Prisoner {pawn.LabelShort} is removing: {wornApparel[num].def.defName} - called return"); + return job2; + } + } + } + else + { + DebugLogger.debug($"Prisoner {pawn.NameShortColored} not motivated. Removing apparel skiped"); + } + + Thing thing = null; + float num2 = 0f; + List list = pawn.Map.listerThings.ThingsInGroup(ThingRequestGroup.Apparel); + if (list.Count == 0) + { + SetNextOptimizeTick(pawn); + DebugLogger.debug($"No apparel found for prisoner {pawn.LabelShort}. Null return."); + return null; + } + CalculateNeedWarmth(pawn); + wornApparelScores.Clear(); + for (int i = 0; i < wornApparel.Count; i++) + { + wornApparelScores.Add(ApparelScoreRaw(pawn, wornApparel[i])); + } + for (int j = 0; j < list.Count; j++) + { + Apparel apparel = (Apparel)list[j]; + bool filterAllows = currentOutfit.filter.Allows(apparel); + bool isStored = IsStored(apparel); + bool notForbidden = !apparel.IsForbidden(pawn); + bool notBurning = !apparel.IsBurning(); + bool genderMatching = IsGenderMatchingApparel(pawn, apparel); + DebugLogger.debug($"Checking {apparel.def.defName} for {pawn.LabelShort}. Fillter allows: {filterAllows}, isStored: {isStored}," + + $" notForbidden: {notForbidden}, notBurning: {notBurning}, gender Matching: {genderMatching}"); + if (filterAllows && isStored && notForbidden && notBurning && genderMatching) + { + float num3 = ApparelScoreGain(pawn, apparel, wornApparelScores); + if (DebugViewSettings.debugApparelOptimize) + { + debugSb.AppendLine(apparel.LabelCap + ": " + num3.ToString("F2")); + } + if (!(num3 < 0.05f) && !(num3 < num2) && (!CompBiocodable.IsBiocoded(apparel) || CompBiocodable.IsBiocodedFor(apparel, pawn)) && ApparelUtility.HasPartsToWear(pawn, apparel.def) && pawn.CanReserveAndReach(apparel, PathEndMode.OnCell, pawn.NormalMaxDanger()) && apparel.def.apparel.developmentalStageFilter.Has(pawn.DevelopmentalStage)) + { + thing = apparel; + num2 = num3; + } + } + } + if (DebugViewSettings.debugApparelOptimize) + { + debugSb.AppendLine("BEST: " + thing); + Log.Message(debugSb.ToString()); + debugSb = null; + } + if (thing == null) + { + SetNextOptimizeTick(pawn); + DebugLogger.debug($"No matching apparel found for prisoner {pawn.LabelShort}. Null return."); + return null; + } + return JobMaker.MakeJob(JobDefOf.Wear, thing); + } + + private static bool IsGenderMatchingApparel(Pawn pawn, Apparel apparel) + { + return apparel.def.apparel.gender == Gender.None || apparel.def.apparel.gender == pawn.gender; + } + + private static bool IsStored(Apparel apparel) + { + return apparel.GetRoom().IsPrisonCell || apparel.IsInAnyStorage(); + } + + private void CalculateNeedWarmth(Pawn pawn) + { + Traverse.Create(this).Field("neededWarmth").SetValue(PawnApparelGenerator.CalculateNeededWarmth(pawn, pawn.Map.Tile, GenLocalDate.Twelfth(pawn))); + } + + private void SetNextOptimizeTick(Pawn pawn) + { + pawn.mindState.nextApparelOptimizeTick = Find.TickManager.TicksGame + Rand.Range(6000, 9000); + } + } +} diff --git a/Source/Core/AI/JobGivers/JobGiver_PrisonersRecreation.cs b/Source/Core/AI/JobGivers/JobGiver_PrisonersRecreation.cs index d3c8553..3fdfcc1 100644 --- a/Source/Core/AI/JobGivers/JobGiver_PrisonersRecreation.cs +++ b/Source/Core/AI/JobGivers/JobGiver_PrisonersRecreation.cs @@ -21,7 +21,7 @@ public override float GetPriority(Pawn pawn) TimeAssignmentDef timeAssignmentDef = (pawn.timetable == null) ? TimeAssignmentDefOf.Anything : pawn.timetable.CurrentAssignment; if (pawn.IsPrisoner && timeAssignmentDef == TimeAssignmentDefOf.Joy) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} joy piority: 10"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} joy piority: 10"); return 10f; } return 0f; @@ -30,29 +30,29 @@ public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobPara { if (!CanDoDuringMedicalRest && pawn.InBed() && HealthAIUtility.ShouldSeekMedicalRest(pawn)) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} no joy because of medic needs"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} no joy because of medic needs"); return ThinkResult.NoJob; } PrisonerJoyDef prisonerJoyDef = DefDatabase.GetNamed("PrisonLabor_PrisonersJoy"); //JoyGiverDef result = prisonerJoyDef.avaliableForPrisonersJoy.RandomElement(); if (prisonerJoyDef.avaliableForPrisonersJoy.TryRandomElementByWeight(def => def.Worker.GetChance(pawn), out JoyGiverDef result)) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} checking joy: {result.defName}."); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} checking joy: {result.defName}."); Job job = result.Worker?.TryGiveJob(pawn); if (job != null) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} joy from {result.defName}."); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} joy from {result.defName}."); return new ThinkResult(job, this); } } - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} no joy found. Trying walk"); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} no joy found. Trying walk"); Job walk = walkDef.Worker.TryGiveJob(pawn); if (walk != null) { - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} going for a walk."); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} going for a walk."); return new ThinkResult(walk, this); } - DebugLogger.debug($"[PL] Prisoner {pawn.NameShortColored} walk failed. Returning no job."); + DebugLogger.debug($"Prisoner {pawn.NameShortColored} walk failed. Returning no job."); return ThinkResult.NoJob; } diff --git a/Source/Core/Alerts/Alert_EscapingPrisoners.cs b/Source/Core/Alerts/Alert_EscapingPrisoners.cs index 7e5fc9c..b9eba57 100644 --- a/Source/Core/Alerts/Alert_EscapingPrisoners.cs +++ b/Source/Core/Alerts/Alert_EscapingPrisoners.cs @@ -1,3 +1,4 @@ +using PrisonLabor.Core.Components; using PrisonLabor.Core.Meta; using PrisonLabor.Core.Other; using PrisonLabor.Core.Trackers; @@ -11,37 +12,43 @@ namespace PrisonLabor.Core.Alerts { - public class Alert_EscapingPrisoners : Alert_Critical + public class Alert_EscapingPrisoners : Alert_Critical + { + public Alert_EscapingPrisoners() { - public Alert_EscapingPrisoners() - { - defaultLabel = "PrisonLabor_Alert_EscapingPrisoners_Title".Translate(); - defaultExplanation = "PrisonLabor_Alert_EscapingPrisoners_DefaultExplanation".Translate(); - } + defaultLabel = "PrisonLabor_Alert_EscapingPrisoners_Title".Translate(); + defaultExplanation = "PrisonLabor_Alert_EscapingPrisoners_DefaultExplanation".Translate(); + } - private IEnumerable PotentialEscapingPrisoners - { - get - { - return EscapeTracker.PrisonersReadyToEscape; - } - } + private IEnumerable PotentialEscapingPrisoners + { + get + { + return PawnsFinder.AllMaps_PrisonersOfColonySpawned.Where(prisoner => EscapingPrisoner(prisoner)); + } + } - public override TaggedString GetExplanation() - { - Tutorials.Motivation(); + private bool EscapingPrisoner(Pawn prisoner) + { + PrisonerComp prisonerComp = prisoner.TryGetComp(); + return prisonerComp != null && prisonerComp.EscapeTracker.ReadyToEscape; + } - var stringBuilder = new StringBuilder(); - foreach (var current in PotentialEscapingPrisoners) - stringBuilder.AppendLine(" " + current.Name.ToStringShort); - return string.Format("PrisonLabor_Alert_EscapingPrisoners_ExplanationFormat".Translate(), stringBuilder); - } + public override TaggedString GetExplanation() + { + Tutorials.Motivation(); + + var stringBuilder = new StringBuilder(); + foreach (var current in PotentialEscapingPrisoners) + stringBuilder.AppendLine(" " + current.Name.ToStringShort); + return string.Format("PrisonLabor_Alert_EscapingPrisoners_ExplanationFormat".Translate(), stringBuilder); + } - public override AlertReport GetReport() - { - if (PrisonLaborPrefs.EnableMotivationMechanics) - return AlertReport.CulpritIs(PotentialEscapingPrisoners.FirstOrDefault()); - return false; - } + public override AlertReport GetReport() + { + if (PrisonLaborPrefs.EnableMotivationMechanics) + return AlertReport.CulpritIs(PotentialEscapingPrisoners.FirstOrDefault()); + return false; } + } } diff --git a/Source/Core/Alerts/Alert_LazyPrisoners.cs b/Source/Core/Alerts/Alert_LazyPrisoners.cs index bad1b4c..a62cc2c 100644 --- a/Source/Core/Alerts/Alert_LazyPrisoners.cs +++ b/Source/Core/Alerts/Alert_LazyPrisoners.cs @@ -9,42 +9,44 @@ namespace PrisonLabor.Core.Alerts { - internal class Alert_LazyPrisoners : Alert + internal class Alert_LazyPrisoners : Alert + { + public Alert_LazyPrisoners() { - public Alert_LazyPrisoners() - { - defaultLabel = "PrisonLabor_LazyPrisonerAlert".Translate(); - defaultExplanation = "PrisonLabor_LazyPrisonerExplanationDef".Translate(); - } + defaultLabel = "PrisonLabor_LazyPrisonerAlert".Translate(); + defaultExplanation = "PrisonLabor_LazyPrisonerExplanationDef".Translate(); + } - private IEnumerable LazyPrisoners - { - get - { - var maps = Find.Maps; - for (var i = 0; i < maps.Count; i++) - foreach (var pawn in maps[i].mapPawns.AllPawns) - if (PrisonLaborUtility.LaborEnabled(pawn) && PrisonLaborUtility.WorkTime(pawn) && - pawn.needs.TryGetNeed().IsLazy) - yield return pawn; - } - } + private IEnumerable LazyPrisoners + { + get + { + return PawnsFinder.AllMaps_PrisonersOfColonySpawned.Where(prisoner => IsLazyPrisoner(prisoner)); + } + } - public override TaggedString GetExplanation() - { - Tutorials.Motivation(); + private bool IsLazyPrisoner(Pawn pawn) + { + return PrisonLaborUtility.LaborEnabled(pawn) && + PrisonLaborUtility.WorkTime(pawn) && + !pawn.IsMotivated(); + } - var stringBuilder = new StringBuilder(); - foreach (var current in LazyPrisoners) - stringBuilder.AppendLine(" " + current.Name.ToStringShort); - return string.Format("PrisonLabor_LazyPrisonerExplanation".Translate(), stringBuilder); - } + public override TaggedString GetExplanation() + { + Tutorials.Motivation(); + + var stringBuilder = new StringBuilder(); + foreach (var current in LazyPrisoners) + stringBuilder.AppendLine(" " + current.Name.ToStringShort); + return string.Format("PrisonLabor_LazyPrisonerExplanation".Translate(), stringBuilder); + } - public override AlertReport GetReport() - { - if (PrisonLaborPrefs.EnableMotivationMechanics) - return AlertReport.CulpritIs(LazyPrisoners.FirstOrDefault()); - return false; - } + public override AlertReport GetReport() + { + if (PrisonLaborPrefs.EnableMotivationMechanics) + return AlertReport.CulpritIs(LazyPrisoners.FirstOrDefault()); + return false; } + } } \ No newline at end of file diff --git a/Source/Core/Alerts/Alert_StarvingPrisoners.cs b/Source/Core/Alerts/Alert_StarvingPrisoners.cs index 5663baa..a9162d9 100644 --- a/Source/Core/Alerts/Alert_StarvingPrisoners.cs +++ b/Source/Core/Alerts/Alert_StarvingPrisoners.cs @@ -8,41 +8,41 @@ namespace PrisonLabor.Core.Alerts { - internal class Alert_StarvingPrisoners : Alert + internal class Alert_StarvingPrisoners : Alert + { + public Alert_StarvingPrisoners() { - public Alert_StarvingPrisoners() - { - defaultLabel = "PrisonLabor_StarvingPrisonerAlert".Translate(); - defaultExplanation = "PrisonLabor_StarvingPrisonerExplanationDef".Translate(); - } + defaultLabel = "PrisonLabor_StarvingPrisonerAlert".Translate(); + defaultExplanation = "PrisonLabor_StarvingPrisonerExplanationDef".Translate(); + } - private IEnumerable StarvingPrisoners - { - get - { - var maps = Find.Maps; - for (var i = 0; i < maps.Count; i++) - foreach (var pawn in maps[i].mapPawns.AllPawns) - if (PrisonLaborUtility.LaborEnabled(pawn) && PrisonLaborUtility.WorkTime(pawn) && - (!PrisonLaborPrefs.EnableMotivationMechanics || - !pawn.needs.TryGetNeed().IsLazy) && pawn.timetable != null && + private IEnumerable StarvingPrisoners + { + get + { + return PawnsFinder.AllMaps_PrisonersOfColonySpawned.Where(prisoner => IsStarvingPrisoner(prisoner)); + } + } + + private bool IsStarvingPrisoner(Pawn pawn) + { + return PrisonLaborUtility.LaborEnabled(pawn) && PrisonLaborUtility.WorkTime(pawn) && + (!PrisonLaborPrefs.EnableMotivationMechanics || !pawn.needs.TryGetNeed().IsLazy) && pawn.timetable != null && pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Anything && - pawn.needs.food.Starving) - yield return pawn; - } - } + pawn.needs.food.Starving; + } - public override TaggedString GetExplanation() - { - var stringBuilder = new StringBuilder(); - foreach (var current in StarvingPrisoners) - stringBuilder.AppendLine(" " + current.Name.ToStringShort); - return string.Format("PrisonLabor_StarvingPrisonerExplanation".Translate(), stringBuilder); - } + public override TaggedString GetExplanation() + { + var stringBuilder = new StringBuilder(); + foreach (var current in StarvingPrisoners) + stringBuilder.AppendLine(" " + current.Name.ToStringShort); + return string.Format("PrisonLabor_StarvingPrisonerExplanation".Translate(), stringBuilder); + } - public override AlertReport GetReport() - { - return AlertReport.CulpritIs(StarvingPrisoners.FirstOrDefault()); - } + public override AlertReport GetReport() + { + return AlertReport.CulpritIs(StarvingPrisoners.FirstOrDefault()); } + } } \ No newline at end of file diff --git a/Source/Core/Components/PrisonerComp.cs b/Source/Core/Components/PrisonerComp.cs index fe63946..908af67 100644 --- a/Source/Core/Components/PrisonerComp.cs +++ b/Source/Core/Components/PrisonerComp.cs @@ -13,99 +13,117 @@ namespace PrisonLabor.Core.Components { - public class PrisonerComp : ThingComp - { - private EscapeTracker escapeTracker; + public class PrisonerComp : ThingComp + { + private EscapeTracker escapeTracker; + private bool hasIntel = true; + private int lastInterraction = 0; - public EscapeTracker EscapeTracker + public EscapeTracker EscapeTracker + { + get + { + if (escapeTracker == null) { - get - { - if (escapeTracker == null) - { - escapeTracker = new EscapeTracker(this.parent as Pawn); - } - return escapeTracker; - } + escapeTracker = new EscapeTracker(this.parent as Pawn); } + return escapeTracker; + } + } + public bool HasIntel + { + get + { + return hasIntel; + } + set + { + hasIntel = value; + } + } + + public int LastInteractionTick + { + get + { + return lastInterraction; + } + set + { + lastInterraction = value; + } + } - private bool Active + private bool Active + { + get + { + Pawn pawn = this.parent as Pawn; + return pawn != null && pawn.IsPrisonerOfColony && !pawn.Dead && pawn.Spawned && pawn.CarriedBy == null; + } + } + + public override void Initialize(CompProperties props) + { + base.Initialize(props); + if (escapeTracker == null) + { + escapeTracker = new EscapeTracker(this.parent as Pawn); + } + } + public override void PostDraw() + { + if (Active && PrisonLaborPrefs.EnableMotivationIcons) + { + Pawn pawn = this.parent as Pawn; + var need = pawn.needs.TryGetNeed(); + if (pawn.health.hediffSet.HasTemperatureInjury(TemperatureInjuryStage.Serious) && PrisonLaborUtility.WorkTime(pawn)) { - get - { - Pawn pawn = this.parent as Pawn; - return pawn != null && pawn.IsPrisonerOfColony && !pawn.Dead && pawn.Spawned && pawn.CarriedBy == null; - } + DrawIcon(TexturePool.freezingTexture); } - - public override void Initialize(CompProperties props) + else if (pawn.IsWatched()) { - base.Initialize(props); - if (escapeTracker == null) - { - escapeTracker = new EscapeTracker(this.parent as Pawn); - } + DrawIcon(TexturePool.watchedTexture); } - public override void PostDraw() + else if (need != null && need.IsLazy && PrisonLaborUtility.LaborEnabled(pawn) && PrisonLaborUtility.WorkTime(pawn)) { - if (Active && PrisonLaborPrefs.EnableMotivationIcons) - { - Pawn pawn = this.parent as Pawn; - var need = pawn.needs.TryGetNeed(); - if (pawn.health.hediffSet.HasTemperatureInjury(TemperatureInjuryStage.Serious) && PrisonLaborUtility.WorkTime(pawn)) - { - DrawIcon(TexturePool.freezingTexture); - } - else if (pawn.IsWatched()) - { - DrawIcon(TexturePool.watchedTexture); - } - else if (need != null && need.IsLazy && PrisonLaborUtility.LaborEnabled(pawn) && PrisonLaborUtility.WorkTime(pawn)) - { - DrawIcon(TexturePool.lazyTexture); - } - } - + DrawIcon(TexturePool.lazyTexture); } + } + } - private void DrawIcon(Material drawIcon) - { - var drawPos = parent.DrawPos; - drawPos.y = AltitudeLayer.MetaOverlays.AltitudeFor() + 0.28125f; - drawPos.x += parent.def.size.x - 0.52f; - drawPos.z += parent.def.size.z - 0.45f; + private void DrawIcon(Material drawIcon) + { + var drawPos = parent.DrawPos; + drawPos.y = AltitudeLayer.MetaOverlays.AltitudeFor() + 0.28125f; + drawPos.x += parent.def.size.x - 0.52f; + drawPos.z += parent.def.size.z - 0.45f; - var num = (Time.realtimeSinceStartup + (397f * (parent.thingIDNumber % 571))) * 4f; - var num2 = ((float)Math.Sin(num) + 1f) * 0.5f; - num2 = 0.3f + (num2 * 0.7f); - var material = FadedMaterialPool.FadedVersionOf(drawIcon, num2); - Graphics.DrawMesh(MeshPool.plane05, drawPos, Quaternion.identity, material, 0); - } - public override void PostExposeData() - { - Scribe_Deep.Look(ref escapeTracker, "EscapeTracker", new object[] { this.parent as Pawn }); - } + var num = (Time.realtimeSinceStartup + (397f * (parent.thingIDNumber % 571))) * 4f; + var num2 = ((float)Math.Sin(num) + 1f) * 0.5f; + num2 = 0.3f + (num2 * 0.7f); + var material = FadedMaterialPool.FadedVersionOf(drawIcon, num2); + Graphics.DrawMesh(MeshPool.plane05, drawPos, Quaternion.identity, material, 0); + } - public override void CompTickRare() - { - if (Active) - { - EscapeTracker.Tick(); - } - else - { - EscapeTracker.DeRegister(this.parent as Pawn); - } - } + public override void PostExposeData() + { + Scribe_Deep.Look(ref escapeTracker, "EscapeTracker", new object[] { this.parent as Pawn }); + Scribe_Values.Look(ref hasIntel, "hasIntel", true); + Scribe_Values.Look(ref lastInterraction, "lastInteractionTick", 0); + } - public override void PostDeSpawn(Map map) - { - EscapeTracker.DeRegister(this.parent as Pawn); - } + public override void CompTickRare() + { + if (Active) + { + EscapeTracker.Tick(); + } } + } } diff --git a/Source/Core/Interrogation/Comp_Interrogation.cs b/Source/Core/Interrogation/Comp_Interrogation.cs new file mode 100644 index 0000000..daa51c0 --- /dev/null +++ b/Source/Core/Interrogation/Comp_Interrogation.cs @@ -0,0 +1,22 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation +{ + public class CompInterrogation : ThingComp + { + } + + public class CompPropertiesInterrogation : CompProperties + { + public CompPropertiesInterrogation() + { + compClass = typeof(CompInterrogation); + } + } +} diff --git a/Source/Core/Interrogation/InterrogationDefsOf.cs b/Source/Core/Interrogation/InterrogationDefsOf.cs new file mode 100644 index 0000000..c8c9be7 --- /dev/null +++ b/Source/Core/Interrogation/InterrogationDefsOf.cs @@ -0,0 +1,24 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace PrisonLabor.Core.Interrogation +{ + [DefOf] + public static class InterrogationDefsOf + { + public static InterrogationQuestGenDef PL_GenQuest; + public static ThoughtDef PL_BitMe; + public static ThoughtDef PL_KindInterrogation; + public static ThoughtDef PL_Interrogated; + public static ThoughtDef PL_BrutallyInterrogated; + public static JobDef PL_Interrogate; + public static InteractionDef PL_InterrogateInteraction; + public static InteractionDef PL_BeIntrrogatedInteraction; + } +} diff --git a/Source/Core/Interrogation/InterrogationQuestGenDef.cs b/Source/Core/Interrogation/InterrogationQuestGenDef.cs new file mode 100644 index 0000000..d9cae5f --- /dev/null +++ b/Source/Core/Interrogation/InterrogationQuestGenDef.cs @@ -0,0 +1,15 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation +{ + public class InterrogationQuestGenDef : Def + { + public List questScriptDefs; + } +} diff --git a/Source/Core/Interrogation/Ritual/JobDriver_Interrogate.cs b/Source/Core/Interrogation/Ritual/JobDriver_Interrogate.cs new file mode 100644 index 0000000..165bdb0 --- /dev/null +++ b/Source/Core/Interrogation/Ritual/JobDriver_Interrogate.cs @@ -0,0 +1,45 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; +using Verse.AI; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + [StaticConstructorOnStartup] + public class JobDriver_Interrogate : JobDriver + { + public static readonly Texture2D moteIcon = ContentFinder.Get("Things/Mote/SpeechSymbols/Speech"); + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return true; + } + + protected override IEnumerable MakeNewToils() + { + this.FailOnDespawnedNullOrForbidden(TargetIndex.A); + Toil toil = ToilMaker.MakeToil("MakeNewToils"); + toil.tickAction = delegate + { + pawn.GainComfortFromCellIfPossible(); + pawn.skills.Learn(SkillDefOf.Social, 0.01f); + pawn.rotationTracker.FaceTarget(TargetB); + Pawn prisoner = TargetThingB as Pawn; + prisoner?.rotationTracker.FaceTarget(pawn.Position); + MoteMaker.MakeSpeechBubble(pawn, moteIcon); + }; + if (ModsConfig.IdeologyActive) + { + toil.PlaySustainerOrSound(() => (pawn.gender != Gender.Female) ? job.speechSoundMale : job.speechSoundFemale, pawn.story.VoicePitchFactor); + } + toil.defaultCompleteMode = ToilCompleteMode.Delay; + toil.defaultDuration = 300; + toil.handlingFacing = true; + yield return toil; + } + } +} diff --git a/Source/Core/Interrogation/Ritual/JobGiver_Interrogate.cs b/Source/Core/Interrogation/Ritual/JobGiver_Interrogate.cs new file mode 100644 index 0000000..5c5f948 --- /dev/null +++ b/Source/Core/Interrogation/Ritual/JobGiver_Interrogate.cs @@ -0,0 +1,64 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse.AI; +using Verse; +using Verse.AI.Group; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class JobGiver_Interrogate : ThinkNode_JobGiver + { + public SoundDef soundDefMale; + + public SoundDef soundDefFemale; + + public bool faceSpectatorsIfPossible; + + public bool showSpeechBubbles = true; + + protected override Job TryGiveJob(Pawn pawn) + { + PawnDuty duty = pawn.mindState.duty; + if (duty == null) + { + return null; + } + IntVec3 result = pawn.Position; + if (!pawn.CanReserve(pawn.Position)) + { + CellFinder.TryRandomClosewalkCellNear(result, pawn.Map, 2, out result, (IntVec3 c) => pawn.CanReserveAndReach(c, PathEndMode.OnCell, pawn.NormalMaxDanger())); + } + LordJob_Ritual lordJob_Ritual = pawn.GetLord()?.LordJob as LordJob_Ritual; + if (lordJob_Ritual == null) + { + return null; + } + Pawn prisoner = lordJob_Ritual.PawnWithRole("prisoner"); + Job job = JobMaker.MakeJob(InterrogationDefsOf.PL_Interrogate, result, prisoner); + job.showSpeechBubbles = showSpeechBubbles; + LordToil_Ritual lordToil_Ritual; + if (lordJob_Ritual != null && (lordToil_Ritual = (lordJob_Ritual.lord.CurLordToil as LordToil_Ritual)) != null) + { + job.interaction = lordToil_Ritual.stage.BehaviorForRole(lordJob_Ritual.RoleFor(pawn).id).speakerInteraction; + } + job.speechSoundMale = (soundDefMale ?? SoundDefOf.Speech_Leader_Male); + job.speechSoundFemale = (soundDefFemale ?? SoundDefOf.Speech_Leader_Female); + job.speechFaceSpectatorsIfPossible = faceSpectatorsIfPossible; + return job; + } + + public override ThinkNode DeepCopy(bool resolve = true) + { + JobGiver_Interrogate obj = (JobGiver_Interrogate)base.DeepCopy(resolve); + obj.soundDefMale = soundDefMale; + obj.soundDefFemale = soundDefFemale; + obj.showSpeechBubbles = showSpeechBubbles; + obj.faceSpectatorsIfPossible = faceSpectatorsIfPossible; + return obj; + } + } +} \ No newline at end of file diff --git a/Source/Core/Interrogation/Ritual/NonColonyPrisonerRole.cs b/Source/Core/Interrogation/Ritual/NonColonyPrisonerRole.cs new file mode 100644 index 0000000..f5f884b --- /dev/null +++ b/Source/Core/Interrogation/Ritual/NonColonyPrisonerRole.cs @@ -0,0 +1,62 @@ +using PrisonLabor.Core.Components; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class NonColonyPrisonerRole : RitualRole + { + public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) + { + if (!AppliesIfChild(p, out reason, skipReason)) + { + return false; + } + if (p.IsPrisonerOfColony && !p.Faction.IsPlayer) + { + PrisonerComp prisonerComp = p.TryGetComp(); + if (prisonerComp == null) + { + PrepareReason("PrisonLabor_MissingComp".Translate(), skipReason, out reason); + return false; + } + + if (!prisonerComp.HasIntel) + { + PrepareReason("PrisonLabor_NoIntel".Translate(base.LabelCap), skipReason, out reason); + return false; + } + if (!ReadyForInterrogation(prisonerComp)) + { + PrepareReason("PrisonLabor_TooSoonInterrogation".Translate(base.LabelCap), skipReason, out reason); + return false; + } + return true; + } + + PrepareReason("PrisonLabor_MustBePrisoner".Translate(base.LabelCap), skipReason, out reason); + return false; + } + + private void PrepareReason(string baseReason, bool skipReason, out string reason) + { + reason = skipReason ? null : baseReason; + } + + private bool ReadyForInterrogation(PrisonerComp prisonerComp) + { + return prisonerComp.LastInteractionTick == 0 || Find.TickManager.TicksGame - prisonerComp.LastInteractionTick > 60_000; + } + + public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn p = null, bool skipReason = false) + { + reason = null; + return false; + } + } +} diff --git a/Source/Core/Interrogation/Ritual/RitualBehaviorWorker_Interrogation.cs b/Source/Core/Interrogation/Ritual/RitualBehaviorWorker_Interrogation.cs new file mode 100644 index 0000000..8588f92 --- /dev/null +++ b/Source/Core/Interrogation/Ritual/RitualBehaviorWorker_Interrogation.cs @@ -0,0 +1,82 @@ +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.Core.Interrogation.Ritual +{ + public class RitualBehaviorWorker_Interrogation : RitualBehaviorWorker + { + private int ticksSinceLastInteraction = -1; + + public const int SocialInteractionIntervalTicks = 700; + private const string PrisonerRoleId = "prisoner"; + private const string WardenRoleId = "warden"; + + public RitualBehaviorWorker_Interrogation() + { + } + + public RitualBehaviorWorker_Interrogation(RitualBehaviorDef def) + : base(def) + { + } + + public override void Cleanup(LordJob_Ritual ritual) + { + Pawn pawn = ritual.PawnWithRole(PrisonerRoleId); + if (pawn.IsPrisonerOfColony) + { + pawn.guest.WaitInsteadOfEscapingFor(2500); + } + } + + public override void PostCleanup(LordJob_Ritual ritual) + { + Pawn warden = ritual.PawnWithRole(WardenRoleId); + Pawn prisoner = ritual.PawnWithRole(PrisonerRoleId); + if (prisoner.IsPrisonerOfColony) + { + ArrestUtility.TakePrisonerToBed(prisoner, warden); + prisoner.guest.WaitInsteadOfEscapingFor(1250); + } + } + + public override void Tick(LordJob_Ritual ritual) + { + base.Tick(ritual); + if (ritual.StageIndex == 0) + { + return; + } + if (ticksSinceLastInteraction == -1 || ticksSinceLastInteraction > SocialInteractionIntervalTicks) + { + ticksSinceLastInteraction = 0; + Pawn warden = ritual.PawnWithRole(WardenRoleId); + Pawn prisoner = ritual.PawnWithRole(PrisonerRoleId); + if (Rand.Bool) + { + warden.interactions.TryInteractWith(prisoner, InterrogationDefsOf.PL_InterrogateInteraction); + } + else + { + prisoner.interactions.TryInteractWith(warden, InterrogationDefsOf.PL_BeIntrrogatedInteraction); + } + } + else + { + ticksSinceLastInteraction++; + } + } + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref ticksSinceLastInteraction, "ticksSinceLastInteraction", -1); + } + } +} diff --git a/Source/Core/Interrogation/Ritual/RitualObligationTargetWorker_Interrogation.cs b/Source/Core/Interrogation/Ritual/RitualObligationTargetWorker_Interrogation.cs new file mode 100644 index 0000000..b321040 --- /dev/null +++ b/Source/Core/Interrogation/Ritual/RitualObligationTargetWorker_Interrogation.cs @@ -0,0 +1,37 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class RitualObligationTargetWorker_Interrogation : RitualObligationTargetFilter + { + public RitualObligationTargetWorker_Interrogation() + { + } + + public RitualObligationTargetWorker_Interrogation(RitualObligationTargetFilterDef def) + : base(def) + { + } + + public override IEnumerable GetTargetInfos(RitualObligation obligation) + { + return Enumerable.Empty(); + } + + public override IEnumerable GetTargets(RitualObligation obligation, Map map) + { + return Enumerable.Empty(); + } + + protected override RitualTargetUseReport CanUseTargetInternal(TargetInfo target, RitualObligation obligation) + { + return target.HasThing && target.Thing.Faction != null && target.Thing.Faction.IsPlayer && target.Thing.TryGetComp() != null; + } + } +} diff --git a/Source/Core/Interrogation/Ritual/RitualOutcomeEffectWorker_Interrogation.cs b/Source/Core/Interrogation/Ritual/RitualOutcomeEffectWorker_Interrogation.cs new file mode 100644 index 0000000..46ce889 --- /dev/null +++ b/Source/Core/Interrogation/Ritual/RitualOutcomeEffectWorker_Interrogation.cs @@ -0,0 +1,232 @@ +using Mono.Cecil; +using PrisonLabor.Core.Components; +using PrisonLabor.Core.Other; +using RimWorld; +using RimWorld.QuestGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; +using Verse.AI; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class RitualOutcomeEffectWorker_Interrogation : RitualOutcomeEffectWorker + { + public RitualOutcomeEffectWorker_Interrogation() + { + } + + public RitualOutcomeEffectWorker_Interrogation(RitualOutcomeEffectDef def) + : base(def) + { + } + + private readonly float BaseChanceToGetIntel = 0.3f; + public override void Apply(float progress, Dictionary totalPresence, LordJob_Ritual jobRitual) + { + Pawn warden = jobRitual.PawnWithRole("warden"); + Pawn prisoner = jobRitual.PawnWithRole("prisoner"); + InterrogationType interrogationType; + float successChances = BaseChanceToGetIntel + CalculateChances(warden, prisoner, out interrogationType); + int hits = 0; + + if (interrogationType == InterrogationType.Brutal || interrogationType == InterrogationType.Psycho) + { + hits += PunchPrisoner(warden, prisoner); + } + if (interrogationType == InterrogationType.Psycho) + { + hits += BitePrisoner(warden, prisoner); + } + if (interrogationType == InterrogationType.Kind) + { + BeNice(warden, prisoner); + } + if (hits > 0 && warden.Faction != null && prisoner.Faction != null && warden.Faction.IsPlayer && warden.IsFreeColonist && !Faction.OfPlayer.HostileTo(prisoner.Faction)) + { + int goodwillChange = (int)(-1.3f * hits); + Faction.OfPlayer.TryAffectGoodwillWith(prisoner.Faction, goodwillChange, canSendMessage: true, false, HistoryEventDefOf.AttackedMember, prisoner); + } + + PrisonerComp prisonerComp = prisoner.GetComp(); + if (Rand.Chance(successChances)) + { + QuestScriptDef questDef = InterrogationDefsOf.PL_GenQuest.questScriptDefs.RandomElement(); + float points = StorytellerUtility.DefaultThreatPointsNow(jobRitual.Map); + Quest quest = QuestUtility.GenerateQuestAndMakeAvailable(questDef, points); + QuestUtility.SendLetterQuestAvailable(quest); + prisonerComp.HasIntel = false; + } + prisonerComp.LastInteractionTick = Find.TickManager.TicksGame; + + } + + private void BeNice(Pawn warden, Pawn prisoner) + { + if (HasTrait(warden, TraitDefOf.Kind)) + { + TryGainMemory(prisoner, warden, InterrogationDefsOf.PL_KindInterrogation); + } + TryGainMemory(prisoner, warden, InterrogationDefsOf.PL_Interrogated); + } + + private void TryGainMemory(Pawn pawn, Pawn otherPawn, ThoughtDef thoughtDef) + { + pawn.needs?.mood?.thoughts?.memories?.TryGainMemory(thoughtDef, otherPawn: otherPawn); + } + + private int BitePrisoner(Pawn warden, Pawn prisoner) + { + DoDamage(warden, prisoner, false, DamageDefOf.Bite, InterrogationDefsOf.PL_BitMe, out bool hitDone); + return hitDone ? 1 : 0; + } + + private float CalculateChances(Pawn warden, Pawn prisoner, out InterrogationType iterrogationType) + { + if (HasTrait(warden, TraitDefOf.Kind) || warden.WorkTagIsDisabled(WorkTags.Violent)) + { + iterrogationType = InterrogationType.Kind; + return GoEasy(warden, prisoner); + } + if (HasTrait(warden, TraitDefOf.Bloodlust)) + { + iterrogationType = InterrogationType.Brutal; + return GoBrutal(warden, prisoner); + } + if (HasTrait(warden, TraitDefOf.Psychopath)) + { + iterrogationType = InterrogationType.Psycho; + return GoBrutal(warden, prisoner); + } + if (Rand.Chance(0.5f + warden.relations.OpinionOf(prisoner) * 0.005f)) + { + iterrogationType = InterrogationType.Kind; + return GoEasy(warden, prisoner); + } + else + { + iterrogationType = InterrogationType.Brutal; + return GoBrutal(warden, prisoner); + } + } + + private float GoBrutal(Pawn warden, Pawn prisoner) + { + float actualChance = 0f; + //Knows how to hit + actualChance += warden.skills.GetSkill(SkillDefOf.Social).Level * 0.01f; + //Knows where to hit + actualChance += warden.skills.GetSkill(SkillDefOf.Medicine).Level * 0.01f; + //Prisoner will is still important + actualChance += Mathf.Clamp(prisoner.guest.will * 0.01f, 0, 1f); + if (HasTrait(warden, TraitDefOf.Brawler)) + { + actualChance += 0.1f; + } + if (HasTrait(prisoner, TraitDefOf.Tough)) + { + actualChance -= 0.3f; + } + if (HasTrait(prisoner, TraitDefOf.Nerves)) + { + Trait nerves = GetTrait(prisoner, TraitDefOf.Nerves); + actualChance -= nerves.Degree * 0.1f; + } + if (HasTrait(prisoner, TraitDefOf.Wimp)) + { + //Wimp can't handle beating + actualChance = 1f; + } + if (HasTrait(prisoner, TraitDefOf.Masochist)) + { + //Prisoner likes pain... + actualChance = 0f; + } + DebugLogger.debug($"Base chances for successful Brutal Interrogation: {actualChance}"); + return actualChance; + } + + private float GoEasy(Pawn warden, Pawn prisoner) + { + float actualChance = 0f; + if (HasTrait(warden, TraitDefOf.AnnoyingVoice)) + { + actualChance -= 0.2f; + } + if (HasTrait(warden, TraitDefOf.CreepyBreathing)) + { + actualChance -= 0.1f; + } + if (HasTrait(warden, TraitDefOf.TooSmart)) + { + actualChance -= 0.1f; + } + if (HasTrait(prisoner, TraitDefOf.Nerves)) + { + Trait nerves = GetTrait(prisoner, TraitDefOf.Nerves); + actualChance -= nerves.Degree * 0.1f; + } + actualChance += prisoner.relations.OpinionOf(warden) * 0.002f; + actualChance += warden.skills.GetSkill(SkillDefOf.Social).Level * 0.01f; + + actualChance += Mathf.Clamp(prisoner.guest.will * 0.01f, 0, 1f); + DebugLogger.debug($"Base chances for successful Easy Interrogation: {actualChance}"); + return actualChance; + } + + private bool HasTrait(Pawn pawn, TraitDef trait) + { + return pawn?.story?.traits != null && pawn.story.traits.HasTrait(trait); + } + + private Trait GetTrait(Pawn pawn, TraitDef trait) + { + return pawn.story.traits.GetTrait(trait); + } + + private int PunchPrisoner(Pawn warden, Pawn prisoner) + { + bool done = false; + int successful = 0; + int amountOfHits = Rand.RangeInclusive(1, warden.skills.GetSkill(SkillDefOf.Melee).Level); + for (int i = 0; i < amountOfHits && !prisoner.Downed; i++) + { + done = DoDamage(warden, prisoner, done, DamageDefOf.Blunt, InterrogationDefsOf.PL_BrutallyInterrogated, out bool hitDone); + successful += hitDone ? 1 : 0; + } + return successful; + } + + private bool DoDamage(Pawn warden, Pawn prisoner, bool done, DamageDef damageDef, ThoughtDef interrogationThoughDef, out bool hitDone) + { + hitDone = false; + IEnumerable verbs = warden.meleeVerbs.GetUpdatedAvailableVerbsList(false).Where(ve => ve.verb.GetDamageDef() == damageDef); + if (verbs.Any()) + { + Verb verb = verbs.RandomElement().verb; + float damage = verb.verbProps.AdjustedMeleeDamageAmount(verb, warden); + DamageInfo damageInfo = new DamageInfo(def: verb.verbProps.meleeDamageDef, amount: damage, instigatorGuilty: false); + prisoner.TakeDamage(damageInfo); + prisoner.pather?.StopDead(); + hitDone = true; + if (!done) + { + done = true; + TryGainMemory(prisoner, warden, interrogationThoughDef); + } + + } + return done; + } + } + internal enum InterrogationType + { + Kind, + Brutal, + Psycho + } +} diff --git a/Source/Core/Interrogation/Ritual/RitualPosition_ThingCenter.cs b/Source/Core/Interrogation/Ritual/RitualPosition_ThingCenter.cs new file mode 100644 index 0000000..8ca165c --- /dev/null +++ b/Source/Core/Interrogation/Ritual/RitualPosition_ThingCenter.cs @@ -0,0 +1,18 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class RitualPosition_ThingCenter : RitualPosition + { + public override PawnStagePosition GetCell(IntVec3 spot, Pawn p, LordJob_Ritual ritual) + { + return new PawnStagePosition(spot, null, Rot4.Invalid, highlight); + } + } +} diff --git a/Source/Core/Interrogation/Ritual/RitualSpectatorFilter_None.cs b/Source/Core/Interrogation/Ritual/RitualSpectatorFilter_None.cs new file mode 100644 index 0000000..21b7d9b --- /dev/null +++ b/Source/Core/Interrogation/Ritual/RitualSpectatorFilter_None.cs @@ -0,0 +1,18 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation.Ritual +{ + public class RitualSpectatorFilter_None : RitualSpectatorFilter + { + public override bool Allowed(Pawn p) + { + return false; + } + } +} diff --git a/Source/Core/Interrogation/RoomRoleWorker_InterrogationRoom.cs b/Source/Core/Interrogation/RoomRoleWorker_InterrogationRoom.cs new file mode 100644 index 0000000..798e12b --- /dev/null +++ b/Source/Core/Interrogation/RoomRoleWorker_InterrogationRoom.cs @@ -0,0 +1,25 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.Interrogation +{ + public class RoomRoleWorker_InterrogationRoom : RoomRoleWorker + { + public override float GetScore(Room room) + { + List containedAndAdjacentThings = room.ContainedAndAdjacentThings; + foreach (Thing thing in containedAndAdjacentThings) + { + if (thing.TryGetComp() != null) + { + return 100000f; + } + } + return 0f; + } + } +} diff --git a/Source/Core/MainButton_Window/ColumnWorker_HasIntel.cs b/Source/Core/MainButton_Window/ColumnWorker_HasIntel.cs new file mode 100644 index 0000000..e88a662 --- /dev/null +++ b/Source/Core/MainButton_Window/ColumnWorker_HasIntel.cs @@ -0,0 +1,43 @@ +using PrisonLabor.Constants; +using PrisonLabor.Core.Components; +using PrisonLabor.Core.Other; +using PrisonLabor.Core.Trackers; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.Core.MainButton_Window +{ + public class ColumnWorker_HasIntel : PawnColumnWorker_Checkbox + { + protected override bool GetValue(Pawn pawn) + { + if (pawn == null) + { + DebugLogger.debug("Null pawn in ColumnWorker_HasIntel:GetValue"); + return true; + } + PrisonerComp prisonerComp = pawn.GetComp(); + return prisonerComp != null && prisonerComp.HasIntel; + } + + protected override void SetValue(Pawn pawn, bool value, PawnTable table) + { + if (pawn == null) + { + DebugLogger.debug("Null pawn in ColumnWorker_HasIntel:SetValue"); + return; + } + table?.SetDirty(); + } + protected override bool HasCheckbox(Pawn pawn) + { + return pawn != null && pawn.GetComp() != null; + } + } +} + diff --git a/Source/Core/Meta/Prefs.cs b/Source/Core/Meta/Prefs.cs index 9d55d14..34b6920 100644 --- a/Source/Core/Meta/Prefs.cs +++ b/Source/Core/Meta/Prefs.cs @@ -8,240 +8,250 @@ namespace PrisonLabor.Core.Meta { - public static class PrisonLaborPrefs - { - private static PrisonLaborPrefsData data; - - 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; } - set - { - data.version = value; - Apply(); - } - } - - public static Version LastVersion - { - get { return data.last_version; } - set - { - data.last_version = value; - Apply(); - } - } - - public static bool ShowNews - { - get { return data.show_news; } - set - { - data.show_news = value; - Apply(); - } - } - - public static bool AllowAllWorkTypes - { - get { return data.allow_all_worktypes; } - set - { - data.allow_all_worktypes = value; - Apply(); - } - } - - public static string DefaultInteractionMode - { - get - { - return data.defaultInteraction; - } - - set - { - data.defaultInteraction = value; - Apply(); - } - } - - public static bool EnableMotivationMechanics - { - get - { - return data.enable_motivation_mechanics; - } - set - { - data.enable_motivation_mechanics = value; - Apply(); - } - } - - public static bool EnableMotivationIcons - { - get - { - return data.enable_motivation_icons; - } - set - { - data.enable_motivation_icons = value; - Apply(); - } - } - - public static bool EnableRevolts - { - get - { - return data.enable_revolts; - } - set - { - data.enable_revolts = value; - Apply(); - } - } - - public static bool ShowTreatmentHappiness - { - get - { - return data.show_treatment_happiness; - } - set - { - data.show_treatment_happiness = value; - Apply(); - } - } - - public static bool EnableSuicide - { - get - { - return data.enable_suicide; - } - set - { - data.enable_suicide = value; - Apply(); - } - } - - public static bool AdvancedGrowing - { - get { return data.advanced_growing; } - set - { - data.advanced_growing = value; - Apply(); - } - } - - public static string AllowedWorkTypes - { - get { return data.allowed_works; } - set - { - data.allowed_works = value; - Apply(); - } - } - - public static bool EnableFullHealRest - { - get { return data.enable_full_heal_rest; } - - set - { - data.enable_full_heal_rest = value; - Apply(); - } - } - - public static void Init() - { - var flag = !new FileInfo(prefsFilePath).Exists; - data = new PrisonLaborPrefsData(); - data = DirectXmlLoader.ItemFromXmlFile(prefsFilePath, true); - Apply(); - } - - public static void Save() - { - Other.Tutorials.UpdateTutorialFlags(); - try - { - var xDocument = new XDocument(); - var content = DirectXmlSaver.XElementFromObject(data, typeof(PrisonLaborPrefsData)); - xDocument.Add(content); - xDocument.Save(prefsFilePath); - } - catch (Exception ex) - { - GenUI.ErrorDialog("ProblemSavingFile".Translate(prefsFilePath, ex.ToString())); - Log.Error("Exception saving prefs: " + ex); - } - } - - public static void Apply() - { - data.Apply(); - WorkSettings.DataString = AllowedWorkTypes; - Tutorials.Apply(); - Need_Treatment.ShowOnList = ShowTreatmentHappiness; - } - - public static void RestoreToDefault() - { - var version = data.version; - var last_version = data.last_version; - var tutorials = data.tutorials_flags; - - data = new PrisonLaborPrefsData(); - - data.version = version; - data.last_version = last_version; - data.tutorials_flags = tutorials; - data.enable_debug_logging = false; - - Apply(); - } - - public static void AddTutorialFlag(TutorialFlag flag) - { - data.tutorials_flags = data.tutorials_flags | flag; - } - - public static bool HasTutorialFlag(TutorialFlag flag) - { - if ((data.tutorials_flags & flag) != 0) - return true; - return false; - } - - public static void ResetTutorials() - { - data.tutorials_flags = TutorialFlag.None; - Tutorials.Reset(); - } + public static class PrisonLaborPrefs + { + private static PrisonLaborPrefsData data; + + 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; } + set + { + data.version = value; + Apply(); + } + } + + public static Version LastVersion + { + get { return data.last_version; } + set + { + data.last_version = value; + Apply(); + } + } + + public static bool ShowNews + { + get { return data.show_news; } + set + { + data.show_news = value; + Apply(); + } + } + + public static bool AllowAllWorkTypes + { + get { return data.allow_all_worktypes; } + set + { + data.allow_all_worktypes = value; + Apply(); + } + } + + public static string DefaultInteractionMode + { + get + { + return data.defaultInteraction; + } + + set + { + data.defaultInteraction = value; + Apply(); + } + } + + public static bool EnableMotivationMechanics + { + get + { + return data.enable_motivation_mechanics; + } + set + { + data.enable_motivation_mechanics = value; + Apply(); + } + } + + public static bool EnableMotivationIcons + { + get + { + return data.enable_motivation_icons; + } + set + { + data.enable_motivation_icons = value; + Apply(); + } + } + + public static bool EnableRevolts + { + get + { + return data.enable_revolts; + } + set + { + data.enable_revolts = value; + Apply(); + } + } + + public static bool ShowTreatmentHappiness + { + get + { + return data.show_treatment_happiness; + } + set + { + data.show_treatment_happiness = value; + Apply(); + } + } + + public static bool EnableSuicide + { + get + { + return data.enable_suicide; + } + set + { + data.enable_suicide = value; + Apply(); + } + } + + public static bool AdvancedGrowing + { + get { return data.advanced_growing; } + set + { + data.advanced_growing = value; + Apply(); + } + } + + public static string AllowedWorkTypes + { + get { return data.allowed_works; } + set + { + data.allowed_works = value; + Apply(); + } + } + + public static bool EnableFullHealRest + { + get { return data.enable_full_heal_rest; } + + set + { + data.enable_full_heal_rest = value; + Apply(); + } + } + + public static bool MechsWorkInLaborZone + { + get { return data.mechs_work_in_labor_zone; } + set + { + data.mechs_work_in_labor_zone = value; + Apply(); + } + } + + public static void Init() + { + var flag = !new FileInfo(prefsFilePath).Exists; + data = new PrisonLaborPrefsData(); + data = DirectXmlLoader.ItemFromXmlFile(prefsFilePath, true); + Apply(); + } + + public static void Save() + { + Other.Tutorials.UpdateTutorialFlags(); + try + { + var xDocument = new XDocument(); + var content = DirectXmlSaver.XElementFromObject(data, typeof(PrisonLaborPrefsData)); + xDocument.Add(content); + xDocument.Save(prefsFilePath); + } + catch (Exception ex) + { + GenUI.ErrorDialog("ProblemSavingFile".Translate(prefsFilePath, ex.ToString())); + Log.Error("Exception saving prefs: " + ex); + } + } + + public static void Apply() + { + data.Apply(); + WorkSettings.DataString = AllowedWorkTypes; + Tutorials.Apply(); + Need_Treatment.ShowOnList = ShowTreatmentHappiness; + } + + public static void RestoreToDefault() + { + var version = data.version; + var last_version = data.last_version; + var tutorials = data.tutorials_flags; + + data = new PrisonLaborPrefsData(); + + data.version = version; + data.last_version = last_version; + data.tutorials_flags = tutorials; + data.enable_debug_logging = false; + + Apply(); + } + + public static void AddTutorialFlag(TutorialFlag flag) + { + data.tutorials_flags = data.tutorials_flags | flag; + } + + public static bool HasTutorialFlag(TutorialFlag flag) + { + if ((data.tutorials_flags & flag) != 0) + return true; + return false; + } + + public static void ResetTutorials() + { + data.tutorials_flags = TutorialFlag.None; + Tutorials.Reset(); } + } } \ No newline at end of file diff --git a/Source/Core/Meta/PrefsData.cs b/Source/Core/Meta/PrefsData.cs index 0ec8eb8..66348e7 100644 --- a/Source/Core/Meta/PrefsData.cs +++ b/Source/Core/Meta/PrefsData.cs @@ -2,43 +2,44 @@ namespace PrisonLabor.Core.Meta { - public class PrisonLaborPrefsData - { - public string defaultInteraction = "PrisonLabor_workOption"; - - public string allowed_works = ""; - public bool allow_all_worktypes = false; - public bool advanced_growing = false; - public bool enable_motivation_mechanics = true; - public bool enable_motivation_icons = true; - public bool enable_revolts = true; - 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 class PrisonLaborPrefsData + { + public string defaultInteraction = "PrisonLabor_workOption"; - public Version last_version = Version.v0_0; - public bool show_news = true; - public bool enable_reports = false; + public string allowed_works = ""; + public bool allow_all_worktypes = false; + public bool advanced_growing = false; + public bool enable_motivation_mechanics = true; + public bool enable_motivation_icons = true; + public bool enable_revolts = true; + 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 bool mechs_work_in_labor_zone = false; - public TutorialFlag tutorials_flags = TutorialFlag.None; - public Version version = Version.v0_0; + public Version last_version = Version.v0_0; + public bool show_news = true; + public bool enable_reports = false; - public void Apply() - { - } - } + public TutorialFlag tutorials_flags = TutorialFlag.None; + public Version version = Version.v0_0; - [Flags] - public enum TutorialFlag + public void Apply() { - None = 0x0, - Introduction = 0x1, - Motivation = 0x2, - Growing = 0x4, - Managment = 0x8, - Timetable = 0x10, - LaborAreaWarning = 0x20, - Treatment = 0x40, } + } + + [Flags] + public enum TutorialFlag + { + None = 0x0, + Introduction = 0x1, + Motivation = 0x2, + Growing = 0x4, + Managment = 0x8, + Timetable = 0x10, + LaborAreaWarning = 0x20, + Treatment = 0x40, + } } \ No newline at end of file diff --git a/Source/Core/Meta/Version.cs b/Source/Core/Meta/Version.cs index 791a4e8..2c0d6ab 100644 --- a/Source/Core/Meta/Version.cs +++ b/Source/Core/Meta/Version.cs @@ -87,6 +87,7 @@ public enum Version v1_4_4, v1_4_5, v1_4_6, - v1_4_7 + v1_4_7, + v1_4_8 } } diff --git a/Source/Core/Meta/VersionUtility.cs b/Source/Core/Meta/VersionUtility.cs index aead99f..fbe4cf3 100644 --- a/Source/Core/Meta/VersionUtility.cs +++ b/Source/Core/Meta/VersionUtility.cs @@ -5,8 +5,8 @@ namespace PrisonLabor.Core.Meta { public class VersionUtility { - public const Version versionNumber = Version.v1_4_7; - public const string versionString = "1.4.7"; + public const Version versionNumber = Version.v1_4_8; + public const string versionString = "1.4.8"; public static Version VersionOfSaveFile { get; set; } diff --git a/Source/Core/Other/CleanPrisonersStatus.cs b/Source/Core/Other/CleanPrisonersStatus.cs index dc7c30a..d6febf0 100644 --- a/Source/Core/Other/CleanPrisonersStatus.cs +++ b/Source/Core/Other/CleanPrisonersStatus.cs @@ -9,45 +9,49 @@ namespace PrisonLabor.Core.Other { - public static class CleanPrisonersStatus - { + public static class CleanPrisonersStatus + { - static public void Clean(Pawn prisoner) + static public void Clean(Pawn prisoner) + { + prisoner.workSettings = new Pawn_WorkSettings(prisoner); + CleanHediffs(prisoner); + prisoner.playerSettings.AreaRestriction = null; + if (prisoner.drugs != null) + { + prisoner.drugs.CurrentPolicy = Current.Game.drugPolicyDatabase.DefaultDrugPolicy(); + } + if (prisoner.outfits != null) + { + prisoner.outfits = null; + } + if (ModsConfig.BiotechActive) + { + if (prisoner.guest != null) { - prisoner.workSettings = new Pawn_WorkSettings(prisoner); - CleanHediffs(prisoner); - prisoner.playerSettings.AreaRestriction = null; - if (prisoner.drugs != null) - { - prisoner.drugs.CurrentPolicy = Current.Game.drugPolicyDatabase.DefaultDrugPolicy(); - } - if (ModsConfig.BiotechActive) - { - if(prisoner.guest != null) - { - prisoner.guest.interactionMode = PrisonerInteractionModeDefOf.NoInteraction; - } - Bill bill = prisoner.BillStack?.Bills?.FirstOrDefault((Bill x) => x.recipe == RecipeDefOf.ExtractHemogenPack); - if (bill != null) - { - prisoner.BillStack.Bills.Remove(bill); - } - - } + prisoner.guest.interactionMode = PrisonerInteractionModeDefOf.NoInteraction; } - - static public void CleanHediffs(Pawn prisoner) + Bill bill = prisoner.BillStack?.Bills?.FirstOrDefault((Bill x) => x.recipe == RecipeDefOf.ExtractHemogenPack); + if (bill != null) { - 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.BillStack.Bills.Remove(bill); } + + } + } + + static public void CleanHediffs(Pawn 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); + } } + } } diff --git a/Source/Core/Other/CustomForbidenUtil.cs b/Source/Core/Other/CustomForbidenUtil.cs index a0e55e5..0f4ffb9 100644 --- a/Source/Core/Other/CustomForbidenUtil.cs +++ b/Source/Core/Other/CustomForbidenUtil.cs @@ -33,7 +33,7 @@ public static bool IsFoodForbiden(this Thing t, Pawn pawn) { if (pawn.IsPrisonerOfColony) { - DebugLogger.debug($"[PL] Pawn {pawn.LabelShort} checking null object"); + DebugLogger.debug($"Pawn {pawn.LabelShort} checking null object"); } return t != null && PrisonerFoodReservation.IsReserved(t) && !pawn.IsPrisoner; } diff --git a/Source/Core/Other/DebugLogger.cs b/Source/Core/Other/DebugLogger.cs index b2a5a23..77dc89b 100644 --- a/Source/Core/Other/DebugLogger.cs +++ b/Source/Core/Other/DebugLogger.cs @@ -14,18 +14,18 @@ public static void debug(string msg) { if (PrisonLaborPrefs.DebugLogs) { - Log.Message(msg); + Log.Message("[PL] " + msg); } } public static void info(string msg) { - Log.Message(msg); + Log.Message("[PL] " + msg); } internal static void warn(string msg) { - Log.Warning(msg); + Log.Warning("[PL] " + msg); } } } diff --git a/Source/Core/PrisonLaborUtility.cs b/Source/Core/PrisonLaborUtility.cs index b234d16..93b83ec 100644 --- a/Source/Core/PrisonLaborUtility.cs +++ b/Source/Core/PrisonLaborUtility.cs @@ -10,162 +10,167 @@ namespace PrisonLabor.Core { - public static class PrisonLaborUtility - { - private static readonly List workOptions = new List { + public static class PrisonLaborUtility + { + private static readonly List workOptions = new List { PL_DefOf.PrisonLabor_workOption, PL_DefOf.PrisonLabor_workAndRecruitOption , PL_DefOf.PrisonLabor_workAndConvertOption, PL_DefOf.PrisonLabor_workAndEnslaveOption, PL_DefOf.PrisonLabor_workAndBloodfeedOption, PL_DefOf.PrisonLabor_workAndHemogenFarmOption }; - public static bool LaborEnabled(this Pawn pawn) - { - return pawn.IsPrisoner && workOptions.Contains(pawn.guest.interactionMode); - } + public static bool LaborEnabled(this Pawn pawn) + { + return pawn.IsPrisoner && workOptions.Contains(pawn.guest.interactionMode); + } - public static bool RecruitInLaborEnabled(Pawn pawn) - { - if (pawn.guest.interactionMode == PL_DefOf.PrisonLabor_workAndRecruitOption && pawn.guest.ScheduledForInteraction) - { - return true; - } + public static bool RecruitInLaborEnabled(Pawn pawn) + { + if (pawn.guest.interactionMode == PL_DefOf.PrisonLabor_workAndRecruitOption && pawn.guest.ScheduledForInteraction) + { + return true; + } - return false; - } + return false; + } - public static bool ConvertInLaborEnabled(Pawn doer, Pawn prisoner) - { - if (prisoner.guest.interactionMode == PL_DefOf.PrisonLabor_workAndConvertOption && prisoner.guest.ScheduledForInteraction - && prisoner.Ideo != doer.Ideo && doer.Ideo == prisoner.guest.ideoForConversion) - { - return true; - } - return false; - } + public static bool ConvertInLaborEnabled(Pawn doer, Pawn prisoner) + { + if (prisoner.guest.interactionMode == PL_DefOf.PrisonLabor_workAndConvertOption && prisoner.guest.ScheduledForInteraction + && prisoner.Ideo != doer.Ideo && doer.Ideo == prisoner.guest.ideoForConversion) + { + return true; + } + return false; + } - public static bool EnslaveInLaborEnabled(Pawn doer, Pawn prisoner) - { - if (prisoner.guest.interactionMode == PL_DefOf.PrisonLabor_workAndEnslaveOption && prisoner.guest.ScheduledForInteraction - && new HistoryEvent(HistoryEventDefOf.EnslavedPrisoner, doer.Named(HistoryEventArgsNames.Doer)).Notify_PawnAboutToDo_Job()) - { - return true; - } - return false; - } - public static bool WorkTime(Pawn pawn) - { - if (pawn.timetable == null) - return true; - if (pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Work) - return true; - if (pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Anything) - { - if (HealthAIUtility.ShouldSeekMedicalRest(pawn) || - pawn.health.hediffSet.HasTemperatureInjury(TemperatureInjuryStage.Serious) || - CheckFoodNeed(pawn) || - CheckRestNeed(pawn)) - return false; - else - return true; - } - return false; - } + public static bool EnslaveInLaborEnabled(Pawn doer, Pawn prisoner) + { + if (prisoner.guest.interactionMode == PL_DefOf.PrisonLabor_workAndEnslaveOption && prisoner.guest.ScheduledForInteraction + && new HistoryEvent(HistoryEventDefOf.EnslavedPrisoner, doer.Named(HistoryEventArgsNames.Doer)).Notify_PawnAboutToDo_Job()) + { + return true; + } + return false; + } + public static bool WorkTime(Pawn pawn) + { + if (pawn.timetable == null) + return true; + if (pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Work) + return true; + if (pawn.timetable.CurrentAssignment == TimeAssignmentDefOf.Anything) + { + if (HealthAIUtility.ShouldSeekMedicalRest(pawn) || + pawn.health.hediffSet.HasTemperatureInjury(TemperatureInjuryStage.Serious) || + CheckFoodNeed(pawn) || + CheckRestNeed(pawn)) + return false; + else + return true; + } + return false; + } - private static bool CheckFoodNeed(Pawn pawn) - { - return pawn.needs != null && pawn.needs.food != null && pawn.needs.food.CurCategory > HungerCategory.Hungry; - } + private static bool CheckFoodNeed(Pawn pawn) + { + return pawn.needs != null && pawn.needs.food != null && pawn.needs.food.CurCategory > HungerCategory.Hungry; + } - private static bool CheckRestNeed(Pawn pawn) - { - return pawn.needs != null && pawn.needs.rest != null && pawn.needs.rest.CurCategory != RestCategory.Rested; - } + private static bool CheckRestNeed(Pawn pawn) + { + return pawn.needs != null && pawn.needs.rest != null && pawn.needs.rest.CurCategory != RestCategory.Rested; + } - public static bool IsDisabledByLabor(IntVec3 pos, Pawn pawn, WorkTypeDef workType) - { - if (pos != null && pawn.Map.areaManager.Get() != null && - !WorkSettings.WorkDisabled(workType)) - return pawn.Map.areaManager.Get()[pos]; - return false; - } + public static bool IsDisabledByLabor(IntVec3 pos, Pawn pawn, WorkTypeDef workType) + { + if (pos != null && pawn.Map.areaManager.Get() != null && + !WorkSettings.WorkDisabled(workType)) + return pawn.Map.areaManager.Get()[pos]; + return false; + } - public static bool CanWorkHere(IntVec3 pos, Pawn pawn, WorkTypeDef workType) + public static bool CanWorkHere(IntVec3 pos, Pawn pawn, WorkTypeDef workType) + { + if (ShouldPawnBeConsidered(pawn) && pos != null && pawn.Map.areaManager.Get() != null && !WorkSettings.WorkDisabled(workType)) + { + bool result = true; + try { - if ((pawn.IsFreeNonSlaveColonist || pawn.IsColonyMech) && pos != null && pawn.Map.areaManager.Get() != null && !WorkSettings.WorkDisabled(workType)) - { - bool result = true; - try - { - result = !pawn.Map.areaManager.Get()[pos]; - } - catch (IndexOutOfRangeException e) - { - DebugLogger.debug($"{pawn.NameShortColored} cause IndexOutOfRangeException for {workType.label} calling pos {pos}"); - } - return result; - } - return true; + result = !pawn.Map.areaManager.Get()[pos]; } - - public static Faction GetPawnFaction(Pawn pawn) + catch (IndexOutOfRangeException e) { - return pawn.IsPrisonerOfColony ? Faction.OfPlayer : pawn.Faction; + DebugLogger.debug($"{pawn.NameShortColored} cause IndexOutOfRangeException for {workType.label} calling pos {pos}"); } + return result; + } + return true; + } + + private static bool ShouldPawnBeConsidered(Pawn pawn) + { + return pawn.IsFreeNonSlaveColonist || (!PrisonLaborPrefs.MechsWorkInLaborZone && pawn.IsColonyMech); + } + + public static Faction GetPawnFaction(Pawn pawn) + { + return pawn.IsPrisonerOfColony ? Faction.OfPlayer : pawn.Faction; + } - public static bool CanUsePrisonerInteraction(this Pawn prisoner, PrisonerInteractionModeDef mode) + public static bool CanUsePrisonerInteraction(this Pawn prisoner, PrisonerInteractionModeDef mode) + { + if (!prisoner.guest.Recruitable && mode.hideIfNotRecruitable) + { + return false; + } + if (prisoner.IsWildMan() && !mode.allowOnWildMan) + { + return false; + } + if (mode.hideIfNoBloodfeeders && prisoner.MapHeld != null && !ColonyHasAnyBloodfeeder(prisoner.MapHeld)) + { + return false; + } + if (mode.hideOnHemogenicPawns && ModsConfig.BiotechActive && prisoner.genes != null && prisoner.genes.HasGene(GeneDefOf.Hemogenic)) + { + return false; + } + if (!mode.allowInClassicIdeoMode && Find.IdeoManager.classicMode) + { + return false; + } + return true; + } + + private static bool ColonyHasAnyBloodfeeder(Map map) + { + if (ModsConfig.BiotechActive) + { + foreach (Pawn item in map.mapPawns.FreeColonistsSpawned) { - if (!prisoner.guest.Recruitable && mode.hideIfNotRecruitable) - { - return false; - } - if (prisoner.IsWildMan() && !mode.allowOnWildMan) - { - return false; - } - if (mode.hideIfNoBloodfeeders && prisoner.MapHeld != null && !ColonyHasAnyBloodfeeder(prisoner.MapHeld)) - { - return false; - } - if (mode.hideOnHemogenicPawns && ModsConfig.BiotechActive && prisoner.genes != null && prisoner.genes.HasGene(GeneDefOf.Hemogenic)) - { - return false; - } - if (!mode.allowInClassicIdeoMode && Find.IdeoManager.classicMode) - { - return false; - } + if (item.IsBloodfeeder()) + { return true; + } } - - private static bool ColonyHasAnyBloodfeeder(Map map) + foreach (Pawn item2 in map.mapPawns.PrisonersOfColony) { - if (ModsConfig.BiotechActive) - { - foreach (Pawn item in map.mapPawns.FreeColonistsSpawned) - { - if (item.IsBloodfeeder()) - { - return true; - } - } - foreach (Pawn item2 in map.mapPawns.PrisonersOfColony) - { - if (item2.IsBloodfeeder()) - { - return true; - } - } - } - return false; + if (item2.IsBloodfeeder()) + { + return true; + } } + } + return false; + } - public static bool HemogenFarmInteractionMode(PrisonerInteractionModeDef interaction) - { - return interaction == PrisonerInteractionModeDefOf.HemogenFarm || interaction == PL_DefOf.PrisonLabor_workAndHemogenFarmOption; - } + public static bool HemogenFarmInteractionMode(PrisonerInteractionModeDef interaction) + { + return interaction == PrisonerInteractionModeDefOf.HemogenFarm || interaction == PL_DefOf.PrisonLabor_workAndHemogenFarmOption; + } - public static bool BloodFeedInteractionMode(PrisonerInteractionModeDef interaction) - { - return interaction == PrisonerInteractionModeDefOf.Bloodfeed || interaction == PL_DefOf.PrisonLabor_workAndBloodfeedOption; - } + public static bool BloodFeedInteractionMode(PrisonerInteractionModeDef interaction) + { + return interaction == PrisonerInteractionModeDefOf.Bloodfeed || interaction == PL_DefOf.PrisonLabor_workAndBloodfeedOption; } + } } \ No newline at end of file diff --git a/Source/Core/Recreation/JoyGiver_PrisonerRecrationWalking.cs b/Source/Core/Recreation/JoyGiver_PrisonerRecrationWalking.cs index 2b3701c..64f84c1 100644 --- a/Source/Core/Recreation/JoyGiver_PrisonerRecrationWalking.cs +++ b/Source/Core/Recreation/JoyGiver_PrisonerRecrationWalking.cs @@ -39,7 +39,7 @@ public override Job TryGiveJob(Pawn pawn) { if (!pawn.IsPrisonerOfColony) { - DebugLogger.debug($"[PL] Pawn {pawn.NameShortColored} is not prisoner {typeof(JoyGiver_PrisonerRecrationWalking).Name}. Return null"); + DebugLogger.debug($"Pawn {pawn.NameShortColored} is not prisoner {typeof(JoyGiver_PrisonerRecrationWalking).Name}. Return null"); return null; } @@ -59,7 +59,7 @@ public override Job TryGiveJob(Pawn pawn) if (!exactWanderDest.IsValid) { pawn.mindState.nextMoveOrderIsWait = false; - DebugLogger.debug($"[PL] Pawn {pawn.NameShortColored} has not valid dest in {typeof(JoyGiver_PrisonerRecrationWalking).Name}. Return null"); + DebugLogger.debug($"Pawn {pawn.NameShortColored} has not valid dest in {typeof(JoyGiver_PrisonerRecrationWalking).Name}. Return null"); return null; } LocomotionUrgency value = locomotionUrgency; diff --git a/Source/Core/Recreation/RecreationUtils.cs b/Source/Core/Recreation/RecreationUtils.cs index 2f32042..8788414 100644 --- a/Source/Core/Recreation/RecreationUtils.cs +++ b/Source/Core/Recreation/RecreationUtils.cs @@ -11,66 +11,66 @@ namespace PrisonLabor.Core.Recreation { - public class RecreationUtils + public class RecreationUtils + { + public static bool PrisonerJoyTickCheckEnd(Pawn pawn, JoyTickFullJoyAction fullJoyAction = JoyTickFullJoyAction.EndJob, float extraJoyGainFactor = 1f, Building joySource = null) { - public static bool PrisonerJoyTickCheckEnd(Pawn pawn, JoyTickFullJoyAction fullJoyAction = JoyTickFullJoyAction.EndJob, float extraJoyGainFactor = 1f, Building joySource = null) + Job curJob = pawn.CurJob; + if (curJob.def.joyKind == null) + { + DebugLogger.warn("This method can only be called for jobs with joyKind."); + return false; + } + if (joySource != null) + { + if (joySource.def.building.joyKind != null && pawn.CurJob.def.joyKind != joySource.def.building.joyKind) { - Job curJob = pawn.CurJob; - if (curJob.def.joyKind == null) - { - Log.Warning("This method can only be called for jobs with joyKind."); - return false; - } - if (joySource != null) - { - if (joySource.def.building.joyKind != null && pawn.CurJob.def.joyKind != joySource.def.building.joyKind) - { - Log.ErrorOnce("Joy source joyKind and jobDef.joyKind are not the same. building=" + joySource.ToStringSafe() + ", jobDef=" + pawn.CurJob.def.ToStringSafe(), joySource.thingIDNumber ^ 0x343FD5CC); - } - extraJoyGainFactor *= joySource.GetStatValue(StatDefOf.JoyGainFactor); - } - Need treatment = pawn.needs.TryGetNeed(); - - if (treatment == null && pawn.needs.joy == null && !curJob.doUntilGatheringEnded ) - { - pawn.jobs.curDriver.EndJobWith(JobCondition.InterruptForced); - DebugLogger.debug("[PL] Both need null. Returning false."); - return false; - } + Log.ErrorOnce("Joy source joyKind and jobDef.joyKind are not the same. building=" + joySource.ToStringSafe() + ", jobDef=" + pawn.CurJob.def.ToStringSafe(), joySource.thingIDNumber ^ 0x343FD5CC); + } + extraJoyGainFactor *= joySource.GetStatValue(StatDefOf.JoyGainFactor); + } + Need treatment = pawn.needs.TryGetNeed(); + if (treatment == null && pawn.needs.joy == null && !curJob.doUntilGatheringEnded) + { + pawn.jobs.curDriver.EndJobWith(JobCondition.InterruptForced); + DebugLogger.debug("Both needs null. Returning false."); + return false; + } - //if somehow prisoner has joy need by other mods. - pawn.needs.joy?.GainJoy(extraJoyGainFactor * curJob.def.joyGainRate * 0.36f / 2500f, curJob.def.joyKind); + //if somehow prisoner has joy need by other mods. + pawn.needs.joy?.GainJoy(extraJoyGainFactor * curJob.def.joyGainRate * 0.36f / 2500f, curJob.def.joyKind); - if (curJob.def.joySkill != null) - { - pawn.skills.GetSkill(curJob.def.joySkill).Learn(curJob.def.joyXpPerTick); - } - if (!curJob.ignoreJoyTimeAssignment && !pawn.GetTimeAssignment().allowJoy && !curJob.doUntilGatheringEnded) - { - pawn.jobs.curDriver.EndJobWith(JobCondition.InterruptForced); - return true; - } - if ((NeedLevelFull(treatment) || NeedLevelFull(pawn.needs.joy)) && !curJob.doUntilGatheringEnded) - { - switch (fullJoyAction) - { - case JoyTickFullJoyAction.EndJob: - pawn.jobs.curDriver.EndJobWith(JobCondition.Succeeded); - return true; - case JoyTickFullJoyAction.GoToNextToil: - pawn.jobs.curDriver.ReadyForNextToil(); - return true; - } - } - return false; - } - private static bool NeedLevelFull(Need need) + if (curJob.def.joySkill != null) + { + pawn.skills.GetSkill(curJob.def.joySkill).Learn(curJob.def.joyXpPerTick); + } + if (!curJob.ignoreJoyTimeAssignment && !pawn.GetTimeAssignment().allowJoy && !curJob.doUntilGatheringEnded) + { + pawn.jobs.curDriver.EndJobWith(JobCondition.InterruptForced); + return true; + } + if ((NeedLevelFull(treatment) || NeedLevelFull(pawn.needs.joy)) && !curJob.doUntilGatheringEnded) + { + switch (fullJoyAction) { - return need != null && need.CurLevel > 0.9999f; + case JoyTickFullJoyAction.EndJob: + pawn.jobs.curDriver.EndJobWith(JobCondition.Succeeded); + return true; + case JoyTickFullJoyAction.GoToNextToil: + pawn.jobs.curDriver.ReadyForNextToil(); + return true; } + } + return false; + } + + private static bool NeedLevelFull(Need need) + { + return need != null && need.CurLevel > 0.9999f; } + } } diff --git a/Source/Core/Settings/SettingsMenu.cs b/Source/Core/Settings/SettingsMenu.cs index 4839ef7..18ac75b 100644 --- a/Source/Core/Settings/SettingsMenu.cs +++ b/Source/Core/Settings/SettingsMenu.cs @@ -8,219 +8,225 @@ namespace PrisonLabor.Core.Settings { - [StaticConstructorOnStartup] - internal class SettingsMenu : Mod + [StaticConstructorOnStartup] + internal class SettingsMenu : Mod + { + private static string difficulty = ""; + private static bool showNews; + private static bool allowAllWorktypes; + private static bool enableMotivationMechanics; + private static bool enableMotivationIcons; + private static bool enableRevolts; + private static bool showTreatmentHappiness; + private static bool enableSuicide; + private static bool enableFullHealRest; + private static bool advancedGrowing; + private static int defaultInteractionMode; + private static bool enableDebbuging; + private static bool mechsWorkInLaborZone; + + private static List interactionModeList; + + public SettingsMenu(ModContentPack content) : base(content) { - private static string difficulty = ""; - private static bool showNews; - private static bool allowAllWorktypes; - private static bool enableMotivationMechanics; - private static bool enableMotivationIcons; - private static bool enableRevolts; - private static bool showTreatmentHappiness; - private static bool enableSuicide; - private static bool enableFullHealRest; - private static bool advancedGrowing; - private static int defaultInteractionMode; - private static bool enableDebbuging; + } + + public static void Init() + { + showNews = PrisonLaborPrefs.ShowNews; + allowAllWorktypes = PrisonLaborPrefs.AllowAllWorkTypes; + advancedGrowing = PrisonLaborPrefs.AdvancedGrowing; + enableMotivationMechanics = PrisonLaborPrefs.EnableMotivationMechanics; + enableMotivationIcons = PrisonLaborPrefs.EnableMotivationIcons; + enableRevolts = PrisonLaborPrefs.EnableRevolts; + enableSuicide = PrisonLaborPrefs.EnableSuicide; + showTreatmentHappiness = PrisonLaborPrefs.ShowTreatmentHappiness; + enableFullHealRest = PrisonLaborPrefs.EnableFullHealRest; + enableDebbuging = PrisonLaborPrefs.DebugLogs; + mechsWorkInLaborZone = PrisonLaborPrefs.MechsWorkInLaborZone; + + interactionModeList = new List(DefDatabase.AllDefs); + defaultInteractionMode = interactionModeList.IndexOf(DefDatabase.GetNamed(PrisonLaborPrefs.DefaultInteractionMode)); + if (defaultInteractionMode < 0 || defaultInteractionMode > interactionModeList.Count - 1) + defaultInteractionMode = 0; + } + + public override void DoSettingsWindowContents(Rect inRect) + { + var leftRect = new Rect(inRect.x, inRect.y, inRect.width * 0.65f, inRect.height); + var rightRect = new Rect((int)(inRect.x + inRect.width * 0.65f + 30f), inRect.y, inRect.width * 0.35f - 30f, + inRect.height); + + var listing_options = new Listing_Standard(); + + listing_options.Begin(leftRect); + + listing_options.CheckboxLabeled("PrisonLabor_ShowNews".Translate(), ref showNews, + "PrisonLabor_ShowNewsDesc".Translate()); + + listing_options.GapLine(); + + if (listing_options.ButtonTextLabeled("PrisonLabor_DefaultInterMode".Translate(), interactionModeList[defaultInteractionMode].LabelCap)) + defaultInteractionMode = defaultInteractionMode < interactionModeList.Count - 1 ? defaultInteractionMode + 1 : 0; + + listing_options.GapLine(); + + listing_options.Label("PrisonLabor_AllowedWorkTypes".Translate(), -1f); + listing_options.CheckboxLabeled(" " + "PrisonLabor_AllowAll".Translate(), ref allowAllWorktypes, "PrisonLabor_AllowAllWorkTypes".Translate()); + if (!allowAllWorktypes) + { + if (listing_options.ButtonTextLabeled(" " + "PrisonLabor_AllowedWorkTypesL".Translate(), "PrisonLabor_Browse".Translate())) + Find.WindowStack.Add(new SelectWorkTypesDialog()); + } + else + { + listing_options.Gap(); + } + + listing_options.GapLine(); + + listing_options.CheckboxLabeled("PrisonLabor_MotivationMechanics".Translate(), ref enableMotivationMechanics, + "PrisonLabor_MotivationWarning".Translate()); + + listing_options.GapLine(); + + listing_options.CheckboxLabeled("PrisonLabor_MotivationIcons".Translate(), ref enableMotivationIcons, + "PrisonLabor_MotivationIconsDesc".Translate()); + + listing_options.GapLine(); + + listing_options.CheckboxLabeled("PrisonLabor_CanGrowAdvanced".Translate(), ref advancedGrowing, + "PrisonLabor_CanGrowAdvancedDesc".Translate()); - private static List interactionModeList; + listing_options.GapLine(); - public SettingsMenu(ModContentPack content) : base(content) - { - } + listing_options.CheckboxLabeled("PrisonLabor_EnableRevolts".Translate(), ref enableRevolts, + "PrisonLabor_EnableRevoltsDesc".Translate()); - public static void Init() - { - showNews = PrisonLaborPrefs.ShowNews; - allowAllWorktypes = PrisonLaborPrefs.AllowAllWorkTypes; - advancedGrowing = PrisonLaborPrefs.AdvancedGrowing; - enableMotivationMechanics = PrisonLaborPrefs.EnableMotivationMechanics; - enableMotivationIcons = PrisonLaborPrefs.EnableMotivationIcons; - enableRevolts = PrisonLaborPrefs.EnableRevolts; - enableSuicide = PrisonLaborPrefs.EnableSuicide; - showTreatmentHappiness = PrisonLaborPrefs.ShowTreatmentHappiness; - enableFullHealRest = PrisonLaborPrefs.EnableFullHealRest; - enableDebbuging = PrisonLaborPrefs.DebugLogs; + listing_options.GapLine(); - interactionModeList = new List(DefDatabase.AllDefs); - defaultInteractionMode = interactionModeList.IndexOf(DefDatabase.GetNamed(PrisonLaborPrefs.DefaultInteractionMode)); - if (defaultInteractionMode < 0 || defaultInteractionMode > interactionModeList.Count - 1) - defaultInteractionMode = 0; - } + listing_options.CheckboxLabeled("PrisonLabor_EnableSuicide".Translate(), ref enableSuicide, + "PrisonLabor_EnableSuicideDesc".Translate()); - public override void DoSettingsWindowContents(Rect inRect) - { - var leftRect = new Rect(inRect.x, inRect.y, inRect.width * 0.65f, inRect.height); - var rightRect = new Rect((int)(inRect.x + inRect.width * 0.65f + 30f), inRect.y, inRect.width * 0.35f - 30f, - inRect.height); + listing_options.CheckboxLabeled("PrisonLabor_EnableFullHealRest".Translate(), ref enableFullHealRest, + "PrisonLabor_EnableFullHealRestDesc".Translate()); - var listing_options = new Listing_Standard(); + listing_options.CheckboxLabeled("PrisonLabor_MechWorksInLaborArea".Translate(), ref mechsWorkInLaborZone, + "PrisonLabor_MechWorksInLaborAreaDesc".Translate()); - listing_options.Begin(leftRect); + listing_options.CheckboxLabeled("PrisonLabor_EnableDebugLogs".Translate(), ref enableDebbuging, + "PrisonLabor_EnableDebugLogsDesc".Translate()); - listing_options.CheckboxLabeled("PrisonLabor_ShowNews".Translate(), ref showNews, - "PrisonLabor_ShowNewsDesc".Translate()); - listing_options.GapLine(); + listing_options.GapLine(); - if (listing_options.ButtonTextLabeled("PrisonLabor_DefaultInterMode".Translate(), interactionModeList[defaultInteractionMode].LabelCap)) - defaultInteractionMode = defaultInteractionMode < interactionModeList.Count - 1 ? defaultInteractionMode + 1 : 0; + listing_options.CheckboxLabeled("PrisonLabor_ShowTreatmentHappiness".Translate(), ref showTreatmentHappiness, + "PrisonLabor_ShowTreatmentHappinessDesc".Translate()); - listing_options.GapLine(); + listing_options.Gap(); + listing_options.Gap(); + listing_options.Gap(); - listing_options.Label("PrisonLabor_AllowedWorkTypes".Translate(), -1f); - listing_options.CheckboxLabeled(" " + "PrisonLabor_AllowAll".Translate(), ref allowAllWorktypes, "PrisonLabor_AllowAllWorkTypes".Translate()); - if (!allowAllWorktypes) - { - if (listing_options.ButtonTextLabeled(" " + "PrisonLabor_AllowedWorkTypesL".Translate(), "PrisonLabor_Browse".Translate())) - Find.WindowStack.Add(new SelectWorkTypesDialog()); - } - else - { - listing_options.Gap(); - } + if (listing_options.ButtonTextLabeled("PrisonLabor_ButtonRemoveModFromSaveDesc".Translate(), "PrisonLabor_ButtonRemoveModFromSave".Translate())) + Find.WindowStack.Add(new SelectSaveForCleaningDialog()); - listing_options.GapLine(); + listing_options.End(); - listing_options.CheckboxLabeled("PrisonLabor_MotivationMechanics".Translate(), ref enableMotivationMechanics, - "PrisonLabor_MotivationWarning".Translate()); + var listing_panel = new Listing_Standard(); - listing_options.GapLine(); + listing_panel.Begin(rightRect); - listing_options.CheckboxLabeled("PrisonLabor_MotivationIcons".Translate(), ref enableMotivationIcons, - "PrisonLabor_MotivationIconsDesc".Translate()); - - listing_options.GapLine(); + var heigh_temp = rightRect.width * 0.56f; + GUI.DrawTexture(new Rect(0, 0, rightRect.width, heigh_temp), ContentFinder.Get("Preview", true)); + listing_panel.Gap(heigh_temp); + listing_panel.Label("Prison Labor", -1f); + listing_panel.Label("PrisonLabor_Version".Translate() + VersionUtility.versionString, -1f); - listing_options.CheckboxLabeled("PrisonLabor_CanGrowAdvanced".Translate(), ref advancedGrowing, - "PrisonLabor_CanGrowAdvancedDesc".Translate()); - - listing_options.GapLine(); - - listing_options.CheckboxLabeled("PrisonLabor_EnableRevolts".Translate(), ref enableRevolts, - "PrisonLabor_EnableRevoltsDesc".Translate()); - - listing_options.GapLine(); - - listing_options.CheckboxLabeled("PrisonLabor_EnableSuicide".Translate(), ref enableSuicide, - "PrisonLabor_EnableSuicideDesc".Translate()); - - 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(); - - listing_options.CheckboxLabeled("PrisonLabor_ShowTreatmentHappiness".Translate(), ref showTreatmentHappiness, - "PrisonLabor_ShowTreatmentHappinessDesc".Translate()); - - listing_options.Gap(); - listing_options.Gap(); - listing_options.Gap(); - - if (listing_options.ButtonTextLabeled("PrisonLabor_ButtonRemoveModFromSaveDesc".Translate(), "PrisonLabor_ButtonRemoveModFromSave".Translate())) - Find.WindowStack.Add(new SelectSaveForCleaningDialog()); - - listing_options.End(); - - var listing_panel = new Listing_Standard(); - - listing_panel.Begin(rightRect); - - var heigh_temp = rightRect.width * 0.56f; - GUI.DrawTexture(new Rect(0, 0, rightRect.width, heigh_temp), ContentFinder.Get("Preview", true)); - listing_panel.Gap(heigh_temp); - listing_panel.Label("Prison Labor", -1f); - listing_panel.Label("PrisonLabor_Version".Translate() + VersionUtility.versionString, -1f); - - listing_panel.GapLine(); - - listing_panel.Label("PrisonLabor_Difficulty".Translate() + difficulty, -1f); - - listing_panel.GapLine(); - - if (listing_panel.ButtonText("PrisonLabor_Defaults".Translate())) - { - PrisonLaborPrefs.RestoreToDefault(); - Init(); - } - - if (listing_panel.ButtonText("PrisonLabor_ShowNews".Translate())) - { - NewsWindow.ShowAll = true; - NewsWindow.ForceShow(); - } - - if (listing_panel.ButtonText("PrisonLabor_ReplayTurorialsButton".Translate())) - { - ReplayTutorialsWindow.Show(); - } - - listing_panel.End(); - - Apply(); - } - - public override string SettingsCategory() - { - return "Prison Labor"; - } - - public override void WriteSettings() - { - PrisonLaborPrefs.ShowNews = showNews; - PrisonLaborPrefs.AllowAllWorkTypes = allowAllWorktypes; - PrisonLaborPrefs.EnableMotivationMechanics = enableMotivationMechanics; - PrisonLaborPrefs.EnableMotivationIcons = enableMotivationIcons; - PrisonLaborPrefs.EnableRevolts = enableRevolts; - PrisonLaborPrefs.ShowTreatmentHappiness = showTreatmentHappiness; - PrisonLaborPrefs.AdvancedGrowing = advancedGrowing; - PrisonLaborPrefs.EnableSuicide = enableSuicide; - PrisonLaborPrefs.EnableFullHealRest = enableFullHealRest; - PrisonLaborPrefs.DefaultInteractionMode = interactionModeList[defaultInteractionMode].defName; - PrisonLaborPrefs.DebugLogs = enableDebbuging; - PrisonLaborPrefs.Save(); - Log.Message("Prison Labor settings saved"); - } - - private static void Apply() - { - PrisonLaborPrefs.Apply(); - CalculateDifficulty(); - } - - private static void CalculateDifficulty() - { - var value = 1000; - if (!enableMotivationMechanics) - value -= 300; - if (advancedGrowing) - value -= 50; - value -= 500; - if (!allowAllWorktypes) - { - var delta = 500 + 7 * 50 + (DefDatabase.DefCount - 20) * 25; - foreach (var wtd in WorkSettings.AvailableWorkTypes) - if (!WorkSettings.WorkDisabled(wtd)) - delta -= 50; - if (delta > 0) - value += delta; - } - - if (value >= 1000) - difficulty = value / 10 + " (" + "PrisonLabor_DifficultyNormal".Translate() + ")"; - else if (value >= 800) - difficulty = value / 10 + " (" + "PrisonLabor_DifficultyCasual".Translate() + ")"; - else if (value >= 500) - difficulty = value / 10 + " (" + "PrisonLabor_DifficultyEasy".Translate() + ")"; - else if (value >= 300) - difficulty = value / 10 + " (" + "PrisonLabor_DifficultyPeaceful".Translate() + ")"; - else - difficulty = value / 10 + " (" + "PrisonLabor_DifficultyJoke".Translate() + ")"; - } + listing_panel.GapLine(); + + listing_panel.Label("PrisonLabor_Difficulty".Translate() + difficulty, -1f); + + listing_panel.GapLine(); + + if (listing_panel.ButtonText("PrisonLabor_Defaults".Translate())) + { + PrisonLaborPrefs.RestoreToDefault(); + Init(); + } + + if (listing_panel.ButtonText("PrisonLabor_ShowNews".Translate())) + { + NewsWindow.ShowAll = true; + NewsWindow.ForceShow(); + } + + if (listing_panel.ButtonText("PrisonLabor_ReplayTurorialsButton".Translate())) + { + ReplayTutorialsWindow.Show(); + } + + listing_panel.End(); + + Apply(); + } + + public override string SettingsCategory() + { + return "Prison Labor"; + } + + public override void WriteSettings() + { + PrisonLaborPrefs.ShowNews = showNews; + PrisonLaborPrefs.AllowAllWorkTypes = allowAllWorktypes; + PrisonLaborPrefs.EnableMotivationMechanics = enableMotivationMechanics; + PrisonLaborPrefs.EnableMotivationIcons = enableMotivationIcons; + PrisonLaborPrefs.EnableRevolts = enableRevolts; + PrisonLaborPrefs.ShowTreatmentHappiness = showTreatmentHappiness; + PrisonLaborPrefs.AdvancedGrowing = advancedGrowing; + PrisonLaborPrefs.EnableSuicide = enableSuicide; + PrisonLaborPrefs.EnableFullHealRest = enableFullHealRest; + PrisonLaborPrefs.DefaultInteractionMode = interactionModeList[defaultInteractionMode].defName; + PrisonLaborPrefs.DebugLogs = enableDebbuging; + PrisonLaborPrefs.MechsWorkInLaborZone = mechsWorkInLaborZone; + PrisonLaborPrefs.Save(); + Log.Message("Prison Labor settings saved"); + } + + private static void Apply() + { + PrisonLaborPrefs.Apply(); + CalculateDifficulty(); + } + + private static void CalculateDifficulty() + { + var value = 1000; + if (!enableMotivationMechanics) + value -= 300; + if (advancedGrowing) + value -= 50; + value -= 500; + if (!allowAllWorktypes) + { + var delta = 500 + 7 * 50 + (DefDatabase.DefCount - 20) * 25; + foreach (var wtd in WorkSettings.AvailableWorkTypes) + if (!WorkSettings.WorkDisabled(wtd)) + delta -= 50; + if (delta > 0) + value += delta; + } + + if (value >= 1000) + difficulty = value / 10 + " (" + "PrisonLabor_DifficultyNormal".Translate() + ")"; + else if (value >= 800) + difficulty = value / 10 + " (" + "PrisonLabor_DifficultyCasual".Translate() + ")"; + else if (value >= 500) + difficulty = value / 10 + " (" + "PrisonLabor_DifficultyEasy".Translate() + ")"; + else if (value >= 300) + difficulty = value / 10 + " (" + "PrisonLabor_DifficultyPeaceful".Translate() + ")"; + else + difficulty = value / 10 + " (" + "PrisonLabor_DifficultyJoke".Translate() + ")"; } + } } \ No newline at end of file diff --git a/Source/Core/Trackers/EscapeTracker.cs b/Source/Core/Trackers/EscapeTracker.cs index 0d893f2..c77a8d3 100644 --- a/Source/Core/Trackers/EscapeTracker.cs +++ b/Source/Core/Trackers/EscapeTracker.cs @@ -11,39 +11,6 @@ namespace PrisonLabor.Core.Trackers { public class EscapeTracker : IExposable { - #region Object Access - /** - * Object Access region: - * This region is for ensuring that for every pawn there will be only one escape tracker. - * It is constructed in this way to prevent heavy modification of Pawn class (on external library). - */ - private static HashSet prisonersReadyToEscape = new HashSet(); - - public static HashSet PrisonersReadyToEscape - { - get - { - return prisonersReadyToEscape; - } - } - - private static void Register(Pawn pawn) - { - if (pawn.IsPrisoner) - { - prisonersReadyToEscape.Add(pawn); - } - } - - public static void DeRegister(Pawn pawn) - { - prisonersReadyToEscape.Remove(pawn); - } - - /// - /// Access EscapeTracker of Pawn - /// - #endregion private SimpleTimer timer = new SimpleTimer(); @@ -121,14 +88,12 @@ public void Tick() { timer.ResetAndStop(); ReadyToEscape = false; - DeRegister(Pawn); } } // Check if timer should trigger escape else if (timer.Ticks >= EscapeLevel) { ReadyToEscape = true; - Register(Pawn); } // Tick timer diff --git a/Source/HarmonyPatches/Patches_Apparel/PrisonerRespectOutfits.cs b/Source/HarmonyPatches/Patches_Apparel/PrisonerRespectOutfits.cs new file mode 100644 index 0000000..24c2edb --- /dev/null +++ b/Source/HarmonyPatches/Patches_Apparel/PrisonerRespectOutfits.cs @@ -0,0 +1,46 @@ +using HarmonyLib; +using PrisonLabor.Core.BillAssignation; +using PrisonLabor.Core.Needs; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.HarmonyPatches.Patches_Apparel +{ + [HarmonyPatch(typeof(JobGiver_PrisonerGetDressed))] + public class PrisonerRespectOutfits + { + [HarmonyPostfix] + [HarmonyPatch("FindGarmentCoveringPart")] + static Apparel Postfix_FindGarmentCoveringPart(Apparel __result, Pawn pawn, BodyPartGroupDef bodyPartGroupDef) + { + return PrisonerWillRespectOutfit(__result, pawn); + } + + [HarmonyPostfix] + [HarmonyPatch("FindGarmentSatisfyingTitleRequirement")] + static Apparel Postfix_FindGarmentSatisfyingTitleRequirement(Apparel __result, Pawn pawn, ApparelRequirement req) + { + return PrisonerWillRespectOutfit(__result, pawn); + } + + private static Apparel PrisonerWillRespectOutfit(Apparel apparel, Pawn prisoner) + { + if (apparel != null && IsMotivatedPrisoner(prisoner) && prisoner.outfits != null && !prisoner.outfits.CurrentOutfit.filter.Allows(apparel.def)) + { + return null; + } + return apparel; + + } + + private static bool IsMotivatedPrisoner(Pawn pawn) + { + return pawn.IsPrisonerOfColony && pawn.IsMotivated(); + } + } +} diff --git a/Source/HarmonyPatches/Patches_GUI/GUI_Feeding/Patch_ITAB_Pawn_Feeding.cs b/Source/HarmonyPatches/Patches_GUI/GUI_Feeding/Patch_ITAB_Pawn_Feeding.cs new file mode 100644 index 0000000..d14c2f8 --- /dev/null +++ b/Source/HarmonyPatches/Patches_GUI/GUI_Feeding/Patch_ITAB_Pawn_Feeding.cs @@ -0,0 +1,76 @@ +using HarmonyLib; +using PrisonLabor.Core; +using PrisonLabor.Core.Other; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace PrisonLabor.HarmonyPatches.Patches_GUI.GUI_Feeding +{ + [HarmonyPatch(typeof(ITab_Pawn_Feeding))] + class Patch_ITAB_Pawn_Feeding + { + [HarmonyPatch("FillTab")] + [HarmonyPatch(new[] { typeof(Pawn), typeof(Rect), typeof(Vector2), typeof(Vector2), typeof(List) }, + new ArgumentType[] { ArgumentType.Normal, ArgumentType.Normal, ArgumentType.Out, ArgumentType.Out, ArgumentType.Normal })] + [HarmonyTranspiler] + static IEnumerable FillTabTranspiler(ILGenerator gen, IEnumerable instr) + { + var expected = AccessTools.PropertyGetter(typeof(PawnsFinder), nameof(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_OfPlayerFaction)); + foreach (CodeInstruction inst in instr) + { + if (inst.OperandIs(expected)) + { + yield return new CodeInstruction(OpCodes.Call, typeof(Patch_ITAB_Pawn_Feeding).GetMethod(nameof(Patch_ITAB_Pawn_Feeding.GetNewRange))); + } + else + { + yield return inst; + + } + } + } + + [HarmonyPatch] + [HarmonyPatch("DrawRow")] + [HarmonyTranspiler] + static IEnumerable DrawRowTranspiler(ILGenerator gen, IEnumerable instr) + { + var expected = AccessTools.PropertyGetter(typeof(Entity), nameof(Entity.LabelShortCap)); + + foreach (CodeInstruction inst in instr) + { + if (inst.OperandIs(expected)) + { + yield return new CodeInstruction(OpCodes.Call, typeof(Patch_ITAB_Pawn_Feeding).GetMethod(nameof(Patch_ITAB_Pawn_Feeding.HandlePrisonerLabel))); + } + else + { + yield return inst; + } + } + } + + public static string HandlePrisonerLabel(Pawn feeder) + { + if (feeder.IsPrisonerOfColony) + { + return "PrisonLabor_Prisoner".Translate(feeder.LabelShortCap); + } + return feeder.LabelShortCap; + } + + public static List GetNewRange() + { + List list = new List(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_OfPlayerFaction); + list.AddRange(PawnsFinder.AllMapsCaravansAndTravelingTransportPods_Alive_PrisonersOfColony); + return list; + } + } +} diff --git a/Source/HarmonyPatches/Patches_InteractionMode/Patch_RemoveHediffsAfterStatusChange.cs b/Source/HarmonyPatches/Patches_InteractionMode/Patch_RemoveHediffsAfterStatusChange.cs index 1562cfa..0446bdb 100644 --- a/Source/HarmonyPatches/Patches_InteractionMode/Patch_RemoveHediffsAfterStatusChange.cs +++ b/Source/HarmonyPatches/Patches_InteractionMode/Patch_RemoveHediffsAfterStatusChange.cs @@ -10,26 +10,30 @@ namespace PrisonLabor.HarmonyPatches.Patches_InteractionMode { - [HarmonyPatch(typeof(Pawn_GuestTracker))] - [HarmonyPatch("SetGuestStatus")] - public class Patch_RemoveHediffsAfterStatusChange + [HarmonyPatch(typeof(Pawn_GuestTracker))] + [HarmonyPatch("SetGuestStatus")] + public class Patch_RemoveHediffsAfterStatusChange + { + private static void Postfix(Pawn_GuestTracker __instance, Faction newHost, GuestStatus guestStatus) { - private static void Postfix(Pawn_GuestTracker __instance, Faction newHost, GuestStatus guestStatus) - { - if (guestStatus != GuestStatus.Prisoner) - { - Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue(); - CleanPrisonersStatus.CleanHediffs(pawn); - } + if (guestStatus != GuestStatus.Prisoner) + { + Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue(); + CleanPrisonersStatus.CleanHediffs(pawn); + } - if (guestStatus == GuestStatus.Prisoner) - { - Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue(); - if (pawn.drugs == null) - { - pawn.drugs = new Pawn_DrugPolicyTracker(pawn); - } - } + if (guestStatus == GuestStatus.Prisoner) + { + Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue(); + if (pawn.drugs == null) + { + pawn.drugs = new Pawn_DrugPolicyTracker(pawn); + } + if (pawn.outfits == null) + { + pawn.outfits = new Pawn_OutfitTracker(pawn); } + } } + } } diff --git a/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Position.cs b/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Position.cs index ba08b05..176ca43 100644 --- a/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Position.cs +++ b/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Position.cs @@ -11,40 +11,28 @@ namespace PrisonLabor.HarmonyPatches.Patches_LaborArea { - [HarmonyPatch] - class Patch_Labor_Position - { - - static IEnumerable TargetMethods() - { - return Assembly.GetAssembly(typeof(WorkGiver_Scanner)).GetTypes() - .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(WorkGiver_Scanner))) - .SelectMany(type => type.GetMethods()) - .Where(method => method.Name.Equals("PotentialWorkCellsGlobal")) - .Cast(); - } - static IEnumerable Postfix(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) - { - if (__result != null && __instance != null) - { - return checkFields(__result, __instance, pawn); - } - else - { - return __result; - } - } - - private static IEnumerable checkFields(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) - { - foreach (IntVec3 pos in __result) - { - if (PrisonLaborUtility.CanWorkHere(pos, pawn, __instance.def.workType)) - { - yield return pos; - } - } - } + [HarmonyPatch] + class Patch_Labor_Position + { + static IEnumerable TargetMethods() + { + return Assembly.GetAssembly(typeof(WorkGiver_Scanner)).GetTypes() + .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(WorkGiver_Scanner))) + .SelectMany(type => type.GetMethods()) + .Where(method => method.Name.Equals("PotentialWorkCellsGlobal")) + .Cast(); + } + static IEnumerable Postfix(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) + { + if (__result != null && __instance != null) + { + return __result.Where(item => PrisonLaborUtility.CanWorkHere(item, pawn, __instance.def.workType)); + } + else + { + return __result; + } } + } } diff --git a/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Thing.cs b/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Thing.cs index a4fa1d0..9923b2c 100644 --- a/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Thing.cs +++ b/Source/HarmonyPatches/Patches_LaborArea/Patch_Labor_Thing.cs @@ -12,56 +12,43 @@ namespace PrisonLabor.HarmonyPatches.Patches_LaborArea { - [HarmonyPatch] - class Patch_Labor_Thing + [HarmonyPatch] + class Patch_Labor_Thing + { + static IEnumerable TargetMethods() { - static IEnumerable TargetMethods() - { - foreach(var method in GetBaseMethods()) - { - yield return method; - } - // yield return getCleanMethod(); - } - static IEnumerable GetBaseMethods() { - return Assembly.GetAssembly(typeof(WorkGiver_Scanner)).GetTypes() - .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(WorkGiver_Scanner)) && myType != typeof(WorkGiver_Teach)) - .SelectMany(type => type.GetMethods()) - .Where(method => method.Name.Equals("PotentialWorkThingsGlobal")) - .Cast(); - } - - static MethodBase getCleanMethod() - { - Assembly asm = typeof(WorkGiver_Scanner).Assembly; - Type type = asm.GetType("RimWorld.WorkGiver_CleanFilth"); - return type.GetMethod("PotentialWorkThingsGlobal"); - } - - static IEnumerable Postfix(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) - { - if (__result != null && __instance != null) - { - return CheckFields(__result, __instance, pawn); - } - else - { - return __result; - } - } + foreach (var method in GetBaseMethods()) + { + yield return method; + } + // yield return getCleanMethod(); + } + static IEnumerable GetBaseMethods() + { + return Assembly.GetAssembly(typeof(WorkGiver_Scanner)).GetTypes() + .Where(myType => myType.IsClass && !myType.IsAbstract && myType.IsSubclassOf(typeof(WorkGiver_Scanner)) && myType != typeof(WorkGiver_Teach)) + .SelectMany(type => type.GetMethods()) + .Where(method => method.Name.Equals("PotentialWorkThingsGlobal")) + .Cast(); + } - private static IEnumerable CheckFields(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) - { - foreach (Thing thing in __result) - { - //Log.Message($"Work type: { __instance.def.workType}, thing is {thing}, value: {PrisonLaborUtility.canWorkHere(thing.Position, pawn, __instance.def.workType)}"); - if (thing != null && PrisonLaborUtility.CanWorkHere(thing.Position, pawn, __instance.def.workType)) - { - // Log.Message($"Work type { __instance.def.workType}, value: {PrisonLaborUtility.canWorkHere(thing.Position, pawn, __instance.def.workType)}"); - yield return thing; - } - } - } + static MethodBase getCleanMethod() + { + Assembly asm = typeof(WorkGiver_Scanner).Assembly; + Type type = asm.GetType("RimWorld.WorkGiver_CleanFilth"); + return type.GetMethod("PotentialWorkThingsGlobal"); + } + static IEnumerable Postfix(IEnumerable __result, WorkGiver_Scanner __instance, Pawn pawn) + { + if (__result != null && __instance != null) + { + return __result.Where(item => item is Thing thing && PrisonLaborUtility.CanWorkHere(thing.Position, pawn, __instance.def.workType)); + } + else + { + return __result; + } } + } } diff --git a/Source/HarmonyPatches/Patches_Work/Patch_Breastfeed.cs b/Source/HarmonyPatches/Patches_Work/Patch_Breastfeed.cs new file mode 100644 index 0000000..a22b16c --- /dev/null +++ b/Source/HarmonyPatches/Patches_Work/Patch_Breastfeed.cs @@ -0,0 +1,32 @@ +using HarmonyLib; +using PrisonLabor.Core; +using PrisonLabor.Core.Other; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection.Emit; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace PrisonLabor.HarmonyPatches.Patches_Work +{ + [HarmonyPatch(typeof(ChildcareUtility))] + [HarmonyPatch(new[] { typeof(Pawn), typeof(Pawn) })] + class Patch_BreastfeedCompatibleFactions + { + static readonly MethodInfo expectedMethod = AccessTools.PropertyGetter(typeof(Pawn), nameof(Pawn.Faction)); + + [HarmonyPatch("HasBreastfeedCompatibleFactions")] + static bool Postfix(bool __result, Pawn mom, Pawn baby) + { + if (mom.IsPrisonerOfColony || baby.IsPrisonerOfColony) + { + return ChildcareUtility.HasBreastfeedCompatibleFactions(PrisonLaborUtility.GetPawnFaction(mom), baby); + } + return __result; + } + } +} diff --git a/Source/HarmonyPatches/Patches_Work/Patch_Smoothing.cs b/Source/HarmonyPatches/Patches_Work/Patch_Smoothing.cs index a9a60a2..3480ec2 100644 --- a/Source/HarmonyPatches/Patches_Work/Patch_Smoothing.cs +++ b/Source/HarmonyPatches/Patches_Work/Patch_Smoothing.cs @@ -16,8 +16,8 @@ class Patch_Smoothing { static IEnumerable TargetMethods() { - yield return (MethodBase)typeof(WorkGiver_ConstructSmoothWall).GetMethod("HasJobOnCell"); - yield return (MethodBase)typeof(WorkGiver_ConstructAffectFloor).GetMethod("HasJobOnCell"); + yield return typeof(WorkGiver_ConstructSmoothWall).GetMethod("HasJobOnCell"); + yield return typeof(WorkGiver_ConstructAffectFloor).GetMethod("HasJobOnCell"); } public static bool Postfix(bool __result, Pawn pawn, IntVec3 c) diff --git a/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_PrisonerFaction.cs b/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_PrisonerFaction.cs index fd1a29c..e64273f 100644 --- a/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_PrisonerFaction.cs +++ b/Source/HarmonyPatches/Patches_Work/Patch_WorkGiver_PrisonerFaction.cs @@ -16,6 +16,7 @@ namespace PrisonLabor.HarmonyPatches.Patches_Work [HarmonyPatch] public class Patch_WorkGiver_PrisonerFaction { + static readonly MethodInfo expectedMethod = AccessTools.PropertyGetter(typeof(Pawn), nameof(Pawn.Faction)); static IEnumerable TargetMethods() { foreach (MethodBase mb in Assembly.GetAssembly(typeof(WorkGiver_Scanner)).GetTypes() @@ -30,6 +31,7 @@ static IEnumerable TargetMethods() yield return typeof(WorkGiver_ConstructFinishFrames).GetMethod(nameof(WorkGiver_ConstructFinishFrames.JobOnThing)); yield return typeof(WorkGiver_ConstructDeliverResourcesToFrames).GetMethod(nameof(WorkGiver_ConstructDeliverResourcesToFrames.JobOnThing)); yield return typeof(WorkGiver_ConstructDeliverResourcesToBlueprints).GetMethod(nameof(WorkGiver_ConstructDeliverResourcesToBlueprints.JobOnThing)); + yield return typeof(ChildcareUtility).GetMethod(nameof(ChildcareUtility.HasBreastfeedCompatibleFactions), new[] { typeof(Faction), typeof(Pawn) }); } public static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase, IEnumerable inst) @@ -51,7 +53,7 @@ public static IEnumerable Transpiler(ILGenerator gen, MethodBas private static bool ShouldPatch(CodeInstruction actual, CodeInstruction prev) { - return prev.opcode == OpCodes.Ldarg_1 && actual.opcode == OpCodes.Callvirt && actual.operand != null && actual.operand.ToString().Contains("RimWorld.Faction get_Faction()"); + return prev.opcode == OpCodes.Ldarg_1 && actual.opcode == OpCodes.Callvirt && actual.OperandIs(expectedMethod); } } } diff --git a/Source/Organizer/NewsFeed.xml b/Source/Organizer/NewsFeed.xml index 0a6905c..a45f194 100644 --- a/Source/Organizer/NewsFeed.xml +++ b/Source/Organizer/NewsFeed.xml @@ -3,331 +3,347 @@ - - - - - - - - - Prison Labor v 1.4.1 - - [-] Added Work and bloodfeed interaction for biotech dlc - [-] Added Work and hemogen farm interaction for biotech dlc - [-] Resocialization offer should not appear on pawn with Unwavering Loyalty - [-] Work and x interaction updated to have similar options to vanilla one - [-] Some interaction should be blocked due to Unwavering Loyalty - [-] Fix for mech gestator usage - [-] Recruited prisoners should have removed drain hemogen bill - [-] Prisoners should not be revolting if genes don't allow that - - - - Prison Labor v 1.4.0 - - [-] Update for Rimworld 1.4. All listed features below will only work with game version 1.4. - [-] Compatibility patch for CleaningArea - [-] Compatibility patch for Hospitality. Prisoners will entertain guest. - [-] Compatibility patch for Therapy. Prisoners can get therapy now. - [-] Split all compatibility patches into DLLs. Mod order is required for prison labor. - [-] Prisoners can use variant of joy giver building like poker table. Joy need is disabled, but during recreation time their mood will be improved. It will happen only during recreation time assignment. - [-] Refactor of prisoners job giver. No new future here, but with enabled prison labor debug logging more info what going on in prisoner mind going on. - - - - - - - - - - - - - - Prison Labor v 1.3.0 - - [-] Update to Rimworld 1.3 - [-] Created menu for prisoners. - [-] Created tab in prisoners menu "Overview". In this tab interaction mode can be chosen, resocialization offer is moved here from pawn prisoner tab. Also, possibility to order removing/putting cuffs on prisoners are here. Motivation level is also displayed here. - [-] Created tab in prisoner menu "Work". It was moved from the tab "Work" in main tab. - [-] Created tab in prisoner menu "Schedule". It was moved from the tab "Schedule" in main tab. - [-] Created tab in prisoner menu "Assign". Allows to assign diet and what kind of medicine should be used for prisoner. - [-] Created tab in prisoner menu "Dev". For dev tools. - [-] Moved restrict bill to group from drop down button to vanilla drop down pawn restriction in bill menu. Added new options to handle vanilla slaves. - [gap] - Some tutorials are now out of date. Hope to fix them soon. - [gap] - Honestly don't know if it will work correctly, didn't have enough time to test it right. Please report any bugs and not working slaves. - - - - Prison Labor v 1.2.5 - - [-]Refactored rendering icons on prisoners. Instead of drawing textures, mesh is used. It may help with gray screen issue. Icons will be smaller now. - [-]Various fixes to work patches which should reduce situations when prisoners stuck. - [gap] - Probably it is the last release for Rimworld version 1.2. Future updates will be pushed with version 1.3 - - - - Prison Labor v 1.2.4 - - [-]Changed adding designer for prisoner labor zone to more "common" way. It may fix missing designators as mod incompatibility - [-]Prisoners should respect their food restriction when motivation is more than 75%, or they are watched - [-]Prisoners should use ground penetration and long scanners - - - - - - - - Prison Labor v0.10.1 - - This patch contains a lot of changes, so there can be bugs. Please [b]report bugs[/b] so I can repair them ASAP - [gap] + + + Prison Labor v1.4.8 + + [-] Apparel policy can be assigned to prisoners + [-] Motivated prisoner will respect assigned apparel policy + [-] Interrogation added as new "ritual" that should not be count to ritual limits + [-] Warden can interrogate prisoners from non-player faction + [-] Interrogation can be performed in interrogation room + [-] Interrogation room needs new furniture "Interrogation chair" (comp from this item can be used in any other mod) + [-] Depends on wardens traits, skills and relation with prisoner interrogation can have different outcome + [-] Patches to allow prisoners to feed colony newborns + [-] Adjusted prisoner related alerts triggers + [gap] + There are a lot of new futures, so creating a backup save is recommended. Also, please do not exploit it too much ;) + + + + + + + + + + Prison Labor v 1.4.1 + + [-] Added Work and bloodfeed interaction for biotech dlc + [-] Added Work and hemogen farm interaction for biotech dlc + [-] Resocialization offer should not appear on pawn with Unwavering Loyalty + [-] Work and x interaction updated to have similar options to vanilla one + [-] Some interaction should be blocked due to Unwavering Loyalty + [-] Fix for mech gestator usage + [-] Recruited prisoners should have removed drain hemogen bill + [-] Prisoners should not be revolting if genes don't allow that + + + + Prison Labor v 1.4.0 + + [-] Update for Rimworld 1.4. All listed features below will only work with game version 1.4. + [-] Compatibility patch for CleaningArea + [-] Compatibility patch for Hospitality. Prisoners will entertain guest. + [-] Compatibility patch for Therapy. Prisoners can get therapy now. + [-] Split all compatibility patches into DLLs. Mod order is required for prison labor. + [-] Prisoners can use variant of joy giver building like poker table. Joy need is disabled, but during recreation time their mood will be improved. It will happen only during recreation time assignment. + [-] Refactor of prisoners job giver. No new future here, but with enabled prison labor debug logging more info what going on in prisoner mind going on. + + + + + + + + + + + + + + Prison Labor v 1.3.0 + + [-] Update to Rimworld 1.3 + [-] Created menu for prisoners. + [-] Created tab in prisoners menu "Overview". In this tab interaction mode can be chosen, resocialization offer is moved here from pawn prisoner tab. Also, possibility to order removing/putting cuffs on prisoners are here. Motivation level is also displayed here. + [-] Created tab in prisoner menu "Work". It was moved from the tab "Work" in main tab. + [-] Created tab in prisoner menu "Schedule". It was moved from the tab "Schedule" in main tab. + [-] Created tab in prisoner menu "Assign". Allows to assign diet and what kind of medicine should be used for prisoner. + [-] Created tab in prisoner menu "Dev". For dev tools. + [-] Moved restrict bill to group from drop down button to vanilla drop down pawn restriction in bill menu. Added new options to handle vanilla slaves. + [gap] + Some tutorials are now out of date. Hope to fix them soon. + [gap] + Honestly don't know if it will work correctly, didn't have enough time to test it right. Please report any bugs and not working slaves. + + + + Prison Labor v 1.2.5 + + [-]Refactored rendering icons on prisoners. Instead of drawing textures, mesh is used. It may help with gray screen issue. Icons will be smaller now. + [-]Various fixes to work patches which should reduce situations when prisoners stuck. + [gap] + Probably it is the last release for Rimworld version 1.2. Future updates will be pushed with version 1.3 + + + + Prison Labor v 1.2.4 + + [-]Changed adding designer for prisoner labor zone to more "common" way. It may fix missing designators as mod incompatibility + [-]Prisoners should respect their food restriction when motivation is more than 75%, or they are watched + [-]Prisoners should use ground penetration and long scanners + + + + + + + + Prison Labor v0.10.1 + + This patch contains a lot of changes, so there can be bugs. Please [b]report bugs[/b] so I can repair them ASAP + [gap] - [b]Treatment system[/b] - [-]added new hidden need "Treatment" that indicates level of prison treatment towards prisoner - [-]prisoners will now give offer to join colony if treatment is good enough (random) - [-]prisoners now will pick up weapons if treated bad - [-]added +5 bonus to mood while prisoner have free time - [-]added +5 bonus to mood if prisoner is not supervised and got lazy - [-]added +15 bonus to mood if treatment is above 75% - [-]added prisoner suicides - [-]added blocking revolts (100%, 95%, 50%, 10%) if overall prisoner treatment is good enough - [-]added treatment drop when prisoner is being beaten - [-]increased base chance for Revolts - [-]added blocking mental breaks for prisoners with low treatment levels - [-]"Treatment happiness" will decrease if health conditions are bad, when prisoners are hungry, or they're working. + [b]Treatment system[/b] + [-]added new hidden need "Treatment" that indicates level of prison treatment towards prisoner + [-]prisoners will now give offer to join colony if treatment is good enough (random) + [-]prisoners now will pick up weapons if treated bad + [-]added +5 bonus to mood while prisoner have free time + [-]added +5 bonus to mood if prisoner is not supervised and got lazy + [-]added +15 bonus to mood if treatment is above 75% + [-]added prisoner suicides + [-]added blocking revolts (100%, 95%, 50%, 10%) if overall prisoner treatment is good enough + [-]added treatment drop when prisoner is being beaten + [-]increased base chance for Revolts + [-]added blocking mental breaks for prisoners with low treatment levels + [-]"Treatment happiness" will decrease if health conditions are bad, when prisoners are hungry, or they're working. - [b]Prisoners can do construction jobs now[/b] + [b]Prisoners can do construction jobs now[/b] - [b]Enchantments[/b] - [-]new system for removing mod from save (new button in mod menu) - [-]prisoners will now seek safe temperature when not supervised - [-]prisoners will respect forbidden items, if "inspired" - [-]prisoners will now work in cold only if "work" time is set - [-]added alert when prisoners can escape - [-]reworked news popup window - [-]wardens no longer deliver food if prisoners can get it from another room - [-]cosmetic changes to bill checkbox - [-]prisoners will now stay at bed if waiting for surgery + [b]Enchantments[/b] + [-]new system for removing mod from save (new button in mod menu) + [-]prisoners will now seek safe temperature when not supervised + [-]prisoners will respect forbidden items, if "inspired" + [-]prisoners will now work in cold only if "work" time is set + [-]added alert when prisoners can escape + [-]reworked news popup window + [-]wardens no longer deliver food if prisoners can get it from another room + [-]cosmetic changes to bill checkbox + [-]prisoners will now stay at bed if waiting for surgery - [b]Bugs[/b] - [-]fixed food reservation throwing errors - [-]fixed cutting some content of bill config in some languages - [-]now work settings reset after prisoner is recruited, so it should fix some issues - [-]finally fixed "OnGui()" error, big thanks to @notfood (https://github.com/notfood) - [-]fixed blurred effect on settings window - [-]fixed Revolts + [b]Bugs[/b] + [-]fixed food reservation throwing errors + [-]fixed cutting some content of bill config in some languages + [-]now work settings reset after prisoner is recruited, so it should fix some issues + [-]finally fixed "OnGui()" error, big thanks to @notfood (https://github.com/notfood) + [-]fixed blurred effect on settings window + [-]fixed Revolts - [gap] + [gap] - If you want to support the work I do, please consider small donation. Link to Ko-fi will be placed at steam page. - - - - Prison Labor Beta v0.9.11 - - [-]fixed compatibility with Fluffy's WorkTab (final) - - - - Prison Labor Beta v0.9.10 - - [-]hotfixed compatibility with Fluffy's WorkTab (still have some visual flaws) - - - - Prison Labor Beta v0.9.9 - - [-]added sub-tabs in \"Work\" Tab and \"Assign\" Tab for \"Colonists\" and \"Prisoners\" - [-]added renaming Prisoners for imprisonment time (pawns will restore old names after releasing) - - - - Prison Labor Beta v0.9.8 - - [-]fixed SeedsPlease compatibility - - - - Prison Labor Beta v0.9.7 - - [-]added warning message before placing labor area for the first time - - - - Prison Labor Beta v0.9.6 - - [-]updated to RimWorld 1.0 - - - - Prison Labor Beta v0.9.5 - - [-]updated to RimWorld Beta 19 - - - - Prison Labor Beta v0.9.4 - - [-]disabled Warden and Jailor types of work for prisoner labor, it should fix bug, where jailors do not warden inside labor area - - - - Prison Labor Beta v0.9.3 - - [-]fixed compatibility with No Water no Life - [-]fixed compatibility with Dubs Bad Hygiene Mod - [-]fixed error with loading old saves - - - - Prison Labor Beta v0.9.2 - - [-]fixed seeds please compatibility issue - [-]added option to disable revolts - - - - Prison Labor Beta v0.9.1 - - [-]changed max. skill required for non-advanced growing by prisoners to 6 instead of 0 - [-]added new work type Jailor - [-]fixed drawing icons on world map - [-]fixed disabling mod from existing saves - [-]fixed incorrectly showing \"advanced growing by prisoners\" option - - - - Prison Labor Beta v0.9.0 - - [-]updated to RimWorld beta v18 - [-]added option to disable icons above prisoners heads in mod menu - [-]fixed error \"null reference in onGui()\" when loading save - - - - Prison Labor Beta v0.8.8 - - [-]changed slow from prisoners chains to act as factor instead offset - [-]fixed compatibility issues with Seeds Please(again) - - - - Prison Labor Beta v0.8.7 - - [-]fixed bug with dropping motivation while in bed - [-]prisoners will now get different weapons when revolt triggers (molotovs, bows, or clubs) - [-]replaced orginal jobs with \"tweak\" jobs (instead of overriding them, this fix is for users who use \"WorkTab\" by Fluffy) - [-]removed warning message from logs - [-]prisoners will now have 50% of normal speed in chains (instead of 35%) - [-]prisoners will now break chains after some period of time instead of immadiately(matter in incidents, breakouts etc.) - [-]wardens will now try to motivate most prisoners at once, but with priority to motivate lowest motivation first - [-]fixed bug with animals do not respect reservations (and vice versa) - - - - Prison Labor Beta v0.8.6 - - [img]NewsElement_Locks[/img][b]Locks mod:[/b]\nIf you want to allow prisoners to pass by closed doors, please check out my other mod called [b]Locks[/b] - [gap] - [-]fixed bug that Sowing job do not comply to Labor Area - [-]fixed bug with JoyGiver debris (sorry about that) - [-]reduced number of null reference errors with OnGui() method (fixed in v 0.8.5) - [-]single warden will be able to maintain 7 prisoners, instead of 5 (because of laziness rate reduction) (changed in v 0.8.5) - [-]decreased laziness rate to 0.002, instead of 0.003 (prisoners will get lazy 1.5x slower) (changed in v 0.8.5) - [-]decreased manipulation to 70% (instead of 80%) (changed in v 0.8.5) - [-]fixed null reference exception at loading game (fixed in v 0.8.4) - - - - Prison Labor Beta v0.8.3 - - [-]fixed bugs with disabling mod(now you can safely disable mod again) - [-]fixed bug with prioritizing work - [-]fixed bug with rendering icons on world map - - - - Prison Labor Beta v0.8.1 - - [-]fixed bug with rendering icons on world map - [subtitle] If you encouter any bugs [b]please report it on github[/b]. I'm fixing most important ones every day. This is (recently) beta version and it has to consist some bugs. Thank you for understaning. - [subtitle] Also you can always [b]download old version[/b] via github, but I think this was last big update - [-]re-enabled button in Bills detail panel - [-]added slider to Bills (temporary fix) - [-]fixed Bill \"Prisoner only\" button (I think, let me know if you still experience errors) - [-]fixed prisoners aren't working when Motivation is disabled (via Settings) - [-]fixed null-reference error on some revolts incidents - - - - Prison Labor Beta v0.8.0 - - [subtitle][b]Now in Beta![/b] I would no longer add any more features. Instead I will focus on improving existing ones. - [gap] - [subtitle][b]Main changes:[/b] - [img]NewsElement_Revolt[/img][b]Revolts:[/b]\nPrisoners will now form organized group under self-elected leader if motivation of prisoners is low. They will try to inflict damage to your colony or they will attemp running to elected enemy faction - [img]NewsElement_InspirationReworked[/img][b]Insiration reworked:[/b]\nQuicker, better and more intuitive.\nYou can now send your prisoners to work outside your walls, but be carefull: they will try to escape if left alone. Prisoners will start thinking about escape after being left for some time. - [img]LaborAreaExpand[/img][b]Labor area:[/b]\nYou can now select area for labor only. Your colonists will no longer go mine with peasants.\nTo access this tool look into \"Architect->Zones\" panel. - [img]NewsElement_PrisonersOnly[/img][b]Prisoners Only button[/b]\nGo to Bill details to mark bills for prisoners only! - [img]NewsElement_WorkAndRecruit[/img][b]Work and recruit:[/b]\nThis feature has been mostly requested by community. I hope it will be well received. - [gap] - [subtitle][b]Other changes:[/b] - [-]added default prisoner interaction mode option to settings menu - [-]added icons above prisoners indicating whenever he's being motivated/inspired - [-]reduced manipulation capability of prisoners (now they have 80% of normal manipulation, down from 100%) - [-]added tutorials triggers (now all tutorials will be shown) - [-]added watched tutorials to properties (tutorials will no longer be shown after reenabling mod) - [-]fixed forbidden bug with harvesting plants (again) - [-]fixed Toil reservation bug (not respecting prisoners' job) - [-]fixed compatibility with Dubs Hygiene Mod - [-]fixed SeedsPlease compatibility - [-]excluded supervising from labor - [-]rewritten news dialog - now with images and stuff - [-]perfomance and code improvements - [-]translation improvements - [gap] - [subtitle]Also I want to annouce that I will start new mod called [b]Prison Expansion[/b] that would be PrisonExtensions remake.The aim of this mod would be improving Prison Labor experience, especially cell doors and fences. - - - - Prison Labor Alpha v0.7 - - [-]Added settings! You can now change almost any aspect of this mod, including:\n * work types\n * motivation mechanics\n * prevention of planting advanced plants. - [-]Added \"uninstaller\" (\"disable\" option in settings), which will allow to disable this mod from existing saves. - [-]\"No more beeping!\". Changed way of informing player what's going on with prisoners. It should be less annoying and more insightful. - [-]Fixed bugs, including bug that prevents prisoners from cleaning and bug that causes warden to stuck in loop of delivering food to prisoner. - [-]\"No more watching while prisoner is sleeping.\"Wardens will no longer watch over not working prisoners. - [-]Prisoners will now stay in bed while waiting for operation - [-]Prisoners will now stop work when starving for default (\"Anything\" time), instead of hungry. They will still get minor debuff. - - - - Prison Labor Alpha v0.6 - - [-]Time restrictions - now you can manage your prisoners time for sleep, work and joy. You can now even force them to work when they're hungry! - [-]Getting food by prisoners - Now prisoners will look for food in much better way, and now (when they desperate enough) they will eat corpses! - [-]\"Laziness\" changed to \"Motivation\" and inverted.\n\n ATTENTION: After PrisonLabor reaches beta all saves with PrisonLabor v0.5a or lower will be corrupted and unplayable. This version (0.6) is safe and converts all older saves. - - - - Prison Labor Alpha v0.5 - - [-]Prisoners can now grow, but only plants that not require any skills. - [-]You can now manage prisoners work types. Just check \"Work\" tab! - [-]Laziness now appear on \"Needs\" tab. Above 50% wardens will watch prisoners. Above 80% prisoners won't work unless supervised. - [-]Wardens will now bring food to prisoners that went too far from his bed. - [-]Prisoners won't gain laziness when not working anymore. - [-]Fixed many bugs - - - + If you want to support the work I do, please consider small donation. Link to Ko-fi will be placed at steam page. + + + + Prison Labor Beta v0.9.11 + + [-]fixed compatibility with Fluffy's WorkTab (final) + + + + Prison Labor Beta v0.9.10 + + [-]hotfixed compatibility with Fluffy's WorkTab (still have some visual flaws) + + + + Prison Labor Beta v0.9.9 + + [-]added sub-tabs in \"Work\" Tab and \"Assign\" Tab for \"Colonists\" and \"Prisoners\" + [-]added renaming Prisoners for imprisonment time (pawns will restore old names after releasing) + + + + Prison Labor Beta v0.9.8 + + [-]fixed SeedsPlease compatibility + + + + Prison Labor Beta v0.9.7 + + [-]added warning message before placing labor area for the first time + + + + Prison Labor Beta v0.9.6 + + [-]updated to RimWorld 1.0 + + + + Prison Labor Beta v0.9.5 + + [-]updated to RimWorld Beta 19 + + + + Prison Labor Beta v0.9.4 + + [-]disabled Warden and Jailor types of work for prisoner labor, it should fix bug, where jailors do not warden inside labor area + + + + Prison Labor Beta v0.9.3 + + [-]fixed compatibility with No Water no Life + [-]fixed compatibility with Dubs Bad Hygiene Mod + [-]fixed error with loading old saves + + + + Prison Labor Beta v0.9.2 + + [-]fixed seeds please compatibility issue + [-]added option to disable revolts + + + + Prison Labor Beta v0.9.1 + + [-]changed max. skill required for non-advanced growing by prisoners to 6 instead of 0 + [-]added new work type Jailor + [-]fixed drawing icons on world map + [-]fixed disabling mod from existing saves + [-]fixed incorrectly showing \"advanced growing by prisoners\" option + + + + Prison Labor Beta v0.9.0 + + [-]updated to RimWorld beta v18 + [-]added option to disable icons above prisoners heads in mod menu + [-]fixed error \"null reference in onGui()\" when loading save + + + + Prison Labor Beta v0.8.8 + + [-]changed slow from prisoners chains to act as factor instead offset + [-]fixed compatibility issues with Seeds Please(again) + + + + Prison Labor Beta v0.8.7 + + [-]fixed bug with dropping motivation while in bed + [-]prisoners will now get different weapons when revolt triggers (molotovs, bows, or clubs) + [-]replaced orginal jobs with \"tweak\" jobs (instead of overriding them, this fix is for users who use \"WorkTab\" by Fluffy) + [-]removed warning message from logs + [-]prisoners will now have 50% of normal speed in chains (instead of 35%) + [-]prisoners will now break chains after some period of time instead of immadiately(matter in incidents, breakouts etc.) + [-]wardens will now try to motivate most prisoners at once, but with priority to motivate lowest motivation first + [-]fixed bug with animals do not respect reservations (and vice versa) + + + + Prison Labor Beta v0.8.6 + + [img]NewsElement_Locks[/img][b]Locks mod:[/b]\nIf you want to allow prisoners to pass by closed doors, please check out my other mod called [b]Locks[/b] + [gap] + [-]fixed bug that Sowing job do not comply to Labor Area + [-]fixed bug with JoyGiver debris (sorry about that) + [-]reduced number of null reference errors with OnGui() method (fixed in v 0.8.5) + [-]single warden will be able to maintain 7 prisoners, instead of 5 (because of laziness rate reduction) (changed in v 0.8.5) + [-]decreased laziness rate to 0.002, instead of 0.003 (prisoners will get lazy 1.5x slower) (changed in v 0.8.5) + [-]decreased manipulation to 70% (instead of 80%) (changed in v 0.8.5) + [-]fixed null reference exception at loading game (fixed in v 0.8.4) + + + + Prison Labor Beta v0.8.3 + + [-]fixed bugs with disabling mod(now you can safely disable mod again) + [-]fixed bug with prioritizing work + [-]fixed bug with rendering icons on world map + + + + Prison Labor Beta v0.8.1 + + [-]fixed bug with rendering icons on world map + [subtitle] If you encouter any bugs [b]please report it on github[/b]. I'm fixing most important ones every day. This is (recently) beta version and it has to consist some bugs. Thank you for understaning. + [subtitle] Also you can always [b]download old version[/b] via github, but I think this was last big update + [-]re-enabled button in Bills detail panel + [-]added slider to Bills (temporary fix) + [-]fixed Bill \"Prisoner only\" button (I think, let me know if you still experience errors) + [-]fixed prisoners aren't working when Motivation is disabled (via Settings) + [-]fixed null-reference error on some revolts incidents + + + + Prison Labor Beta v0.8.0 + + [subtitle][b]Now in Beta![/b] I would no longer add any more features. Instead I will focus on improving existing ones. + [gap] + [subtitle][b]Main changes:[/b] + [img]NewsElement_Revolt[/img][b]Revolts:[/b]\nPrisoners will now form organized group under self-elected leader if motivation of prisoners is low. They will try to inflict damage to your colony or they will attemp running to elected enemy faction + [img]NewsElement_InspirationReworked[/img][b]Insiration reworked:[/b]\nQuicker, better and more intuitive.\nYou can now send your prisoners to work outside your walls, but be carefull: they will try to escape if left alone. Prisoners will start thinking about escape after being left for some time. + [img]LaborAreaExpand[/img][b]Labor area:[/b]\nYou can now select area for labor only. Your colonists will no longer go mine with peasants.\nTo access this tool look into \"Architect->Zones\" panel. + [img]NewsElement_PrisonersOnly[/img][b]Prisoners Only button[/b]\nGo to Bill details to mark bills for prisoners only! + [img]NewsElement_WorkAndRecruit[/img][b]Work and recruit:[/b]\nThis feature has been mostly requested by community. I hope it will be well received. + [gap] + [subtitle][b]Other changes:[/b] + [-]added default prisoner interaction mode option to settings menu + [-]added icons above prisoners indicating whenever he's being motivated/inspired + [-]reduced manipulation capability of prisoners (now they have 80% of normal manipulation, down from 100%) + [-]added tutorials triggers (now all tutorials will be shown) + [-]added watched tutorials to properties (tutorials will no longer be shown after reenabling mod) + [-]fixed forbidden bug with harvesting plants (again) + [-]fixed Toil reservation bug (not respecting prisoners' job) + [-]fixed compatibility with Dubs Hygiene Mod + [-]fixed SeedsPlease compatibility + [-]excluded supervising from labor + [-]rewritten news dialog - now with images and stuff + [-]perfomance and code improvements + [-]translation improvements + [gap] + [subtitle]Also I want to annouce that I will start new mod called [b]Prison Expansion[/b] that would be PrisonExtensions remake.The aim of this mod would be improving Prison Labor experience, especially cell doors and fences. + + + + Prison Labor Alpha v0.7 + + [-]Added settings! You can now change almost any aspect of this mod, including:\n * work types\n * motivation mechanics\n * prevention of planting advanced plants. + [-]Added \"uninstaller\" (\"disable\" option in settings), which will allow to disable this mod from existing saves. + [-]\"No more beeping!\". Changed way of informing player what's going on with prisoners. It should be less annoying and more insightful. + [-]Fixed bugs, including bug that prevents prisoners from cleaning and bug that causes warden to stuck in loop of delivering food to prisoner. + [-]\"No more watching while prisoner is sleeping.\"Wardens will no longer watch over not working prisoners. + [-]Prisoners will now stay in bed while waiting for operation + [-]Prisoners will now stop work when starving for default (\"Anything\" time), instead of hungry. They will still get minor debuff. + + + + Prison Labor Alpha v0.6 + + [-]Time restrictions - now you can manage your prisoners time for sleep, work and joy. You can now even force them to work when they're hungry! + [-]Getting food by prisoners - Now prisoners will look for food in much better way, and now (when they desperate enough) they will eat corpses! + [-]\"Laziness\" changed to \"Motivation\" and inverted.\n\n ATTENTION: After PrisonLabor reaches beta all saves with PrisonLabor v0.5a or lower will be corrupted and unplayable. This version (0.6) is safe and converts all older saves. + + + + Prison Labor Alpha v0.5 + + [-]Prisoners can now grow, but only plants that not require any skills. + [-]You can now manage prisoners work types. Just check \"Work\" tab! + [-]Laziness now appear on \"Needs\" tab. Above 50% wardens will watch prisoners. Above 80% prisoners won't work unless supervised. + [-]Wardens will now bring food to prisoners that went too far from his bed. + [-]Prisoners won't gain laziness when not working anymore. + [-]Fixed many bugs + + + diff --git a/Source/PrisonLabor.csproj b/Source/PrisonLabor.csproj index b3179c4..8fefef9 100644 --- a/Source/PrisonLabor.csproj +++ b/Source/PrisonLabor.csproj @@ -85,6 +85,7 @@ + @@ -97,6 +98,18 @@ + + + + + + + + + + + + @@ -106,6 +119,7 @@ + @@ -142,10 +156,13 @@ + + + diff --git a/changelog.txt b/changelog.txt index 9e60264..d6d9bec 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,14 @@ Changelog: +1.4.8 +- Apparel policy can be assigned to prisoners +- Motivated prisoner will respect assigned apparel policy +- Interrogation added as new "ritual" that should not be count to ritual limits +- Warden can interrogate prisoners from non-player faction +- Interrogation can be performed in interrogation room +- Interrogation room needs new furniture "Interrogation chair" (comp from this item can be used in any other mod) +- Depends on wardens traits, skills and relation with prisoner interrogation can have different outcome +- Patches to allow prisoners to feed colony newborns +- Adjusted prisoner related alerts triggers 1.4.7 - Fixes for Vultures from "Reinforced Mechanoid 2" 1.4.6