This commit is contained in:
moreoreganostodump 2021-09-25 00:14:02 +09:00
parent 24a4d9452c
commit 71fef3848f
70 changed files with 4292 additions and 922 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest>
<identifier>RJW Sexperience</identifier>
<version>1.0.1.11b</version>
<version>1.0.2.0</version>
<dependencies>
</dependencies>
<incompatibleWith />

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<JobDef>
<defName>CleanSelfwithBucket</defName>
<driverClass>RJWSexperience.JobDriver_CleanSelfWithBucket</driverClass>
<reportString>collecting cum</reportString>
<casualInterruptible>true</casualInterruptible>
</JobDef>
</Defs>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<KeyBindingDef ParentName="GameKeyBinding">
<defName>OpenSexStatistics</defName>
<label>sexperience: open sex history</label>
</KeyBindingDef>
</Defs>

View File

@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<RecipeDef>
<defName>Surgery_RestoreHymen</defName>
<label>hymenoplasty</label>
<description>Disguises as virgin.</description>
<workerClass>RJWSexperience.Recipe_HymenSurgery</workerClass>
<jobString>restoring hymen</jobString>
<effectWorking>Surgery</effectWorking>
<soundWorking>Recipe_Surgery</soundWorking>
<workSpeedStat>MedicalOperationSpeed</workSpeedStat>
<workSkill>Medicine</workSkill>
<workSkillLearnFactor>0.2</workSkillLearnFactor>
<workAmount>400</workAmount>
<anesthetize>false</anesthetize>
<recipeUsers>
<li>Human</li>
</recipeUsers>
<surgerySuccessChanceFactor>100</surgerySuccessChanceFactor>
<ingredients>
<li>
<filter>
<categories>
<li>Medicine</li>
</categories>
</filter>
<count>1</count>
</li>
</ingredients>
<fixedIngredientFilter>
<categories>
<li>Medicine</li>
</categories>
</fixedIngredientFilter>
</RecipeDef>
</Defs>

View File

@ -4,7 +4,14 @@
<RecordDef>
<defName>NumofEatenCum</defName>
<label>swallowed cum</label>
<description>The number of times that i swalloed cum.</description>
<description>The number of times that i swallowed cum.</description>
<type>Int</type>
</RecordDef>
<RecordDef>
<defName>AmountofEatenCum</defName>
<label>swallowed cum(mL)</label>
<description>The amount of cum that i swallowed.</description>
<type>Int</type>
</RecordDef>

View File

@ -44,7 +44,7 @@
</RecordDef>
<RecordDef>
<defName>HadnjobCount</defName>
<defName>HandjobCount</defName>
<label>handjobs</label>
<description>The number of times of handjob.</description>
<type>Int</type>

View File

@ -1,102 +1,47 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<ThingDef Name ="GatheredCum" ParentName="OrganicProductBase">
<defName>GatheredCum</defName>
<label>cum</label>
<description>Gathered cum.</description>
<thingCategories>
<li>AnimalProductRaw</li>
</thingCategories>
<graphicData>
<texPath>Things/Item/GatheredCum</texPath>
<drawSize>1</drawSize>
<graphicClass>Graphic_StackCount</graphicClass>
</graphicData>
<socialPropernessMatters>true</socialPropernessMatters>
<statBases>
<MarketValue>0.1</MarketValue>
<Mass>0.1</Mass>
<Nutrition>0.01</Nutrition>
<Beauty>-5</Beauty>
<Cleanliness>-1</Cleanliness>
<FoodPoisonChanceFixedHuman>0.00</FoodPoisonChanceFixedHuman>
<DeteriorationRate>60</DeteriorationRate>
<Flammability>0.1</Flammability>
</statBases>
<ingestible>
<foodType>Fluid, AnimalProduct</foodType>
<preferability>DesperateOnlyForHumanlikes</preferability>
<tasteThought>AteCum</tasteThought>
<specialThoughtAsIngredient>AteCum</specialThoughtAsIngredient>
<optimalityOffsetHumanlikes>-10</optimalityOffsetHumanlikes>
<optimalityOffsetFeedingAnimals>-10</optimalityOffsetFeedingAnimals>
<outcomeDoers>
<li Class="IngestionOutcomeDoer_GiveHediff">
<hediffDef>CumTolerance</hediffDef>
<severity>0.032</severity>
<divideByBodySize>true</divideByBodySize>
</li>
<li Class="IngestionOutcomeDoer_OffsetPsyfocus">
<offset>0.05</offset>
</li>
</outcomeDoers>
</ingestible>
<comps>
<li Class="CompProperties_Drug">
<chemical>Cum</chemical>
<addictiveness>0.050</addictiveness>
<minToleranceToAddict>0.8</minToleranceToAddict>
<existingAddictionSeverityOffset>0.1</existingAddictionSeverityOffset>
<needLevelOffset>1</needLevelOffset>
<listOrder>30</listOrder>
</li>
</comps>
</ThingDef>
<ThingDef ParentName="PlantFoodRawBase">
<defName>UsedCondom</defName>
<label>Used Condom</label>
<description>A condom filled with sperm. MMMM So good and tasty!</description>
<ThingDef Name="GatheredCum" ParentName="OrganicProductBase">
<defName>GatheredCum</defName>
<label>cum</label>
<description>Gathered cum.</description>
<thingCategories>
<li>AnimalProductRaw</li>
</thingCategories>
<graphicData>
<texPath>Things/Item/UsedCondom</texPath>
<texPath>Things/Item/GatheredCum</texPath>
<drawSize>1</drawSize>
<graphicClass>Graphic_StackCount</graphicClass>
</graphicData>
<stackLimit>50</stackLimit>
<useHitPoints>true</useHitPoints>
<selectable>true</selectable>
<generateCommonality>0.0</generateCommonality>
<techLevel>Industrial</techLevel>
<socialPropernessMatters>true</socialPropernessMatters>
<statBases>
<Beauty>-10</Beauty>
<MarketValue>1</MarketValue>
<Mass>0.05</Mass>
<Nutrition>0.05</Nutrition>
<MarketValue>0.1</MarketValue>
<Mass>0.1</Mass>
<Nutrition>0.01</Nutrition>
<Beauty>-5</Beauty>
<Cleanliness>-1</Cleanliness>
<FoodPoisonChanceFixedHuman>0.00</FoodPoisonChanceFixedHuman>
<DeteriorationRate>60</DeteriorationRate>
<Flammability>0.1</Flammability>
</statBases>
<ingestible>
<foodType>Fluid, AnimalProduct</foodType>
<preferability>DesperateOnlyForHumanlikes</preferability>
<tasteThought>AteCum</tasteThought>
<specialThoughtAsIngredient>AteCum</specialThoughtAsIngredient>
<outcomeDoers>
<li Class="IngestionOutcomeDoer_GiveHediff">
<hediffDef>CumTolerance</hediffDef>
<severity>0.032</severity>
<divideByBodySize>true</divideByBodySize>
</li>
<li Class="IngestionOutcomeDoer_OffsetPsyfocus">
<offset>0.05</offset>
</li>
</outcomeDoers>
<tasteThought>AteCum</tasteThought>
<specialThoughtAsIngredient>AteCum</specialThoughtAsIngredient>
<optimalityOffsetHumanlikes>-10</optimalityOffsetHumanlikes>
<optimalityOffsetFeedingAnimals>-10</optimalityOffsetFeedingAnimals>
<outcomeDoers>
<li Class="IngestionOutcomeDoer_GiveHediff">
<hediffDef>CumTolerance</hediffDef>
<severity>0.032</severity>
<divideByBodySize>true</divideByBodySize>
</li>
<li Class="IngestionOutcomeDoer_OffsetPsyfocus">
<offset>0.05</offset>
</li>
<li Class="RJWSexperience.CumOutcomeDoers"/>
</outcomeDoers>
</ingestible>
<altitudeLayer>Item</altitudeLayer>
<tickerType>Never</tickerType>
<tradeTags>
<li>Exotic</li>
</tradeTags>
<tradeability>Sellable</tradeability>
<thingCategories>
<li>AnimalProductRaw</li>
</thingCategories>
<comps>
<li Class="CompProperties_Drug">
<chemical>Cum</chemical>
@ -109,6 +54,7 @@
</comps>
</ThingDef>
<ChemicalDef>
<defName>Cum</defName>
<label>cum</label>

View File

