diff --git a/About/Manifest.xml b/About/Manifest.xml index 3e1adcf..40ce23d 100644 --- a/About/Manifest.xml +++ b/About/Manifest.xml @@ -1,7 +1,7 @@ RJW Sexperience - 1.0.1.11b + 1.0.2.0 diff --git a/Assemblies/RJWSexperience.dll b/Assemblies/RJWSexperience.dll index acb5320..4fc9b67 100644 Binary files a/Assemblies/RJWSexperience.dll and b/Assemblies/RJWSexperience.dll differ diff --git a/Assemblies/UnityEngine.TextCoreModule.dll b/Assemblies/UnityEngine.TextCoreModule.dll new file mode 100644 index 0000000..e13a54d Binary files /dev/null and b/Assemblies/UnityEngine.TextCoreModule.dll differ diff --git a/Assemblies/UnityEngine.TextRenderingModule.dll b/Assemblies/UnityEngine.TextRenderingModule.dll new file mode 100644 index 0000000..447239e Binary files /dev/null and b/Assemblies/UnityEngine.TextRenderingModule.dll differ diff --git a/Defs/JobDefs/Jobs_CleanSelfwithBucket.xml b/Defs/JobDefs/Jobs_CleanSelfwithBucket.xml new file mode 100644 index 0000000..7b8b8cd --- /dev/null +++ b/Defs/JobDefs/Jobs_CleanSelfwithBucket.xml @@ -0,0 +1,10 @@ + + + + + CleanSelfwithBucket + RJWSexperience.JobDriver_CleanSelfWithBucket + collecting cum + true + + \ No newline at end of file diff --git a/Defs/KeyBindings/KeyBindings_Sexperience.xml b/Defs/KeyBindings/KeyBindings_Sexperience.xml new file mode 100644 index 0000000..977f08a --- /dev/null +++ b/Defs/KeyBindings/KeyBindings_Sexperience.xml @@ -0,0 +1,8 @@ + + + + + OpenSexStatistics + + + diff --git a/Defs/Recipe_Surgery/Recipes_Surgery_Hymen.xml b/Defs/Recipe_Surgery/Recipes_Surgery_Hymen.xml new file mode 100644 index 0000000..07900d2 --- /dev/null +++ b/Defs/Recipe_Surgery/Recipes_Surgery_Hymen.xml @@ -0,0 +1,38 @@ + + + + Surgery_RestoreHymen + + Disguises as virgin. + RJWSexperience.Recipe_HymenSurgery + restoring hymen + Surgery + Recipe_Surgery + MedicalOperationSpeed + Medicine + 0.2 + 400 + false + +
  • Human
  • +
    + 100 + +
  • + + +
  • Medicine
  • + + + 1 + +
    + + +
  • Medicine
  • +
    +
    +
    + + +
    diff --git a/Defs/RecordDefs/Records_Sexperiences.xml b/Defs/RecordDefs/Records_Sexperiences.xml index c7c4057..731d4a9 100644 --- a/Defs/RecordDefs/Records_Sexperiences.xml +++ b/Defs/RecordDefs/Records_Sexperiences.xml @@ -4,7 +4,14 @@ NumofEatenCum - The number of times that i swalloed cum. + The number of times that i swallowed cum. + Int + + + + AmountofEatenCum + + The amount of cum that i swallowed. Int diff --git a/Defs/RecordDefs/Records_Sextypes.xml b/Defs/RecordDefs/Records_Sextypes.xml index 824b66f..2e98b49 100644 --- a/Defs/RecordDefs/Records_Sextypes.xml +++ b/Defs/RecordDefs/Records_Sextypes.xml @@ -44,7 +44,7 @@ - HadnjobCount + HandjobCount The number of times of handjob. Int diff --git a/Defs/ThingDefs/Items_Resource_Cum.xml b/Defs/ThingDefs/Items_Resource_Cum.xml index ffb7c64..d01cc7e 100644 --- a/Defs/ThingDefs/Items_Resource_Cum.xml +++ b/Defs/ThingDefs/Items_Resource_Cum.xml @@ -1,102 +1,47 @@ - - GatheredCum - - Gathered cum. - -
  • AnimalProductRaw
  • -
    - - Things/Item/GatheredCum - 1 - Graphic_StackCount - - true - - 0.1 - 0.1 - 0.01 - -5 - -1 - 0.00 - 60 - 0.1 - - - Fluid, AnimalProduct - DesperateOnlyForHumanlikes - AteCum - AteCum - -10 - -10 - -
  • - CumTolerance - 0.032 - true -
  • -
  • - 0.05 -
  • -
    -
    - -
  • - Cum - 0.050 - 0.8 - 0.1 - 1 - 30 -
  • -
    -
    - - - UsedCondom - - A condom filled with sperm. MMMM So good and tasty! + + GatheredCum + + Gathered cum. + +
  • AnimalProductRaw
  • +
    - Things/Item/UsedCondom + Things/Item/GatheredCum + 1 Graphic_StackCount - 50 - true - true - 0.0 - Industrial + true - -10 - 1 - 0.05 - 0.05 + 0.1 + 0.1 + 0.01 + -5 + -1 + 0.00 + 60 + 0.1 Fluid, AnimalProduct DesperateOnlyForHumanlikes - AteCum - AteCum - -
  • - CumTolerance - 0.032 - true -
  • -
  • - 0.05 -
  • -
    + AteCum + AteCum + -10 + -10 + +
  • + CumTolerance + 0.032 + true +
  • +
  • + 0.05 +
  • +
  • + - Item - Never - -
  • Exotic
  • - - Sellable - -
  • AnimalProductRaw
  • -
  • Cum @@ -109,6 +54,7 @@ + Cum diff --git a/Defs/TraitDefs/Traits_sex.xml b/Defs/TraitDefs/Traits_sex.xml index 4c023b5..d6361eb 100644 --- a/Defs/TraitDefs/Traits_sex.xml +++ b/Defs/TraitDefs/Traits_sex.xml @@ -7,17 +7,57 @@ 0.0
  • - - [PAWN_nameDef] has no experience. + BUGGED! MALE CANNOT HAS THIS TRAIT + damaged virgin + [PAWN_nameDef] never experienced. However, her hymen had damaged for some reason. + -1 + 0.05 - 0.1 + 0.2 - -
  • - Sex - -4 -
  • - + +
  • + Sex + -4 +
  • +
    + +
  • + + [PAWN_nameDef] never experienced. + 0 + + 0.2 + + +
  • + Sex + -4 +
  • + + +
  • + BUGGED! MALE CANNOT HAS THIS TRAIT + virgin? + [PAWN_nameDef] looks experienced. But the hymen is still threre. + 0.10 + 1 +
  • +
  • + BUGGED! MALE CANNOT HAS THIS TRAIT + virgin + [PAWN_nameDef] never experienced. + 2 + + 0.2 + + +
  • + Sex + -4 +
  • + + 0.20 diff --git a/Languages/English/Keyed/RJW_Sexperience.xml b/Languages/English/Keyed/RJW_Sexperience.xml index 12cc018..b7561f6 100644 --- a/Languages/English/Keyed/RJW_Sexperience.xml +++ b/Languages/English/Keyed/RJW_Sexperience.xml @@ -13,6 +13,48 @@ capable of sex is required Total gathered cum: {1} took {0}'s virginity. + Gather cums on body + Best sextype + Recent sextype + Sex partners + Cum swallowed + Selected Partner's Info + {0}: {1} times + Avg: {0} + Sex count: + Orgasms: + Recent Sex Partner + A recent sex partner. + First Sex Partner + The first sex partner. + Most Sex Partner + The most sex partner. + Best Sex Partner + The partner who had most satisfying sex. + Taken virgins + The number of partners who i taken first. + Total sex had + Total number of sex. + Raped: + Raped me: + Sex History + Sex Statistics + Partner List + Sexuality + Had been raped + Raped someone + Prefer Race + Bestiality + Interspecies + Normal + Necrophile + Gather cum + Sex skill + Cum addiction + Addicted to cum. + Cum addictiveness + More likely to get addicted to cum. + times Enable record randomizer Randomize pawn's sex records. @@ -37,4 +79,40 @@ + Vaginal + Anal + Oral + Masturbation + Double penetration + Boobjob + Handjob + Footjob + Fingering + Scissoring + Mutual masturbation + Fisting + Mech implant + Rimming + Fellatio + Cunnilingus + Sixtynine + + None + Asexual + Pansexual + Hetero + Mostly hetero + Bisexual, leaning hetero + Bisexual + Bisexual, leaning gay + Mostly gay + Gay + + + + lust + unknown + virgin + incest + \ No newline at end of file diff --git a/Languages/Korean/DefInjected/PawnRelationDefDefs/Translations_PawnRelationDefs.xml b/Languages/Korean/DefInjected/PawnRelationDefDefs/Translations_PawnRelationDefs.xml new file mode 100644 index 0000000..8ec5e25 --- /dev/null +++ b/Languages/Korean/DefInjected/PawnRelationDefDefs/Translations_PawnRelationDefs.xml @@ -0,0 +1,5 @@ + + + 사생아 + 사생아 + \ No newline at end of file diff --git a/Languages/Korean/Keyed/RJW_Sexperience.xml b/Languages/Korean/Keyed/RJW_Sexperience.xml index a542592..7daa25b 100644 --- a/Languages/Korean/Keyed/RJW_Sexperience.xml +++ b/Languages/Korean/Keyed/RJW_Sexperience.xml @@ -11,6 +11,8 @@ 사람이 아님 동물이 아님 성관계가 가능해야 합니다. + 수집한 정액 양: + {1}이(가) {0}의 아다를 뗐습니다. 기록 생성기 활성화 폰의 섹스기록을 무작위로 생성합니다. @@ -28,4 +30,8 @@ 활성화할 경우 노예는 강간당한 경험을 가집니다. 음란함 한계 음란함의 한계치를 설정합니다. 음란함의 절대값이 이 값에 가까워지거나 클수록, 음란함이 적게 변합니다. + 섹스가능 최소나이 + 섹스 가능한 최소나이를 설정합니다. 이 값은 RJW의 최소 나이 설정과 관계가 없고 기록을 생성하는데만 사용됩니다. + 동정 비율 + 나이 상관없이 동정일 확률을 설정합니다. \ No newline at end of file diff --git a/Patches/RJW_ThingDefs.xml b/Patches/RJW_ThingDefs.xml new file mode 100644 index 0000000..4df0f34 --- /dev/null +++ b/Patches/RJW_ThingDefs.xml @@ -0,0 +1,75 @@ + + + + + + Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers + + Defs/ThingDef[defName="UsedCondom"]/ingestible + + +
  • + CumTolerance + 0.032 + true +
  • +
  • + 0.05 +
  • +
  • + 5.2 +
  • +
    +
    +
    + + Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers + +
  • + CumTolerance + 0.032 + true +
  • +
  • + 0.05 +
  • +
  • + 5.2 +
  • +
    +
    +
    + + + Defs/ThingDef[defName="UsedCondom"]/comps + + Defs/ThingDef[defName="UsedCondom"] + + +
  • + Cum + 0.050 + 0.8 + 0.1 + 1 + 30 +
  • +
    +
    +
    + + Defs/ThingDef[defName="UsedCondom"]/comps + +
  • + Cum + 0.050 + 0.8 + 0.1 + 1 + 30 +
  • +
    +
    +
    + +
    \ No newline at end of file diff --git a/RJWSexperience/IdeologyAddon/Ideology/PreceptComp_SelftTookThoughtExtended.cs b/RJWSexperience/IdeologyAddon/Ideology/PreceptComp_SelftTookThoughtExtended.cs index 4520d5d..b3af6c2 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/PreceptComp_SelftTookThoughtExtended.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/PreceptComp_SelftTookThoughtExtended.cs @@ -19,16 +19,21 @@ namespace RJWSexperience.Ideology public const string Incestous = "[Incestuos]"; public const string BeenRaped = "[BeenRaped]"; public const string Rape = "[Rape]"; + public const string Spouse = "[Spouse]"; + public const string NotSpouse = "[NotSpouse]"; + public static string Gender(Pawn pawn) => "[" + pawn.gender + "]"; + + } public class PreceptComp_SelfTookThoughtTagged : PreceptComp_SelfTookMemoryThought { public string tag; public bool exclusive = false; - public RecordDef recordDef; - public float? recordoffset; + //public RecordDef recordDef; + //public float? recordoffset; public PreceptComp_SelfTookThoughtTagged() { } @@ -41,28 +46,28 @@ namespace RJWSexperience.Ideology if (tags.ContainAll(tag.Replace(" ","").Split(',')) ^ exclusive) { TookThought(ev, precept, canApplySelfTookThoughts); - if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) - { - AdjustRecord(pawn); - } + //if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) + //{ + // AdjustRecord(pawn); + //} } } else if (exclusive) { TookThought(ev, precept, canApplySelfTookThoughts); - if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) - { - AdjustRecord(pawn); - } + //if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) + //{ + // AdjustRecord(pawn); + //} } } else { TookThought(ev, precept, canApplySelfTookThoughts); - if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) - { - AdjustRecord(pawn); - } + //if (ev.args.TryGetArg(HistoryEventArgsNames.Doer, out Pawn pawn)) + //{ + // AdjustRecord(pawn); + //} } } @@ -99,13 +104,13 @@ namespace RJWSexperience.Ideology } - protected void AdjustRecord(Pawn pawn) - { - if (recordDef != null) - { - pawn.records.AddTo(recordDef, recordoffset ?? 1f); - } - } + //protected void AdjustRecord(Pawn pawn) + //{ + // if (recordDef != null) + // { + // pawn.records.AddTo(recordDef, recordoffset ?? 1f); + // } + //} } diff --git a/RJWSexperience/IdeologyAddon/Ideology/PreceptDef_RequirementExtended.cs b/RJWSexperience/IdeologyAddon/Ideology/PreceptDef_RequirementExtended.cs new file mode 100644 index 0000000..62e4321 --- /dev/null +++ b/RJWSexperience/IdeologyAddon/Ideology/PreceptDef_RequirementExtended.cs @@ -0,0 +1,19 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; + + + +namespace RJWSexperience.Ideology +{ + public class PreceptDef_RequirementExtended : PreceptDef + { + public List requiredAllMemes = new List(); + } + + +} diff --git a/RJWSexperience/IdeologyAddon/Ideology/RJW_Patch_Ideo.cs b/RJWSexperience/IdeologyAddon/Ideology/RJW_Patch_Ideo.cs index c7c7c38..f5a67f0 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/RJW_Patch_Ideo.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/RJW_Patch_Ideo.cs @@ -59,8 +59,8 @@ namespace RJWSexperience.Ideology public static float BestialityByPrecept(Ideo ideo) { - if (ideo.HasPrecept(VariousDefOf.Bestiality_Honorable)) return 0.3f; - else if (ideo.HasPrecept(VariousDefOf.Bestiality_OnlyVenerated)) return 0.6f; + if (ideo.HasPrecept(VariousDefOf.Bestiality_Honorable)) return 0.5f; + else if (ideo.HasPrecept(VariousDefOf.Bestiality_OnlyVenerated)) return 0.65f; else if (ideo.HasPrecept(VariousDefOf.Bestiality_Acceptable)) return 0.75f; else if (ideo.HasPrecept(VariousDefOf.Bestiality_Disapproved)) return 1.0f; else return 5f; @@ -78,13 +78,30 @@ namespace RJWSexperience.Ideology public static float RapeByPrecept(Ideo ideo) { - if (ideo.HasPrecept(VariousDefOf.Rape_Honorable)) return 0.25f; - else if (ideo.HasPrecept(VariousDefOf.Rape_Acceptable)) return 0.5f; + if (ideo.HasPrecept(VariousDefOf.Rape_Honorable)) return 0.5f; + else if (ideo.HasPrecept(VariousDefOf.Rape_Acceptable)) return 0.75f; else if (ideo.HasPrecept(VariousDefOf.Rape_Disapproved)) return 1.0f; else return 3f; } } + [HarmonyPatch(typeof(ThinkNode_ChancePerHour_Necro), "MtbHours")] + public static class RJW_Patch_ThinkNode_ChancePerHour_Necro + { + public static void Postfix(Pawn pawn, ref float __result) + { + Ideo ideo = pawn.Ideo; + if (ideo != null) __result *= NecroByPrecept(ideo); // ideo is null if don't have dlc + } + + public static float NecroByPrecept(Ideo ideo) + { + if (ideo.HasPrecept(VariousDefOf.Necrophilia_Approved)) return 0.5f; + else if (ideo.HasPrecept(VariousDefOf.Necrophilia_Acceptable)) return 0.75f; + else if (ideo.HasPrecept(VariousDefOf.Necrophilia_Disapproved)) return 1.0f; + else return 8f; + } + } [HarmonyPatch(typeof(xxx), "is_rapist")] public static class RJW_Patch_is_rapist @@ -371,6 +388,19 @@ namespace RJWSexperience.Ideology } } + [HarmonyPatch(typeof(PawnDesignations_Comfort), "UpdateCanDesignateComfort")] + public static class RJW_PatchUpdateCanDesignateComfort + { + public static void Postfix(Pawn pawn, ref bool __result) + { + if (pawn.IsSubmissive()) + { + SaveStorage.DataStore.GetPawnData(pawn).CanDesignateComfort = true; + __result = true; + } + } + } + [HarmonyPatch(typeof(Hediff_BasePregnancy), "PostBirth")] public static class RJW_Patch_PostBirth { diff --git a/RJWSexperience/IdeologyAddon/Ideology/Rimworld_Patch.cs b/RJWSexperience/IdeologyAddon/Ideology/Rimworld_Patch.cs index 934969c..a4520a0 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/Rimworld_Patch.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/Rimworld_Patch.cs @@ -55,5 +55,36 @@ namespace RJWSexperience.Ideology } } + [HarmonyPatch(typeof(IdeoFoundation), "CanAdd")] + public static class Rimworld_Patch_IdeoFoundation + { + public static void Postfix(PreceptDef precept, bool checkDuplicates, ref IdeoFoundation __instance, ref AcceptanceReport __result) + { + if (precept is PreceptDef_RequirementExtended) + { + PreceptDef_RequirementExtended def = precept as PreceptDef_RequirementExtended; + if (!def.requiredAllMemes.NullOrEmpty()) + { + for (int i=0; i< def.requiredAllMemes.Count; i++) + { + if (!__instance.ideo.memes.Contains(def.requiredAllMemes[i])) + { + List report = new List(); + foreach (MemeDef meme in def.requiredAllMemes) report.Add(meme.LabelCap); + + __result = new AcceptanceReport("RequiresMeme".Translate() + ": " + report.ToCommaList()); + return; + } + } + } + + } + + + } + + + + } } diff --git a/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangConsensual.cs b/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangConsensual.cs new file mode 100644 index 0000000..56bf498 --- /dev/null +++ b/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangConsensual.cs @@ -0,0 +1,162 @@ +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; + + if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_fuck(pawn)) + { + return null; + } + + Pawn target = duty.focusSecond.Pawn; + + if (!pawn.CanReach(target, PathEndMode.ClosestTouch, Danger.None)) return null; + + return JobMaker.MakeJob(VariousDefOf.Gangbang, target); + } + } + + + public class JobDriver_Gangbang : JobDriver_SexBaseInitiator + { + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return true; + } + + protected override IEnumerable MakeNewToils() + { + //ModLog.Message("" + this.GetType().ToString() + "::MakeNewToils() called"); + setup_ticks(); + + this.FailOnDespawnedNullOrForbidden(iTarget); + this.FailOn(() => Partner == null); + this.FailOn(() => pawn.Drafted); + 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 + { + + 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); + } + }; + yield return StartPartnerJob; + + Toil SexToil = new Toil(); + SexToil.defaultCompleteMode = ToilCompleteMode.Never; + SexToil.defaultDuration = duration; + SexToil.handlingFacing = true; + SexToil.FailOn(() => Partner.CurJob.def != VariousDefOf.GettinGangbang); + SexToil.initAction = delegate + { + Start(); + Sexprops.usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner); + }; + SexToil.AddPreTickAction(delegate + { + SexTick(pawn, Partner); + SexUtility.reduce_rest(Partner, 1); + SexUtility.reduce_rest(pawn, 2); + if (ticks_left <= 0) + ReadyForNextToil(); + }); + SexToil.AddFinishAction(delegate + { + End(); + }); + yield return SexToil; + + yield return new Toil + { + initAction = delegate + { + // Trying to add some interactions and social logs + SexUtility.ProcessSex(Sexprops); + }, + defaultCompleteMode = ToilCompleteMode.Instant + }; + } + } + + 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 + { + pawn.pather.StopDead(); + pawn.jobs.curDriver.asleep = false; + }; + get_banged.tickAction = delegate + { + if ((parteners.Count > 0) && (pawn.IsHashIntervalTick(ticks_between_hearts / parteners.Count))) + if (pawn.IsHashIntervalTick(ticks_between_hearts)) + ThrowMetaIconF(pawn.Position, pawn.Map, FleckDefOf.Heart); + }; + get_banged.AddEndCondition(new Func(() => + { + if (parteners.Count <= 0) + { + return JobCondition.Succeeded; + } + return JobCondition.Ongoing; + })); + get_banged.AddFinishAction(delegate + { + if (xxx.is_human(pawn)) + pawn.Drawer.renderer.graphics.ResolveApparelGraphics(); + GlobalTextureAtlasManager.TryMarkPawnFrameSetDirty(pawn); + + if (Bed != null && pawn.Downed) + { + Job tobed = JobMaker.MakeJob(JobDefOf.Rescue, pawn, Bed); + tobed.count = 1; + Partner.jobs.jobQueue.EnqueueFirst(tobed); + //Log.Message(xxx.get_pawnname(Initiator) + ": job tobed:" + tobed); + } + else if (pawn.HostileTo(Partner)) + pawn.health.AddHediff(xxx.submitting); + }); + get_banged.socialMode = RandomSocialMode.Off; + yield return get_banged; + + } + } + +} diff --git a/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangVictim.cs b/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangVictim.cs index 35335bd..44ad646 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangVictim.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/Rituals/JobGiver_GangbangVictim.cs @@ -26,7 +26,7 @@ namespace RJWSexperience.Ideology } else return null; - if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_rape(pawn, true)) + if (dutyDef == DutyDefOf.TravelOrLeave || !xxx.can_fuck(pawn)) { return null; } @@ -57,7 +57,6 @@ namespace RJWSexperience.Ideology var PartnerJob = xxx.gettin_raped; this.FailOnDespawnedNullOrForbidden(iTarget); - //this.FailOn(() => (!Partner.health.capacities.CanBeAwake) || (!comfort_prisoners.is_designated(Partner)));//this is wrong this.FailOn(() => Partner == null); this.FailOn(() => pawn.Drafted); this.FailOn(() => Partner.Drafted); diff --git a/RJWSexperience/IdeologyAddon/Ideology/Rituals/LordJob_Rituals.cs b/RJWSexperience/IdeologyAddon/Ideology/Rituals/LordJob_Rituals.cs index 832f809..e976d61 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/Rituals/LordJob_Rituals.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/Rituals/LordJob_Rituals.cs @@ -14,11 +14,11 @@ namespace RJWSexperience.Ideology { public LordJob_Ritual_Gangbang() { } - public LordJob_Ritual_Gangbang(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("victim")) + if (ritualRole != null && ritualRole.id.Contains(targetID)) { Pawn item = assignments.FirstAssignedPawn(ritualRole); pawnsDeathIgnored.Add(item); diff --git a/RJWSexperience/IdeologyAddon/Ideology/Rituals/RitualBehaviorWorkers.cs b/RJWSexperience/IdeologyAddon/Ideology/Rituals/RitualBehaviorWorkers.cs index 6d00196..ec831f2 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/Rituals/RitualBehaviorWorkers.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/Rituals/RitualBehaviorWorkers.cs @@ -23,17 +23,27 @@ namespace RJWSexperience.Ideology { WorkGiver_Warden_TakeToBed.TryTakePrisonerToBed(pawn, warden); pawn.guest.WaitInsteadOfEscapingFor(1250); - } } protected override LordJob CreateLordJob(TargetInfo target, Pawn organizer, Precept_Ritual ritual, RitualObligation obligation, RitualRoleAssignments assignments) { - return new LordJob_Ritual_Gangbang(target, ritual, obligation, def.stages, assignments, organizer); + return new LordJob_Ritual_Gangbang("victim", target, ritual, obligation, def.stages, assignments, organizer); } - } + public class RitualBehaviorWorker_Gangbang_Consensual : RitualBehaviorWorker + { + public RitualBehaviorWorker_Gangbang_Consensual() { } + + public RitualBehaviorWorker_Gangbang_Consensual(RitualBehaviorDef def) : base(def) { } + + protected override LordJob CreateLordJob(TargetInfo target, Pawn organizer, Precept_Ritual ritual, RitualObligation obligation, RitualRoleAssignments assignments) + { + return new LordJob_Ritual_Gangbang("initiator", target, ritual, obligation, def.stages, assignments, organizer); + } + } + public class RitualStage_InteractWithVictim : RitualStage { public override TargetInfo GetSecondFocus(LordJob_Ritual ritual) @@ -49,5 +59,11 @@ namespace RJWSexperience.Ideology return ritual.assignments.AssignedPawns("victim").FirstOrDefault(); } } - + public class RitualStage_InteractWithInitiator : RitualStage + { + public override TargetInfo GetSecondFocus(LordJob_Ritual ritual) + { + return ritual.assignments.AssignedPawns("initiator").FirstOrDefault(); + } + } } diff --git a/RJWSexperience/IdeologyAddon/Ideology/Sexperience_Patch.cs b/RJWSexperience/IdeologyAddon/Ideology/Sexperience_Patch.cs new file mode 100644 index 0000000..7a5433e --- /dev/null +++ b/RJWSexperience/IdeologyAddon/Ideology/Sexperience_Patch.cs @@ -0,0 +1,75 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using rjw; +using RJWSexperience; +using Verse; +using RimWorld; + + +namespace RJWSexperience.Ideology +{ + [HarmonyPatch(typeof(RJWUtility), "ThrowVirginHIstoryEvent")] + public static class Sexperience_Patch_ThrowVirginHIstoryEvent + { + public static void Postfix(Pawn pawn, Pawn partner, SexProps props, int degree) + { + string tag = ""; + if (props.isRape) + { + if (pawn == props.pawn && props.isRapist) tag += HETag.Rape; + else tag += HETag.BeenRaped; + } + if (!pawn.relations.DirectRelationExists(PawnRelationDefOf.Spouse, partner)) + { + tag += HETag.NotSpouse; + } + + + if (pawn.gender == Gender.Male) + { + if (degree > 1) Find.HistoryEventsManager.RecordEvent(VariousDefOf.Virgin_TakenM.TaggedEvent(pawn, tag + HETag.Gender(pawn), partner)); + Find.HistoryEventsManager.RecordEvent(VariousDefOf.Virgin_TookM.TaggedEvent(partner, tag + HETag.Gender(pawn), pawn)); + } + else + { + if (degree > 1) Find.HistoryEventsManager.RecordEvent(VariousDefOf.Virgin_TakenF.TaggedEvent(pawn, tag + HETag.Gender(pawn), partner)); + Find.HistoryEventsManager.RecordEvent(VariousDefOf.Virgin_TookF.TaggedEvent(partner, tag + HETag.Gender(pawn), pawn)); + } + + + + } + } + + [HarmonyPatch(typeof(Utility), "IsIncest")] + public static class Sexperience_Patch_IsIncest + { + public static bool Prefix(Pawn pawn, Pawn otherpawn, ref bool __result) + { + __result = IsIncest(pawn, otherpawn); + return false; + } + + private static bool IsIncest(Pawn pawn, Pawn partner) + { + IEnumerable relations = pawn.GetRelations(partner); + Ideo ideo = pawn.Ideo; + bool wide = false; + if (ideo != null) wide = ideo.HasPrecept(VariousDefOf.Incestuos_Disapproved_CloseOnly); + if (!relations.EnumerableNullOrEmpty()) foreach (PawnRelationDef relation in relations) + { + if (wide) + { + if (relation.incestOpinionOffset < 0) return true; + } + else if (relation.familyByBloodRelation) return true; + } + return false; + } + } + +} diff --git a/RJWSexperience/IdeologyAddon/Ideology/Utility.cs b/RJWSexperience/IdeologyAddon/Ideology/Utility.cs index 398b4ef..9f678b2 100644 --- a/RJWSexperience/IdeologyAddon/Ideology/Utility.cs +++ b/RJWSexperience/IdeologyAddon/Ideology/Utility.cs @@ -10,25 +10,9 @@ using UnityEngine; namespace RJWSexperience.Ideology { - public static class Utility + public static class IdeoUtility { - public static bool IsIncest(this Pawn pawn, Pawn partner) - { - IEnumerable relations = pawn.GetRelations(partner); - Ideo ideo = pawn.Ideo; - bool wide = false; - if (ideo != null) wide = ideo.HasPrecept(VariousDefOf.Incestuos_Disapproved_CloseOnly); - if (!relations.EnumerableNullOrEmpty()) foreach (PawnRelationDef relation in relations) - { - if (wide) - { - if (relation.incestOpinionOffset < 0) return true; - } - else if (relation.familyByBloodRelation) return true; - } - return false; - } public static bool IsSubmissive(this Pawn pawn) { diff --git a/RJWSexperience/IdeologyAddon/IdeologyAddon.csproj b/RJWSexperience/IdeologyAddon/IdeologyAddon.csproj index f8b8004..e87fbed 100644 --- a/RJWSexperience/IdeologyAddon/IdeologyAddon.csproj +++ b/RJWSexperience/IdeologyAddon/IdeologyAddon.csproj @@ -95,9 +95,12 @@ + + + diff --git a/RJWSexperience/IdeologyAddon/VariousDefOf.cs b/RJWSexperience/IdeologyAddon/VariousDefOf.cs index bbb4695..a8b11d5 100644 --- a/RJWSexperience/IdeologyAddon/VariousDefOf.cs +++ b/RJWSexperience/IdeologyAddon/VariousDefOf.cs @@ -11,6 +11,8 @@ namespace RJWSexperience.Ideology public static class VariousDefOf { public static readonly JobDef RapeVictim = DefDatabase.GetNamed("RapeVictim"); + public static readonly JobDef Gangbang = DefDatabase.GetNamed("Gangbang"); + public static readonly JobDef GettinGangbang = DefDatabase.GetNamed("GettinGangbang"); public static readonly JobDef DrugSex = DefDatabase.GetNamed("DrugSex"); public static readonly JobDef GettinDrugSex = DefDatabase.GetNamed("GettinDrugSex"); public static readonly JobDef DrugMasturbate = DefDatabase.GetNamed("DrugMasturbate"); @@ -34,6 +36,10 @@ namespace RJWSexperience.Ideology [MayRequireIdeology] public static readonly HistoryEventDef PromiscuousSex = DefDatabase.GetNamed("PromiscuousSex"); [MayRequireIdeology] public static readonly HistoryEventDef Incestuos_Marriage = DefDatabase.GetNamed("Incestuos_Marriage"); [MayRequireIdeology] public static readonly HistoryEventDef SexWithCorpse = DefDatabase.GetNamed("SexWithCorpse"); + [MayRequireIdeology] public static readonly HistoryEventDef Virgin_TakenF = DefDatabase.GetNamed("Virgin_TakenF"); + [MayRequireIdeology] public static readonly HistoryEventDef Virgin_TakenM = DefDatabase.GetNamed("Virgin_TakenM"); + [MayRequireIdeology] public static readonly HistoryEventDef Virgin_TookF = DefDatabase.GetNamed("Virgin_TookF"); + [MayRequireIdeology] public static readonly HistoryEventDef Virgin_TookM = DefDatabase.GetNamed("Virgin_TookM"); [MayRequireIdeology] public static readonly PreceptDef Bestiality_Abhorrent = DefDatabase.GetNamed("Bestiality_Abhorrent"); [MayRequireIdeology] public static readonly PreceptDef Bestiality_Horrible = DefDatabase.GetNamed("Bestiality_Horrible"); [MayRequireIdeology] public static readonly PreceptDef Bestiality_Disapproved = DefDatabase.GetNamed("Bestiality_Disapproved"); diff --git a/RJWSexperience/RJWSexperience/Buildings.cs b/RJWSexperience/RJWSexperience/Building_Cumbucket.cs similarity index 82% rename from RJWSexperience/RJWSexperience/Buildings.cs rename to RJWSexperience/RJWSexperience/Building_Cumbucket.cs index e913598..a1f3586 100644 --- a/RJWSexperience/RJWSexperience/Buildings.cs +++ b/RJWSexperience/RJWSexperience/Building_Cumbucket.cs @@ -5,6 +5,7 @@ using System.Text; using System.Threading.Tasks; using Verse; using RimWorld; +using rjw; namespace RJWSexperience { @@ -43,7 +44,11 @@ namespace RJWSexperience int num = (int)storedcum; cum.stackCount = num; - if (cum.stackCount > 0) GenPlace.TryPlaceThing(cum, PositionHeld, Map, ThingPlaceMode.Direct, out Thing res); + if (cum.stackCount > 0) + { + if (!GenPlace.TryPlaceThing(cum, PositionHeld, Map, ThingPlaceMode.Direct, out Thing res)) + FilthMaker.TryMakeFilth(PositionHeld, Map, VariousDefOf.FilthCum, num); + } storedcum -= num; } diff --git a/RJWSexperience/RJWSexperience/Configurations.cs b/RJWSexperience/RJWSexperience/Configurations.cs index a10122d..6662846 100644 --- a/RJWSexperience/RJWSexperience/Configurations.cs +++ b/RJWSexperience/RJWSexperience/Configurations.cs @@ -36,6 +36,8 @@ namespace RJWSexperience public static float MinSexablePercent = MinSexablePercentDefault; public static float VirginRatio = VirginRatioDefault; + public static bool SelectionLocked = false; + public static void ResettoDefault() { MaxLustDeviation = MaxInitialLustDefault; @@ -62,6 +64,7 @@ namespace RJWSexperience Scribe_Values.Look(ref LustLimit, "LustLimit", LustLimit, true); Scribe_Values.Look(ref MinSexablePercent, "MinSexablePercent", MinSexablePercent, true); Scribe_Values.Look(ref VirginRatio, "VirginRatio", VirginRatio, true); + Scribe_Values.Look(ref SelectionLocked, "SelectionLocked", SelectionLocked, true); base.ExposeData(); } } diff --git a/RJWSexperience/RJWSexperience/DebugAction.cs b/RJWSexperience/RJWSexperience/DebugAction.cs index f2610aa..901b5ac 100644 --- a/RJWSexperience/RJWSexperience/DebugAction.cs +++ b/RJWSexperience/RJWSexperience/DebugAction.cs @@ -11,6 +11,25 @@ namespace RJWSexperience { public static class DebugToolsSexperience { + [DebugAction("RJW Sexperience", "Reset pawn's record", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.PlayingOnMap)] + private static void ResetRecords(Pawn p) + { + Trait virgin = p.story?.traits?.GetTrait(VariousDefOf.Virgin); + if (virgin != null) p.story.traits.RemoveTrait(virgin); + p.ResetRecord(true); + p.ResetRecord(false); + MoteMaker.ThrowText(p.TrueCenter(), p.Map, "Records resetted!"); + } + + [DebugAction("RJW Sexperience", "Reset pawn's record(virgin)", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.PlayingOnMap)] + private static void ResetRecordsZero(Pawn p) + { + p.ResetRecord(true); + p.AddVirginTrait(); + MoteMaker.ThrowText(p.TrueCenter(), p.Map, "Records resetted!\nVirginified!"); + } + + [DebugAction("RJW Sexperience", "Reset lust", false, false, actionType = DebugActionType.ToolMapForPawns, allowedGameStates = AllowedGameStates.PlayingOnMap)] private static void ResetLust(Pawn p) { diff --git a/RJWSexperience/RJWSexperience/IngestionOutcomeDoers.cs b/RJWSexperience/RJWSexperience/IngestionOutcomeDoers.cs new file mode 100644 index 0000000..6b44141 --- /dev/null +++ b/RJWSexperience/RJWSexperience/IngestionOutcomeDoers.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using rjw; +using RimWorld; +using Verse; + + + +namespace RJWSexperience +{ + public class CumOutcomeDoers : IngestionOutcomeDoer + { + public float unitAmount = 1.0f; + + protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested) + { + pawn.AteCum(ingested.stackCount * unitAmount); + } + } +} diff --git a/RJWSexperience/RJWSexperience/JobDrivers.cs b/RJWSexperience/RJWSexperience/JobDrivers.cs new file mode 100644 index 0000000..a0bcd5a --- /dev/null +++ b/RJWSexperience/RJWSexperience/JobDrivers.cs @@ -0,0 +1,108 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using Verse.AI; +using RimWorld; +using rjw; + +namespace RJWSexperience +{ + public class JobGiver_UseBucket : ThinkNode_JobGiver + { + protected override Job TryGiveJob(Pawn pawn) + { + throw new NotImplementedException(); + } + + + } + + public class JobDriver_CleanSelfWithBucket : JobDriver + { + const int UNITTIME = 240;//ticks - 120 = 2 real seconds, 3 in-game minutes + protected float progress = 0; + protected float severitycache = 1; + protected Hediff hediffcache; + protected float CleaningTime + { + get + { + return severitycache * UNITTIME; + } + } + + + protected Building_CumBucket Bucket => TargetB.Thing as Building_CumBucket; + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + return pawn.Reserve(pawn, job, 1, -1, null, errorOnFailed); + } + + protected override IEnumerable MakeNewToils() + { + + this.FailOn(delegate + { + List hediffs = pawn.health.hediffSet.hediffs; + return !hediffs.Exists(x => x.def == RJW_SemenoOverlayHediffDefOf.Hediff_Bukkake); + }); + yield return Toils_Goto.GotoThing(TargetIndex.B, PathEndMode.ClosestTouch); + Toil cleaning = new Toil(); + cleaning.initAction = CleaningInit; + cleaning.tickAction = CleaningTick; + cleaning.AddFinishAction(Finish); + cleaning.defaultCompleteMode = ToilCompleteMode.Never; + cleaning.WithProgressBar(TargetIndex.A, () => progress/CleaningTime); + + yield return cleaning; + yield break; + } + + protected void CleaningInit() + { + hediffcache = pawn.health.hediffSet.hediffs.Find(x => (x.def == RJW_SemenoOverlayHediffDefOf.Hediff_Semen || x.def == RJW_SemenoOverlayHediffDefOf.Hediff_InsectSpunk)); + if (hediffcache == null) + { + pawn.jobs.EndCurrentJob(JobCondition.Succeeded); + } + else + { + progress = 0; + severitycache = hediffcache.Severity; + } + } + + protected void CleaningTick() + { + progress += 1; + if (progress > CleaningTime) + { + Cleaned(); + } + } + + protected void Cleaned() + { + if (hediffcache != null) + { + float cumamount = hediffcache.Severity * 10; + hediffcache.Severity = 0; + Bucket.AddCum(cumamount); + } + CleaningInit(); + } + + protected void Finish() + { + if (pawn.CurJobDef == JobDefOf.Wait_MaintainPosture) + { + pawn.jobs.EndCurrentJob(JobCondition.InterruptForced); + } + } + + } +} diff --git a/RJWSexperience/RJWSexperience/Keyed.cs b/RJWSexperience/RJWSexperience/Keyed.cs index 530dfb7..d3f7bac 100644 --- a/RJWSexperience/RJWSexperience/Keyed.cs +++ b/RJWSexperience/RJWSexperience/Keyed.cs @@ -5,7 +5,8 @@ using System.Text; using System.Threading.Tasks; using Verse; using RimWorld; - +using rjw; +using UnityEngine; namespace RJWSexperience { @@ -14,7 +15,9 @@ namespace RJWSexperience public static string LustStatFactor(string value) => "LustStatFactor".Translate(value); public static string SlaveStatFactor(string value) => "SlaveStatFactor".Translate(value); public static string MemeStatFactor(string value) => "MemeStatFactor".Translate(value); - public static string RS_LostVirgin(string pawn, string partner) => "RS_LostVirgin".Translate(pawn,partner); + public static string RS_LostVirgin(string pawn, string partner) => "RS_LostVirgin".Translate(pawn.Colorize(Color.yellow),partner.Colorize(Color.yellow)); + public static string RS_Sex_Info(string sextype, string sexcount) => "RS_Sex_Info".Translate(sextype, sexcount); + public static string RS_SAT_AVG(string avgsat) => "RS_SAT_AVG".Translate(avgsat); public static readonly string Mod_Title = "RS_Mod_Title".Translate(); public static readonly string SlaveStatFactorDefault = "SlaveStatFactorDefault".Translate(); @@ -24,6 +27,50 @@ namespace RJWSexperience public static readonly string RSNotAnimal = "RSNotAnimal".Translate(); public static readonly string RSShouldCanFuck = "RSShouldCanFuck".Translate(); public static readonly string RSTotalGatheredCum = "RSTotalGatheredCum".Translate(); + public static readonly string RS_FloatMenu_CleanSelf = "RS_FloatMenu_CleanSelf".Translate(); + public static readonly string RS_Best_Sextype = "RS_Best_Sextype".Translate(); + public static readonly string RS_Recent_Sextype = "RS_Recent_Sextype".Translate(); + public static readonly string RS_Sex_Partners = "RS_Sex_Partners".Translate(); + public static readonly string RS_Cum_Swallowed = "RS_Cum_Swallowed".Translate(); + public static readonly string RS_Selected_Partner = "RS_Selected_Partner".Translate(); + public static readonly string RS_Sex_Count = "RS_Sex_Count".Translate(); + public static readonly string RS_Orgasms = "RS_Orgasms".Translate(); + public static readonly string RS_Recent_Sex_Partner = "RS_Recent_Sex_Partner".Translate(); + public static readonly string RS_First_Sex_Partner = "RS_First_Sex_Partner".Translate(); + public static readonly string RS_Most_Sex_Partner = "RS_Most_Sex_Partner".Translate(); + public static readonly string RS_Best_Sex_Partner = "RS_Best_Sex_Partner".Translate(); + public static readonly string RS_VirginsTaken = "RS_VirginsTaken".Translate(); + public static readonly string RS_TotalSexHad = "RS_TotalSexHad".Translate(); + public static readonly string RS_Recent_Sex_Partner_ToolTip = "RS_Recent_Sex_Partner_ToolTip".Translate(); + public static readonly string RS_First_Sex_Partner_ToolTip = "RS_First_Sex_Partner_ToolTip".Translate(); + public static readonly string RS_Most_Sex_Partner_ToolTip = "RS_Most_Sex_Partner_ToolTip".Translate(); + public static readonly string RS_Best_Sex_Partner_ToolTip = "RS_Best_Sex_Partner_ToolTip".Translate(); + public static readonly string RS_VirginsTaken_ToolTip = "RS_VirginsTaken_ToolTip".Translate(); + public static readonly string RS_TotalSexHad_ToolTip = "RS_TotalSexHad_ToolTip".Translate(); + public static readonly string RS_Raped = "RS_Raped".Translate(); + public static readonly string RS_RapedMe = "RS_RapedMe".Translate(); + public static readonly string RS_Sex_History = "RS_Sex_History".Translate(); + public static readonly string RS_Statistics = "RS_Statistics".Translate(); + public static readonly string RS_PartnerList = "RS_PartnerList".Translate(); + public static readonly string RS_Sexuality = "RS_Sexuality".Translate(); + public static readonly string RS_BeenRaped = "RS_BeenRaped".Translate(); + public static readonly string RS_RapedSomeone = "RS_RapedSomeone".Translate(); + public static readonly string RS_PreferRace = "RS_PreferRace".Translate(); + public static readonly string Lust = "Lust".Translate(); + public static readonly string Unknown = "Unknown".Translate(); + public static readonly string Incest = "Incest".Translate(); + public static readonly string None = "None".Translate(); + public static readonly string RS_Bestiality = "RS_Bestiality".Translate(); + public static readonly string RS_Interspecies = "RS_Interspecies".Translate(); + public static readonly string RS_Normal = "RS_Normal".Translate(); + public static readonly string RS_Necrophile = "RS_Necrophile".Translate(); + public static readonly string RS_GatherCum = "RS_GatherCum".Translate(); + public static readonly string RS_SexSkill = "RS_SexSkill".Translate(); + public static readonly string RS_CumAddiction = "RS_CumAddiction".Translate(); + public static readonly string RS_CumAddiction_Tooltip = "RS_CumAddiction_Tooltip".Translate(); + public static readonly string RS_CumAddictiveness = "RS_CumAddictiveness".Translate(); + public static readonly string RS_CumAddictiveness_Tooltip = "RS_CumAddictiveness_Tooltip".Translate(); + public static readonly string RS_NumofTimes = "RS_NumofTimes".Translate(); public static readonly string Option_1_Label = "RSOption_1_Label".Translate(); @@ -49,5 +96,46 @@ namespace RJWSexperience public static readonly string Option_11_Label = "RSOption_11_Label".Translate(); public static readonly string Option_11_Desc = "RSOption_11_Desc".Translate(); + + public static readonly string[] Sextype = + { + ((xxx.rjwSextype)0).ToString().Translate(), + ((xxx.rjwSextype)1).ToString().Translate(), + ((xxx.rjwSextype)2).ToString().Translate(), + ((xxx.rjwSextype)3).ToString().Translate(), + ((xxx.rjwSextype)4).ToString().Translate(), + ((xxx.rjwSextype)5).ToString().Translate(), + ((xxx.rjwSextype)6).ToString().Translate(), + ((xxx.rjwSextype)7).ToString().Translate(), + ((xxx.rjwSextype)8).ToString().Translate(), + ((xxx.rjwSextype)9).ToString().Translate(), + ((xxx.rjwSextype)10).ToString().Translate(), + ((xxx.rjwSextype)11).ToString().Translate(), + ((xxx.rjwSextype)12).ToString().Translate(), + ((xxx.rjwSextype)13).ToString().Translate(), + ((xxx.rjwSextype)14).ToString().Translate(), + ((xxx.rjwSextype)15).ToString().Translate(), + ((xxx.rjwSextype)16).ToString().Translate(), + ((xxx.rjwSextype)17).ToString().Translate(), + ((xxx.rjwSextype)18).ToString().Translate(), + ((xxx.rjwSextype)19).ToString().Translate(), + ((xxx.rjwSextype)20).ToString().Translate() + }; + + public static readonly string[] Sexuality = + { + ((Orientation)0).ToString().Translate(), + ((Orientation)1).ToString().Translate(), + ((Orientation)2).ToString().Translate(), + ((Orientation)3).ToString().Translate(), + ((Orientation)4).ToString().Translate(), + ((Orientation)5).ToString().Translate(), + ((Orientation)6).ToString().Translate(), + ((Orientation)7).ToString().Translate(), + ((Orientation)8).ToString().Translate(), + ((Orientation)9).ToString().Translate(), + ((Orientation)10).ToString().Translate() + }; + } } diff --git a/RJWSexperience/RJWSexperience/Patches/DefInjection.cs b/RJWSexperience/RJWSexperience/Patches/DefInjection.cs new file mode 100644 index 0000000..15fafee --- /dev/null +++ b/RJWSexperience/RJWSexperience/Patches/DefInjection.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using HarmonyLib; + + +namespace RJWSexperience +{ + [StaticConstructorOnStartup] + public static class DefInjection + { + static DefInjection() + { + InjectRaces(); + } + + private static void InjectRaces() + { + List PawnDefs = DefDatabase.AllDefs.Where(x => x.race != null).ToList(); + InjectComp(PawnDefs); + } + + private static void InjectComp(List PawnDefs) + { + CompProperties comp = new CompProperties(typeof(SexPartnerHistory)); + if (!PawnDefs.NullOrEmpty()) foreach(ThingDef def in PawnDefs) + { + def.comps.Add(comp); + } + } + } +} diff --git a/RJWSexperience/RJWSexperience/Patches/GetGizmos.cs b/RJWSexperience/RJWSexperience/Patches/GetGizmos.cs new file mode 100644 index 0000000..e6ffa0a --- /dev/null +++ b/RJWSexperience/RJWSexperience/Patches/GetGizmos.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; +using HarmonyLib; +using rjw; +using RJWSexperience.UI; + +namespace RJWSexperience +{ + [HarmonyPatch(typeof(Pawn),"GetGizmos")] + public class Pawn_GetGizmos + { + public static void Postfix(ref IEnumerable __result, Pawn __instance) + { + + List gizmoList = __result.ToList(); + + AddHistoryGizmo(__instance, ref gizmoList); + + + __result = gizmoList; + } + + private static void AddHistoryGizmo(Pawn pawn, ref List gizmos) + { + SexPartnerHistory history = pawn.GetPartnerHistory(); + if (history != null) gizmos.Add(CreateHIstoryGizmo(pawn,history)); + } + + private static Gizmo CreateHIstoryGizmo(Pawn pawn, SexPartnerHistory history) + { + Gizmo gizmo = new Command_Action + { + defaultLabel = Keyed.RS_Sex_History, + icon = HistoryUtility.HistoryIcon, + defaultIconColor = HistoryUtility.HistoryColor, + hotKey = VariousDefOf.OpenSexStatistics, + action = delegate + { + SexStatusWindow.ToggleWindow(pawn, history); + } + + }; + + return gizmo; + } + + + } + + + +} diff --git a/RJWSexperience/RJWSexperience/Patches/RJW_Patch.cs b/RJWSexperience/RJWSexperience/Patches/RJW_Patch.cs new file mode 100644 index 0000000..f58973c --- /dev/null +++ b/RJWSexperience/RJWSexperience/Patches/RJW_Patch.cs @@ -0,0 +1,207 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using rjw; +using RimWorld; +using Verse; +using Verse.AI; +using UnityEngine; + + +namespace RJWSexperience +{ + + + + [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] + public static class RJW_Patch_Orgasm + { + public static void Postfix(JobDriver_Sex __instance) + { + if (__instance.Sexprops.sexType != xxx.rjwSextype.Masturbation && !(__instance is JobDriver_Masturbate)) + { + if (__instance.Sexprops.isRape) + { + __instance.pawn?.skills?.Learn(VariousDefOf.SexSkill, 0.05f, true); + } + { + __instance.pawn?.skills?.Learn(VariousDefOf.SexSkill, 0.35f, true); + } + } + } + } + + [HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMin")] + public static class RJW_Patch_WhoreAbilityAdjustmentMin + { + public static void Postfix(Pawn whore, ref float __result) + { + __result *= whore.GetSexStat(); + } + } + + [HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMax")] + public static class RJW_Patch_WhoreAbilityAdjustmentMax + { + public static void Postfix(Pawn whore, ref float __result) + { + __result *= whore.GetSexStat(); + } + } + + [HarmonyPatch(typeof(SexUtility), "SatisfyPersonal")] + public static class RJW_Patch_SatisfyPersonal + { + private const float base_sat_per_fuck = 0.4f; + + public static void Prefix(SexProps props, ref float satisfaction) + { + Pawn pawn = props.pawn; + Pawn partner = props.partner; + satisfaction = Mathf.Max(base_sat_per_fuck, satisfaction * partner.GetSexStat()); + } + + public static void Postfix(SexProps props, ref float satisfaction) + { + Pawn pawn = props.pawn; + Pawn partner = props.partner; + float? lust = pawn.records?.GetValue(VariousDefOf.Lust); + xxx.rjwSextype sextype = props.sexType; + if (lust != null) + { + if (sextype != xxx.rjwSextype.Masturbation || partner != null) pawn.records.AddTo(VariousDefOf.Lust, Mathf.Clamp((satisfaction - base_sat_per_fuck) * RJWUtility.LustIncrementFactor(lust ?? 0), -0.5f, 0.5f)); // If the sex is satisfactory, lust grows up. Declines at the opposite. + else pawn.records.AddTo(VariousDefOf.Lust, Mathf.Clamp(satisfaction * satisfaction * RJWUtility.LustIncrementFactor(lust ?? 0), 0, 0.5f)); // Masturbation always increases lust. + } + + if (sextype == xxx.rjwSextype.Masturbation || partner == null) + { + Building_CumBucket cumbucket = (Building_CumBucket)pawn.GetAdjacentBuilding(); + if (cumbucket != null) + { + cumbucket.AddCum(pawn.GetCumVolume()); + } + } + + RJWUtility.UpdateSatisfactionHIstory(pawn, partner, props, satisfaction); + pawn.records?.Increment(VariousDefOf.OrgasmCount); + + } + + + + + } + + [HarmonyPatch(typeof(SexUtility), "TransferNutrition")] + public static class RJW_Patch_TransferNutrition + { + public static void Postfix(SexProps props) + { + Pawn pawn = props.pawn; + Pawn partner = props.partner; + xxx.rjwSextype sextype = props.sexType; + Pawn giver = null; + Pawn receiver = null; + + if (Genital_Helper.has_penis_fertile(pawn)) + { + giver = pawn; + receiver = partner; + } + else if (Genital_Helper.has_penis_fertile(partner)) + { + giver = partner; + receiver = pawn; + } + + if (receiver != null && ( + sextype == xxx.rjwSextype.Oral || + sextype == xxx.rjwSextype.Fellatio || + sextype == xxx.rjwSextype.Sixtynine)) + { + receiver.AteCum(giver.GetCumVolume(), true); + } + } + } + + [HarmonyPatch(typeof(Nymph_Generator), "set_skills")] + public static class RJW_Patch_Nymph_set_skills + { + public static void Postfix(Pawn pawn) + { + SkillRecord sexskill = pawn.skills.GetSkill(VariousDefOf.SexSkill); + if (sexskill != null) + { + sexskill.passion = Passion.Major; + sexskill.Level = (int)Utility.RandGaussianLike(7f, 20.99f); + sexskill.xpSinceLastLevel = sexskill.XpRequiredForLevelUp * Rand.Range(0.10f, 0.90f); + } + } + } + + [HarmonyPatch(typeof(AfterSexUtility), "UpdateRecords")] + public static class RJW_Patch_UpdateRecords + { + public static void Postfix(SexProps props) + { + RJWUtility.UpdateSextypeRecords(props); + RJWUtility.UpdatePartnerHistory(props.pawn, props.partner, props); + RJWUtility.UpdatePartnerHistory(props.partner, props.pawn, props); + } + + } + + [HarmonyPatch(typeof(JobDriver_SexBaseInitiator), "Start")] + public static class RJW_Patch_LogSextype + { + public static void Postfix(JobDriver_SexBaseInitiator __instance) + { + if (__instance.Partner != null) + { + __instance.pawn.PoptheCherry(__instance.Partner, __instance.Sexprops); + __instance.Partner.PoptheCherry(__instance.pawn, __instance.Sexprops); + } + } + } + + + [HarmonyPatch(typeof(WorkGiver_CleanSelf), "JobOnThing")] + public static class RJW_Patch_CleanSelf_JobOnThing + { + public static bool Prefix(Pawn pawn, Thing t, bool forced, ref Job __result) + { + Building_CumBucket bucket = pawn.GetAdjacentBuilding(); + if (bucket == null) bucket = pawn.FindClosestBucket(); + if (bucket != null) + { + __result = JobMaker.MakeJob(VariousDefOf.CleanSelfwithBucket, null, bucket, bucket.Position); + return false; + } + + + return true; + } + } + + [HarmonyPatch(typeof(JobGiver_Masturbate), "TryGiveJob")] + public static class RJW_Patch_Masturabte_TryGiveJob + { + public static void Postfix(Pawn pawn, ref Job __result) + { + if (RJWPreferenceSettings.FapEverywhere && __result != null) + { + Building_CumBucket bucket = pawn.FindClosestBucket(); + if (bucket != null) + { + __result.Clear(); + __result = JobMaker.MakeJob(xxx.Masturbate, null, null, bucket.RandomAdjacentCell8Way()); + } + } + + } + } + +} diff --git a/RJWSexperience/RJWSexperience/Patches/Rimworld_Patch.cs b/RJWSexperience/RJWSexperience/Patches/Rimworld_Patch.cs new file mode 100644 index 0000000..d3740a9 --- /dev/null +++ b/RJWSexperience/RJWSexperience/Patches/Rimworld_Patch.cs @@ -0,0 +1,145 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using HarmonyLib; +using RimWorld; +using Verse; +using rjw; +using UnityEngine; + + + + +namespace RJWSexperience +{ + [HarmonyPatch(typeof(PawnGenerator), "GeneratePawn", new Type[] { typeof(PawnGenerationRequest) })] + public static class Rimworld_Patch_GeneratePawn + { + public static void Postfix(PawnGenerationRequest request, ref Pawn __result) + { + if (Configurations.EnableRecordRandomizer && __result != null && !request.Newborn && xxx.is_human(__result)) + { + int avgsex = -500; + bool isvirgin = Rand.Chance(Configurations.VirginRatio); + int totalsex = 0; + int totalbirth = 0; + int deviation = (int)Configurations.MaxSexCountDeviation; + if (__result.story != null) + { + float lust; + if (xxx.is_nympho(__result)) lust = __result.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, 0); + else lust = __result.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, float.MinValue); + + int sexableage = 0; + int minsexage = (int)(__result.RaceProps.lifeExpectancy * Configurations.MinSexablePercent); + if (__result.ageTracker.AgeBiologicalYears > minsexage) + { + sexableage = __result.ageTracker.AgeBiologicalYears - minsexage; + avgsex = (int)(sexableage * Configurations.SexPerYear * __result.LustFactor()); + } + + + if (__result.relations != null && __result.gender == Gender.Female) + { + totalbirth += __result.relations.ChildrenCount; + totalsex += totalbirth; + __result.records?.AddTo(xxx.CountOfSexWithHumanlikes, totalbirth); + __result.records?.SetTo(xxx.CountOfBirthHuman, totalbirth); + if (totalbirth > 0) isvirgin = false; + } + if (!isvirgin) + { + if (xxx.is_rapist(__result)) + { + if (xxx.is_zoophile(__result)) + { + if (__result.Has(Quirk.ChitinLover)) totalsex += __result.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, deviation); + else totalsex += __result.RecordRandomizer(xxx.CountOfRapedAnimals, avgsex, deviation); + } + else totalsex += __result.RecordRandomizer(xxx.CountOfRapedHumanlikes, avgsex, deviation); + avgsex /= 8; + } + + if (xxx.is_zoophile(__result)) + { + if (__result.Has(Quirk.ChitinLover)) totalsex += __result.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, deviation); + else totalsex += __result.RecordRandomizer(xxx.CountOfSexWithAnimals, avgsex, deviation); + avgsex /= 10; + } + else if (xxx.is_necrophiliac(__result)) + { + totalsex += __result.RecordRandomizer(xxx.CountOfSexWithCorpse, avgsex, deviation); + avgsex /= 4; + } + + if (__result.IsSlave) + { + totalsex += __result.RecordRandomizer(xxx.CountOfBeenRapedByAnimals, Rand.Range(-50, 10), Rand.Range(0, 10) * sexableage); + totalsex += __result.RecordRandomizer(xxx.CountOfBeenRapedByHumanlikes, 0, Rand.Range(0, 100) * sexableage); + } + + + totalsex += __result.RecordRandomizer(xxx.CountOfSexWithHumanlikes, avgsex, deviation); + + if (totalsex > 0) __result.records.AddTo(VariousDefOf.SexPartnerCount, Math.Max(1, Rand.Range(0, totalsex/7))); + } + } + __result.records?.SetTo(xxx.CountOfSex, totalsex); + RJWUtility.GenerateSextypeRecords(__result, totalsex); + } + if (__result.story?.traits != null) + { + if (__result.IsVirgin()) + { + int degree = 0; + if (__result.gender == Gender.Female) degree = 2; + Trait virgin = new Trait(VariousDefOf.Virgin, degree ,true); + __result.story.traits.GainTrait(virgin); + } + else if (__result.gender == Gender.Female && Rand.Chance(0.05f)) + { + Trait virgin = new Trait(VariousDefOf.Virgin, 1, true); + __result.story.traits.GainTrait(virgin); + } + } + } + } + + + + [HarmonyPatch(typeof(FloatMenuMakerMap), "AddHumanlikeOrders")] + public class HumanlikeOrder_Patch + { + public static void Postfix(Vector3 clickPos, Pawn pawn, List opts) + { + var targets = GenUI.TargetsAt(clickPos, TargetingParameters.ForBuilding()); + + if (pawn.health.hediffSet.HasHediff(RJW_SemenoOverlayHediffDefOf.Hediff_Bukkake)) + foreach (LocalTargetInfo t in targets) + { + Building building = t.Thing as Building; + if (building != null) + { + if (building is Building_CumBucket) + { + opts.AddDistinct(MakeMenu(pawn, building)); + break; + } + } + } + } + + public static FloatMenuOption MakeMenu(Pawn pawn, LocalTargetInfo target) + { + FloatMenuOption option = FloatMenuUtility.DecoratePrioritizedTask(new FloatMenuOption(Keyed.RS_FloatMenu_CleanSelf, delegate () + { + pawn.jobs.TryTakeOrderedJob(new Verse.AI.Job(VariousDefOf.CleanSelfwithBucket, null, target, target.Cell)); + }, MenuOptionPriority.Low), pawn, target); + + return option; + } + } + +} diff --git a/RJWSexperience/RJWSexperience/RJWSexperience.csproj b/RJWSexperience/RJWSexperience/RJWSexperience.csproj index 45fe3cc..1878a3e 100644 --- a/RJWSexperience/RJWSexperience/RJWSexperience.csproj +++ b/RJWSexperience/RJWSexperience/RJWSexperience.csproj @@ -63,6 +63,12 @@ ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll False + + ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextCoreModule.dll + + + ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextRenderingModule.dll + ..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.UI.dll False @@ -77,20 +83,31 @@ - + - + + + + + + + + - - + + + + + + \ No newline at end of file diff --git a/RJWSexperience/RJWSexperience/RJWUtility.cs b/RJWSexperience/RJWSexperience/RJWUtility.cs new file mode 100644 index 0000000..6655d24 --- /dev/null +++ b/RJWSexperience/RJWSexperience/RJWUtility.cs @@ -0,0 +1,409 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using rjw; +using RimWorld; +using Verse; +using Verse.AI; +using UnityEngine; + +namespace RJWSexperience +{ + public static class RJWUtility + { + public static float GetSexStat(this Pawn pawn) + { + if (xxx.is_human(pawn) && !pawn.Dead) + { + return pawn.GetStatValue(xxx.sex_stat); + } + else return 1.0f; + } + + public static float LustIncrementFactor(float lust) + { + return Mathf.Exp(-Mathf.Pow(lust / Configurations.LustLimit, 2)); + } + + /// + /// If the pawn is virgin, return true. + /// + public static bool IsVirgin(this Pawn pawn) + { + if (pawn.records.GetValue(VariousDefOf.VaginalSexCount) == 0) return true; + return false; + } + public static bool HasHymen(this Pawn pawn) + { + Trait virgin = pawn.story?.traits?.GetTrait(VariousDefOf.Virgin); + if (virgin != null) + { + if (virgin.Degree > 0) return true; + } + return false; + } + + /// + /// If pawn is virgin, lose his/her virginity. + /// + public static void PoptheCherry(this Pawn pawn, Pawn partner, SexProps props) + { + if (props != null && props.sexType == xxx.rjwSextype.Vaginal) + { + if (pawn.IsVirgin()) + { + SexPartnerHistory history = pawn.GetPartnerHistory(); + if (history != null) + { + history.RecordFirst(partner, props); + } + if (RemoveVirginTrait(pawn, partner, props)) + { + Messages.Message(Keyed.RS_LostVirgin(pawn.LabelShort, partner.LabelShort), MessageTypeDefOf.NeutralEvent, true); + } + } + else + { + RemoveVirginTrait(pawn, partner, props); + } + } + } + + public static bool RemoveVirginTrait(Pawn pawn, Pawn partner, SexProps props) + { + int degree; + Trait virgin = pawn.story?.traits?.GetTrait(VariousDefOf.Virgin); + if (virgin != null) + { + degree = virgin.Degree; + if (pawn.gender == Gender.Female && degree > 0) + { + FilthMaker.TryMakeFilth(pawn.Position, pawn.Map, ThingDefOf.Filth_Blood, pawn.LabelShort, 1, FilthSourceFlags.Pawn); + } + ThrowVirginHIstoryEvent(pawn, partner, props, degree); + pawn.story.traits.RemoveTrait(virgin); + return true; + } + return false; + } + + + /// + /// For ideo patch + /// + public static void ThrowVirginHIstoryEvent(Pawn pawn, Pawn partner, SexProps props, int degree) + { + //for non-ideo + if (partner.Ideo == null) + { + partner.needs?.mood?.thoughts?.memories.TryGainMemory(xxx.took_virginity, pawn); + } + } + + public static void UpdateSextypeRecords(SexProps props) + { + xxx.rjwSextype sextype = props.sexType; + Pawn pawn = props.pawn; + Pawn partner = props.partner; + Pawn receiver = props.reciever; + Pawn giver = props.giver; + + if (partner != null) + { + + switch (sextype) + { + case xxx.rjwSextype.Vaginal: + case xxx.rjwSextype.Scissoring: + IncreaseSameRecords(pawn, partner, VariousDefOf.VaginalSexCount); + break; + case xxx.rjwSextype.Anal: + IncreaseSameRecords(pawn, partner, VariousDefOf.AnalSexCount); + break; + case xxx.rjwSextype.Oral: + case xxx.rjwSextype.Fellatio: + if (Genital_Helper.has_penis_fertile(giver) || Genital_Helper.has_penis_infertile(giver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.OralSexCount, VariousDefOf.BlowjobCount); + } + else if (Genital_Helper.has_penis_infertile(receiver) || Genital_Helper.has_penis_infertile(receiver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.BlowjobCount, VariousDefOf.OralSexCount); + } + break; + case xxx.rjwSextype.Sixtynine: + IncreaseSameRecords(pawn, partner, VariousDefOf.OralSexCount); + RecordDef recordpawn, recordpartner; + if (Genital_Helper.has_penis_fertile(pawn) || Genital_Helper.has_penis_infertile(pawn)) + { + recordpartner = VariousDefOf.BlowjobCount; + } + else + { + recordpartner = VariousDefOf.CunnilingusCount; + } + + if (Genital_Helper.has_penis_fertile(partner) || Genital_Helper.has_penis_infertile(partner)) + { + recordpawn = VariousDefOf.BlowjobCount; + } + else + { + recordpawn = VariousDefOf.CunnilingusCount; + } + IncreaseRecords(pawn, partner, recordpawn, recordpartner); + break; + case xxx.rjwSextype.Cunnilingus: + if (Genital_Helper.has_vagina(giver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.OralSexCount, VariousDefOf.CunnilingusCount); + } + else if (Genital_Helper.has_vagina(receiver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.CunnilingusCount, VariousDefOf.OralSexCount); + } + break; + case xxx.rjwSextype.Masturbation: + break; + case xxx.rjwSextype.Handjob: + if (Genital_Helper.has_penis_fertile(giver) || Genital_Helper.has_penis_infertile(giver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.GenitalCaressCount, VariousDefOf.HandjobCount); + } + else + { + IncreaseRecords(giver, receiver, VariousDefOf.HandjobCount, VariousDefOf.GenitalCaressCount); + } + break; + case xxx.rjwSextype.Fingering: + case xxx.rjwSextype.Fisting: + if (Genital_Helper.has_vagina(giver)) + { + IncreaseRecords(giver, receiver, VariousDefOf.GenitalCaressCount, VariousDefOf.FingeringCount); + } + else + { + IncreaseRecords(giver, receiver, VariousDefOf.FingeringCount, VariousDefOf.GenitalCaressCount); + } + break; + case xxx.rjwSextype.Footjob: + IncreaseSameRecords(pawn, partner, VariousDefOf.FootjobCount); + break; + default: + IncreaseSameRecords(pawn, partner, VariousDefOf.MiscSexualBehaviorCount); + break; + } + } + } + + public static void UpdatePartnerHistory(Pawn pawn, Pawn partner, SexProps props) + { + if (partner != null) + { + SexPartnerHistory pawnshistory = pawn.TryGetComp(); + pawnshistory?.RecordHistory(partner, props); + } + } + + public static void UpdateSatisfactionHIstory(Pawn pawn, Pawn partner, SexProps props, float satisfaction) + { + if (partner != null) + { + SexPartnerHistory pawnshistory = pawn.TryGetComp(); + pawnshistory?.RecordSatisfactionHistory(partner, props, satisfaction); + } + } + + public static void IncreaseSameRecords(Pawn pawn, Pawn partner, RecordDef record) + { + pawn.records?.AddTo(record, 1); + partner.records?.AddTo(record, 1); + } + + public static void IncreaseRecords(Pawn pawn, Pawn partner, RecordDef recordforpawn, RecordDef recordforpartner) + { + pawn.records?.AddTo(recordforpawn, 1); + partner.records?.AddTo(recordforpartner, 1); + } + + public static void GenerateSextypeRecords(Pawn pawn, int totalsex) + { + float totalweight = + RJWPreferenceSettings.vaginal + + RJWPreferenceSettings.anal + + RJWPreferenceSettings.fellatio + + RJWPreferenceSettings.cunnilingus + + RJWPreferenceSettings.rimming + + RJWPreferenceSettings.double_penetration + + RJWPreferenceSettings.breastjob + + RJWPreferenceSettings.handjob + + RJWPreferenceSettings.mutual_masturbation + + RJWPreferenceSettings.fingering + + RJWPreferenceSettings.footjob + + RJWPreferenceSettings.scissoring + + RJWPreferenceSettings.fisting + + RJWPreferenceSettings.sixtynine; + Gender prefer = pawn.PreferGender(); + int sex = (int)(totalsex * RJWPreferenceSettings.vaginal / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.VaginalSexCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.anal / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.AnalSexCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.fellatio / totalweight); + totalsex -= sex; + if (prefer == Gender.Male) pawn.records.AddTo(VariousDefOf.BlowjobCount, sex); + else pawn.records.AddTo(VariousDefOf.OralSexCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.cunnilingus / totalweight); + totalsex -= sex; + if (prefer == Gender.Male) pawn.records.AddTo(VariousDefOf.OralSexCount, sex); + else pawn.records.AddTo(VariousDefOf.CunnilingusCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.rimming / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.MiscSexualBehaviorCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.double_penetration / totalweight) / 2; + totalsex -= sex; + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.VaginalSexCount, sex); + pawn.records.AddTo(VariousDefOf.AnalSexCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.breastjob / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.MiscSexualBehaviorCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.handjob / totalweight); + totalsex -= sex; + if (prefer == Gender.Male) pawn.records.AddTo(VariousDefOf.HandjobCount, sex); + else pawn.records.AddTo(VariousDefOf.GenitalCaressCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.fingering / totalweight); + totalsex -= sex; + if (prefer == Gender.Female) pawn.records.AddTo(VariousDefOf.FingeringCount, sex); + else pawn.records.AddTo(VariousDefOf.GenitalCaressCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.mutual_masturbation / totalweight); + totalsex -= sex; + if (prefer == Gender.Male) pawn.records.AddTo(VariousDefOf.HandjobCount, sex); + else pawn.records.AddTo(VariousDefOf.FingeringCount, sex); + pawn.records.AddTo(VariousDefOf.GenitalCaressCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.footjob / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.FootjobCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.scissoring / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.MiscSexualBehaviorCount, sex); + + sex = (int)(totalsex * RJWPreferenceSettings.fisting / totalweight); + totalsex -= sex; + pawn.records.AddTo(VariousDefOf.MiscSexualBehaviorCount, sex); + + pawn.records.AddTo(VariousDefOf.OralSexCount, totalsex); + if (prefer == Gender.Male) pawn.records.AddTo(VariousDefOf.BlowjobCount, totalsex); + else pawn.records.AddTo(VariousDefOf.CunnilingusCount, totalsex); + + } + + public static Gender PreferGender(this Pawn pawn) + { + if (pawn.gender == Gender.Male) + { + if (xxx.is_homosexual(pawn)) return Gender.Male; + else return Gender.Female; + } + else + { + if (xxx.is_homosexual(pawn)) return Gender.Female; + else return Gender.Male; + } + } + + public static bool GetRapist(this SexProps props, out Pawn rapist) + { + if (!props.isRape) + { + rapist = null; + return false; + } + + rapist = props.pawn; + return true; + } + + public static bool IsBestiality(this SexProps props) + { + if (props.partner != null) + { + return props.pawn.IsAnimal() ^ props.partner.IsAnimal(); + } + return false; + } + + public static Building_CumBucket FindClosestBucket(this Pawn pawn) + { + List buckets = pawn.Map.listerBuildings.allBuildingsColonist.FindAll(x => x is Building_CumBucket); + Dictionary targets = new Dictionary(); + if (!buckets.NullOrEmpty()) for (int i = 0; i < buckets.Count; i++) + { + if (pawn.CanReach(buckets[i], PathEndMode.ClosestTouch, Danger.None)) + { + targets.Add(buckets[i], pawn.Position.DistanceTo(buckets[i].Position)); + } + } + if (!targets.NullOrEmpty()) + { + return (Building_CumBucket)targets.MinBy(x => x.Value).Key; + } + return null; + } + + public static void AteCum(this Pawn pawn, float amount, bool doDrugEffect = false) + { + pawn.records.AddTo(VariousDefOf.NumofEatenCum, 1); + pawn.records.AddTo(VariousDefOf.AmountofEatenCum, amount); + if (doDrugEffect) pawn.CumDrugEffect(); + } + + public static void CumDrugEffect(this Pawn pawn) + { + Need need = pawn.needs?.TryGetNeed(VariousDefOf.Chemical_Cum); + if (need != null) need.CurLevel += VariousDefOf.CumneedLevelOffset; + Hediff addictive = HediffMaker.MakeHediff(VariousDefOf.CumTolerance, pawn); + addictive.Severity = 0.032f; + pawn.health.AddHediff(addictive); + Hediff addiction = pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.CumAddiction); + if (addiction != null) addiction.Severity += VariousDefOf.CumexistingAddictionSeverityOffset; + + pawn.needs?.mood?.thoughts?.memories?.TryGainMemoryFast(VariousDefOf.AteCum); + } + + public static void AddVirginTrait(this Pawn pawn) + { + if (pawn.story?.traits != null) + { + if (pawn.IsVirgin()) + { + int degree = 0; + if (pawn.gender == Gender.Female) degree = 2; + Trait virgin = new Trait(VariousDefOf.Virgin, degree, true); + pawn.story.traits.GainTrait(virgin); + } + else if (pawn.gender == Gender.Female && Rand.Chance(0.05f)) + { + Trait virgin = new Trait(VariousDefOf.Virgin, 1, true); + pawn.story.traits.GainTrait(virgin); + } + } + } + + + } +} diff --git a/RJWSexperience/RJWSexperience/RJW_Patch.cs b/RJWSexperience/RJWSexperience/RJW_Patch.cs deleted file mode 100644 index 998837f..0000000 --- a/RJWSexperience/RJWSexperience/RJW_Patch.cs +++ /dev/null @@ -1,305 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HarmonyLib; -using rjw; -using RimWorld; -using Verse; -using UnityEngine; - - -namespace RJWSexperience -{ - public static class RJWUtility - { - public static float GetSexStat(this Pawn pawn) - { - if (xxx.is_human(pawn) && !pawn.Dead) - { - return pawn.GetStatValue(xxx.sex_stat); - } - else return 1.0f; - } - - public static float LustIncrementFactor(float lust) - { - return Mathf.Exp(-Mathf.Pow(lust / Configurations.LustLimit, 2)); - } - - /// - /// If the pawn is virgin, return true. - /// - public static bool IsVirgin(this Pawn pawn) - { - if (pawn.records.GetValue(xxx.CountOfSex) == 0) return true; - return false; - } - - /// - /// If pawn is virgin, lose his/her virginity. - /// - public static void PoptheCherry(this Pawn pawn, Pawn partner, bool violent) - { - if (pawn.IsVirgin()) - { - Messages.Message(Keyed.RS_LostVirgin(pawn.LabelShort, partner.LabelShort), MessageTypeDefOf.NeutralEvent, true); - RemoveVirginTrait(pawn); - FilthMaker.TryMakeFilth(pawn.Position, pawn.Map, ThingDefOf.Filth_Blood, 1, FilthSourceFlags.Pawn); - } - } - - public static void RemoveVirginTrait(Pawn pawn) - { - Trait virgin = pawn.story?.traits?.GetTrait(VariousDefOf.Virgin); - if (virgin != null) - { - pawn.story.traits.RemoveTrait(virgin); - } - } - - public static void UpdateSextypeRecords(SexProps props) - { - xxx.rjwSextype sextype = props.sexType; - Pawn pawn = props.pawn; - Pawn partner = props.partner; - Pawn receiver = props.reciever; - Pawn giver = props.giver; - - if (partner != null) - { - - switch (sextype) - { - case xxx.rjwSextype.Vaginal: - case xxx.rjwSextype.Scissoring: - IncreaseSameRecords(pawn, partner, VariousDefOf.VaginalSexCount); - break; - case xxx.rjwSextype.Anal: - IncreaseSameRecords(pawn, partner, VariousDefOf.AnalSexCount); - break; - case xxx.rjwSextype.Oral: - case xxx.rjwSextype.Fellatio: - if (Genital_Helper.has_penis_fertile(giver) || Genital_Helper.has_penis_infertile(giver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.OralSexCount, VariousDefOf.BlowjobCount); - } - else if (Genital_Helper.has_penis_infertile(receiver) || Genital_Helper.has_penis_infertile(receiver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.BlowjobCount, VariousDefOf.OralSexCount); - } - break; - case xxx.rjwSextype.Sixtynine: - IncreaseSameRecords(pawn, partner, VariousDefOf.OralSexCount); - RecordDef recordpawn, recordpartner; - if (Genital_Helper.has_penis_fertile(pawn) || Genital_Helper.has_penis_infertile(pawn)) - { - recordpartner = VariousDefOf.BlowjobCount; - } - else - { - recordpartner = VariousDefOf.CunnilingusCount; - } - - if (Genital_Helper.has_penis_fertile(partner) || Genital_Helper.has_penis_infertile(partner)) - { - recordpawn = VariousDefOf.BlowjobCount; - } - else - { - recordpawn = VariousDefOf.CunnilingusCount; - } - IncreaseRecords(pawn, partner, recordpawn, recordpartner); - break; - case xxx.rjwSextype.Cunnilingus: - if (Genital_Helper.has_vagina(giver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.OralSexCount, VariousDefOf.CunnilingusCount); - } - else if (Genital_Helper.has_vagina(receiver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.CunnilingusCount, VariousDefOf.OralSexCount); - } - break; - case xxx.rjwSextype.Masturbation: - break; - case xxx.rjwSextype.Handjob: - if (Genital_Helper.has_penis_fertile(giver) || Genital_Helper.has_penis_infertile(giver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.GenitalCaressCount, VariousDefOf.HadnjobCount); - } - else - { - IncreaseRecords(giver, receiver, VariousDefOf.HadnjobCount, VariousDefOf.GenitalCaressCount); - } - break; - case xxx.rjwSextype.Fingering: - case xxx.rjwSextype.Fisting: - if (Genital_Helper.has_vagina(giver)) - { - IncreaseRecords(giver, receiver, VariousDefOf.GenitalCaressCount, VariousDefOf.FingeringCount); - } - else - { - IncreaseRecords(giver, receiver, VariousDefOf.FingeringCount, VariousDefOf.GenitalCaressCount); - } - break; - case xxx.rjwSextype.Footjob: - IncreaseSameRecords(pawn, partner, VariousDefOf.FootjobCount); - break; - default: - IncreaseSameRecords(pawn, partner, VariousDefOf.MiscSexualBehaviorCount); - break; - } - } - } - - public static void UpdatePartnerHistory(Pawn pawn, Pawn partner, SexProps props, float satisfaction) - { - SexPartnerHistory pawnshistory = pawn.GetComp(); - pawnshistory.RecordHistory(partner, props); - } - - public static void IncreaseSameRecords(Pawn pawn, Pawn partner, RecordDef record) - { - pawn.records?.AddTo(record, 1); - partner.records?.AddTo(record, 1); - } - - public static void IncreaseRecords(Pawn pawn, Pawn partner, RecordDef recordforpawn, RecordDef recordforpartner) - { - pawn.records?.AddTo(recordforpawn, 1); - partner.records?.AddTo(recordforpartner, 1); - } - - } - - - - [HarmonyPatch(typeof(JobDriver_Sex), "Orgasm")] - public static class RJW_Patch_Orgasm - { - public static void Postfix(JobDriver_Sex __instance) - { - if (__instance.Sexprops.sexType != xxx.rjwSextype.Masturbation && !(__instance is JobDriver_Masturbate)) - { - if (__instance.Sexprops.isRape) - { - __instance.pawn?.skills?.Learn(VariousDefOf.SexSkill, 0.05f, true); - } - { - __instance.pawn?.skills?.Learn(VariousDefOf.SexSkill, 0.35f, true); - } - } - } - } - - [HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMin")] - public static class RJW_Patch_WhoreAbilityAdjustmentMin - { - public static void Postfix(Pawn whore, ref float __result) - { - __result *= whore.GetSexStat(); - } - } - - [HarmonyPatch(typeof(WhoringHelper), "WhoreAbilityAdjustmentMax")] - public static class RJW_Patch_WhoreAbilityAdjustmentMax - { - public static void Postfix(Pawn whore, ref float __result) - { - __result *= whore.GetSexStat(); - } - } - - [HarmonyPatch(typeof(SexUtility), "SatisfyPersonal")] - public static class RJW_Patch_SatisfyPersonal - { - private const float base_sat_per_fuck = 0.4f; - - public static void Prefix(SexProps props, ref float satisfaction) - { - Pawn pawn = props.pawn; - Pawn partner = props.partner; - satisfaction = Mathf.Max(base_sat_per_fuck, satisfaction * partner.GetSexStat()); - } - - public static void Postfix(SexProps props, float satisfaction) - { - Pawn pawn = props.pawn; - Pawn partner = props.partner; - float? lust = pawn.records?.GetValue(VariousDefOf.Lust); - xxx.rjwSextype sextype = props.sexType; - if (lust != null) - { - if (sextype != xxx.rjwSextype.Masturbation || partner != null) pawn.records.AddTo(VariousDefOf.Lust, Mathf.Clamp((satisfaction - base_sat_per_fuck) * RJWUtility.LustIncrementFactor(lust ?? 0), -0.5f, 0.5f)); // If the sex is satisfactory, lust grows up. Declines at the opposite. - else pawn.records.AddTo(VariousDefOf.Lust, Mathf.Clamp(satisfaction * satisfaction * RJWUtility.LustIncrementFactor(lust ?? 0), 0, 0.5f)); // Masturbation always increases lust. - } - - if (sextype == xxx.rjwSextype.Masturbation || partner == null) - { - Building_CumBucket cumbucket = (Building_CumBucket)pawn.GetAdjacentBuilding(); - if (cumbucket != null) - { - cumbucket.AddCum(pawn.GetCumVolume()); - } - } - } - - - - - } - - [HarmonyPatch(typeof(SexUtility), "TransferNutrition")] - public static class RJW_Patch_TransferNutrition - { - public static void Postfix(SexProps props) - { - Pawn pawn = props.pawn; - Pawn partner = props.partner; - xxx.rjwSextype sextype = props.sexType; - Pawn receiver = null; - - if (Genital_Helper.has_penis_fertile(pawn)) receiver = partner; - else if (Genital_Helper.has_penis_fertile(partner)) receiver = pawn; - - if (receiver != null && ( - sextype == xxx.rjwSextype.Oral || - sextype == xxx.rjwSextype.Fellatio || - sextype == xxx.rjwSextype.Sixtynine)) - { - receiver.CumDrugEffect(); - } - } - } - - [HarmonyPatch(typeof(Nymph_Generator), "set_skills")] - public static class RJW_Patch_Nymph_set_skills - { - public static void Postfix(Pawn pawn) - { - SkillRecord sexskill = pawn.skills.GetSkill(VariousDefOf.SexSkill); - if (sexskill != null) - { - sexskill.passion = Passion.Major; - sexskill.Level = (int)Utility.RandGaussianLike(7f, 20.99f); - sexskill.xpSinceLastLevel = sexskill.XpRequiredForLevelUp * Rand.Range(0.10f, 0.90f); - } - } - } - - [HarmonyPatch(typeof(AfterSexUtility), "UpdateRecords")] - public static class RJW_Patch_UpdateRecords - { - public static void Postfix(SexProps props) - { - RJWUtility.UpdateSextypeRecords(props); - } - - } - - - -} diff --git a/RJWSexperience/RJWSexperience/Recipe_HymenSurgery.cs b/RJWSexperience/RJWSexperience/Recipe_HymenSurgery.cs new file mode 100644 index 0000000..62962d2 --- /dev/null +++ b/RJWSexperience/RJWSexperience/Recipe_HymenSurgery.cs @@ -0,0 +1,55 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; +using rjw; + +namespace RJWSexperience +{ + public class Recipe_HymenSurgery : Recipe_Surgery + { + public override IEnumerable GetPartsToApplyOn(Pawn pawn, RecipeDef recipe) + { + + if (pawn.gender != Gender.Female) + { + yield break; + } + + BodyPartRecord part = Genital_Helper.get_genitalsBPR(pawn); + if (part != null) + { + List hediffs = Genital_Helper.get_PartsHediffList(pawn, part); + if (Genital_Helper.has_vagina(pawn, hediffs) && !pawn.HasHymen()) + { + yield return part; + } + + } + } + + public override void ApplyOnPawn(Pawn pawn, BodyPartRecord part, Pawn billDoer, List ingredients, Bill bill) + { + if (billDoer != null) + { + TaleRecorder.RecordTale(TaleDefOf.DidSurgery, new object[] + { + billDoer, + pawn + }); + SurgeryResult(pawn); + } + } + + protected void SurgeryResult(Pawn pawn) + { + int degree = 1; + if (pawn.IsVirgin()) degree = 2; + Trait virgin = new Trait(VariousDefOf.Virgin, degree, true); + pawn.story.traits.GainTrait(virgin); + } + } +} diff --git a/RJWSexperience/RJWSexperience/Rimworld_Patch.cs b/RJWSexperience/RJWSexperience/Rimworld_Patch.cs deleted file mode 100644 index f495a8c..0000000 --- a/RJWSexperience/RJWSexperience/Rimworld_Patch.cs +++ /dev/null @@ -1,91 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using HarmonyLib; -using RimWorld; -using Verse; -using rjw; - - - - -namespace RJWSexperience -{ - [HarmonyPatch(typeof(PawnGenerator), "GeneratePawn", new Type[] { typeof(PawnGenerationRequest) })] - public static class Rimworld_Patch_GeneratePawn - { - public static void Postfix(PawnGenerationRequest request, ref Pawn __result) - { - if (__result != null && !request.Newborn && xxx.is_human(__result)) - { - float avgsex = -500; - bool isvirgin = Rand.Chance(Configurations.VirginRatio); - int totalsex = 0; - float totalbirth = 0; - if (__result.story != null) - { - float lust; - if (xxx.is_nympho(__result)) lust = __result.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, 0); - else lust = __result.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, float.MinValue); - - float sexableage = 0; - float minsexage = __result.RaceProps.lifeExpectancy * Configurations.MinSexablePercent; - if (__result.ageTracker.AgeBiologicalYears > minsexage) - { - sexableage = __result.ageTracker.AgeBiologicalYearsFloat - minsexage; - avgsex = sexableage * Configurations.SexPerYear * __result.LustFactor(); - } - - - if (__result.relations != null && __result.gender == Gender.Female) - { - totalbirth += __result.relations.ChildrenCount; - totalsex += (int)totalbirth; - __result.records?.AddTo(xxx.CountOfSexWithHumanlikes, totalbirth); - __result.records?.SetTo(xxx.CountOfBirthHuman, totalbirth); - if (totalbirth > 0) isvirgin = false; - } - if (!isvirgin) - { - if (xxx.is_rapist(__result)) - { - if (xxx.is_zoophile(__result)) - { - if (__result.Has(Quirk.ChitinLover)) totalsex += (int)__result.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, Configurations.MaxSexCountDeviation); - else totalsex += (int)__result.RecordRandomizer(xxx.CountOfRapedAnimals, avgsex, Configurations.MaxSexCountDeviation); - } - else totalsex += (int)__result.RecordRandomizer(xxx.CountOfRapedHumanlikes, avgsex, Configurations.MaxSexCountDeviation); - avgsex /= 4; - } - - if (xxx.is_zoophile(__result)) - { - if (__result.Has(Quirk.ChitinLover)) totalsex += (int)__result.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, Configurations.MaxSexCountDeviation); - else totalsex += (int)__result.RecordRandomizer(xxx.CountOfSexWithAnimals, avgsex, Configurations.MaxSexCountDeviation); - avgsex /= 2; - } - else if (xxx.is_necrophiliac(__result)) - { - totalsex += (int)__result.RecordRandomizer(xxx.CountOfSexWithCorpse, avgsex, Configurations.MaxSexCountDeviation); - avgsex /= 2; - } - - if (__result.IsSlave) - { - totalsex += (int)__result.RecordRandomizer(xxx.CountOfBeenRapedByAnimals, Rand.Range(-50, 10), Rand.Range(0, 10) * sexableage); - totalsex += (int)__result.RecordRandomizer(xxx.CountOfBeenRapedByHumanlikes, 0, Rand.Range(0, 100) * sexableage); - } - - - totalsex += (int)__result.RecordRandomizer(xxx.CountOfSexWithHumanlikes, avgsex, Configurations.MaxSexCountDeviation); - } - } - __result.records?.SetTo(xxx.CountOfSex, totalsex); - } - } - } - - -} diff --git a/RJWSexperience/RJWSexperience/SexHistory.cs b/RJWSexperience/RJWSexperience/SexHistory.cs deleted file mode 100644 index 0e40701..0000000 --- a/RJWSexperience/RJWSexperience/SexHistory.cs +++ /dev/null @@ -1,284 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; -using RimWorld; -using Verse; -using rjw; - - -namespace RJWSexperience -{ - public class SexPartnerHistory : ThingComp - { - public SexPartnerHistory() { } - - - //protected List histories = new List(); - protected Dictionary histories = new Dictionary(); - protected string first = ""; - protected bool dirty = true; - protected string bestaffinity = ""; - protected float bestaffinitysat = 0; - protected xxx.rjwSextype recentsex = xxx.rjwSextype.None; - protected string recentpartner = ""; - protected int[] sextypecount = new int[20]; - protected float[] sextypesat = new float[20]; - - protected string mostpartnercache = ""; - protected xxx.rjwSextype mostsextypecache = xxx.rjwSextype.None; - protected xxx.rjwSextype mostsatsextypecache = xxx.rjwSextype.None; - - - public string FirstSexInfo - { - get - { - Update(); - return - "Partner: " + histories.TryGetValue(first)?.Label ?? "Unknown" + - ""; - } - } - public string MostSexPartner - { - get - { - Update(); - return histories.TryGetValue(mostpartnercache)?.Label ?? "Unknown"; - } - } - public xxx.rjwSextype MostSextype - { - get - { - Update(); - return mostsextypecache; - } - } - public xxx.rjwSextype MostSatisfiedSex - { - get - { - Update(); - return mostsatsextypecache; - } - } - - - - public override void PostExposeData() - { - Scribe_Collections.Look(ref histories, "histories", LookMode.Deep); - Scribe_Values.Look(ref first, "first", "", true); - Scribe_Values.Look(ref bestaffinity, "bestaffinity", "", true); - Scribe_Values.Look(ref bestaffinitysat, "bestaffinitysat", bestaffinitysat, true); - Scribe_Values.Look(ref recentsex, "recentsex", recentsex, true); - Scribe_Values.Look(ref recentpartner, "recentpartner", recentpartner, true); - Scribe_Values.Look(ref sextypecount, "sextypecount", sextypecount, true); - Scribe_Values.Look(ref sextypesat, "sextypesat", sextypesat, true); - base.PostExposeData(); - } - - public void RecordHistory(Pawn partner, SexProps props) - { - TryAddHistory(partner); - recentpartner = partner.ThingID; - SexHistory history = histories[partner.ThingID]; - history?.RecordSex(props); - recentsex = props.sexType; - sextypecount[(int)props.sexType]++; - - dirty = true; - } - - public void RecordSatisfactionHistory(Pawn partner, SexProps props, float satisfaction) - { - TryAddHistory(partner); - RecordFirst(partner, props); - SexHistory history = histories[partner.ThingID]; - history?.RecordSatisfaction(props, satisfaction); - sextypesat[(int)props.sexType] += satisfaction; - dirty = true; - } - - protected bool TryAddHistory(Pawn partner) - { - if (!histories.ContainsKey(partner.ThingID)) - { - histories.Add(partner.ThingID, new SexHistory(partner)); - Pawn pawn = parent as Pawn; - if (pawn != null) - { - pawn.records.AddTo(VariousDefOf.SexPartnerCount, 1); - } - return true; - } - return false; - } - - protected void RecordFirst(Pawn partner, SexProps props) - { - if (VirginCheck() && props.sexType == xxx.rjwSextype.Vaginal) - { - first = partner.ThingID; - } - } - - protected void Update() - { - if (dirty) - { - UpdateStatistics(); - dirty = false; - } - } - - protected void UpdateStatistics() - { - int max = 0; - float maxf = 0; - int maxindex = 0; - string mostID = "Unknown"; - - foreach (KeyValuePair element in histories) - { - SexHistory h = element.Value; - - //find most sex partner - if (max < h.TotalSexCount) - { - max = h.TotalSexCount; - mostID = element.Key; - } - } - - max = 0; - for (int i=0; i < sextypecount.Length; i++) - { - float avgsat = sextypesat[i] / sextypecount[i]; - if (maxf < avgsat) - { - maxf = avgsat; - maxindex = i; - } - } - - mostsatsextypecache = (xxx.rjwSextype)maxindex; - mostsextypecache = (xxx.rjwSextype)sextypecount.FirstIndexOf(x => x == sextypecount.Max()); - mostpartnercache = mostID; - } - - protected bool VirginCheck() - { - Pawn pawn = parent as Pawn; - if (pawn != null) - { - if (pawn.IsVirgin()) return true; - } - return false; - } - - } - - - public class SexHistory : IExposable - { - protected Pawn partner; - protected string namecache; - protected int totalsexhad = 0; - protected int raped = 0; - protected int rapedme = 0; - protected int orgasms = 0; - protected xxx.rjwSextype bestsextype = xxx.rjwSextype.None; - protected float bestsatisfaction = 0; - - - - public string Label - { - get - { - if (partner != null) - { - namecache = partner.Label; - return namecache; - } - else return namecache; - } - } - public xxx.rjwSextype BestSextype - { - get - { - return bestsextype; - } - } - public float BestSatisfaction - { - get - { - return bestsatisfaction; - } - } - public int TotalSexCount - { - get - { - return totalsexhad; - } - } - - - public SexHistory() { } - - public SexHistory(Pawn pawn) - { - partner = pawn; - namecache = pawn.Label; - } - - - public void ExposeData() - { - Scribe_References.Look(ref partner, "partner", true); - Scribe_Values.Look(ref namecache, "namecache", namecache, true); - Scribe_Values.Look(ref totalsexhad, "totalsexhad", totalsexhad, true); - Scribe_Values.Look(ref raped, "raped", raped, true); - Scribe_Values.Look(ref rapedme, "rapedme", rapedme, true); - Scribe_Values.Look(ref orgasms, "orgasms", orgasms, true); - Scribe_Values.Look(ref bestsextype, "bestsextype", bestsextype, true); - Scribe_Values.Look(ref bestsatisfaction, "bestsatisfaction", bestsatisfaction, true); - } - - public void RecordSex(SexProps props) - { - totalsexhad++; - if (props.isRape) - { - if (partner == props.giver) - { - rapedme++; - } - else if (partner == props.reciever) - { - raped++; - } - } - } - - public void RecordSatisfaction(SexProps props, float satisfaction) - { - if (satisfaction > bestsatisfaction) - { - orgasms++; - bestsextype = props.sexType; - bestsatisfaction = satisfaction; - } - } - - - } - -} diff --git a/RJWSexperience/RJWSexperience/SexHistory/HistoryUtility.cs b/RJWSexperience/RJWSexperience/SexHistory/HistoryUtility.cs new file mode 100644 index 0000000..8388e5d --- /dev/null +++ b/RJWSexperience/RJWSexperience/SexHistory/HistoryUtility.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; +using rjw; +using UnityEngine; + +namespace RJWSexperience +{ + [StaticConstructorOnStartup] + public static class HistoryUtility + { + public static readonly Texture2D HistoryIcon = ContentFinder.Get("UI/buttons/OpenStatsReport"); + public static readonly Texture2D UnknownPawn = ContentFinder.Get("UI/Icon/UnknownPawn"); + public static readonly Texture2D FirstOverlay = ContentFinder.Get("UI/Icon/FirstBG"); + public static readonly Texture2D Heart = ContentFinder.Get("Things/Mote/Heart"); + public static readonly Texture2D Incest = ContentFinder.Get("UI/Icon/Incest"); + public static readonly Texture2D Locked = ContentFinder.Get("UI/Icon/RSLocked"); + public static readonly Texture2D Unlocked = ContentFinder.Get("UI/Icon/RSUnlocked"); + public static Texture2D Slaanesh = SolidColorMaterials.NewSolidColorTexture(0.686f, 0.062f, 0.698f, 1.0f); + public static Texture2D Khorne = SolidColorMaterials.NewSolidColorTexture(0.415f, 0.0f, 0.003f, 1.0f); + public static Texture2D Tzeentch = SolidColorMaterials.NewSolidColorTexture(0.082f, 0.453f, 0.6f, 1.0f); + public static Texture2D Nurgle = SolidColorMaterials.NewSolidColorTexture(0.6f, 0.83f, 0.35f, 1.0f); + public static Texture2D Partners = SolidColorMaterials.NewSolidColorTexture(0.843f, 0.474f, 0.6f, 1.0f); + public static Texture2D TotalSex = SolidColorMaterials.NewSolidColorTexture(0.878f, 0.674f, 0.411f, 1.0f); + public static Texture2D Satisfaction = SolidColorMaterials.NewSolidColorTexture(0.325f, 0.815f, 0.729f,1.0f); + public static readonly Color HistoryColor = new Color(0.9f,0.5f,0.5f); + + public static readonly Texture2D[] SextypeColor = new Texture2D[] + { + Texture2D.linearGrayTexture, //None = 0, + SolidColorMaterials.NewSolidColorTexture(0.900f, 0.500f, 0.500f, 1.0f), //Vaginal = 1, + SolidColorMaterials.NewSolidColorTexture(0.529f, 0.313f, 0.113f, 1.0f), //Anal = 2, + SolidColorMaterials.NewSolidColorTexture(0.529f, 0.113f, 0.305f, 1.0f), //Oral = 3, + SolidColorMaterials.NewSolidColorTexture(0.000f, 0.819f, 0.219f, 1.0f), //Masturbation = 4, + SolidColorMaterials.NewSolidColorTexture(0.000f, 0.560f, 0.090f, 1.0f), //DoublePenetration + SolidColorMaterials.NewSolidColorTexture(0.839f, 0.850f, 0.505f, 1.0f), //Boobjob = 6, + SolidColorMaterials.NewSolidColorTexture(0.858f, 0.886f, 0.113f, 1.0f), //Handjob = 7, + SolidColorMaterials.NewSolidColorTexture(0.752f, 0.780f, 0.000f, 1.0f), //Footjob = 8, + SolidColorMaterials.NewSolidColorTexture(0.484f, 0.500f, 0.241f, 1.0f), //Fingering = 9, + SolidColorMaterials.NewSolidColorTexture(0.913f, 0.909f, 0.909f, 1.0f), //Scissoring = 10, + SolidColorMaterials.NewSolidColorTexture(0.588f, 0.576f, 0.431f, 1.0f), //MutualMasturbation + SolidColorMaterials.NewSolidColorTexture(0.741f, 0.000f, 0.682f, 1.0f), //Fisting = 12, + SolidColorMaterials.NewSolidColorTexture(0.121f, 0.929f, 1.000f, 1.0f), //MechImplant = 13, + SolidColorMaterials.NewSolidColorTexture(0.478f, 0.274f, 0.160f, 1.0f), //Rimming = 14, + SolidColorMaterials.NewSolidColorTexture(0.819f, 0.301f, 0.552f, 1.0f), //Fellatio = 15, + SolidColorMaterials.NewSolidColorTexture(0.819f, 0.301f, 0.552f, 1.0f), //Cunnilingus = 16, + SolidColorMaterials.NewSolidColorTexture(0.529f, 0.113f, 0.305f, 1.0f), //Sixtynine = 17 + Texture2D.linearGrayTexture, //? = 18 + Texture2D.linearGrayTexture, //? = 19 + Texture2D.linearGrayTexture //? = 20 + }; + + public static readonly Texture2D[] PassionBG = new Texture2D[] + { + + Texture2D.blackTexture, //None = 0, + SolidColorMaterials.NewSolidColorTexture(0.800f, 0.800f, 0.800f, 1.0f), //Minor = 1, + SolidColorMaterials.NewSolidColorTexture(1.000f, 0.875f, 0.000f, 1.0f) //Major = 2, + }; + + public static SexPartnerHistory GetPartnerHistory(this Pawn pawn) + { + return pawn.TryGetComp(); + } + + + + } +} diff --git a/RJWSexperience/RJWSexperience/SexHistory/SexHistory.cs b/RJWSexperience/RJWSexperience/SexHistory/SexHistory.cs new file mode 100644 index 0000000..09cdb17 --- /dev/null +++ b/RJWSexperience/RJWSexperience/SexHistory/SexHistory.cs @@ -0,0 +1,638 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using RimWorld; +using Verse; +using rjw; +using UnityEngine; + +namespace RJWSexperience +{ + public class SexPartnerHistory : ThingComp + { + public SexPartnerHistory() { } + public const int ARRLEN = 20; + + //protected List histories = new List(); + protected Dictionary histories = new Dictionary(); + protected string first = ""; + protected bool dirty = true; + protected xxx.rjwSextype recentsex = xxx.rjwSextype.None; + protected float recentsat = 0; + protected string recentpartner = ""; + protected int[] sextypecount = new int[ARRLEN]; + protected float[] sextypesat = new float[ARRLEN]; + protected int virginstaken = 0; + protected int incestuous = 0; + protected int bestiality = 0; + protected int corpsefuck = 0; + protected int interspecies = 0; + + protected string mostpartnercache = ""; + protected xxx.rjwSextype mostsextypecache = xxx.rjwSextype.None; + protected xxx.rjwSextype mostsatsextypecache = xxx.rjwSextype.None; + protected xxx.rjwSextype bestsextypecache = xxx.rjwSextype.None; + protected float bestsextypesatcache = 0; + protected string bestpartnercache = ""; + protected int totalsexcache = 0; + protected int totalrapedcache = 0; + protected int totalbeenrapedcache = 0; + protected ThingDef preferracecache = null; + protected int preferracesexcountcache = 0; + protected Pawn preferracepawncache = null; + protected float avtsatcache = 0; + + + private List partnerlistcache; + private List sextypecountsave; + private List sextypesatsave; + + + public SexHistory GetFirstPartnerHistory + { + get + { + Update(); + return histories.TryGetValue(first); + } + } + public SexHistory GetMostPartnerHistory + { + get + { + Update(); + return histories.TryGetValue(mostpartnercache); + } + } + public xxx.rjwSextype MostSextype + { + get + { + Update(); + return mostsextypecache; + } + } + public xxx.rjwSextype MostSatisfiedSex + { + get + { + Update(); + return mostsatsextypecache; + } + } + public SexHistory GetRecentPartnersHistory + { + get + { + return histories.TryGetValue(recentpartner); + } + } + public SexHistory GetBestSexPartnerHistory + { + get + { + Update(); + SexHistory history = histories.TryGetValue(bestpartnercache); + return history; + } + } + public float TotalSexHad + { + get + { + Update(); + return totalsexcache; + } + } + public int VirginsTaken + { + get + { + return virginstaken; + } + } + public List PartnerList + { + get + { + Update(); + return partnerlistcache; + } + } + public int PartnerCount + { + get + { + if (histories == null) histories = new Dictionary(); + return histories.Count; + } + } + public int IncestuousCount + { + get + { + return incestuous; + } + } + public int RapedCount + { + get + { + Update(); + return totalrapedcache; + } + } + public int BeenRapedCount + { + get + { + Update(); + return totalbeenrapedcache; + } + } + public ThingDef PreferRace + { + get + { + Update(); + return preferracecache; + } + } + public int PreferRaceSexCount + { + get + { + Update(); + return preferracesexcountcache; + } + } + public int BestialityCount + { + get + { + return bestiality; + } + } + public int CorpseFuckCount + { + get + { + return corpsefuck; + } + } + public int InterspeciesCount + { + get + { + return interspecies; + } + } + public float AVGSat + { + get + { + Update(); + if (totalsexcache == 0) return 0; + return sextypesat.Sum() / totalsexcache; + } + } + public Texture GetPreferRaceIcon(Vector2 size) + { + Update(); + if (preferracepawncache != null) return PortraitsCache.Get(preferracepawncache, size, Rot4.South, default, 1, true, true, false, false); + else return HistoryUtility.UnknownPawn; + + } + + public float GetBestSextype(out xxx.rjwSextype sextype) + { + if (dirty) Update(); + sextype = bestsextypecache; + return bestsextypesatcache; + } + + public float GetRecentSextype(out xxx.rjwSextype sextype) + { + if (dirty) Update(); + sextype = recentsex; + return recentsat; + } + + public SexHistory this[Pawn pawn] + { + get + { + return histories.TryGetValue(pawn.ThingID); + } + } + + public float GetAVGSat(xxx.rjwSextype sextype) + { + int index = (int)sextype; + return GetAVGSat(index); + } + + public float GetAVGSat(int index) + { + float res = sextypesat[index] / sextypecount[index]; + return float.IsNaN(res) ? 0f : res; + } + + public int GetSexCount(int index) + { + return sextypecount[index]; + } + + + + public override void PostExposeData() + { + if (Scribe.mode == LoadSaveMode.Saving) + { + sextypecountsave = sextypecount.ToList(); + sextypesatsave = sextypesat.ToList(); + } + + Scribe_Collections.Look(ref histories, "histories", LookMode.Value, LookMode.Deep); + Scribe_Values.Look(ref first, "first", "", true); + Scribe_Values.Look(ref recentsex, "recentsex", recentsex, true); + Scribe_Values.Look(ref recentsat, "recentsat", recentsat, true); + Scribe_Values.Look(ref recentpartner, "recentpartner", recentpartner, true); + Scribe_Values.Look(ref virginstaken, "virginstaken", virginstaken, true); + Scribe_Values.Look(ref incestuous, "incestous", incestuous, true); + Scribe_Values.Look(ref bestiality, "bestiality", bestiality, true); + Scribe_Values.Look(ref corpsefuck, "corpsefuck", corpsefuck, true); + Scribe_Values.Look(ref interspecies, "interspecies", interspecies, true); + Scribe_Collections.Look(ref sextypecountsave, "sextypecountsave", LookMode.Value); + Scribe_Collections.Look(ref sextypesatsave, "sextypesatsave", LookMode.Value); + //Scribe_Values.Look(ref sextypecount, "sextypecount", new int[ARRLEN], true); // not work + //Scribe_Values.Look(ref sextypesat, "sextypesat", new float[ARRLEN], true); + if (Scribe.mode == LoadSaveMode.LoadingVars) + { + sextypecount = sextypecountsave?.ToArray() ?? new int[ARRLEN]; + sextypesat = sextypesatsave?.ToArray() ?? new float[ARRLEN]; + } + + if (histories == null) histories = new Dictionary(); + + base.PostExposeData(); + } + + public void RecordHistory(Pawn partner, SexProps props) + { + Pawn pawn = parent as Pawn; + TryAddHistory(partner); + RecordFirst(partner, props); + recentpartner = partner.ThingID; + SexHistory history = histories[partner.ThingID]; + history?.RecordSex(props); + recentsex = props.sexType; + sextypecount[(int)props.sexType]++; + if (partner.IsIncest(pawn)) incestuous++; + if (partner.Dead) corpsefuck++; + if (props.IsBestiality()) bestiality++; + else if (pawn.def != partner.def) interspecies++; + dirty = true; + } + + public void RecordSatisfactionHistory(Pawn partner, SexProps props, float satisfaction) + { + TryAddHistory(partner); + RecordFirst(partner, props); + SexHistory history = histories[partner.ThingID]; + history?.RecordSatisfaction(props, satisfaction); + recentsat = satisfaction; + sextypesat[(int)props.sexType] += satisfaction; + dirty = true; + } + + protected bool TryAddHistory(Pawn partner) + { + if (!histories.ContainsKey(partner.ThingID)) + { + SexHistory newhistory = new SexHistory(partner,partner.IsIncest(parent as Pawn)); + histories.Add(partner.ThingID, newhistory); + Pawn pawn = parent as Pawn; + if (pawn != null) + { + pawn.records.AddTo(VariousDefOf.SexPartnerCount, 1); + } + return true; + } + return false; + } + + public void RecordFirst(Pawn partner, SexProps props) + { + if (VirginCheck() && props.sexType == xxx.rjwSextype.Vaginal) + { + TryAddHistory(partner); + first = partner.ThingID; + SexPartnerHistory history = partner.GetPartnerHistory(); + if (history != null) + { + history.TakeSomeonesVirgin(parent as Pawn); + } + + } + } + + public void TakeSomeonesVirgin(Pawn partner) + { + TryAddHistory(partner); + SexHistory history = histories[partner.ThingID]; + if (history != null) history.TookVirgin(); + virginstaken++; + } + + protected void Update() + { + if (dirty) + { + UpdateStatistics(); + UpdateBestSex(); + UpdatePartnerList(); + dirty = false; + } + } + + protected void UpdateStatistics() + { + int max = 0; + float maxsat = 0; + float maxf = 0; + int maxindex = 0; + string mostID = Keyed.Unknown; + string bestID = Keyed.Unknown; + totalsexcache = 0; + totalrapedcache = 0; + totalbeenrapedcache = 0; + Dictionary racetotalsat = new Dictionary(); + List allpartners = new List(); + + foreach (KeyValuePair element in histories) + { + SexHistory h = element.Value; + + //find most sex partner + if (max < h.TotalSexCount) + { + max = h.TotalSexCount; + mostID = element.Key; + } + if (maxsat < h.BestSatisfaction) + { + maxsat = h.BestSatisfaction; + bestID = element.Key; + } + + if (h.Partner != null) + { + Pawn partner = h.Partner; + allpartners.Add(partner); + if (racetotalsat.ContainsKey(partner.def)) + { + racetotalsat[partner.def] += h.TotalSexCount - h.RapedMe; + } + else + { + racetotalsat.Add(partner.def, h.TotalSexCount - h.RapedMe); + } + } + + totalsexcache += h.TotalSexCount; + totalrapedcache += h.Raped; + totalbeenrapedcache += h.RapedMe; + } + + if (!racetotalsat.NullOrEmpty()) + { + KeyValuePair prefer = racetotalsat.MaxBy(x => x.Value); + preferracecache = prefer.Key; + preferracesexcountcache = prefer.Value; + preferracepawncache = allpartners.FirstOrDefault(x => x.def == preferracecache); + } + + max = 0; + for (int i=0; i < sextypecount.Length; i++) + { + float avgsat = sextypesat[i] / sextypecount[i]; + if (maxf < avgsat) + { + maxf = avgsat; + maxindex = i; + } + } + + mostsatsextypecache = (xxx.rjwSextype)maxindex; + mostsextypecache = (xxx.rjwSextype)sextypecount.FirstIndexOf(x => x == sextypecount.Max()); + mostpartnercache = mostID; + bestpartnercache = bestID; + + racetotalsat.Clear(); + allpartners.Clear(); + } + + protected void UpdateBestSex() + { + int bestindex = 0; + float bestsat = 0; + float avgsat; + for(int i=0; i< sextypecount.Length; i++) + { + avgsat = sextypesat[i] / sextypecount[i]; + if (bestsat < avgsat) + { + bestindex = i; + bestsat = avgsat; + } + } + bestsextypecache = (xxx.rjwSextype)bestindex; + bestsextypesatcache = bestsat; + } + + protected void UpdatePartnerList() + { + if (partnerlistcache == null) partnerlistcache = new List(); + partnerlistcache.Clear(); + if (!histories.NullOrEmpty()) foreach (SexHistory history in histories.Values) + { + if (history != null) partnerlistcache.Add(history); + } + } + + protected bool VirginCheck() + { + if (histories.TryGetValue(first) != null) return false; + + Pawn pawn = parent as Pawn; + if (pawn != null) + { + if (pawn.IsVirgin()) return true; + } + return false; + } + + + + } + + + public class SexHistory : IExposable + { + protected Pawn partner = null; + protected string namecache; + protected int totalsexhad = 0; + protected int raped = 0; + protected int rapedme = 0; + protected int orgasms = 0; + protected xxx.rjwSextype bestsextype = xxx.rjwSextype.None; + protected float bestsatisfaction = 0; + protected bool itookvirgin = false; + protected bool incest = false; + + public string Label + { + get + { + if (partner != null) + { + namecache = partner.Label; + return namecache; + } + else return namecache; + } + } + public xxx.rjwSextype BestSextype + { + get + { + return bestsextype; + } + } + public float BestSatisfaction + { + get + { + return bestsatisfaction; + } + } + public int TotalSexCount + { + get + { + return totalsexhad; + } + } + public Pawn Partner + { + get + { + return partner; + } + } + public string RapeInfo + { + get + { + string res = ""; + if (raped > 0) res += Keyed.RS_Raped + raped + " "; + if (rapedme > 0) res += Keyed.RS_RapedMe + rapedme + " "; + return res; + } + } + public int OrgasmCount + { + get + { + return orgasms; + } + } + public bool IamFirst + { + get + { + return itookvirgin; + } + } + public bool Incest + { + get + { + return incest; + } + } + public int Raped + { + get + { + return raped; + } + } + public int RapedMe + { + get + { + return rapedme; + } + } + + public SexHistory() { } + + public SexHistory(Pawn pawn, bool incest = false) + { + this.partner = pawn; + this.namecache = pawn.Label; + this.incest = incest; + } + + + public void ExposeData() + { + Scribe_References.Look(ref partner, "partner", true); + Scribe_Values.Look(ref namecache, "namecache", namecache, true); + Scribe_Values.Look(ref totalsexhad, "totalsexhad", totalsexhad, true); + Scribe_Values.Look(ref raped, "raped", raped, true); + Scribe_Values.Look(ref rapedme, "rapedme", rapedme, true); + Scribe_Values.Look(ref orgasms, "orgasms", orgasms, true); + Scribe_Values.Look(ref bestsextype, "bestsextype", bestsextype, true); + Scribe_Values.Look(ref bestsatisfaction, "bestsatisfaction", bestsatisfaction, true); + Scribe_Values.Look(ref itookvirgin, "itookvirgin", itookvirgin, true); + Scribe_Values.Look(ref incest, "incest", incest, true); + } + + public void RecordSex(SexProps props) + { + totalsexhad++; + if (props.isRape) + { + if (partner == props.giver) + { + rapedme++; + } + else if (partner == props.reciever) + { + raped++; + } + } + } + + public void RecordSatisfaction(SexProps props, float satisfaction) + { + if (satisfaction > bestsatisfaction) + { + orgasms++; + bestsextype = props.sexType; + bestsatisfaction = satisfaction; + } + } + + public void TookVirgin() + { + itookvirgin = true; + } + } + +} diff --git a/RJWSexperience/RJWSexperience/Thought_Opinionbased.cs b/RJWSexperience/RJWSexperience/Thought_Opinionbased.cs new file mode 100644 index 0000000..7442e35 --- /dev/null +++ b/RJWSexperience/RJWSexperience/Thought_Opinionbased.cs @@ -0,0 +1,42 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; + + +namespace RJWSexperience +{ + /// + /// ThoughtDef using opinion + /// + public class ThoughtDef_Opinionbased : ThoughtDef + { + public List minimumValueforStage = new List(); + } + + /// + /// Thought class using record. + /// + public class Thought_Opinionbased : Thought_Memory + { + protected ThoughtDef_Opinionbased Def => (ThoughtDef_Opinionbased)def; + protected List minimumValueforStage => Def.minimumValueforStage; + + public override int CurStageIndex + { + get + { + float value = 0f; + if (otherPawn != null) value = pawn.relations?.OpinionOf(otherPawn) ?? 0f; + for (int i = minimumValueforStage.Count - 1; i > 0; i--) + { + if (minimumValueforStage[i] < value) return i; + } + return 0; + } + } + } +} diff --git a/RJWSexperience/RJWSexperience/Thought_Recordbased.cs b/RJWSexperience/RJWSexperience/Thought_Recordbased.cs index 364032d..b99e623 100644 --- a/RJWSexperience/RJWSexperience/Thought_Recordbased.cs +++ b/RJWSexperience/RJWSexperience/Thought_Recordbased.cs @@ -45,9 +45,6 @@ namespace RJWSexperience public class Thought_AteCum : Thought_Recordbased { - - protected int recordIncrement = 1; - public override int CurStageIndex { get @@ -60,21 +57,13 @@ namespace RJWSexperience public override void ExposeData() { base.ExposeData(); - Scribe_Values.Look(ref recordIncrement, "recordIncrement", recordIncrement, true); } - //There is no direct way to modify custom records via ingestion. So i increase it from thought. public override void ThoughtInterval() { base.ThoughtInterval(); - if (recordIncrement >= 1) - { - recordIncrement--; - pawn.records.AddTo(VariousDefOf.NumofEatenCum, 1); - } - } public override bool TryMergeWithExistingMemory(out bool showBubble) @@ -97,13 +86,11 @@ namespace RJWSexperience public override void Init() { base.Init(); - recordIncrement = 1; } protected virtual void Merged() { age = 0; - recordIncrement += 1; } } diff --git a/RJWSexperience/RJWSexperience/UI/RJWUIUtility.cs b/RJWSexperience/RJWSexperience/UI/RJWUIUtility.cs new file mode 100644 index 0000000..b6bc4e6 --- /dev/null +++ b/RJWSexperience/RJWSexperience/UI/RJWUIUtility.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using UnityEngine; +using rjw; + + +namespace RJWSexperience.UI +{ + public static class RJWUIUtility + { + public const float FONTHEIGHT = 22f; + public const float CARDHEIGHT = 110f; + public const float LISTPAWNSIZE = 100f; + public const float BASESAT = 0.40f; + public const float ICONSIZE = 30f; + + + public static void DrawQuirk(this Rect rect, Pawn pawn) + { + List quirks = Quirk.All.FindAll(x => pawn.Has(x)); + string quirkstr = quirks.Select(x => x.Key).ToCommaList(); + string tooltip = ""; + + Widgets.Label(rect, "Quirks".Translate() + quirkstr); + + if (Mouse.IsOver(rect)) + { + if (quirks.NullOrEmpty()) + { + tooltip = "NoQuirks".Translate(); + } + else + { + StringBuilder stringBuilder = new StringBuilder(); + foreach (var q in quirks) + { + stringBuilder.AppendLine(q.Key.Colorize(Color.yellow)); + stringBuilder.AppendLine(q.LocaliztionKey.Translate(pawn.Named("pawn")).AdjustedFor(pawn).Resolve()); + stringBuilder.AppendLine(""); + } + tooltip = stringBuilder.ToString().TrimEndNewlines(); + } + Widgets.DrawHighlight(rect); + } + + TooltipHandler.TipRegion(rect, tooltip); + } + + public static void DrawSexuality(this Rect rect, CompRJW comp) + { + if (comp != null) + { + string sexuality = Keyed.Sexuality[(int)comp.orientation]; + Widgets.Label(rect, Keyed.RS_Sexuality + ": " + sexuality); + Widgets.DrawHighlightIfMouseover(rect); + } + } + + public static string GetRelationsString(this Pawn pawn, Pawn otherpawn) + { + if (otherpawn != null) + { + IEnumerable relations = pawn.GetRelations(otherpawn); + if (!relations.EnumerableNullOrEmpty()) return relations.Select(x => x.GetGenderSpecificLabel(otherpawn)).ToCommaList().CapitalizeFirst(); + } + return ""; + } + + public static void DrawBorder(this Rect rect, Texture border, float thickness = 1f) + { + GUI.DrawTexture(new Rect(rect.x,rect.y,rect.width, thickness), border); + GUI.DrawTexture(new Rect(rect.x+rect.width-thickness,rect.y, thickness, rect.height), border); + GUI.DrawTexture(new Rect(rect.x,rect.y+rect.height - thickness,rect.width, thickness), border); + GUI.DrawTexture(new Rect(rect.x, rect.y, thickness, rect.height), border); + } + + public static string GetStatExplanation(Pawn pawn, StatDef stat, float val) + { + return stat.description + "\n" + + stat.Worker.GetExplanationFull(StatRequest.For(pawn), ToStringNumberSense.Undefined, val); + } + + } +} diff --git a/RJWSexperience/RJWSexperience/UI/SexStatus.cs b/RJWSexperience/RJWSexperience/UI/SexStatus.cs new file mode 100644 index 0000000..b36139d --- /dev/null +++ b/RJWSexperience/RJWSexperience/UI/SexStatus.cs @@ -0,0 +1,608 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; +using Verse.Sound; +using RimWorld; +using rjw; + + +namespace RJWSexperience.UI +{ + public class SexStatusWindow : Window + { + public const float FONTHEIGHT = RJWUIUtility.FONTHEIGHT; + public const float CARDHEIGHT = RJWUIUtility.CARDHEIGHT; + public const float LISTPAWNSIZE = RJWUIUtility.LISTPAWNSIZE; + public const float BASESAT = RJWUIUtility.BASESAT; + public const float ICONSIZE = RJWUIUtility.ICONSIZE; + + public static readonly int[] Sextype = + { + (int)xxx.rjwSextype.Vaginal, + (int)xxx.rjwSextype.Anal, + (int)xxx.rjwSextype.Oral, + (int)xxx.rjwSextype.Fellatio, + (int)xxx.rjwSextype.Cunnilingus, + (int)xxx.rjwSextype.DoublePenetration, + (int)xxx.rjwSextype.Boobjob, + (int)xxx.rjwSextype.Handjob, + (int)xxx.rjwSextype.Footjob, + (int)xxx.rjwSextype.Fingering, + (int)xxx.rjwSextype.Scissoring, + (int)xxx.rjwSextype.MutualMasturbation, + (int)xxx.rjwSextype.Fisting, + (int)xxx.rjwSextype.Rimming, + (int)xxx.rjwSextype.Sixtynine + }; + + + protected Pawn pawn; + protected SexHistory selectedPawn; + protected SexPartnerHistory history; + protected CompRJW rjwcomp; + + private static GUIStyleState fontstylestate = new GUIStyleState() { textColor = Color.white }; + private static GUIStyleState boxstylestate = GUI.skin.textArea.normal; + private static GUIStyleState buttonstylestate = GUI.skin.button.normal; + private static GUIStyle fontstylecenter = new GUIStyle() { alignment = TextAnchor.MiddleCenter, normal = fontstylestate }; + private static GUIStyle fontstyleright = new GUIStyle() { alignment = TextAnchor.MiddleRight, normal = fontstylestate }; + private static GUIStyle fontstyleleft = new GUIStyle() { alignment = TextAnchor.MiddleLeft, normal = fontstylestate }; + private static GUIStyle boxstyle = new GUIStyle(GUI.skin.textArea) { hover = boxstylestate, onHover = boxstylestate, onNormal = boxstylestate }; + private static GUIStyle buttonstyle = new GUIStyle(GUI.skin.button) { hover = buttonstylestate, onHover = buttonstylestate, onNormal = buttonstylestate }; + + private static Vector2 pos; + private static Vector2 scroll; + private static bool opened; + + public SexStatusWindow(Pawn pawn, SexPartnerHistory history) + { + this.pawn = pawn; + this.history = history; + this.selectedPawn = null; + this.rjwcomp = pawn.TryGetComp(); + } + + protected override void SetInitialSizeAndPosition() + { + Vector2 initialSize = InitialSize; + if (!opened) + { + windowRect = new Rect((Verse.UI.screenWidth - initialSize.x) / 2f, ((float)Verse.UI.screenHeight - initialSize.y) / 2f, initialSize.x, initialSize.y); + opened = true; + } + else + { + windowRect = new Rect(pos, initialSize); + } + windowRect = windowRect.Rounded(); + + } + + public override Vector2 InitialSize + { + get + { + float width = 900f; + float height = 600f; + soundClose = SoundDefOf.CommsWindow_Close; + absorbInputAroundWindow = false; + forcePause = false; + preventCameraMotion = false; + draggable = true; + doCloseX = true; + return new Vector2(width, height); + } + } + + + public override void DoWindowContents(Rect inRect) + { + pos = windowRect.position; + if (!Configurations.SelectionLocked) + { + List selected = Find.Selector.SelectedPawns; + if (selected.Count == 1) + { + Pawn p = selected.First(); + if (p != pawn) + { + SexPartnerHistory h = p.GetPartnerHistory(); + if (h != null) ChangePawn(p, h); + } + } + } + + + DrawSexStatus(inRect,history); + } + + public static void ToggleWindow(Pawn pawn, SexPartnerHistory history) + { + SexStatusWindow window = (SexStatusWindow)Find.WindowStack.Windows.FirstOrDefault(x => x.GetType() == typeof(SexStatusWindow)); + if (window != null) + { + if (window.pawn != pawn) + { + SoundDefOf.TabOpen.PlayOneShotOnCamera(); + window.ChangePawn(pawn, history); + } + } + else + { + Find.WindowStack.Add(new SexStatusWindow(pawn, history)); + } + } + + public void ChangePawn(Pawn pawn, SexPartnerHistory history) + { + List selected = Find.Selector.SelectedPawns; + if (!selected.NullOrEmpty()) foreach(Pawn p in selected) + { + Find.Selector.Deselect(p); + } + this.pawn = pawn; + this.history = history; + this.selectedPawn = null; + this.rjwcomp = pawn.TryGetComp(); + if (!pawn.DestroyedOrNull() && Find.CurrentMap == pawn.Map) Find.Selector.Select(pawn); + } + + /// + /// Main contents + /// + protected void DrawSexStatus(Rect mainrect, SexPartnerHistory history) + { + float sectionwidth = mainrect.width / 3; + + Rect leftRect = new Rect(mainrect.x, mainrect.y, sectionwidth, mainrect.height); + Rect centerRect = new Rect(mainrect.x + sectionwidth, mainrect.y, sectionwidth, mainrect.height); + Rect rightRect = new Rect(mainrect.x + sectionwidth * 2, mainrect.y, sectionwidth, mainrect.height); + + if (history != null) + { + //Left section + DrawBaseSexInfoLeft(leftRect.ContractedBy(4f)); + + //Center section + DrawBaseSexInfoCenter(centerRect.ContractedBy(4f),history.parent as Pawn); + + //Right section + DrawBaseSexInfoRight(rightRect.ContractedBy(4f)); + } + + + + } + + protected void DrawInfoWithPortrait(Rect rect, SexHistory history, string tooltip = "") + { + Widgets.DrawMenuSection(rect); + string str = tooltip; + Rect portraitRect = new Rect(rect.x, rect.y, rect.height - FONTHEIGHT, rect.height - FONTHEIGHT); + Rect nameRect = new Rect(rect.x + portraitRect.width, rect.y, rect.width - portraitRect.width, FONTHEIGHT); + Rect sexinfoRect = new Rect(rect.x + portraitRect.width, rect.y + FONTHEIGHT, rect.width - portraitRect.width, FONTHEIGHT); + Rect sexinfoRect2 = new Rect(rect.x + portraitRect.width, rect.y + FONTHEIGHT * 2, rect.width - portraitRect.width, FONTHEIGHT); + Rect bestsexRect = new Rect(rect.x + 2f, rect.y + FONTHEIGHT * 3, rect.width - 4f, FONTHEIGHT - 2f); + + if (history != null) + { + if (history.Incest) str += " - " + Keyed.Incest; + Pawn partner = history.Partner; + DrawPawn(portraitRect, history); + Widgets.DrawHighlightIfMouseover(portraitRect); + if (Widgets.ButtonInvisible(portraitRect)) + { + SexPartnerHistory pawnhistory = partner?.GetPartnerHistory(); + if (pawnhistory != null) + { + ChangePawn(partner, pawnhistory); + SoundDefOf.Click.PlayOneShotOnCamera(); + } + else SoundDefOf.ClickReject.PlayOneShotOnCamera(); + } + GUI.Label(nameRect, partner?.Name?.ToStringFull ?? history.Label.CapitalizeFirst(), fontstyleleft); + GUI.Label(sexinfoRect, Keyed.RS_Sex_Count + history.TotalSexCount + " " + history.RapeInfo, fontstyleleft); + GUI.Label(sexinfoRect2, Keyed.RS_Orgasms + history.OrgasmCount, fontstyleleft); + GUI.Label(sexinfoRect2, pawn.GetRelationsString(partner) + " ", fontstyleright); + float p = history.BestSatisfaction / BASESAT; + FillableBarLabeled(bestsexRect,String.Format(Keyed.RS_Best_Sextype+": {0}", Keyed.Sextype[(int)history.BestSextype]), p / 2, HistoryUtility.SextypeColor[(int)history.BestSextype], Texture2D.blackTexture, null, String.Format("{0:P2}", p)); + + if (history.IamFirst) str += "\n" + Keyed.RS_LostVirgin(history.Label, pawn.LabelShort); + + + TooltipHandler.TipRegion(rect, str); + } + else + { + Widgets.DrawTextureFitted(portraitRect, HistoryUtility.UnknownPawn, 1.0f); + Widgets.Label(nameRect, Keyed.Unknown); + Widgets.Label(sexinfoRect, Keyed.RS_Sex_Count + "?"); + Widgets.Label(sexinfoRect2, Keyed.RS_Orgasms+"?"); + FillableBarLabeled(bestsexRect,String.Format(Keyed .RS_Best_Sextype + ": {0}", Keyed.Sextype[(int)xxx.rjwSextype.None]), 0, Texture2D.linearGrayTexture, Texture2D.blackTexture); + } + } + + protected void DrawSexInfoCard(Rect rect, SexHistory history, string label, string tooltip) + { + Rect labelRect = new Rect(rect.x, rect.y, rect.width, FONTHEIGHT); + Rect infoRect = new Rect(rect.x, rect.y + FONTHEIGHT, rect.width, rect.height - FONTHEIGHT); + GUI.Label(labelRect, label, fontstyleleft); + DrawInfoWithPortrait(infoRect,history, tooltip); + + + } + + /// + /// Right section + /// + protected void DrawBaseSexInfoRight(Rect rect) + { + Listing_Standard listmain = new Listing_Standard(); + listmain.Begin(rect.ContractedBy(4f)); + DrawSexInfoCard(listmain.GetRect(CARDHEIGHT), history.GetRecentPartnersHistory, Keyed.RS_Recent_Sex_Partner, Keyed.RS_Recent_Sex_Partner_ToolTip); + DrawSexInfoCard(listmain.GetRect(CARDHEIGHT), history.GetFirstPartnerHistory, Keyed.RS_First_Sex_Partner, Keyed.RS_First_Sex_Partner_ToolTip); + DrawSexInfoCard(listmain.GetRect(CARDHEIGHT), history.GetMostPartnerHistory, Keyed.RS_Most_Sex_Partner, Keyed.RS_Most_Sex_Partner_ToolTip); + DrawSexInfoCard(listmain.GetRect(CARDHEIGHT), history.GetBestSexPartnerHistory, Keyed.RS_Best_Sex_Partner, Keyed.RS_Best_Sex_Partner_ToolTip); + GUI.Label(listmain.GetRect(FONTHEIGHT), Keyed.RS_PreferRace, fontstyleleft); + DrawPreferRace(listmain.GetRect(66f+15f)); + listmain.GetRect(15f); + + + listmain.End(); + } + + protected void DrawPreferRace(Rect rect) + { + Widgets.DrawMenuSection(rect); + Rect portraitRect = new Rect(rect.x, rect.y, rect.height-15f, rect.height-15f); + Rect infoRect1 = new Rect(rect.x + portraitRect.width, rect.y, rect.width - portraitRect.width, FONTHEIGHT); + Rect infoRect2 = new Rect(rect.x + portraitRect.width, rect.y + FONTHEIGHT, rect.width - portraitRect.width, FONTHEIGHT); + Rect infoRect3 = new Rect(rect.x + portraitRect.width, rect.y + FONTHEIGHT*2, rect.width - portraitRect.width - 2f, FONTHEIGHT); + + if (history.PreferRace != null) + { + Widgets.DrawTextureFitted(portraitRect, history.GetPreferRaceIcon(portraitRect.size), 1.0f); + GUI.Label(infoRect1, history.PreferRace?.label.CapitalizeFirst() ?? Keyed.None, fontstyleleft); + GUI.Label(infoRect2, Keyed.RS_Sex_Count + history.PreferRaceSexCount, fontstyleleft); + if (history.PreferRace != pawn.def) + { + if (history.PreferRace.race.Animal ^ pawn.def.race.Animal) + { + GUI.Label(infoRect1, Keyed.RS_Bestiality + " ", fontstyleright); + FillableBarLabeled(infoRect3, Keyed.RS_Sex_Info(Keyed.RS_Bestiality, history.BestialityCount.ToString()), history.BestialityCount/100f, Texture2D.linearGrayTexture, Texture2D.blackTexture); + } + else + { + GUI.Label(infoRect1, Keyed.RS_Interspecies + " ", fontstyleright); + FillableBarLabeled(infoRect3, Keyed.RS_Sex_Info(Keyed.RS_Interspecies, history.InterspeciesCount.ToString()), history.InterspeciesCount / 100f, Texture2D.linearGrayTexture, Texture2D.blackTexture); + } + } + else + { + GUI.Label(infoRect1, Keyed.RS_Normal + " ", fontstyleright); + } + } + else + { + Widgets.DrawTextureFitted(portraitRect, HistoryUtility.UnknownPawn, 1.0f); + GUI.Label(infoRect1, Keyed.None, fontstyleleft); + } + } + + + /// + /// Center section + /// + protected void DrawBaseSexInfoCenter(Rect rect, Pawn pawn) + { + Rect portraitRect = new Rect(rect.x + rect.width / 4, rect.y, rect.width / 2, rect.width / 1.5f); + Rect nameRect = new Rect(portraitRect.x, portraitRect.yMax - FONTHEIGHT * 2, portraitRect.width, FONTHEIGHT * 2); + Rect infoRect = new Rect(rect.x, rect.y + portraitRect.height, rect.width, rect.height - portraitRect.height); + Rect lockRect = new Rect(portraitRect.xMax - ICONSIZE, portraitRect.y, ICONSIZE, ICONSIZE); + Rect tmp; + + if (Mouse.IsOver(portraitRect)) + { + Texture lockicon = Configurations.SelectionLocked ? HistoryUtility.Locked : HistoryUtility.Unlocked; + Widgets.DrawTextureFitted(lockRect, lockicon, 1.0f); + if (Widgets.ButtonInvisible(lockRect)) + { + SoundDefOf.Click.PlayOneShotOnCamera(); + Configurations.SelectionLocked = !Configurations.SelectionLocked; + } + } + + + GUI.Box(portraitRect, "", boxstyle); + Widgets.DrawTextureFitted(portraitRect, PortraitsCache.Get(pawn, portraitRect.size, Rot4.South, default, 1, true, true, false, false), 1.0f); + Widgets.DrawHighlightIfMouseover(portraitRect); + if (Widgets.ButtonInvisible(portraitRect)) + { + SoundDefOf.Click.PlayOneShotOnCamera(); + selectedPawn = null; + } + + GUI.Box(nameRect, "", boxstyle); + GUI.Label(nameRect.TopHalf(), pawn.Name?.ToStringFull ?? pawn.Label, fontstylecenter); + if (pawn.story != null) GUI.Label(nameRect.BottomHalf(), pawn.ageTracker.AgeBiologicalYears + ", " + pawn.story.Title, fontstylecenter); + else GUI.Label(nameRect.BottomHalf(), pawn.ageTracker.AgeBiologicalYears + ", " + pawn.def.label, fontstylecenter); + + Listing_Standard listmain = new Listing_Standard(); + listmain.Begin(infoRect); + listmain.Gap(20f); + float p; + + if (pawn.IsVirgin()) + { + tmp = listmain.GetRect(FONTHEIGHT); + GUI.color = Color.red; + GUI.Box(tmp, "", boxstyle); + GUI.color = Color.white; + GUI.Label(tmp, "Virgin", fontstylecenter); + } + else + { + p = history.TotalSexHad; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_TotalSexHad + ": {0:0} ({1:0})", p, pawn.records.GetValue(xxx.CountOfSex)), p / 100, HistoryUtility.TotalSex, Texture2D.blackTexture, null, Keyed.RS_SAT_AVG(String.Format("{0:P2}", history.AVGSat))); + } + listmain.Gap(1f); + + + tmp = listmain.GetRect(FONTHEIGHT); + p = pawn.records.GetValue(VariousDefOf.Lust); + FillableBarLabeled(tmp, String.Format(Keyed.Lust +": {0:0.00}", p), Mathf.Clamp01(p.Normalization(-Configurations.LustLimit*3, Configurations.LustLimit*3)), HistoryUtility.Slaanesh, Texture2D.blackTexture, null, String.Format(xxx.sex_drive_stat.LabelCap.CapitalizeFirst() + ": {0:P2}", pawn.GetStatValue(xxx.sex_drive_stat))); + listmain.Gap(1f); + if (Mouse.IsOver(tmp)) + { + TooltipHandler.TipRegion(tmp, RJWUIUtility.GetStatExplanation(pawn, xxx.sex_drive_stat, pawn.GetStatValue(xxx.sex_drive_stat))); + } + + p = history.GetBestSextype(out xxx.rjwSextype sextype) / BASESAT; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT),String.Format(Keyed.RS_Best_Sextype+": {0}", Keyed.Sextype[(int)sextype]), p / 2, HistoryUtility.SextypeColor[(int)sextype], Texture2D.blackTexture, null, Keyed.RS_SAT_AVG(String.Format("{0:P2}", p))); + listmain.Gap(1f); + + p = history.GetRecentSextype(out sextype) / BASESAT; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT),String.Format(Keyed.RS_Recent_Sextype+": {0}", Keyed.Sextype[(int)sextype]), p / 2, HistoryUtility.SextypeColor[(int)sextype], Texture2D.blackTexture, null, String.Format("{0:P2}", p)); + listmain.Gap(1f); + + if (history.IncestuousCount < history.CorpseFuckCount) + { + p = history.CorpseFuckCount; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_Necrophile + ": {0}", p), p / 50, HistoryUtility.Nurgle, Texture2D.blackTexture); + listmain.Gap(1f); + } + else + { + p = history.IncestuousCount; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.Incest + ": {0}", p), p / 50, HistoryUtility.Nurgle, Texture2D.blackTexture); + listmain.Gap(1f); + } + + p = pawn.records.GetValue(VariousDefOf.AmountofEatenCum); + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_Cum_Swallowed + ": {0:0.00} mL, {1} " + Keyed.RS_NumofTimes, p, pawn.records.GetValue(VariousDefOf.NumofEatenCum)), p / 1000, Texture2D.linearGrayTexture, Texture2D.blackTexture); + listmain.Gap(1f); + + Hediff addiction = pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.CumAddiction); + if (addiction != null) + { + p = addiction.Severity; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_CumAddiction + ": {0:P2}", p), p, Texture2D.linearGrayTexture, Texture2D.blackTexture, Keyed.RS_CumAddiction_Tooltip); + listmain.Gap(1f); + } + else if ((addiction = pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.CumTolerance)) != null) + { + p = addiction.Severity; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_CumAddictiveness + ": {0:P}", p), p, Texture2D.linearGrayTexture, Texture2D.blackTexture, Keyed.RS_CumAddictiveness_Tooltip); + listmain.Gap(1f); + } + else + { + listmain.GetRect(FONTHEIGHT); + listmain.Gap(1f); + } + + + //listmain.GetRect(FONTHEIGHT); + //listmain.Gap(1f); + + p = history.RapedCount; + tmp = listmain.GetRect(FONTHEIGHT); + if (p < history.BeenRapedCount) + { + p = history.BeenRapedCount; + FillableBarLabeled(tmp, String.Format(Keyed.RS_BeenRaped + ": {0}", p), p / 50, Texture2D.grayTexture, Texture2D.blackTexture, null, String.Format(xxx.vulnerability_stat.LabelCap.CapitalizeFirst() + ": {0:P2}", pawn.GetStatValue(xxx.vulnerability_stat))); + listmain.Gap(1f); + } + else + { + FillableBarLabeled(tmp, String.Format(Keyed.RS_RapedSomeone + ": {0}", p), p / 50, HistoryUtility.Khorne, Texture2D.blackTexture, null, String.Format(xxx.vulnerability_stat.LabelCap.CapitalizeFirst() + ": {0:P2}", pawn.GetStatValue(xxx.vulnerability_stat))); + listmain.Gap(1f); + } + if (Mouse.IsOver(tmp)) + { + TooltipHandler.TipRegion(tmp, RJWUIUtility.GetStatExplanation(pawn, xxx.vulnerability_stat, pawn.GetStatValue(xxx.vulnerability_stat))); + } + + + p = pawn.GetStatValue(xxx.sex_satisfaction); + tmp = listmain.GetRect(FONTHEIGHT); + FillableBarLabeled(tmp, String.Format(xxx.sex_satisfaction.LabelCap.CapitalizeFirst() + ": {0:P2}", p), p/2, HistoryUtility.Satisfaction, Texture2D.blackTexture); + listmain.Gap(1f); + if (Mouse.IsOver(tmp)) + { + TooltipHandler.TipRegion(tmp, RJWUIUtility.GetStatExplanation(pawn, xxx.sex_satisfaction, pawn.GetStatValue(xxx.sex_satisfaction))); + } + + //p = pawn.GetStatValue(xxx.vulnerability_stat); + //FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(xxx.vulnerability_stat.LabelCap.CapitalizeFirst() + ": {0:P2}", p), p / 2, HistoryUtility.Khorne, Texture2D.blackTexture, xxx.vulnerability_stat.description); + //listmain.Gap(1f); + + SkillRecord skill = pawn.skills?.GetSkill(VariousDefOf.SexSkill); + p = skill?.Level ?? 0; + tmp = listmain.GetRect(FONTHEIGHT); + FillableBarLabeled(tmp, String.Format(Keyed.RS_SexSkill + ": {0}, {1:P2}", p, skill?.xpSinceLastLevel/ skill?.XpRequiredForLevelUp), p / 20, HistoryUtility.Tzeentch, Texture2D.blackTexture, null, String.Format(xxx.sex_stat.LabelCap.CapitalizeFirst() + ": {0:P2}", pawn.GetStatValue(xxx.sex_stat)), HistoryUtility.PassionBG[(int)(skill?.passion ?? 0)]); + if (Mouse.IsOver(tmp)) + { + TooltipHandler.TipRegion(tmp, RJWUIUtility.GetStatExplanation(pawn, xxx.sex_stat, pawn.GetStatValue(xxx.sex_stat))); + } + + + listmain.Gap(1f); + + if (selectedPawn != null) DrawSexInfoCard(listmain.GetRect(CARDHEIGHT), selectedPawn, Keyed.RS_Selected_Partner, Keyed.RS_Selected_Partner); + else DrawExtraInfo(listmain.GetRect(CARDHEIGHT)); + + listmain.End(); + } + + protected void DrawExtraInfo(Rect rect) + { + Widgets.DrawMenuSection(rect); + Rect inRect = rect.ContractedBy(4f); + Listing_Standard listmain = new Listing_Standard(); + listmain.Begin(inRect); + listmain.Gap(4f); + listmain.GetRect(FONTHEIGHT).DrawSexuality(rjwcomp); + listmain.Gap(1f); + listmain.GetRect(FONTHEIGHT).DrawQuirk(pawn); + listmain.Gap(1f); + + + + listmain.End(); + + + } + + + + /// + /// Left section + /// + protected void DrawBaseSexInfoLeft(Rect rect) + { + + Listing_Standard listmain = new Listing_Standard(); + listmain.Begin(rect); + float p; + + //Sex statistics + GUI.Label(listmain.GetRect(FONTHEIGHT), " " + Keyed.RS_Statistics, fontstyleleft); + listmain.Gap(1f); + for (int i = 0; i < Sextype.Length; i++) + { + int sexindex = Sextype[i]; + p = history.GetAVGSat(sexindex) / BASESAT; + string label = Keyed.RS_Sex_Info(Keyed.Sextype[sexindex], history.GetSexCount(sexindex).ToString()); + FillableBarLabeled(listmain.GetRect(FONTHEIGHT),label, p / 2, HistoryUtility.SextypeColor[sexindex], Texture2D.blackTexture, null, Keyed.RS_SAT_AVG(String.Format("{0:P2}", p))); + listmain.Gap(1f); + } + + p = history.PartnerCount; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_Sex_Partners + ": {0} ({1})", p, pawn.records.GetValue(VariousDefOf.SexPartnerCount)), p / 50, HistoryUtility.Partners, Texture2D.blackTexture); + listmain.Gap(1f); + + p = history.VirginsTaken; + FillableBarLabeled(listmain.GetRect(FONTHEIGHT), String.Format(Keyed.RS_VirginsTaken + ": {0:0}", p), p / 100, HistoryUtility.Partners, Texture2D.blackTexture); + listmain.Gap(1f); + + //Partner list + GUI.Label(listmain.GetRect(FONTHEIGHT)," "+Keyed.RS_PartnerList, fontstyleleft); + listmain.Gap(1f); + + Rect scrollRect = listmain.GetRect(CARDHEIGHT+1f); + GUI.Box(scrollRect,"", buttonstyle); + List partnerList = history.PartnerList; + Rect listRect = new Rect(scrollRect.x, scrollRect.y, LISTPAWNSIZE * partnerList.Count, scrollRect.height - 30f); + Widgets.BeginScrollView(scrollRect, ref scroll, listRect); + Widgets.ScrollHorizontal(scrollRect, ref scroll, listRect); + DrawPartnerList(listRect, partnerList); + Widgets.EndScrollView(); + + listmain.End(); + } + + protected void DrawPartnerList(Rect rect, List partnerList) + { + Rect pawnRect = new Rect(rect.x, rect.y, LISTPAWNSIZE, LISTPAWNSIZE); + for (int i = 0; i < partnerList.Count; i++) + { + Rect labelRect = new Rect(pawnRect.x,pawnRect.yMax - FONTHEIGHT,pawnRect.width,FONTHEIGHT); + + DrawPawn(pawnRect, partnerList[i]); + Widgets.DrawHighlightIfMouseover(pawnRect); + GUI.Label(labelRect, partnerList[i].Label, fontstylecenter); + if (Widgets.ButtonInvisible(pawnRect)) + { + selectedPawn = partnerList[i]; + SoundDefOf.Click.PlayOneShotOnCamera(); + } + if (partnerList[i] == selectedPawn) + { + Widgets.DrawHighlightSelected(pawnRect); + } + + pawnRect.x += LISTPAWNSIZE; + } + } + + protected void DrawPawn(Rect rect, SexHistory history) + { + if (history != null) + { + bool drawheart = false; + Rect iconRect = new Rect(rect.x + rect.width * 3 / 4, rect.y, rect.width / 4, rect.height / 4); + Texture img = HistoryUtility.UnknownPawn; + if (history.Partner != null) + { + img = PortraitsCache.Get(history.Partner, rect.size, Rot4.South, default, 1, true, true, false, false); + if (history.IamFirst) + { + GUI.color = HistoryUtility.HistoryColor; + Widgets.DrawTextureFitted(rect, HistoryUtility.FirstOverlay, 1.0f); + GUI.color = Color.white; + } + + drawheart = LovePartnerRelationUtility.LovePartnerRelationExists(pawn, history.Partner); + + } + + if (history.Incest) + { + Widgets.DrawTextureFitted(iconRect, HistoryUtility.Incest, 1.0f); + iconRect.x -= iconRect.width; + } + Widgets.DrawTextureFitted(rect, img, 1.0f); + if (drawheart) + { + Widgets.DrawTextureFitted(iconRect, HistoryUtility.Heart,1.0f); + iconRect.x -= iconRect.width; + } + } + } + + + + + public static void FillableBarLabeled(Rect rect, string label, float fillPercent, Texture2D filltexture, Texture2D bgtexture, string tooltip = null, string rightlabel = "", Texture2D border = null) + { + Widgets.FillableBar(rect, Math.Min(fillPercent, 1.0f), filltexture, bgtexture, true); + GUI.Label(rect, " " + label.CapitalizeFirst(), fontstyleleft); + GUI.Label(rect, rightlabel.CapitalizeFirst() + " ", fontstyleright); + Widgets.DrawHighlightIfMouseover(rect); + if (tooltip != null) TooltipHandler.TipRegion(rect, tooltip); + if (border != null) + { + rect.DrawBorder(border,2f); + } + + } + + } + + +} diff --git a/RJWSexperience/RJWSexperience/Utility.cs b/RJWSexperience/RJWSexperience/Utility.cs index 199e6f3..dc94fd5 100644 --- a/RJWSexperience/RJWSexperience/Utility.cs +++ b/RJWSexperience/RJWSexperience/Utility.cs @@ -10,26 +10,23 @@ using UnityEngine; namespace RJWSexperience { + public static class Utility { public static System.Random random = new System.Random(Environment.TickCount); - //public static readonly Dictionary sextypeRecords = new Dictionary { - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex }, - // { xxx.rjwSextype.Vaginal, xxx.CountOfSex } - // - // - //}; + public static bool IsIncest(this Pawn pawn, Pawn otherpawn) + { + if (otherpawn != null) + { + IEnumerable relations = pawn.GetRelations(otherpawn); + if (!relations.EnumerableNullOrEmpty()) foreach (PawnRelationDef relation in relations) + { + if (relation.incestOpinionOffset < 0) return true; + } + } + return false; + } public static float RandGaussianLike(float min, float max, int iterations = 3) { @@ -59,6 +56,15 @@ namespace RJWSexperience return value; } + public static int RecordRandomizer(this Pawn pawn, RecordDef record, int avg, int dist, int min = 0, int max = int.MaxValue) + { + int value = (int)Mathf.Clamp(RandGaussianLike(avg - dist, avg + dist), min, max); + int recordvalue = pawn.records.GetAsInt(record); + pawn.records.AddTo(record, value - recordvalue); + + return value; + } + public static bool ContainAll(this string str, string[] tags) { string lstr = str.ToLower(); @@ -86,17 +92,17 @@ namespace RJWSexperience } - public static Building GetAdjacentBuilding(this Pawn pawn) where T : Building + public static T GetAdjacentBuilding(this Pawn pawn) where T : Building { if (pawn.Spawned) { EdificeGrid edifice = pawn.Map.edificeGrid; - if (edifice[pawn.Position] is T) return edifice[pawn.Position]; + if (edifice[pawn.Position] is T) return (T)edifice[pawn.Position]; IEnumerable adjcells = GenAdjFast.AdjacentCells8Way(pawn.Position); foreach(IntVec3 pos in adjcells) { - if (edifice[pos] is T) return edifice[pos]; + if (edifice[pos] is T) return (T)edifice[pos]; } } return null; @@ -139,18 +145,6 @@ namespace RJWSexperience return res; } - public static void CumDrugEffect(this Pawn pawn) - { - Need need = pawn.needs?.TryGetNeed(VariousDefOf.Chemical_Cum); - if (need != null) need.CurLevel += VariousDefOf.CumneedLevelOffset; - Hediff addictive = HediffMaker.MakeHediff(VariousDefOf.CumTolerance, pawn); - addictive.Severity = 0.032f; - pawn.health.AddHediff(addictive); - Hediff addiction = pawn.health.hediffSet.GetFirstHediffOfDef(VariousDefOf.CumAddiction); - if (addiction != null) addiction.Severity += VariousDefOf.CumexistingAddictionSeverityOffset; - - pawn.needs?.mood?.thoughts?.memories?.TryGainMemoryFast(VariousDefOf.AteCum); - } public static float Normalization(this float num, float min, float max) { @@ -163,5 +157,134 @@ namespace RJWSexperience return num * (max - min) + min; } + public static void ResetRecord(this Pawn pawn, bool allzero) + { + if (!allzero) + { + if (Configurations.EnableRecordRandomizer && pawn != null && xxx.is_human(pawn)) + { + int avgsex = -500; + bool isvirgin = Rand.Chance(Configurations.VirginRatio); + int totalsex = 0; + int totalbirth = 0; + int deviation = (int)Configurations.MaxSexCountDeviation; + if (pawn.story != null) + { + float lust; + if (xxx.is_nympho(pawn)) lust = pawn.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, 0); + else lust = pawn.RecordRandomizer(VariousDefOf.Lust, Configurations.AvgLust, Configurations.MaxLustDeviation, float.MinValue); + + int sexableage = 0; + int minsexage = (int)(pawn.RaceProps.lifeExpectancy * Configurations.MinSexablePercent); + if (pawn.ageTracker.AgeBiologicalYears > minsexage) + { + sexableage = pawn.ageTracker.AgeBiologicalYears - minsexage; + avgsex = (int)(sexableage * Configurations.SexPerYear * pawn.LustFactor()); + } + + + if (pawn.relations != null && pawn.gender == Gender.Female) + { + totalbirth += pawn.relations.ChildrenCount; + totalsex += totalbirth; + pawn.records?.AddTo(xxx.CountOfSexWithHumanlikes, totalbirth); + pawn.records?.SetTo(xxx.CountOfBirthHuman, totalbirth); + if (totalbirth > 0) isvirgin = false; + } + if (!isvirgin) + { + if (xxx.is_rapist(pawn)) + { + if (xxx.is_zoophile(pawn)) + { + if (pawn.Has(Quirk.ChitinLover)) totalsex += pawn.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, deviation); + else totalsex += pawn.RecordRandomizer(xxx.CountOfRapedAnimals, avgsex, deviation); + } + else totalsex += pawn.RecordRandomizer(xxx.CountOfRapedHumanlikes, avgsex, deviation); + avgsex /= 8; + } + + if (xxx.is_zoophile(pawn)) + { + if (pawn.Has(Quirk.ChitinLover)) totalsex += pawn.RecordRandomizer(xxx.CountOfRapedInsects, avgsex, deviation); + else totalsex += pawn.RecordRandomizer(xxx.CountOfSexWithAnimals, avgsex, deviation); + avgsex /= 10; + } + else if (xxx.is_necrophiliac(pawn)) + { + totalsex += pawn.RecordRandomizer(xxx.CountOfSexWithCorpse, avgsex, deviation); + avgsex /= 4; + } + + if (pawn.IsSlave) + { + totalsex += pawn.RecordRandomizer(xxx.CountOfBeenRapedByAnimals, Rand.Range(-50, 10), Rand.Range(0, 10) * sexableage); + totalsex += pawn.RecordRandomizer(xxx.CountOfBeenRapedByHumanlikes, 0, Rand.Range(0, 100) * sexableage); + } + + + totalsex += pawn.RecordRandomizer(xxx.CountOfSexWithHumanlikes, avgsex, deviation); + + if (totalsex > 0) pawn.records.AddTo(VariousDefOf.SexPartnerCount, Math.Max(1, Rand.Range(0, totalsex / 7))); + } + } + pawn.records?.SetTo(xxx.CountOfSex, totalsex); + RJWUtility.GenerateSextypeRecords(pawn, totalsex); + } + if (pawn.story?.traits != null) + { + if (pawn.IsVirgin()) + { + int degree = 0; + if (pawn.gender == Gender.Female) degree = 2; + Trait virgin = new Trait(VariousDefOf.Virgin, degree, true); + pawn.story.traits.GainTrait(virgin); + } + else if (pawn.gender == Gender.Female && Rand.Chance(0.05f)) + { + Trait virgin = new Trait(VariousDefOf.Virgin, 1, true); + pawn.story.traits.GainTrait(virgin); + } + } + } + else + { + pawn.records.SetTo(VariousDefOf.Lust, 0); + pawn.records.SetTo(VariousDefOf.NumofEatenCum, 0); + pawn.records.SetTo(VariousDefOf.AmountofEatenCum, 0); + pawn.records.SetTo(VariousDefOf.VaginalSexCount, 0); + pawn.records.SetTo(VariousDefOf.AnalSexCount, 0); + pawn.records.SetTo(VariousDefOf.OralSexCount, 0); + pawn.records.SetTo(VariousDefOf.BlowjobCount, 0); + pawn.records.SetTo(VariousDefOf.CunnilingusCount, 0); + pawn.records.SetTo(VariousDefOf.GenitalCaressCount, 0); + pawn.records.SetTo(VariousDefOf.HandjobCount, 0); + pawn.records.SetTo(VariousDefOf.FingeringCount, 0); + pawn.records.SetTo(VariousDefOf.FootjobCount, 0); + pawn.records.SetTo(VariousDefOf.MiscSexualBehaviorCount, 0); + pawn.records.SetTo(VariousDefOf.SexPartnerCount, 0); + pawn.records.SetTo(VariousDefOf.OrgasmCount, 0); + pawn.records.SetTo(xxx.CountOfBeenRapedByAnimals, 0); + pawn.records.SetTo(xxx.CountOfBeenRapedByHumanlikes, 0); + pawn.records.SetTo(xxx.CountOfBeenRapedByInsects, 0); + pawn.records.SetTo(xxx.CountOfBeenRapedByOthers, 0); + pawn.records.SetTo(xxx.CountOfBirthAnimal, 0); + pawn.records.SetTo(xxx.CountOfBirthEgg, 0); + pawn.records.SetTo(xxx.CountOfBirthHuman, 0); + pawn.records.SetTo(xxx.CountOfFappin, 0); + pawn.records.SetTo(xxx.CountOfRapedAnimals, 0); + pawn.records.SetTo(xxx.CountOfRapedHumanlikes, 0); + pawn.records.SetTo(xxx.CountOfRapedInsects, 0); + pawn.records.SetTo(xxx.CountOfRapedOthers, 0); + pawn.records.SetTo(xxx.CountOfSex, 0); + pawn.records.SetTo(xxx.CountOfSexWithAnimals, 0); + pawn.records.SetTo(xxx.CountOfSexWithCorpse, 0); + pawn.records.SetTo(xxx.CountOfSexWithHumanlikes, 0); + pawn.records.SetTo(xxx.CountOfSexWithInsects, 0); + pawn.records.SetTo(xxx.CountOfSexWithOthers, 0); + pawn.records.SetTo(xxx.CountOfWhore, 0); + } + } + } } diff --git a/RJWSexperience/RJWSexperience/VariousDefOf.cs b/RJWSexperience/RJWSexperience/VariousDefOf.cs index 2210db1..48730bc 100644 --- a/RJWSexperience/RJWSexperience/VariousDefOf.cs +++ b/RJWSexperience/RJWSexperience/VariousDefOf.cs @@ -11,6 +11,7 @@ namespace RJWSexperience public static class VariousDefOf { public static readonly RecordDef NumofEatenCum = DefDatabase.GetNamed("NumofEatenCum"); + public static readonly RecordDef AmountofEatenCum = DefDatabase.GetNamed("AmountofEatenCum"); public static readonly RecordDef Lust = DefDatabase.GetNamed("Lust"); public static readonly RecordDef VaginalSexCount = DefDatabase.GetNamed("VaginalSexCount"); public static readonly RecordDef AnalSexCount = DefDatabase.GetNamed("AnalSexCount"); @@ -18,20 +19,27 @@ namespace RJWSexperience public static readonly RecordDef BlowjobCount = DefDatabase.GetNamed("BlowjobCount"); public static readonly RecordDef CunnilingusCount = DefDatabase.GetNamed("CunnilingusCount"); public static readonly RecordDef GenitalCaressCount = DefDatabase.GetNamed("GenitalCaressCount"); - public static readonly RecordDef HadnjobCount = DefDatabase.GetNamed("HadnjobCount"); + public static readonly RecordDef HandjobCount = DefDatabase.GetNamed("HandjobCount"); public static readonly RecordDef FingeringCount = DefDatabase.GetNamed("FingeringCount"); public static readonly RecordDef FootjobCount = DefDatabase.GetNamed("FootjobCount"); public static readonly RecordDef MiscSexualBehaviorCount = DefDatabase.GetNamed("MiscSexualBehaviorCount"); public static readonly RecordDef SexPartnerCount = DefDatabase.GetNamed("SexPartnerCount"); + public static readonly RecordDef OrgasmCount = DefDatabase.GetNamed("OrgasmCount"); public static readonly SkillDef SexSkill = DefDatabase.GetNamed("Sex"); public static readonly ThoughtDef_Recordbased AteCum = DefDatabase.GetNamed("AteCum"); public static readonly PawnRelationDef Bastard = DefDatabase.GetNamed("Bastard"); public static readonly ThingDef GatheredCum = DefDatabase.GetNamed("GatheredCum"); + public static readonly ThingDef FilthCum = ThingDef.Named("FilthCum"); + public static readonly ThingDef FilthGirlcum = ThingDef.Named("FilthGirlCum"); public static readonly HediffDef CumAddiction = DefDatabase.GetNamed("CumAddiction"); public static readonly HediffDef CumTolerance = DefDatabase.GetNamed("CumTolerance"); public static readonly ChemicalDef Cum = DefDatabase.GetNamed("Cum"); public static readonly NeedDef Chemical_Cum = DefDatabase.GetNamed("Chemical_Cum"); public static readonly TraitDef Virgin = DefDatabase.GetNamed("Virgin"); + public static readonly JobDef CleanSelfwithBucket = DefDatabase.GetNamed("CleanSelfwithBucket"); + public static readonly PawnRelationDef relation_birthgiver = DefDatabase.GetNamed("RJW_Sire"); + public static readonly PawnRelationDef relation_spawn = DefDatabase.GetNamed("RJW_Pup"); + public static readonly KeyBindingDef OpenSexStatistics = DefDatabase.GetNamed("OpenSexStatistics"); public static float CumneedLevelOffset { diff --git a/RJWSexperience_Ideology/Assemblies/RJWSexperience.Ideology.dll b/RJWSexperience_Ideology/Assemblies/RJWSexperience.Ideology.dll index 05346b8..34aea9e 100644 Binary files a/RJWSexperience_Ideology/Assemblies/RJWSexperience.Ideology.dll and b/RJWSexperience_Ideology/Assemblies/RJWSexperience.Ideology.dll differ diff --git a/RJWSexperience_Ideology/Defs/DutyDefs/Duties_Rituals_sex.xml b/RJWSexperience_Ideology/Defs/DutyDefs/Duties_Rituals_sex.xml index b831aff..87b4ade 100644 --- a/RJWSexperience_Ideology/Defs/DutyDefs/Duties_Rituals_sex.xml +++ b/RJWSexperience_Ideology/Defs/DutyDefs/Duties_Rituals_sex.xml @@ -2,7 +2,7 @@ - Gangbang + Gangbang_Rape HighPriority Off @@ -25,6 +25,31 @@ + + + Gangbang_Consensual + HighPriority + Off + + +
  • + +
  • + 0.25 + +
  • + +
  • +
    + + +
  • + Jog + 50~250 +
  • + +
    +
    FuckVictim diff --git a/RJWSexperience_Ideology/Defs/JobDefs/Jobs_Ritual_Sex.xml b/RJWSexperience_Ideology/Defs/JobDefs/Jobs_Ritual_Sex.xml index 3098074..3f3151b 100644 --- a/RJWSexperience_Ideology/Defs/JobDefs/Jobs_Ritual_Sex.xml +++ b/RJWSexperience_Ideology/Defs/JobDefs/Jobs_Ritual_Sex.xml @@ -28,4 +28,20 @@ masturbatin'. false
    + + + Gangbang + RJWSexperience.Ideology.JobDriver_Gangbang + lovin'. + false + + + + GettinGangbang + RJWSexperience.Ideology.JobDriver_GangbangReceiver + gettin' gangbanged. + Never + false + +
    \ No newline at end of file diff --git a/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Ritual_sex.xml b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Ritual_sex.xml index f7280cb..002d760 100644 --- a/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Ritual_sex.xml +++ b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Ritual_sex.xml @@ -25,8 +25,30 @@
  • Rapist
  • - + + GangbangCeremony_Consensual + + A ritualistic gangbang where a organizer being fucked. The audience will fuck the organizer. + Ritual + Medium + UI/Issues/Gangbang_Consensual + Precept_Ritual + Gangbang_Consensual + true + false + 1.0 + 100 + false + true + false + true + +
  • Lewd
  • +
    +
    + + AnimalGangbangCeremony A ritualistic gangbang where animals rape a victim. @@ -43,12 +65,36 @@ true false true + +
  • Rapist
  • +
  • Zoophile
  • +
    +
    + + + AnimalGangbangCeremony_Consensual + + A ritualistic gangbang where animals fuck the organizer. + Ritual + Medium + UI/Commands/Breeding_Pawn_on + Precept_Ritual + GangbangByAnimal_Consensual + true + false + 1.0 + 100 + false + true + false + true
  • Zoophile
  • + DrugOrgyCeremony diff --git a/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Sex.xml b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Sex.xml index 9d2a904..cbe18a9 100644 --- a/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Sex.xml +++ b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Sex.xml @@ -58,8 +58,6 @@
  • AnalSex Sex_Promiscuous - Lust - 2.0
  • AnalSex @@ -68,8 +66,6 @@
  • OralSex Sex_Promiscuous - Lust - 2.0
  • OralSex @@ -78,8 +74,6 @@
  • MiscSex Sex_Promiscuous - Lust - 2.0
  • MiscSex @@ -88,8 +82,6 @@
  • PromiscuousSex Sex_Promiscuous - Lust - 3.0
  • PromiscuousSex @@ -111,8 +103,6 @@
  • VaginalSex Sex_Promiscuous - Lust - 2.0
  • VaginalSex @@ -121,8 +111,6 @@
  • OralSex Sex_Promiscuous - Lust - 2.0
  • OralSex @@ -131,8 +119,6 @@
  • MiscSex Sex_Promiscuous - Lust - 2.0
  • MiscSex @@ -141,8 +127,6 @@
  • PromiscuousSex Sex_Promiscuous - Lust - 3.0
  • PromiscuousSex @@ -164,8 +148,6 @@
  • VaginalSex Sex_Promiscuous - Lust - 2.0
  • VaginalSex @@ -174,8 +156,6 @@
  • AnalSex Sex_Promiscuous - Lust - 2.0
  • AnalSex @@ -184,8 +164,6 @@
  • MiscSex Sex_Promiscuous - Lust - 2.0
  • MiscSex @@ -194,8 +172,6 @@
  • PromiscuousSex Sex_Promiscuous - Lust - 3.0
  • PromiscuousSex diff --git a/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Virginity.xml b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Virginity.xml new file mode 100644 index 0000000..a171b25 --- /dev/null +++ b/RJWSexperience_Ideology/Defs/PreceptDefs/Precepts_Virginity.xml @@ -0,0 +1,342 @@ + + + + + Virginity_Female + + UI/Issues/Female + + + + Virginity_Male + + UI/Issues/Male + + + + Virgin_TakenF + + + + + Virgin_TakenM + + + + + Virgin_TookF + + + + + Virgin_TookM + + + + + + + Virgin_UselessF + Virginity_Female + + Female's virginity is useless. + Medium + 50 + 1000 + 10 + + + + Virgin_UselessM + Virginity_Male + + Male's virginity is useless. + Low + 50 + 1000 + 80 + + + + Virgin_PreciousF + Virginity_Female + + Female's virginity is precious. + Medium + 40 + 1000 + 80 + +
  • + Virgin_TakenF + Virgin_Precious_Taken_Forcefully + BeenRaped +
  • +
  • + Virgin_TakenF + Virgin_Precious_Taken + BeenRaped + true +
  • +
  • + Virgin_TookF + TookVirginity +
  • + +
    + + + Virgin_PreciousM + Virginity_Male + + Male's virginity is precious. + Medium + 40 + 1000 + 1 + +
  • + Virgin_TakenM + Virgin_Precious_Taken_Forcefully + BeenRaped +
  • +
  • + Virgin_TakenM + Virgin_Precious_Taken + BeenRaped + true +
  • +
  • + Virgin_TookM + TookVirginity +
  • +
    +
    + + + Virgin_OnlyForSpouseF + Virginity_Female + + Losing virginity before marriage is evil. + Medium + 40 + 1000 + 80 + +
  • MaleSupremacy
  • +
    + +
  • FemaleSupremacy
  • +
    + +
  • MaleSupremacy
  • +
    + +
  • + Virgin_TakenF + Virgin_Precious_Taken_Forcefully + BeenRaped +
  • +
  • + Virgin_TakenF + Virgin_Precious_Taken + BeenRaped + true +
  • +
  • + Virgin_TakenF + Virgin_OnlyForSpouse_Know_Taken + Female, NotSpouse +
  • +
  • + Virgin_TookF + TookVirginity +
  • +
    +
    + + + Virgin_OnlyForSpouseM + Virginity_Male + + Losing virginity before marriage is evil. + Medium + 40 + 1000 + 20 + +
  • FemaleSupremacy
  • +
    + +
  • MaleSupremacy
  • +
    + +
  • FemaleSupremacy
  • +
    + +
  • + Virgin_TakenM + Virgin_Precious_Taken_Forcefully + BeenRaped +
  • +
  • + Virgin_TakenM + Virgin_Precious_Taken + BeenRaped + true +
  • +
  • + Virgin_TakenM + Virgin_OnlyForSpouse_Know_Taken + Male, NotSpouse +
  • +
  • + Virgin_TookM + TookVirginity +
  • +
    +
    + + + Virgin_ShamefulF + Virginity_Female + + Remaining as virgin is shameful thing and being laughed at. + Medium + 30 + 1000 + 1 + +
  • FemaleSupremacy
  • +
    + +
  • + Virgin_TakenF + Virgin_Shameful_Taken + BeenRaped + true +
  • +
    +
    + + + Virgin_ShamefulM + Virginity_Male + + Remaining as virgin is shameful thing and being laughed at. + Medium + 30 + 1000 + 40 + +
  • MaleSupremacy
  • +
    + +
  • + Virgin_TakenM + Virgin_Shameful_Taken + BeenRaped + true +
  • +
    +
    + + + + + Virgin_Precious_Taken_Forcefully + Thought_MemorySocial + 30 + 1 + +
  • + + I lost my virginity forcefully. + -10 + -200 +
  • +
    +
    + + + Virgin_Precious_Taken + RJWSexperience.Thought_Opinionbased + 7 + 1 + +
  • -100
  • +
  • -50
  • +
  • 0
  • +
  • 75
  • +
    + +
  • + + I am no longer virgin. + -5 +
  • +
  • + + I am no longer virgin. + -3 +
  • +
  • + + I am no longer virgin. + -1 +
  • +
  • + + I Gave my virginity to my love. + 5 +
  • +
    +
    + + + Virgin_Shameful_Taken + RJWSexperience.Thought_Opinionbased + 7 + 1 + +
  • -100
  • +
  • 0
  • +
  • 75
  • +
    + +
  • + + Finally! + 5 +
  • +
  • + + Finally! + 10 +
  • +
  • + + Finally! + 20 +
  • +
    +
    + + + + Virgin_OnlyForSpouse_Know_Taken + Thought_MemorySocial + 30 + 100 + 3 + +
  • Nymphomaniac
  • +
    + +
  • + + -30 +
  • +
    +
    + \ No newline at end of file diff --git a/RJWSexperience_Ideology/Defs/PreceptDefs/RitualPatternDefs/RitualPatterns_sex.xml b/RJWSexperience_Ideology/Defs/PreceptDefs/RitualPatternDefs/RitualPatterns_sex.xml index 60e28d5..cd63d8c 100644 --- a/RJWSexperience_Ideology/Defs/PreceptDefs/RitualPatternDefs/RitualPatterns_sex.xml +++ b/RJWSexperience_Ideology/Defs/PreceptDefs/RitualPatternDefs/RitualPatterns_sex.xml @@ -21,6 +21,17 @@ + + Gangbang_Consensual + Gangbang_Consensual + gangbang + A ritualistic gangbang. The organizer will give a speech to excite the crowd, then fucked by the crowd. + UI/Issues/Gangbang_Consensual + false + Gangbang_Consensual + + + GangbangByAnimal GangbangByAnimal @@ -32,6 +43,17 @@ + + GangbangByAnimal_Consensual + GangbangByAnimal_Consensual + gangbang by animal + A ritualistic animal gangbang. The organizer will give a speech to excite the crowd, then animals begin fuck the organizer. + UI/Commands/Breeding_Pawn_on + false + BestialGangbang_Consensual + + + DrugOrgy drug orgy diff --git a/RJWSexperience_Ideology/Defs/Rituals/Ritual_Behaviors_sex.xml b/RJWSexperience_Ideology/Defs/Rituals/Ritual_Behaviors_sex.xml index 12accc6..aff19a9 100644 --- a/RJWSexperience_Ideology/Defs/Rituals/Ritual_Behaviors_sex.xml +++ b/RJWSexperience_Ideology/Defs/Rituals/Ritual_Behaviors_sex.xml @@ -2,7 +2,9 @@ -
  • + +
  • + 7500
  • @@ -84,7 +86,7 @@
  • - Gangbang + Gangbang_Rape True
  • @@ -102,7 +104,7 @@
  • - Gangbang + Gangbang_Rape
  • 0.1 @@ -122,6 +124,85 @@ + + Gangbang_Consensual + RJWSexperience.Ideology.RitualBehaviorWorker_Gangbang_Consensual + +
  • + Spectate + +
  • + +
  • initiator
  • + + + + +
  • + initiator + ArriveToCell +
  • +
    + +
  • + Spectate + +
  • + 0.1 +
  • + + +
  • + initiator + SpeakOnCellFacingSpectators + Speech_Gangbang + +
  • + 5 +
  • +
  • + +
  • +
    + +
  • + Gangbang_Consensual + True + +
  • + 1.0 +
  • + + +
  • + initiator + LayDownAwake + +
  • + +
  • +
    + +
  • + Spectate + +
  • + 0.1 +
  • + + +
  • + initiator + SpeakOnCellFacingSpectators + Speech_Gangbang + +
  • + +
  • +
    + + +
    @@ -228,7 +309,7 @@
  • animal - Gangbang + Gangbang_Rape
  • @@ -263,7 +344,106 @@
  • + + + GangbangByAnimal_Consensual + RJWSexperience.Ideology.RitualBehaviorWorker_Gangbang_Consensual + +
  • + + animal + 30 + false + a breedable animal + false +
  • +
    + +
  • + Spectate + +
  • + +
  • initiator
  • + + + + +
  • + initiator + ArriveToCell +
  • +
    + +
  • + Spectate + +
  • + 0.1 +
  • + + +
  • + initiator + SpeakOnCellFacingSpectators + Speech_Zoophile + +
  • + 5 +
  • +
  • + +
  • +
  • + animal + Spectate +
  • +
    + +
  • + Spectate + True + +
  • + 0.9 +
  • + + +
  • + animal + Gangbang_Consensual + +
  • + +
  • +
  • + initiator + LayDownAwake +
  • +
    + +
  • + Spectate + +
  • + 0.1 +
  • + + +
  • + initiator + SpeakOnCellFacingSpectators + Speech_Zoophile + +
  • + +
  • +
    + +
    +
    + DrugOrgy 7500 diff --git a/RJWSexperience_Ideology/Defs/Rituals/Ritual_Outcomes_sex.xml b/RJWSexperience_Ideology/Defs/Rituals/Ritual_Outcomes_sex.xml index c3f5664..a6c9646 100644 --- a/RJWSexperience_Ideology/Defs/Rituals/Ritual_Outcomes_sex.xml +++ b/RJWSexperience_Ideology/Defs/Rituals/Ritual_Outcomes_sex.xml @@ -32,31 +32,114 @@
  • - 0.2 + 0.15 FeelingBroken 0.3 victim
  • - 0.2 + 0.15 FeelingBroken 0.5 victim
  • - 0.4 + 0.3 FeelingBroken 0.9 victim
  • - 0.2 + 0.4 Sex 0.7
  • +
  • + + 0.4 + Sex + 0.9 +
  • + + +
  • + + 0.05 + TerribleGangbang + The {0} was terrible! The speech was stuttering and incoherent, and the victim was botched - everyone was waiting for it to end. + -2 +
  • +
  • + + 0.10 + BoringGangbang + The {0} was boring. The speech was repetitive and the victim was noticeably flawed. It just didn't feel dignified. + -1 +
  • +
  • + + 0.6 + FunGangbang + The {0} was satisfying. The speech felt meaningful, and the victim was precise and dignified. + There's a 5% chance that a random participant gets an inspiration. + 1 +
  • +
  • + + 0.25 + UnforgettableGangbang + The {0} was spectacular! The speech brought everyone to the edge of a frenzy and the victim was like succubus. + There's a 10% chance that a random participant gets an inspiration. + 2 +
  • +
    + + + + Gangbang_Consensual + Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days. + RitualOutcomeEffectWorker_Consumable + +
  • If the {0} is satisfying, one of the participants might gain an inspiration.
  • +
    + +
  • + initiator + + 0.10 +
  • +
  • + + + +
  • (1, -0.20)
  • +
  • (3, -0.05)
  • +
  • (5, 0.05)
  • +
  • (10, 0.10)
  • + + + +
  • + true + + 0.2 + an altar +
  • +
  • + + 0.4 + Sex + 0.7 +
  • +
  • + + 1.0 + Sex + 0.8 +
  • @@ -92,7 +175,6 @@ - BestialGangbang Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days. @@ -125,21 +207,21 @@
  • - 0.3 + 0.45 FeelingBroken 0.3 victim
  • - 0.3 + 0.45 FeelingBroken 0.5 victim
  • - 0.6 + 0.8 FeelingBroken 0.9 victim @@ -179,6 +261,70 @@ + + BestialGangbang_Consensual + Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days. + RitualOutcomeEffectWorker_Consumable + +
  • If the {0} is satisfying, one of the participants might gain an inspiration.
  • + + +
  • + initiator + + 0.10 +
  • +
  • + + + +
  • (1, 0.20)
  • +
  • (3, 0.40)
  • +
  • (5, 0.65)
  • +
  • (10, 1.20)
  • + + + +
  • + true + + 0.2 + an altar +
  • +
    + +
  • + + 0.05 + TerribleGangbang + The {0} was terrible! The speech was stuttering and incoherent, and the victim was botched - everyone was waiting for it to end. + -2 +
  • +
  • + + 0.10 + BoringGangbang + The {0} was boring. The speech was repetitive and the victim was noticeably flawed. It just didn't feel dignified. + -1 +
  • +
  • + + 0.65 + FunGangbang + The {0} was satisfying. The speech felt meaningful, and the victim was precise and dignified. + There's a 5% chance that a random participant gets an inspiration. + 1 +
  • +
  • + + 0.2 + UnforgettableGangbang + The {0} was spectacular! The speech brought everyone to the edge of a frenzy and the victim was like succubus. + There's a 10% chance that a random participant gets an inspiration. + 2 +
  • +
    +
    DrugOrgy diff --git a/RJWSexperience_Ideology/Textures/UI/Issues/Female.png b/RJWSexperience_Ideology/Textures/UI/Issues/Female.png new file mode 100644 index 0000000..d2bece2 Binary files /dev/null and b/RJWSexperience_Ideology/Textures/UI/Issues/Female.png differ diff --git a/RJWSexperience_Ideology/Textures/UI/Issues/Gangbang_Consensual.png b/RJWSexperience_Ideology/Textures/UI/Issues/Gangbang_Consensual.png new file mode 100644 index 0000000..5250867 Binary files /dev/null and b/RJWSexperience_Ideology/Textures/UI/Issues/Gangbang_Consensual.png differ diff --git a/RJWSexperience_Ideology/Textures/UI/Issues/Gender.png b/RJWSexperience_Ideology/Textures/UI/Issues/Gender.png new file mode 100644 index 0000000..9b73621 Binary files /dev/null and b/RJWSexperience_Ideology/Textures/UI/Issues/Gender.png differ diff --git a/RJWSexperience_Ideology/Textures/UI/Issues/Male.png b/RJWSexperience_Ideology/Textures/UI/Issues/Male.png new file mode 100644 index 0000000..8d37b41 Binary files /dev/null and b/RJWSexperience_Ideology/Textures/UI/Issues/Male.png differ diff --git a/Textures/UI/Icon/FirstBG.png b/Textures/UI/Icon/FirstBG.png new file mode 100644 index 0000000..c8bc007 Binary files /dev/null and b/Textures/UI/Icon/FirstBG.png differ diff --git a/Textures/UI/Icon/Incest.png b/Textures/UI/Icon/Incest.png new file mode 100644 index 0000000..ff01ab0 Binary files /dev/null and b/Textures/UI/Icon/Incest.png differ diff --git a/Textures/UI/Icon/RSLocked.png b/Textures/UI/Icon/RSLocked.png new file mode 100644 index 0000000..0dc2754 Binary files /dev/null and b/Textures/UI/Icon/RSLocked.png differ diff --git a/Textures/UI/Icon/RSUnlocked.png b/Textures/UI/Icon/RSUnlocked.png new file mode 100644 index 0000000..21116b0 Binary files /dev/null and b/Textures/UI/Icon/RSUnlocked.png differ diff --git a/Textures/UI/Icon/UnknownPawn.png b/Textures/UI/Icon/UnknownPawn.png new file mode 100644 index 0000000..90c7225 Binary files /dev/null and b/Textures/UI/Icon/UnknownPawn.png differ diff --git a/changelogs.txt b/changelogs.txt index 119a9c9..6e3286c 100644 --- a/changelogs.txt +++ b/changelogs.txt @@ -1,7 +1,22 @@ Version Beta 1.0.2.0 +This update will mess your pawn's record. Use debug tools. + - requires RimWorld 1.3.3117 or later + - requires RJW 4.8.1 or later + - submissive gender can be designated as comfort - added virgin - - added sex history - - + - added virgin precept + - added hymenoplasty(hymen restoration surgery) + - added sex history(not applied retroactively) + - you can change hotkey in keyboard configuration(default: none) + - can collect cum on body + - cum can spill out from cum buckets if over the stack count + - fixed disabling sex record generation was not worked + - removed lust adjustment from precepts that causing massive lust increment + - changed gangbang condition + - now pawns will go to the nearest cum bucket when cleaning self or masturbating + - added consensual ganbang rituals(requires lewd meme) + - non-consensual animal gangbang requires both rapist and zoophile memes + - adjusted gangbang outcome values Version Beta 1.0.1.11b - fixed erros on masturbations