diff --git a/1.4/Assemblies/PrisonLabor.dll b/1.4/Assemblies/PrisonLabor.dll index 8b11ebc..78c4b92 100644 Binary files a/1.4/Assemblies/PrisonLabor.dll and b/1.4/Assemblies/PrisonLabor.dll differ diff --git a/PL_Biotech_PrisonersInteractionMode.xml b/1.4/Biotech/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PL_Biotech_PrisonersInteractionMode.xml similarity index 99% rename from PL_Biotech_PrisonersInteractionMode.xml rename to 1.4/Biotech/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PL_Biotech_PrisonersInteractionMode.xml index b586484..1e1e57c 100644 --- a/PL_Biotech_PrisonersInteractionMode.xml +++ b/1.4/Biotech/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PL_Biotech_PrisonersInteractionMode.xml @@ -1,7 +1,7 @@ - - - 工作與供血 強迫囚犯工作,血原需求者可無視囚犯心情直接對其進食。 - - 工作和血包 強迫囚犯工作,以不造成死亡為原則,抽取血液。 - + + + 工作與供血 強迫囚犯工作,血原需求者可無視囚犯心情直接對其進食。 + + 工作和血包 強迫囚犯工作,以不造成死亡為原則,抽取血液。 + \ No newline at end of file diff --git a/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll b/1.4/CashRegistry/Assemblies/PrisonLaborCashRegistryCompatibility.dll index dbc7128..8a9dbc6 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 80a7df4..48b71f9 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 new file mode 100644 index 0000000..d789ec7 Binary files /dev/null and b/1.4/ColonyGroups/Assemblies/PrisonLaborColonyGroupsCompatibility.dll differ diff --git a/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll b/1.4/Hospitality/Assemblies/PrisonLaborHospitalityCompatibility.dll index 46e3899..8fb3d32 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 96a9f16..5e8a32c 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 66720e8..13be35a 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 e9f4b4f..3075d0f 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 14b4e17..0284a2e 100644 --- a/About/About.xml +++ b/About/About.xml @@ -35,7 +35,7 @@ - Version 1.4.5 + Version 1.4.6 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/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PrisonerInteractionModeDef.xml b/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PrisonerInteractionModeDef.xml index c2eb755..2d6b02a 100644 --- a/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PrisonerInteractionModeDef.xml +++ b/Languages/ChineseTraditional/DefInjected/PrisonerInteractionModeDef/PrisonerInteractionModeDef.xml @@ -3,12 +3,4 @@ 強迫工作 工作與招募 - - 工作與供血 - 強迫囚犯工作,血原需求者可無視囚犯心情直接對其進食。 - - 工作和血包 - 強迫囚犯工作,以不造成死亡為原則,抽取血液。 - - diff --git a/LoadFolders.xml b/LoadFolders.xml index 0391afd..d52b0e8 100644 --- a/LoadFolders.xml +++ b/LoadFolders.xml @@ -29,5 +29,6 @@
  • 1.4/Kijin2
  • 1.4/Kijin
  • 1.4/Quarry
  • +
  • 1.4/ColonyGroups
  • \ No newline at end of file diff --git a/README.md b/README.md index aceed2d..c2111af 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

    - v1.4.5 + v1.4.6

    diff --git a/Source/CompatibilityProjects/ColonyGroupsCompatibility/ColonyGroupsCompatibility.csproj b/Source/CompatibilityProjects/ColonyGroupsCompatibility/ColonyGroupsCompatibility.csproj new file mode 100644 index 0000000..5154ce6 --- /dev/null +++ b/Source/CompatibilityProjects/ColonyGroupsCompatibility/ColonyGroupsCompatibility.csproj @@ -0,0 +1,76 @@ + + + + + Debug + AnyCPU + {A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD} + Library + Properties + ColonyGroupsCompatibility + PrisonLaborColonyGroupsCompatibility + v4.8 + 512 + true + + + + true + full + false + ..\..\..\1.4\ColonyGroups\Assemblies\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Lib.Harmony.2.2.2\lib\net472\0Harmony.dll + False + + + ..\..\..\..\..\Gry\Steam\steamapps\common\RimWorld\RimWorldWin64_Data\Managed\Assembly-CSharp.dll + False + + + ..\..\..\..\..\Gry\Steam\steamapps\workshop\content\294100\2345493945\1.4\Assemblies\CompatUtils.dll + False + + + + + + + + + + + ..\..\..\..\..\Gry\Steam\steamapps\workshop\content\294100\2345493945\1.4\Assemblies\TacticalGroups.dll + False + + + + + + + + + + {97750974-4cb6-4d31-84a1-a3aa77b1e2ee} + PrisonLabor + False + + + + + + + \ No newline at end of file diff --git a/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyInit.cs b/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyInit.cs new file mode 100644 index 0000000..5962469 --- /dev/null +++ b/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyInit.cs @@ -0,0 +1,29 @@ +using HarmonyLib; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace ColonyGroupsCompatibility +{ + [StaticConstructorOnStartup] + public class HarmonyInit + { + static HarmonyInit() + { + var harmony = new Harmony("Harmony_PrisonLabor_ColonyGroups"); + try + { + harmony.PatchAll(Assembly.GetExecutingAssembly()); + Log.Message("[PL] ColonyGroups patched"); + } + catch (Exception e) + { + Log.Error($"[PL] Patches for ColonyGroups failed: {e}"); + } + } + } +} diff --git a/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyPatches/MarkGroupAssigment_Patch.cs b/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyPatches/MarkGroupAssigment_Patch.cs new file mode 100644 index 0000000..b8185c9 --- /dev/null +++ b/Source/CompatibilityProjects/ColonyGroupsCompatibility/HarmonyPatches/MarkGroupAssigment_Patch.cs @@ -0,0 +1,89 @@ +using HarmonyLib; +using RimWorld; +using PrisonLabor.Core.BillAssignation; +using PrisonLabor.HarmonyPatches.Patches_GUI.GUI_Bill; +using TacticalGroups; +using System.Collections.Generic; +using Verse; +using PrisonLabor.Core.Other; +using System.Reflection; +using System.Reflection.Emit; +using System.Linq; +using static Verse.Widgets; +using System; + +namespace ColonyGroupsCompatibility.HarmonyPatches +{ + [HarmonyPatch(typeof(Patch_RestrictBillToPrisoner))] + public class ReturnLabel_Patch + { + [HarmonyPostfix] + [HarmonyPatch("GetDropLabel")] + public static string PostfixGetDropLabel(string __result, Dialog_BillConfig dialog) + { + Bill_Production bill = Traverse.Create(dialog).Field("bill").GetValue(); + if (BillAssignationUtility.IsFor(bill) == GroupMode.ColonyGroups) + { + if (HarmonyPatches_GroupBills.BillsSelectedGroup.TryGetValue(bill, out PawnGroup group)) + { + string label = "TG.AnyPawnOfGroup".Translate(group.curGroupName); + return label; + } + } + return __result; + } + + } + [HarmonyPatch] + public class MarkGroupAssigment_Patch + { + static MethodBase TargetMethod() + { + return AccessTools.Method("TacticalGroups.HarmonyPatches_GroupBills:GeneratePawnRestrictionOptions"); + } + public static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase, IEnumerable inst) + { + int bill = -1; + var codes = new List(inst); + for (int i = 0; i < codes.Count(); i++) + { + yield return codes[i]; + if (ShouldCopy(codes[i])) + { + bill = i; + } + if (ShouldPatch(codes[i]) && bill > -1) + { + DebugLogger.debug($"Changing delegate: {mBase.ReflectedType.Assembly.GetName().Name}.{mBase.ReflectedType.Name}.{mBase.Name}"); + yield return new CodeInstruction(OpCodes.Ldloc_3, null); + //ldfld | TacticalGroups.HarmonyPatches_GroupBills+<>c__DisplayClass6_0 CS$<>8__locals1 | no labels + yield return codes[bill - 1]; + //ldfld | RimWorld.Bill_Production ___bill | no labels + yield return codes[bill]; + //ldloc.s | Verse.Widgets+DropdownMenuElement`1[Verse.Pawn] (8) | no labels + yield return codes[i - 1]; + yield return new CodeInstruction(OpCodes.Call, typeof(MarkGroupAssigment_Patch).GetMethod(nameof(MarkGroupAssigment_Patch.UpdateAction))); + } + } + } + + private static bool ShouldPatch(CodeInstruction actual) + { + return actual.opcode == OpCodes.Callvirt && actual.operand != null && actual.operand.ToString().Contains("Void Insert(Int32, DropdownMenuElement`1)"); + } + + private static bool ShouldCopy(CodeInstruction actual) + { + return actual.opcode == OpCodes.Ldfld && actual.operand != null && actual.operand.ToString().Contains("RimWorld.Bill_Production ___bill"); + } + public static void UpdateAction(Bill_Production bill, DropdownMenuElement element) + { + Action notify = delegate + { + BillAssignationUtility.SetFor(bill, GroupMode.ColonyGroups); + DebugLogger.debug($"For {bill.Label} set {GroupMode.ColonyGroups}"); + }; + element.option.action += notify; + } + } +} diff --git a/Source/CompatibilityProjects/ColonyGroupsCompatibility/Properties/AssemblyInfo.cs b/Source/CompatibilityProjects/ColonyGroupsCompatibility/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..40ae7d8 --- /dev/null +++ b/Source/CompatibilityProjects/ColonyGroupsCompatibility/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("ColonyGroupsCompatibility")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ColonyGroupsCompatibility")] +[assembly: AssemblyCopyright("Copyright © 2023")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("a77ae1eb-ba5d-4b3a-9d9b-a9580850faad")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Source/CompatibilityProjects/ColonyGroupsCompatibility/packages.config b/Source/CompatibilityProjects/ColonyGroupsCompatibility/packages.config new file mode 100644 index 0000000..6bf55ad --- /dev/null +++ b/Source/CompatibilityProjects/ColonyGroupsCompatibility/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Source/Core/BillAssignation/BillAssignationUtility.cs b/Source/Core/BillAssignation/BillAssignationUtility.cs index 84d72b7..bc9ae2c 100644 --- a/Source/Core/BillAssignation/BillAssignationUtility.cs +++ b/Source/Core/BillAssignation/BillAssignationUtility.cs @@ -3,34 +3,48 @@ namespace PrisonLabor.Core.BillAssignation { - public class BillAssignationUtility + public class BillAssignationUtility + { + private static readonly Dictionary Map = new Dictionary(); + + public static GroupMode IsFor(Bill key) { - private static readonly Dictionary Map = new Dictionary(); + if (!Map.ContainsKey(key)) + { + Map[key] = new BillGroupData(); + SetMechanitorIfNeeded(key); + } + return Map[key].Mode; + } - public static GroupMode IsFor(Bill key) - { - if (!Map.ContainsKey(key)) - Map[key] = new BillGroupData(); - return Map[key].Mode; - } + public static void SetFor(Bill key, GroupMode value) + { + if (!Map.ContainsKey(key)) + Map[key] = new BillGroupData(); + Map[key].Mode = value; + } - public static void SetFor(Bill key, GroupMode value) - { - if (!Map.ContainsKey(key)) - Map[key] = new BillGroupData(); - Map[key].Mode = value; - } + public static BillGroupData GetData(Bill key) + { + if (!Map.ContainsKey(key)) + { + Map[key] = new BillGroupData(); + SetMechanitorIfNeeded(key); + } + return Map[key]; + } - public static BillGroupData GetData(Bill key) - { - if (!Map.ContainsKey(key)) - Map[key] = new BillGroupData(); - return Map[key]; - } + private static void SetMechanitorIfNeeded(Bill key) + { + if (key.recipe.mechanitorOnlyRecipe) + { + Map[key].Mode = GroupMode.MechanitorOnly; + } + } - public static void Remove(Bill bill) - { - Map.Remove(bill); - } + public static void Remove(Bill bill) + { + Map.Remove(bill); } + } } \ No newline at end of file diff --git a/Source/Core/BillAssignation/BillGroupData.cs b/Source/Core/BillAssignation/BillGroupData.cs index d9d35ae..c37ee45 100644 --- a/Source/Core/BillAssignation/BillGroupData.cs +++ b/Source/Core/BillAssignation/BillGroupData.cs @@ -8,7 +8,11 @@ public enum GroupMode PrisonersOnly, ColonistsOnly, SlavesOnly, - CaptiveOnly + HumansOnly, + MechsOnly, + MechanitorOnly, + CaptiveOnly, + ColonyGroups } public class BillGroupData : IExposable diff --git a/Source/Core/GameSaves/SaveCleaner.cs b/Source/Core/GameSaves/SaveCleaner.cs index 9936063..0fd3d30 100644 --- a/Source/Core/GameSaves/SaveCleaner.cs +++ b/Source/Core/GameSaves/SaveCleaner.cs @@ -11,263 +11,259 @@ namespace PrisonLabor.Core.GameSaves { - public static class SaveCleaner + public static class SaveCleaner + { + public static void BackupSavegame(string fileName) { - public static void BackupSavegame(string fileName) - { - string savegamePath = GenFilePaths.FilePathForSavedGame(fileName); - string backupPath = GetFilePathForBackup(savegamePath); - - File.Copy(savegamePath, backupPath, false); - Log.Message($"Save copied to \"{backupPath}\""); - } + string savegamePath = GenFilePaths.FilePathForSavedGame(fileName); + string backupPath = GetFilePathForBackup(fileName); - public static void RemoveFromSave(string fileName) - { - LongEventHandler.QueueLongEvent( - () => UpdateFile(fileName), - "Removing", - false, - (e) => OnError(e) - ); - } + File.Copy(savegamePath, backupPath, false); + Log.Message($"Save copied to \"{backupPath}\""); + } - private static void UpdateFile(string fileName) - { - string filePath = GenFilePaths.FilePathForSavedGame(fileName); + public static void RemoveFromSave(string fileName) + { + LongEventHandler.QueueLongEvent( + () => UpdateFile(fileName), + "Removing", + false, + (e) => OnError(e) + ); + } - XmlElement xmlNode; - using (StreamReader streamReader = new StreamReader(filePath)) - { - using (XmlTextReader xmlTextReader = new XmlTextReader(streamReader)) - { - var XmlDocument = new XmlDocument(); - XmlDocument.Load(xmlTextReader); - xmlNode = XmlDocument.DocumentElement; - } - } + private static void UpdateFile(string fileName) + { + string filePath = GenFilePaths.FilePathForSavedGame(fileName); - UpdateData(xmlNode); + XmlElement xmlNode; + using (StreamReader streamReader = new StreamReader(filePath)) + { + using (XmlTextReader xmlTextReader = new XmlTextReader(streamReader)) + { + var XmlDocument = new XmlDocument(); + XmlDocument.Load(xmlTextReader); + xmlNode = XmlDocument.DocumentElement; + } + } - using (FileStream saveStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) - { - var xmlWriterSettings = new XmlWriterSettings(); - xmlWriterSettings.Indent = true; - xmlWriterSettings.IndentChars = "\t"; - using (XmlWriter writer = XmlWriter.Create(saveStream, xmlWriterSettings)) - { - writer.WriteStartDocument(); - writer.WriteNode(xmlNode.CreateNavigator(), false); - } - } + UpdateData(xmlNode); - Log.Message($"Save'{fileName}' converted successfuly"); + using (FileStream saveStream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.None)) + { + var xmlWriterSettings = new XmlWriterSettings(); + xmlWriterSettings.Indent = true; + xmlWriterSettings.IndentChars = "\t"; + using (XmlWriter writer = XmlWriter.Create(saveStream, xmlWriterSettings)) + { + writer.WriteStartDocument(); + writer.WriteNode(xmlNode.CreateNavigator(), false); } + } - private static void UpdateData(XmlElement xmlNode) - { - List removalBuffer = new List(); - XmlNode curNode = xmlNode; + Log.Message($"Save'{fileName}' converted successfuly"); + } - #region Meta - var metaNode = xmlNode["meta"]; + private static void UpdateData(XmlElement xmlNode) + { + List removalBuffer = new List(); + XmlNode curNode = xmlNode; - // Meta.ModIds & Meta.ModNames - XmlNode modIdsNode = metaNode["modIds"], modNamesNode = metaNode["modNames"]; - for (int i = 0; i < modIdsNode.ChildNodes.Count; i++) - { - var modNode = modIdsNode.ChildNodes[i]; - - if (modNode.InnerText == "972057888" || modNode.InnerText == "PrisonLabor") - { - modIdsNode.RemoveChild(modIdsNode.ChildNodes[i]); - modNamesNode.RemoveChild(modNamesNode.ChildNodes[i]); - break; - } - } + #region Meta + var metaNode = xmlNode["meta"]; - // Remove version of PL - var plVersionInfo = metaNode["PrisonLaborVersion"]; - if (plVersionInfo != null) - metaNode.RemoveChild(plVersionInfo); - #endregion + // Meta.ModIds & Meta.ModNames + XmlNode modIdsNode = metaNode["modIds"], modNamesNode = metaNode["modNames"]; + for (int i = 0; i < modIdsNode.ChildNodes.Count; i++) + { + var modNode = modIdsNode.ChildNodes[i]; - #region Game - var gameNode = xmlNode["game"]; + if (modNode.InnerText == "972057888" || modNode.InnerText == "PrisonLabor") + { + modIdsNode.RemoveChild(modIdsNode.ChildNodes[i]); + modNamesNode.RemoveChild(modNamesNode.ChildNodes[i]); + break; + } + } + + // Remove version of PL + var plVersionInfo = metaNode["PrisonLaborVersion"]; + if (plVersionInfo != null) + metaNode.RemoveChild(plVersionInfo); + #endregion + + #region Game + var gameNode = xmlNode["game"]; + + // Game.Tutor + string[] conceptDefs = { "PrisonLabor_Indroduction", "PrisonLabor_Motivation", "PrisonLabor_Growing", "PrisonLabor_Management", "PrisonLabor_Timetable" }; + + var tutorNode = gameNode["tutor"]; + //var activeLessonsNode = tutorNode["activeLesson"]; + var learningReadoutNode = tutorNode["learningReadout"]; + if (learningReadoutNode["activeConcepts"].HasChildNodes) + { + removalBuffer.Clear(); + foreach (XmlNode concept in learningReadoutNode["activeConcepts"].ChildNodes) + { + foreach (string conceptDef in conceptDefs) + { + if (concept.InnerText == conceptDef) + removalBuffer.Add(concept); + } + } + foreach (var concept in removalBuffer) + learningReadoutNode["activeConcepts"].RemoveChild(concept); + } + if (learningReadoutNode["selectedConcept"] != null) + { + removalBuffer.Clear(); + foreach (string conceptDef in conceptDefs) + { + if (learningReadoutNode["selectedConcept"].InnerText == conceptDef) + learningReadoutNode.RemoveChild(learningReadoutNode["selectedConcept"]); + } + } + //var tutorialStateNode = tutorNode["tutorialState"]; - // Game.Tutor - string[] conceptDefs = { "PrisonLabor_Indroduction", "PrisonLabor_Motivation", "PrisonLabor_Growing", "PrisonLabor_Management", "PrisonLabor_Timetable" }; + // Game.Maps + foreach (XmlNode mapNode in gameNode["maps"].ChildNodes) + { + // Game.Maps.AreaManager + var areaManagerNode = mapNode["areaManager"]; - var tutorNode = gameNode["tutor"]; - //var activeLessonsNode = tutorNode["activeLesson"]; - var learningReadoutNode = tutorNode["learningReadout"]; - if (learningReadoutNode["activeConcepts"].HasChildNodes) - { - removalBuffer.Clear(); - foreach (XmlNode concept in learningReadoutNode["activeConcepts"].ChildNodes) - { - foreach (string conceptDef in conceptDefs) - { - if (concept.InnerText == conceptDef) - removalBuffer.Add(concept); - } - } - foreach (var concept in removalBuffer) - learningReadoutNode["activeConcepts"].RemoveChild(concept); - } - if (learningReadoutNode["selectedConcept"] != null) + if (areaManagerNode["areas"] != null && areaManagerNode["areas"].HasChildNodes) + { + removalBuffer.Clear(); + foreach (XmlNode areaNode in areaManagerNode["areas"].ChildNodes) + { + if (areaNode.Attributes["Class"].Value == typeof(Area_Labor).FullName) { - removalBuffer.Clear(); - foreach (string conceptDef in conceptDefs) - { - if (learningReadoutNode["selectedConcept"].InnerText == conceptDef) - learningReadoutNode.RemoveChild(learningReadoutNode["selectedConcept"]); - } + removalBuffer.Add(areaNode); } - //var tutorialStateNode = tutorNode["tutorialState"]; + } + foreach (var node in removalBuffer) + areaManagerNode["areas"].RemoveChild(node); + } - // Game.Maps - foreach (XmlNode mapNode in gameNode["maps"].ChildNodes) - { - // Game.Maps.AreaManager - var areaManagerNode = mapNode["areaManager"]; - - if (areaManagerNode["areas"] != null && areaManagerNode["areas"].HasChildNodes) - { - removalBuffer.Clear(); - foreach (XmlNode areaNode in areaManagerNode["areas"].ChildNodes) - { - if (areaNode.Attributes["Class"].Value == typeof(Area_Labor).FullName) - { - removalBuffer.Add(areaNode); - } - } - foreach (var node in removalBuffer) - areaManagerNode["areas"].RemoveChild(node); - } - - //Game.Maps.Components - var components = mapNode["components"]; - removalBuffer.Clear(); - foreach (XmlNode component in components) - { - if (component.Attributes["Class"].Value == "PrisonLabor.Core.GUI_Components.PawnIcons") - { - removalBuffer.Add(component); - } - - if (component.Attributes["Class"].Value == "PrisonLabor.Core.Trackers.CuffsTracker") - { - removalBuffer.Add(component); - } - } - foreach (var item in removalBuffer) - components.RemoveChild(item); - } + //Game.Maps.Components + var components = mapNode["components"]; + removalBuffer.Clear(); + foreach (XmlNode component in components) + { + if (component.Attributes["Class"].Value == "PrisonLabor.Core.GUI_Components.PawnIcons") + { + removalBuffer.Add(component); + } + + if (component.Attributes["Class"].Value == "PrisonLabor.Core.Trackers.CuffsTracker") + { + removalBuffer.Add(component); + } + } + foreach (var item in removalBuffer) + components.RemoveChild(item); + } - // TODO bills + // TODO bills - // Interaction Mode - string[] interactions = { PL_DefOf.PrisonLabor_workOption.defName, PL_DefOf.PrisonLabor_workAndRecruitOption.defName, PL_DefOf.PrisonLabor_workAndConvertOption.defName, PL_DefOf.PrisonLabor_workAndEnslaveOption.defName }; + // Interaction Mode + string[] interactions = { PL_DefOf.PrisonLabor_workOption.defName, PL_DefOf.PrisonLabor_workAndRecruitOption.defName, PL_DefOf.PrisonLabor_workAndConvertOption.defName, PL_DefOf.PrisonLabor_workAndEnslaveOption.defName }; - foreach (var guestTracker in gameNode.GetEveryNode("guest")) - { - var interactionMode = guestTracker["interactionMode"]; - if (interactionMode != null) - { - foreach (string interaction in interactions) - { - if (interactionMode.InnerText == interaction) - interactionMode.InnerText = PrisonerInteractionModeDefOf.NoInteraction.defName; - } - } - } + foreach (var guestTracker in gameNode.GetEveryNode("guest")) + { + var interactionMode = guestTracker["interactionMode"]; + if (interactionMode != null) + { + foreach (string interaction in interactions) + { + if (interactionMode.InnerText == interaction) + interactionMode.InnerText = PrisonerInteractionModeDefOf.NoInteraction.defName; + } + } + } - // Remove Heddifs - foreach (var needTracker in gameNode.GetEveryNode("needs")) - { - var needs = needTracker["needs"]; - if (needs != null) - { - - if (needs != null && needs.HasChildNodes) - { - removalBuffer.Clear(); - foreach (XmlNode need in needs.ChildNodes) - { - if (need.Attributes["Class"].Value == typeof(Need_Motivation).FullName) - removalBuffer.Add(need); - else if (need.Attributes["Class"].Value == typeof(Need_Treatment).FullName) - removalBuffer.Add(need); - } - foreach (var node in removalBuffer) - needs.RemoveChild(node); - } - } - } + // Remove Heddifs + foreach (var needTracker in gameNode.GetEveryNode("needs")) + { + var needs = needTracker["needs"]; + if (needs != null) + { - // Remove Heddifs - foreach (var hediffSet in gameNode.GetEveryNode("hediffSet")) + if (needs != null && needs.HasChildNodes) + { + removalBuffer.Clear(); + foreach (XmlNode need in needs.ChildNodes) { - var hediffs = hediffSet["hediffs"]; - - if (hediffs != null && hediffs.HasChildNodes) - { - removalBuffer.Clear(); - foreach (XmlNode hediff in hediffs.ChildNodes) - { - if (hediff["def"].InnerText == "PrisonLabor_PrisonerChains") - { - removalBuffer.Add(hediff); - } - } - foreach (var node in removalBuffer) - hediffs.RemoveChild(node); - } + if (need.Attributes["Class"].Value == typeof(Need_Motivation).FullName) + removalBuffer.Add(need); + else if (need.Attributes["Class"].Value == typeof(Need_Treatment).FullName) + removalBuffer.Add(need); } - #endregion + foreach (var node in removalBuffer) + needs.RemoveChild(node); + } } + } + + // Remove Heddifs + foreach (var hediffSet in gameNode.GetEveryNode("hediffSet")) + { + var hediffs = hediffSet["hediffs"]; - private static IEnumerable GetEveryNode(this XmlNode rootElement, string nodeName) + if (hediffs != null && hediffs.HasChildNodes) { - foreach (XmlNode node in rootElement.ChildNodes) + removalBuffer.Clear(); + foreach (XmlNode hediff in hediffs.ChildNodes) + { + if (hediff["def"].InnerText == "PrisonLabor_PrisonerChains") { - if (node.Name.Equals(nodeName)) - yield return node; - if (node.HasChildNodes) - { - foreach (XmlNode childNode in node.GetEveryNode(nodeName)) - yield return childNode; - } + removalBuffer.Add(hediff); } + } + foreach (var node in removalBuffer) + hediffs.RemoveChild(node); } + } + #endregion + } - private static void OnError(Exception e) + private static IEnumerable GetEveryNode(this XmlNode rootElement, string nodeName) + { + foreach (XmlNode node in rootElement.ChildNodes) + { + if (node.Name.Equals(nodeName)) + yield return node; + if (node.HasChildNodes) { - Log.Error(e.ToString()); + foreach (XmlNode childNode in node.GetEveryNode(nodeName)) + yield return childNode; } + } + } - private static string GetFilePathForBackup(string filePath) - { - string originFilePathWithoutExtension = Path.GetDirectoryName(filePath) + @"\" + Path.GetFileNameWithoutExtension(filePath); - - string backupFileCoreString = originFilePathWithoutExtension + "_Backup"; + private static void OnError(Exception e) + { + Log.Error(e.ToString()); + } - string backupFilePathFinal = backupFileCoreString + ".rws"; + private static string GetFilePathForBackup(string fileName) + { + string backupFile = GenFilePaths.FilePathForSavedGame(fileName + "_Backup"); - if (!File.Exists(backupFilePathFinal)) - return backupFilePathFinal; + if (!File.Exists(backupFile)) + return backupFile; - for (int i = 1; i < int.MaxValue; i++) - { - backupFilePathFinal = backupFileCoreString + i.ToString() + ".rws"; + for (int i = 1; i < int.MaxValue; i++) + { + backupFile = GenFilePaths.FilePathForSavedGame(fileName + "_Backup" + i); - if (!File.Exists(backupFilePathFinal)) - return backupFilePathFinal; - } + if (!File.Exists(backupFile)) + return backupFile; + } - throw new IndexOutOfRangeException(); - } + throw new IndexOutOfRangeException(); } + } } diff --git a/Source/Core/Meta/Version.cs b/Source/Core/Meta/Version.cs index 6a5f75f..ac4e8b1 100644 --- a/Source/Core/Meta/Version.cs +++ b/Source/Core/Meta/Version.cs @@ -85,6 +85,7 @@ public enum Version v1_4_2, v1_4_3, v1_4_4, - v1_4_5 + v1_4_5, + v1_4_6 } } diff --git a/Source/Core/Meta/VersionUtility.cs b/Source/Core/Meta/VersionUtility.cs index 69f0247..b5cda28 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_5; - public const string versionString = "1.4.5"; + public const Version versionNumber = Version.v1_4_6; + public const string versionString = "1.4.6"; public static Version VersionOfSaveFile { get; set; } diff --git a/Source/Core/Other/CustomForbidenUtil.cs b/Source/Core/Other/CustomForbidenUtil.cs index dc17053..a0e55e5 100644 --- a/Source/Core/Other/CustomForbidenUtil.cs +++ b/Source/Core/Other/CustomForbidenUtil.cs @@ -10,74 +10,80 @@ namespace PrisonLabor.Core.Other { - public static class CustomForbidenUtil + public static class CustomForbidenUtil + { + public static bool PrisonerCaresAboutForbidden(Pawn pawn, bool cellTarget) { - public static bool PrisonerCaresAboutForbidden(Pawn pawn, bool cellTarget) - { - if (!pawn.Spawned || !pawn.IsPrisonerOfColony && pawn.timetable.CurrentAssignment != TimeAssignmentDefOf.Work) - { - return false; - } - if (pawn.InMentalState) - { - return false; - } - if (cellTarget && ThinkNode_ConditionalShouldFollowMaster.ShouldFollowMaster(pawn)) - { - return false; - } - return true; - } + if (!pawn.Spawned || !pawn.IsPrisonerOfColony && pawn.timetable.CurrentAssignment != TimeAssignmentDefOf.Work) + { + return false; + } + if (pawn.InMentalState) + { + return false; + } + if (cellTarget && ThinkNode_ConditionalShouldFollowMaster.ShouldFollowMaster(pawn)) + { + return false; + } + return true; + } - public static bool IsFoodForbiden(this Thing t, Pawn pawn) - { - if (pawn.IsPrisonerOfColony) - { - DebugLogger.debug($"[PL] Pawn {pawn.LabelShort} checking null object"); - } - return t != null && PrisonerFoodReservation.IsReserved(t) && !pawn.IsPrisoner; - } + public static bool IsFoodForbiden(this Thing t, Pawn pawn) + { + if (pawn.IsPrisonerOfColony) + { + DebugLogger.debug($"[PL] Pawn {pawn.LabelShort} checking null object"); + } + return t != null && PrisonerFoodReservation.IsReserved(t) && !pawn.IsPrisoner; + } - public static bool IsForbiddenForPrisoner(this Thing t, Pawn pawn) - { + public static bool IsForbiddenForPrisoner(this Thing t, Pawn pawn) + { + if ((t is Frame || t is Blueprint) && ForbidUtility.IsForbidden(t, Faction.OfPlayer)) + { + //Should prevent delivering resources for frames by prisoners when forbidden. + //Simpified solution, not worth to overthing about that. + return true; + } - if (pawn.IsWatched() && ForbidUtility.IsForbidden(t, Faction.OfPlayer)) - { - return true; - } - if (!PrisonerCaresAboutForbidden(pawn, cellTarget: false)) - { - return false; - } - if (t != null && t.Spawned && t.Position.IsForbiddenForPrisoner(pawn)) - { - return true; - } - Lord lord = pawn.GetLord(); - if (lord != null && lord.extraForbiddenThings.Contains(t)) - { - return true; - } - return false; - } + if (pawn.IsWatched() && ForbidUtility.IsForbidden(t, Faction.OfPlayer)) + { + return true; + } + if (!PrisonerCaresAboutForbidden(pawn, cellTarget: false)) + { + return false; + } + if (t != null && t.Spawned && t.Position.IsForbiddenForPrisoner(pawn)) + { + return true; + } + Lord lord = pawn.GetLord(); + if (lord != null && lord.extraForbiddenThings.Contains(t)) + { + return true; + } + return false; + } - public static bool IsForbiddenForPrisoner(this IntVec3 c, Pawn pawn) - { - if (!PrisonerCaresAboutForbidden(pawn, cellTarget: true)) - { - return false; - } - if (!c.InAllowedArea(pawn)) - { - return true; - } - if (pawn.mindState.maxDistToSquadFlag > 0f && !c.InHorDistOf(pawn.DutyLocation(), pawn.mindState.maxDistToSquadFlag)) - { - return true; - } - return false; - } + public static bool IsForbiddenForPrisoner(this IntVec3 c, Pawn pawn) + { + if (!PrisonerCaresAboutForbidden(pawn, cellTarget: true)) + { + return false; + } + if (!c.InAllowedArea(pawn)) + { + return true; + } + if (pawn.mindState.maxDistToSquadFlag > 0f && !c.InHorDistOf(pawn.DutyLocation(), pawn.mindState.maxDistToSquadFlag)) + { + return true; + } + return false; } + } } diff --git a/Source/HarmonyPatches/Patches_BillAssignation/Bill_StartAnew_Patch.cs b/Source/HarmonyPatches/Patches_BillAssignation/Bill_StartAnew_Patch.cs index ea31509..0b5b215 100644 --- a/Source/HarmonyPatches/Patches_BillAssignation/Bill_StartAnew_Patch.cs +++ b/Source/HarmonyPatches/Patches_BillAssignation/Bill_StartAnew_Patch.cs @@ -1,5 +1,6 @@ using HarmonyLib; using PrisonLabor.Core.BillAssignation; +using PrisonLabor.Core.Other; using RimWorld; using System; using System.Collections.Generic; @@ -11,56 +12,61 @@ namespace PrisonLabor.HarmonyPatches.Patches_BillAssignation { - [HarmonyPatch(typeof(Bill))] - [HarmonyPatch("PawnAllowedToStartAnew")] - public class Bill_StartAnew_Patch + [HarmonyPatch(typeof(Bill))] + [HarmonyPatch("PawnAllowedToStartAnew")] + public class Bill_StartAnew_Patch + { + static bool Postfix(bool __result, Bill __instance, Pawn p) { - static bool Postfix(bool __result, Bill __instance, Pawn p) - { - if (__result == false && __instance.PawnRestriction == null) - { - GroupMode group = BillAssignationUtility.IsFor(__instance); + if (__result == false && __instance.PawnRestriction == null) + { + GroupMode group = BillAssignationUtility.IsFor(__instance); - if (group == GroupMode.ColonyOnly && __instance.SlavesOnly && p.IsSlave) - { - return true; - } - if (group == GroupMode.SlavesOnly && __instance.SlavesOnly && p.IsSlave) - { - return true; - } + if (group == GroupMode.ColonyGroups) + { + DebugLogger.debug($"Skiping checking for {__instance.Label}. Pawn: {p.NameShortColored}"); + return __result; + } - if (group == GroupMode.CaptiveOnly && __instance.SlavesOnly && p.IsSlave) - { - return true; - } - if (__instance.recipe.workSkill != null && (p.skills != null || p.IsColonyMech)) - { - int level = (p.skills != null) ? p.skills.GetSkill(__instance.recipe.workSkill).Level : p.RaceProps.mechFixedSkillLevel; - if (level < __instance.allowedSkillRange.min) - { - JobFailReason.Is("UnderAllowedSkill".Translate(__instance.allowedSkillRange.min), __instance.Label); - return false; - } - if (level > __instance.allowedSkillRange.max) - { - JobFailReason.Is("AboveAllowedSkill".Translate(__instance.allowedSkillRange.max), __instance.Label); - return false; - } + if (group == GroupMode.ColonyOnly && __instance.SlavesOnly && p.IsSlave) + { + return true; + } + if (group == GroupMode.SlavesOnly && __instance.SlavesOnly && p.IsSlave) + { + return true; + } - } - if (ModsConfig.BiotechActive && __instance.recipe.mechanitorOnlyRecipe && !MechanitorUtility.IsMechanitor(p)) - { - JobFailReason.Is("NotAMechanitor".Translate()); - return false; - } - if (group == GroupMode.ColonyOnly || (group == GroupMode.CaptiveOnly && p.IsPrisoner)) - { - return true; - } + if (group == GroupMode.CaptiveOnly && __instance.SlavesOnly && p.IsSlave) + { + return true; + } + if (__instance.recipe.workSkill != null && (p.skills != null || p.IsColonyMech)) + { + int level = (p.skills != null) ? p.skills.GetSkill(__instance.recipe.workSkill).Level : p.RaceProps.mechFixedSkillLevel; + if (level < __instance.allowedSkillRange.min) + { + JobFailReason.Is("UnderAllowedSkill".Translate(__instance.allowedSkillRange.min), __instance.Label); + return false; + } + if (level > __instance.allowedSkillRange.max) + { + JobFailReason.Is("AboveAllowedSkill".Translate(__instance.allowedSkillRange.max), __instance.Label); + return false; + } - } - return __result; } + if (group == GroupMode.MechanitorOnly) + { + return MechanitorUtility.IsMechanitor(p); + } + if (group == GroupMode.ColonyOnly || (group == GroupMode.CaptiveOnly && p.IsPrisoner)) + { + return true; + } + + } + return __result; } + } } diff --git a/Source/HarmonyPatches/Patches_BillAssignation/Patch_BillPrevention.cs b/Source/HarmonyPatches/Patches_BillAssignation/Patch_BillPrevention.cs index bff73f4..42372a0 100644 --- a/Source/HarmonyPatches/Patches_BillAssignation/Patch_BillPrevention.cs +++ b/Source/HarmonyPatches/Patches_BillAssignation/Patch_BillPrevention.cs @@ -7,33 +7,34 @@ using System; using System.IO; using PrisonLabor.Core.BillAssignation; +using Verse.AI; namespace PrisonLabor.HarmonyPatches.Patches_BillAssignation { - [HarmonyPatch(typeof(WorkGiver_DoBill))] - [HarmonyPatch("StartOrResumeBillJob")] - [HarmonyPatch(new[] { typeof(Pawn), typeof(IBillGiver) })] - internal class Patch_BillPrevention + [HarmonyPatch(typeof(WorkGiver_DoBill))] + [HarmonyPatch("StartOrResumeBillJob")] + [HarmonyPatch(new[] { typeof(Pawn), typeof(IBillGiver) })] + internal class Patch_BillPrevention + { + private static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase, + IEnumerable instr) { - private static IEnumerable Transpiler(ILGenerator gen, MethodBase mBase, - IEnumerable instr) - { - OpCode[] opCodes = - { + OpCode[] opCodes = + { OpCodes.Ldfld, OpCodes.Ldfld, OpCodes.Bne_Un }; - String[] operands = - { + String[] operands = + { "RimWorld.WorkGiverDef def", "Verse.WorkTypeDef workType", "System.Reflection.Emit.Label" }; - var label = (Label)HPatcher.FindOperandAfter(opCodes, operands, instr); + var label = (Label)HPatcher.FindOperandAfter(opCodes, operands, instr); - OpCode[] opCodes2 = - { + OpCode[] opCodes2 = + { OpCodes.Ldc_I4_0, OpCodes.Stloc_1, OpCodes.Br, @@ -43,8 +44,8 @@ private static IEnumerable Transpiler(ILGenerator gen, MethodBa OpCodes.Callvirt, OpCodes.Stloc_2, }; - String[] operands2 = - { + String[] operands2 = + { "", "", "System.Reflection.Emit.Label", @@ -54,45 +55,62 @@ private static IEnumerable Transpiler(ILGenerator gen, MethodBa "RimWorld.Bill get_Item(Int32)", "", }; - var step = 0; - foreach (var ci in instr) - { - yield return ci; - if (HPatcher.IsFragment(opCodes2, operands2, ci, ref step, "Patch_BillPrevention")) - { - yield return new CodeInstruction(OpCodes.Ldarg_1); - yield return new CodeInstruction(OpCodes.Ldloc_2); - yield return new CodeInstruction(OpCodes.Call, typeof(Patch_BillPrevention).GetMethod(nameof(IsForCertainGroup))); - yield return new CodeInstruction(OpCodes.Brfalse, label); - } - } + var step = 0; + foreach (var ci in instr) + { + yield return ci; + if (HPatcher.IsFragment(opCodes2, operands2, ci, ref step, "Patch_BillPrevention")) + { + yield return new CodeInstruction(OpCodes.Ldarg_1); + yield return new CodeInstruction(OpCodes.Ldloc_2); + yield return new CodeInstruction(OpCodes.Call, typeof(Patch_BillPrevention).GetMethod(nameof(IsForCertainGroup))); + yield return new CodeInstruction(OpCodes.Brfalse, label); } + } + } - public static bool IsForCertainGroup(Pawn pawn, Bill bill) - { - var group = BillAssignationUtility.IsFor(bill); - if (group == GroupMode.ColonyOnly) - { - return true; - } - if (group == GroupMode.ColonistsOnly && !pawn.IsPrisoner && !pawn.IsSlave) - { - return true; - } - if (group == GroupMode.PrisonersOnly && pawn.IsPrisoner) - { - return true; - } - if(group == GroupMode.SlavesOnly && bill.SlavesOnly && pawn.IsSlave) - { - return true; - } + public static bool IsForCertainGroup(Pawn pawn, Bill bill) + { + var group = BillAssignationUtility.IsFor(bill); - if(group == GroupMode.CaptiveOnly && (pawn.IsPrisoner || (bill.SlavesOnly && pawn.IsSlave))) - { - return true; - } - return false; - } + if (group == GroupMode.ColonyOnly) + { + return true; + } + if (group == GroupMode.ColonistsOnly && !pawn.IsPrisoner && !pawn.IsSlave) + { + return true; + } + if (group == GroupMode.PrisonersOnly && pawn.IsPrisoner) + { + return true; + } + if (group == GroupMode.SlavesOnly && bill.SlavesOnly && pawn.IsSlave) + { + return true; + } + + if (group == GroupMode.CaptiveOnly && (pawn.IsPrisoner || (bill.SlavesOnly && pawn.IsSlave))) + { + return true; + } + if (group == GroupMode.ColonyGroups) + { + return true; + } + if (group == GroupMode.MechanitorOnly && MechanitorUtility.IsMechanitor(pawn)) + { + return true; + } + if (group == GroupMode.MechsOnly && pawn.IsColonyMechPlayerControlled) + { + return true; + } + if (group == GroupMode.HumansOnly && !pawn.IsColonyMech) + { + return true; + } + return false; } + } } \ No newline at end of file diff --git a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_Bill_Assigment.cs b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_Bill_Assigment.cs index 2e9c03f..6067cf8 100644 --- a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_Bill_Assigment.cs +++ b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_Bill_Assigment.cs @@ -9,21 +9,43 @@ namespace PrisonLabor.HarmonyPatches.Patches_GUI.GUI_Bill { - [HarmonyPatch(typeof(Bill))] - public class Patch_Bill_Assigment + [HarmonyPatch(typeof(Bill))] + public class Patch_Bill_Assigment + { + [HarmonyPostfix] + [HarmonyPatch("SetAnyPawnRestriction")] + static void ColonistPostFix(Bill __instance) { - [HarmonyPostfix] - [HarmonyPatch("SetAnyPawnRestriction")] - static void ColonistPostFix(Bill __instance) - { - BillAssignationUtility.SetFor(__instance, GroupMode.ColonistsOnly); - } + if (__instance.recipe.mechanitorOnlyRecipe) + { + BillAssignationUtility.SetFor(__instance, GroupMode.MechanitorOnly); + } + else + { + BillAssignationUtility.SetFor(__instance, GroupMode.ColonistsOnly); + } + } + + [HarmonyPostfix] + [HarmonyPatch("SetAnyMechRestriction")] + static void MechPostFix(Bill __instance) + { + BillAssignationUtility.SetFor(__instance, GroupMode.MechsOnly); + } + - [HarmonyPostfix] - [HarmonyPatch("SetAnySlaveRestriction")] - static void SlavePostFix(Bill __instance) - { - BillAssignationUtility.SetFor(__instance, GroupMode.SlavesOnly); - } + [HarmonyPostfix] + [HarmonyPatch("SetAnyNonMechRestriction")] + static void OnlyHumanPostFix(Bill __instance) + { + BillAssignationUtility.SetFor(__instance, GroupMode.HumansOnly); + } + + [HarmonyPostfix] + [HarmonyPatch("SetAnySlaveRestriction")] + static void SlavePostFix(Bill __instance) + { + BillAssignationUtility.SetFor(__instance, GroupMode.SlavesOnly); } + } } diff --git a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs index 414951c..eb99dd7 100644 --- a/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs +++ b/Source/HarmonyPatches/Patches_GUI/GUI_Bill/Patch_RestrictBillToPrisoner.cs @@ -13,232 +13,252 @@ namespace PrisonLabor.HarmonyPatches.Patches_GUI.GUI_Bill { - [HarmonyPatch(typeof(Dialog_BillConfig))] - class Patch_RestrictBillToPrisoner - { + [HarmonyPatch(typeof(Dialog_BillConfig))] + public class Patch_RestrictBillToPrisoner + { - /// - /// Replace button label to allow select more element - /// Oryginal: - /// Widgets.Dropdown(buttonLabel: (bill.PawnRestriction != null) ? bill.PawnRestriction.LabelShortCap : ((!ModsConfig.IdeologyActive || !bill.SlavesOnly) ? ((string)"AnyWorker".Translate()) : ((string)"AnySlave".Translate())) - /// - /// - /// - [HarmonyTranspiler] - [HarmonyPatch("DoWindowContents")] - [HarmonyPatch(new[] { typeof(Rect) })] - static IEnumerable Transpiler_DoWindowContent(IEnumerable instructions) - { - /* - call | Boolean get_IdeologyActive() | Label 39 - brfalse.s | Label 41 | no labels - ldarg.0 | | no labels - ldfld | RimWorld.Bill_Production bill | no labels - callvirt | Boolean get_SlavesOnly() | no labels - brfalse.s | Label 42 | no labels - ldstr | AnySlave | no labels - call | Verse.TaggedString Translate(System.String) | no labels - call | System.String op_Implicit(Verse.TaggedString) | no labels - stloc.s | System.String (25) | no labels - br.s | Label 43 | no labels - ldstr | AnyWorker | Label 41Label 42 - call | Verse.TaggedString Translate(System.String) | no labels - call | System.String op_Implicit(Verse.TaggedString) | no labels - stloc.s | System.String (25) | no labels - */ - CodeInstruction[] replacement = - { + /// + /// Replace button label to allow select more element + /// Oryginal: + /// Widgets.Dropdown(buttonLabel: (bill.PawnRestriction != null) ? bill.PawnRestriction.LabelShortCap : ((!ModsConfig.IdeologyActive || !bill.SlavesOnly) ? ((string)"AnyWorker".Translate()) : ((string)"AnySlave".Translate())) + /// + /// + /// + [HarmonyTranspiler] + [HarmonyPatch("DoWindowContents")] + [HarmonyPatch(new[] { typeof(Rect) })] + static IEnumerable Transpiler_DoWindowContent(IEnumerable instructions) + { + /* + call | Boolean get_IdeologyActive() | Label 39 + brfalse.s | Label 41 | no labels + ldarg.0 | | no labels + ldfld | RimWorld.Bill_Production bill | no labels + callvirt | Boolean get_SlavesOnly() | no labels + brfalse.s | Label 42 | no labels + ldstr | AnySlave | no labels + call | Verse.TaggedString Translate(System.String) | no labels + call | System.String op_Implicit(Verse.TaggedString) | no labels + stloc.s | System.String (25) | no labels + br.s | Label 43 | no labels + ldstr | AnyWorker | Label 41Label 42 + call | Verse.TaggedString Translate(System.String) | no labels + call | System.String op_Implicit(Verse.TaggedString) | no labels + stloc.s | System.String (25) | no labels + */ + CodeInstruction[] replacement = + { new CodeInstruction(OpCodes.Ldarg_0), new CodeInstruction(OpCodes.Call, typeof(Patch_RestrictBillToPrisoner).GetMethod(nameof(GetLabel))), new CodeInstruction(OpCodes.Stloc_S, 25) }; - // return HPatcher.ReplaceFragment(opCodes, operands, instructions, replacement, "Patch_RestrictBillToPrisoner patch for DoWindowContents", false); + // return HPatcher.ReplaceFragment(opCodes, operands, instructions, replacement, "Patch_RestrictBillToPrisoner patch for DoWindowContents", false); - List instr = instructions.ToList(); - int start = 0; - int end = 0; - for (int i = 0; i < instr.Count(); i++) - { - if (instr[i].IsLdarg(0) && instr[i - 1].opcode == OpCodes.Stloc_S) - { - if (instr[i - 1].operand is LocalBuilder lb1 && lb1.LocalIndex == 24) - { - start = i; - - } - } + List instr = instructions.ToList(); + int start = 0; + int end = 0; + for (int i = 0; i < instr.Count(); i++) + { + if (instr[i].IsLdarg(0) && instr[i - 1].opcode == OpCodes.Stloc_S) + { + if (instr[i - 1].operand is LocalBuilder lb1 && lb1.LocalIndex == 24) + { + start = i; - if (instr[i].IsStloc() && instr[i].operand is LocalBuilder lb && lb.LocalIndex == 25 && instr[i + 1].opcode == OpCodes.Ldloc_S) - { - end = i; - } - } - instr.RemoveRange(start, end - start + 1); - instr.InsertRange(start, replacement); - - return instr.AsEnumerable(); + } } - public static string GetLabel(Dialog_BillConfig dialog) + + if (instr[i].IsStloc() && instr[i].operand is LocalBuilder lb && lb.LocalIndex == 25 && instr[i + 1].opcode == OpCodes.Ldloc_S) { + end = i; + } + } + instr.RemoveRange(start, end - start + 1); + instr.InsertRange(start, replacement); - Bill_Production bill = Traverse.Create(dialog).Field("bill").GetValue(); - if(bill.PawnRestriction != null) - { - return bill.PawnRestriction.LabelShortCap; - } - return GetDropLabel(dialog); + return instr.AsEnumerable(); + } + public static string GetLabel(Dialog_BillConfig dialog) + { + + Bill_Production bill = Traverse.Create(dialog).Field("bill").GetValue(); + if (bill.PawnRestriction != null) + { + return bill.PawnRestriction.LabelShortCap; + } + return GetDropLabel(dialog); + + } + public static string GetDropLabel(Dialog_BillConfig dialog) + { + Bill_Production bill = Traverse.Create(dialog).Field("bill").GetValue(); + GroupMode groupMode = ExtractGroupMode(bill); + switch (groupMode) + { + case GroupMode.ColonyOnly: + return "PrisonLabor_ColonyOnly".Translate(); + case GroupMode.PrisonersOnly: + return "PrisonLabor_PrisonersOnly".Translate(); + case GroupMode.ColonistsOnly: + return "AnyWorker".Translate(); + case GroupMode.SlavesOnly: + return "AnySlave".Translate(); + case GroupMode.CaptiveOnly: + return "PrisonLabor_PrisonersAndSlaveOnly".Translate(); + case GroupMode.MechanitorOnly: + return "AnyMechanitor".Translate(); + case GroupMode.MechsOnly: + return "AnyMech".Translate(); + case GroupMode.HumansOnly: + return "AnyNonMech".Translate(); + default: + return (!ModsConfig.IdeologyActive || !bill.SlavesOnly) ? ("AnyWorker".Translate()) : ("AnySlave".Translate()); + } + } + public static GroupMode ExtractGroupMode(Bill_Production bill) + { + return BillAssignationUtility.IsFor(bill); + } + + [HarmonyPostfix] + [HarmonyPatch("GeneratePawnRestrictionOptions")] + static IEnumerable> Postfix_GenerateFields(IEnumerable> values, Dialog_BillConfig __instance) + { + int check = ModsConfig.IdeologyActive ? 1 : 0; + int i = 0; + Bill_Production bill = Traverse.Create(__instance).Field("bill").GetValue(); + + if (bill.recipe.mechanitorOnlyRecipe) + { + foreach (Widgets.DropdownMenuElement value in values) + { + yield return value; } - public static string GetDropLabel(Dialog_BillConfig dialog) + yield break; + } + Widgets.DropdownMenuElement anyone = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption("PrisonLabor_ColonyOnly".Translate(), delegate + { + Traverse.Create(bill).Field("slavesOnly").SetValue(true); + Traverse.Create(bill).Field("pawnRestriction").SetValue(null); + BillAssignationUtility.SetFor(bill, GroupMode.ColonyOnly); + }), + payload = null + }; + yield return anyone; + foreach (Widgets.DropdownMenuElement value in values) + { + yield return value; + if (check == i) { - Bill_Production bill = Traverse.Create(dialog).Field("bill").GetValue(); - GroupMode groupMode = BillAssignationUtility.IsFor(bill); - switch (groupMode) + Widgets.DropdownMenuElement prisonerMenu = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption("PrisonLabor_PrisonersOnly".Translate(), delegate + { + bill.SetAnyPawnRestriction(); + BillAssignationUtility.SetFor(bill, GroupMode.PrisonersOnly); + }), + payload = null + }; + yield return prisonerMenu; + + Widgets.DropdownMenuElement anyCaptive = new Widgets.DropdownMenuElement + { + option = new FloatMenuOption("PrisonLabor_PrisonersAndSlaveOnly".Translate(), delegate { - case GroupMode.ColonyOnly: - return "PrisonLabor_ColonyOnly".Translate(); - case GroupMode.PrisonersOnly: - return "PrisonLabor_PrisonersOnly".Translate(); - case GroupMode.ColonistsOnly: - return "AnyWorker".Translate(); - case GroupMode.SlavesOnly: - return "AnySlave".Translate(); - case GroupMode.CaptiveOnly: - return "PrisonLabor_PrisonersAndSlaveOnly".Translate(); - default: - return (!ModsConfig.IdeologyActive || !bill.SlavesOnly) ? ("AnyWorker".Translate()) : ("AnySlave".Translate()); - } + bill.SetAnySlaveRestriction(); + BillAssignationUtility.SetFor(bill, GroupMode.CaptiveOnly); + }), + payload = null + }; + yield return anyCaptive; } + i++; + } + WorkGiverDef workGiver = bill.billStack.billGiver.GetWorkgiver(); + SkillDef workSkill = bill.recipe.workSkill; + IEnumerable allPrisonersOfColony = PawnsFinder.AllMaps_PrisonersOfColony; - [HarmonyPostfix] - [HarmonyPatch("GeneratePawnRestrictionOptions")] - static IEnumerable> Postfix_GenerateFields(IEnumerable> values, Dialog_BillConfig __instance) + allPrisonersOfColony = allPrisonersOfColony.OrderBy((Pawn pawn) => pawn.LabelShortCap); + if (workSkill != null) + { + allPrisonersOfColony = allPrisonersOfColony.OrderByDescending((Pawn pawn) => pawn.skills.GetSkill(bill.recipe.workSkill).Level); + } + if (workGiver == null) + { + Log.ErrorOnce("Generating pawn restrictions for a BillGiver without a Workgiver", 96455148); + yield break; + } + allPrisonersOfColony = allPrisonersOfColony.OrderByDescending((Pawn pawn) => pawn.workSettings.WorkIsActive(workGiver.workType)); + allPrisonersOfColony = allPrisonersOfColony.OrderBy((Pawn pawn) => pawn.WorkTypeIsDisabled(workGiver.workType)); + + Widgets.DropdownMenuElement dropdownMenuElement; + foreach (Pawn pawn in allPrisonersOfColony) + { + if (PrisonLaborUtility.LaborEnabled(pawn)) { - int check = ModsConfig.IdeologyActive ? 1 : 0; - int i = 0; - Bill_Production bill = Traverse.Create(__instance).Field("bill").GetValue(); - Widgets.DropdownMenuElement anyone = new Widgets.DropdownMenuElement + if (pawn.WorkTypeIsDisabled(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement { - option = new FloatMenuOption("PrisonLabor_ColonyOnly".Translate(), delegate - { - Traverse.Create(bill).Field("slavesOnly").SetValue(true); - Traverse.Create(bill).Field("pawnRestriction").SetValue(null); - BillAssignationUtility.SetFor(bill, GroupMode.ColonyOnly); - }), - payload = null + option = new FloatMenuOption(string.Format("P: {0} ({1})", pawn.LabelShortCap, "WillNever".Translate(workGiver.verb)), null), + payload = pawn }; - yield return anyone; - foreach (Widgets.DropdownMenuElement value in values) + yield return dropdownMenuElement; + } + else if (bill.recipe.workSkill != null && !pawn.workSettings.WorkIsActive(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement { - yield return value; - if (check == i) - { - Widgets.DropdownMenuElement prisonerMenu = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption("PrisonLabor_PrisonersOnly".Translate(), delegate - { - bill.SetAnyPawnRestriction(); - BillAssignationUtility.SetFor(bill, GroupMode.PrisonersOnly); - }), - payload = null - }; - yield return prisonerMenu; - - Widgets.DropdownMenuElement anyCaptive = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption("PrisonLabor_PrisonersAndSlaveOnly".Translate(), delegate - { - bill.SetAnySlaveRestriction(); - BillAssignationUtility.SetFor(bill, GroupMode.CaptiveOnly); - }), - payload = null - }; - yield return anyCaptive; - } - i++; - } - WorkGiverDef workGiver = bill.billStack.billGiver.GetWorkgiver(); - SkillDef workSkill = bill.recipe.workSkill; - IEnumerable allPrisonersOfColony = PawnsFinder.AllMaps_PrisonersOfColony; - - allPrisonersOfColony = allPrisonersOfColony.OrderBy((Pawn pawn) => pawn.LabelShortCap); - if (workSkill != null) + option = new FloatMenuOption(string.Format("P: {0} ({1} {2}, {3})", pawn.LabelShortCap, pawn.skills.GetSkill(bill.recipe.workSkill).Level, bill.recipe.workSkill.label, "NotAssigned".Translate()), delegate + { + bill.SetPawnRestriction(pawn); + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else if (!pawn.workSettings.WorkIsActive(workGiver.workType)) + { + dropdownMenuElement = new Widgets.DropdownMenuElement { - allPrisonersOfColony = allPrisonersOfColony.OrderByDescending((Pawn pawn) => pawn.skills.GetSkill(bill.recipe.workSkill).Level); - } - if (workGiver == null) + option = new FloatMenuOption(string.Format("P: {0} ({1})", pawn.LabelShortCap, "NotAssigned".Translate()), delegate + { + bill.SetPawnRestriction(pawn); + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else if (bill.recipe.workSkill != null) + { + dropdownMenuElement = new Widgets.DropdownMenuElement { - Log.ErrorOnce("Generating pawn restrictions for a BillGiver without a Workgiver", 96455148); - yield break; - } - allPrisonersOfColony = allPrisonersOfColony.OrderByDescending((Pawn pawn) => pawn.workSettings.WorkIsActive(workGiver.workType)); - allPrisonersOfColony = allPrisonersOfColony.OrderBy((Pawn pawn) => pawn.WorkTypeIsDisabled(workGiver.workType)); - - Widgets.DropdownMenuElement dropdownMenuElement; - foreach (Pawn pawn in allPrisonersOfColony) + option = new FloatMenuOption($"P: {pawn.LabelShortCap} ({pawn.skills.GetSkill(bill.recipe.workSkill).Level} {bill.recipe.workSkill.label})", delegate + { + bill.SetPawnRestriction(pawn); + }), + payload = pawn + }; + yield return dropdownMenuElement; + } + else + { + dropdownMenuElement = new Widgets.DropdownMenuElement { - if (PrisonLaborUtility.LaborEnabled(pawn)) - { - if (pawn.WorkTypeIsDisabled(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("P: {0} ({1})", pawn.LabelShortCap, "WillNever".Translate(workGiver.verb)), null), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (bill.recipe.workSkill != null && !pawn.workSettings.WorkIsActive(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("P: {0} ({1} {2}, {3})", pawn.LabelShortCap, pawn.skills.GetSkill(bill.recipe.workSkill).Level, bill.recipe.workSkill.label, "NotAssigned".Translate()), delegate - { - bill.SetPawnRestriction(pawn); - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (!pawn.workSettings.WorkIsActive(workGiver.workType)) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption(string.Format("P: {0} ({1})", pawn.LabelShortCap, "NotAssigned".Translate()), delegate - { - bill.SetPawnRestriction(pawn); - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else if (bill.recipe.workSkill != null) - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption($"P: {pawn.LabelShortCap} ({pawn.skills.GetSkill(bill.recipe.workSkill).Level} {bill.recipe.workSkill.label})", delegate - { - bill.SetPawnRestriction(pawn); - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - else - { - dropdownMenuElement = new Widgets.DropdownMenuElement - { - option = new FloatMenuOption($"P: {pawn.LabelShortCap}", delegate - { - bill.SetPawnRestriction(pawn); - }), - payload = pawn - }; - yield return dropdownMenuElement; - } - } - } + option = new FloatMenuOption($"P: {pawn.LabelShortCap}", delegate + { + bill.SetPawnRestriction(pawn); + }), + payload = pawn + }; + yield return dropdownMenuElement; + } } + } } + } } diff --git a/Source/Organizer/NewsFeed.xml b/Source/Organizer/NewsFeed.xml index 6a5af86..efcc06f 100644 --- a/Source/Organizer/NewsFeed.xml +++ b/Source/Organizer/NewsFeed.xml @@ -4,6 +4,7 @@ + diff --git a/Source/PrisonLabor.sln b/Source/PrisonLabor.sln index 6eea459..5160984 100644 --- a/Source/PrisonLabor.sln +++ b/Source/PrisonLabor.sln @@ -23,6 +23,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "KijinCompatibility", "Compa EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleaningAreaCompatibility", "CompatibilityProjects\CleaningAreaCompatibility\CleaningAreaCompatibility.csproj", "{B904E495-7C04-412A-AF45-B02EE0150087}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ColonyGroupsCompatibility", "CompatibilityProjects\ColonyGroupsCompatibility\ColonyGroupsCompatibility.csproj", "{A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -57,6 +59,10 @@ Global {B904E495-7C04-412A-AF45-B02EE0150087}.Debug|Any CPU.Build.0 = Debug|Any CPU {B904E495-7C04-412A-AF45-B02EE0150087}.Release|Any CPU.ActiveCfg = Release|Any CPU {B904E495-7C04-412A-AF45-B02EE0150087}.Release|Any CPU.Build.0 = Release|Any CPU + {A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {A77AE1EB-BA5D-4B3A-9D9B-A9580850FAAD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/changelog.txt b/changelog.txt index 613411a..7bdb02b 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,4 +1,9 @@ Changelog: +1.4.6 +- Chinese translation update (https://github.com/shiuanyue) +- Mechanitor and Mechs should be assignable from bills menu +- Prisoners should not deliver resources to forbidden frames and blueprints +- Compatibility patches for [LTO] Colony Groups 1.4.5 - Fix: need assigments for prisoners only 1.4.4