@ -7,17 +7,57 @@
<commonalityFemale>0.0</commonalityFemale>
<degreeDatas>
<li>
<label>virgin</label>
<description>[PAWN_nameDef] has no experience.</description>
<labelMale>BUGGED! MALE CANNOT HAS THIS TRAIT</labelMale>
<labelFemale>damaged virgin</labelFemale>
<description>[PAWN_nameDef] never experienced. However, her hymen had damaged for some reason.</description>
<degree>-1</degree>
<marketValueFactorOffset>0.05</marketValueFactorOffset>
<statOffsets>
<SexFrequency>0.1</SexFrequency>
<SexFrequency>0.2</SexFrequency>
</statOffsets>
<skillGains>
<li>
<key>Sex</key>
<value>-4</value>
</li>
</skillGains>
<skillGains>
<li>
<key>Sex</key>
<value>-4</value>
</li>
</skillGains>
</li>
<li>
<label>virgin</label>
<description>[PAWN_nameDef] never experienced.</description>
<degree>0</degree>
<statOffsets>
<SexFrequency>0.2</SexFrequency>
</statOffsets>
<skillGains>
<li>
<key>Sex</key>
<value>-4</value>
</li>
</skillGains>
</li>
<li>
<labelMale>BUGGED! MALE CANNOT HAS THIS TRAIT</labelMale>
<labelFemale>virgin?</labelFemale>
<description>[PAWN_nameDef] looks experienced. But the hymen is still threre.</description>
<marketValueFactorOffset>0.10</marketValueFactorOffset>
<degree>1</degree>
</li>
<li>
<labelMale>BUGGED! MALE CANNOT HAS THIS TRAIT</labelMale>
<labelFemale>virgin</labelFemale>
<description>[PAWN_nameDef] never experienced.</description>
<degree>2</degree>
<statOffsets>
<SexFrequency>0.2</SexFrequency>
</statOffsets>
<skillGains>
<li>
<key>Sex</key>
<value>-4</value>
</li>
</skillGains>
<marketValueFactorOffset>0.20</marketValueFactorOffset>
</li>
</degreeDatas>
</TraitDef>

View File

@ -13,6 +13,48 @@
<RSShouldCanFuck>capable of sex is required</RSShouldCanFuck>
<RSTotalGatheredCum>Total gathered cum: </RSTotalGatheredCum>
<RS_LostVirgin>{1} took {0}'s virginity.</RS_LostVirgin>
<RS_FloatMenu_CleanSelf>Gather cums on body</RS_FloatMenu_CleanSelf>
<RS_Best_Sextype>Best sextype</RS_Best_Sextype>
<RS_Recent_Sextype>Recent sextype</RS_Recent_Sextype>
<RS_Sex_Partners>Sex partners</RS_Sex_Partners>
<RS_Cum_Swallowed>Cum swallowed</RS_Cum_Swallowed>
<RS_Selected_Partner>Selected Partner's Info</RS_Selected_Partner>
<RS_Sex_Info>{0}: {1} times</RS_Sex_Info>
<RS_SAT_AVG>Avg: {0}</RS_SAT_AVG>
<RS_Sex_Count>Sex count: </RS_Sex_Count>
<RS_Orgasms>Orgasms: </RS_Orgasms>
<RS_Recent_Sex_Partner>Recent Sex Partner</RS_Recent_Sex_Partner>
<RS_Recent_Sex_Partner_ToolTip>A recent sex partner.</RS_Recent_Sex_Partner_ToolTip>
<RS_First_Sex_Partner>First Sex Partner</RS_First_Sex_Partner>
<RS_First_Sex_Partner_ToolTip>The first sex partner.</RS_First_Sex_Partner_ToolTip>
<RS_Most_Sex_Partner>Most Sex Partner</RS_Most_Sex_Partner>
<RS_Most_Sex_Partner_ToolTip>The most sex partner.</RS_Most_Sex_Partner_ToolTip>
<RS_Best_Sex_Partner>Best Sex Partner</RS_Best_Sex_Partner>
<RS_Best_Sex_Partner_ToolTip>The partner who had most satisfying sex.</RS_Best_Sex_Partner_ToolTip>
<RS_VirginsTaken>Taken virgins</RS_VirginsTaken>
<RS_VirginsTaken_ToolTip>The number of partners who i taken first.</RS_VirginsTaken_ToolTip>
<RS_TotalSexHad>Total sex had</RS_TotalSexHad>
<RS_TotalSexHad_ToolTip>Total number of sex.</RS_TotalSexHad_ToolTip>
<RS_Raped>Raped: </RS_Raped>
<RS_RapedMe>Raped me: </RS_RapedMe>
<RS_Sex_History>Sex History</RS_Sex_History>
<RS_Statistics>Sex Statistics</RS_Statistics>
<RS_PartnerList>Partner List</RS_PartnerList>
<RS_Sexuality>Sexuality</RS_Sexuality>
<RS_BeenRaped>Had been raped</RS_BeenRaped>
<RS_RapedSomeone>Raped someone</RS_RapedSomeone>
<RS_PreferRace>Prefer Race</RS_PreferRace>
<RS_Bestiality>Bestiality</RS_Bestiality>
<RS_Interspecies>Interspecies</RS_Interspecies>
<RS_Normal>Normal</RS_Normal>
<RS_Necrophile>Necrophile</RS_Necrophile>
<RS_GatherCum>Gather cum</RS_GatherCum>
<RS_SexSkill>Sex skill</RS_SexSkill>
<RS_CumAddiction>Cum addiction</RS_CumAddiction>
<RS_CumAddiction_Tooltip>Addicted to cum.</RS_CumAddiction_Tooltip>
<RS_CumAddictiveness>Cum addictiveness</RS_CumAddictiveness>
<RS_CumAddictiveness_Tooltip>More likely to get addicted to cum.</RS_CumAddictiveness_Tooltip>
<RS_NumofTimes>times</RS_NumofTimes>
<RSOption_1_Label>Enable record randomizer</RSOption_1_Label>
<RSOption_1_Desc>Randomize pawn's sex records.</RSOption_1_Desc>
@ -37,4 +79,40 @@
<RSOption_11_Label></RSOption_11_Label>
<RSOption_11_Desc> </RSOption_11_Desc>
<Vaginal>Vaginal</Vaginal>
<Anal>Anal</Anal>
<Oral>Oral</Oral>
<Masturbation>Masturbation</Masturbation>
<DoublePenetration>Double penetration</DoublePenetration>
<Boobjob>Boobjob</Boobjob>
<Handjob>Handjob</Handjob>
<Footjob>Footjob</Footjob>
<Fingering>Fingering</Fingering>
<Scissoring>Scissoring</Scissoring>
<MutualMasturbation>Mutual masturbation</MutualMasturbation>
<Fisting>Fisting</Fisting>
<MechImplant>Mech implant</MechImplant>
<Rimming>Rimming</Rimming>
<Fellatio>Fellatio</Fellatio>
<Cunnilingus>Cunnilingus</Cunnilingus>
<Sixtynine>Sixtynine</Sixtynine>
<None>None</None>
<Asexual>Asexual</Asexual>
<Pansexual>Pansexual</Pansexual>
<Heterosexual>Hetero</Heterosexual>
<MostlyHeterosexual>Mostly hetero</MostlyHeterosexual>
<LeaningHeterosexual>Bisexual, leaning hetero</LeaningHeterosexual>
<Bisexual>Bisexual</Bisexual>
<LeaningHomosexual>Bisexual, leaning gay</LeaningHomosexual>
<MostlyHomosexual>Mostly gay</MostlyHomosexual>
<Homosexual>Gay</Homosexual>
<Lust>lust</Lust>
<Unknown>unknown</Unknown>
<Virgin>virgin</Virgin>
<Incest>incest</Incest>
</LanguageData>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LanguageData>
<Bastard.label>사생아</Bastard.label>
<Bastard.labelFemale>사생아</Bastard.labelFemale>
</LanguageData>

View File

