diff --git a/CRIALactation/1.3/Assemblies/CRIALactation.dll b/CRIALactation/1.3/Assemblies/CRIALactation.dll index 603de22..15d9f7e 100644 Binary files a/CRIALactation/1.3/Assemblies/CRIALactation.dll and b/CRIALactation/1.3/Assemblies/CRIALactation.dll differ diff --git a/CRIALactation/CRIALactation.csproj b/CRIALactation/CRIALactation.csproj index 05c1d6c..f1c7208 100644 --- a/CRIALactation/CRIALactation.csproj +++ b/CRIALactation/CRIALactation.csproj @@ -70,10 +70,14 @@ + + + + @@ -81,12 +85,16 @@ + + + + \ No newline at end of file diff --git a/CRIALactation/Defs/JobDefs/Jobs_CRIALactation.xml b/CRIALactation/Defs/JobDefs/Jobs_CRIALactation.xml new file mode 100644 index 0000000..970f70b --- /dev/null +++ b/CRIALactation/Defs/JobDefs/Jobs_CRIALactation.xml @@ -0,0 +1,9 @@ + + + + MassageBreasts + CRIALactation.JobDriver_MassageBreasts + stimulating TargetA's breasts. + true + + diff --git a/CRIALactation/Defs/WorkGiverDefs/WorkGiver_MassageBreasts.xml b/CRIALactation/Defs/WorkGiverDefs/WorkGiver_MassageBreasts.xml new file mode 100644 index 0000000..b1dee55 --- /dev/null +++ b/CRIALactation/Defs/WorkGiverDefs/WorkGiver_MassageBreasts.xml @@ -0,0 +1,15 @@ + + + + MassageBreasts + + CRIALactation.WorkGiver_MassageBreasts + Handling + massage + stimulating the breasts of + 91 + +
  • Manipulation
  • +
    +
    +
    diff --git a/CRIALactation/Patches/Patch_LactationInduction.xml b/CRIALactation/Patches/Patch_LactationInduction.xml new file mode 100644 index 0000000..fb63d15 --- /dev/null +++ b/CRIALactation/Patches/Patch_LactationInduction.xml @@ -0,0 +1,28 @@ + + + + Always + +
  • + /Defs/ThingDef/comps + Always + + /Defs/ThingDef + + + + +
  • + +
  • + /Defs/ThingDef[@Name="BasePawn"]/comps + +
  • + 15 + 2.5 +
  • + + +
    +
    +
    diff --git a/CRIALactation/Source/CompProperties/CompProperties_InduceLactation.cs b/CRIALactation/Source/CompProperties/CompProperties_InduceLactation.cs new file mode 100644 index 0000000..9c119b2 --- /dev/null +++ b/CRIALactation/Source/CompProperties/CompProperties_InduceLactation.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using rjw; +using Milk; +using UnityEngine; + +namespace CRIALactation +{ + public class CompProperties_InduceLactation : CompProperties + { + public CompProperties_InduceLactation() + { + this.compClass = typeof(CompInduceLactation); + } + + public float DaysToLactating = 15; + public float TimesMassagedADay = 2.5f; + } +} diff --git a/CRIALactation/Source/Comps/CompInduceLactation.cs b/CRIALactation/Source/Comps/CompInduceLactation.cs new file mode 100644 index 0000000..2695ffc --- /dev/null +++ b/CRIALactation/Source/Comps/CompInduceLactation.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using rjw; +using Milk; +using UnityEngine; + +namespace CRIALactation +{ + public class CompInduceLactation : ThingComp + { + private readonly int OneDayInTicks = 60000; + private int TicksSinceLastMassage = -60000; + + private float InductionCompletionPercent = 0f; + public bool isActive = false; + public bool CanMassage = true; + + public override void CompTick() + { + base.CompTick(); + Pawn p = this.parent as Pawn; + + if (!isActive) + { + return; + } + if (!p.IsHashIntervalTick(100)) + { + return; + } + + if (LactationUtility.IsLactating(p)) + { + isActive = false; + return; + } + + if(TicksSinceLastMassage + OneDayInTicks / Props.TimesMassagedADay < GenTicks.TicksGame) + { + CanMassage = true; + } + + if(InductionCompletionPercent >= 1) + { + string main = p.Name.ToStringShort + "'s breasts have been stimulated enough to induce lactation! They can now begin producing milk for their colony's consumption."; + + var letter = LetterMaker.MakeLetter(p.Name.ToStringShort + " induced lactation", main, LetterDefOf.PositiveEvent); + Find.LetterStack.ReceiveLetter(letter); + + LactationUtility.StartLactating(p, true); + isActive = false; + InductionCompletionPercent = 0.6f; //start at 60% in case they ever lose lactating again + } + } + + public void MassageBreasts() + { + InductionCompletionPercent += (float)1 / (Props.DaysToLactating * (Props.TimesMassagedADay + Rand.Value)); + TicksSinceLastMassage = GenTicks.TicksGame; + CanMassage = false; + } + + public CompProperties_InduceLactation Props + { + get + { + return (CompProperties_InduceLactation)props; + } + } + + public override IEnumerable CompFloatMenuOptions(Pawn pawn) + { + if (pawn != this.parent as Pawn) yield break; + if (LactationUtility.IsLactating(pawn)) yield break; + if(LactationUtility.HasMilkableBreasts(this.parent as Pawn)) + { + if(isActive) + { + //stop trying to induce lactation + yield return new FloatMenuOption("Undesignate induce lactation", () => + { + isActive = false; + }); + } + else + { + //induce lactation + yield return new FloatMenuOption("Designate induce lactation", () => + { + isActive = true; + }); + } + } + else + { + yield return new FloatMenuOption("Designate induce lactation (no milkable breasts)", null); + } + + yield break; + } + + public override void PostExposeData() + { + base.PostExposeData(); + Scribe_Values.Look(ref this.InductionCompletionPercent, "InductionCompletionPercent", 0f); + Scribe_Values.Look(ref this.TicksSinceLastMassage, "TicksSinceLastMassage", -60000); + + Scribe_Values.Look(ref this.isActive, "IsActive", false); + Scribe_Values.Look(ref this.CanMassage, "CanMassage", false); + + } + + public override string CompInspectStringExtra() + { + if (!isActive) return null; + + string result = "Induce lactation completion: " + InductionCompletionPercent.ToStringPercent(); + + if(CanMassage) + { + result += "\nReady to massage."; + } + + return result; + } + } +} diff --git a/CRIALactation/Source/JobDefOf/JobDefOf_CRIALactation.cs b/CRIALactation/Source/JobDefOf/JobDefOf_CRIALactation.cs new file mode 100644 index 0000000..7aa204d --- /dev/null +++ b/CRIALactation/Source/JobDefOf/JobDefOf_CRIALactation.cs @@ -0,0 +1,21 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace CRIALactation +{ + [DefOf] + public static class JobDefOf_CRIALactation + { + static JobDefOf_CRIALactation() + { + DefOfHelper.EnsureInitializedInCtor(typeof(HediffDefOf_Milk)); + } + + public static JobDef MassageBreasts; + } +} diff --git a/CRIALactation/Source/JobDrivers/JobDriver_MassageBreasts.cs b/CRIALactation/Source/JobDrivers/JobDriver_MassageBreasts.cs new file mode 100644 index 0000000..4092ef0 --- /dev/null +++ b/CRIALactation/Source/JobDrivers/JobDriver_MassageBreasts.cs @@ -0,0 +1,79 @@ +using Milk; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using RimWorld; +using Verse.AI; + +namespace CRIALactation +{ + public class JobDriver_MassageBreasts : JobDriver + { + private readonly float WorkTotal = 300f; + + public override bool TryMakePreToilReservations(bool errorOnFailed) + { + LocalTargetInfo Target = job.GetTarget(TargetIndex.A); + return pawn.Reserve(Target, job, 1, -1, null, errorOnFailed); + } + + protected override IEnumerable MakeNewToils() + { + this.FailOnDespawnedNullOrForbidden(TargetIndex.A); + yield return Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch); + Toil massage = new Toil(); + massage.FailOnDespawnedOrNull(TargetIndex.A); + massage.FailOnAggroMentalStateAndHostile(TargetIndex.A); + massage.initAction = delegate + { + Pawn p = job.GetTarget(TargetIndex.A).Thing as Pawn; + pawn.pather.StopDead(); + PawnUtility.ForceWait(p, 15000, null, true); + }; + massage.tickAction = delegate () + { + pawn.skills.Learn(SkillDefOf.Animals, 0.13f, false); + massageProgress += pawn.GetStatValue(StatDefOf.AnimalGatherSpeed, true); + + }; + massage.AddEndCondition(delegate + { + Pawn p = job.GetTarget(TargetIndex.A).Thing as Pawn; + if (massageProgress >= WorkTotal) + { + p.TryGetComp().MassageBreasts(); + return JobCondition.Succeeded; + } + + if (!(p.TryGetComp().isActive && p.TryGetComp().CanMassage)) + { + return JobCondition.Incompletable; + } + + return JobCondition.Ongoing; + + }); + + massage.AddFinishAction(delegate { + Pawn pawn = this.job.GetTarget(TargetIndex.A).Thing as Pawn; + if (pawn != null && pawn.CurJobDef == JobDefOf.Wait_MaintainPosture) + { + pawn.jobs.EndCurrentJob(JobCondition.InterruptForced, true, true); + } + }); + massage.defaultCompleteMode = ToilCompleteMode.Never; + + massage.WithProgressBar(TargetIndex.A, () => massageProgress / WorkTotal); + massage.activeSkill = (() => SkillDefOf.Animals); + yield return massage; + yield break; + + } + + float massageProgress = 0f; + } +} diff --git a/CRIALactation/Source/LactationUtility.cs b/CRIALactation/Source/LactationUtility.cs index 00e0246..12ee7d0 100644 --- a/CRIALactation/Source/LactationUtility.cs +++ b/CRIALactation/Source/LactationUtility.cs @@ -38,5 +38,17 @@ namespace CRIALactation lactating.Severity = Rand.Value; p.health.AddHediff(lactating, Genital_Helper.get_breastsBPR(p)); } + + public static bool isMassageable(Pawn p) + { + CompInduceLactation c = p.TryGetComp(); + if (c != null && c.isActive && c.CanMassage) + { + return true; + } + + return false; + + } } } diff --git a/CRIALactation/Source/WorkGivers/WorkGiver_MassageBreasts.cs b/CRIALactation/Source/WorkGivers/WorkGiver_MassageBreasts.cs new file mode 100644 index 0000000..db54550 --- /dev/null +++ b/CRIALactation/Source/WorkGivers/WorkGiver_MassageBreasts.cs @@ -0,0 +1,56 @@ +using Milk; +using RimWorld; +using RimWorld.Planet; +using rjw; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; +using Verse.AI; + +namespace CRIALactation +{ + public class WorkGiver_MassageBreasts : WorkGiver_Scanner + { + public override IEnumerable PotentialWorkThingsGlobal(Pawn pawn) + { + return pawn.Map.mapPawns.SpawnedPawnsInFaction(pawn.Faction); + } + + public override bool ShouldSkip(Pawn pawn, bool forced = false) + { + List list = pawn.Map.mapPawns.SpawnedPawnsInFaction(pawn.Faction); + for(int i = 0; i < list.Count; i++) + { + if(LactationUtility.isMassageable(list[i])) + { + return false; + } + } + + return true; + } + + public override bool HasJobOnThing(Pawn p, Thing t, bool forced = false) + { + Pawn pawn2 = t as Pawn; + if(pawn2?.TryGetComp() == null) + { + return false; + } + CompInduceLactation c = pawn2.TryGetComp(); + + return p != pawn2 && c.isActive && c.CanMassage && !pawn2.Downed && !pawn2.Drafted && !pawn2.InAggroMentalState && !pawn2.IsFormingCaravan() && pawn2.CanCasuallyInteractNow(false, true, false) && p.CanReserve(pawn2, 1, -1, null, forced); + + } + + public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false) + { + return JobMaker.MakeJob(JobDefOf_CRIALactation.MassageBreasts, t); + } + + + } +}