Compare commits

..

No commits in common. "cd9647f999587dd8feef7b5fbf155ae8a754f751" and "67c2328ad6c41ad5b5cdd0535ab71f8a1175a514" have entirely different histories.

7 changed files with 108 additions and 89 deletions

View file

@ -13,7 +13,7 @@ namespace RJWSexperience
return false; return false;
IEnumerable<PawnRelationDef> relations = pawn.GetRelations(otherpawn); IEnumerable<PawnRelationDef> relations = pawn.GetRelations(otherpawn);
if (relations == null) if (relations.EnumerableNullOrEmpty())
return false; return false;
foreach (PawnRelationDef relation in relations) foreach (PawnRelationDef relation in relations)
@ -31,50 +31,67 @@ namespace RJWSexperience
return 1.0f; return 1.0f;
} }
public static T GetAdjacentBuilding<T>(this Pawn pawn) where T : Building => GetAdjacentBuildings<T>(pawn).FirstOrFallback(); public static T GetAdjacentBuilding<T>(this Pawn pawn) where T : Building
public static IEnumerable<T> GetAdjacentBuildings<T>(this Pawn pawn) where T : Building
{ {
if (!pawn.Spawned) if (!pawn.Spawned)
yield break; return null;
EdificeGrid edifice = pawn.Map.edificeGrid; EdificeGrid edifice = pawn.Map.edificeGrid;
if (edifice[pawn.Position] is T building) if (edifice[pawn.Position] is T building)
yield return building; return building;
foreach (IntVec3 pos in GenAdjFast.AdjacentCells8Way(pawn.Position))
{
if (edifice[pos] is T adjBuilding)
return adjBuilding;
}
return null;
}
public static IEnumerable<T> GetAdjacentBuildings<T>(this Pawn pawn) where T : Building
{
var results = new List<T>();
if (!pawn.Spawned)
return results;
EdificeGrid edifice = pawn.Map.edificeGrid;
if (edifice[pawn.Position] is T building)
results.Add(building);
foreach (IntVec3 pos in GenAdjFast.AdjacentCells8Way(pawn.Position)) foreach (IntVec3 pos in GenAdjFast.AdjacentCells8Way(pawn.Position))
{ {
if (pos.InBounds(pawn.Map) && edifice[pos] is T adjBuilding) if (pos.InBounds(pawn.Map) && edifice[pos] is T adjBuilding)
yield return adjBuilding; results.Add(adjBuilding);
} }
return results;
} }
/// <summary> /// <summary>
/// Check if the pawn is virgin /// If the pawn is virgin, return true.
/// </summary> /// </summary>
public static bool IsVirgin(this Pawn pawn) public static bool IsVirgin(this Pawn pawn)
{ {
return pawn.records.GetValue(RsDefOf.Record.VaginalSexCount) == 0 || return pawn.records.GetValue(RsDefOf.Record.VaginalSexCount) == 0;
pawn.relations?.ChildrenCount > 0; // Male is a virgins unless he stick into vagina? Not sure it should work this way
} }
/// <summary> /// <summary>
/// Remove virginity if pawn is virgin and announce it /// If pawn is virgin, lose his/her virginity.
/// </summary> /// </summary>
public static void TryRemoveVirginity(this Pawn pawn, Pawn partner, SexProps props) public static void PoptheCherry(this Pawn pawn, Pawn partner, SexProps props)
{ {
if (props?.sexType != xxx.rjwSextype.Vaginal)
return;
int? removedDegree = Virginity.TraitHandler.RemoveVirginTrait(pawn); int? removedDegree = Virginity.TraitHandler.RemoveVirginTrait(pawn);
if (SexperienceMod.Settings.EnableSexHistory && pawn.IsVirgin()) if (pawn.IsVirgin())
{ {
pawn.TryGetComp<SexHistory.SexHistoryComp>()?.RecordFirst(partner); pawn.TryGetComp<SexHistory.SexHistoryComp>()?.RecordFirst(partner, props);
if (removedDegree != null)
Messages.Message(Keyed.RS_LostVirgin(pawn.LabelShort, partner.LabelShort), MessageTypeDefOf.NeutralEvent, true);
} }
if (removedDegree != null && removedDegree != Virginity.TraitDegree.FemaleAfterSurgery) if (removedDegree != null)
{
Messages.Message(Keyed.RS_LostVirgin(pawn.LabelShort, partner.LabelShort), MessageTypeDefOf.NeutralEvent, true);
RJWUtility.ThrowVirginHistoryEvent(pawn, partner, props, (int)removedDegree); RJWUtility.ThrowVirginHistoryEvent(pawn, partner, props, (int)removedDegree);
} }
} }
} }
}