@ -11,6 +11,8 @@
<RSNotHuman>사람이 아님</RSNotHuman>
<RSNotAnimal>동물이 아님</RSNotAnimal>
<RSShouldCanFuck>성관계가 가능해야 합니다.</RSShouldCanFuck>
<RSTotalGatheredCum>수집한 정액 양: </RSTotalGatheredCum>
<RS_LostVirgin>{1}이(가) {0}의 아다를 뗐습니다.</RS_LostVirgin>
<RSOption_1_Label>기록 생성기 활성화</RSOption_1_Label>
<RSOption_1_Desc>폰의 섹스기록을 무작위로 생성합니다.</RSOption_1_Desc>
@ -28,4 +30,8 @@
<RSOption_7_Desc>활성화할 경우 노예는 강간당한 경험을 가집니다.</RSOption_7_Desc>
<RSOption_8_Label>음란함 한계</RSOption_8_Label>
<RSOption_8_Desc>음란함의 한계치를 설정합니다.&#10;음란함의 절대값이 이 값에 가까워지거나 클수록, 음란함이 적게 변합니다.</RSOption_8_Desc>
<RSOption_9_Label>섹스가능 최소나이</RSOption_9_Label>
<RSOption_9_Desc>섹스 가능한 최소나이를 설정합니다.&#10;이 값은 RJW의 최소 나이 설정과 관계가 없고 기록을 생성하는데만 사용됩니다.</RSOption_9_Desc>
<RSOption_10_Label>동정 비율</RSOption_10_Label>
<RSOption_10_Desc>나이 상관없이 동정일 확률을 설정합니다.</RSOption_10_Desc>
</LanguageData>

75
Patches/RJW_ThingDefs.xml Normal file
View File

@ -0,0 +1,75 @@
<?xml version="1.0" encoding="UTF-8"?>
<Patch>
<Operation Class="PatchOperationConditional">
<xpath>Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers</xpath>
<nomatch Class="PatchOperationAdd">
<xpath>Defs/ThingDef[defName="UsedCondom"]/ingestible</xpath>
<value>
<outcomeDoers>
<li Class="IngestionOutcomeDoer_GiveHediff">
<hediffDef>CumTolerance</hediffDef>
<severity>0.032</severity>
<divideByBodySize>true</divideByBodySize>
</li>
<li Class="IngestionOutcomeDoer_OffsetPsyfocus">
<offset>0.05</offset>
</li>
<li Class="RJWSexperience.CumOutcomeDoers">
<unitAmount>5.2</unitAmount>
</li>
</outcomeDoers>
</value>
</nomatch>
<match Class="PatchOperationAdd">
<xpath>Defs/ThingDef[defName="UsedCondom"]/ingestible/outcomeDoers</xpath>
<value>
<li Class="IngestionOutcomeDoer_GiveHediff">
<hediffDef>CumTolerance</hediffDef>
<severity>0.032</severity>
<divideByBodySize>true</divideByBodySize>
</li>
<li Class="IngestionOutcomeDoer_OffsetPsyfocus">
<offset>0.05</offset>
</li>
<li Class="RJWSexperience.CumOutcomeDoers">
<unitAmount>5.2</unitAmount>
</li>
</value>
</match>
</Operation>
<Operation Class="PatchOperationConditional">
<xpath>Defs/ThingDef[defName="UsedCondom"]/comps</xpath>
<nomatch Class="PatchOperationAdd">
<xpath>Defs/ThingDef[defName="UsedCondom"]</xpath>
<value>
<comps>
<li Class="CompProperties_Drug">
<chemical>Cum</chemical>
<addictiveness>0.050</addictiveness>
<minToleranceToAddict>0.8</minToleranceToAddict>
<existingAddictionSeverityOffset>0.1</existingAddictionSeverityOffset>
<needLevelOffset>1</needLevelOffset>
<listOrder>30</listOrder>
</li>
</comps>
</value>
</nomatch>
<match Class="PatchOperationAdd">
<xpath>Defs/ThingDef[defName="UsedCondom"]/comps</xpath>
<value>
<li Class="CompProperties_Drug">
<chemical>Cum</chemical>
<addictiveness>0.050</addictiveness>
<minToleranceToAddict>0.8</minToleranceToAddict>
<existingAddictionSeverityOffset>0.1</existingAddictionSeverityOffset>
<needLevelOffset>1</needLevelOffset>
<listOrder>30</listOrder>
</li>
</value>
</match>
</Operation>
</Patch>

View File

@ -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);
// }
//}
}

View File

@ -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<MemeDef> requiredAllMemes = new List<MemeDef>();
}
}

View File

@ -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
{

View File

@ -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<string> report = new List<string>();
foreach (MemeDef meme in def.requiredAllMemes) report.Add(meme.LabelCap);
__result = new AcceptanceReport("RequiresMeme".Translate() + ": " + report.ToCommaList());
return;
}
}
}
}
}
}
}

View File

@ -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<Toil> 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<Toil> 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<JobCondition>(() =>
{
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;
}
}
}

View File

@ -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);

View File

@ -14,11 +14,11 @@ namespace RJWSexperience.Ideology
{
public LordJob_Ritual_Gangbang() { }
public LordJob_Ritual_Gangbang(TargetInfo selectedTarget, Precept_Ritual ritual, RitualObligation obligation, List<RitualStage> 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<RitualStage> 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);

View File

@ -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();
}
}
}

View File

@ -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<PawnRelationDef> 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;
}
}
}

View File

@ -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<PawnRelationDef> 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)
{

View File

@ -95,9 +95,12 @@
<ItemGroup>
<Compile Include="Ideology\GoodwillSituationWorker_MemeCompatibility.cs" />
<Compile Include="Harmony.cs" />
<Compile Include="Ideology\PreceptDef_RequirementExtended.cs" />
<Compile Include="Ideology\Rituals\JobGiver_GangbangConsensual.cs" />
<Compile Include="Ideology\Rituals\LordJob_Rituals.cs" />
<Compile Include="Ideology\RJW_Patch_Ideo.cs" />
<Compile Include="Ideology\PreceptComp_SelftTookThoughtExtended.cs" />
<Compile Include="Ideology\Sexperience_Patch.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Ideology\Rimworld_Patch.cs" />
<Compile Include="Ideology\Rituals\JobGiver_DrugOrgy.cs" />

View File

@ -11,6 +11,8 @@ namespace RJWSexperience.Ideology
public static class VariousDefOf
{
public static readonly JobDef RapeVictim = DefDatabase<JobDef>.GetNamed("RapeVictim");
public static readonly JobDef Gangbang = DefDatabase<JobDef>.GetNamed("Gangbang");
public static readonly JobDef GettinGangbang = DefDatabase<JobDef>.GetNamed("GettinGangbang");
public static readonly JobDef DrugSex = DefDatabase<JobDef>.GetNamed("DrugSex");
public static readonly JobDef GettinDrugSex = DefDatabase<JobDef>.GetNamed("GettinDrugSex");
public static readonly JobDef DrugMasturbate = DefDatabase<JobDef>.GetNamed("DrugMasturbate");
@ -34,6 +36,10 @@ namespace RJWSexperience.Ideology
[MayRequireIdeology] public static readonly HistoryEventDef PromiscuousSex = DefDatabase<HistoryEventDef>.GetNamed("PromiscuousSex");
[MayRequireIdeology] public static readonly HistoryEventDef Incestuos_Marriage = DefDatabase<HistoryEventDef>.GetNamed("Incestuos_Marriage");
[MayRequireIdeology] public static readonly HistoryEventDef SexWithCorpse = DefDatabase<HistoryEventDef>.GetNamed("SexWithCorpse");
[MayRequireIdeology] public static readonly HistoryEventDef Virgin_TakenF = DefDatabase<HistoryEventDef>.GetNamed("Virgin_TakenF");
[MayRequireIdeology] public static readonly HistoryEventDef Virgin_TakenM = DefDatabase<HistoryEventDef>.GetNamed("Virgin_TakenM");
[MayRequireIdeology] public static readonly HistoryEventDef Virgin_TookF = DefDatabase<HistoryEventDef>.GetNamed("Virgin_TookF");
[MayRequireIdeology] public static readonly HistoryEventDef Virgin_TookM = DefDatabase<HistoryEventDef>.GetNamed("Virgin_TookM");
[MayRequireIdeology] public static readonly PreceptDef Bestiality_Abhorrent = DefDatabase<PreceptDef>.GetNamed("Bestiality_Abhorrent");
[MayRequireIdeology] public static readonly PreceptDef Bestiality_Horrible = DefDatabase<PreceptDef>.GetNamed("Bestiality_Horrible");
[MayRequireIdeology] public static readonly PreceptDef Bestiality_Disapproved = DefDatabase<PreceptDef>.GetNamed("Bestiality_Disapproved");

View File

@ -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;
}

View File

@ -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();
}
}

