diff --git a/1.3/Assemblies/RJW_Menstruation.dll b/1.3/Assemblies/RJW_Menstruation.dll index ca99272..d5046a4 100644 Binary files a/1.3/Assemblies/RJW_Menstruation.dll and b/1.3/Assemblies/RJW_Menstruation.dll differ diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/DebugActions.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/DebugActions.cs index 50a596c..4eb1680 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/DebugActions.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/DebugActions.cs @@ -1,4 +1,5 @@ -using Verse; +using RimWorld; +using Verse; #pragma warning disable IDE0051 // Remove unused private members namespace RJW_Menstruation @@ -9,24 +10,28 @@ namespace RJW_Menstruation private static void SetFollicular(Pawn p) { p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Follicular; + Messages.Message($"{p} is now follicular", MessageTypeDefOf.NeutralEvent, false); } [DebugAction("RJW Menstruation", "Set pawn's state to ovulatory", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] private static void SetOvulatory(Pawn p) { p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Ovulatory; + Messages.Message($"{p} is now ovulatory", MessageTypeDefOf.NeutralEvent, false); } [DebugAction("RJW Menstruation", "Set pawn's state to luteal", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] private static void SetLuteal(Pawn p) { p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Luteal; + Messages.Message($"{p} is now luteal", MessageTypeDefOf.NeutralEvent, false); } [DebugAction("RJW Menstruation", "Set pawn's state to bleeding", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] private static void SetBleeding(Pawn p) { p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Bleeding; + Messages.Message($"{p} is now bleeding", MessageTypeDefOf.NeutralEvent, false); } /* [DebugAction("RJW Menstruation", "Set pawn's state to recovering", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] @@ -45,17 +50,20 @@ namespace RJW_Menstruation private static void RemoveCums(Pawn p) { p.GetMenstruationComp().RemoveAllCums(); + Messages.Message($"All cum removed from {p}'s womb", MessageTypeDefOf.NeutralEvent, false); } [DebugAction("RJW Menstruation", "Add egg to pawn's next ovulation", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] private static void AddEgg(Pawn p) { p.GetMenstruationComp().eggstack++; + Messages.Message($"1 egg added to {p}'s next ovulation ({p.GetMenstruationComp().eggstack})", MessageTypeDefOf.NeutralEvent, false); } [DebugAction("RJW Menstruation", "Recalculate pawn's ovary power", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)] private static void RecalculateOvaryPower(Pawn p) { p.GetMenstruationComp().ovarypower = p.GetMenstruationComp().GetOvaryPowerByAge(p); + Messages.Message($"{p}'s ovarypower recalculated ({p.GetMenstruationComp().ovarypower})", MessageTypeDefOf.NeutralEvent, false); } } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs index dae3f79..a56bad4 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_InducedOvulator.cs @@ -56,14 +56,18 @@ namespace RJW_Menstruation { if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false; - if (curStage == Stage.Follicular || curStage == Stage.ClimactericFollicular) return true; - else if (curStage == Stage.Luteal || curStage == Stage.ClimactericLuteal) + switch (curStage) { - if (!IsEggExist) return false; - else return curStageHrs < Props.eggLifespanDays * 24; + case Stage.Follicular: + case Stage.ClimactericFollicular: + case Stage.Ovulatory: + return true; + case Stage.Luteal: + case Stage.ClimactericLuteal: + return IsEggExist && curStageHrs < Props.eggLifespanDays * 24; + default: + return false; } - else if (curStage == Stage.Ovulatory) return true; - return false; } } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs index b361dcb..80a1d2f 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/HediffComps/HediffComp_Menstruation.cs @@ -213,9 +213,7 @@ namespace RJW_Menstruation { float factor = 1.0f; if (parent.pawn.Has(Quirk.Breeder)) factor = 10.0f; - //if (xxx.is_animal(parent.pawn)) factor *= RJWPregnancySettings.animal_impregnation_chance / 100f; - //else factor *= RJWPregnancySettings.humanlike_impregnation_chance / 100f; - return parent.pawn.health.capacities.GetLevel(xxx.reproduction) * factor; + return parent.pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * factor; } } public IEnumerable GetCumsInfo @@ -397,16 +395,19 @@ namespace RJW_Menstruation { if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false; - if (curStage == Stage.Follicular || curStage == Stage.ClimactericFollicular) + switch (curStage) { - if (curStageHrs > 0.7f * (follicularIntervalhours - bleedingIntervalhours)) return true; + case Stage.Follicular: + case Stage.ClimactericFollicular: + return curStageHrs > 0.7f * (follicularIntervalhours - bleedingIntervalhours); + case Stage.Ovulatory: + return true; + case Stage.Luteal: + case Stage.ClimactericLuteal: + return curStageHrs < Props.eggLifespanDays * 24; + default: + return false; } - else if (curStage == Stage.Luteal || curStage == Stage.ClimactericLuteal) - { - if (curStageHrs < Props.eggLifespanDays * 24) return true; - } - else if (curStage == Stage.Ovulatory) return true; - return false; } } public int GetNumofEggs @@ -890,6 +891,7 @@ namespace RJW_Menstruation { follicularIntervalhours = PeriodRandomizer(Props.folicularIntervalDays * 24, Props.deviationFactor); if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young; + else if (!IsBreedingSeason()) curStage = Stage.Anestrus; else curStage = RandomStage(); } @@ -1030,10 +1032,7 @@ namespace RJW_Menstruation public void SetEstrus(int days) { - HediffDef estrusdef; - if (Props.concealedEstrus) estrusdef = VariousDefOf.Hediff_Estrus_Concealed; - else estrusdef = VariousDefOf.Hediff_Estrus; - + HediffDef estrusdef = Props.concealedEstrus ? VariousDefOf.Hediff_Estrus_Concealed : VariousDefOf.Hediff_Estrus; HediffWithComps hediff = (HediffWithComps)parent.pawn.health.hediffSet.GetFirstHediffOfDef(estrusdef); if (hediff != null) { @@ -1098,7 +1097,7 @@ namespace RJW_Menstruation foreach (Egg egg in eggs) { if (!egg.fertilized || egg.fertstage < 168) continue; - else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * Props.baseImplantationChanceFactor * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer)) + else if (Rand.Range(0.0f, 1.0f) <= Configurations.ImplantationChance * ImplantFactor * InterspeciesImplantFactor(egg.fertilizer)) { Hediff_BasePregnancy pregnancy = parent.pawn.GetRJWPregnancy(); if (pregnancy != null) diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs index 7eb0acc..ccfa500 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/Pawn_Patch.cs @@ -89,11 +89,21 @@ namespace RJW_Menstruation public const float buttonWidth = 50f; public const float buttonHeight = 20f; + private static HediffComp_Menstruation GetFirstMenstruation(IEnumerable diffs, float rectWidth) + { + foreach (Hediff diff in diffs) + { + HediffComp_Menstruation comp = diff.GetMenstruationComp(); + if (comp != null) return comp; + } + return null; + } + public static void Prefix(Rect rect, Pawn pawn, IEnumerable diffs, ref float curY) { if (Configurations.EnableButtonInHT && pawn.ShowStatus()) { - HediffComp_Menstruation comp = diffs.First().GetMenstruationComp(); + HediffComp_Menstruation comp = GetFirstMenstruation(diffs, rect.width * 0.625f); if (comp != null) { Rect buttonrect = new Rect((rect.xMax) / 2 - 5f, curY + 2f, buttonWidth, buttonHeight); diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs index 4ff4fd4..7ee6784 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Patch/RJW_Patch.cs @@ -195,16 +195,17 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { - // We only want the first fuckability check, i.e. the estrus-haver towards a partner - bool found_fuckability = false; + bool first_fuckability = true; foreach(CodeInstruction instruction in instructions) { - if(!found_fuckability && instruction.LoadsField(MinimumFuckabilityToHookup)) + if(instruction.LoadsField(MinimumFuckabilityToHookup)) { - found_fuckability = true; - yield return new CodeInstruction(OpCodes.Ldarg_0); - yield return new CodeInstruction(OpCodes.Ldarg_1); + // The first load will be for the estrus-haver considering a partner, the second for a pawn considering the estrus-haver + yield return new CodeInstruction(first_fuckability ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1); + yield return new CodeInstruction(first_fuckability ? OpCodes.Ldarg_1 : OpCodes.Ldarg_0); + yield return CodeInstruction.Call(typeof(Roll_To_Skip_Patch), nameof(FuckabilityThreshold)); + first_fuckability = false; } else yield return instruction; } @@ -229,31 +230,39 @@ namespace RJW_Menstruation private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup)); public static IEnumerable Transpiler(IEnumerable instructions) { - object pawn_index = null; - // Like in the last one, we're only interested in the first of each - bool found_first_attractiveness = false; - bool found_first_relationship = false; + LocalBuilder pawn_index = null; + // Like in the last one, we switch the arguments around for the second load + bool first_attractiveness = true; + bool first_relationship = true; foreach(CodeInstruction instruction in instructions) { // Get where the compiler decided to index the pawn at if (pawn_index is null && instruction.opcode == OpCodes.Stloc_S) // the first stloc.s in the IL is the pawn being loaded out of the list { // a future RJW or compiler update might change this, or maybe another mod's patch - pawn_index = instruction.operand; + pawn_index = (LocalBuilder)instruction.operand; yield return instruction; } - else if (!found_first_attractiveness && instruction.LoadsField(MinimumAttractivenessToHookup)) + else if (instruction.LoadsField(MinimumAttractivenessToHookup)) { - found_first_attractiveness = true; - yield return new CodeInstruction(OpCodes.Ldarg_0); - yield return new CodeInstruction(OpCodes.Ldloc_S, pawn_index); + if (pawn_index?.LocalType != typeof(Pawn)) + throw new System.InvalidOperationException($"pawn_index is not a Pawn ({pawn_index?.LocalType})"); + + yield return first_attractiveness ? new CodeInstruction(OpCodes.Ldarg_0) : new CodeInstruction(OpCodes.Ldloc_S, pawn_index); + yield return first_attractiveness ? new CodeInstruction(OpCodes.Ldloc_S, pawn_index) : new CodeInstruction(OpCodes.Ldarg_0); + yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(AttractivenessThreshold)); - } - else if (!found_first_relationship && instruction.LoadsField(MinimumRelationshipToHookup)) + first_attractiveness = false; + } + else if (instruction.LoadsField(MinimumRelationshipToHookup)) { - found_first_relationship = true; - yield return new CodeInstruction(OpCodes.Ldarg_0); - yield return new CodeInstruction(OpCodes.Ldloc_S, pawn_index); + if (pawn_index?.LocalType != typeof(Pawn)) + throw new System.InvalidOperationException($"pawn_index is not a Pawn ({pawn_index?.LocalType})"); + + yield return first_relationship ? new CodeInstruction(OpCodes.Ldarg_0) : new CodeInstruction(OpCodes.Ldloc_S, pawn_index); + yield return first_relationship ? new CodeInstruction(OpCodes.Ldloc_S, pawn_index) : new CodeInstruction(OpCodes.Ldarg_0); + yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(RelationshipThreshold)); + first_relationship = false; } else yield return instruction; } diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs index fdd5db6..b208103 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/UI/Dialog_WombStatus.cs @@ -426,7 +426,7 @@ namespace RJW_Menstruation lineRect.y += height; } - statvalue = Configurations.ImplantationChance * comp.Props.baseImplantationChanceFactor * comp.ImplantFactor; + statvalue = Configurations.ImplantationChance * comp.ImplantFactor; float fertchance = comp.GetFertilityChance(); FillableBarLabeled(lineRect, " " + xxx.reproduction.LabelCap.CapitalizeFirst() + " " + statvalue.ToStringPercent(), statvalue, TextureCache.FertilityTexture, Texture2D.blackTexture, Translations.FertilityDesc(String.Format("{0:0.##}", fertchance*100))); Rect overayRect = new Rect(lineRect.x, lineRect.y, lineRect.width * Math.Min(1.0f, fertchance), lineRect.height); diff --git a/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs b/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs index 1fc1c1a..095b740 100644 --- a/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs +++ b/1.3/source/RJW_Menstruation/RJW_Menstruation/Utility.cs @@ -458,7 +458,7 @@ namespace RJW_Menstruation public static bool ShouldShowWombGizmo(this Pawn pawn) { - if (Configurations.EnableWombIcon && pawn.gender == Gender.Female) + if (Configurations.EnableWombIcon) { if (!pawn.IsAnimal()) { diff --git a/1.3/source/RJW_Menstruation/TextFile1.txt b/1.3/source/RJW_Menstruation/TextFile1.txt deleted file mode 100644 index e69de29..0000000 diff --git a/About/Manifest.xml b/About/Manifest.xml index 9c3cbb5..46de34f 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RJW Menstruation - 1.0.6.2 + 1.0.6.3 diff --git a/changelogs.txt b/changelogs.txt index 0f83dc8..59d1415 100644 --- a/changelogs.txt +++ b/changelogs.txt @@ -1,3 +1,11 @@ +Version 1.0.6.3 + - Fix pawn generation for races with a single lifestage. + - Show womb gizmo for males with vaginas, too. + - Originally, the casual hookup override only applied to a pawn searching for a partner. It will now also apply to a partner deciding whether to accept a hookup. + - Message feedback added to debug actions. + - Show the status button in the health tab for pawns with more than one genital. + - Known issue: The status button will be next to the first genital instead of the vagina. + Version 1.0.6.2 - Fix error/crash when a pawn in estrus (with hookup override enabled) looks for partners. - Teratophiles get the "I came inside" mood buff for ugly partners instead of pretty ones.