mirror of
https://github.com/amevarashi/RJW-Sexperience.git
synced 2024-08-14 23:54:08 +00:00
Rename source folder
This commit is contained in:
parent
0a412a0060
commit
a4c046a841
55 changed files with 0 additions and 0 deletions
77
Source/RJWSexperience/Cum/Building_Cumbucket.cs
Normal file
77
Source/RJWSexperience/Cum/Building_Cumbucket.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using RimWorld;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Verse;
|
||||
|
||||
namespace RJWSexperience // Used in Menstruation with this namespace
|
||||
{
|
||||
public class Building_CumBucket : Building_Storage
|
||||
{
|
||||
protected float storedDecimalRemainder = 0f;
|
||||
protected float totalGathered = 0f;
|
||||
|
||||
public int StoredStackCount
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!slotGroup.HeldThings.Any())
|
||||
return 0;
|
||||
return slotGroup.HeldThings.Select(thing => thing.stackCount).Aggregate((sum, x) => sum + x);
|
||||
}
|
||||
}
|
||||
|
||||
public override void ExposeData()
|
||||
{
|
||||
Scribe_Values.Look(ref storedDecimalRemainder, "storedcum", 0f);
|
||||
Scribe_Values.Look(ref totalGathered, "totalgathered", 0f);
|
||||
base.ExposeData();
|
||||
}
|
||||
|
||||
public override string GetInspectString()
|
||||
{
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
|
||||
string baseString = base.GetInspectString();
|
||||
if (!baseString.NullOrEmpty())
|
||||
{
|
||||
stringBuilder.AppendLine(baseString);
|
||||
}
|
||||
|
||||
stringBuilder.Append(Keyed.RSTotalGatheredCum).AppendFormat("{0:0.##}ml", totalGathered);
|
||||
|
||||
if (SexperienceMod.Settings.Debug.DevMode)
|
||||
{
|
||||
stringBuilder.AppendLine();
|
||||
stringBuilder.AppendLine($"[Debug] stored: {StoredStackCount}");
|
||||
stringBuilder.Append($"[Debug] storedDecimalRemainder: {storedDecimalRemainder}");
|
||||
}
|
||||
|
||||
return stringBuilder.ToString();
|
||||
}
|
||||
|
||||
public void AddCum(float amount)
|
||||
{
|
||||
AddCum(amount, VariousDefOf.GatheredCum);
|
||||
}
|
||||
|
||||
public void AddCum(float amount, ThingDef cumDef)
|
||||
{
|
||||
Thing cum = ThingMaker.MakeThing(cumDef);
|
||||
AddCum(amount, cum);
|
||||
}
|
||||
|
||||
public void AddCum(float amount, Thing cum)
|
||||
{
|
||||
storedDecimalRemainder += amount;
|
||||
totalGathered += amount;
|
||||
int num = (int)storedDecimalRemainder;
|
||||
|
||||
cum.stackCount = num;
|
||||
if (cum.stackCount > 0 && !GenPlace.TryPlaceThing(cum, PositionHeld, Map, ThingPlaceMode.Direct, out Thing res))
|
||||
{
|
||||
FilthMaker.TryMakeFilth(PositionHeld, Map, VariousDefOf.FilthCum, num);
|
||||
}
|
||||
storedDecimalRemainder -= num;
|
||||
}
|
||||
}
|
||||
}
|
160
Source/RJWSexperience/Cum/CumUtility.cs
Normal file
160
Source/RJWSexperience/Cum/CumUtility.cs
Normal file
|
@ -0,0 +1,160 @@
|
|||
using rjw;
|
||||
using rjw.Modules.Interactions.Enums;
|
||||
using RJWSexperience.ExtensionMethods;
|
||||
using RJWSexperience.Logs;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum
|
||||
{
|
||||
public static class CumUtility
|
||||
{
|
||||
private static readonly rjw.Modules.Shared.Logs.ILog log = LogManager.GetLogger<DebugLogProvider>("CumUtility");
|
||||
|
||||
public static float GetOnePartCumVolume(Pawn pawn)
|
||||
{
|
||||
List<Hediff> hediffs = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn));
|
||||
if (hediffs.NullOrEmpty())
|
||||
return 0f;
|
||||
|
||||
float result = GetCumVolume(pawn, GetOneBodyPartComp(hediffs));
|
||||
log.Message($"GetOnePartCumVolume({pawn.NameShortColored}) = {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float GetCumVolume(Pawn pawn)
|
||||
{
|
||||
List<Hediff> hediffs = Genital_Helper.get_PartsHediffList(pawn, Genital_Helper.get_genitalsBPR(pawn));
|
||||
if (hediffs.NullOrEmpty())
|
||||
return 0f;
|
||||
float result = GetCumVolume(pawn, GetAllBodyPartComps(hediffs));
|
||||
log.Message($"GetCumVolume({pawn.NameShortColored}) = {result}");
|
||||
return result;
|
||||
}
|
||||
|
||||
public static float GetCumVolume(Pawn pawn, List<CompHediffBodyPart> parts)
|
||||
{
|
||||
return parts.Select(part => GetCumVolume(pawn, part)).Aggregate((sum, x) => sum + x);
|
||||
}
|
||||
|
||||
public static float GetCumVolume(Pawn pawn, CompHediffBodyPart part)
|
||||
{
|
||||
float res;
|
||||
|
||||
try
|
||||
{
|
||||
res = part.FluidAmmount * part.FluidModifier * pawn.BodySize / pawn.RaceProps.baseBodySize * Rand.Range(0.8f, 1.2f) * 0.3f;
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
res = 0.0f;
|
||||
}
|
||||
if (pawn.Has(Quirk.Messy)) res *= Rand.Range(4.0f, 8.0f);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
public static List<CompHediffBodyPart> GetAllBodyPartComps(List<Hediff> hediffs)
|
||||
{
|
||||
List<CompHediffBodyPart> bodyPartComps = new List<CompHediffBodyPart>();
|
||||
|
||||
foreach (Hediff bodyPart in hediffs)
|
||||
{
|
||||
CompHediffBodyPart bodyPartComp = bodyPart.TryGetComp<CompHediffBodyPart>();
|
||||
if (bodyPartComp != null)
|
||||
bodyPartComps.Add(bodyPartComp);
|
||||
}
|
||||
|
||||
return bodyPartComps;
|
||||
}
|
||||
|
||||
public static CompHediffBodyPart GetOneBodyPartComp(List<Hediff> hediffs)
|
||||
{
|
||||
CompHediffBodyPart part = hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("penis")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>();
|
||||
if (part == null) part = hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorf")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>();
|
||||
if (part == null) part = hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("ovipositorm")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>();
|
||||
if (part == null) part = hediffs?.FindAll((Hediff hed) => hed.def.defName.ToLower().Contains("tentacle")).InRandomOrder().FirstOrDefault()?.TryGetComp<CompHediffBodyPart>();
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
public static void TryFeedCum(SexProps props)
|
||||
{
|
||||
if (!Genital_Helper.has_penis_fertile(props.pawn))
|
||||
return;
|
||||
|
||||
if (!PawnsPenisIsInPartnersMouth(props))
|
||||
return;
|
||||
|
||||
float cumAmount = CumUtility.GetOnePartCumVolume(props.pawn);
|
||||
|
||||
if (cumAmount <= 0)
|
||||
return;
|
||||
|
||||
FeedCum(props.partner, cumAmount);
|
||||
}
|
||||
|
||||
private static bool PawnsPenisIsInPartnersMouth(SexProps props)
|
||||
{
|
||||
var interaction = rjw.Modules.Interactions.Helpers.InteractionHelper.GetWithExtension(props.dictionaryKey);
|
||||
|
||||
if (props.pawn == props.GetInteractionInitiator())
|
||||
{
|
||||
if (!interaction.DominantHasTag(GenitalTag.CanPenetrate) && !interaction.DominantHasFamily(GenitalFamily.Penis))
|
||||
return false;
|
||||
var requirement = interaction.SelectorExtension.submissiveRequirement;
|
||||
if (!requirement.mouth && !requirement.beak && !requirement.mouthORbeak)
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!interaction.SubmissiveHasTag(GenitalTag.CanPenetrate) && !interaction.SubmissiveHasFamily(GenitalFamily.Penis))
|
||||
return false;
|
||||
var requirement = interaction.SelectorExtension.dominantRequirement;
|
||||
if (!requirement.mouth && !requirement.beak && !requirement.mouthORbeak)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void FeedCum(Pawn pawn, float amount)
|
||||
{
|
||||
const float allOf = 1000f;
|
||||
|
||||
log.Message($"FeedCum({pawn.NameShortColored}, {amount})");
|
||||
Thing cum = ThingMaker.MakeThing(VariousDefOf.GatheredCum);
|
||||
cum.stackCount = (int)Math.Ceiling(amount);
|
||||
log.Message($"Created a stack of {cum.stackCount} cum");
|
||||
cum.Ingested(pawn, allOf);
|
||||
log.Message($"{pawn.NameShortColored} ingested cum");
|
||||
}
|
||||
|
||||
public static void FillCumBuckets(SexProps props)
|
||||
{
|
||||
xxx.rjwSextype sextype = props.sexType;
|
||||
|
||||
bool sexFillsCumbuckets =
|
||||
// Base: Fill Cumbuckets on Masturbation. Having no partner means it must be masturbation too
|
||||
sextype == xxx.rjwSextype.Masturbation || props.partner == null
|
||||
// Depending on configuration, also fill cumbuckets when certain sextypes are matched
|
||||
|| (SexperienceMod.Settings.SexCanFillBuckets && (sextype == xxx.rjwSextype.Boobjob || sextype == xxx.rjwSextype.Footjob || sextype == xxx.rjwSextype.Handjob));
|
||||
|
||||
if (!sexFillsCumbuckets)
|
||||
return;
|
||||
|
||||
IEnumerable<Building_CumBucket> buckets = props.pawn.GetAdjacentBuildings<Building_CumBucket>();
|
||||
|
||||
if (buckets?.EnumerableCount() > 0)
|
||||
{
|
||||
var initialCum = CumUtility.GetCumVolume(props.pawn);
|
||||
foreach (Building_CumBucket bucket in buckets)
|
||||
{
|
||||
bucket.AddCum(initialCum / buckets.EnumerableCount());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum.FilterWorkers
|
||||
{
|
||||
public class SpecialThingFilterWorker_Cum : SpecialThingFilterWorker_CumBase
|
||||
{
|
||||
public override bool Matches(Thing t)
|
||||
{
|
||||
return IsCum(t) || IsFoodWithCum(t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum.FilterWorkers
|
||||
{
|
||||
public abstract class SpecialThingFilterWorker_CumBase : SpecialThingFilterWorker
|
||||
{
|
||||
public override bool CanEverMatch(ThingDef def)
|
||||
{
|
||||
return def.IsIngestible && def.IsProcessedFood;
|
||||
}
|
||||
|
||||
protected bool IsCum(Thing t) => IsCum(t.def);
|
||||
|
||||
protected bool IsCum(ThingDef t) => t == VariousDefOf.GatheredCum;
|
||||
|
||||
protected bool IsFoodWithCum(Thing food)
|
||||
{
|
||||
CompIngredients compIngredients = food.TryGetComp<CompIngredients>();
|
||||
|
||||
if (compIngredients == null)
|
||||
return false;
|
||||
|
||||
foreach (ThingDef ingredient in compIngredients.ingredients)
|
||||
{
|
||||
if (IsCum(ingredient))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum.FilterWorkers
|
||||
{
|
||||
public class SpecialThingFilterWorker_NoCum : SpecialThingFilterWorker_CumBase
|
||||
{
|
||||
public override bool Matches(Thing t)
|
||||
{
|
||||
return !IsCum(t) && !IsFoodWithCum(t);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using RimWorld;
|
||||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum
|
||||
{
|
||||
public class IngestionOutcomeDoer_RecordEatenCum : IngestionOutcomeDoer
|
||||
{
|
||||
[System.Diagnostics.CodeAnalysis.SuppressMessage("Minor Code Smell", "S1104:Fields should not have public accessibility", Justification = "Field value loaded from XML")]
|
||||
public float unitAmount = 1.0f;
|
||||
|
||||
protected override void DoIngestionOutcomeSpecial(Pawn pawn, Thing ingested)
|
||||
{
|
||||
int amount = ingested.stackCount * (int)unitAmount;
|
||||
Logs.LogManager.GetLogger<IngestionOutcomeDoer_RecordEatenCum, Logs.DebugLogProvider>().Message($"Record {pawn.NameShortColored} eating {amount} ml of cum");
|
||||
pawn.records.Increment(VariousDefOf.NumofEatenCum);
|
||||
pawn.records.AddTo(VariousDefOf.AmountofEatenCum, amount);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,75 @@
|
|||
using RimWorld;
|
||||
using rjw.Modules.Interactions.Contexts;
|
||||
using rjw.Modules.Interactions.Enums;
|
||||
using rjw.Modules.Interactions.Rules.PartKindUsageRules;
|
||||
using rjw.Modules.Shared;
|
||||
using RJWSexperience.Logs;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Verse;
|
||||
|
||||
namespace RJWSexperience.Cum.Interactions
|
||||
{
|
||||
public class CumAddictPartKindUsageRule : IPartPreferenceRule
|
||||
{
|
||||
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForDominant(InteractionContext context)
|
||||
{
|
||||
if (context.Internals.Submissive.Parts.Penises.Any())
|
||||
return GetForCumAddict(context.Internals.Dominant.Pawn);
|
||||
|
||||
if (AddictionUtility.IsAddicted(context.Internals.Submissive.Pawn, VariousDefOf.Cum))
|
||||
return GetForPartner();
|
||||
|
||||
return Enumerable.Empty<Weighted<LewdablePartKind>>();
|
||||
}
|
||||
|
||||
public IEnumerable<Weighted<LewdablePartKind>> ModifiersForSubmissive(InteractionContext context)
|
||||
{
|
||||
if (context.Internals.Dominant.Parts.Penises.Any())
|
||||
return GetForCumAddict(context.Internals.Submissive.Pawn);
|
||||
|
||||
if (AddictionUtility.IsAddicted(context.Internals.Dominant.Pawn, VariousDefOf.Cum))
|
||||
return GetForPartner();
|
||||
|
||||
return Enumerable.Empty<Weighted<LewdablePartKind>>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Addict wants to use mouth
|
||||
/// </summary>
|
||||
private IEnumerable<Weighted<LewdablePartKind>> GetForCumAddict(Pawn pawn)
|
||||
{
|
||||
var log = LogManager.GetLogger<CumAddictPartKindUsageRule, DebugLogProvider>();
|
||||
log.Message($"Called for {pawn.NameShortColored}");
|
||||
|
||||
if (!(pawn.needs?.TryGetNeed(VariousDefOf.Chemical_Cum) is Need_Chemical cumNeed))
|
||||
yield break;
|
||||
|
||||
log.Message($"{pawn.NameShortColored} is cum addict, current desire level: {cumNeed.CurCategory}");
|
||||
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.DoubledPlus, LewdablePartKind.Mouth);
|
||||
|
||||
// In dire need also they are also refuse to use other orifices
|
||||
switch (cumNeed.CurCategory)
|
||||
{
|
||||
case DrugDesireCategory.Desire:
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.VeryRare, LewdablePartKind.Anus);
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.VeryRare, LewdablePartKind.Vagina);
|
||||
break;
|
||||
|
||||
case DrugDesireCategory.Withdrawal:
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Never, LewdablePartKind.Anus);
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Never, LewdablePartKind.Vagina);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Addict asks partner to use penis
|
||||
/// </summary>
|
||||
private IEnumerable<Weighted<LewdablePartKind>> GetForPartner()
|
||||
{
|
||||
yield return new Weighted<LewdablePartKind>(Multipliers.Common, LewdablePartKind.Penis);
|
||||
}
|
||||
}
|
||||
}
|
39
Source/RJWSexperience/Cum/Thought_AteCum.cs
Normal file
39
Source/RJWSexperience/Cum/Thought_AteCum.cs
Normal file
|
@ -0,0 +1,39 @@
|
|||
using RimWorld;
|
||||
|
||||
namespace RJWSexperience // Change in namespace will lead to save incompatibility
|
||||
{
|
||||
public class Thought_AteCum : Thought_Recordbased
|
||||
{
|
||||
public override int CurStageIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pawn?.health?.hediffSet?.HasHediff(VariousDefOf.CumAddiction) ?? false)
|
||||
return def.stages.Count - 1;
|
||||
return base.CurStageIndex;
|
||||
}
|
||||
}
|
||||
|
||||
public override bool TryMergeWithExistingMemory(out bool showBubble)
|
||||
{
|
||||
ThoughtHandler thoughts = pawn.needs.mood.thoughts;
|
||||
if (thoughts.memories.NumMemoriesInGroup(this) >= def.stackLimit)
|
||||
{
|
||||
Thought_AteCum thought_Memory = (Thought_AteCum)thoughts.memories.OldestMemoryInGroup(this);
|
||||
if (thought_Memory != null)
|
||||
{
|
||||
showBubble = thought_Memory.age > thought_Memory.def.DurationTicks / 2;
|
||||
thought_Memory.Merged();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
showBubble = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void Merged()
|
||||
{
|
||||
age = 0;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue