2022-07-26 03:55:56 +00:00
using HarmonyLib ;
2023-06-28 15:02:42 +00:00
using Mono.Cecil.Cil ;
2022-07-26 03:55:56 +00:00
using RimWorld ;
using rjw ;
using RJWSexperience.Ideology.HistoryEvents ;
using RJWSexperience.Ideology.Precepts ;
using System.Collections.Generic ;
2022-11-20 13:47:55 +00:00
using System.Linq ;
2022-11-24 18:10:03 +00:00
using System.Reflection ;
using System.Reflection.Emit ;
2023-06-25 13:54:32 +00:00
using System.Text ;
2022-07-26 03:55:56 +00:00
using Verse ;
namespace RJWSexperience.Ideology.Patches
{
[HarmonyPatch(typeof(MarriageCeremonyUtility), nameof(MarriageCeremonyUtility.Married))]
public static class Rimworld_Patch_Marriage
{
public static void Postfix ( Pawn firstPawn , Pawn secondPawn )
{
2023-04-23 11:41:27 +00:00
RsiDefOf . HistoryEvent . RSI_NonIncestuosMarriage . RecordEventWithPartner ( firstPawn , secondPawn ) ;
RsiDefOf . HistoryEvent . RSI_NonIncestuosMarriage . RecordEventWithPartner ( secondPawn , firstPawn ) ;
2022-07-26 03:55:56 +00:00
}
}
[HarmonyPatch(typeof(RitualOutcomeEffectWorker_FromQuality), "GiveMemoryToPawn")]
public static class Rimworld_Patch_RitualOutcome_DontGiveMemoryToAnimals
{
public static bool Prefix ( Pawn pawn )
{
return ! pawn . IsAnimal ( ) ;
}
}
[HarmonyPatch(typeof(IdeoFoundation), nameof(IdeoFoundation.CanAdd))]
public static class Rimworld_Patch_IdeoFoundation
{
public static void Postfix ( PreceptDef precept , ref IdeoFoundation __instance , ref AcceptanceReport __result )
{
DefExtension_MultipleMemesRequired extension = precept . GetModExtension < DefExtension_MultipleMemesRequired > ( ) ;
if ( extension = = null )
return ;
if ( extension . requiredAllMemes . NullOrEmpty ( ) )
return ;
for ( int i = 0 ; i < extension . requiredAllMemes . Count ; i + + )
{
if ( ! __instance . ideo . memes . Contains ( extension . requiredAllMemes [ i ] ) )
{
List < string > report = new List < string > ( ) ;
foreach ( MemeDef meme in extension . requiredAllMemes ) report . Add ( meme . LabelCap ) ;
__result = new AcceptanceReport ( "RequiresMeme" . Translate ( ) + ": " + report . ToCommaList ( ) ) ;
return ;
}
}
}
}
2022-11-20 13:47:55 +00:00
2022-11-24 18:10:03 +00:00
[HarmonyPatch(typeof(RelationsUtility), "Incestuous")]
2022-11-20 13:47:55 +00:00
public static class Rimworld_Patch_IncestuousManualRomance
{
2023-06-25 13:54:32 +00:00
public static bool Prepare ( ) = > RsiMod . Prefs . patchIncestuousManualRomance ;
2022-11-20 13:47:55 +00:00
/// <summary>
/// Override incestuous check in the manual romance
/// </summary>
/// <param name="one">Pawn to try do romance</param>
/// <param name="two">Target for romance</param>
/// <param name="__result">Result of the original method</param>
/// <returns>Run original method implementation</returns>
public static bool Prefix ( Pawn one , Pawn two , ref bool __result )
{
__result = RsiIncestuous ( one , two ) ;
return false ;
}
/// <summary>
/// Check if Ideology allows romance attempt
/// </summary>
/// <param name="one">Pawn to try do romance</param>
/// <param name="two">Target for romance</param>
/// <returns>Forbid romance option</returns>
public static bool RsiIncestuous ( Pawn one , Pawn two )
{
2023-04-23 11:41:27 +00:00
PreceptDef incestuousPrecept = one . Ideo ? . PreceptsListForReading . Select ( precept = > precept . def ) . FirstOrFallback ( def = > def . issue = = RsiDefOf . Issue . Incestuos ) ;
2022-11-23 14:42:47 +00:00
var allowManualRomanceOnlyFor = incestuousPrecept ? . GetModExtension < DefExtension_Incest > ( ) ? . allowManualRomanceOnlyFor ;
2022-11-20 13:47:55 +00:00
BloodRelationDegree relationDegree = RelationHelpers . GetBloodRelationDegree ( one , two ) ;
2022-11-23 14:42:47 +00:00
if ( allowManualRomanceOnlyFor = = null )
2022-11-20 13:47:55 +00:00
{
return relationDegree < BloodRelationDegree . NotRelated ;
}
2022-11-23 14:42:47 +00:00
return ! allowManualRomanceOnlyFor . Contains ( relationDegree ) ;
2022-11-20 13:47:55 +00:00
}
}
2022-11-24 18:10:03 +00:00
[HarmonyPatch(typeof(Pawn_RelationsTracker), nameof(Pawn_RelationsTracker.SecondaryRomanceChanceFactor))]
public static class Rimworld_Patch_SecondaryRomanceChanceFactor
{
2023-06-25 13:54:32 +00:00
public static bool Prepare ( ) = > RsiMod . Prefs . patchRomanceChanceFactor ;
2022-11-24 18:10:03 +00:00
/// <summary>
/// <para>
/// Replace
/// float num = 1f;
/// foreach (PawnRelationDef pawnRelationDef in this.pawn.GetRelations(otherPawn))
/// {
/// num *= pawnRelationDef.romanceChanceFactor;
/// }
/// </para>
/// <para>with</para>
/// <para>
/// float num = 1f;
/// num = RomanceChanceFactorHelpers.GetRomanceChanceFactor(this.pawn, otherPawn)
/// </para>
/// </summary>
/// <param name="instructions">Original method body</param>
/// <returns>Modified method body</returns>
public static IEnumerable < CodeInstruction > Transpiler ( IEnumerable < CodeInstruction > instructions )
{
MethodInfo getRelationsInfo = AccessTools . Method (
typeof ( PawnRelationUtility ) ,
nameof ( PawnRelationUtility . GetRelations ) ,
new [ ] { typeof ( Pawn ) , typeof ( Pawn ) } ) ;
MethodInfo helperInfo = AccessTools . Method (
typeof ( RomanceChanceFactorHelpers ) ,
nameof ( RomanceChanceFactorHelpers . GetRomanceChanceFactor ) ,
new [ ] { typeof ( Pawn ) , typeof ( Pawn ) } ) ;
// Original IL looks something like this:
// Load this.pawn
// Load otherPawn
// Call GetRelations
// Start loop
// ...
// Mul num and romanceChanceFactor
// Store result
// ...
// Endfinaly
// Idea is to substitute GetRelations call with a method with the same signature,
// store results in the same place original loop does and remove everything else until Endfinaly
2023-06-25 13:54:32 +00:00
IEnumerator < CodeInstruction > enumerator = instructions . GetEnumerator ( ) ;
2023-06-28 15:02:42 +00:00
bool endOfInstructions = ! enumerator . MoveNext ( ) ;
2023-06-25 13:54:32 +00:00
// Find and replace GetRelations
while ( ! endOfInstructions )
2022-11-24 18:10:03 +00:00
{
2023-06-25 13:54:32 +00:00
var instruction = enumerator . Current ;
if ( instruction . Calls ( getRelationsInfo ) )
2022-11-24 18:10:03 +00:00
{
2023-06-25 13:54:32 +00:00
yield return new CodeInstruction ( OpCodes . Call , helperInfo ) ;
enumerator . MoveNext ( ) ; // skip original method call
break ;
2022-11-24 18:10:03 +00:00
}
2023-06-25 13:54:32 +00:00
yield return instruction ;
2023-06-28 15:02:42 +00:00
endOfInstructions = ! enumerator . MoveNext ( ) ;
2023-06-25 13:54:32 +00:00
}
if ( endOfInstructions )
{
Log . Error ( "[RSI] Failed to transpile Pawn_RelationsTracker.SecondaryRomanceChanceFactor: PawnRelationUtility.GetRelations call not found" ) ;
yield break ;
}
// Skip everything until Mul
while ( ! endOfInstructions )
{
if ( enumerator . Current . opcode = = OpCodes . Mul )
2022-11-24 18:10:03 +00:00
{
2023-06-25 13:54:32 +00:00
enumerator . MoveNext ( ) ; // skip Mul
yield return enumerator . Current ; // return next op, it should be "store result"
break ;
}
2023-06-28 15:02:42 +00:00
endOfInstructions = ! enumerator . MoveNext ( ) ;
2023-06-25 13:54:32 +00:00
}
if ( endOfInstructions )
{
Log . Error ( "[RSI] Failed to transpile Pawn_RelationsTracker.SecondaryRomanceChanceFactor: Mul not found. This error means half of SecondaryRomanceChanceFactor was erased. Very not good" ) ;
yield break ;
}
2022-11-24 18:10:03 +00:00
2023-06-25 13:54:32 +00:00
// Skip the rest of the loop
while ( ! endOfInstructions )
{
if ( enumerator . Current . opcode = = OpCodes . Endfinally )
{
// Endfinally will be skipped by the next MoveNext()
break ;
2022-11-24 18:10:03 +00:00
}
2023-06-28 15:02:42 +00:00
endOfInstructions = ! enumerator . MoveNext ( ) ;
2023-06-25 13:54:32 +00:00
}
if ( endOfInstructions )
{
Log . Error ( "[RSI] Failed to transpile Pawn_RelationsTracker.SecondaryRomanceChanceFactor: Endfinally not found. This error means half of SecondaryRomanceChanceFactor was erased. Very not good" ) ;
yield break ;
}
// Return the rest of the method
while ( enumerator . MoveNext ( ) )
{
yield return enumerator . Current ;
}
2023-06-28 15:02:42 +00:00
if ( Prefs . DevMode ) Log . Message ( "[RSI] Successfully transpiled Pawn_RelationsTracker.SecondaryRomanceChanceFactor" ) ;
2023-06-25 13:54:32 +00:00
}
[HarmonyPatch(typeof(Precept), nameof(Precept.GetTip))]
public static class Rimworld_Patch_PreceptTip
{
public static void Postfix ( ref string __result , Precept __instance )
{
if ( __instance . def . modExtensions . NullOrEmpty ( ) )
2022-11-24 18:10:03 +00:00
{
2023-06-25 13:54:32 +00:00
return ;
2022-11-24 18:10:03 +00:00
}
2023-06-25 13:54:32 +00:00
bool tipChanged = false ;
StringBuilder tipBuilder = new StringBuilder ( __result ) ;
tipBuilder . AppendLine ( ) ;
tipBuilder . AppendInNewLine ( ( Keyed . ModTitle + ":" ) . Colorize ( ColoredText . TipSectionTitleColor ) ) ;
for ( int i = 0 ; i < __instance . def . modExtensions . Count ; i + + )
{
if ( __instance . def . modExtensions [ i ] is IPreceptTipPostfix tipPostfix )
{
tipBuilder . AppendInNewLine ( " - " + tipPostfix . GetTip ( ) ) ;
tipChanged = true ;
}
}
if ( tipChanged )
{
__result = tipBuilder . ToString ( ) ;
}
2022-11-24 18:10:03 +00:00
}
}
}
2022-07-26 03:55:56 +00:00
}