public override float RandomSelectionWeight(Pawn initiator, Pawn recipient) { if (!initiator.IsColonist || !recipient.IsColonist) { return(0f); } if (!PartyUtility.AcceptableGameConditionsToStartParty(initiator.Map)) { return(0f); } PsychologyPawn realRecipient = recipient as PsychologyPawn; PsychologyPawn realInitiator = initiator as PsychologyPawn; if (realRecipient == null || realInitiator == null) { return(0f); } if (!LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } if (realInitiator.psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7 || realRecipient.psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7) { return(0f); } if (initiator.health.summaryHealth.SummaryHealthPercent < 1f || recipient.health.summaryHealth.SummaryHealthPercent < 1f) { return(0f); } return(1.2f * realInitiator.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - realInitiator.psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) * realRecipient.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - realRecipient.psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) * RendezvousUtility.ColonySizeFactor(initiator)); }
protected override ThoughtState CurrentSocialStateInternal(Pawn p, Pawn otherPawn) { if (!RelationsUtility.PawnsKnowEachOther(p, otherPawn)) { return(false); } if (!LovePartnerRelationUtility.LovePartnerRelationExists(p, otherPawn)) { return(false); } if (!PsycheHelper.PsychologyEnabled(p)) { return(false); } if (p.Map == otherPawn.Map) { PsycheHelper.Comp(p).LDRTick = Find.TickManager.TicksAbs; return(false); } int tickSinceLastSeen = PsycheHelper.Comp(p).LDRTick; int ticksApart = Find.TickManager.TicksAbs - tickSinceLastSeen; int quadrumsApart = Mathf.FloorToInt((float)ticksApart / (float)GenDate.TicksPerQuadrum); int maxApart = (p.relations.GetDirectRelation(PawnRelationDefOf.Spouse, otherPawn) == null ? 7 : 6); if (quadrumsApart > maxApart) { quadrumsApart = maxApart; } if (quadrumsApart > 1) { return(ThoughtState.ActiveAtStage(quadrumsApart - 1)); } return(false); }
public static bool NewSelectionWeight(InteractionWorker_Breakup __instance, ref float __result, Pawn initiator, Pawn recipient) { /* Also this one. */ if (!LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { __result = 0f; return(false); } else if (initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { __result = 0f; return(false); } float chance = 0.02f; float romanticFactor = 1f; PsychologyPawn realInitiator = initiator as PsychologyPawn; if (realInitiator != null) { chance = 0.05f; romanticFactor = Mathf.InverseLerp(1.05f, 0f, realInitiator.psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic)); } float opinionFactor = Mathf.InverseLerp(100f, -100f, (float)initiator.relations.OpinionOf(recipient)); float spouseFactor = 1f; if (initiator.relations.DirectRelationExists(PawnRelationDefOf.Spouse, recipient)) { spouseFactor = 0.4f; } __result = chance * romanticFactor * opinionFactor * spouseFactor; return(false); }
public override void Tick() { base.Tick(); if (!LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.partner)) { this.pawn.health.RemoveHediff(this); } else if (Find.TickManager.TicksGame >= this.day && GenLocalDate.HourOfDay(this.pawn) == this.hour) { if (this.pawn.GetTimeAssignment() != TimeAssignmentDefOf.Work && this.partner.GetTimeAssignment() != TimeAssignmentDefOf.Work && !this.pawn.Drafted && !this.partner.Drafted && PartyUtility.AcceptableGameConditionsToStartParty(this.pawn.Map) && this.pawn.Map == this.partner.Map) { pawn.jobs.StopAll(); if (pawn.Awake() && partner.Awake()) { LordMaker.MakeNewLord(this.pawn.Faction, new LordJob_Date(this.pawn, this.partner), this.pawn.Map, new Pawn[] { this.pawn, this.partner }); } else if (pawn.Awake()) { this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MissedDate, this.partner); } else { this.partner.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MissedDate, this.pawn); } } else { this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.DateCancelled); this.partner.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.DateCancelled); } this.pawn.health.RemoveHediff(this); } }
public static void Postfix(ref float __result, Pawn initiator, Pawn recipient) { // one in mental break OR is already lover of the initiator can't be targeted if (recipient.InMentalState || LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { __result = 0f; return; } // one can't perform romance atempt if recently rebuffed if (initiator.needs.mood.thoughts.memories.NumMemoriesOfDef(ThoughtDefOf.RebuffedMyRomanceAttempt) > 0) { __result = 0f; return; } // one can't target other people if current lover is good enough var initiator_partner = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (initiator_partner != null && initiator.relations.OpinionOf(initiator_partner) >= 25) { __result = 0f; return; } // one can't be targeted if current lover is good enough var recipient_partner = LovePartnerRelationUtility.ExistingMostLikedLovePartner(recipient, false); if (recipient_partner != null && recipient.relations.OpinionOf(recipient_partner) >= 25) { __result = 0f; } }
public override float RandomSelectionWeight(Pawn initiator, Pawn recipient) { if (!initiator.IsColonist || !recipient.IsColonist) { return(0f); } if (!RendezvousUtility.AcceptableGameConditionsToStartHangingOut(initiator.Map)) { return(0f); } if (!PsycheHelper.PsychologyEnabled(initiator) || !PsycheHelper.PsychologyEnabled(recipient)) { return(0f); } if (!LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } if (PsycheHelper.Comp(initiator).Psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7 || PsycheHelper.Comp(recipient).Psyche.lastDateTick >= Find.TickManager.TicksGame - GenDate.TicksPerDay * 7) { return(0f); } if (!GatheringsUtility.ShouldGuestKeepAttendingGathering(initiator) || !GatheringsUtility.ShouldGuestKeepAttendingGathering(recipient)) { return(0f); } return(1.2f * (1f + Mathf.InverseLerp(100f, 0f, initiator.needs.mood.thoughts.TotalOpinionOffset(recipient))) * PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) * PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic) * (1f - PsycheHelper.Comp(recipient).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Independent)) * RendezvousUtility.ColonySizeFactor(initiator)); }
internal static float _RandomSelectionWeight(this InteractionWorker_RomanceAttempt _this, Pawn initiator, Pawn recipient) { PsychologyPawn realInitiator = initiator as PsychologyPawn; //Lovers won't romance each other if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } //Codependents won't romance anyone if they are in a relationship if (LovePartnerRelationUtility.HasAnyLovePartner(initiator) && initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { return(0f); } //No one will romance someone they find less than 25% attractive float num = initiator.relations.SecondaryRomanceChanceFactor(recipient); if (num < 0.25f) { return(0f); } //No one will romance someone they have less than +5 opinion of int num2 = initiator.relations.OpinionOf(recipient); if (num2 < 5) { return(0f); } //Only lechers will romance someone that has less than +5 opinion of them if (recipient.relations.OpinionOf(initiator) < 5 && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) { return(0f); } //A pawn with +50 or more opinion of their lover will not hit on other pawns unless they are lecherous or polygamous (and their lover is also polygamous). float num3 = 1f; Pawn pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher) && (!initiator.story.traits.HasTrait(TraitDefOfPsychology.Polygamous) && !pawn.story.traits.HasTrait(TraitDefOfPsychology.Polygamous))) { float value = (float)initiator.relations.OpinionOf(pawn); num3 = Mathf.InverseLerp(50f, -50f, value); } //Straight women are 15% as likely to romance anyone. float num4 = (!initiator.story.traits.HasTrait(TraitDefOf.Gay)) ? ((initiator.gender != Gender.Female) ? 1f : 0.15f) : 1f; float num5 = Mathf.InverseLerp(0.25f, 1f, num); float num6 = Mathf.InverseLerp(5f, 100f, (float)num2); //People who have hit on someone in the past and been rejected because of their sexuality will rarely attempt to hit on them again. float num7 = (realInitiator != null && realInitiator.sexuality.IncompatibleSexualityKnown(recipient)) ? 0.05f : 1f; //Only lechers will try to romance someone in a stable relationship. float num8 = 1f; Pawn pawn2 = LovePartnerRelationUtility.ExistingMostLikedLovePartner(recipient, false); if (pawn2 != null && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) { int value = recipient.relations.OpinionOf(pawn2); num8 = Mathf.InverseLerp(5f, -100f, (float)value); } return(1.15f * num3 * num4 * num5 * num6 * num3 * num7 * num8); }
public static void CurrentStateInternal(ref ThoughtState __result, Pawn p) { DirectPawnRelation directPawnRelation = LovePartnerRelationUtility.ExistingMostLikedLovePartnerRel(p, false); bool multiplePartners = (from r in p.relations.PotentiallyRelatedPawns where LovePartnerRelationUtility.LovePartnerRelationExists(p, r) select r).Count() > 1; bool partnerBedInRoom = (from t in p.ownership.OwnedBed.GetRoom().ContainedBeds where t.AssignedPawns.Contains(directPawnRelation.otherPawn) select t).Count() > 0; if (directPawnRelation != null && p.ownership.OwnedBed != null && p.story.traits.HasTrait(TraitDefOfPsychology.Polygamous) && multiplePartners && partnerBedInRoom) { __result = false; } }
// Copied private static IEnumerable <Pawn> GetOwnersInternal(Room room) { // Extracted room types if (room.TouchesMapEdge || room.IsHuge || WrongRoomType(room)) { yield break; } Pawn pawn = null; Pawn secondOwner = null; foreach (Building_Bed containedBed in room.ContainedBeds) { if (containedBed.def.building.bed_humanlike) { foreach (var owner in containedBed.Owners()) { if (pawn == null) { pawn = owner; } else { if (secondOwner != null) { yield break; } secondOwner = owner; } } } } if (pawn != null) { if (secondOwner == null) { yield return(pawn); } else if (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, secondOwner)) { yield return(pawn); yield return(secondOwner); } } }
// Token: 0x06000C7E RID: 3198 RVA: 0x0003DCB8 File Offset: 0x0003BEB8 internal static float _RandomSelectionWeight(this InteractionWorker_RomanceAttempt _this, Pawn initiator, Pawn recipient) { if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } if (LovePartnerRelationUtility.HasAnyLovePartner(initiator) && initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { return(0f); } float num = initiator.relations.AttractionTo(recipient); int num2 = initiator.relations.OpinionOf(recipient); if (!initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) { if (num < 0.25f) { return(0f); } if (num2 < 5) { return(0f); } if (recipient.relations.OpinionOf(initiator) < 5) { return(0f); } } else { num = 0.25f; num2 = 5; } float num3 = 1f; Pawn pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null) { float value = (float)initiator.relations.OpinionOf(pawn); num3 = Mathf.InverseLerp(50f, -50f, value); } float num4 = (initiator.gender != Gender.Female) ? 1f : 0.125f; float num5 = Mathf.InverseLerp(0.25f, 1f, num); float num6 = Mathf.InverseLerp(5f, 100f, (float)num2); float num7 = (initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) ? 0.25f : 0f; return(1.15f * num4 * num5 * num6 * num3 + num7); }
// Token: 0x06000052 RID: 82 RVA: 0x00005688 File Offset: 0x00003888 public static Pawn GetCondomPartnerInMyBed(Pawn pawn, Building_Bed LovinBed) { if (LovinBed.SleepingSlotsCount <= 1) { return(null); } if (!LovePartnerRelationUtility.HasAnyLovePartner(pawn)) { return(null); } foreach (Pawn curOccupant in LovinBed.CurOccupants) { if (curOccupant != pawn && LovePartnerRelationUtility.LovePartnerRelationExists(pawn, curOccupant)) { return(curOccupant); } } return(null); }
internal static float _RandomSelectionWeight(this InteractionWorker_Breakup _this, Pawn initiator, Pawn recipient) { if (!LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } else if (initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { return(0f); } float num = Mathf.InverseLerp(100f, -100f, (float)initiator.relations.OpinionOf(recipient)); float num2 = 1f; if (initiator.relations.DirectRelationExists(PawnRelationDefOf.Spouse, recipient)) { num2 = 0.4f; } return(0.02f * num * num2); }
public static bool PawnIsInLoveBed(Pawn p) { Building_Bed Bed = p.CurrentBed(); if (Bed == null) { return(false); } for (int i = 0; i < Bed.OwnersForReading.Count; i++) { if (LovePartnerRelationUtility.LovePartnerRelationExists(p, Bed.OwnersForReading[i])) { return(true); } } return(false); }
public override void Tick() { base.Tick(); if (!LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.partner)) { this.pawn.health.RemoveHediff(this); } else if (Find.TickManager.TicksAbs >= this.day && GenLocalDate.HourOfDay(this.pawn) == this.hour) { if (ShouldStartDate(pawn, partner) && ShouldStartDate(partner, pawn)) { pawn.jobs.StopAll(); partner.jobs.StopAll(); if (pawn.GetLord() != null) { pawn.GetLord().Notify_PawnLost(pawn, PawnLostCondition.ForcedToJoinOtherLord); } if (partner.GetLord() != null) { partner.GetLord().Notify_PawnLost(partner, PawnLostCondition.ForcedToJoinOtherLord); } if (pawn.Awake() && partner.Awake()) { LordMaker.MakeNewLord(this.pawn.Faction, new LordJob_Date(this.pawn, this.partner), this.pawn.Map, new Pawn[] { this.pawn, this.partner }); } else if (pawn.Awake()) { this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MissedDate, this.partner); } else if (partner.Awake()) { this.partner.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.MissedDate, this.pawn); } } else { this.pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.DateCancelled); this.partner.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOfPsychology.DateCancelled); } this.pawn.health.RemoveHediff(this); } }
public override float RandomSelectionWeight(Pawn initiator, Pawn recipient) { if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } var num = initiator.relations.SecondaryRomanceChanceFactor(recipient); if (num < 0.25f) { return(0f); } var num2 = initiator.relations.OpinionOf(recipient); if (num2 < 5) { return(0f); } if (recipient.relations.OpinionOf(initiator) < 5) { return(0f); } var num3 = 1f; var pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null) { float value = initiator.relations.OpinionOf(pawn); num3 = Mathf.InverseLerp(50f, -50f, value); } var num5 = Mathf.InverseLerp(0.25f, 1f, num); var num6 = Mathf.InverseLerp(5f, 100f, num2); return(1.15f * num5 * num6 * num3); }
public override float RandomSelectionWeight(Pawn initiator, Pawn recipient) { if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } float num = initiator.relations.SecondaryRomanceChanceFactor(recipient); if (num < 0.25f) { return(0f); } int num2 = initiator.relations.OpinionOf(recipient); if (num2 < 5) { return(0f); } if (recipient.relations.OpinionOf(initiator) < 5) { return(0f); } float num3 = 1f; Pawn pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null) { float value = initiator.relations.OpinionOf(pawn); num3 = Mathf.InverseLerp(50f, -50f, value); } float num4 = (!initiator.story.traits.HasTrait(TraitDefOf.Gay)) ? ((initiator.gender != Gender.Female) ? 1f : 0.15f) : 1f; float num5 = Mathf.InverseLerp(0.25f, 1f, num); float num6 = Mathf.InverseLerp(5f, 100f, num2); float num7 = initiator.gender != recipient.gender || (initiator.story.traits.HasTrait(TraitDefOf.Gay) && recipient.story.traits.HasTrait(TraitDefOf.Gay)) ? 1f : 0.15f; return(1.15f * num4 * num5 * num6 * num3 * num7); }
private ThoughtDef CreateSocialThought(out float opinionMod) { //We create a dynamic def to hold this thought so that the game won't worry about it being used anywhere else. ThoughtDef def = new ThoughtDef(); def.defName = this.pawn.GetHashCode() + "Conversation" + topic.defName; def.label = topic.defName; def.durationDays = PsychologyBase.ConvoDuration(); def.nullifyingTraits = new List <TraitDef>(); def.nullifyingTraits.Add(TraitDefOf.Psychopath); def.thoughtClass = typeof(Thought_MemorySocialDynamic); ThoughtStage stage = new ThoughtStage(); /* Base opinion mod is 5 to the power of controversiality. * Controversiality varies from 0.7 (~3.09) to 1.5 (~11.18). */ opinionMod = Mathf.Pow(5f, topic.controversiality); /* That opinion mod is weighted by the difference in their personality. 1 is identical, 0 is polar opposites. * Here's the math on how this works: * * The weighting is on a heavily customized cubic curve. It looks like this: https://www.wolframalpha.com/input/?i=(9.5((x-0.5)%5E3))%2B(2x%2F3)%5E2-0.3+from+0+to+1 * The maximum positive weight is 1.27x. The maximum negative weight is -1.4875x. The neutral weight (0x) is at an opinion diff of 0.706. * This means that to have a positive thought from a conversation, pawns need to have a <31% difference in personality on that topic. * However, since it's a cubic curve, the negative modifier builds gradually. Pawns will need a >79% difference in personality to have a -0.5x weight. * But they'll also need a <23% difference to have a 0.5x weight. Normal agreement is at ~0.962, and normal disagreement is at ~0.073. * Pawns are unlikely to have huge differences in opinion. There are more ways for them to be close to each other than far apart. Here's the proof: https://anydice.com/program/1177b4 * The approximate likelihood for them to agree on something with this weighting is 49.89%. * * Pawns' differences are exacerbated when they are in a relationship, but their similarities are also magnified. * The neutral conversation weight (0x) moves from 0.706 to 0.759, so the threshold for agreement is ~5% higher. * Normal disagreement moves from 0.073 to 0.127, and normal agreement moves from 0.962 to 0.946. * The maximum positive weight moves from 1.27x to 1.4986x. The maximum negative weight moves from -1.425x to -1.9875x. * The approximate likelihood for them to agree on something with this weighting is 42.63%. */ float rawOpinionDiff = 1f - Mathf.Abs(PsycheHelper.Comp(pawn).Psyche.GetPersonalityRating(topic) - PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(topic)); if (LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.otherPawn)) { opinionMod *= (13.5f * (Mathf.Pow(rawOpinionDiff - 0.5f, 3))) + Mathf.Pow(((3f * rawOpinionDiff) / 9f), 2) - 0.3f; } else { opinionMod *= (9.5f * (Mathf.Pow(rawOpinionDiff - 0.5f, 3))) + Mathf.Pow(((2f * rawOpinionDiff) / 3f), 2) - 0.3f; } //Old cubic interpolation weighting. //opinionMod *= Mathf.Lerp((LovePartnerRelationUtility.LovePartnerRelationExists(pawn, otherPawn) ? -2f : -1.5f), (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, otherPawn) ? 1.5f : 1.25f), weightedOpinionDiff); /* The Cool modifier ranges from 3^(0.7) ~ 2.16 to 3^(1.5) ~ 5.2. * If a pawn is Cool, that modifier is a positive one added to all conversational thoughts. Otherwise, it's subtracted. * On average, Cool pawns will be liked better, and non-Cool pawns will be disliked more. */ opinionMod += Mathf.Pow(3f, topic.controversiality) * (PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Cool) - 0.5f); /* The length of the talk has a large impact on how much the pawn cares. * A conversation is considered "full impact" at 1,125 ticks, or less than half an hour in-game. * A short talk (500 ticks or less) has a maximum 0.53x impact. The max opinion this could give (for non-lovers) is 7.5/-8.8. * A normal talk (half an hour or less) has a maximum 1.33x impact. The max opinion this could give is 18.9/-22.1. * A long talk (2.5 hours or less) has a maximum 6.67x impact. The max opinion this could give is 94.7/-110.9. * An epic talk (2.5+ hours) has no maximum impact, but after 2 hours the MTB to end the conversation becomes half an hour, so it's unlikely they will ever have an epic talk. * An average conversation is 1-2 hours, so on average the max opinion (not counting Cool modifier) is 37.9/-44.3 to 75.7/-88.7. * Again, it's unlikely the numbers will get that high. This is assuming identical or polar opposite personalities. */ opinionMod *= 6f * ((float)this.ageTicks / (float)(GenDate.TicksPerHour * 2.25f)); // Negative opinions are tempered by how Polite the other pawn is. An extremely impolite pawn will make a bad opinion 1.5x worse. A very polite pawn will make it half as bad. opinionMod *= (opinionMod < 0f ? 0.5f + (1f - PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Polite)) : 1f); // Positive opinions are bolstered by how Friendly the other pawn is. An extremely friendly pawn will make a positive opinion 1.5x better. A very unfriendly pawn will halve it. opinionMod *= (opinionMod > 0f ? 0.5f + PsycheHelper.Comp(otherPawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Friendly) : 1f); // The more Judgmental the pawn, the more they're affected by all conversations. opinionMod *= 0.5f + PsycheHelper.Comp(pawn).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Judgmental); // In low-population colonies, pawns will put aside their differences. if (opinionMod < 0f) { opinionMod *= PopulationModifier; } else if (LovePartnerRelationUtility.LovePartnerRelationExists(this.pawn, this.otherPawn) && this.pawn.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { //If it's a positive thought about their lover, Codependent pawns are always 1.25x as affected by it. opinionMod *= 1.25f; } stage.label = "ConversationStage".Translate() + " " + convoTopic; stage.baseOpinionOffset = Mathf.RoundToInt(opinionMod); def.stages.Add(stage); return(def); }
// ReSharper disable once RedundantAssignment private static bool Prefix(Room __instance, ref IEnumerable <Pawn> __result) { __result = new List <Pawn>(); if (__instance.TouchesMapEdge) { return(false); } if (__instance.IsHuge) { return(false); } if (__instance.Role != RoomRoleDefOf.Bedroom && __instance.Role != RoomRoleDefOf.PrisonCell && __instance.Role != RoomRoleDefOf.Barracks && __instance.Role != RoomRoleDefOf.PrisonBarracks) { return(false); } foreach (var building_Bed in __instance.ContainedBeds) { if (!building_Bed.def.building.bed_humanlike) { continue; } if (building_Bed.OwnersForReading.Count == 0) { continue; } if (building_Bed.OwnersForReading.Count < 3) { return(true); } var returnValue = new HashSet <Pawn>(); for (var index = 0; index < building_Bed.OwnersForReading.Count; index++) { var pawn = building_Bed.OwnersForReading[index]; if (pawn == null) { continue; } if (index == building_Bed.OwnersForReading.Count - 1) { returnValue.Add(pawn); } var pawnHasLover = false; for (var otherIndex = 0; otherIndex < building_Bed.OwnersForReading.Count; otherIndex++) { if (otherIndex == index) { continue; } var otherPawn = building_Bed.OwnersForReading[otherIndex]; if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, otherPawn)) { continue; } pawnHasLover = true; break; } if (!pawnHasLover) { return(false); } returnValue.Add(pawn); } __result = returnValue; break; } return(false); }
public static void BreakupRelations(Pawn pawn) { var relations = pawn.relations.DirectRelations.Where(r => !r.otherPawn.Dead && r.otherPawn.Faction != null && r.otherPawn.Faction.IsPlayer && LovePartnerRelationUtility.LovePartnerRelationExists(pawn, r.otherPawn)).ToArray(); var breakup = new InteractionWorker_Breakup(); foreach (var relation in relations) { breakup.Interacted(relation.otherPawn, pawn, null); } Faction hostileFaction; if ( Find.FactionManager.AllFactions.Where(f => f.def.humanlikeFaction && f.HostileTo(Faction.OfPlayer)) .TryRandomElement(out hostileFaction)) { pawn.SetFaction(hostileFaction); } }
public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false) { //Log.Message("[RJW]" + this.GetType().ToString() + " base checks: pass"); Pawn target = t as Pawn; if (target == pawn) { //JobFailReason.Is("no self sex", null); return(false); } if (!WorkGiverChecks(pawn, t, forced)) { return(false); } if (!xxx.is_human(target)) { return(false); } if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0)) { return(false); } if (!pawn.IsDesignatedHero()) { if (!RJWSettings.WildMode) { //check initiator //fail for: //satisfied non nymph pawns if (xxx.need_some_sex(pawn) <= 1f && !xxx.is_nympho(pawn)) { if (RJWSettings.DevMode) { JobFailReason.Is("not horny enough"); } return(false); } if (!xxx.IsTargetPawnOkay(target)) { if (RJWSettings.DevMode) { JobFailReason.Is("target not healthy enough"); } return(false); } if (!xxx.is_lecher(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_nympho(pawn)) { if (!xxx.isSingleOrPartnerNotHere(pawn)) { if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target)) { if (RJWSettings.DevMode) { JobFailReason.Is("cannot have sex while partner around"); } return(false); } } } float relations = 0; float attraction = 0; if (!xxx.is_animal(target)) { relations = pawn.relations.OpinionOf(target); if (relations < RJWHookupSettings.MinimumRelationshipToHookup) { if (!(relations > 0 && xxx.is_nympho(pawn))) { if (RJWSettings.DevMode) { JobFailReason.Is($"i dont like them:({relations})"); } return(false); } } attraction = pawn.relations.SecondaryRomanceChanceFactor(target); if (attraction < RJWHookupSettings.MinimumAttractivenessToHookup) { if (!(attraction > 0 && xxx.is_nympho(pawn))) { if (RJWSettings.DevMode) { JobFailReason.Is($"i dont find them attractive:({attraction})"); } return(false); } } } //Log.Message("[RJW]WorkGiver_Sex::" + xxx.would_fuck(pawn, target)); if (xxx.would_fuck(pawn, target) < 0.1f) { return(false); } if (!xxx.is_animal(target)) { //check partner if (xxx.need_some_sex(target) <= 1f && !xxx.is_nympho(target)) { if (RJWSettings.DevMode) { JobFailReason.Is("partner not horny enough"); } return(false); } if (!xxx.is_lecher(target) && !xxx.is_psychopath(target) && !xxx.is_nympho(target)) { if (!xxx.isSingleOrPartnerNotHere(target)) { if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target)) { if (RJWSettings.DevMode) { JobFailReason.Is("partner cannot have sex while their partner around"); } return(false); } } } relations = target.relations.OpinionOf(pawn); if (relations <= RJWHookupSettings.MinimumRelationshipToHookup) { if (!(relations > 0 && xxx.is_nympho(target))) { if (RJWSettings.DevMode) { JobFailReason.Is($"dont like me:({relations})"); } return(false); } } attraction = target.relations.SecondaryRomanceChanceFactor(pawn); if (attraction <= RJWHookupSettings.MinimumAttractivenessToHookup) { if (!(attraction > 0 && xxx.is_nympho(target))) { if (RJWSettings.DevMode) { JobFailReason.Is($"doesnt find me attractive:({attraction})"); } return(false); } } } //Log.Message("[RJW]WorkGiver_Sex::" + xxx.would_fuck(target, pawn)); if (xxx.would_fuck(target, pawn) < 0.1f) { return(false); } } } //Log.Message("[RJW]" + this.GetType().ToString() + " extended checks: can start sex"); return(true); }
public static void PsychologyException(ref float __result, Pawn initiator, Pawn recipient) { //Don't hit on people in mental breaks... unless you're really freaky. if (recipient.InMentalState && PsycheHelper.PsychologyEnabled(initiator) && PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Experimental) < 0.8f) { __result = 0f; return; } //Pawns won't hit on their spouses. if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { __result = 0f; return; } //Codependents won't romance anyone if they are in a relationship if (LovePartnerRelationUtility.HasAnyLovePartner(initiator) && initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { __result = 0f; return; } //Only lechers will romance someone that has less than +5 opinion of them if (recipient.relations.OpinionOf(initiator) < 5 && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) { __result = 0f; return; } float attractiveness = initiator.relations.SecondaryRomanceChanceFactor(recipient); int opinion = initiator.relations.OpinionOf(recipient); float romanceChance = 1.15f; if (!PsycheHelper.PsychologyEnabled(initiator)) { //Vanilla: Straight women are 15% as likely to romance anyone. romanceChance = (!initiator.story.traits.HasTrait(TraitDefOf.Gay)) ? ((initiator.gender != Gender.Female) ? romanceChance : romanceChance * 0.15f) : romanceChance; } else { //Psychology: A pawn's likelihood to romance is based on how Aggressive and Romantic they are. float personalityFactor = Mathf.Pow(20f, PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Aggressive)) * Mathf.Pow(12f, (1f - PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic))); romanceChance = personalityFactor * 0.02f; } //A pawn with +50 or more opinion of their lover will not hit on other pawns unless they are lecherous or polygamous (and their lover is also polygamous). float existingLovePartnerFactor = 1f; Pawn pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher) && (!initiator.story.traits.HasTrait(TraitDefOfPsychology.Polygamous) && !pawn.story.traits.HasTrait(TraitDefOfPsychology.Polygamous))) { float value = (float)initiator.relations.OpinionOf(pawn); existingLovePartnerFactor = Mathf.InverseLerp(50f, -50f, value); } float attractivenessFactor = Mathf.InverseLerp(0.25f, 1f, attractiveness); float opinionFactor = Mathf.InverseLerp(-5f, 100f, (float)opinion) * 2f; //People who have hit on someone in the past and been rejected because of their sexuality will rarely attempt to hit on them again. float knownSexualityFactor = (PsycheHelper.PsychologyEnabled(initiator) && PsychologyBase.ActivateKinsey() && PsycheHelper.Comp(initiator).Sexuality.IncompatibleSexualityKnown(recipient) && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) ? 0.05f : (PsycheHelper.PsychologyEnabled(initiator) ? (initiator.gender == recipient.gender ? (initiator.story.traits.HasTrait(TraitDefOf.Gay) && recipient.story.traits.HasTrait(TraitDefOf.Gay) ? 1f : 0.15f) : (!initiator.story.traits.HasTrait(TraitDefOf.Gay) && !recipient.story.traits.HasTrait(TraitDefOf.Gay) ? 1f : 0.15f)) : 1f); //Only lechers will try to romance someone in a stable relationship. float recipientLovePartnerFactor = 1f; Pawn pawn2 = LovePartnerRelationUtility.ExistingMostLikedLovePartner(recipient, false); if (pawn2 != null && !initiator.story.traits.HasTrait(TraitDefOfPsychology.Lecher)) { int value = recipient.relations.OpinionOf(pawn2); recipientLovePartnerFactor = Mathf.InverseLerp(5f, -100f, (float)value); } __result = romanceChance * existingLovePartnerFactor * attractivenessFactor * opinionFactor * knownSexualityFactor * recipientLovePartnerFactor; return; }
private static float RandomSelectionWeight_Method(Pawn initiator, Pawn recipient) { CompIndividuality compOther = recipient.TryGetComp <CompIndividuality>(); CompIndividuality comp = initiator.TryGetComp <CompIndividuality>(); if (LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } float attractiveness = initiator.relations.SecondaryRomanceChanceFactor(recipient); if (attractiveness < 0.15f) { return(0f); } int opinionOfOther = initiator.relations.OpinionOf(recipient); if (opinionOfOther < 5) { return(0f); } if (recipient.relations.OpinionOf(initiator) < 5) { return(0f); } float existingLovePartnerFactor = 1f; Pawn pawn = LovePartnerRelationUtility.ExistingMostLikedLovePartner(initiator, false); if (pawn != null) { float opinionOfSpouse = initiator.relations.OpinionOf(pawn); existingLovePartnerFactor = Mathf.InverseLerp(50f, -50f, opinionOfSpouse); } float romanceFactor; if (compOther != null) { romanceFactor = compOther.RomanceFactor * 2f; } else { romanceFactor = 1f; } float attractivenessFactor = Mathf.InverseLerp(0.15f, 1f, attractiveness); float opinionFactor = Mathf.InverseLerp(5f, 100f, opinionOfOther); float genderFactor = 1f; if (initiator.gender != recipient.gender && compOther != null && comp != null) { if (compOther.sexuality == CompIndividuality.Sexuality.Straight) { genderFactor = 1.0f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Bisexual) { genderFactor = 0.75f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Gay) { genderFactor = 0.1f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Asexual && comp.sexuality == CompIndividuality.Sexuality.Asexual) { genderFactor = 1.0f; } } if (initiator.gender == recipient.gender && compOther != null && comp != null) { if (compOther.sexuality == CompIndividuality.Sexuality.Gay) { genderFactor = 1.0f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Bisexual) { genderFactor = 0.75f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Straight) { genderFactor = 0.1f; } else if (compOther.sexuality == CompIndividuality.Sexuality.Asexual && comp.sexuality == CompIndividuality.Sexuality.Asexual) { genderFactor = 0.5f; } } return(1.15f * romanceFactor * attractivenessFactor * opinionFactor * existingLovePartnerFactor * genderFactor); }
private static bool BedClaimedByStranger(Building_Bed bed, Pawn guest) { return(bed.Owners().Any(p => p != guest && !p.RaceProps.Animal && !LovePartnerRelationUtility.LovePartnerRelationExists(p, guest))); }
public static Building_AIPawnRechargeStation FindRechargeStationFor(AIPawn sleeper, AIPawn traveler, bool sleeperWillBePrisoner, bool checkSocialProperness, bool forceCheckMedBed = false) { Predicate <Thing> bedValidator = (Thing t) => { Building_AIPawnRechargeStation foundRechargeStation = t as Building_AIPawnRechargeStation; if (foundRechargeStation == null) { return(false); } if (!traveler.CanReserveAndReach(t, PathEndMode.OnCell, Danger.Some, foundRechargeStation.SleepingSlotsCount)) { return(false); } if (!foundRechargeStation.AnyUnoccupiedSleepingSlot && (!sleeper.InBed() || sleeper.CurrentBed() != foundRechargeStation)) { foreach (Pawn owner in foundRechargeStation.owners) { if (owner as AIPawn != null) { return(false); } } } if (sleeperWillBePrisoner) { if (!foundRechargeStation.ForPrisoners) { return(false); } if (!foundRechargeStation.Position.IsInPrisonCell(sleeper.Map)) { return(false); } } else { if (foundRechargeStation.Faction != traveler.Faction) { return(false); } if (foundRechargeStation.ForPrisoners) { return(false); } } if (foundRechargeStation.Medical) { if (!HealthAIUtility.ShouldEverReceiveMedicalCare(sleeper)) { return(false); } if (!HealthAIUtility.ShouldSeekMedicalRest(sleeper)) { return(false); } if (!foundRechargeStation.AnyUnoccupiedSleepingSlot && (!sleeper.InBed() || sleeper.CurrentBed() != foundRechargeStation)) { return(false); } } else if (foundRechargeStation.owners.Any <Pawn>() && !foundRechargeStation.owners.Contains(sleeper)) { // The pawn in the recharge station is not an AIPawn. UnassignPawn! foreach (Pawn owner in foundRechargeStation.owners) { if (owner as AIPawn == null) { if (foundRechargeStation.owners.Find((Pawn x) => LovePartnerRelationUtility.LovePartnerRelationExists(sleeper, x)) == null) { foundRechargeStation.TryUnassignPawn(owner); break; } } } // Now recheck if there is a free place if (!foundRechargeStation.AnyUnownedSleepingSlot) { return(false); } } return((!checkSocialProperness || foundRechargeStation.IsSociallyProper(sleeper, sleeperWillBePrisoner, false)) && !foundRechargeStation.IsForbidden(traveler) && !foundRechargeStation.IsBurning()); }; if (sleeper.ownership != null && sleeper.ownership.OwnedBed != null && bedValidator(sleeper.ownership.OwnedBed)) { Building_AIPawnRechargeStation rStation = sleeper.ownership.OwnedBed as Building_AIPawnRechargeStation; if (rStation != null) { return(rStation); } else { sleeper.ownership.UnclaimBed(); } } DirectPawnRelation directPawnRelation = LovePartnerRelationUtility.ExistingMostLikedLovePartnerRel(sleeper, false); if (directPawnRelation != null) { Building_AIPawnRechargeStation ownedBed = directPawnRelation.otherPawn.ownership.OwnedBed as Building_AIPawnRechargeStation; if (ownedBed != null && bedValidator(ownedBed)) { return(ownedBed); } } for (int j = 0; j < RestUtility.AllBedDefBestToWorst.Count; j++) { ThingDef thingDef = RestUtility.AllBedDefBestToWorst[j]; if (RestUtility.CanUseBedEver(sleeper, thingDef)) { Predicate <Thing> validator = (Thing b) => bedValidator(b) && (b as Building_AIPawnRechargeStation != null) && !((Building_AIPawnRechargeStation)b).Medical; Building_AIPawnRechargeStation building_Bed2 = GenClosest.ClosestThingReachable(sleeper.Position, sleeper.Map, ThingRequest.ForDef(thingDef), PathEndMode.OnCell, TraverseParms.For(traveler, Danger.Deadly, TraverseMode.ByPawn, false), 9999f, validator, null, 0, -1, false) as Building_AIPawnRechargeStation; if (building_Bed2 != null) { if (sleeper.ownership != null) { sleeper.ownership.UnclaimBed(); } return(building_Bed2); } } } return(null); }
// Plundered and adapted from Psychology public override float RandomSelectionWeight(Pawn initiator, Pawn recipient) { if (!GRPawnRelationUtility.HasInformalRelationship(initiator, recipient) && !LovePartnerRelationUtility.LovePartnerRelationExists(initiator, recipient)) { return(0f); } else if (initiator.story.traits.HasTrait(TraitDefOfPsychology.Codependent)) { return(0f); } float chance = 0.02f * GradualRomanceMod.BaseBreakupChance; float romanticFactor = 1f; if (PsycheHelper.PsychologyEnabled(initiator)) { chance = 0.05f * GradualRomanceMod.BaseBreakupChance; romanticFactor = Mathf.InverseLerp(1.05f, 0f, PsycheHelper.Comp(initiator).Psyche.GetPersonalityRating(PersonalityNodeDefOf.Romantic)); } float opinionFactor = Mathf.InverseLerp(100f, -100f, (float)initiator.relations.OpinionOf(recipient)); float spouseFactor = 1f; if (initiator.relations.DirectRelationExists(PawnRelationDefOf.Spouse, recipient)) { spouseFactor = 0.4f; } return(chance * romanticFactor * opinionFactor * spouseFactor); }
protected override Job TryGiveJob(Pawn pawn) { LordToil_HangOut toil = pawn.GetLord().CurLordToil as LordToil_HangOut; Pawn friend = (pawn == toil.friends[0] ? toil.friends[1] : toil.friends[0]); if (friend == null) { return(null); } /* If they are partners, possibly send them to lay down together so they'll do lovin'. */ if (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, friend) && pawn.ownership.OwnedBed != null && !pawn.GetPosture().Laying() && (pawn.IsHashIntervalTick(GenDate.TicksPerHour) || friend.IsHashIntervalTick(GenDate.TicksPerHour))) { return(new Job(JobDefOf.LayDown, pawn.ownership.OwnedBed, GenDate.TicksPerHour)); } /* If they have no joy activity assigned, or they've been doing it for 1-3 hours, give them a new one. */ if (toil.hangOut == null || toil.ticksToNextJoy < Find.TickManager.TicksGame) { toil.hangOut = base.TryGiveJob(pawn); toil.ticksToNextJoy = Find.TickManager.TicksGame + Rand.RangeInclusive(GenDate.TicksPerHour, GenDate.TicksPerHour * 3); } /* If they need joy, go do the joy activity.*/ if (toil.hangOut != null && friend.needs.food.CurLevel > 0.33f && pawn.needs.joy.CurLevel < 0.8f) { /* Sometimes the joy activity can't be reserved because it's for one person only. */ Job job = new Job(toil.hangOut.def); job.targetA = toil.hangOut.targetA; job.targetB = toil.hangOut.targetB; job.targetC = toil.hangOut.targetC; job.targetQueueA = toil.hangOut.targetQueueA; job.targetQueueB = toil.hangOut.targetQueueB; job.count = toil.hangOut.count; job.countQueue = toil.hangOut.countQueue; job.expiryInterval = toil.hangOut.expiryInterval; job.locomotionUrgency = toil.hangOut.locomotionUrgency; if (job.TryMakePreToilReservations(pawn, false)) { return(job); } else { pawn.ClearAllReservations(false); } } if (((pawn.Position - friend.Position).LengthHorizontalSquared >= 54 || !GenSight.LineOfSight(pawn.Position, friend.Position, pawn.Map, true))) { /* Make sure they are close to each other if they're not actively doing a joy activity. */ /* If the other pawn is already walking over, just hang around until they get there. */ if (friend.CurJob.def != JobDefOf.Goto) { return(new Job(JobDefOf.Goto, friend)); } else { pawn.rotationTracker.FaceCell(friend.Position); return(null); } } else { /* If they are already standing close enough, but can't do the joy activity together, then wander around. */ IntVec3 result; /* Make sure they only wander within conversational distance. */ Predicate <IntVec3> validator = (IntVec3 x) => x.Standable(pawn.Map) && x.InAllowedArea(pawn) && !x.IsForbidden(pawn) && pawn.CanReserveAndReach(x, PathEndMode.OnCell, Danger.None, 1, -1, null, false) && (x - friend.Position).LengthHorizontalSquared < 50 && GenSight.LineOfSight(x, friend.Position, pawn.Map, true) && x != friend.Position; if (CellFinder.TryFindRandomReachableCellNear(pawn.Position, pawn.Map, 12f, TraverseParms.For(TraverseMode.NoPassClosedDoors, Danger.Deadly, false), (IntVec3 x) => validator(x), null, out result)) { if ((pawn.Position - friend.Position).LengthHorizontalSquared >= 5 || (LovePartnerRelationUtility.LovePartnerRelationExists(pawn, friend) && pawn.Position != friend.Position)) { /* Sending them to goto a friend ends with them standing right next to/on top of them. So make them respect personal space a little more. */ pawn.mindState.nextMoveOrderIsWait = !pawn.mindState.nextMoveOrderIsWait; if (!result.IsValid || pawn.mindState.nextMoveOrderIsWait) { /* Alternate between relaxing socially and wandering. */ pawn.rotationTracker.FaceCell(friend.Position); return(null); } } Job wander = new Job(JobDefOf.GotoWander, result); pawn.Map.pawnDestinationReservationManager.Reserve(pawn, wander, result); return(wander); } /* If we can't find a valid spot, just relax socially. */ pawn.rotationTracker.FaceCell(friend.Position); return(null); } }
public override bool MoreChecks(Pawn pawn, Thing t, bool forced = false) { if (!RJWSettings.rape_enabled) { return(false); } Pawn target = t as Pawn; if (!RJWSettings.WildMode) { if (xxx.is_kind(pawn)) { JobFailReason.Is("refuses to rape"); return(false); } //satisfied pawns //horny non rapists if ((xxx.need_some_sex(pawn) <= 1f) || (xxx.need_some_sex(pawn) <= 2f && !(xxx.is_rapist(pawn) || xxx.is_psychopath(pawn) || xxx.is_nympho(pawn)))) { JobFailReason.Is("not horny enough"); return(false); } if (!target.IsDesignatedComfort()) { //JobFailReason.Is("not designated as CP", null); return(false); } if (!xxx.is_healthy_enough(target) || !xxx.is_not_dying(target) && (xxx.is_bloodlust(pawn) || xxx.is_psychopath(pawn) || xxx.is_rapist(pawn) || xxx.has_quirk(pawn, "Somnophile"))) { //--Log.Message("[RJW]WorkGiver_RapeCP::HasJobOnThing called0 - target isn't healthy enough or is in a forbidden position."); JobFailReason.Is("target not healthy enough"); return(false); } if (pawn.relations.OpinionOf(target) > 50 && !xxx.is_rapist(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_masochist(target)) { JobFailReason.Is("refuses to rape a friend"); return(false); } if (!xxx.can_rape(pawn)) { //--Log.Message("[RJW]WorkGiver_RapeCP::HasJobOnThing called1 - pawn don't need sex or is not healthy, or cannot rape"); JobFailReason.Is("cannot rape target (vulnerability too low, or age mismatch)"); return(false); } if (!xxx.isSingleOrPartnerNotHere(pawn) && !xxx.is_lecher(pawn) && !xxx.is_psychopath(pawn) && !xxx.is_nympho(pawn)) { if (!LovePartnerRelationUtility.LovePartnerRelationExists(pawn, target)) { //--Log.Message("[RJW]WorkGiver_RapeCP::HasJobOnThing called2 - pawn is not single or has partner around"); JobFailReason.Is("cannot rape while in stable relationship"); return(false); } } } if (!pawn.CanReserve(target, xxx.max_rapists_per_prisoner, 0)) { return(false); } //Log.Message("[RJW]" + this.GetType().ToString() + " extended checks: can start sex"); return(true); }
protected override Job TryGiveJob(Pawn pawn) { //Log.Message("Try give job GotoForLovinAvali"); if (pawn.def != ThingDefOf.Avali) { //Log.Message("race = " + pawn.def.defName); return(null); } if (Find.TickManager.TicksGame < pawn.mindState.canLovinTick) { /* * string inventory = pawn.inventory.ToString(); * if (inventory.Contains("EggAvali")) * { * * } */ //Log.Message("TickManager.TicksGame < pawn.mindState.canLovinTick"); return(null); } Predicate <Thing> validator = delegate(Thing t) { Pawn pawn3 = t as Pawn; return(!pawn3.Downed && !pawn3.IsForbidden(pawn) && !pawn3.health.HasHediffsNeedingTend() && pawn3.InBed() && //pawn3.CanCasuallyInteractNow(false) && !pawn.health.HasHediffsNeedingTend() && !pawn.Drafted && //!pawn.InBed() && LovePartnerRelationUtility.LovePartnerRelationExists(pawn, pawn3) && Find.TickManager.TicksGame >= pawn3.mindState.canLovinTick && //pawn.relations.OpinionOf(pawn3) >= 25 && //pawn3.relations.OpinionOf(pawn) >= 25 && pawn3.RaceProps.Humanlike == pawn.RaceProps.Humanlike); }; Pawn pawn2 = (Pawn)GenClosest.ClosestThingReachable(pawn.Position, pawn.Map, ThingRequest.ForDef(pawn.def), PathEndMode.Touch, TraverseParms.For(pawn, Danger.Deadly, TraverseMode.ByPawn, false), 30f, validator, null, 0, -1, false, RegionType.Set_Passable, false); if (pawn2 == null) { //Log.Message("pawn2 = null"); return(null); } Building_Bed bed = RestUtility.FindBedFor(pawn2); //Log.Message(pawn + " bed = " + bed); if (bed != null) { //Log.Message(pawn + " current bed = " + pawn2.CurrentBed()); if (pawn2.CurrentBed() != bed) { return(null); } //Log.Message(pawn + " bed medical = " + bed.Medical); if (!bed.Medical) { //Log.Message("pawn2 = " + pawn2); return(new Job(JobDefOf.GotoForLovinAvali, pawn2, bed)); // give job } } return(null); }
public static bool SingleInvBedIsSpare(Pawn p, Pawn sleepyPawn) { return(p.RaceProps.Animal || p.ownership.OwnedBed != null || LovePartnerRelationUtility.LovePartnerRelationExists(sleepyPawn, p)); }
internal static float _ChanceOfBecomingChildOf(Pawn child, Pawn father, Pawn mother, PawnGenerationRequest?childGenerationRequest, PawnGenerationRequest?fatherGenerationRequest, PawnGenerationRequest?motherGenerationRequest) { var GetMelanin = typeof(ChildRelationUtility).GetMethod("GetMelanin", BindingFlags.Static | BindingFlags.NonPublic); var GetSkinColorFactor = typeof(ChildRelationUtility).GetMethod("GetSkinColorFactor", BindingFlags.Static | BindingFlags.NonPublic); var GetParentAgeFactor = typeof(ChildRelationUtility).GetMethod("GetParentAgeFactor", BindingFlags.Static | BindingFlags.NonPublic); var NumberOfChildrenFemaleWantsEver = typeof(ChildRelationUtility).GetMethod("NumberOfChildrenFemaleWantsEver", BindingFlags.Static | BindingFlags.NonPublic); if (GetMelanin == null) { Log.Error("Could not reflect ChildRelationUtility.GetMelanin!"); return(0f); } if (GetSkinColorFactor == null) { Log.Error("Could not reflect ChildRelationUtility.GetSkinColorFactor!"); return(0f); } if (GetParentAgeFactor == null) { Log.Error("Could not reflect ChildRelationUtility.GetParentAgeFactor!"); return(0f); } if (NumberOfChildrenFemaleWantsEver == null) { Log.Error("Could not reflect ChildRelationUtility.NumberOfChildrenFemaleWantsEver!"); return(0f); } if (father != null && father.gender != Gender.Male) { Log.Warning("Tried to calculate chance for father with gender \"" + father.gender + "\"."); return(0f); } if (mother != null && mother.gender != Gender.Female) { Log.Warning("Tried to calculate chance for mother with gender \"" + mother.gender + "\"."); return(0f); } if (father != null && child.GetFather() != null && child.GetFather() != father) { return(0f); } if (mother != null && child.GetMother() != null && child.GetMother() != mother) { return(0f); } if (mother != null && father != null && !LovePartnerRelationUtility.LovePartnerRelationExists(mother, father) && !LovePartnerRelationUtility.ExLovePartnerRelationExists(mother, father)) { return(0f); } float?melanin = (float?)GetMelanin.Invoke(typeof(ChildRelationUtility), new object[] { child, childGenerationRequest }); float?melanin2 = (float?)GetMelanin.Invoke(typeof(ChildRelationUtility), new object[] { father, fatherGenerationRequest }); float?melanin3 = (float?)GetMelanin.Invoke(typeof(ChildRelationUtility), new object[] { mother, motherGenerationRequest }); bool fatherIsNew = father != null && child.GetFather() != father; bool motherIsNew = mother != null && child.GetMother() != mother; float skinColorFactor = (float)GetSkinColorFactor.Invoke(typeof(ChildRelationUtility), new object[] { melanin, melanin2, melanin3, fatherIsNew, motherIsNew }); if (skinColorFactor <= 0f) { return(0f); } float num = 1f; float num2 = 1f; float num3 = 1f; float num4 = 1f; if (father != null && child.GetFather() == null) { PsychologyPawn realFather = father as PsychologyPawn; num = (float)GetParentAgeFactor.Invoke(typeof(ChildRelationUtility), new object[] { father, child, 14f, 30f, 50f }); if (num == 0f) { return(0f); } if (PsychologyBase.ActivateKinsey() && realFather != null) { num4 = Mathf.InverseLerp(6f, 0f, realFather.sexuality.kinseyRating); } else if (father.story.traits.HasTrait(TraitDefOf.Gay)) { num4 = 0.1f; } } if (mother != null && child.GetMother() == null) { PsychologyPawn realMother = mother as PsychologyPawn; num2 = (float)GetParentAgeFactor.Invoke(typeof(ChildRelationUtility), new object[] { mother, child, 16f, 27f, 45f }); if (num2 == 0f) { return(0f); } int num5 = (int)NumberOfChildrenFemaleWantsEver.Invoke(typeof(ChildRelationUtility), new object[] { mother }); if (mother.relations.ChildrenCount >= num5) { return(0f); } num3 = 1f - (float)mother.relations.ChildrenCount / (float)num5; if (PsychologyBase.ActivateKinsey() && realMother != null) { num4 = Mathf.InverseLerp(6f, 0f, realMother.sexuality.kinseyRating); } else if (mother.story.traits.HasTrait(TraitDefOf.Gay)) { num4 = 0.1f; } } float num6 = 1f; if (mother != null) { Pawn firstDirectRelationPawn = mother.relations.GetFirstDirectRelationPawn(PawnRelationDefOf.Spouse, null); if (firstDirectRelationPawn != null && firstDirectRelationPawn != father) { num6 *= 0.15f; } } if (father != null) { Pawn firstDirectRelationPawn2 = father.relations.GetFirstDirectRelationPawn(PawnRelationDefOf.Spouse, null); if (firstDirectRelationPawn2 != null && firstDirectRelationPawn2 != mother) { num6 *= 0.15f; } } return(skinColorFactor * num * num2 * num3 * num6 * num4); }