View file

@ -19,22 +19,11 @@ namespace RJWSexperience.ExtensionMethods
public static bool IsBestiality(this SexProps props) public static bool IsBestiality(this SexProps props)
{ {
if (props.hasPartner()) if (props.partner != null)
{ {
return props.pawn.IsAnimal() ^ props.partner.IsAnimal(); return props.pawn.IsAnimal() ^ props.partner.IsAnimal();
} }
return false; return false;
} }
/// <summary>
/// Get a not-so-unique ID. Same interaction between the same partners will return same ID
/// </summary>
public static int GetTempId(this SexProps props)
{
return props.pawn.GetHashCode() ^
(props.partner?.GetHashCode() ?? 0) ^
props.dictionaryKey.GetHashCode() ^
(props.isReceiver ? 0 : 1);
}
} }
} }

View file

@ -11,7 +11,7 @@ using Verse;
namespace RJWSexperience namespace RJWSexperience
{ {
[HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] // Despite the name, called every tick [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")]
public static class RJW_Patch_Orgasm public static class RJW_Patch_Orgasm
{ {
public static void Postfix(JobDriver_Sex __instance) public static void Postfix(JobDriver_Sex __instance)
@ -30,7 +30,7 @@ namespace RJWSexperience
} }
} }
[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))] // Actual on orgasm method [HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))]
public static class RJW_Patch_SatisfyPersonal public static class RJW_Patch_SatisfyPersonal
{ {
private const float base_sat_per_fuck = 0.4f; private const float base_sat_per_fuck = 0.4f;
@ -46,7 +46,7 @@ namespace RJWSexperience
CumUtility.FillCumBuckets(props); CumUtility.FillCumBuckets(props);
props.pawn.records?.Increment(RsDefOf.Record.OrgasmCount); props.pawn.records?.Increment(RsDefOf.Record.OrgasmCount);
if (SexperienceMod.Settings.EnableSexHistory && props.hasPartner()) if (SexperienceMod.Settings.EnableSexHistory && props.hasPartner())
props.pawn.TryGetComp<SexHistoryComp>()?.RecordOrgasm(props.partner, props, satisfaction); props.pawn.TryGetComp<SexHistoryComp>()?.RecordSatisfaction(props.partner, props, satisfaction);
} }
} }
@ -94,10 +94,10 @@ namespace RJWSexperience
{ {
public static void Postfix(JobDriver_SexBaseInitiator __instance) public static void Postfix(JobDriver_SexBaseInitiator __instance)
{ {
if (__instance.Sexprops.hasPartner() && __instance.Sexprops.sexType == xxx.rjwSextype.Vaginal) if (__instance.Sexprops.hasPartner())
{ {
__instance.pawn.TryRemoveVirginity(__instance.Partner, __instance.Sexprops); __instance.pawn.PoptheCherry(__instance.Partner, __instance.Sexprops);
__instance.Partner.TryRemoveVirginity(__instance.pawn, __instance.Sexprops); __instance.Partner.PoptheCherry(__instance.pawn, __instance.Sexprops);
} }
} }
} }
@ -108,7 +108,9 @@ namespace RJWSexperience
/// <summary> /// <summary>
/// If masturbation and current map has a bucket, return location near the bucket /// If masturbation and current map has a bucket, return location near the bucket
/// </summary> /// </summary>
/// <param name="__result">The place to stand near a bucket</param> /// <param name="pawn"></param>
/// <param name="partner"></param>
/// <param name="__result"></param>
/// <returns>Run original method</returns> /// <returns>Run original method</returns>
public static bool Prefix(Pawn pawn, Pawn partner, ref IntVec3 __result) public static bool Prefix(Pawn pawn, Pawn partner, ref IntVec3 __result)
{ {

View file

@ -6,14 +6,11 @@ using Verse;
namespace RJWSexperience.SexHistory namespace RJWSexperience.SexHistory
{ {
/// <summary>
/// Stores pawn's sex history and handles its updates
/// </summary>
public class SexHistoryComp : ThingComp public class SexHistoryComp : ThingComp
{ {
public const int ARRLEN = 20; public const int ARRLEN = 20;
protected Dictionary<string, SexPartnerHistoryRecord> partnerRecords = new Dictionary<string, SexPartnerHistoryRecord>(); protected Dictionary<string, SexPartnerHistoryRecord> histories = new Dictionary<string, SexPartnerHistoryRecord>();
protected string first = ""; protected string first = "";
protected bool dirty = true; protected bool dirty = true;
protected xxx.rjwSextype recentSex = xxx.rjwSextype.None; protected xxx.rjwSextype recentSex = xxx.rjwSextype.None;
@ -46,14 +43,17 @@ namespace RJWSexperience.SexHistory
protected int bestSexTickAbsCache = 0; protected int bestSexTickAbsCache = 0;
public Gizmo Gizmo { get; private set; } public Gizmo Gizmo { get; private set; }
public Pawn ParentPawn => parent as Pawn; public Pawn ParentPawn => parent as Pawn;
public SexPartnerHistoryRecord FirstPartnerRecord => partnerRecords.TryGetValue(first);
public SexPartnerHistoryRecord MostPartnerRecord public SexPartnerHistoryRecord GetFirstPartnerHistory => histories.TryGetValue(first);
public SexPartnerHistoryRecord GetMostPartnerHistory
{ {
get get
{ {
Update(); Update();
return partnerRecords.TryGetValue(mostPartnerCache); return histories.TryGetValue(mostPartnerCache);
} }
} }
public xxx.rjwSextype MostSextype public xxx.rjwSextype MostSextype
@ -72,13 +72,13 @@ namespace RJWSexperience.SexHistory
return mostSatSextypeCache; return mostSatSextypeCache;
} }
} }
public SexPartnerHistoryRecord RecentPartnerRecord => partnerRecords.TryGetValue(recentPartner); public SexPartnerHistoryRecord GetRecentPartnersHistory => histories.TryGetValue(recentPartner);
public SexPartnerHistoryRecord BestSexPartnerRecord public SexPartnerHistoryRecord GetBestSexPartnerHistory
{ {
get get
{ {
Update(); Update();
return partnerRecords.TryGetValue(bestPartnerCache); return histories.TryGetValue(bestPartnerCache);
} }
} }
public float TotalSexHad public float TotalSexHad
@ -96,14 +96,21 @@ namespace RJWSexperience.SexHistory
{ {
IEnumerable<SexPartnerHistoryRecord> res = Enumerable.Empty<SexPartnerHistoryRecord>(); IEnumerable<SexPartnerHistoryRecord> res = Enumerable.Empty<SexPartnerHistoryRecord>();
Update(); Update();
if (!partnerRecords.NullOrEmpty()) if (!histories.NullOrEmpty())
{ {
res = partnerRecords.Values; res = histories.Values;
} }
return res; return res;
} }
} }
public int PartnerCount => partnerRecords?.Count ?? 0; public int PartnerCount
{
get
{
if (histories == null) histories = new Dictionary<string, SexPartnerHistoryRecord>();
return histories.Count;
}
}
public int IncestuousCount => incestuous; public int IncestuousCount => incestuous;
public int RapedCount public int RapedCount
{ {
@ -153,6 +160,7 @@ namespace RJWSexperience.SexHistory
public int FirstSexTickAbs => firstSexTickAbs; public int FirstSexTickAbs => firstSexTickAbs;
public int MostSexTickAbs => mostSexTickAbsCache; public int MostSexTickAbs => mostSexTickAbsCache;
public int BestSexTickAbs => bestSexTickAbsCache; public int BestSexTickAbs => bestSexTickAbsCache;
public Pawn PreferRacePawn public Pawn PreferRacePawn
{ {
get get
@ -178,9 +186,9 @@ namespace RJWSexperience.SexHistory
public int GetSextypeRecentTickAbs(int sextype) => sextypeRecentTickAbs[sextype]; public int GetSextypeRecentTickAbs(int sextype) => sextypeRecentTickAbs[sextype];
public float GetAVGSat(int sextype) public float GetAVGSat(int index)
{ {
float res = sextypeSat[sextype] / sextypeCount[sextype]; float res = sextypeSat[index] / sextypeCount[index];
return float.IsNaN(res) ? 0f : res; return float.IsNaN(res) ? 0f : res;
} }
@ -205,7 +213,7 @@ namespace RJWSexperience.SexHistory
sextyperecenttickabssave = new List<int>(); sextyperecenttickabssave = new List<int>();
} }
Scribe_Collections.Look(ref partnerRecords, "histories", LookMode.Value, LookMode.Deep); Scribe_Collections.Look(ref histories, "histories", LookMode.Value, LookMode.Deep);
Scribe_Values.Look(ref first, "first", string.Empty); Scribe_Values.Look(ref first, "first", string.Empty);
Scribe_Values.Look(ref recentSex, "recentsex", xxx.rjwSextype.None); Scribe_Values.Look(ref recentSex, "recentsex", xxx.rjwSextype.None);
Scribe_Values.Look(ref recentSat, "recentsat", 0); Scribe_Values.Look(ref recentSat, "recentsat", 0);
@ -220,8 +228,8 @@ namespace RJWSexperience.SexHistory
Scribe_Collections.Look(ref sextypesatsave, "sextypesatsave", LookMode.Value); Scribe_Collections.Look(ref sextypesatsave, "sextypesatsave", LookMode.Value);
Scribe_Collections.Look(ref sextyperecenttickabssave, "sextyperecenttickabssave", LookMode.Value); Scribe_Collections.Look(ref sextyperecenttickabssave, "sextyperecenttickabssave", LookMode.Value);
if (partnerRecords == null) if (histories == null)
partnerRecords = new Dictionary<string, SexPartnerHistoryRecord>(); histories = new Dictionary<string, SexPartnerHistoryRecord>();
if (Scribe.mode == LoadSaveMode.LoadingVars) if (Scribe.mode == LoadSaveMode.LoadingVars)
{ {
@ -229,7 +237,7 @@ namespace RJWSexperience.SexHistory
sextypeSat = sextypesatsave?.ToArray() ?? new float[ARRLEN]; sextypeSat = sextypesatsave?.ToArray() ?? new float[ARRLEN];
sextypeRecentTickAbs = sextyperecenttickabssave?.ToArray() ?? new int[ARRLEN]; sextypeRecentTickAbs = sextyperecenttickabssave?.ToArray() ?? new int[ARRLEN];
foreach (KeyValuePair<string, SexPartnerHistoryRecord> element in partnerRecords) foreach (KeyValuePair<string, SexPartnerHistoryRecord> element in histories)
{ {
element.Value.PartnerID = element.Key; element.Value.PartnerID = element.Key;
} }
@ -239,52 +247,50 @@ namespace RJWSexperience.SexHistory
public void RecordSex(Pawn partner, SexProps props) public void RecordSex(Pawn partner, SexProps props)
{ {
SexPartnerHistoryRecord partnerRecord = GetPartnerRecord(partner); RecordFirst(partner, props);
partnerRecord.RecordSex(props); GetPartnerRecord(partner)?.RecordSex(props);
recentPartner = partner.ThingID; recentPartner = partner.ThingID;
recentSex = props.sexType; recentSex = props.sexType;
sextypeCount[(int)props.sexType]++; sextypeCount[(int)props.sexType]++;
sextypeRecentTickAbs[(int)props.sexType] = GenTicks.TicksAbs; sextypeRecentTickAbs[(int)props.sexType] = GenTicks.TicksAbs;
if (partnerRecord.Incest) incestuous++; if (partner.IsIncest(ParentPawn)) incestuous++;
if (partner.Dead) corpsefuck++; if (partner.Dead) corpsefuck++;
if (props.IsBestiality()) bestiality++; if (props.IsBestiality()) bestiality++;
else if (ParentPawn.def != partner.def) interspecies++; else if (ParentPawn.def != partner.def) interspecies++;
dirty = true; dirty = true;
} }
public void RecordOrgasm(Pawn partner, SexProps props, float satisfaction) public void RecordSatisfaction(Pawn partner, SexProps props, float satisfaction)
{ {
GetPartnerRecord(partner).RecordOrgasm(props.sexType, satisfaction); RecordFirst(partner, props);
GetPartnerRecord(partner)?.RecordSatisfaction(props, satisfaction);
recentSat = satisfaction; recentSat = satisfaction;
sextypeSat[(int)props.sexType] += satisfaction; // Several orgasmsms in one sex are messing with this sextypeSat[(int)props.sexType] += satisfaction;
dirty = true; dirty = true;
} }
/// <summary> public void RecordFirst(Pawn partner, SexProps props)
/// Record first partner and time of sex. No checks are performed, the caller should make sure it is the first time. {
/// </summary> if (VirginCheck() && props.sexType == xxx.rjwSextype.Vaginal)
/// <param name="partner"></param>
public void RecordFirst(Pawn partner)
{ {
first = partner.ThingID; first = partner.ThingID;
SexHistoryComp history = partner.TryGetComp<SexHistoryComp>();
firstSexTickAbs = GenTicks.TicksAbs; firstSexTickAbs = GenTicks.TicksAbs;
partner.TryGetComp<SexHistoryComp>()?.TakeSomeonesVirgin(ParentPawn); history?.TakeSomeonesVirgin(ParentPawn);
}
} }
/// <summary>
/// Retrive an existing partner record or add a new one. Increments SexPartnerCount when new record is added
/// </summary>
protected SexPartnerHistoryRecord GetPartnerRecord(Pawn partner) protected SexPartnerHistoryRecord GetPartnerRecord(Pawn partner)
{ {
string partnerId = partner.ThingID; string partnerId = partner.ThingID;
if (partnerRecords.TryGetValue(partnerId, out SexPartnerHistoryRecord record)) if (histories.TryGetValue(partnerId, out SexPartnerHistoryRecord record))
{ {
return record; return record;
} }
SexPartnerHistoryRecord newRecord = new SexPartnerHistoryRecord(partner, partner.IsIncest(ParentPawn)); SexPartnerHistoryRecord newRecord = new SexPartnerHistoryRecord(partner, partner.IsIncest(ParentPawn));
partnerRecords.Add(partnerId, newRecord); histories.Add(partnerId, newRecord);
ParentPawn.records.Increment(RsDefOf.Record.SexPartnerCount); ParentPawn.records.Increment(RsDefOf.Record.SexPartnerCount);
return newRecord; return newRecord;
} }
@ -322,7 +328,7 @@ namespace RJWSexperience.SexHistory
Dictionary<ThingDef, int> racetotalsat = new Dictionary<ThingDef, int>(); Dictionary<ThingDef, int> racetotalsat = new Dictionary<ThingDef, int>();
List<Pawn> allpartners = new List<Pawn>(); List<Pawn> allpartners = new List<Pawn>();
foreach (KeyValuePair<string, SexPartnerHistoryRecord> element in partnerRecords) foreach (KeyValuePair<string, SexPartnerHistoryRecord> element in histories)
{ {
SexPartnerHistoryRecord h = element.Value; SexPartnerHistoryRecord h = element.Value;
@ -380,9 +386,9 @@ namespace RJWSexperience.SexHistory
mostPartnerCache = mostID; mostPartnerCache = mostID;
bestPartnerCache = bestID; bestPartnerCache = bestID;
recentSexTickAbsCache = partnerRecords.TryGetValue(recentPartner)?.RecentSexTickAbs ?? 0; recentSexTickAbsCache = histories.TryGetValue(recentPartner)?.RecentSexTickAbs ?? 0;
mostSexTickAbsCache = partnerRecords.TryGetValue(mostPartnerCache)?.RecentSexTickAbs ?? 0; mostSexTickAbsCache = histories.TryGetValue(mostPartnerCache)?.RecentSexTickAbs ?? 0;
bestSexTickAbsCache = partnerRecords.TryGetValue(bestPartnerCache)?.BestSexTickAbs ?? 0; bestSexTickAbsCache = histories.TryGetValue(bestPartnerCache)?.BestSexTickAbs ?? 0;
racetotalsat.Clear(); racetotalsat.Clear();
allpartners.Clear(); allpartners.Clear();
@ -408,6 +414,14 @@ namespace RJWSexperience.SexHistory
#endregion Cache update #endregion Cache update
protected bool VirginCheck()
{
if (histories.TryGetValue(first) != null)
return false;
return ParentPawn.IsVirgin();
}
public override IEnumerable<Gizmo> CompGetGizmosExtra() public override IEnumerable<Gizmo> CompGetGizmosExtra()
{ {
if (SexperienceMod.Settings.HideGizmoWhenDrafted && ParentPawn.Drafted) if (SexperienceMod.Settings.HideGizmoWhenDrafted && ParentPawn.Drafted)

View file

@ -104,13 +104,13 @@ namespace RJWSexperience.SexHistory
recentSexTickAbs = GenTicks.TicksAbs; recentSexTickAbs = GenTicks.TicksAbs;
} }
public void RecordOrgasm(xxx.rjwSextype sextype, float satisfaction) public void RecordSatisfaction(SexProps props, float satisfaction)
{ {
orgasms++; orgasms++;
if (satisfaction > bestSatisfaction) if (satisfaction > bestSatisfaction)
{ {
bestSextype = sextype; bestSextype = props.sexType;
bestSatisfaction = satisfaction; bestSatisfaction = satisfaction;
bestSexTickAbs = GenTicks.TicksAbs; bestSexTickAbs = GenTicks.TicksAbs;
} }

View file

@ -106,28 +106,28 @@ namespace RJWSexperience.SexHistory.UI
InfoCards.Add(new InfoCard( InfoCards.Add(new InfoCard(
pawn: Pawn, pawn: Pawn,
partnerRecord: _history.RecentPartnerRecord, partnerRecord: _history.GetRecentPartnersHistory,
label: Keyed.RS_Recent_Sex_Partner, label: Keyed.RS_Recent_Sex_Partner,
tooltipLabel: Keyed.RS_Recent_Sex_Partner_ToolTip, tooltipLabel: Keyed.RS_Recent_Sex_Partner_ToolTip,
lastSexTimeTicks: _history.RecentSexTickAbs)); lastSexTimeTicks: _history.RecentSexTickAbs));
InfoCards.Add(new InfoCard( InfoCards.Add(new InfoCard(
pawn: Pawn, pawn: Pawn,
partnerRecord: _history.FirstPartnerRecord, partnerRecord: _history.GetFirstPartnerHistory,
label: Keyed.RS_First_Sex_Partner, label: Keyed.RS_First_Sex_Partner,
tooltipLabel: Keyed.RS_First_Sex_Partner_ToolTip, tooltipLabel: Keyed.RS_First_Sex_Partner_ToolTip,
lastSexTimeTicks: _history.FirstSexTickAbs)); lastSexTimeTicks: _history.FirstSexTickAbs));
InfoCards.Add(new InfoCard( InfoCards.Add(new InfoCard(
pawn: Pawn, pawn: Pawn,
partnerRecord: _history.MostPartnerRecord, partnerRecord: _history.GetMostPartnerHistory,
label: Keyed.RS_Most_Sex_Partner, label: Keyed.RS_Most_Sex_Partner,
tooltipLabel: Keyed.RS_Most_Sex_Partner_ToolTip, tooltipLabel: Keyed.RS_Most_Sex_Partner_ToolTip,
lastSexTimeTicks: _history.MostSexTickAbs)); lastSexTimeTicks: _history.MostSexTickAbs));
InfoCards.Add(new InfoCard( InfoCards.Add(new InfoCard(
pawn: Pawn, pawn: Pawn,
partnerRecord: _history.BestSexPartnerRecord, partnerRecord: _history.GetBestSexPartnerHistory,
label: Keyed.RS_Best_Sex_Partner, label: Keyed.RS_Best_Sex_Partner,
tooltipLabel: Keyed.RS_Best_Sex_Partner_ToolTip, tooltipLabel: Keyed.RS_Best_Sex_Partner_ToolTip,
lastSexTimeTicks: _history.BestSexTickAbs)); lastSexTimeTicks: _history.BestSexTickAbs));

View file

@ -1,4 +1,5 @@
using RimWorld; using RimWorld;
using rjw;
using Verse; using Verse;
namespace RJWSexperience.Virginity namespace RJWSexperience.Virginity
@ -45,10 +46,6 @@ namespace RJWSexperience.Virginity
} }
} }
/// <summary>
/// Remove virginity trait and spawn blood filth if applicable
/// </summary>
/// <returns>Degree of the removed trait</returns>
public static int? RemoveVirginTrait(Pawn pawn) public static int? RemoveVirginTrait(Pawn pawn)
{ {
Trait virgin = pawn.story?.traits?.GetTrait(RsDefOf.Trait.Virgin); Trait virgin = pawn.story?.traits?.GetTrait(RsDefOf.Trait.Virgin);