View File

@ -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)
{

View File

@ -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);
}
}
}

View File

@ -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<Toil> MakeNewToils()
{
this.FailOn(delegate
{
List<Hediff> 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);
}
}
}
}

View File

@ -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()
};
}
}

View File

@ -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<ThingDef> PawnDefs = DefDatabase<ThingDef>.AllDefs.Where(x => x.race != null).ToList();
InjectComp(PawnDefs);
}
private static void InjectComp(List<ThingDef> PawnDefs)
{
CompProperties comp = new CompProperties(typeof(SexPartnerHistory));
if (!PawnDefs.NullOrEmpty()) foreach(ThingDef def in PawnDefs)
{
def.comps.Add(comp);
}
}
}
}

View File

@ -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<Gizmo> __result, Pawn __instance)
{
List<Gizmo> gizmoList = __result.ToList();
AddHistoryGizmo(__instance, ref gizmoList);
__result = gizmoList;
}
private static void AddHistoryGizmo(Pawn pawn, ref List<Gizmo> 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;
}
}
}

View File

@ -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<Building_CumBucket>();
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<Building_CumBucket>();
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());
}
}
}
}
}

View File

@ -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<FloatMenuOption> 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;
}
}
}

View File

@ -63,6 +63,12 @@
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.IMGUIModule.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="UnityEngine.TextCoreModule">
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextCoreModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.TextRenderingModule">
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.TextRenderingModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI">
<HintPath>..\..\..\..\RimWorldWin64_Data\Managed\UnityEngine.UI.dll</HintPath>
<Private>False</Private>
@ -77,20 +83,31 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Buildings.cs" />
<Compile Include="Building_Cumbucket.cs" />
<Compile Include="Configurations.cs" />
<Compile Include="DebugAction.cs" />
<Compile Include="Harmony.cs" />
<Compile Include="SexHistory.cs" />
<Compile Include="IngestionOutcomeDoers.cs" />
<Compile Include="JobDrivers.cs" />
<Compile Include="Patches\DefInjection.cs" />
<Compile Include="Patches\GetGizmos.cs" />
<Compile Include="Recipe_HymenSurgery.cs" />
<Compile Include="RJWUtility.cs" />
<Compile Include="SexHistory\HistoryUtility.cs" />
<Compile Include="SexHistory\SexHistory.cs" />
<Compile Include="PawnRelationWorkers.cs" />
<Compile Include="Keyed.cs" />
<Compile Include="Rimworld_Patch.cs" />
<Compile Include="RJW_Patch.cs" />
<Compile Include="Patches\Rimworld_Patch.cs" />
<Compile Include="Patches\RJW_Patch.cs" />
<Compile Include="StatParts.cs" />
<Compile Include="Thought_Opinionbased.cs" />
<Compile Include="Thought_Recordbased.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="UI\RJWUIUtility.cs" />
<Compile Include="UI\SexStatus.cs" />
<Compile Include="Utility.cs" />
<Compile Include="VariousDefOf.cs" />
</ItemGroup>
<ItemGroup />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
</Project>

View File

@ -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));
}
/// <summary>
/// If the pawn is virgin, return true.
/// </summary>
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;
}
/// <summary>
/// If pawn is virgin, lose his/her virginity.
/// </summary>
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;
}
/// <summary>
/// For ideo patch
/// </summary>
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<SexPartnerHistory>();
pawnshistory?.RecordHistory(partner, props);
}
}
public static void UpdateSatisfactionHIstory(Pawn pawn, Pawn partner, SexProps props, float satisfaction)
{
if (partner != null)
{
SexPartnerHistory pawnshistory = pawn.TryGetComp<SexPartnerHistory>();
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<Building> buckets = pawn.Map.listerBuildings.allBuildingsColonist.FindAll(x => x is Building_CumBucket);
Dictionary<Building, float> targets = new Dictionary<Building, float>();
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);
}
}
}
}
}

View File

@ -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));
}
/// <summary>
/// If the pawn is virgin, return true.
/// </summary>
public static bool IsVirgin(this Pawn pawn)
{
if (pawn.records.GetValue(xxx.CountOfSex) == 0) return true;
return false;
}
/// <summary>
/// If pawn is virgin, lose his/her virginity.
/// </summary>
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<SexPartnerHistory>();
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<Building_CumBucket>();
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);
}
}
}

View File

@ -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<BodyPartRecord> GetPartsToApplyOn(Pawn pawn, RecipeDef recipe)
{
if (pawn.gender != Gender.Female)
{
yield break;
}
BodyPartRecord part = Genital_Helper.get_genitalsBPR(pawn);
if (part != null)
{
List<Hediff> 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<Thing> 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);
}
}
}

View File

@ -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);
}
}
}
}

View File

@ -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<SexHistory> histories = new List<SexHistory>();
protected Dictionary<string,SexHistory> histories = new Dictionary<string,SexHistory>();
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<string,SexHistory> 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;
}
}
}
}

View File

@ -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<Texture2D>.Get("UI/buttons/OpenStatsReport");
public static readonly Texture2D UnknownPawn = ContentFinder<Texture2D>.Get("UI/Icon/UnknownPawn");
public static readonly Texture2D FirstOverlay = ContentFinder<Texture2D>.Get("UI/Icon/FirstBG");
public static readonly Texture2D Heart = ContentFinder<Texture2D>.Get("Things/Mote/Heart");
public static readonly Texture2D Incest = ContentFinder<Texture2D>.Get("UI/Icon/Incest");
public static readonly Texture2D Locked = ContentFinder<Texture2D>.Get("UI/Icon/RSLocked");
public static readonly Texture2D Unlocked = ContentFinder<Texture2D>.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<SexPartnerHistory>();
}
}
}

View File

@ -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<SexHistory> histories = new List<SexHistory>();
protected Dictionary<string, SexHistory> histories = new Dictionary<string, SexHistory>();
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<SexHistory> partnerlistcache;
private List<int> sextypecountsave;
private List<float> 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<SexHistory> PartnerList
{
get
{
Update();
return partnerlistcache;
}
}
public int PartnerCount
{
get
{
if (histories == null) histories = new Dictionary<string, SexHistory>();
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<string, SexHistory>();
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<ThingDef, int> racetotalsat = new Dictionary<ThingDef, int>();
List<Pawn> allpartners = new List<Pawn>();
foreach (KeyValuePair<string,SexHistory> 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<ThingDef, int> 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<SexHistory>();
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;
}
}
}

View File

@ -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
{
/// <summary>
/// ThoughtDef using opinion
/// </summary>
public class ThoughtDef_Opinionbased : ThoughtDef
{
public List<float> minimumValueforStage = new List<float>();
}
/// <summary>
/// Thought class using record.
/// </summary>
public class Thought_Opinionbased : Thought_Memory
{
protected ThoughtDef_Opinionbased Def => (ThoughtDef_Opinionbased)def;
protected List<float> 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;
}
}
}
}

View File

@ -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;
}
}

View File

@ -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<Quirk> 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<PawnRelationDef> 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);
}
}
}

View File

@ -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<CompRJW>();
}
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<Pawn> 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<Pawn> 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<CompRJW>();
if (!pawn.DestroyedOrNull() && Find.CurrentMap == pawn.Map) Find.Selector.Select(pawn);
}
/// <summary>
/// Main contents
/// </summary>
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);
}
/// <summary>
/// Right section
/// </summary>
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);
}
}
/// <summary>
/// Center section
/// </summary>
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();
}
/// <summary>
/// Left section
/// </summary>
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<SexHistory> 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<SexHistory> 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);
}
}
}
}

View File

@ -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<xxx.rjwSextype, RecordDef> sextypeRecords = new Dictionary<xxx.rjwSextype, RecordDef> {
// { 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<PawnRelationDef> 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<T>(this Pawn pawn) where T : Building
public static T GetAdjacentBuilding<T>(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<IntVec3> 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);
}
}
}
}

View File

