/// <summary> Checks all of our potential partners to see if anyone's eligible, returning the most attractive and convenient one. </summary> protected static Pawn FindBestPartner(Pawn pawn, List <Pawn> targets, bool pawnCanPickAnyone, bool pawnIsNympho) { string pawnName = xxx.get_pawnname(pawn); Pawn best_fuckee = null; float best_fuckability_score = 0; foreach (Pawn targetPawn in targets) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): checking hookup {xxx.get_pawnname(targetPawn)}"); } // Check to see if the mod settings for hookups allow this pairing if (!pawnCanPickAnyone && !HookupAllowedViaSettings(pawn, targetPawn)) { continue; } // Check for homewrecking (banging a pawn who's in a relationship) if (!xxx.is_animal(targetPawn) && xxx.HasNonPolyPartnerOnCurrentMap(targetPawn)) { if (RJWHookupSettings.NymphosCanHomewreck && pawnIsNympho && xxx.is_frustrated(pawn)) { // Hookup allowed... rip colony mood } else if (RJWHookupSettings.NymphosCanHomewreckReverse && xxx.is_nympho(targetPawn) && xxx.is_frustrated(targetPawn)) { // Hookup allowed... rip colony mood } else { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): not hooking up with {xxx.get_pawnname(targetPawn)} to avoid homewrecking"); } continue; } } // If the pawn has had sex recently and isn't horny right now, skip them. if (!SexUtility.ReadyForLovin(targetPawn) && !xxx.is_horny(targetPawn)) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)} isn't ready for lovin'"); } continue; } if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)} is sufficiently single"); } if (!xxx.is_animal(targetPawn)) { float relations = pawn.relations.OpinionOf(targetPawn); if (relations < RJWHookupSettings.MinimumRelationshipToHookup) { if (!(relations > 0 && xxx.is_nympho(pawn))) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)}, i dont like them:({relations})"); } continue; } } relations = targetPawn.relations.OpinionOf(pawn); if (relations < RJWHookupSettings.MinimumRelationshipToHookup) { if (!(relations > 0 && xxx.is_nympho(targetPawn))) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)}, dont like me:({relations})"); } continue; } } float attraction = pawn.relations.SecondaryRomanceChanceFactor(targetPawn); if (attraction < RJWHookupSettings.MinimumAttractivenessToHookup) { if (!(attraction > 0 && xxx.is_nympho(pawn))) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)}, i dont find them attractive:({attraction})"); } continue; } } attraction = targetPawn.relations.SecondaryRomanceChanceFactor(pawn); if (attraction < RJWHookupSettings.MinimumAttractivenessToHookup) { if (!(attraction > 0 && xxx.is_nympho(targetPawn))) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)}, doesnt find me attractive:({attraction})"); } continue; } } } // Check to see if the two pawns are willing to bang, and if so remember how much attractive we find them float fuckability = 0f; if (pawn.CanReserveAndReach(targetPawn, PathEndMode.OnCell, Danger.Some, 1, 0) && targetPawn.CanReserve(pawn, 1, 0) && roll_to_skip(pawn, targetPawn, out fuckability)) // do NOT check pawnIgnoresRules here - these checks, particularly roll_to_skip, are critical { int dis = pawn.Position.DistanceToSquared(targetPawn.Position); if (dis <= 4) { // Right next to me (in my bed)? You'll do. if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)} is right next to me. we'll bang, ok?"); } best_fuckability_score = 1.0e6f; best_fuckee = targetPawn; } else if (dis > MaxDistanceSquaredToFuck) { // too far if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)} is too far... distance:{dis} max:{MaxDistanceSquaredToFuck}"); } continue; } else { // scaling fuckability by distance may give us more varied results and give the less attractive folks a chance float fuckability_score = fuckability / GenMath.Sqrt(GenMath.Sqrt(dis)); if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): hookup {xxx.get_pawnname(targetPawn)} is totally bangable. attraction: {fuckability}, score:{fuckability_score}"); } if (fuckability_score > best_fuckability_score) { best_fuckee = targetPawn; best_fuckability_score = fuckability_score; } } } } if (best_fuckee == null) { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): couldn't find anyone to bang"); } } else { if (RJWSettings.DebugLogJoinInBed) { Log.Message($"[RJW] FindBestPartner({pawnName}): found rando {xxx.get_pawnname(best_fuckee)} with score {best_fuckability_score}"); } } return(best_fuckee); }