2022-03-07 04:57:23 +00:00
using HarmonyLib ;
using RimWorld ;
2021-09-24 15:14:02 +00:00
using rjw ;
2022-02-26 08:03:42 +00:00
using rjw.Modules.Interactions.Enums ;
2022-04-27 10:56:16 +00:00
using RJWSexperience.Cum ;
2022-03-07 04:57:23 +00:00
using RJWSexperience.ExtensionMethods ;
2022-04-21 18:36:14 +00:00
using RJWSexperience.Logs ;
2022-04-30 14:35:32 +00:00
using System.Collections.Generic ;
2022-03-07 04:57:23 +00:00
using UnityEngine ;
2021-09-24 15:14:02 +00:00
using Verse ;
using Verse.AI ;
namespace RJWSexperience
{
2022-03-07 04:57:23 +00:00
[HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")]
public static class RJW_Patch_Orgasm
{
public static void Postfix ( JobDriver_Sex __instance )
{
if ( __instance . Sexprops . sexType ! = xxx . rjwSextype . Masturbation & & ! ( __instance is JobDriver_Masturbate ) )
{
2022-03-24 17:31:07 +00:00
if ( __instance . Sexprops . isRape & & __instance . Sexprops . isReceiver )
2022-03-07 04:57:23 +00:00
{
__instance . pawn ? . skills ? . Learn ( VariousDefOf . SexSkill , 0.05f , true ) ;
}
2022-03-24 17:31:07 +00:00
else
2022-03-07 04:57:23 +00:00
{
__instance . pawn ? . skills ? . Learn ( VariousDefOf . SexSkill , 0.35f , true ) ;
}
}
}
}
[HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMin")]
public static class RJW_Patch_WhoreAbilityAdjustmentMin
{
public static void Postfix ( Pawn whore , ref float __result )
{
__result * = whore . GetSexStat ( ) ;
}
}
[HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMax")]
public static class RJW_Patch_WhoreAbilityAdjustmentMax
{
public static void Postfix ( Pawn whore , ref float __result )
{
__result * = whore . GetSexStat ( ) ;
}
}
[HarmonyPatch(typeof(SexUtility), "SatisfyPersonal")]
public static class RJW_Patch_SatisfyPersonal
{
private const float base_sat_per_fuck = 0.4f ;
public static void Prefix ( SexProps props , ref float satisfaction )
{
satisfaction = Mathf . Max ( base_sat_per_fuck , satisfaction * props . partner . GetSexStat ( ) ) ;
}
public static void Postfix ( SexProps props , ref float satisfaction )
{
Pawn pawn = props . pawn ;
Pawn partner = props . partner ;
2022-04-30 14:35:32 +00:00
xxx . rjwSextype sextype = props . sexType ;
2022-03-07 04:57:23 +00:00
UpdateLust ( props , satisfaction ) ;
if ( props . sexType = = xxx . rjwSextype . Masturbation | | partner = = null )
{
Building_CumBucket cumbucket = pawn . GetAdjacentBuilding < Building_CumBucket > ( ) ;
2022-04-27 10:56:16 +00:00
cumbucket ? . AddCum ( CumUtility . GetCumVolume ( pawn ) ) ;
2022-03-07 04:57:23 +00:00
}
2022-04-30 14:35:32 +00:00
bool sexFillsCumbuckets =
// Base: Fill Cumbuckets on Masturbation. Having no partner means it must be masturbation too
sextype = = xxx . rjwSextype . Masturbation | | partner = = null
// Depending on configuration, also fill cumbuckets when certain sextypes are matched
| | ( SexperienceMod . Settings . SexCanFillBuckets & & ( sextype = = xxx . rjwSextype . Boobjob | | sextype = = xxx . rjwSextype . Footjob | | sextype = = xxx . rjwSextype . Handjob ) ) ;
if ( sexFillsCumbuckets )
{
IEnumerable < Building_CumBucket > buckets = pawn . GetAdjacentBuildings < Building_CumBucket > ( ) ;
if ( buckets ! = null & & buckets . EnumerableCount ( ) > 0 )
{
var initial_Cum = pawn . GetCumVolume ( ) ;
foreach ( Building_CumBucket b in buckets )
{
b . AddCum ( initial_Cum / buckets . EnumerableCount ( ) ) ;
}
}
}
2022-03-07 04:57:23 +00:00
RJWUtility . UpdateSatisfactionHIstory ( pawn , partner , props , satisfaction ) ;
pawn . records ? . Increment ( VariousDefOf . OrgasmCount ) ;
}
private static void UpdateLust ( SexProps props , float satisfaction )
{
float? lust = props . pawn . records ? . GetValue ( VariousDefOf . Lust ) ;
if ( lust = = null )
return ;
float lustDelta ;
2022-03-27 05:38:33 +00:00
if ( props . sexType ! = xxx . rjwSextype . Masturbation )
2022-03-07 04:57:23 +00:00
{
2022-03-27 05:38:33 +00:00
lustDelta = satisfaction - base_sat_per_fuck ;
if ( Mathf . Sign ( lustDelta ) = = Mathf . Sign ( ( float ) lust ) ) // Only if getting closer to the limit
lustDelta * = LustIncrementFactor ( ( float ) lust ) ;
2022-03-27 16:05:10 +00:00
lustDelta = Mathf . Clamp ( lustDelta , - SexperienceMod . Settings . MaxSingleLustChange , SexperienceMod . Settings . MaxSingleLustChange ) ; // If the sex is satisfactory, lust grows up. Declines at the opposite.
2022-03-07 04:57:23 +00:00
}
else
{
2022-03-27 16:05:10 +00:00
lustDelta = Mathf . Clamp ( satisfaction * satisfaction * LustIncrementFactor ( ( float ) lust ) , 0 , SexperienceMod . Settings . MaxSingleLustChange ) ; // Masturbation always increases lust.
2022-03-07 04:57:23 +00:00
}
2022-03-24 17:31:07 +00:00
if ( lustDelta = = 0 )
return ;
2022-04-21 18:36:14 +00:00
LogManager . GetLogger < DebugLogProvider > ( "RJW_Patch_SatisfyPersonal" ) . Message ( $"{props.pawn.NameShortColored}'s lust changed by {lustDelta} (from {lust})" ) ;
2022-03-07 04:57:23 +00:00
props . pawn . records . AddTo ( VariousDefOf . Lust , lustDelta ) ;
}
2022-03-26 18:11:59 +00:00
private static float LustIncrementFactor ( float lust )
{
2022-04-02 11:18:26 +00:00
return Mathf . Exp ( - Mathf . Pow ( lust / SexperienceMod . Settings . LustLimit , 2 ) ) ;
2022-03-26 18:11:59 +00:00
}
2022-03-07 04:57:23 +00:00
}
[HarmonyPatch(typeof(SexUtility), "TransferNutrition")]
public static class RJW_Patch_TransferNutrition
{
public static void Postfix ( SexProps props )
{
TryFeedCum ( props ) ;
}
private static void TryFeedCum ( SexProps props )
{
if ( ! Genital_Helper . has_penis_fertile ( props . pawn ) )
return ;
if ( ! PawnsPenisIsInPartnersMouth ( props ) )
return ;
2022-04-27 10:56:16 +00:00
CumUtility . FeedCum ( props . partner , CumUtility . GetCumVolume ( props . pawn ) ) ;
2022-03-07 04:57:23 +00:00
}
private static bool PawnsPenisIsInPartnersMouth ( SexProps props )
{
var interaction = rjw . Modules . Interactions . Helpers . InteractionHelper . GetWithExtension ( props . dictionaryKey ) ;
if ( props . pawn = = props . GetInteractionInitiator ( ) )
{
if ( ! interaction . DominantHasTag ( GenitalTag . CanPenetrate ) & & ! interaction . DominantHasFamily ( GenitalFamily . Penis ) )
return false ;
var requirement = interaction . SelectorExtension . submissiveRequirement ;
if ( ! requirement . mouth & & ! requirement . beak & & ! requirement . mouthORbeak )
return false ;
}
else
{
if ( ! interaction . SubmissiveHasTag ( GenitalTag . CanPenetrate ) & & ! interaction . SubmissiveHasFamily ( GenitalFamily . Penis ) )
return false ;
var requirement = interaction . SelectorExtension . dominantRequirement ;
if ( ! requirement . mouth & & ! requirement . beak & & ! requirement . mouthORbeak )
return false ;
}
return true ;
}
}
[HarmonyPatch(typeof(Nymph_Generator), "set_skills")]
public static class RJW_Patch_Nymph_set_skills
{
public static void Postfix ( Pawn pawn )
{
SkillRecord sexskill = pawn . skills . GetSkill ( VariousDefOf . SexSkill ) ;
if ( sexskill ! = null )
{
sexskill . passion = Passion . Major ;
sexskill . Level = ( int ) Utility . RandGaussianLike ( 7f , 20.99f ) ;
sexskill . xpSinceLastLevel = sexskill . XpRequiredForLevelUp * Rand . Range ( 0.10f , 0.90f ) ;
}
}
}
[HarmonyPatch(typeof(AfterSexUtility), "UpdateRecords")]
public static class RJW_Patch_UpdateRecords
{
public static void Postfix ( SexProps props )
{
RJWUtility . UpdateSextypeRecords ( props ) ;
RJWUtility . UpdatePartnerHistory ( props . pawn , props . partner , props ) ;
RJWUtility . UpdatePartnerHistory ( props . partner , props . pawn , props ) ;
}
}
[HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "Start")]
public static class RJW_Patch_LogSextype
{
public static void Postfix ( JobDriver_SexBaseInitiator __instance )
{
if ( __instance . Partner ! = null )
{
__instance . pawn . PoptheCherry ( __instance . Partner , __instance . Sexprops ) ;
__instance . Partner . PoptheCherry ( __instance . pawn , __instance . Sexprops ) ;
}
}
}
[HarmonyPatch(typeof(WorkGiver_CleanSelf), "JobOnThing")]
public static class RJW_Patch_CleanSelf_JobOnThing
{
public static bool Prefix ( Pawn pawn , Thing t , bool forced , ref Job __result )
{
Building_CumBucket bucket = pawn . GetAdjacentBuilding < Building_CumBucket > ( ) ;
if ( bucket = = null ) bucket = pawn . FindClosestBucket ( ) ;
if ( bucket ! = null )
{
__result = JobMaker . MakeJob ( VariousDefOf . CleanSelfwithBucket , null , bucket , bucket . Position ) ;
return false ;
}
return true ;
}
}
2022-03-24 17:31:07 +00:00
[HarmonyPatch(typeof(CasualSex_Helper), nameof(CasualSex_Helper.FindSexLocation))]
public static class RJW_Patch_CasualSex_Helper_FindSexLocation
2022-03-07 04:57:23 +00:00
{
2022-03-24 17:31:07 +00:00
/// <summary>
/// If masturbation and current map has a bucket, return location near the bucket
/// </summary>
/// <param name="pawn"></param>
/// <param name="partner"></param>
/// <param name="__result"></param>
/// <returns></returns>
public static bool Prefix ( Pawn pawn , Pawn partner , ref IntVec3 __result )
2022-03-07 04:57:23 +00:00
{
2022-03-24 17:31:07 +00:00
if ( partner ! = null )
return true ; // Not masturbation
2022-04-21 18:36:14 +00:00
var log = LogManager . GetLogger < DebugLogProvider > ( "RJW_Patch_CasualSex_Helper_FindSexLocation" ) ;
log . Message ( $"Called for {pawn.NameShortColored}" ) ;
2022-03-24 17:31:07 +00:00
2022-04-27 05:37:40 +00:00
if ( pawn . Faction ? . IsPlayer ! = true & & ! pawn . IsPrisonerOfColony )
2022-03-07 04:57:23 +00:00
{
2022-04-27 05:37:40 +00:00
log . Message ( "Not a player's faction or a prisoner" ) ;
2022-03-24 17:31:07 +00:00
return true ;
}
Building_CumBucket bucket = pawn . FindClosestBucket ( ) ;
if ( bucket = = null )
{
2022-04-21 18:36:14 +00:00
log . Message ( "Bucket not found" ) ;
2022-03-24 17:31:07 +00:00
return true ;
2022-03-07 04:57:23 +00:00
}
2022-03-24 17:31:07 +00:00
__result = bucket . RandomAdjacentCell8Way ( ) ;
2022-04-21 18:36:14 +00:00
log . Message ( $"Bucket location: {__result}" ) ;
2022-03-24 17:31:07 +00:00
return false ;
2022-03-07 04:57:23 +00:00
}
}
2021-09-24 15:14:02 +00:00
}