@ -11,6 +11,7 @@ namespace RJWSexperience
public static class VariousDefOf
{
public static readonly RecordDef NumofEatenCum = DefDatabase<RecordDef>.GetNamed("NumofEatenCum");
public static readonly RecordDef AmountofEatenCum = DefDatabase<RecordDef>.GetNamed("AmountofEatenCum");
public static readonly RecordDef Lust = DefDatabase<RecordDef>.GetNamed("Lust");
public static readonly RecordDef VaginalSexCount = DefDatabase<RecordDef>.GetNamed("VaginalSexCount");
public static readonly RecordDef AnalSexCount = DefDatabase<RecordDef>.GetNamed("AnalSexCount");
@ -18,20 +19,27 @@ namespace RJWSexperience
public static readonly RecordDef BlowjobCount = DefDatabase<RecordDef>.GetNamed("BlowjobCount");
public static readonly RecordDef CunnilingusCount = DefDatabase<RecordDef>.GetNamed("CunnilingusCount");
public static readonly RecordDef GenitalCaressCount = DefDatabase<RecordDef>.GetNamed("GenitalCaressCount");
public static readonly RecordDef HadnjobCount = DefDatabase<RecordDef>.GetNamed("HadnjobCount");
public static readonly RecordDef HandjobCount = DefDatabase<RecordDef>.GetNamed("HandjobCount");
public static readonly RecordDef FingeringCount = DefDatabase<RecordDef>.GetNamed("FingeringCount");
public static readonly RecordDef FootjobCount = DefDatabase<RecordDef>.GetNamed("FootjobCount");
public static readonly RecordDef MiscSexualBehaviorCount = DefDatabase<RecordDef>.GetNamed("MiscSexualBehaviorCount");
public static readonly RecordDef SexPartnerCount = DefDatabase<RecordDef>.GetNamed("SexPartnerCount");
public static readonly RecordDef OrgasmCount = DefDatabase<RecordDef>.GetNamed("OrgasmCount");
public static readonly SkillDef SexSkill = DefDatabase<SkillDef>.GetNamed("Sex");
public static readonly ThoughtDef_Recordbased AteCum = DefDatabase<ThoughtDef_Recordbased>.GetNamed("AteCum");
public static readonly PawnRelationDef Bastard = DefDatabase<PawnRelationDef>.GetNamed("Bastard");
public static readonly ThingDef GatheredCum = DefDatabase<ThingDef>.GetNamed("GatheredCum");
public static readonly ThingDef FilthCum = ThingDef.Named("FilthCum");
public static readonly ThingDef FilthGirlcum = ThingDef.Named("FilthGirlCum");
public static readonly HediffDef CumAddiction = DefDatabase<HediffDef>.GetNamed("CumAddiction");
public static readonly HediffDef CumTolerance = DefDatabase<HediffDef>.GetNamed("CumTolerance");
public static readonly ChemicalDef Cum = DefDatabase<ChemicalDef>.GetNamed("Cum");
public static readonly NeedDef Chemical_Cum = DefDatabase<NeedDef>.GetNamed("Chemical_Cum");
public static readonly TraitDef Virgin = DefDatabase<TraitDef>.GetNamed("Virgin");
public static readonly JobDef CleanSelfwithBucket = DefDatabase<JobDef>.GetNamed("CleanSelfwithBucket");
public static readonly PawnRelationDef relation_birthgiver = DefDatabase<PawnRelationDef>.GetNamed("RJW_Sire");
public static readonly PawnRelationDef relation_spawn = DefDatabase<PawnRelationDef>.GetNamed("RJW_Pup");
public static readonly KeyBindingDef OpenSexStatistics = DefDatabase<KeyBindingDef>.GetNamed("OpenSexStatistics");
public static float CumneedLevelOffset
{

View File

@ -2,7 +2,7 @@
<Defs>
<DutyDef>
<defName>Gangbang</defName>
<defName>Gangbang_Rape</defName>
<hook>HighPriority</hook>
<socialModeMax>Off</socialModeMax>
<thinkNode Class="ThinkNode_Priority">
@ -25,6 +25,31 @@
</subNodes>
</thinkNode>
</DutyDef>
<DutyDef>
<defName>Gangbang_Consensual</defName>
<hook>HighPriority</hook>
<socialModeMax>Off</socialModeMax>
<thinkNode Class="ThinkNode_Priority">
<subNodes>
<li Class="ThinkNode_ConditionalInGatheringArea">
<subNodes>
<li Class="ThinkNode_ConditionalRandom">
<chance>0.25</chance>
<subNodes>
<li Class="RJWSexperience.Ideology.JobGiver_GangbangConsensual"/>
</subNodes>
</li>
</subNodes>
</li>
<li Class="JobGiver_WanderInGatheringArea">
<locomotionUrgency>Jog</locomotionUrgency>
<ticksBetweenWandersRange>50~250</ticksBetweenWandersRange>
</li>
</subNodes>
</thinkNode>
</DutyDef>
<DutyDef>
<defName>FuckVictim</defName>

View File

@ -28,4 +28,20 @@
<reportString>masturbatin'.</reportString>
<casualInterruptible>false</casualInterruptible>
</JobDef>
<JobDef>
<defName>Gangbang</defName>
<driverClass>RJWSexperience.Ideology.JobDriver_Gangbang</driverClass>
<reportString>lovin'.</reportString>
<casualInterruptible>false</casualInterruptible>
</JobDef>
<JobDef>
<defName>GettinGangbang</defName>
<driverClass>RJWSexperience.Ideology.JobDriver_GangbangReceiver</driverClass>
<reportString>gettin' gangbanged.</reportString>
<checkOverrideOnDamage>Never</checkOverrideOnDamage>
<casualInterruptible>false</casualInterruptible>
</JobDef>
</Defs>

View File

@ -25,8 +25,30 @@
<li>Rapist</li>
</requiredMemes>
</PreceptDef>
<PreceptDef>
<defName>GangbangCeremony_Consensual</defName>
<label>gangbang</label>
<description>A ritualistic gangbang where a organizer being fucked. The audience will fuck the organizer.</description>
<issue>Ritual</issue>
<impact>Medium</impact>
<iconPath>UI/Issues/Gangbang_Consensual</iconPath>
<preceptClass>Precept_Ritual</preceptClass>
<ritualPatternBase>Gangbang_Consensual</ritualPatternBase>
<allowDuplicates>true</allowDuplicates>
<countsTowardsPreceptLimit>false</countsTowardsPreceptLimit>
<selectionWeight>1.0</selectionWeight>
<displayOrderInImpact>100</displayOrderInImpact>
<ignoreLimitsInEditMode>false</ignoreLimitsInEditMode>
<receivesExpectationsQualityOffset>true</receivesExpectationsQualityOffset>
<canGenerateAsSpecialPrecept>false</canGenerateAsSpecialPrecept>
<allowStackingRitualObligationAlerts>true</allowStackingRitualObligationAlerts>
<requiredMemes>
<li>Lewd</li>
</requiredMemes>
</PreceptDef>
<RJWSexperience.Ideology.PreceptDef_RequirementExtended>
<defName>AnimalGangbangCeremony</defName>
<label>animal gangbang</label>
<description>A ritualistic gangbang where animals rape a victim.</description>
@ -43,12 +65,36 @@
<receivesExpectationsQualityOffset>true</receivesExpectationsQualityOffset>
<canGenerateAsSpecialPrecept>false</canGenerateAsSpecialPrecept>
<allowStackingRitualObligationAlerts>true</allowStackingRitualObligationAlerts>
<requiredAllMemes>
<li>Rapist</li>
<li>Zoophile</li>
</requiredAllMemes>
</RJWSexperience.Ideology.PreceptDef_RequirementExtended>
<PreceptDef>
<defName>AnimalGangbangCeremony_Consensual</defName>
<label>animal gangbang</label>
<description>A ritualistic gangbang where animals fuck the organizer.</description>
<issue>Ritual</issue>
<impact>Medium</impact>
<iconPath>UI/Commands/Breeding_Pawn_on</iconPath>
<preceptClass>Precept_Ritual</preceptClass>
<ritualPatternBase>GangbangByAnimal_Consensual</ritualPatternBase>
<allowDuplicates>true</allowDuplicates>
<countsTowardsPreceptLimit>false</countsTowardsPreceptLimit>
<selectionWeight>1.0</selectionWeight>
<displayOrderInImpact>100</displayOrderInImpact>
<ignoreLimitsInEditMode>false</ignoreLimitsInEditMode>
<receivesExpectationsQualityOffset>true</receivesExpectationsQualityOffset>
<canGenerateAsSpecialPrecept>false</canGenerateAsSpecialPrecept>
<allowStackingRitualObligationAlerts>true</allowStackingRitualObligationAlerts>
<requiredMemes>
<li>Zoophile</li>
</requiredMemes>
</PreceptDef>
<PreceptDef>
<defName>DrugOrgyCeremony</defName>
<label>drug orgy</label>

View File

@ -58,8 +58,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>AnalSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>AnalSex</eventDef>
@ -68,8 +66,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>OralSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>OralSex</eventDef>
@ -78,8 +74,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>MiscSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>MiscSex</eventDef>
@ -88,8 +82,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>PromiscuousSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>3.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>PromiscuousSex</eventDef>
@ -111,8 +103,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>VaginalSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>VaginalSex</eventDef>
@ -121,8 +111,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>OralSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>OralSex</eventDef>
@ -131,8 +119,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>MiscSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>MiscSex</eventDef>
@ -141,8 +127,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>PromiscuousSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>3.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>PromiscuousSex</eventDef>
@ -164,8 +148,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>VaginalSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>VaginalSex</eventDef>
@ -174,8 +156,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>AnalSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>AnalSex</eventDef>
@ -184,8 +164,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>MiscSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>2.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>MiscSex</eventDef>
@ -194,8 +172,6 @@
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>PromiscuousSex</eventDef>
<thought>Sex_Promiscuous</thought>
<recordDef>Lust</recordDef>
<recordoffset>3.0</recordoffset>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>PromiscuousSex</eventDef>

View File

@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8" ?>
<Defs>
<!-- Issues -->
<IssueDef>
<defName>Virginity_Female</defName>
<label>virginity of female</label>
<iconPath>UI/Issues/Female</iconPath>
</IssueDef>
<IssueDef>
<defName>Virginity_Male</defName>
<label>virginity of male</label>
<iconPath>UI/Issues/Male</iconPath>
</IssueDef>
<HistoryEventDef>
<defName>Virgin_TakenF</defName>
<label>virgin taken</label>
</HistoryEventDef>
<HistoryEventDef>
<defName>Virgin_TakenM</defName>
<label>virgin taken</label>
</HistoryEventDef>
<HistoryEventDef>
<defName>Virgin_TookF</defName>
<label>virgin took</label>
</HistoryEventDef>
<HistoryEventDef>
<defName>Virgin_TookM</defName>
<label>virgin took</label>
</HistoryEventDef>
<!-- Precepts -->
<PreceptDef>
<defName>Virgin_UselessF</defName>
<issue>Virginity_Female</issue>
<label>useless</label>
<description>Female's virginity is useless.</description>
<impact>Medium</impact>
<displayOrderInIssue>50</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>10</defaultSelectionWeight>
</PreceptDef>
<PreceptDef>
<defName>Virgin_UselessM</defName>
<issue>Virginity_Male</issue>
<label>useless</label>
<description>Male's virginity is useless.</description>
<impact>Low</impact>
<displayOrderInIssue>50</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>80</defaultSelectionWeight>
</PreceptDef>
<PreceptDef>
<defName>Virgin_PreciousF</defName>
<issue>Virginity_Female</issue>
<label>precious</label>
<description>Female's virginity is precious.</description>
<impact>Medium</impact>
<displayOrderInIssue>40</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>80</defaultSelectionWeight>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_Precious_Taken_Forcefully</thought>
<tag>BeenRaped</tag>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_Precious_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TookF</eventDef>
<thought>TookVirginity</thought>
</li>
</comps>
</PreceptDef>
<PreceptDef>
<defName>Virgin_PreciousM</defName>
<issue>Virginity_Male</issue>
<label>precious</label>
<description>Male's virginity is precious.</description>
<impact>Medium</impact>
<displayOrderInIssue>40</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>1</defaultSelectionWeight>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_Precious_Taken_Forcefully</thought>
<tag>BeenRaped</tag>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_Precious_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TookM</eventDef>
<thought>TookVirginity</thought>
</li>
</comps>
</PreceptDef>
<PreceptDef>
<defName>Virgin_OnlyForSpouseF</defName>
<issue>Virginity_Female</issue>
<label>precious(strict)</label>
<description>Losing virginity before marriage is evil.</description>
<impact>Medium</impact>
<displayOrderInIssue>40</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>80</defaultSelectionWeight>
<requiredMemes>
<li>MaleSupremacy</li>
</requiredMemes>
<conflictingMemes>
<li>FemaleSupremacy</li>
</conflictingMemes>
<associatedMemes>
<li>MaleSupremacy</li>
</associatedMemes>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_Precious_Taken_Forcefully</thought>
<tag>BeenRaped</tag>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_Precious_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_OnlyForSpouse_Know_Taken</thought>
<tag>Female, NotSpouse</tag>
</li>
<li Class="PreceptComp_SelfTookMemoryThought">
<eventDef>Virgin_TookF</eventDef>
<thought>TookVirginity</thought>
</li>
</comps>
</PreceptDef>
<PreceptDef>
<defName>Virgin_OnlyForSpouseM</defName>
<issue>Virginity_Male</issue>
<label>precious(strict)</label>
<description>Losing virginity before marriage is evil.</description>
<impact>Medium</impact>
<displayOrderInIssue>40</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>20</defaultSelectionWeight>
<requiredMemes>
<li>FemaleSupremacy</li>
</requiredMemes>
<conflictingMemes>
<li>MaleSupremacy</li>
</conflictingMemes>
<associatedMemes>
<li>FemaleSupremacy</li>
</associatedMemes>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_Precious_Taken_Forcefully</thought>
<tag>BeenRaped</tag>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_Precious_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
<li Class="RJWSexperience.Ideology.PreceptComp_KnowsMemoryThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_OnlyForSpouse_Know_Taken</thought>
<tag>Male, NotSpouse</tag>
</li>
<li Class="PreceptComp_SelfTookMemoryThought">
<eventDef>Virgin_TookM</eventDef>
<thought>TookVirginity</thought>
</li>
</comps>
</PreceptDef>
<PreceptDef>
<defName>Virgin_ShamefulF</defName>
<issue>Virginity_Female</issue>
<label>shameful</label>
<description>Remaining as virgin is shameful thing and being laughed at.</description>
<impact>Medium</impact>
<displayOrderInIssue>30</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>1</defaultSelectionWeight>
<associatedMemes>
<li>FemaleSupremacy</li>
</associatedMemes>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenF</eventDef>
<thought>Virgin_Shameful_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
</comps>
</PreceptDef>
<PreceptDef>
<defName>Virgin_ShamefulM</defName>
<issue>Virginity_Male</issue>
<label>shameful</label>
<description>Remaining as virgin is shameful thing and being laughed at.</description>
<impact>Medium</impact>
<displayOrderInIssue>30</displayOrderInIssue>
<displayOrderInImpact>1000</displayOrderInImpact>
<defaultSelectionWeight>40</defaultSelectionWeight>
<associatedMemes>
<li>MaleSupremacy</li>
</associatedMemes>
<comps>
<li Class="RJWSexperience.Ideology.PreceptComp_SelfTookThoughtTagged">
<eventDef>Virgin_TakenM</eventDef>
<thought>Virgin_Shameful_Taken</thought>
<tag>BeenRaped</tag>
<exclusive>true</exclusive>
</li>
</comps>
</PreceptDef>
<!-- Thoughts -->
<ThoughtDef>
<defName>Virgin_Precious_Taken_Forcefully</defName>
<thoughtClass>Thought_MemorySocial</thoughtClass>
<durationDays>30</durationDays>
<stackLimit>1</stackLimit>
<stages>
<li>
<label>Lost virginity</label>
<description>I lost my virginity forcefully.</description>
<baseMoodEffect>-10</baseMoodEffect>
<baseOpinionOffset>-200</baseOpinionOffset>
</li>
</stages>
</ThoughtDef>
<RJWSexperience.ThoughtDef_Opinionbased>
<defName>Virgin_Precious_Taken</defName>
<thoughtClass>RJWSexperience.Thought_Opinionbased</thoughtClass>
<durationDays>7</durationDays>
<stackLimit>1</stackLimit>
<minimumValueforStage>
<li>-100</li>
<li>-50</li>
<li>0</li>
<li>75</li>
</minimumValueforStage>
<stages>
<li>
<label>Lost virginity by {0}</label>
<description>I am no longer virgin.</description>
<baseMoodEffect>-5</baseMoodEffect>
</li>
<li>
<label>Lost virginity by {0}</label>
<description>I am no longer virgin.</description>
<baseMoodEffect>-3</baseMoodEffect>
</li>
<li>
<label>Lost virginity by {0}</label>
<description>I am no longer virgin.</description>
<baseMoodEffect>-1</baseMoodEffect>
</li>
<li>
<label>Gave virginity to {0}</label>
<description>I Gave my virginity to my love.</description>
<baseMoodEffect>5</baseMoodEffect>
</li>
</stages>
</RJWSexperience.ThoughtDef_Opinionbased>
<RJWSexperience.ThoughtDef_Opinionbased>
<defName>Virgin_Shameful_Taken</defName>
<thoughtClass>RJWSexperience.Thought_Opinionbased</thoughtClass>
<durationDays>7</durationDays>
<stackLimit>1</stackLimit>
<minimumValueforStage>
<li>-100</li>
<li>0</li>
<li>75</li>
</minimumValueforStage>
<stages>
<li>
<label>Lost virginity by {0}</label>
<description>Finally!</description>
<baseMoodEffect>5</baseMoodEffect>
</li>
<li>
<label>Lost virginity by {0}</label>
<description>Finally!</description>
<baseMoodEffect>10</baseMoodEffect>
</li>
<li>
<label>Lost virginity by {0}</label>
<description>Finally!</description>
<baseMoodEffect>20</baseMoodEffect>
</li>
</stages>
</RJWSexperience.ThoughtDef_Opinionbased>
<ThoughtDef>
<defName>Virgin_OnlyForSpouse_Know_Taken</defName>
<thoughtClass>Thought_MemorySocial</thoughtClass>
<durationDays>30</durationDays>
<stackLimit>100</stackLimit>
<stackLimitForSameOtherPawn>3</stackLimitForSameOtherPawn>
<nullifyingTraits>
<li>Nymphomaniac</li>
</nullifyingTraits>
<stages>
<li>
<label>slut</label>
<baseOpinionOffset>-30</baseOpinionOffset>
</li>
</stages>
</ThoughtDef>
</Defs>

View File

@ -21,6 +21,17 @@
<patternGroupTag/>
</RitualPatternDef>
<RitualPatternDef ParentName="GangbangBase">
<defName>Gangbang_Consensual</defName>
<ritualBehavior>Gangbang_Consensual</ritualBehavior>
<shortDescOverride>gangbang</shortDescOverride>
<descOverride>A ritualistic gangbang. The organizer will give a speech to excite the crowd, then fucked by the crowd.</descOverride>
<iconPathOverride>UI/Issues/Gangbang_Consensual</iconPathOverride>
<ritualOnlyForIdeoMembers>false</ritualOnlyForIdeoMembers>
<ritualOutcomeEffect>Gangbang_Consensual</ritualOutcomeEffect>
<patternGroupTag/>
</RitualPatternDef>
<RitualPatternDef ParentName="GangbangBase">
<defName>GangbangByAnimal</defName>
<ritualBehavior>GangbangByAnimal</ritualBehavior>
@ -32,6 +43,17 @@
<patternGroupTag/>
</RitualPatternDef>
<RitualPatternDef ParentName="GangbangBase">
<defName>GangbangByAnimal_Consensual</defName>
<ritualBehavior>GangbangByAnimal_Consensual</ritualBehavior>
<shortDescOverride>gangbang by animal</shortDescOverride>
<descOverride>A ritualistic animal gangbang. The organizer will give a speech to excite the crowd, then animals begin fuck the organizer.</descOverride>
<iconPathOverride>UI/Commands/Breeding_Pawn_on</iconPathOverride>
<ritualOnlyForIdeoMembers>false</ritualOnlyForIdeoMembers>
<ritualOutcomeEffect>BestialGangbang_Consensual</ritualOutcomeEffect>
<patternGroupTag/>
</RitualPatternDef>
<RitualPatternDef ParentName="CelebrationConsumable">
<defName>DrugOrgy</defName>
<shortDescOverride>drug orgy</shortDescOverride>

View File

@ -2,7 +2,9 @@
<Defs>
<RitualBehaviorDef Name="GangbangBehaviorBase" Abstract="True" ParentName="DateRitualBehavior">
<preceptRequirements><li Class="PreceptRequirement_Altar"/></preceptRequirements>
<preceptRequirements>
<li Class="PreceptRequirement_Altar"/>
</preceptRequirements>
<durationTicks>7500</durationTicks>
<roles Inherit="False">
<li Class="RitualRoleTag">
@ -84,7 +86,7 @@
</roleBehaviors>
</li>
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithVictim">
<defaultDuty>Gangbang</defaultDuty>
<defaultDuty>Gangbang_Rape</defaultDuty>
<essential>True</essential>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
@ -102,7 +104,7 @@
</roleBehaviors>
</li>
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithVictim">
<defaultDuty>Gangbang</defaultDuty>
<defaultDuty>Gangbang_Rape</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.1</percentage>
@ -122,6 +124,85 @@
</stages>
</RitualBehaviorDef>
<RitualBehaviorDef ParentName="GangbangBehaviorBase">
<defName>Gangbang_Consensual</defName>
<workerClass>RJWSexperience.Ideology.RitualBehaviorWorker_Gangbang_Consensual</workerClass>
<stages Inherit="False">
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithInitiator">
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_RolesArrived">
<roleIds>
<li>initiator</li>
</roleIds>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>ArriveToCell</dutyDef>
</li>
</roleBehaviors>
</li>
<li>
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.1</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>SpeakOnCellFacingSpectators</dutyDef>
<speakerInteraction>Speech_Gangbang</speakerInteraction>
<customPositions>
<li Class="RitualPosition_Lectern">
<maxDistanceToFocus>5</maxDistanceToFocus>
</li>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
</roleBehaviors>
</li>
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithInitiator">
<defaultDuty>Gangbang_Consensual</defaultDuty>
<essential>True</essential>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>1.0</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>LayDownAwake</dutyDef>
<customPositions>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
</roleBehaviors>
</li>
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithInitiator">
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.1</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>SpeakOnCellFacingSpectators</dutyDef>
<speakerInteraction>Speech_Gangbang</speakerInteraction>
<customPositions>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
</roleBehaviors>
</li>
</stages>
</RitualBehaviorDef>
<RitualBehaviorDef ParentName="GangbangBehaviorBase">
@ -228,7 +309,7 @@
<roleBehaviors>
<li>
<roleId>animal</roleId>
<dutyDef>Gangbang</dutyDef>
<dutyDef>Gangbang_Rape</dutyDef>
<customPositions>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
@ -263,7 +344,106 @@
</li>
</stages>
</RitualBehaviorDef>
<RitualBehaviorDef ParentName="GangbangBehaviorBase">
<defName>GangbangByAnimal_Consensual</defName>
<workerClass>RJWSexperience.Ideology.RitualBehaviorWorker_Gangbang_Consensual</workerClass>
<roles>
<li Class="RJWSexperience.Ideology.RitualRole_AnimalBreeder">
<label>breeder</label>
<id>animal</id>
<maxCount>30</maxCount>
<required>false</required>
<missingDesc>a breedable animal</missingDesc>
<countsAsParticipant>false</countsAsParticipant>
</li>
</roles>
<stages Inherit="False">
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithInitiator">
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_RolesArrived">
<roleIds>
<li>initiator</li>
</roleIds>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>ArriveToCell</dutyDef>
</li>
</roleBehaviors>
</li>
<li>
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.1</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>SpeakOnCellFacingSpectators</dutyDef>
<speakerInteraction>Speech_Zoophile</speakerInteraction>
<customPositions>
<li Class="RitualPosition_Lectern">
<maxDistanceToFocus>5</maxDistanceToFocus>
</li>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
<li>
<roleId>animal</roleId>
<dutyDef>Spectate</dutyDef>
</li>
</roleBehaviors>
</li>
<li Class="RJWSexperience.Ideology.RitualStage_InteractWithInitiator">
<defaultDuty>Spectate</defaultDuty>
<essential>True</essential>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.9</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>animal</roleId>
<dutyDef>Gangbang_Consensual</dutyDef>
<customPositions>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
<li>
<roleId>initiator</roleId>
<dutyDef>LayDownAwake</dutyDef>
</li>
</roleBehaviors>
</li>
<li>
<defaultDuty>Spectate</defaultDuty>
<endTriggers>
<li Class="StageEndTrigger_DurationPercentage">
<percentage>0.1</percentage>
</li>
</endTriggers>
<roleBehaviors>
<li>
<roleId>initiator</roleId>
<dutyDef>SpeakOnCellFacingSpectators</dutyDef>
<speakerInteraction>Speech_Zoophile</speakerInteraction>
<customPositions>
<li Class="RitualPosition_OnInteractionCell" />
</customPositions>
</li>
</roleBehaviors>
</li>
</stages>
</RitualBehaviorDef>
<RitualBehaviorDef ParentName="DateRitualBehavior">
<defName>DrugOrgy</defName>
<durationTicks>7500</durationTicks>

View File

@ -32,31 +32,114 @@
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>victim broken</label>
<qualityOffset>0.2</qualityOffset>
<qualityOffset>0.15</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.3</minSeverity>
<roleId>victim</roleId>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>victim extremly broken</label>
<qualityOffset>0.2</qualityOffset>
<qualityOffset>0.15</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.5</minSeverity>
<roleId>victim</roleId>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>victim completely broken</label>
<qualityOffset>0.4</qualityOffset>
<qualityOffset>0.3</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.9</minSeverity>
<roleId>victim</roleId>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_NeedBased">
<label>statisfied participants</label>
<qualityOffset>0.2</qualityOffset>
<qualityOffset>0.4</qualityOffset>
<needDef>Sex</needDef>
<minAvgNeed>0.7</minAvgNeed>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_NeedBased">
<label>completly statisfied participants</label>
<qualityOffset>0.4</qualityOffset>
<needDef>Sex</needDef>
<minAvgNeed>0.9</minAvgNeed>
</li>
</comps>
<outcomeChances>
<li>
<label>Terrible</label>
<chance>0.05</chance>
<memory>TerribleGangbang</memory>
<description>The {0} was terrible! The speech was stuttering and incoherent, and the victim was botched - everyone was waiting for it to end.</description>
<positivityIndex>-2</positivityIndex>
</li>
<li>
<label>Boring</label>
<chance>0.10</chance>
<memory>BoringGangbang</memory>
<description>The {0} was boring. The speech was repetitive and the victim was noticeably flawed. It just didn't feel dignified.</description>
<positivityIndex>-1</positivityIndex>
</li>
<li>
<label>Satisfying</label>
<chance>0.6</chance>
<memory>FunGangbang</memory>
<description>The {0} was satisfying. The speech felt meaningful, and the victim was precise and dignified.</description>
<potentialExtraOutcomeDesc>There's a 5% chance that a random participant gets an inspiration.</potentialExtraOutcomeDesc>
<positivityIndex>1</positivityIndex>
</li>
<li>
<label>Spectacular</label>
<chance>0.25</chance>
<memory>UnforgettableGangbang</memory>
<description>The {0} was spectacular! The speech brought everyone to the edge of a frenzy and the victim was like succubus.</description>
<potentialExtraOutcomeDesc>There's a 10% chance that a random participant gets an inspiration.</potentialExtraOutcomeDesc>
<positivityIndex>2</positivityIndex>
</li>
</outcomeChances>
</RitualOutcomeEffectDef>
<RitualOutcomeEffectDef>
<defName>Gangbang_Consensual</defName>
<description>Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days.</description>
<workerClass>RitualOutcomeEffectWorker_Consumable</workerClass>
<extraPredictedOutcomeDescriptions>
<li>If the {0} is satisfying, one of the participants might gain an inspiration.</li>
</extraPredictedOutcomeDescriptions>
<comps>
<li Class="RitualOutcomeComp_RolePresentNotSubstituted">
<roleId>initiator</roleId>
<label>moral guide present</label>
<qualityOffset>0.10</qualityOffset>
</li>
<li Class="RitualOutcomeComp_ParticipantCount">
<label>participant count</label>
<curve>
<points>
<li>(1, -0.20)</li>
<li>(3, -0.05)</li>
<li>(5, 0.05)</li>
<li>(10, 0.10)</li>
</points>
</curve>
</li>
<li Class="RitualOutcomeComp_RitualTargetDefs">
<allowAltars>true</allowAltars>
<label>started at altar</label>
<qualityOffset>0.2</qualityOffset>
<expectedThingLabelTip>an altar</expectedThingLabelTip>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_NeedBased">
<label>statisfied participants</label>
<qualityOffset>0.4</qualityOffset>
<needDef>Sex</needDef>
<minAvgNeed>0.7</minAvgNeed>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_NeedBased">
<label>completly statisfied participants</label>
<qualityOffset>1.0</qualityOffset>
<needDef>Sex</needDef>
<minAvgNeed>0.8</minAvgNeed>
</li>
</comps>
<outcomeChances>
<li>
@ -92,7 +175,6 @@
</outcomeChances>
</RitualOutcomeEffectDef>
<RitualOutcomeEffectDef>
<defName>BestialGangbang</defName>
<description>Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days.</description>
@ -125,21 +207,21 @@
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>breedee broken</label>
<qualityOffset>0.3</qualityOffset>
<qualityOffset>0.45</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.3</minSeverity>
<roleId>victim</roleId>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>breedee extremly broken</label>
<qualityOffset>0.3</qualityOffset>
<qualityOffset>0.45</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.5</minSeverity>
<roleId>victim</roleId>
</li>
<li Class="RJWSexperience.Ideology.RitualOutcomeComp_HediffBased">
<label>breedee completely broken</label>
<qualityOffset>0.6</qualityOffset>
<qualityOffset>0.8</qualityOffset>
<hediffDef>FeelingBroken</hediffDef>
<minSeverity>0.9</minSeverity>
<roleId>victim</roleId>
@ -179,6 +261,70 @@
</outcomeChances>
</RitualOutcomeEffectDef>
<RitualOutcomeEffectDef>
<defName>BestialGangbang_Consensual</defName>
<description>Depending on ritual quality, participants will get between {MINMOOD} and {MAXMOOD} mood for {MOODDAYS} days.</description>
<workerClass>RitualOutcomeEffectWorker_Consumable</workerClass>
<extraPredictedOutcomeDescriptions>
<li>If the {0} is satisfying, one of the participants might gain an inspiration.</li>
</extraPredictedOutcomeDescriptions>
<comps>
<li Class="RitualOutcomeComp_RolePresentNotSubstituted">
<roleId>initiator</roleId>
<label>moral guide present</label>
<qualityOffset>0.10</qualityOffset>
</li>
<li Class="RitualOutcomeComp_ParticipantCount">
<label>participant count</label>
<curve>
<points>
<li>(1, 0.20)</li>
<li>(3, 0.40)</li>
<li>(5, 0.65)</li>
<li>(10, 1.20)</li>
</points>
</curve>
</li>
<li Class="RitualOutcomeComp_RitualTargetDefs">
<allowAltars>true</allowAltars>
<label>started at altar</label>
<qualityOffset>0.2</qualityOffset>
<expectedThingLabelTip>an altar</expectedThingLabelTip>
</li>
</comps>
<outcomeChances>
<li>
<label>Terrible</label>
<chance>0.05</chance>
<memory>TerribleGangbang</memory>
<description>The {0} was terrible! The speech was stuttering and incoherent, and the victim was botched - everyone was waiting for it to end.</description>
<positivityIndex>-2</positivityIndex>
</li>
<li>
<label>Boring</label>
<chance>0.10</chance>
<memory>BoringGangbang</memory>
<description>The {0} was boring. The speech was repetitive and the victim was noticeably flawed. It just didn't feel dignified.</description>
<positivityIndex>-1</positivityIndex>
</li>
<li>
<label>Satisfying</label>
<chance>0.65</chance>
<memory>FunGangbang</memory>
<description>The {0} was satisfying. The speech felt meaningful, and the victim was precise and dignified.</description>
<potentialExtraOutcomeDesc>There's a 5% chance that a random participant gets an inspiration.</potentialExtraOutcomeDesc>
<positivityIndex>1</positivityIndex>
</li>
<li>
<label>Spectacular</label>
<chance>0.2</chance>
<memory>UnforgettableGangbang</memory>
<description>The {0} was spectacular! The speech brought everyone to the edge of a frenzy and the victim was like succubus.</description>
<potentialExtraOutcomeDesc>There's a 10% chance that a random participant gets an inspiration.</potentialExtraOutcomeDesc>
<positivityIndex>2</positivityIndex>
</li>
</outcomeChances>
</RitualOutcomeEffectDef>
<RitualOutcomeEffectDef>
<defName>DrugOrgy</defName>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

BIN
Textures/UI/Icon/Incest.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

View File

@ -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