diff --git a/1.4/Assemblies/RJWSexperience.Ideology.dll b/1.4/Assemblies/RJWSexperience.Ideology.dll index ab82b7a..88b1f5a 100644 Binary files a/1.4/Assemblies/RJWSexperience.Ideology.dll and b/1.4/Assemblies/RJWSexperience.Ideology.dll differ diff --git a/1.4/Defs/PreceptDefs/Precepts_Incest.xml b/1.4/Defs/PreceptDefs/Precepts_Incest.xml index df0e490..54c079a 100644 --- a/1.4/Defs/PreceptDefs/Precepts_Incest.xml +++ b/1.4/Defs/PreceptDefs/Precepts_Incest.xml @@ -27,16 +27,9 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • - + +
  • CloseRelative
  • +
    RSI_CloseRelativeMarriage @@ -44,24 +37,9 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • -
  • GreatGrandparent
  • -
  • GreatGrandchild
  • -
  • GranduncleOrGrandaunt
  • -
  • GrandnephewOrGrandniece
  • -
  • CousinOnceRemoved
  • -
  • SecondCousin
  • -
  • Cousin
  • -
  • Kin
  • - + +
  • FarRelative
  • +
    RSI_IncestuosMarriage @@ -90,16 +68,9 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • - + +
  • CloseRelative
  • +
    RSI_CloseRelativeSex @@ -107,24 +78,9 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • -
  • GreatGrandparent
  • -
  • GreatGrandchild
  • -
  • GranduncleOrGrandaunt
  • -
  • GrandnephewOrGrandniece
  • -
  • CousinOnceRemoved
  • -
  • SecondCousin
  • -
  • Cousin
  • -
  • Kin
  • - + +
  • FarRelative
  • +
    RSI_IncestuosSex @@ -145,6 +101,29 @@ 60 1000 100 + +
  • + +
  • CloseRelative
  • +
  • FarRelative
  • +
  • NotRelated
  • + + +
  • + CloseRelative + 1 +
  • +
  • + FarRelative + 1 +
  • +
  • + NotRelated + 1 +
  • +
    + +
    @@ -172,16 +151,9 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • - + +
  • CloseRelative
  • +
  • Spouse
  • @@ -191,6 +163,22 @@ +
  • + +
  • FarRelative
  • +
  • NotRelated
  • + + +
  • + FarRelative + 1 +
  • +
  • + NotRelated + 1 +
  • +
    +
    @@ -223,24 +211,10 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • -
  • GreatGrandparent
  • -
  • GreatGrandchild
  • -
  • GranduncleOrGrandaunt
  • -
  • GrandnephewOrGrandniece
  • -
  • CousinOnceRemoved
  • -
  • SecondCousin
  • -
  • Cousin
  • -
  • Kin
  • - + +
  • CloseRelative
  • +
  • FarRelative
  • +
  • Spouse
  • @@ -282,24 +256,10 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • -
  • GreatGrandparent
  • -
  • GreatGrandchild
  • -
  • GranduncleOrGrandaunt
  • -
  • GrandnephewOrGrandniece
  • -
  • CousinOnceRemoved
  • -
  • SecondCousin
  • -
  • Cousin
  • -
  • Kin
  • - + +
  • CloseRelative
  • +
  • FarRelative
  • +
  • Spouse
  • @@ -309,6 +269,18 @@ +
  • + +
  • + CloseRelative + 0.03 +
  • +
  • + FarRelative + 0.03 +
  • + + @@ -320,9 +292,6 @@ High 0 1000 - -
  • Zoophile
  • -
  • RSI_NonIncestuosMarriage @@ -339,30 +308,35 @@
  • - -
  • Parent
  • -
  • Child
  • -
  • Sibling
  • -
  • HalfSibling
  • -
  • Grandparent
  • -
  • Grandchild
  • -
  • NephewOrNiece
  • -
  • UncleOrAunt
  • -
  • GreatGrandparent
  • -
  • GreatGrandchild
  • -
  • GranduncleOrGrandaunt
  • -
  • GrandnephewOrGrandniece
  • -
  • CousinOnceRemoved
  • -
  • SecondCousin
  • -
  • Cousin
  • -
  • Kin
  • - + +
  • NotRelated
  • +
    - 2.0 + 0.1 +
  • + +
  • CloseRelative
  • +
  • FarRelative
  • + + +
  • + CloseRelative + 1 +
  • +
  • + FarRelative + 1 +
  • +
  • + NotRelated + 0.03 +
  • +
    + diff --git a/1.4/Defs/PreceptDefs/Precepts_Pregnancy.xml b/1.4/Defs/PreceptDefs/Precepts_Pregnancy.xml index 7e5b69f..bdd6015 100644 --- a/1.4/Defs/PreceptDefs/Precepts_Pregnancy.xml +++ b/1.4/Defs/PreceptDefs/Precepts_Pregnancy.xml @@ -100,14 +100,14 @@ - Pregnancy_Respected_Pregnant + Pregnancy_Respected_Pregnant RJWSexperience.Ideology.PreceptWorkers.ThoughtWorker_Precept_Pregnant Thought_Situational
  • I am pregnant. This makes me a pillar of society. - 5 + 10
  • @@ -120,19 +120,19 @@
  • I am soon making our colony stronger. - 10 + 5
  • - Pregnancy_Respected_Pregnant_Social + Pregnancy_Respected_Pregnant_Social RJWSexperience.Ideology.PreceptWorkers.ThoughtWorker_Precept_Pregnant_Social Thought_SituationalSocial
  • - 10 + 20
  • @@ -144,7 +144,7 @@
  • - 20 + 10
  • diff --git a/1.4/Defs/PreceptDefs/Precepts_Submissive.xml b/1.4/Defs/PreceptDefs/Precepts_Submissive.xml index e69c135..aa7ae4d 100644 --- a/1.4/Defs/PreceptDefs/Precepts_Submissive.xml +++ b/1.4/Defs/PreceptDefs/Precepts_Submissive.xml @@ -76,11 +76,11 @@ BeenRaped_NotSubmissive Female -
  • + @@ -140,11 +140,11 @@ BeenRaped_NotSubmissive Male
  • -
  • + diff --git a/1.4/Patches/RJW_ThoughtDefs.xml b/1.4/Patches/RJW_ThoughtDefs.xml index e2e3f6e..30a1b66 100644 --- a/1.4/Patches/RJW_ThoughtDefs.xml +++ b/1.4/Patches/RJW_ThoughtDefs.xml @@ -8,6 +8,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • @@ -19,6 +20,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • @@ -30,6 +32,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • @@ -41,6 +44,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • @@ -52,6 +56,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • @@ -63,6 +68,7 @@
  • Bestiality_OnlyVenerated
  • Bestiality_BondOnly
  • Bestiality_Honorable
  • +
  • Bestiality_Acceptable
  • diff --git a/About/Manifest.xml b/About/Manifest.xml index bac3aa3..c6907d3 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RJWSexperienceIdeology - 1.0.1.2 + 1.0.2.1
  • RimJobWorld >= 5.3.0
  • diff --git a/CHANGELOG.md b/CHANGELOG.md index f9784d2..97418aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ +## Version 1.0.2.1 +* Fixed SecondaryRomanceChanceFactor patch +## Version 1.0.2.0 +* Removed Incestuos_IncestOnly conflict with Zoophile +* Patched manual romance to respect incestuous precepts +* Patched SecondaryRomanceChanceFactor for incest precept +* Added settings to disable ether of patches if needed +* Changed Incestuos_IncestOnly would_fuck multiplier for blood related pawns: 2.0 -> 1.0 +* Changed Incestuos_IncestOnly would_fuck multiplier for non-blood related pawns: 1.0 -> 0.1 +* Removed "not obedient" social thought for raping a slave +* Bestiality_Acceptable now nullifies RJW bestiality thoughts +* Fixed swapped baseMoodEffect of holy and elevated pregnancy precepts ## Version 1.0.1.2 * Removed 100% certainty spam for sex proselyzing * Maybe removed sex proselyzing error with bestiality diff --git a/Languages/English/Keyed/RJW_Sexperience.xml b/Languages/English/Keyed/RJW_Sexperience.xml index 9550b00..83d2026 100644 --- a/Languages/English/Keyed/RJW_Sexperience.xml +++ b/Languages/English/Keyed/RJW_Sexperience.xml @@ -9,4 +9,16 @@ not animal capable of sex is required + Enable romance patch for incest precepts* + Patch for incest precepts to affect RomanceChanceFactor. May conflict with romance mods./n/n* Requires a game restart to apply changes + Enable manual romance patch for incest precepts* + Patch for incest precepts to affect manual romance options./n/n* Requires a game restart to apply changes + + Time between bestiality attempts x{0} + Time between masturbation attempts x{0} + Time between necrophilia attempts x{0} + Time between rape attempts x{0} + + + \ No newline at end of file diff --git a/Source/IdeologyAddon/BloodRelationDegree.cs b/Source/IdeologyAddon/BloodRelationDegree.cs new file mode 100644 index 0000000..e23f9ee --- /dev/null +++ b/Source/IdeologyAddon/BloodRelationDegree.cs @@ -0,0 +1,9 @@ +namespace RJWSexperience.Ideology +{ + public enum BloodRelationDegree + { + CloseRelative, + FarRelative, + NotRelated + } +} diff --git a/Source/IdeologyAddon/DebugAction.cs b/Source/IdeologyAddon/DebugAction.cs index 9655f50..55838d7 100644 --- a/Source/IdeologyAddon/DebugAction.cs +++ b/Source/IdeologyAddon/DebugAction.cs @@ -1,20 +1,37 @@ using rjw; using RJWSexperience.Ideology.HistoryEvents; +using RJWSexperience.Ideology.Patches; +using System.Collections.Generic; using System.Linq; using Verse; namespace RJWSexperience.Ideology { - internal class DebugAction + internal static class DebugAction { [DebugAction("RJW Sexperience Ideology", "Test marriage event", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.PlayingOnMap)] - private static void GenerateMarriageEvent(Pawn p) + public static void GenerateMarriageEvent(Pawn p) { Pawn hero = p.Map.PlayerPawnsForStoryteller.First(x => x.IsDesignatedHero()); if (hero == null) return; - RsiHistoryEventDefOf.RSI_NonIncestuosMarriage.RecordEventWithPartner(hero, p); - RsiHistoryEventDefOf.RSI_NonIncestuosMarriage.RecordEventWithPartner(p, hero); + RsiDefOf.HistoryEvent.RSI_NonIncestuosMarriage.RecordEventWithPartner(hero, p); + RsiDefOf.HistoryEvent.RSI_NonIncestuosMarriage.RecordEventWithPartner(p, hero); + } + + [DebugAction("RJW Sexperience Ideology", "Manual romance check", false, true, actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.PlayingOnMap)] + public static void DisplayDebugTable() + { + IEnumerable pawns = Find.CurrentMap.mapPawns.AllPawnsSpawned.Where(pawn => pawn.IsColonist); + + IEnumerable> columns = pawns + .Select(pawn => new TableDataGetter(pawn.Name.ToStringShort, (Pawn p) => Rimworld_Patch_IncestuousManualRomance.RsiIncestuous(p, pawn))); + + var name = new TableDataGetter("Name", (Pawn pawn) => pawn.Name.ToStringShort); + + TableDataGetter[] getters = (new List>() { name }).Concat(columns).ToArray(); + + DebugTables.MakeTablesDialog(pawns, getters); } } } diff --git a/Source/IdeologyAddon/RelationFilter.cs b/Source/IdeologyAddon/Filters/RelationFilter.cs similarity index 64% rename from Source/IdeologyAddon/RelationFilter.cs rename to Source/IdeologyAddon/Filters/RelationFilter.cs index cff5738..732ed7e 100644 --- a/Source/IdeologyAddon/RelationFilter.cs +++ b/Source/IdeologyAddon/Filters/RelationFilter.cs @@ -3,31 +3,33 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using Verse; -namespace RJWSexperience.Ideology +namespace RJWSexperience.Ideology.Filters { + /// + /// Filter to describe how one pawn sees another + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] public class RelationFilter { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public bool? isVeneratedAnimal; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] - public bool? isAlien; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public List hasOneOfRelations; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public List hasNoneOfRelations; + public List hasOneOfRelationDegrees; private bool initialized = false; private HashSet hasOneOfRelationsHashed; private HashSet hasNoneOfRelationsHashed; + private HashSet hasOneOfRelationDegreesHashed; + /// + /// Check if the pair of pawns fits filter conditions + /// public bool Applies(Pawn pawn, Pawn partner) { + // Fail if any single condition fails if (isVeneratedAnimal != null && isVeneratedAnimal != pawn.Ideo.IsVeneratedAnimal(partner)) return false; - //if (isAlien != null && isAlien != partner) - // return false; - if (!CheckRelations(pawn, partner)) return false; @@ -39,9 +41,14 @@ namespace RJWSexperience.Ideology if (!initialized) Initialize(); - if (hasNoneOfRelationsHashed == null && hasOneOfRelationsHashed == null) + if (hasNoneOfRelationsHashed == null && hasOneOfRelationsHashed == null && hasOneOfRelationDegreesHashed == null) return true; + if (hasOneOfRelationDegreesHashed != null && !hasOneOfRelationDegreesHashed.Contains(RelationHelpers.GetBloodRelationDegree(pawn, partner))) + { + return false; + } + IEnumerable relations = pawn.GetRelations(partner); if (hasOneOfRelationsHashed != null) @@ -69,6 +76,9 @@ namespace RJWSexperience.Ideology if (!hasOneOfRelations.NullOrEmpty()) hasOneOfRelationsHashed = new HashSet(hasOneOfRelations); + if (!hasOneOfRelationDegrees.NullOrEmpty()) + hasOneOfRelationDegreesHashed = new HashSet(hasOneOfRelationDegrees); + initialized = true; } } diff --git a/Source/IdeologyAddon/SinglePawnFilter.cs b/Source/IdeologyAddon/Filters/SinglePawnFilter.cs similarity index 50% rename from Source/IdeologyAddon/SinglePawnFilter.cs rename to Source/IdeologyAddon/Filters/SinglePawnFilter.cs index daa240f..40e7a0a 100644 --- a/Source/IdeologyAddon/SinglePawnFilter.cs +++ b/Source/IdeologyAddon/Filters/SinglePawnFilter.cs @@ -2,19 +2,24 @@ using System.Diagnostics.CodeAnalysis; using Verse; -namespace RJWSexperience.Ideology +namespace RJWSexperience.Ideology.Filters { + /// + /// Filter to describe one pawn + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] public class SinglePawnFilter { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public bool? isAnimal; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public bool? isSlave; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public bool? isPrisoner; + /// + /// Check if pawn fits filter conditions + /// public bool Applies(Pawn pawn) { + // Fail if any single condition fails if (isAnimal != null && isAnimal != pawn.IsAnimal()) return false; diff --git a/Source/IdeologyAddon/Filters/TwoPawnFilter.cs b/Source/IdeologyAddon/Filters/TwoPawnFilter.cs new file mode 100644 index 0000000..c0580b0 --- /dev/null +++ b/Source/IdeologyAddon/Filters/TwoPawnFilter.cs @@ -0,0 +1,34 @@ +using System.Diagnostics.CodeAnalysis; +using Verse; + +namespace RJWSexperience.Ideology.Filters +{ + /// + /// Filter to describe two pawns and relations between them + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] + public class TwoPawnFilter + { + public SinglePawnFilter doer; + public SinglePawnFilter partner; + public RelationFilter relations; + + /// + /// Check if the pair of pawns fits filter conditions + /// + public bool Applies(Pawn pawn, Pawn partner) + { + // Fail if any single condition fails + if (doer?.Applies(pawn) == false) + return false; + + if (this.partner?.Applies(partner) == false) + return false; + + if (relations?.Applies(pawn, partner) == false) + return false; + + return true; + } + } +} diff --git a/Source/IdeologyAddon/Harmony.cs b/Source/IdeologyAddon/Harmony.cs index 08a78d0..d756855 100644 --- a/Source/IdeologyAddon/Harmony.cs +++ b/Source/IdeologyAddon/Harmony.cs @@ -1,25 +1,14 @@ -using HarmonyLib; -using RJWSexperience.Ideology.Patches; -using System.Reflection; +using System.Reflection; using Verse; namespace RJWSexperience.Ideology { [StaticConstructorOnStartup] - internal static class First + internal static class Harmony { - static First() + static Harmony() { - var harmony = new Harmony("RJW_Sexperience.Ideology"); - harmony.PatchAll(Assembly.GetExecutingAssembly()); - - if (ModLister.HasActiveModWithName("RJW Sexperience")) - { - harmony.Patch(AccessTools.Method("RJWSexperience.RJWUtility:ThrowVirginHistoryEvent"), - prefix: null, - postfix: new HarmonyMethod(typeof(Sexperience_Patch_ThrowVirginHistoryEvent), nameof(Sexperience_Patch_ThrowVirginHistoryEvent.Postfix)) - ); - } + new HarmonyLib.Harmony("RJW_Sexperience.Ideology").PatchAll(Assembly.GetExecutingAssembly()); } } } diff --git a/Source/IdeologyAddon/HistoryEvents/TwoPawnEventRule.cs b/Source/IdeologyAddon/HistoryEvents/TwoPawnEventRule.cs index dc61b89..9c9e3f1 100644 --- a/Source/IdeologyAddon/HistoryEvents/TwoPawnEventRule.cs +++ b/Source/IdeologyAddon/HistoryEvents/TwoPawnEventRule.cs @@ -1,16 +1,22 @@ using RimWorld; +using RJWSexperience.Ideology.Filters; using System.Diagnostics.CodeAnalysis; using Verse; namespace RJWSexperience.Ideology.HistoryEvents { + /// + /// Type to associate single HistoryEventDef with a TwoPawnFilter + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] public class TwoPawnEventRule { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public HistoryEventDef historyEventDef; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public TwoPawnFilter filter; + /// + /// Check if the pair of pawns fits filter conditions + /// public bool Applies(Pawn pawn, Pawn partner) => filter?.Applies(pawn, partner) == true; } } diff --git a/Source/IdeologyAddon/IdeoUtility.cs b/Source/IdeologyAddon/IdeoUtility.cs index 4b44cce..05ffd75 100644 --- a/Source/IdeologyAddon/IdeoUtility.cs +++ b/Source/IdeologyAddon/IdeoUtility.cs @@ -12,9 +12,9 @@ namespace RJWSexperience.Ideology if (ideo == null) return false; - if (ideo.HasPrecept(VariousDefOf.Submissive_Female) && pawn.gender == Gender.Female) + if (ideo.HasPrecept(RsiDefOf.Precept.Submissive_Female) && pawn.gender == Gender.Female) return true; - else if (ideo.HasPrecept(VariousDefOf.Submissive_Male) && pawn.gender == Gender.Male) + else if (ideo.HasPrecept(RsiDefOf.Precept.Submissive_Male) && pawn.gender == Gender.Male) return true; return false; @@ -89,7 +89,7 @@ namespace RJWSexperience.Ideology Hediff pregnancy = PregnancyHelper.GetPregnancy(pawn); // Currently RJW does not check Biotech pregnancy - if (pregnancy == null && VariousDefOf.PregnantHuman != null) + if (pregnancy == null && RsiDefOf.Hediff.PregnantHuman != null) { pregnancy = pawn.health.hediffSet.GetFirstHediffOfDef(HediffDefOf.PregnantHuman); } diff --git a/Source/IdeologyAddon/IdeologyAddon.csproj b/Source/IdeologyAddon/IdeologyAddon.csproj index 651dd5b..f791556 100644 --- a/Source/IdeologyAddon/IdeologyAddon.csproj +++ b/Source/IdeologyAddon/IdeologyAddon.csproj @@ -42,6 +42,7 @@ + @@ -52,16 +53,19 @@ + + - - - - + + + + + @@ -84,17 +88,19 @@ + + - + - 1.4.3537 + 1.4.3704 2.2.2 diff --git a/Source/IdeologyAddon/Keyed.cs b/Source/IdeologyAddon/Keyed.cs index 8a98c01..4083479 100644 --- a/Source/IdeologyAddon/Keyed.cs +++ b/Source/IdeologyAddon/Keyed.cs @@ -4,11 +4,17 @@ namespace RJWSexperience.Ideology { public static class Keyed { + public static readonly string ModTitle = "RSI_Mod_Title".Translate(); public static readonly string MemeStatFactor = "MemeStatFactor".Translate(); public static readonly string RSVictimCondition = "RSVictimCondition".Translate(); public static readonly string RSBreederCondition = "RSBreederCondition".Translate(); public static readonly string RSNotHuman = "RSNotHuman".Translate(); public static readonly string RSNotAnimal = "RSNotAnimal".Translate(); public static readonly string RSShouldCanFuck = "RSShouldCanFuck".Translate(); + + public static readonly string PatchRomanceChanceFactor = "RSI_PatchRomanceChanceFactor".Translate(); + public static readonly string PatchRomanceChanceFactorTip = "RSI_PatchRomanceChanceFactorTip".Translate(); + public static readonly string PatchIncestuousManualRomance = "RSI_PatchIncestuousManualRomance".Translate(); + public static readonly string PatchIncestuousManualRomanceTip = "RSI_PatchIncestuousManualRomanceTip".Translate(); } } diff --git a/Source/IdeologyAddon/Patches/RJW_Patch_ChancePerHour.cs b/Source/IdeologyAddon/Patches/RJW_Patch_ChancePerHour.cs index 2a22c2c..18d8550 100644 --- a/Source/IdeologyAddon/Patches/RJW_Patch_ChancePerHour.cs +++ b/Source/IdeologyAddon/Patches/RJW_Patch_ChancePerHour.cs @@ -15,7 +15,7 @@ namespace RJWSexperience.Ideology.Patches if (__result < 0f || pawn.Ideo == null) // ideo is null if don't have dlc return; - if (!RsiHistoryEventDefOf.RSI_SexWithAnimal.CreateEvent(pawn).DoerWillingToDo()) + if (!RsiDefOf.HistoryEvent.RSI_SexWithAnimal.CreateEvent(pawn).DoerWillingToDo()) { __result = -2f; return; @@ -32,7 +32,7 @@ namespace RJWSexperience.Ideology.Patches if (__result < 0f || pawn.Ideo == null) // ideo is null if don't have dlc return; - if (!RsiHistoryEventDefOf.RSI_Raped.CreateEvent(pawn).DoerWillingToDo()) + if (!RsiDefOf.HistoryEvent.RSI_Raped.CreateEvent(pawn).DoerWillingToDo()) { __result = -2f; return; @@ -48,7 +48,7 @@ namespace RJWSexperience.Ideology.Patches if (__result < 0f || pawn.Ideo == null) // ideo is null if don't have dlc return; - if (!RsiHistoryEventDefOf.RSI_SexWithCorpse.CreateEvent(pawn).DoerWillingToDo()) + if (!RsiDefOf.HistoryEvent.RSI_SexWithCorpse.CreateEvent(pawn).DoerWillingToDo()) { __result = -2f; return; @@ -65,7 +65,7 @@ namespace RJWSexperience.Ideology.Patches if (__result < 0f || p.Ideo == null) // ideo is null if don't have dlc return; - if (!RsiHistoryEventDefOf.RSI_Masturbated.CreateEvent(p).DoerWillingToDo()) + if (!RsiDefOf.HistoryEvent.RSI_Masturbated.CreateEvent(p).DoerWillingToDo()) { __result = -2f; return; diff --git a/Source/IdeologyAddon/Patches/RJW_Patch_Ideo.cs b/Source/IdeologyAddon/Patches/RJW_Patch_Ideo.cs index f387f14..4a06922 100644 --- a/Source/IdeologyAddon/Patches/RJW_Patch_Ideo.cs +++ b/Source/IdeologyAddon/Patches/RJW_Patch_Ideo.cs @@ -19,7 +19,7 @@ namespace RJWSexperience.Ideology.Patches Ideo ideo = pawn.Ideo; if (ideo != null && !pawn.IsSubmissive()) { - __result = __result || ideo.HasMeme(VariousDefOf.Rapist); + __result = __result || ideo.HasMeme(RsiDefOf.Meme.Rapist); } } } @@ -32,7 +32,7 @@ namespace RJWSexperience.Ideology.Patches Ideo ideo = pawn.Ideo; if (ideo != null) { - __result = __result || ideo.HasMeme(VariousDefOf.Zoophile); + __result = __result || ideo.HasMeme(RsiDefOf.Meme.Zoophile); } } } @@ -45,7 +45,7 @@ namespace RJWSexperience.Ideology.Patches Ideo ideo = pawn.Ideo; if (ideo != null) { - __result = __result || ideo.HasMeme(VariousDefOf.Necrophile); + __result = __result || ideo.HasMeme(RsiDefOf.Meme.Necrophile); } } } @@ -85,10 +85,10 @@ namespace RJWSexperience.Ideology.Patches private static void AfterSexHuman(Pawn human, Pawn partner) { - RsiHistoryEventDefOf.RSI_NonIncestuosSex.RecordEventWithPartner(human, partner); + RsiDefOf.HistoryEvent.RSI_NonIncestuosSex.RecordEventWithPartner(human, partner); if (partner.IsAnimal()) - RsiHistoryEventDefOf.RSI_SexWithAnimal.RecordEventWithPartner(human, partner); + RsiDefOf.HistoryEvent.RSI_SexWithAnimal.RecordEventWithPartner(human, partner); } } @@ -113,11 +113,13 @@ namespace RJWSexperience.Ideology.Patches public static float PreceptSextype(Pawn pawn, Pawn partner, float score, List historyEventDefs) { - foreach(HistoryEventDef eventDef in historyEventDefs) + for (int i = 0; i < historyEventDefs.Count; i++) { + HistoryEventDef eventDef = historyEventDefs[i]; + if (eventDef.CreateEventWithPartner(pawn, partner).DoerWillingToDo()) { - float mult = 8.0f * Math.Max(0.3f, 1 / Math.Max(0.01f, pawn.GetStatValue(xxx.sex_drive_stat))); + float mult = 8.0f * Math.Max(0.3f, 1 / Math.Max(0.01f, pawn.GetStatValue(xxx.sex_drive_stat, cacheStaleAfterTicks: 60))); return score * mult; } } @@ -148,7 +150,7 @@ namespace RJWSexperience.Ideology.Patches public static void Postfix(Pawn pawn, ref bool __result) { Ideo ideo = pawn.Ideo; - if (ideo?.HasMeme(VariousDefOf.Zoophile) == true) + if (ideo?.HasMeme(RsiDefOf.Meme.Zoophile) == true) { SaveStorage.DataStore.GetPawnData(pawn).CanDesignateBreeding = true; __result = true; @@ -213,14 +215,14 @@ namespace RJWSexperience.Ideology.Patches Ideo mainideo = playerfaction.ideos.PrimaryIdeo; if (mainideo != null) { - if (mainideo.HasPrecept(VariousDefOf.BabyFaction_AlwaysFather)) + if (mainideo.HasPrecept(RsiDefOf.Precept.BabyFaction_AlwaysFather)) { Pawn parent = baby.GetFather() ?? baby.GetMother(); ideo = parent.Ideo; return parent.Faction; } - else if (mainideo.HasPrecept(VariousDefOf.BabyFaction_AlwaysColony)) + else if (mainideo.HasPrecept(RsiDefOf.Precept.BabyFaction_AlwaysColony)) { ideo = mainideo; return playerfaction; @@ -241,7 +243,7 @@ namespace RJWSexperience.Ideology.Patches if (props.pawn?.Ideo == null || !props.hasPartner()) return; - if (props.partner.Ideo?.HasPrecept(VariousDefOf.ProselyzingByOrgasm) == true) + if (props.partner.Ideo?.HasPrecept(RsiDefOf.Precept.ProselyzingByOrgasm) == true) { // Pawn is the one having the orgasm // Partner is "giving" the orgasm, hence the pawn will be converted towards the partners ideology diff --git a/Source/IdeologyAddon/Patches/Rimworld_Patch.cs b/Source/IdeologyAddon/Patches/Rimworld_Patch.cs index e50098e..1cbf453 100644 --- a/Source/IdeologyAddon/Patches/Rimworld_Patch.cs +++ b/Source/IdeologyAddon/Patches/Rimworld_Patch.cs @@ -1,9 +1,14 @@ using HarmonyLib; +using Mono.Cecil.Cil; using RimWorld; using rjw; using RJWSexperience.Ideology.HistoryEvents; using RJWSexperience.Ideology.Precepts; using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; using Verse; namespace RJWSexperience.Ideology.Patches @@ -13,8 +18,8 @@ namespace RJWSexperience.Ideology.Patches { public static void Postfix(Pawn firstPawn, Pawn secondPawn) { - RsiHistoryEventDefOf.RSI_NonIncestuosMarriage.RecordEventWithPartner(firstPawn, secondPawn); - RsiHistoryEventDefOf.RSI_NonIncestuosMarriage.RecordEventWithPartner(secondPawn, firstPawn); + RsiDefOf.HistoryEvent.RSI_NonIncestuosMarriage.RecordEventWithPartner(firstPawn, secondPawn); + RsiDefOf.HistoryEvent.RSI_NonIncestuosMarriage.RecordEventWithPartner(secondPawn, firstPawn); } } @@ -53,4 +58,193 @@ namespace RJWSexperience.Ideology.Patches } } } + + [HarmonyPatch(typeof(RelationsUtility), "Incestuous")] + public static class Rimworld_Patch_IncestuousManualRomance + { + public static bool Prepare() => RsiMod.Prefs.patchIncestuousManualRomance; + + /// + /// Override incestuous check in the manual romance + /// + /// Pawn to try do romance + /// Target for romance + /// Result of the original method + /// Run original method implementation + public static bool Prefix(Pawn one, Pawn two, ref bool __result) + { + __result = RsiIncestuous(one, two); + return false; + } + + /// + /// Check if Ideology allows romance attempt + /// + /// Pawn to try do romance + /// Target for romance + /// Forbid romance option + public static bool RsiIncestuous(Pawn one, Pawn two) + { + PreceptDef incestuousPrecept = one.Ideo?.PreceptsListForReading.Select(precept => precept.def).FirstOrFallback(def => def.issue == RsiDefOf.Issue.Incestuos); + var allowManualRomanceOnlyFor = incestuousPrecept?.GetModExtension()?.allowManualRomanceOnlyFor; + BloodRelationDegree relationDegree = RelationHelpers.GetBloodRelationDegree(one, two); + + if (allowManualRomanceOnlyFor == null) + { + return relationDegree < BloodRelationDegree.NotRelated; + } + + return !allowManualRomanceOnlyFor.Contains(relationDegree); + } + } + + [HarmonyPatch(typeof(Pawn_RelationsTracker), nameof(Pawn_RelationsTracker.SecondaryRomanceChanceFactor))] + public static class Rimworld_Patch_SecondaryRomanceChanceFactor + { + public static bool Prepare() => RsiMod.Prefs.patchRomanceChanceFactor; + + /// + /// + /// Replace + /// float num = 1f; + /// foreach (PawnRelationDef pawnRelationDef in this.pawn.GetRelations(otherPawn)) + /// { + /// num *= pawnRelationDef.romanceChanceFactor; + /// } + /// + /// with + /// + /// float num = 1f; + /// num = RomanceChanceFactorHelpers.GetRomanceChanceFactor(this.pawn, otherPawn) + /// + /// + /// Original method body + /// Modified method body + public static IEnumerable Transpiler(IEnumerable 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 + + IEnumerator enumerator = instructions.GetEnumerator(); + bool endOfInstructions = !enumerator.MoveNext(); + + // Find and replace GetRelations + while (!endOfInstructions) + { + var instruction = enumerator.Current; + + if (instruction.Calls(getRelationsInfo)) + { + yield return new CodeInstruction(OpCodes.Call, helperInfo); + enumerator.MoveNext(); // skip original method call + break; + } + + yield return instruction; + endOfInstructions = !enumerator.MoveNext(); + } + + 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) + { + enumerator.MoveNext(); // skip Mul + yield return enumerator.Current; // return next op, it should be "store result" + break; + } + + endOfInstructions = !enumerator.MoveNext(); + } + + 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; + } + + // Skip the rest of the loop + while (!endOfInstructions) + { + if (enumerator.Current.opcode == OpCodes.Endfinally) + { + // Endfinally will be skipped by the next MoveNext() + break; + } + + endOfInstructions = !enumerator.MoveNext(); + } + + 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; + } + + if (Prefs.DevMode) Log.Message("[RSI] Successfully transpiled Pawn_RelationsTracker.SecondaryRomanceChanceFactor"); + } + + [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()) + { + return; + } + + 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(); + } + } + } + } } diff --git a/Source/IdeologyAddon/Patches/Sexperience_Patch.cs b/Source/IdeologyAddon/Patches/Sexperience_Patch.cs index 6951eea..4f7471e 100644 --- a/Source/IdeologyAddon/Patches/Sexperience_Patch.cs +++ b/Source/IdeologyAddon/Patches/Sexperience_Patch.cs @@ -1,21 +1,25 @@ -using rjw; +using HarmonyLib; +using rjw; using RJWSexperience.Ideology.HistoryEvents; using Verse; namespace RJWSexperience.Ideology.Patches { + [HarmonyPatch("RJWSexperience.RJWUtility", "ThrowVirginHistoryEvent")] public static class Sexperience_Patch_ThrowVirginHistoryEvent { + public static bool Prepare() => ModsConfig.IsActive("rjw.sexperience"); + public static void Postfix(Pawn exVirgin, Pawn partner, SexProps props, int degree) { const int femaleAfterSurgery = 1; if (props.isRape && exVirgin == props.partner) - RsiHistoryEventDefOf.RSI_VirginStolen.RecordEventWithPartner(exVirgin, partner); + RsiDefOf.HistoryEvent.RSI_VirginStolen.RecordEventWithPartner(exVirgin, partner); else if (degree != femaleAfterSurgery) - RsiHistoryEventDefOf.RSI_VirginTaken.RecordEventWithPartner(exVirgin, partner); + RsiDefOf.HistoryEvent.RSI_VirginTaken.RecordEventWithPartner(exVirgin, partner); - RsiHistoryEventDefOf.RSI_TookVirgin.RecordEventWithPartner(partner, exVirgin); + RsiDefOf.HistoryEvent.RSI_TookVirgin.RecordEventWithPartner(partner, exVirgin); } } } diff --git a/Source/IdeologyAddon/Precepts/DefExtension_Incest.cs b/Source/IdeologyAddon/Precepts/DefExtension_Incest.cs new file mode 100644 index 0000000..caf0ed0 --- /dev/null +++ b/Source/IdeologyAddon/Precepts/DefExtension_Incest.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Verse; + +namespace RJWSexperience.Ideology.Precepts +{ + /// + /// Special Def extension for the Incestuous issue precepts + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] + public class DefExtension_Incest : DefModExtension + { + public List allowManualRomanceOnlyFor; + public List bloodRelationDegreeRomanceFactors; + + private Dictionary _relationDegreeFactorsDict; + + public bool TryGetRomanceChanceFactor(BloodRelationDegree relationDegree, out float romanceChanceFactor) + { + if (bloodRelationDegreeRomanceFactors.NullOrEmpty()) + { + romanceChanceFactor = 1f; + return false; + } + + if (_relationDegreeFactorsDict == null) + { + _relationDegreeFactorsDict = new Dictionary(); + foreach (BloodRelationDegreeFactor relationDegreeFactor in bloodRelationDegreeRomanceFactors) + { + _relationDegreeFactorsDict.Add((BloodRelationDegree)relationDegreeFactor.bloodRelationDegree, relationDegreeFactor.romanceChanceFactor); + } + } + + return _relationDegreeFactorsDict.TryGetValue(relationDegree, out romanceChanceFactor); + } + + public override IEnumerable ConfigErrors() + { + foreach (string error in base.ConfigErrors()) + { + yield return error; + } + + foreach (BloodRelationDegreeFactor factor in bloodRelationDegreeRomanceFactors) + { + foreach(string error in factor.ConfigErrors()) + { + yield return error; + } + } + } + + public class BloodRelationDegreeFactor + { + public BloodRelationDegree? bloodRelationDegree; + public float romanceChanceFactor; + + public IEnumerable ConfigErrors() + { + if (bloodRelationDegree == null) + { + yield return " is empty"; + } + + if (romanceChanceFactor == 0f) + { + yield return " should be > 0"; + } + } + } + } +} diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyBestialityMtb.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyBestialityMtb.cs index 1d97595..111ee69 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyBestialityMtb.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyBestialityMtb.cs @@ -2,5 +2,6 @@ { public class DefExtension_ModifyBestialityMtb : DefExtension_ModifyMtb { + protected override string TipTemplateKey => "RSI_PreceptTipModifyBestialityMtb"; } } diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyFappinMtb.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyFappinMtb.cs index 8596b28..f01c4ed 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyFappinMtb.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyFappinMtb.cs @@ -2,5 +2,6 @@ { public class DefExtension_ModifyFappinMtb : DefExtension_ModifyMtb { + protected override string TipTemplateKey => "RSI_PreceptTipModifyFappinMtb"; } } diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyMtb.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyMtb.cs index e1553f3..361ceb1 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyMtb.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyMtb.cs @@ -1,11 +1,28 @@ -using System.Diagnostics.CodeAnalysis; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; using Verse; namespace RJWSexperience.Ideology.Precepts { - public abstract class DefExtension_ModifyMtb : DefModExtension + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field values are loaded from XML")] + public abstract class DefExtension_ModifyMtb : DefModExtension, IPreceptTipPostfix { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] + protected abstract string TipTemplateKey { get; } + public float multiplier = 1f; + + public string GetTip() => TipTemplateKey.Translate(multiplier.ToString()); + + public override IEnumerable ConfigErrors() + { + if (multiplier == 1f) + { + yield return "There is no point if is 1"; + } + else if (multiplier <= 0f) + { + yield return " must be > 0"; + } + } } } diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyNecroMtb.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyNecroMtb.cs index 3e544f7..ce35b27 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyNecroMtb.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyNecroMtb.cs @@ -2,5 +2,6 @@ { public class DefExtension_ModifyNecroMtb : DefExtension_ModifyMtb { + protected override string TipTemplateKey => "RSI_PreceptTipModifyNecroMtb"; } } diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyPreference.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyPreference.cs index 698bda1..19689bb 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyPreference.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyPreference.cs @@ -1,30 +1,41 @@ -using System.Collections.Generic; +using RJWSexperience.Ideology.Filters; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; +using System.Linq; using Verse; namespace RJWSexperience.Ideology.Precepts { + /// + /// Def extension to enable changing SexAppraiser results based on filters + /// + [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Def loader")] public class DefExtension_ModifyPreference : DefModExtension { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public List rules; + /// + /// Apply SexAppraiser modifiers from rules with a satisfied filter + /// public void Apply(Pawn pawn, Pawn partner, ref float preference) { - foreach (Rule rule in rules) + foreach (Rule rule in rules.Where(rule => rule.Applies(pawn, partner))) { - if (rule.Applies(pawn, partner)) - preference *= rule.multiplier; + preference *= rule.multiplier; } } + /// + /// Type to associate SexAppraiser result modifier with a TwoPawnFilter + /// public class Rule { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public float multiplier = 1f; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] public TwoPawnFilter filter; + /// + /// Check if the pair of pawns fits filter conditions + /// public bool Applies(Pawn pawn, Pawn partner) { if (filter == null) diff --git a/Source/IdeologyAddon/Precepts/DefExtension_ModifyRapeCPMtb.cs b/Source/IdeologyAddon/Precepts/DefExtension_ModifyRapeCPMtb.cs index e83be70..ff09728 100644 --- a/Source/IdeologyAddon/Precepts/DefExtension_ModifyRapeCPMtb.cs +++ b/Source/IdeologyAddon/Precepts/DefExtension_ModifyRapeCPMtb.cs @@ -2,5 +2,6 @@ { public class DefExtension_ModifyRapeCPMtb : DefExtension_ModifyMtb { + protected override string TipTemplateKey => "RSI_PreceptTipModifyRapeCPMtb"; } } diff --git a/Source/IdeologyAddon/Precepts/IPreceptTipPostfix.cs b/Source/IdeologyAddon/Precepts/IPreceptTipPostfix.cs new file mode 100644 index 0000000..85411fb --- /dev/null +++ b/Source/IdeologyAddon/Precepts/IPreceptTipPostfix.cs @@ -0,0 +1,7 @@ +namespace RJWSexperience.Ideology.Precepts +{ + public interface IPreceptTipPostfix + { + string GetTip(); + } +} diff --git a/Source/IdeologyAddon/RelationHelpers.cs b/Source/IdeologyAddon/RelationHelpers.cs new file mode 100644 index 0000000..1033307 --- /dev/null +++ b/Source/IdeologyAddon/RelationHelpers.cs @@ -0,0 +1,52 @@ +using RimWorld; +using System.Linq; +using Verse; + +namespace RJWSexperience.Ideology +{ + public static class RelationHelpers + { + /// + /// Get degree of blood relation between two pawns + /// + public static BloodRelationDegree GetBloodRelationDegree(Pawn pawn, Pawn partner) + { + if (!pawn.relations.FamilyByBlood.Contains(partner)) + { + return BloodRelationDegree.NotRelated; + } + + PawnRelationDef closestBloodRelation = pawn + .GetRelations(partner) + ?.Where(def => def.familyByBloodRelation) + ?.OrderByDescending(def => def.importance) + ?.FirstOrFallback(); + + if (closestBloodRelation == null) + { + return BloodRelationDegree.NotRelated; + } + + return GetBloodRelationDegree(closestBloodRelation); + } + + /// + /// Get degree of blood relation for a relationDef + /// + public static BloodRelationDegree GetBloodRelationDegree(PawnRelationDef relationDef) + { + if (!relationDef.familyByBloodRelation) + { + return BloodRelationDegree.NotRelated; + } + else if (relationDef.importance <= PawnRelationDefOf.Cousin.importance) + { + return BloodRelationDegree.FarRelative; + } + else + { + return BloodRelationDegree.CloseRelative; + } + } + } +} diff --git a/Source/IdeologyAddon/Rituals/JobGiver_DrugOrgy.cs b/Source/IdeologyAddon/Rituals/JobGiver_DrugOrgy.cs index a7eacb0..82a541e 100644 --- a/Source/IdeologyAddon/Rituals/JobGiver_DrugOrgy.cs +++ b/Source/IdeologyAddon/Rituals/JobGiver_DrugOrgy.cs @@ -1,56 +1,47 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +using RimWorld; using rjw; +using System; +using System.Collections.Generic; using Verse; using Verse.AI; -using RimWorld; - namespace RJWSexperience.Ideology { - public class JobGiver_DrugOrgy : ThinkNode_JobGiver - { - protected override Job TryGiveJob(Pawn pawn) - { - if (pawn.Drafted) return null; - DutyDef dutyDef = null; - PawnDuty duty = null; - if (pawn.mindState != null) - { - duty = pawn.mindState.duty; - dutyDef = duty.def; - } - else return null; + public class JobGiver_DrugOrgy : ThinkNode_JobGiver + { + protected override Job TryGiveJob(Pawn pawn) + { + if (pawn.Drafted || pawn.mindState == null) + { + return null; + } - if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) - { - return null; - } - - Pawn target = FindPartner(pawn, duty); + PawnDuty duty = pawn.mindState.duty; - if (target == null || !pawn.CanReserveAndReach(target, PathEndMode.ClosestTouch, Danger.None,1)) return JobMaker.MakeJob(VariousDefOf.DrugMasturbate); + if (duty.def == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) + { + return null; + } - return JobMaker.MakeJob(VariousDefOf.DrugSex, target); - } + Pawn target = FindPartner(pawn, duty); - protected Pawn FindPartner(Pawn pawn, PawnDuty duty) - { - if (duty != null) - { - List pawns = pawn.Map.mapPawns.AllPawnsSpawned.FindAll(x => x.mindState?.duty?.def == duty.def); - return pawns.RandomElementByWeightWithDefault(x => SexAppraiser.would_fuck(pawn,x), 0.1f); - } - - + if (target == null || !pawn.CanReserveAndReach(target, PathEndMode.ClosestTouch, Danger.None, 1)) + return JobMaker.MakeJob(RsiDefOf.Job.DrugMasturbate); - return null; - } + return JobMaker.MakeJob(RsiDefOf.Job.DrugSex, target); + } - } + protected Pawn FindPartner(Pawn pawn, PawnDuty duty) + { + if (duty != null) + { + List pawns = pawn.Map.mapPawns.AllPawnsSpawned.FindAll(x => x.mindState?.duty?.def == duty.def); + return pawns.RandomElementByWeightWithDefault(x => SexAppraiser.would_fuck(pawn, x), 0.1f); + } + + return null; + } + } /// /// copied from rjw @@ -65,7 +56,7 @@ namespace RJWSexperience.Ideology protected override IEnumerable MakeNewToils() { setup_ticks(); - var PartnerJob = VariousDefOf.GettinDrugSex; + var PartnerJob = RsiDefOf.Job.GettinDrugSex; this.FailOnDespawnedNullOrForbidden(iTarget); this.FailOn(() => !Partner.health.capacities.CanBeAwake); @@ -73,47 +64,52 @@ namespace RJWSexperience.Ideology this.FailOn(() => Partner == null); yield return Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell); - Toil WaitForPartner = new Toil(); - WaitForPartner.defaultCompleteMode = ToilCompleteMode.Delay; - WaitForPartner.initAction = delegate + Toil WaitForPartner = new Toil { - ticksLeftThisToil = 5000; - }; - WaitForPartner.tickAction = delegate - { - pawn.GainComfortFromCellIfPossible(); - if (pawn.Position.DistanceTo(Partner.Position) <= 1f) + defaultCompleteMode = ToilCompleteMode.Delay, + initAction = delegate { - ReadyForNextToil(); + ticksLeftThisToil = 5000; + }, + tickAction = delegate + { + pawn.GainComfortFromCellIfPossible(); + if (pawn.Position.DistanceTo(Partner.Position) <= 1f) + { + ReadyForNextToil(); + } } }; yield return WaitForPartner; - Toil StartPartnerJob = new Toil(); - StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; - StartPartnerJob.socialMode = RandomSocialMode.Off; - StartPartnerJob.initAction = delegate + Toil StartPartnerJob = new Toil { - var dri = Partner.jobs.curDriver as JobDriver_DrugSexReceiver; - if (dri == null) - { - Job gettingQuickie = JobMaker.MakeJob(PartnerJob, pawn, Partner); - Partner.jobs.StartJob(gettingQuickie, JobCondition.InterruptForced); + defaultCompleteMode = ToilCompleteMode.Instant, + socialMode = RandomSocialMode.Off, + initAction = delegate + { + if (!(Partner.jobs.curDriver is JobDriver_DrugSexReceiver)) + { + Job gettingQuickie = JobMaker.MakeJob(PartnerJob, pawn, Partner); + Partner.jobs.StartJob(gettingQuickie, JobCondition.InterruptForced); + } } }; yield return StartPartnerJob; - Toil SexToil = new Toil(); - SexToil.defaultCompleteMode = ToilCompleteMode.Never; - SexToil.socialMode = RandomSocialMode.Off; - SexToil.defaultDuration = duration; - SexToil.handlingFacing = true; + Toil SexToil = new Toil + { + defaultCompleteMode = ToilCompleteMode.Never, + socialMode = RandomSocialMode.Off, + defaultDuration = duration, + handlingFacing = true + }; SexToil.FailOn(() => Partner.CurJob.def != PartnerJob); SexToil.initAction = delegate { Partner.pather.StopDead(); Partner.jobs.curDriver.asleep = false; - + Start(); Sexprops.usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner); }; @@ -147,8 +143,7 @@ namespace RJWSexperience.Ideology /// copied from rjw /// public class JobDriver_DrugSexReceiver : JobDriver_SexBaseRecieverLoved - { - + { protected override IEnumerable MakeNewToils() { setup_ticks(); @@ -168,23 +163,25 @@ namespace RJWSexperience.Ideology yield return Toils_Reserve.Reserve(iTarget, 1, 0); - var get_loved = MakeSexToil(); - get_loved.handlingFacing = false; - yield return get_loved; + var get_loved = MakeSexToil(); + get_loved.handlingFacing = false; + yield return get_loved; } protected Toil MakeSexToil() { - Toil get_loved = new Toil(); - get_loved.defaultCompleteMode = ToilCompleteMode.Never; - get_loved.socialMode = RandomSocialMode.Off; - get_loved.handlingFacing = true; - get_loved.tickAction = delegate + Toil get_loved = new Toil { + defaultCompleteMode = ToilCompleteMode.Never, + socialMode = RandomSocialMode.Off, + handlingFacing = true, + tickAction = delegate + { + } }; get_loved.AddEndCondition(new Func(() => { - if (parteners.Count <= 0) + if (parteners.Count == 0) { return JobCondition.Succeeded; } @@ -204,8 +201,7 @@ namespace RJWSexperience.Ideology /// copied from rjw /// public class JobDriver_DrugMasturabate : JobDriver_Masturbate - { - + { protected override IEnumerable MakeNewToils() { setup_ticks(); @@ -252,6 +248,4 @@ namespace RJWSexperience.Ideology }; } } - - } diff --git a/Source/IdeologyAddon/Rituals/JobGiver_GangbangConsensual.cs b/Source/IdeologyAddon/Rituals/JobGiver_GangbangConsensual.cs index dc6dc15..eae27e5 100644 --- a/Source/IdeologyAddon/Rituals/JobGiver_GangbangConsensual.cs +++ b/Source/IdeologyAddon/Rituals/JobGiver_GangbangConsensual.cs @@ -1,43 +1,36 @@ -using System; +using RimWorld; +using rjw; +using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Verse; using Verse.AI; -using Verse.AI.Group; -using RimWorld; -using rjw; namespace RJWSexperience.Ideology { - public class JobGiver_GangbangConsensual : ThinkNode_JobGiver - { - protected override Job TryGiveJob(Pawn pawn) - { - if (pawn.Drafted) return null; - DutyDef dutyDef = null; - PawnDuty duty = null; - if (pawn.mindState != null) - { - duty = pawn.mindState.duty; - dutyDef = duty.def; - } - else return null; + public class JobGiver_GangbangConsensual : ThinkNode_JobGiver + { + protected override Job TryGiveJob(Pawn pawn) + { + if (pawn.Drafted || pawn.mindState == null) + { + return null; + } - if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) - { - return null; - } + PawnDuty duty = pawn.mindState.duty; - Pawn target = duty.focusSecond.Pawn; + if (duty.def == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) + { + return null; + } - if (!pawn.CanReach(target, PathEndMode.ClosestTouch, Danger.None)) return null; + Pawn target = duty.focusSecond.Pawn; - return JobMaker.MakeJob(VariousDefOf.Gangbang, target); - } - } + if (!pawn.CanReach(target, PathEndMode.ClosestTouch, Danger.None)) + return null; + return JobMaker.MakeJob(RsiDefOf.Job.Gangbang, target); + } + } public class JobDriver_Gangbang : JobDriver_SexBaseInitiator { @@ -56,26 +49,28 @@ namespace RJWSexperience.Ideology this.FailOn(() => Partner.Drafted); yield return Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell); - Toil StartPartnerJob = new Toil(); - StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; - StartPartnerJob.socialMode = RandomSocialMode.Off; - StartPartnerJob.initAction = delegate + Toil StartPartnerJob = new Toil { - - var dri = Partner.jobs.curDriver as JobDriver_SexBaseRecieverRaped; - if (dri == null) - { - Job gettin_loved = JobMaker.MakeJob(VariousDefOf.GettinGangbang, pawn, Bed); - Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); + defaultCompleteMode = ToilCompleteMode.Instant, + socialMode = RandomSocialMode.Off, + initAction = delegate + { + if (!(Partner.jobs.curDriver is JobDriver_SexBaseRecieverRaped)) + { + Job gettin_loved = JobMaker.MakeJob(RsiDefOf.Job.GettinGangbang, pawn, Bed); + Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced); + } } }; yield return StartPartnerJob; - Toil SexToil = new Toil(); - SexToil.defaultCompleteMode = ToilCompleteMode.Never; - SexToil.defaultDuration = duration; - SexToil.handlingFacing = true; - SexToil.FailOn(() => Partner.CurJob.def != VariousDefOf.GettinGangbang); + Toil SexToil = new Toil + { + defaultCompleteMode = ToilCompleteMode.Never, + defaultDuration = duration, + handlingFacing = true + }; + SexToil.FailOn(() => Partner.CurJob.def != RsiDefOf.Job.GettinGangbang); SexToil.initAction = delegate { Start(); @@ -108,28 +103,30 @@ namespace RJWSexperience.Ideology } public class JobDriver_GangbangReceiver : JobDriver_SexBaseRecieverLoved - { + { protected override IEnumerable MakeNewToils() { setup_ticks(); parteners.Add(Partner);// add job starter, so this wont fail, before Initiator starts his job - Toil get_banged = new Toil(); - get_banged.defaultCompleteMode = ToilCompleteMode.Never; - get_banged.handlingFacing = true; - get_banged.initAction = delegate + Toil get_banged = new Toil { - pawn.pather.StopDead(); - pawn.jobs.curDriver.asleep = false; - }; - get_banged.tickAction = delegate - { - if ((parteners.Count > 0) && pawn.IsHashIntervalTick(ticks_between_hearts / parteners.Count) && pawn.IsHashIntervalTick(ticks_between_hearts)) - ThrowMetaIconF(pawn.Position, pawn.Map, FleckDefOf.Heart); + defaultCompleteMode = ToilCompleteMode.Never, + handlingFacing = true, + initAction = delegate + { + pawn.pather.StopDead(); + pawn.jobs.curDriver.asleep = false; + }, + tickAction = delegate + { + if ((parteners.Count > 0) && pawn.IsHashIntervalTick(ticks_between_hearts / parteners.Count) && pawn.IsHashIntervalTick(ticks_between_hearts)) + ThrowMetaIconF(pawn.Position, pawn.Map, FleckDefOf.Heart); + } }; get_banged.AddEndCondition(new Func(() => { - if (parteners.Count <= 0) + if (parteners.Count == 0) { return JobCondition.Succeeded; } @@ -148,12 +145,12 @@ namespace RJWSexperience.Ideology Partner.jobs.jobQueue.EnqueueFirst(tobed); } else if (pawn.HostileTo(Partner)) + { pawn.health.AddHediff(xxx.submitting); + } }); get_banged.socialMode = RandomSocialMode.Off; yield return get_banged; - } } - } diff --git a/Source/IdeologyAddon/Rituals/JobGiver_GangbangVictim.cs b/Source/IdeologyAddon/Rituals/JobGiver_GangbangVictim.cs index ce2ec72..092b00b 100644 --- a/Source/IdeologyAddon/Rituals/JobGiver_GangbangVictim.cs +++ b/Source/IdeologyAddon/Rituals/JobGiver_GangbangVictim.cs @@ -1,56 +1,46 @@ -using System; +using RimWorld; +using rjw; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Verse; using Verse.AI; -using Verse.AI.Group; -using RimWorld; -using rjw; - namespace RJWSexperience.Ideology { - public class JobGiver_GangbangVictim : ThinkNode_JobGiver - { - protected override Job TryGiveJob(Pawn pawn) - { - if (pawn.Drafted) return null; - DutyDef dutyDef = null; - PawnDuty duty = null; - if (pawn.mindState != null) - { - duty = pawn.mindState.duty; - dutyDef = duty.def; - } - else return null; + public class JobGiver_GangbangVictim : ThinkNode_JobGiver + { + protected override Job TryGiveJob(Pawn pawn) + { + if (pawn.Drafted || pawn.mindState == null) + { + return null; + } - if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) - { - return null; + PawnDuty duty = pawn.mindState.duty; + + if (duty.def == DutyDefOf.TravelOrLeave || !xxx.can_do_loving(pawn)) + { + return null; } Pawn target = duty.focusSecond.Pawn; - if (!pawn.CanReach(target, PathEndMode.ClosestTouch, Danger.None)) return null; - - return JobMaker.MakeJob(VariousDefOf.RapeVictim, target); - } - } + if (!pawn.CanReach(target, PathEndMode.ClosestTouch, Danger.None)) return null; + return JobMaker.MakeJob(RsiDefOf.Job.RapeVictim, target); + } + } /// /// copied from rjw /// public class JobDriver_RapeVictim : JobDriver_Rape { - public override bool TryMakePreToilReservations(bool errorOnFailed) - { + public override bool TryMakePreToilReservations(bool errorOnFailed) + { return true; - } + } - protected override IEnumerable MakeNewToils() + protected override IEnumerable MakeNewToils() { if (RJWSettings.DebugRape) ModLog.Message("" + this.GetType().ToString() + "::MakeNewToils() called"); setup_ticks(); @@ -64,25 +54,28 @@ namespace RJWSexperience.Ideology SexUtility.RapeTargetAlert(pawn, Partner); - Toil StartPartnerJob = new Toil(); - StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant; - StartPartnerJob.socialMode = RandomSocialMode.Off; - StartPartnerJob.initAction = delegate + Toil StartPartnerJob = new Toil { - var dri = Partner.jobs.curDriver as JobDriver_SexBaseRecieverRaped; - if (dri == null) + defaultCompleteMode = ToilCompleteMode.Instant, + socialMode = RandomSocialMode.Off, + initAction = delegate { - Job gettin_raped = JobMaker.MakeJob(PartnerJob, pawn); + if (!(Partner.jobs.curDriver is JobDriver_SexBaseRecieverRaped)) + { + Job gettin_raped = JobMaker.MakeJob(PartnerJob, pawn); - Partner.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null); + Partner.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null); + } } }; yield return StartPartnerJob; - Toil SexToil = new Toil(); - SexToil.defaultCompleteMode = ToilCompleteMode.Never; - SexToil.defaultDuration = duration; - SexToil.handlingFacing = true; + Toil SexToil = new Toil + { + defaultCompleteMode = ToilCompleteMode.Never, + defaultDuration = duration, + handlingFacing = true + }; SexToil.FailOn(() => Partner.CurJob.def != PartnerJob); SexToil.initAction = delegate { diff --git a/Source/IdeologyAddon/Rituals/LordJob_Rituals.cs b/Source/IdeologyAddon/Rituals/LordJob_Rituals.cs index e976d61..b496689 100644 --- a/Source/IdeologyAddon/Rituals/LordJob_Rituals.cs +++ b/Source/IdeologyAddon/Rituals/LordJob_Rituals.cs @@ -1,21 +1,15 @@ -using System; +using RimWorld; using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Verse; -using Verse.AI; -using RimWorld; - namespace RJWSexperience.Ideology { - public class LordJob_Ritual_Gangbang : LordJob_Ritual - { + public class LordJob_Ritual_Gangbang : LordJob_Ritual + { public LordJob_Ritual_Gangbang() { } - public LordJob_Ritual_Gangbang(string targetID ,TargetInfo selectedTarget, Precept_Ritual ritual, RitualObligation obligation, List allStages, RitualRoleAssignments assignments, Pawn organizer = null) : base(selectedTarget, ritual, obligation, allStages, assignments, organizer) - { + public LordJob_Ritual_Gangbang(string targetID, TargetInfo selectedTarget, Precept_Ritual ritual, RitualObligation obligation, List allStages, RitualRoleAssignments assignments, Pawn organizer = null) : base(selectedTarget, ritual, obligation, allStages, assignments, organizer) + { foreach (RitualRole ritualRole in assignments.AllRolesForReading) { if (ritualRole != null && ritualRole.id.Contains(targetID)) @@ -25,6 +19,5 @@ namespace RJWSexperience.Ideology } } } - } } diff --git a/Source/IdeologyAddon/Rituals/RitualRoles.cs b/Source/IdeologyAddon/Rituals/RitualRoles.cs index 0d26048..e7fb7fc 100644 --- a/Source/IdeologyAddon/Rituals/RitualRoles.cs +++ b/Source/IdeologyAddon/Rituals/RitualRoles.cs @@ -1,106 +1,101 @@ using RimWorld; -using Verse; using rjw; +using Verse; namespace RJWSexperience.Ideology { - public class RitualRole_RapeVictim : RitualRole - { - public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) - { - reason = null; - return false; - } - - public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) - { - reason = null; - if (CanBeVictim(p)) return true; - if (!skipReason) - { - reason = Keyed.RSVictimCondition; - } - return false; - } + public class RitualRole_RapeVictim : RitualRole + { + public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) + { + reason = null; + return false; + } - public static bool CanBeVictim(Pawn pawn) - { - if (pawn.IsPrisonerOfColony || pawn.IsSlaveOfColony) return true; - if (pawn.IsSubmissive()) return true; - if (pawn.IsDesignatedComfort() || (pawn.guilt != null && pawn.guilt.IsGuilty) || (pawn.apparel != null && pawn.apparel.PsychologicallyNude)) return true; - return false; - } - } + public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) + { + reason = null; + if (CanBeVictim(p)) return true; + if (!skipReason) + { + reason = Keyed.RSVictimCondition; + } + return false; + } - public class RitualRole_HumanBreedee : RitualRole - { - public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) - { - reason = null; - return false; - } + public static bool CanBeVictim(Pawn pawn) + { + if (pawn.IsPrisonerOfColony || pawn.IsSlaveOfColony) return true; + if (pawn.IsSubmissive()) return true; + if (pawn.IsDesignatedComfort() || (pawn.guilt != null && pawn.guilt.IsGuilty) || (pawn.apparel != null && pawn.apparel.PsychologicallyNude)) return true; + return false; + } + } - public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) - { - - reason = null; - if (!xxx.is_human(p)) - { - reason = Keyed.RSNotHuman; - return false; - } - if (CanBeBreedee(p)) return true; - if (!skipReason) - { - reason = Keyed.RSShouldCanFuck; - } - return false; - } + public class RitualRole_HumanBreedee : RitualRole + { + public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) + { + reason = null; + return false; + } - public static bool CanBeBreedee(Pawn pawn) - { - if (xxx.can_be_fucked(pawn)) return true; - return false; - } - } + public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) + { + reason = null; + if (!xxx.is_human(p)) + { + reason = Keyed.RSNotHuman; + return false; + } + if (CanBeBreedee(p)) return true; + if (!skipReason) + { + reason = Keyed.RSShouldCanFuck; + } + return false; + } - public class RitualRole_AnimalBreeder : RitualRole - { - public override bool Animal => true; + public static bool CanBeBreedee(Pawn pawn) => xxx.can_be_fucked(pawn); + } - public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) - { - reason = null; - return false; - } + public class RitualRole_AnimalBreeder : RitualRole + { + public override bool Animal => true; - public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) - { - reason = null; - if (!p.IsAnimal()) - { - reason = Keyed.RSNotAnimal; - return false; - } - if (CanBeBreeder(p, assignments?.Ritual)) return true; - if (!skipReason) - { - reason = Keyed.RSBreederCondition; - } - return false; - } + public override bool AppliesToRole(Precept_Role role, out string reason, Precept_Ritual ritual = null, Pawn pawn = null, bool skipReason = false) + { + reason = null; + return false; + } - public static bool CanBeBreeder(Pawn animal, Precept_Ritual precept) - { - if (precept != null && precept.ideo.HasPrecept(VariousDefOf.Bestiality_OnlyVenerated) && !precept.ideo.IsVeneratedAnimal(animal)) + public override bool AppliesToPawn(Pawn p, out string reason, TargetInfo selectedTarget, LordJob_Ritual ritual = null, RitualRoleAssignments assignments = null, Precept_Ritual precept = null, bool skipReason = false) + { + reason = null; + if (!p.IsAnimal()) + { + reason = Keyed.RSNotAnimal; + return false; + } + if (CanBeBreeder(p, assignments?.Ritual)) return true; + if (!skipReason) + { + reason = Keyed.RSBreederCondition; + } + return false; + } + + public static bool CanBeBreeder(Pawn animal, Precept_Ritual precept) + { + if (precept != null && precept.ideo.HasPrecept(RsiDefOf.Precept.Bestiality_OnlyVenerated) && !precept.ideo.IsVeneratedAnimal(animal)) { return false; } - if (!xxx.can_rape(animal)) return false; - return true; - } - - } - - + if (!xxx.can_rape(animal)) + { + return false; + } + return true; + } + } } diff --git a/Source/IdeologyAddon/RomanceChanceFactorHelpers.cs b/Source/IdeologyAddon/RomanceChanceFactorHelpers.cs new file mode 100644 index 0000000..6d970f3 --- /dev/null +++ b/Source/IdeologyAddon/RomanceChanceFactorHelpers.cs @@ -0,0 +1,89 @@ +using RimWorld; +using RJWSexperience.Ideology.Precepts; +using System.Collections.Generic; +using System.Linq; +using Verse; + +namespace RJWSexperience.Ideology +{ + public static class RomanceChanceFactorHelpers + { + /// + /// Default value for parent relation + /// + private const float parentRomanceChanceFactor = 0.03f; + + /// + /// Get ideology adjusted romanceChanceFactor + /// + public static float GetRomanceChanceFactor(Pawn pawn, Pawn partner) + { + float romanceChanceFactor = 1f; + + if (!pawn.relations.FamilyByBlood.Contains(partner)) + { + if (pawn.Ideo?.HasPrecept(RsiDefOf.Precept.Incestuos_IncestOnly) == true) + { + return parentRomanceChanceFactor; + } + else + { + return romanceChanceFactor; + } + } + + PreceptDef incestuousPrecept = pawn.Ideo?.PreceptsListForReading.Select(precept => precept.def).FirstOrFallback(def => def.issue == RsiDefOf.Issue.Incestuos); + IEnumerable relations = pawn.GetRelations(partner).Where(def => def.familyByBloodRelation); + foreach (PawnRelationDef relationDef in relations) + { + romanceChanceFactor *= GetRomanceChanceFactor(relationDef, incestuousPrecept); + } + + return romanceChanceFactor; + } + + /// + /// Get ideology adjusted romanceChanceFactor for the relation + /// + public static float GetRomanceChanceFactor(PawnRelationDef relationDef, PreceptDef incestuousPrecept) + { + if (incestuousPrecept == null) + { + return relationDef.romanceChanceFactor; + } + + var incestDefExt = incestuousPrecept.GetModExtension(); + + if (incestDefExt == null) + { + return relationDef.romanceChanceFactor; + } + + BloodRelationDegree relationDegree = RelationHelpers.GetBloodRelationDegree(relationDef); + + if (incestDefExt.TryGetRomanceChanceFactor(relationDegree, out var romanceChanceOverride)) + { + return romanceChanceOverride; + } + + return relationDef.romanceChanceFactor; + } + + [DebugAction("RJW Sexperience Ideology", "Show romanceChanceFactors", false, true, actionType = DebugActionType.Action, allowedGameStates = AllowedGameStates.Entry)] + public static void DisplayDebugTable() + { + IEnumerable incestuousPrecepts = DefDatabase + .AllDefsListForReading + .Where(def => def.issue == RsiDefOf.Issue.Incestuos); + + IEnumerable> preceptGetters = incestuousPrecepts + .Select(precept => new TableDataGetter(precept.defName,(PawnRelationDef rel) => GetRomanceChanceFactor(rel, precept))); + + var relName = new TableDataGetter("Relation Def", (PawnRelationDef rel) => rel.defName); + + TableDataGetter[] getters = (new List>() { relName }).Concat(preceptGetters).ToArray(); + + DebugTables.MakeTablesDialog(DefDatabase.AllDefsListForReading, getters); + } + } +} \ No newline at end of file diff --git a/Source/IdeologyAddon/RsiDefOf.cs b/Source/IdeologyAddon/RsiDefOf.cs new file mode 100644 index 0000000..d5b0cfa --- /dev/null +++ b/Source/IdeologyAddon/RsiDefOf.cs @@ -0,0 +1,65 @@ +using RimWorld; +using Verse; + +namespace RJWSexperience.Ideology +{ + public static class RsiDefOf + { + [DefOf] + public static class Job + { + public static readonly JobDef RapeVictim; + public static readonly JobDef Gangbang; + public static readonly JobDef GettinGangbang; + public static readonly JobDef DrugSex; + public static readonly JobDef GettinDrugSex; + public static readonly JobDef DrugMasturbate; + } + + [DefOf] + public static class Meme + { + public static readonly MemeDef Zoophile; + public static readonly MemeDef Rapist; + public static readonly MemeDef Necrophile; + } + + [DefOf] + public static class Issue + { + public static readonly IssueDef Incestuos; + } + + [DefOf] + public static class Precept + { + public static readonly PreceptDef Incestuos_IncestOnly; + public static readonly PreceptDef Bestiality_OnlyVenerated; + public static readonly PreceptDef BabyFaction_AlwaysFather; + public static readonly PreceptDef BabyFaction_AlwaysColony; + public static readonly PreceptDef Submissive_Male; + public static readonly PreceptDef Submissive_Female; + public static readonly PreceptDef ProselyzingByOrgasm; + } + + [DefOf] + public static class HistoryEvent + { + public static readonly HistoryEventDef RSI_SexWithAnimal; + public static readonly HistoryEventDef RSI_Raped; + public static readonly HistoryEventDef RSI_NonIncestuosMarriage; + public static readonly HistoryEventDef RSI_NonIncestuosSex; + public static readonly HistoryEventDef RSI_SexWithCorpse; + public static readonly HistoryEventDef RSI_VirginTaken; + public static readonly HistoryEventDef RSI_VirginStolen; + public static readonly HistoryEventDef RSI_TookVirgin; + public static readonly HistoryEventDef RSI_Masturbated; + } + + [DefOf] + public static class Hediff + { + [MayRequireBiotech] public static readonly HediffDef PregnantHuman; + } + } +} diff --git a/Source/IdeologyAddon/RsiHistoryEventDefOf.cs b/Source/IdeologyAddon/RsiHistoryEventDefOf.cs deleted file mode 100644 index 0155d66..0000000 --- a/Source/IdeologyAddon/RsiHistoryEventDefOf.cs +++ /dev/null @@ -1,18 +0,0 @@ -using RimWorld; - -namespace RJWSexperience.Ideology -{ - [DefOf] - public static class RsiHistoryEventDefOf - { - [MayRequireIdeology] public static readonly HistoryEventDef RSI_SexWithAnimal; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_Raped; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_NonIncestuosMarriage; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_NonIncestuosSex; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_SexWithCorpse; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_VirginTaken; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_VirginStolen; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_TookVirgin; - [MayRequireIdeology] public static readonly HistoryEventDef RSI_Masturbated; - } -} diff --git a/Source/IdeologyAddon/RsiMod.cs b/Source/IdeologyAddon/RsiMod.cs new file mode 100644 index 0000000..66dab60 --- /dev/null +++ b/Source/IdeologyAddon/RsiMod.cs @@ -0,0 +1,26 @@ +using UnityEngine; +using Verse; + +namespace RJWSexperience.Ideology +{ + public class RsiMod : Mod + { + public static RsiSettings Prefs { get; private set; } + + public RsiMod(ModContentPack content) : base(content) + { + Prefs = GetSettings(); + } + + public override string SettingsCategory() => Keyed.ModTitle; + + public override void DoSettingsWindowContents(Rect inRect) + { + Listing_Standard listmain = new Listing_Standard(); + listmain.Begin(inRect); + listmain.CheckboxLabeled(Keyed.PatchRomanceChanceFactor, ref Prefs.patchRomanceChanceFactor, Keyed.PatchRomanceChanceFactorTip); + listmain.CheckboxLabeled(Keyed.PatchIncestuousManualRomance, ref Prefs.patchIncestuousManualRomance, Keyed.PatchIncestuousManualRomanceTip); + listmain.End(); + } + } +} diff --git a/Source/IdeologyAddon/RsiSettings.cs b/Source/IdeologyAddon/RsiSettings.cs new file mode 100644 index 0000000..215b625 --- /dev/null +++ b/Source/IdeologyAddon/RsiSettings.cs @@ -0,0 +1,17 @@ +using Verse; + +namespace RJWSexperience.Ideology +{ + public class RsiSettings : ModSettings + { + public bool patchRomanceChanceFactor; + public bool patchIncestuousManualRomance; + + public override void ExposeData() + { + base.ExposeData(); + Scribe_Values.Look(ref patchRomanceChanceFactor, "patchSecondaryRomanceChanceFactor", true); + Scribe_Values.Look(ref patchIncestuousManualRomance, "patchIncestuousManualRomance", true); + } + } +} diff --git a/Source/IdeologyAddon/TwoPawnFilter.cs b/Source/IdeologyAddon/TwoPawnFilter.cs deleted file mode 100644 index 7c49f92..0000000 --- a/Source/IdeologyAddon/TwoPawnFilter.cs +++ /dev/null @@ -1,30 +0,0 @@ -using rjw; -using System.Diagnostics.CodeAnalysis; -using Verse; - -namespace RJWSexperience.Ideology -{ - public class TwoPawnFilter - { - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] - public SinglePawnFilter doer; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] - public SinglePawnFilter partner; - [SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")] - public RelationFilter relations; - - public bool Applies(Pawn pawn, Pawn partner) - { - if (doer?.Applies(pawn) == false) - return false; - - if (this.partner?.Applies(partner) == false) - return false; - - if (relations?.Applies(pawn, partner) == false) - return false; - - return true; - } - } -} diff --git a/Source/IdeologyAddon/VariousDefOf.cs b/Source/IdeologyAddon/VariousDefOf.cs deleted file mode 100644 index fb926ce..0000000 --- a/Source/IdeologyAddon/VariousDefOf.cs +++ /dev/null @@ -1,27 +0,0 @@ -using RimWorld; -using Verse; - -namespace RJWSexperience.Ideology -{ - [DefOf] - public static class VariousDefOf - { - public static readonly JobDef RapeVictim; - public static readonly JobDef Gangbang; - public static readonly JobDef GettinGangbang; - public static readonly JobDef DrugSex; - public static readonly JobDef GettinDrugSex; - public static readonly JobDef DrugMasturbate; - - [MayRequireIdeology] public static readonly MemeDef Zoophile; - [MayRequireIdeology] public static readonly MemeDef Rapist; - [MayRequireIdeology] public static readonly MemeDef Necrophile; - [MayRequireIdeology] public static readonly PreceptDef Bestiality_OnlyVenerated; - [MayRequireIdeology] public static readonly PreceptDef BabyFaction_AlwaysFather; - [MayRequireIdeology] public static readonly PreceptDef BabyFaction_AlwaysColony; - [MayRequireIdeology] public static readonly PreceptDef Submissive_Male; - [MayRequireIdeology] public static readonly PreceptDef Submissive_Female; - [MayRequireIdeology] public static readonly PreceptDef ProselyzingByOrgasm; - [MayRequireBiotech] public static readonly HediffDef PregnantHuman; - } -}