diff --git a/1.5/Assemblies/RJW_Menstruation.dll b/1.5/Assemblies/RJW_Menstruation.dll index 7e99807..84270e6 100644 Binary files a/1.5/Assemblies/RJW_Menstruation.dll and b/1.5/Assemblies/RJW_Menstruation.dll differ diff --git a/1.5/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs b/1.5/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs index 38a25de..6732a92 100644 --- a/1.5/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs +++ b/1.5/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_PregeneratedBabies.cs @@ -150,7 +150,7 @@ namespace RJW_Menstruation } } - [HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome))] + [HarmonyPatch(typeof(PregnancyUtility), nameof(PregnancyUtility.ApplyBirthOutcome_NewTemp))] public static class ApplyBirthOutcome_PregeneratedBabies_Patch { private static Pawn GetPregeneratedBaby(PawnGenerationRequest request, Thing birtherThing) @@ -182,6 +182,7 @@ namespace RJW_Menstruation public static IEnumerable Transpiler(IEnumerable instructions) { + bool methodPatched = false; if (birtherThing < 0) throw new InvalidOperationException("Could not locate index of birtherThing"); if (GeneratePawn?.ReturnType != typeof(Pawn)) throw new InvalidOperationException("GeneratePawn not found"); foreach (CodeInstruction instruction in instructions) @@ -190,16 +191,18 @@ namespace RJW_Menstruation { yield return new CodeInstruction(OpCodes.Ldarg, birtherThing); yield return CodeInstruction.Call(typeof(ApplyBirthOutcome_PregeneratedBabies_Patch), nameof(GetPregeneratedBaby)); + methodPatched = true; } else yield return instruction; } + if (!methodPatched) throw new InvalidOperationException("PregnancyUtility.ApplyBirthOutcome_NewTemp not patched"); } } [HarmonyPatch(typeof(Hediff_LaborPushing), nameof(Hediff_LaborPushing.PreRemoved))] public static class Hediff_LaborPushing_PreRemoved_Patch { - private static Thing ApplyBirthLoop(RitualOutcomePossibility outcome, float quality, Precept_Ritual ritual, List genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments) + private static Thing ApplyBirthLoop(RitualOutcomePossibility outcome, float quality, Precept_Ritual ritual, List genes, Pawn geneticMother, Thing birtherThing, Pawn father, Pawn doctor, LordJob_Ritual lordJobRitual, RitualRoleAssignments assignments, bool preventLetter) { if (birtherThing is Pawn mother) { @@ -215,7 +218,7 @@ namespace RJW_Menstruation Pawn thisFather = baby.GetFather() ?? father; baby.relations.ClearAllRelations(); // To keep ApplyBirthOutcome from erroring when it tries to set up relations - PregnancyUtility.ApplyBirthOutcome(thisOutcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments); + PregnancyUtility.ApplyBirthOutcome_NewTemp(thisOutcome, quality, ritual, genes, geneticMother, birtherThing, thisFather, doctor, lordJobRitual, assignments, preventLetter); // No more babies if mom dies halfway through. Unrealistic maybe, but saves a lot of headache in ApplyBirthOutcome if (mother.Dead) break; if (xxx.is_human(baby)) @@ -230,20 +233,25 @@ namespace RJW_Menstruation } } - return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments); + return PregnancyUtility.ApplyBirthOutcome_NewTemp(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments, preventLetter); } - private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome), - new Type[] {typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments)}); + private static readonly MethodInfo ApplyBirthOutcome_NewTemp = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome_NewTemp), + new Type[] {typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments), typeof(bool)}); public static IEnumerable Transpiler(IEnumerable instructions) { - if (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found"); + bool methodPatched = false; + if (ApplyBirthOutcome_NewTemp?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome_NewTemp not found"); foreach (CodeInstruction instruction in instructions) { - if (instruction.Calls(ApplyBirthOutcome)) + if (instruction.Calls(ApplyBirthOutcome_NewTemp)) + { yield return CodeInstruction.Call(typeof(Hediff_LaborPushing_PreRemoved_Patch), nameof(Hediff_LaborPushing_PreRemoved_Patch.ApplyBirthLoop)); + methodPatched = true; + } else yield return instruction; } + if (!methodPatched) throw new InvalidOperationException("Hediff_LaborPushing.PreRemoved not patched"); } } @@ -283,17 +291,23 @@ namespace RJW_Menstruation } return PregnancyUtility.ApplyBirthOutcome(outcome, quality, ritual, genes, geneticMother, birtherThing, father, doctor, lordJobRitual, assignments); } + // RitualOutcomeEffectWorker_ChildBirth.Apply does not call ApplyBirthOutcome_NewTemp private static readonly MethodInfo ApplyBirthOutcome = typeof(PregnancyUtility).GetMethod(nameof(PregnancyUtility.ApplyBirthOutcome), new Type[] { typeof(RitualOutcomePossibility), typeof(float), typeof(Precept_Ritual), typeof(List), typeof(Pawn), typeof(Thing), typeof(Pawn), typeof(Pawn), typeof(LordJob_Ritual), typeof(RitualRoleAssignments) }); public static IEnumerable Transpiler(IEnumerable instructions) { + bool methodPatched = false; if (ApplyBirthOutcome?.ReturnType != typeof(Thing)) throw new InvalidOperationException("ApplyBirthOutcome not found"); foreach (CodeInstruction instruction in instructions) { if (instruction.Calls(ApplyBirthOutcome)) + { yield return CodeInstruction.Call(typeof(Ritual_ChildBirth_Apply_Patch), nameof(Ritual_ChildBirth_Apply_Patch.ApplyBirthLoop)); + methodPatched = true; + } else yield return instruction; } + if (!methodPatched) throw new InvalidOperationException("RitualOutcomeEffectWorker_ChildBirth.Apply not patched"); } } diff --git a/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs b/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs index 0125f26..7f5468f 100644 --- a/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs +++ b/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/Biotech_Patch.cs @@ -128,7 +128,7 @@ namespace RJW_Menstruation public static IEnumerable TargetMethods() { yield return AccessTools.Method(typeof(PregnancyUtility), nameof(PregnancyUtility.TryTerminatePregnancy)); - yield return AccessTools.Method(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn)); +// yield return AccessTools.Method(typeof(Recipe_TerminatePregnancy), nameof(Recipe_TerminatePregnancy.ApplyOnPawn)); } private static PregnancyAttitude? GetAttitude(Hediff pregnancy) @@ -155,19 +155,30 @@ namespace RJW_Menstruation public static IEnumerable Transpiler(IEnumerable instructions) { + int methodPatched = 0; if (GetPregnancyHediff?.ReturnType != typeof(Hediff)) throw new InvalidOperationException("GetPregnancyHediff not found"); if (Get_Attitude == null || Nullable.GetUnderlyingType(Get_Attitude.ReturnType) != typeof(PregnancyAttitude)) throw new InvalidOperationException("get_Attitude not found"); foreach (CodeInstruction instruction in instructions) { if (instruction.Calls(GetPregnancyHediff)) + { yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetEarliestPregnancy)); + methodPatched++; + } // Menstruation pregnancies don't have an attitude, so skip the cast to Hediff_Pregnant and call a version that handles it else if (instruction.opcode == OpCodes.Castclass && (Type)instruction.operand == typeof(Hediff_Pregnant)) + { yield return new CodeInstruction(OpCodes.Nop); + methodPatched++; + } else if (instruction.Calls(Get_Attitude)) + { yield return CodeInstruction.Call(typeof(TerminatePregnancy_Patch), nameof(TerminatePregnancy_Patch.GetAttitude)); + methodPatched++; + } else yield return instruction; } + if (methodPatched != 3) throw new InvalidOperationException($"PregnancyUtility.TryTerminatePregnancy or Recipe_TerminatePregnancy.ApplyOnPawn not patched ({methodPatched}"); } } diff --git a/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs b/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs index e02c665..d4a6f94 100644 --- a/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs +++ b/1.5/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs @@ -3,6 +3,7 @@ using RimWorld; using rjw; using rjw.Modules.Interactions.Enums; using rjw.Modules.Interactions.Objects; +using System; using System.Collections.Generic; using System.Linq; using System.Reflection; @@ -132,13 +133,18 @@ namespace RJW_Menstruation private static readonly MethodInfo IsPregnant = AccessTools.Method(typeof(PawnExtensions), nameof(PawnExtensions.IsPregnant), new System.Type[] { typeof(Pawn), typeof(bool) }); public static IEnumerable Transpiler(IEnumerable instructions) { + bool methodPatched = false; if (IsPregnant?.ReturnType != typeof(bool)) throw new System.InvalidOperationException("IsPregnant not found"); foreach (CodeInstruction instruction in instructions) { if (instruction.Calls(IsPregnant)) + { yield return CodeInstruction.Call(typeof(CanImpregnate_Patch), nameof(PregnancyBlocksImpregnation)); + methodPatched = true; + } else yield return instruction; } + if (!methodPatched) throw new InvalidOperationException("PregnancyHelper.CanImpregnate not patched"); } } @@ -238,6 +244,7 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { + bool methodPatched = false; if (MinimumFuckabilityToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumFuckabilityToHookup not found"); bool first_fuckability = true; foreach (CodeInstruction instruction in instructions) @@ -250,9 +257,11 @@ namespace RJW_Menstruation yield return CodeInstruction.Call(typeof(Roll_To_Skip_Patch), nameof(FuckabilityThreshold)); first_fuckability = false; + methodPatched = true; } else yield return instruction; } + if (!methodPatched) throw new InvalidOperationException("CasualSex_Helper.roll_to_skip not patched"); } } @@ -274,6 +283,7 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { + int methodPatched = 0; if (MinimumAttractivenessToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumAttractivenessToHookup not found"); if (MinimumRelationshipToHookup?.FieldType != typeof(float)) throw new System.InvalidOperationException("MinimumRelationshipToHookup not found"); LocalBuilder pawn_index = null; @@ -287,6 +297,7 @@ namespace RJW_Menstruation { // a future RJW or compiler update might change this, or maybe another mod's patch pawn_index = (LocalBuilder)instruction.operand; yield return instruction; + methodPatched++; } else if (instruction.LoadsField(MinimumAttractivenessToHookup)) { @@ -298,6 +309,7 @@ namespace RJW_Menstruation yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(AttractivenessThreshold)); first_attractiveness = false; + methodPatched++; } else if (instruction.LoadsField(MinimumRelationshipToHookup)) { @@ -309,9 +321,12 @@ namespace RJW_Menstruation yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(RelationshipThreshold)); first_relationship = false; + methodPatched++; } else yield return instruction; } + // 5 because each LoadsField gets checked twice + if (methodPatched != 5) throw new System.InvalidOperationException($"CasualSex_Helper.FindBestPartner not patched ({methodPatched})"); } } diff --git a/1.5/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs b/1.5/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs index 9b9bdad..324ff39 100644 --- a/1.5/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs +++ b/1.5/source/RJW_Menstruation/RJW_Menstruation/PregnancyCommon.cs @@ -97,53 +97,39 @@ namespace RJW_Menstruation bool IsAndroidmother = AndroidsCompatibility.IsAndroid(mother); bool IsAndroidfather = AndroidsCompatibility.IsAndroid(father); - if (IsAndroidmother && !IsAndroidfather) - { - spawn_kind_def = fatherKindDef; - } - else if (!IsAndroidmother && IsAndroidfather) - { - spawn_kind_def = motherKindDef; - } + if (IsAndroidmother != IsAndroidfather) + spawn_kind_def = IsAndroidmother ? fatherKindDef : motherKindDef; - string MotherRaceName = ""; - string FatherRaceName = ""; - MotherRaceName = motherKindDef?.race?.defName; - PawnKindDef non_hybrid_kind_def = spawn_kind_def; - if (father != null) - FatherRaceName = fatherKindDef?.race?.defName; + string MotherRaceName = motherKindDef?.race?.defName; + string FatherRaceName = fatherKindDef?.race?.defName; - - if (FatherRaceName != "" && Configurations.UseHybridExtention) + if (MotherRaceName != FatherRaceName && !FatherRaceName.NullOrEmpty()) { - spawn_kind_def = GetHybrid(father, mother); - //Log.Message("pawnkind: " + spawn_kind_def?.defName); - } - - if (MotherRaceName != FatherRaceName && FatherRaceName != "") - { - if (!Configurations.UseHybridExtention || spawn_kind_def == null) + PawnKindDef hybridPawnKind = Configurations.UseHybridExtention ? GetHybrid(father, mother) : null; + if (hybridPawnKind != null) + { + spawn_kind_def = hybridPawnKind; + } + else { - spawn_kind_def = non_hybrid_kind_def; IEnumerable groups = DefDatabase.AllDefs.Where(x => !(x.hybridRaceParents.NullOrEmpty() || x.hybridChildKindDef.NullOrEmpty())); - //ModLog.Message(" found custom RaceGroupDefs " + groups.Count()); - foreach (RaceGroupDef t in groups) + foreach (RaceGroupDef def in groups) { - if ((t.hybridRaceParents.Contains(MotherRaceName) && t.hybridRaceParents.Contains(FatherRaceName)) - || (t.hybridRaceParents.Contains("Any") && (t.hybridRaceParents.Contains(MotherRaceName) || t.hybridRaceParents.Contains(FatherRaceName)))) + if ((def.hybridRaceParents.Contains(MotherRaceName) && def.hybridRaceParents.Contains(FatherRaceName)) + || (def.hybridRaceParents.Contains("Any") && (def.hybridRaceParents.Contains(MotherRaceName) || def.hybridRaceParents.Contains(FatherRaceName)))) { //ModLog.Message(" has hybridRaceParents"); - if (t.hybridChildKindDef.Contains("MotherKindDef")) + if (def.hybridChildKindDef.Contains("MotherKindDef")) spawn_kind_def = motherKindDef; - else if (t.hybridChildKindDef.Contains("FatherKindDef") && father != null) + else if (def.hybridChildKindDef.Contains("FatherKindDef") && father != null) spawn_kind_def = fatherKindDef; else { //ModLog.Message(" trying hybridChildKindDef " + t.defName); List child_kind_def_list = new List(); - child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => t.hybridChildKindDef.Contains(x.defName))); + child_kind_def_list.AddRange(DefDatabase.AllDefs.Where(x => def.hybridChildKindDef.Contains(x.defName))); //ModLog.Message(" found custom hybridChildKindDefs " + t.hybridChildKindDef.Count); if (!child_kind_def_list.NullOrEmpty()) @@ -152,12 +138,10 @@ namespace RJW_Menstruation } } } + } - } - else if (!Configurations.UseHybridExtention || spawn_kind_def == null) - { + if (spawn_kind_def == null) spawn_kind_def = mother.RaceProps?.AnyPawnKind ?? motherKindDef; - } if (spawn_kind_def.defName.Contains("Nymph")) {