Merge 1.0.6.3

This commit is contained in:
lutepickle 2022-05-29 20:33:47 -07:00
commit ca70b0b1d4
11 changed files with 85 additions and 47 deletions

Binary file not shown.

View file

@ -1,4 +1,5 @@
using Verse; using RimWorld;
using Verse;
#pragma warning disable IDE0051 // Remove unused private members #pragma warning disable IDE0051 // Remove unused private members
namespace RJW_Menstruation namespace RJW_Menstruation
@ -9,24 +10,28 @@ namespace RJW_Menstruation
private static void SetFollicular(Pawn p) private static void SetFollicular(Pawn p)
{ {
p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Follicular; 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)] [DebugAction("RJW Menstruation", "Set pawn's state to ovulatory", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
private static void SetOvulatory(Pawn p) private static void SetOvulatory(Pawn p)
{ {
p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Ovulatory; 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)] [DebugAction("RJW Menstruation", "Set pawn's state to luteal", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
private static void SetLuteal(Pawn p) private static void SetLuteal(Pawn p)
{ {
p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Luteal; 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)] [DebugAction("RJW Menstruation", "Set pawn's state to bleeding", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
private static void SetBleeding(Pawn p) private static void SetBleeding(Pawn p)
{ {
p.GetMenstruationComp().curStage = HediffComp_Menstruation.Stage.Bleeding; 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)] [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) private static void RemoveCums(Pawn p)
{ {
p.GetMenstruationComp().RemoveAllCums(); 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)] [DebugAction("RJW Menstruation", "Add egg to pawn's next ovulation", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
private static void AddEgg(Pawn p) private static void AddEgg(Pawn p)
{ {
p.GetMenstruationComp().eggstack++; 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)] [DebugAction("RJW Menstruation", "Recalculate pawn's ovary power", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.Playing)]
private static void RecalculateOvaryPower(Pawn p) private static void RecalculateOvaryPower(Pawn p)
{ {
p.GetMenstruationComp().ovarypower = p.GetMenstruationComp().GetOvaryPowerByAge(p); p.GetMenstruationComp().ovarypower = p.GetMenstruationComp().GetOvaryPowerByAge(p);
Messages.Message($"{p}'s ovarypower recalculated ({p.GetMenstruationComp().ovarypower})", MessageTypeDefOf.NeutralEvent, false);
} }
} }
} }

View file

@ -56,14 +56,18 @@ namespace RJW_Menstruation
{ {
if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false; if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false;
if (curStage == Stage.Follicular || curStage == Stage.ClimactericFollicular) return true; switch (curStage)
else if (curStage == Stage.Luteal || curStage == Stage.ClimactericLuteal)
{ {
if (!IsEggExist) return false; case Stage.Follicular:
else return curStageHrs < Props.eggLifespanDays * 24; 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;
} }
} }

View file

@ -213,9 +213,7 @@ namespace RJW_Menstruation
{ {
float factor = 1.0f; float factor = 1.0f;
if (parent.pawn.Has(Quirk.Breeder)) factor = 10.0f; if (parent.pawn.Has(Quirk.Breeder)) factor = 10.0f;
//if (xxx.is_animal(parent.pawn)) factor *= RJWPregnancySettings.animal_impregnation_chance / 100f; return parent.pawn.health.capacities.GetLevel(xxx.reproduction) * Props.baseImplantationChanceFactor * factor;
//else factor *= RJWPregnancySettings.humanlike_impregnation_chance / 100f;
return parent.pawn.health.capacities.GetLevel(xxx.reproduction) * factor;
} }
} }
public IEnumerable<string> GetCumsInfo public IEnumerable<string> GetCumsInfo
@ -397,16 +395,19 @@ namespace RJW_Menstruation
{ {
if (parent.pawn.health.hediffSet.HasHediff(VariousDefOf.RJW_IUD)) return false; 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 public int GetNumofEggs
@ -890,6 +891,7 @@ namespace RJW_Menstruation
{ {
follicularIntervalhours = PeriodRandomizer(Props.folicularIntervalDays * 24, Props.deviationFactor); follicularIntervalhours = PeriodRandomizer(Props.folicularIntervalDays * 24, Props.deviationFactor);
if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young; if (parent.pawn.health.capacities.GetLevel(xxx.reproduction) <= 0) curStage = Stage.Young;
else if (!IsBreedingSeason()) curStage = Stage.Anestrus;
else curStage = RandomStage(); else curStage = RandomStage();
} }
@ -1030,10 +1032,7 @@ namespace RJW_Menstruation
public void SetEstrus(int days) public void SetEstrus(int days)
{ {
HediffDef estrusdef; HediffDef estrusdef = Props.concealedEstrus ? VariousDefOf.Hediff_Estrus_Concealed : VariousDefOf.Hediff_Estrus;
if (Props.concealedEstrus) estrusdef = VariousDefOf.Hediff_Estrus_Concealed;
else estrusdef = VariousDefOf.Hediff_Estrus;
HediffWithComps hediff = (HediffWithComps)parent.pawn.health.hediffSet.GetFirstHediffOfDef(estrusdef); HediffWithComps hediff = (HediffWithComps)parent.pawn.health.hediffSet.GetFirstHediffOfDef(estrusdef);
if (hediff != null) if (hediff != null)
{ {
@ -1098,7 +1097,7 @@ namespace RJW_Menstruation
foreach (Egg egg in eggs) foreach (Egg egg in eggs)
{ {
if (!egg.fertilized || egg.fertstage < 168) continue; 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(); Hediff_BasePregnancy pregnancy = parent.pawn.GetRJWPregnancy();
if (pregnancy != null) if (pregnancy != null)

View file

@ -89,11 +89,21 @@ namespace RJW_Menstruation
public const float buttonWidth = 50f; public const float buttonWidth = 50f;
public const float buttonHeight = 20f; public const float buttonHeight = 20f;
private static HediffComp_Menstruation GetFirstMenstruation(IEnumerable<Hediff> 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<Hediff> diffs, ref float curY) public static void Prefix(Rect rect, Pawn pawn, IEnumerable<Hediff> diffs, ref float curY)
{ {
if (Configurations.EnableButtonInHT && pawn.ShowStatus()) if (Configurations.EnableButtonInHT && pawn.ShowStatus())
{ {
HediffComp_Menstruation comp = diffs.First().GetMenstruationComp(); HediffComp_Menstruation comp = GetFirstMenstruation(diffs, rect.width * 0.625f);
if (comp != null) if (comp != null)
{ {
Rect buttonrect = new Rect((rect.xMax) / 2 - 5f, curY + 2f, buttonWidth, buttonHeight); Rect buttonrect = new Rect((rect.xMax) / 2 - 5f, curY + 2f, buttonWidth, buttonHeight);

View file

@ -195,16 +195,17 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup)); private static readonly FieldInfo MinimumFuckabilityToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumFuckabilityToHookup));
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{ {
// We only want the first fuckability check, i.e. the estrus-haver towards a partner bool first_fuckability = true;
bool found_fuckability = false;
foreach(CodeInstruction instruction in instructions) foreach(CodeInstruction instruction in instructions)
{ {
if(!found_fuckability && instruction.LoadsField(MinimumFuckabilityToHookup)) if(instruction.LoadsField(MinimumFuckabilityToHookup))
{ {
found_fuckability = true; // 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(OpCodes.Ldarg_0); yield return new CodeInstruction(first_fuckability ? OpCodes.Ldarg_0 : OpCodes.Ldarg_1);
yield return new CodeInstruction(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)); yield return CodeInstruction.Call(typeof(Roll_To_Skip_Patch), nameof(FuckabilityThreshold));
first_fuckability = false;
} }
else yield return instruction; else yield return instruction;
} }
@ -229,31 +230,39 @@ namespace RJW_Menstruation
private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup)); private static readonly FieldInfo MinimumRelationshipToHookup = AccessTools.Field(typeof(RJWHookupSettings), nameof(RJWHookupSettings.MinimumRelationshipToHookup));
public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) public static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{ {
object pawn_index = null; LocalBuilder pawn_index = null;
// Like in the last one, we're only interested in the first of each // Like in the last one, we switch the arguments around for the second load
bool found_first_attractiveness = false; bool first_attractiveness = true;
bool found_first_relationship = false; bool first_relationship = true;
foreach(CodeInstruction instruction in instructions) foreach(CodeInstruction instruction in instructions)
{ {
// Get where the compiler decided to index the pawn at // 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 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 { // 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; yield return instruction;
} }
else if (!found_first_attractiveness && instruction.LoadsField(MinimumAttractivenessToHookup)) else if (instruction.LoadsField(MinimumAttractivenessToHookup))
{ {
found_first_attractiveness = true; if (pawn_index?.LocalType != typeof(Pawn))
yield return new CodeInstruction(OpCodes.Ldarg_0); throw new System.InvalidOperationException($"pawn_index is not a Pawn ({pawn_index?.LocalType})");
yield return new CodeInstruction(OpCodes.Ldloc_S, pawn_index);
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)); yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(AttractivenessThreshold));
} first_attractiveness = false;
else if (!found_first_relationship && instruction.LoadsField(MinimumRelationshipToHookup)) }
else if (instruction.LoadsField(MinimumRelationshipToHookup))
{ {
found_first_relationship = true; if (pawn_index?.LocalType != typeof(Pawn))
yield return new CodeInstruction(OpCodes.Ldarg_0); throw new System.InvalidOperationException($"pawn_index is not a Pawn ({pawn_index?.LocalType})");
yield return new CodeInstruction(OpCodes.Ldloc_S, pawn_index);
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)); yield return CodeInstruction.Call(typeof(FindBestPartner_Patch), nameof(RelationshipThreshold));
first_relationship = false;
} }
else yield return instruction; else yield return instruction;
} }

View file

@ -426,7 +426,7 @@ namespace RJW_Menstruation
lineRect.y += height; lineRect.y += height;
} }
statvalue = Configurations.ImplantationChance * comp.Props.baseImplantationChanceFactor * comp.ImplantFactor; statvalue = Configurations.ImplantationChance * comp.ImplantFactor;
float fertchance = comp.GetFertilityChance(); 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))); 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); Rect overayRect = new Rect(lineRect.x, lineRect.y, lineRect.width * Math.Min(1.0f, fertchance), lineRect.height);

View file

@ -458,7 +458,7 @@ namespace RJW_Menstruation
public static bool ShouldShowWombGizmo(this Pawn pawn) public static bool ShouldShowWombGizmo(this Pawn pawn)
{ {
if (Configurations.EnableWombIcon && pawn.gender == Gender.Female) if (Configurations.EnableWombIcon)
{ {
if (!pawn.IsAnimal()) if (!pawn.IsAnimal())
{ {

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest> <Manifest>
<identifier>RJW Menstruation</identifier> <identifier>RJW Menstruation</identifier>
<version>1.0.6.2</version> <version>1.0.6.3</version>
<dependencies> <dependencies>
</dependencies> </dependencies>
<incompatibleWith /> <incompatibleWith />

View file

@ -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 Version 1.0.6.2
- Fix error/crash when a pawn in estrus (with hookup override enabled) looks for partners. - 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. - Teratophiles get the "I came inside" mood buff for ugly partners instead of pretty ones.