2022-07-26 03:55:56 +00:00
using HarmonyLib ;
using RimWorld ;
using rjw ;
using rjw.Modules.Interactions.Internals.Implementation ;
using rjw.Modules.Interactions.Objects ;
using RJWSexperience.Ideology.HistoryEvents ;
using RJWSexperience.Ideology.Precepts ;
using System ;
using System.Collections.Generic ;
2023-11-06 11:28:08 +00:00
using System.Reflection.Emit ;
2022-07-26 03:55:56 +00:00
using Verse ;
namespace RJWSexperience.Ideology.Patches
{
2023-11-06 11:28:08 +00:00
[HarmonyPatch(typeof(xxx), nameof(xxx.can_rape))]
public static class RJW_Patch_CannotRapeBecauseIdeo
{
/// <summary>
/// Injects IdeoCanRape call into is_human block of xxx.can_rape
/// </summary>
/// <param name="instructions">Original method instructions</param>
/// <returns>Modified method instructions</returns>
[HarmonyTranspiler]
public static IEnumerable < CodeInstruction > AddIdeoCheck ( IEnumerable < CodeInstruction > instructions , ILGenerator generator )
{
using IEnumerator < CodeInstruction > enumerator = instructions . GetEnumerator ( ) ;
System . Reflection . FieldInfo wildMode = AccessTools . Field ( typeof ( RJWSettings ) , nameof ( RJWSettings . WildMode ) ) ;
Label labelWildMode = generator . DefineLabel ( ) ;
bool done = false ;
while ( enumerator . MoveNext ( ) )
{
if ( ! done & & enumerator . Current . LoadsField ( wildMode ) )
{
// Found RJWSettings.WildMode check, insert before
// Need to move labels to our instruction because previous check jumps to one of them, skipping our call
var existingLabels = enumerator . Current . labels ;
enumerator . Current . labels = new List < Label > ( ) { labelWildMode } ;
// Load the first argument - Pawn
yield return new CodeInstruction ( OpCodes . Ldarg_0 ) { labels = existingLabels } ;
// Call the check. Consumes pawn and pushes bool
yield return CodeInstruction . Call ( typeof ( RJW_Patch_CannotRapeBecauseIdeo ) , nameof ( IdeoCanRape ) ) ; ;
// If bool is true, jump to the next check
yield return new CodeInstruction ( OpCodes . Brtrue_S , labelWildMode ) ;
// The bool was false, push false and exit the method
yield return new CodeInstruction ( OpCodes . Ldc_I4_0 ) ;
yield return new CodeInstruction ( OpCodes . Ret ) ;
done = true ;
}
yield return enumerator . Current ;
}
}
public static bool IdeoCanRape ( Pawn pawn ) = > RsiDefOf . HistoryEvent . RSI_Raped . CreateEvent ( pawn ) . DoerWillingToDo ( ) ;
}
2022-07-26 03:55:56 +00:00
[HarmonyPatch(typeof(xxx), nameof(xxx.is_rapist))]
public static class RJW_Patch_is_rapist
{
public static void Postfix ( Pawn pawn , ref bool __result )
{
Ideo ideo = pawn . Ideo ;
if ( ideo ! = null & & ! pawn . IsSubmissive ( ) )
{
2023-04-23 11:41:27 +00:00
__result = __result | | ideo . HasMeme ( RsiDefOf . Meme . Rapist ) ;
2022-07-26 03:55:56 +00:00
}
}
}
[HarmonyPatch(typeof(xxx), nameof(xxx.is_zoophile))]
public static class RJW_Patch_is_zoophile
{
public static void Postfix ( Pawn pawn , ref bool __result )
{
Ideo ideo = pawn . Ideo ;
if ( ideo ! = null )
{
2023-04-23 11:41:27 +00:00
__result = __result | | ideo . HasMeme ( RsiDefOf . Meme . Zoophile ) ;
2022-07-26 03:55:56 +00:00
}
}
}
[HarmonyPatch(typeof(xxx), nameof(xxx.is_necrophiliac))]
public static class RJW_Patch_is_necrophiliac
{
public static void Postfix ( Pawn pawn , ref bool __result )
{
Ideo ideo = pawn . Ideo ;
if ( ideo ! = null )
{
2023-04-23 11:41:27 +00:00
__result = __result | | ideo . HasMeme ( RsiDefOf . Meme . Necrophile ) ;
2022-07-26 03:55:56 +00:00
}
}
}
[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.Aftersex), new Type[] { typeof ( SexProps ) } ) ]
public static class RJW_Patch_SexUtility_Aftersex_RecordHistoryEvents
{
public static void Postfix ( SexProps props )
{
InteractionDefExtension_HistoryEvents interactionEvents = props . dictionaryKey . GetModExtension < InteractionDefExtension_HistoryEvents > ( ) ;
if ( props . hasPartner ( ) )
{
if ( xxx . is_human ( props . pawn ) )
AfterSexHuman ( props . pawn , props . partner ) ;
if ( xxx . is_human ( props . partner ) )
AfterSexHuman ( props . partner , props . pawn ) ;
if ( interactionEvents ! = null )
{
foreach ( HistoryEventDef eventDef in interactionEvents . pawnEvents )
eventDef . RecordEventWithPartner ( props . pawn , props . partner ) ;
foreach ( HistoryEventDef eventDef in interactionEvents . partnerEvents )
eventDef . RecordEventWithPartner ( props . partner , props . pawn ) ;
}
}
else
{
if ( interactionEvents ! = null )
{
foreach ( HistoryEventDef eventDef in interactionEvents . pawnEvents )
Find . HistoryEventsManager . RecordEvent ( eventDef . CreateEvent ( props . pawn ) ) ;
}
}
}
private static void AfterSexHuman ( Pawn human , Pawn partner )
{
2023-04-23 11:41:27 +00:00
RsiDefOf . HistoryEvent . RSI_NonIncestuosSex . RecordEventWithPartner ( human , partner ) ;
2022-07-26 03:55:56 +00:00
if ( partner . IsAnimal ( ) )
2023-04-23 11:41:27 +00:00
RsiDefOf . HistoryEvent . RSI_SexWithAnimal . RecordEventWithPartner ( human , partner ) ;
2022-07-26 03:55:56 +00:00
}
}
/// <summary>
/// Set prefer sextype using precepts
/// </summary>
[HarmonyPatch(typeof(InteractionScoringService), nameof(InteractionScoringService.Score), new Type[] { typeof ( InteractionWithExtension ) , typeof ( InteractionPawn ) , typeof ( InteractionPawn ) } ) ]
public static class RJW_Patch_DetermineSexScores
{
public static void Postfix ( InteractionWithExtension interaction , InteractionPawn dominant , InteractionPawn submissive , ref InteractionScore __result )
{
InteractionDefExtension_HistoryEvents interactionEvents = interaction . Interaction . GetModExtension < InteractionDefExtension_HistoryEvents > ( ) ;
if ( interactionEvents = = null )
return ;
if ( dominant . Pawn . Ideo ! = null )
__result . Dominant = PreceptSextype ( dominant . Pawn , submissive . Pawn , __result . Dominant , interactionEvents . pawnEvents ) ;
if ( submissive . Pawn . Ideo ! = null )
__result . Submissive = PreceptSextype ( submissive . Pawn , dominant . Pawn , __result . Submissive , interactionEvents . partnerEvents ) ;
}
public static float PreceptSextype ( Pawn pawn , Pawn partner , float score , List < HistoryEventDef > historyEventDefs )
{
2023-04-23 12:15:07 +00:00
for ( int i = 0 ; i < historyEventDefs . Count ; i + + )
2022-07-26 03:55:56 +00:00
{
2023-04-23 12:15:07 +00:00
HistoryEventDef eventDef = historyEventDefs [ i ] ;
2022-07-26 03:55:56 +00:00
if ( eventDef . CreateEventWithPartner ( pawn , partner ) . DoerWillingToDo ( ) )
{
2023-04-23 12:15:07 +00:00
float mult = 8.0f * Math . Max ( 0.3f , 1 / Math . Max ( 0.01f , pawn . GetStatValue ( xxx . sex_drive_stat , cacheStaleAfterTicks : 60 ) ) ) ;
2022-07-26 03:55:56 +00:00
return score * mult ;
}
}
return score ;
}
}
[HarmonyPatch(typeof(SexAppraiser), nameof(SexAppraiser.would_fuck), new Type[] { typeof ( Pawn ) , typeof ( Pawn ) , typeof ( bool ) , typeof ( bool ) , typeof ( bool ) } ) ]
public static class RJW_Patch_would_fuck
{
public static void Postfix ( Pawn fucker , Pawn fucked , ref float __result )
{
if ( ! xxx . is_human ( fucker ) )
return ;
Ideo ideo = fucker . Ideo ;
if ( ideo = = null )
return ;
for ( int i = 0 ; i < ideo . PreceptsListForReading . Count ; i + + )
ideo . PreceptsListForReading [ i ] . def . GetModExtension < DefExtension_ModifyPreference > ( ) ? . Apply ( fucker , fucked , ref __result ) ;
}
}
[HarmonyPatch(typeof(PawnDesignations_Breedee), nameof(PawnDesignations_Breedee.UpdateCanDesignateBreeding))]
public static class RJW_Patch_UpdateCanDesignateBreeding
{
public static void Postfix ( Pawn pawn , ref bool __result )
{
Ideo ideo = pawn . Ideo ;
2023-04-23 11:41:27 +00:00
if ( ideo ? . HasMeme ( RsiDefOf . Meme . Zoophile ) = = true )
2022-07-26 03:55:56 +00:00
{
SaveStorage . DataStore . GetPawnData ( pawn ) . CanDesignateBreeding = true ;
__result = true ;
}
}
}
2022-10-28 17:49:15 +00:00
[HarmonyPatch(typeof(PawnDesignations_Comfort))]
public static class RJW_Patch_PawnDesignations_Comfort_Submissive
2022-07-26 03:55:56 +00:00
{
2022-10-28 17:49:15 +00:00
[HarmonyPostfix, HarmonyPatch(nameof(PawnDesignations_Comfort.UpdateCanDesignateComfort))]
public static void UpdateCanDesignateComfort ( Pawn pawn , ref bool __result )
2022-07-26 03:55:56 +00:00
{
if ( pawn . IsSubmissive ( ) )
{
SaveStorage . DataStore . GetPawnData ( pawn ) . CanDesignateComfort = true ;
__result = true ;
}
}
2022-10-28 17:49:15 +00:00
/// <summary>
/// RJW undesignates if it thinks that the pawn can't be a comfort pawn.
/// Why the hell checker method changes the state?
/// </summary>
/// <param name="pawn">Pawn to check</param>
/// <param name="__result">Is pawn currenlty designated as comfort</param>
/// <returns>Run the original method</returns>
[HarmonyPrefix, HarmonyPatch(nameof(PawnDesignations_Comfort.IsDesignatedComfort))]
public static bool IsDesignatedComfort ( Pawn pawn , ref bool __result )
{
if ( pawn . IsSubmissive ( ) & & ! pawn . Dead )
{
__result = pawn . GetRJWPawnData ( ) . Comfort ;
return false ;
}
return true ;
}
2022-07-26 03:55:56 +00:00
}
[HarmonyPatch(typeof(Hediff_BasePregnancy), nameof(Hediff_BasePregnancy.PostBirth))]
public static class RJW_Patch_PostBirth
{
public static void Postfix ( Pawn mother , Pawn baby )
{
if ( ! mother . IsAnimal ( ) )
{
Faction faction = baby . GetFactionUsingPrecept ( out Ideo ideo ) ;
if ( baby . Faction ! = faction )
baby . SetFaction ( faction ) ;
baby . ideo ? . SetIdeo ( ideo ) ;
if ( baby . Faction = = Find . FactionManager . OfPlayer & & ! baby . IsSlave )
baby . guest ? . SetGuestStatus ( null , GuestStatus . Guest ) ;
}
}
private static Faction GetFactionUsingPrecept ( this Pawn baby , out Ideo ideo )
{
Faction playerfaction = Find . FactionManager . OfPlayer ;
Ideo mainideo = playerfaction . ideos . PrimaryIdeo ;
if ( mainideo ! = null )
{
2023-04-23 11:41:27 +00:00
if ( mainideo . HasPrecept ( RsiDefOf . Precept . BabyFaction_AlwaysFather ) )
2022-07-26 03:55:56 +00:00
{
Pawn parent = baby . GetFather ( ) ? ? baby . GetMother ( ) ;
ideo = parent . Ideo ;
return parent . Faction ;
}
2023-04-23 11:41:27 +00:00
else if ( mainideo . HasPrecept ( RsiDefOf . Precept . BabyFaction_AlwaysColony ) )
2022-07-26 03:55:56 +00:00
{
ideo = mainideo ;
return playerfaction ;
}
}
Pawn mother = baby . GetMother ( ) ;
ideo = mother ? . Ideo ;
return mother ? . Faction ? ? baby . Faction ;
}
2022-10-22 05:12:18 +00:00
}
2022-08-10 19:08:21 +00:00
2022-10-22 05:12:18 +00:00
[HarmonyPatch(typeof(SexUtility), nameof(SexUtility.SatisfyPersonal))]
public static class RJW_Patch_Orgasm_IdeoConversion
{
public static void Postfix ( SexProps props )
2022-08-10 19:08:21 +00:00
{
2022-10-22 05:12:18 +00:00
// ShortCuts: Exit Early if Pawn or Partner are null (can happen with Animals or Masturbation)
2022-11-06 14:16:15 +00:00
if ( props . pawn ? . Ideo = = null | | ! props . hasPartner ( ) )
2022-10-22 05:12:18 +00:00
return ;
2022-08-10 19:08:21 +00:00
2023-04-23 11:41:27 +00:00
if ( props . partner . Ideo ? . HasPrecept ( RsiDefOf . Precept . ProselyzingByOrgasm ) = = true )
2022-08-10 19:08:21 +00:00
{
2022-10-22 05:12:18 +00:00
// Pawn is the one having the orgasm
// Partner is "giving" the orgasm, hence the pawn will be converted towards the partners ideology
IdeoUtility . ConvertPawnBySex ( props . pawn , props . partner , 0.03f ) ;
2022-08-10 19:08:21 +00:00
}
}
2022-07-26 03:55:56 +00:00
}
}