コード例 #1
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            //--Log.Message("[RJW] JobGiver_DoFappin::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called");

            if (pawn.Drafted)
            {
                return(null);
            }

            if (!xxx.can_be_fucked(pawn) && !xxx.can_fuck(pawn))
            {
                return(null);
            }

            // W****s only fap if frustrated, unless imprisoned.
            if ((SexUtility.ReadyForLovin(pawn) && (!xxx.is_whore(pawn) || pawn.IsPrisoner)) || xxx.is_frustrated(pawn))
            {
                if (pawn.jobs.curDriver is JobDriver_LayDown && RJWPreferenceSettings.FapInBed)
                {
                    Building_Bed bed = ((JobDriver_LayDown)pawn.jobs.curDriver).Bed;
                    if (bed != null)
                    {
                        return(new Job(xxx.fappin, bed));
                    }
                }
                else if ((xxx.is_frustrated(pawn) || xxx.has_quirk(pawn, "Exhibitionist")) && RJWPreferenceSettings.FapEverywhere)
                {
                    return(new Job(xxx.quickfap, FindFapLocation(pawn)));
                }
            }
            return(null);
        }
コード例 #2
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            //Log.Message("[RJW] JobGiver_AIRapePrisoner::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called ");

            if (!xxx.can_rape(pawn))
            {
                return(null);
            }

            if (SexUtility.ReadyForLovin(pawn) || xxx.is_hornyorfrustrated(pawn))
            {
                // don't allow pawns marked as comfort prisoners to rape others
                if (xxx.is_healthy(pawn))
                {
                    Pawn prisoner = find_victim(pawn, pawn.Map);

                    if (prisoner != null)
                    {
                        //--Log.Message("[RJW] JobGiver_RandomRape::TryGiveJob( " + xxx.get_pawnname(p) + " ) - found victim " + xxx.get_pawnname(prisoner));
                        return(JobMaker.MakeJob(xxx.RapeRandom, prisoner));
                    }
                }
            }

            return(null);
        }
コード例 #3
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            // Most checks are done in ThinkNode_ConditionalNecro.

            // filter out necro for nymphs
            if (!RJWSettings.necrophilia_enabled)
            {
                return(null);
            }

            if (pawn.Drafted)
            {
                return(null);
            }

            //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob for ( " + xxx.get_pawnname(pawn) + " )");
            if (SexUtility.ReadyForLovin(pawn) || xxx.is_hornyorfrustrated(pawn))
            {
                //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob, can love ");
                if (!xxx.can_rape(pawn))
                {
                    return(null);
                }

                var target = find_corpse(pawn, pawn.Map);
                //--Log.Message("[RJW] JobGiver_ViolateCorpse::TryGiveJob - target is " + (target == null ? "NULL" : "Found"));
                if (target != null)
                {
                    return(JobMaker.MakeJob(xxx.RapeCorpse, target));
                }
                // Ticks should only be increased after successful sex.
            }

            return(null);
        }
コード例 #4
0
        public void Start()
        {
            if (Partner == null)             //TODO: solo sex descriptions
            {
                isRape    = false;
                isWhoring = false;
                //sexType = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner);
            }
            else if (Partner.Dead)
            {
                isRape    = true;
                isWhoring = false;
                sexType   = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner);
            }
            else if (Partner.jobs?.curDriver is JobDriver_SexBaseReciever)
            {
                (Partner.jobs.curDriver as JobDriver_SexBaseReciever).parteners.AddDistinct(pawn);
                (Partner.jobs.curDriver as JobDriver_SexBaseReciever).increase_time(duration);

                //prevent Receiver standing up and interrupting rape
                if (Partner.health.hediffSet.HasHediff(HediffDef.Named("Hediff_Submitting")))
                {
                    Partner.health.AddHediff(HediffDef.Named("Hediff_Submitting"));
                }

                //(Target.jobs.curDriver as JobDriver_SexBaseReciever).parteners.Count; //TODO: add multipartner support so sex doesnt repeat, maybe, someday
                isRape    = Partner?.CurJob.def == xxx.gettin_raped;
                isWhoring = pawn?.CurJob.def == xxx.whore_is_serving_visitors;
                sexType   = SexUtility.DetermineSextype(pawn, Partner, isRape, isWhoring, Partner);
            }
            //Log.Message("sexType: " + sexType.ToString());
            //props = new SexProps(pawn, Partener, sexType, isRape);//maybe merge everything into this ?
        }
コード例 #5
0
        public override void NeedInterval()         //150 ticks between each calls from Pawn_NeedsTracker()
        {
            if (isInvisible)
            {
                return;                        // no caravans
            }
            if (needsex_tick <= 0)             // every 10 ticks - real tick
            {
                std_updater.update(pawn);

                if (xxx.is_asexual(pawn))
                {
                    CurLevel = 0.5f;
                    return;
                }

                //--Log.Message("[RJW]Need_Sex::NeedInterval is called0 - pawn is "+xxx.get_pawnname(pawn));
                needsex_tick = needsex_tick_timer;

                if (!def.freezeWhileSleeping || pawn.Awake())
                {
                    var fall_per_call = 150 * needsex_tick_timer * fall_per_tick(pawn);
                    CurLevel -= fall_per_call * xxx.get_sex_drive(pawn) * RJWSettings.sexneed_decay_rate;
                    // Each day has 60000 ticks, each hour has 2500 ticks, so each hour has 50/3 calls, in other words, each call takes .06 hour.

                    //Log.Message("[RJW] " + xxx.get_pawnname(pawn) + "'s sex need stats:: Decay/call: " + fall_per_call * decay_rate_modifier * xxx.get_sex_drive(pawn) + ", Cur.lvl: " + CurLevel + ", Dec. rate: " + decay_rate_modifier + ", Sex drive: " +  xxx.get_sex_drive(pawn));

                    if (CurLevel < thresh_horny())
                    {
                        SexUtility.OffsetPsyfocus(pawn, -0.01f);
                    }
                    if (CurLevel < thresh_frustrated() || CurLevel > thresh_ahegao())
                    {
                        SexUtility.OffsetPsyfocus(pawn, -0.05f);
                    }
                }

                //--Log.Message("[RJW]Need_Sex::NeedInterval is called1");

                //If they need it, they should seek it
                if (CurLevel < thresh_horny() && (pawn.mindState.canLovinTick - Find.TickManager.TicksGame > 300))
                {
                    pawn.mindState.canLovinTick = Find.TickManager.TicksGame + 300;
                }

                // the bootstrap of the mapInjector will only be triggered once per visible pawn.
                if (!BootStrapTriggered)
                {
                    //--Log.Message("[RJW]Need_Sex::NeedInterval::calling boostrap - pawn is " + xxx.get_pawnname(pawn));
                    xxx.bootstrap(pawn.Map);
                    BootStrapTriggered = true;
                }
            }
            else
            {
                needsex_tick--;
            }
            //--Log.Message("[RJW]Need_Sex::NeedInterval is called2 - needsex_tick is "+needsex_tick);
        }
コード例 #6
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //this.FailOn(() => PawnUtility.PlayerForcedJobNowOrSoon(pawn));
            this.FailOn(() => pawn.health.Downed);
            this.FailOn(() => pawn.IsBurning());
            this.FailOn(() => pawn.IsFighting());
            this.FailOn(() => pawn.Drafted);

            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            // Faster fapping when frustrated.
            ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f));

            Toil findfapspot = new Toil
            {
                initAction = delegate
                {
                    pawn.pather.StartPath(cell, PathEndMode.OnCell);
                },
                defaultCompleteMode = ToilCompleteMode.PatherArrival
            };

            yield return(findfapspot);

            //Log.Message("[RJW] Making new toil for QuickFap.");

            Toil fap = Toils_General.Wait(ticks_left);

            fap.tickAction = delegate
            {
                --ticks_left;
                xxx.reduce_rest(pawn, 1);
                if (ticks_left <= 0)
                {
                    ReadyForNextToil();
                }
                else if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
            };
            fap.AddFinishAction(delegate
            {
                SexUtility.Aftersex(pawn, xxx.rjwSextype.Masturbation);
                if (!SexUtility.ConsiderCleaning(pawn))
                {
                    return;
                }

                LocalTargetInfo own_cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map);

                Job clean = new Job(JobDefOf.Clean);
                clean.AddQueuedTarget(TargetIndex.A, own_cum);

                pawn.jobs.jobQueue.EnqueueFirst(clean);
            });
            yield return(fap);
        }
コード例 #7
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //--Log.Message("JobDriver_JoinInBed::MakeNewToils() called");
            this.FailOnDespawnedOrNull(ipartner);
            this.FailOnDespawnedOrNull(ibed);
            this.FailOn(() => !Partner.health.capacities.CanBeAwake);
            this.FailOn(() => !(Partner.InBed() || xxx.in_same_bed(Partner, Top)));
            this.FailOn(() => pawn.Drafted);
            yield return(Toils_Reserve.Reserve(ipartner, xxx.max_rapists_per_prisoner, 0));

            yield return(Toils_Goto.GotoThing(ipartner, PathEndMode.OnCell));

            yield return(new Toil
            {
                initAction = delegate
                {
                    //--Log.Message("JobDriver_JoinInBed::MakeNewToils() - setting initAction");
                    //Rand.PopState();
                    //Rand.PushState(RJW_Multiplayer.PredictableSeed());
                    ticks_left = (int)(2500.0f * Rand.Range(0.30f, 1.30f));
                    Job gettin_loved = new Job(xxx.gettin_loved, Top, Bed);
                    Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });

            Toil do_lovin = new Toil {
                defaultCompleteMode = ToilCompleteMode.Never
            };

            do_lovin.FailOn(() => (Partner.CurJob == null) || (Partner.CurJob.def != xxx.gettin_loved));
            do_lovin.AddPreTickAction(delegate
            {
                --ticks_left;
                xxx.reduce_rest(Partner, 1);
                xxx.reduce_rest(Top, 2);
                if (ticks_left <= 0)
                {
                    ReadyForNextToil();
                }
                else if (Top.IsHashIntervalTick(ticks_between_hearts))
                {
                    MoteMaker.ThrowMetaIcon(Top.Position, Top.Map, ThingDefOf.Mote_Heart);
                }
            });
            do_lovin.socialMode = RandomSocialMode.Off;
            yield return(do_lovin);

            yield return(new Toil
            {
                initAction = delegate
                {
                    // Trying to add some interactions and social logs
                    SexUtility.ProcessSex(Top, Partner, false /*rape*/, false /*isCoreLovin*/, false /*whoring*/);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #8
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            //Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called0");

            if (!RJWSettings.WildMode)
            {
                // don't allow pawns marked as comfort prisoners to rape others
                if (!xxx.is_healthy(pawn) || pawn.IsDesignatedComfort() || (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn)))
                {
                    return(null);
                }
            }

            if (pawn.Drafted)
            {
                return(null);
            }

            //Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called1");
            if (!xxx.can_rape(pawn))
            {
                return(null);
            }

            // It's unnecessary to include other job checks. Pawns seem to only look for new jobs when between jobs or layind down idle.
            if (!(pawn.jobs.curJob == null || pawn.jobs.curJob.def == JobDefOf.LayDown))
            {
                return(null);
            }

            //--Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called2");
            // Faction check.
            if (!(pawn.Faction?.IsPlayer ?? false) && !pawn.IsPrisonerOfColony)
            {
                return(null);
            }

            Pawn target = find_prisoner_to_rape(pawn, pawn.Map);

            //--Log.Message("[RJW] JobGiver_ComfortPrisonerRape::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called3 - (" + ((target == null) ? "no target found" : xxx.get_pawnname(target))+") is the prisoner");

            if (target == null)
            {
                return(null);
            }

            //Log.Message("giving job to " + pawner + " with target " + target);
            if (xxx.is_animal(target))
            {
                return(new Job(xxx.bestiality, target));
            }
            else
            {
                return(new Job(xxx.comfort_prisoner_rapin, target));
            }
        }
コード例 #9
0
        public static void sexualize_pawn(Pawn pawn)
        {
            //Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) called");
            if (pawn == null)
            {
                return;
            }

            if (RaceGroupDef_Helper.TryGetRaceGroupDef(pawn, out var raceGroupDef) &&
                raceGroupDef.hasSingleGender)
            {
                Log.Message($"[RJW] sexualize_pawn() - sexualizing single gender pawn {xxx.get_pawnname(pawn)}  race: {raceGroupDef.defName}");
                SexualizeSingleGenderPawn(pawn);
            }
            else if (pawn.RaceProps.hasGenders)
            {
                SexualizeGenderedPawn(pawn);
            }
            else
            {
                if (Current.ProgramState == ProgramState.Playing)                 // DO NOT run at world generation, throws error in generating relationship stuff
                {
                    SexulaizeGenderlessPawn(pawn);
                    return;
                }
            }

            if (!pawn.Dead)
            {
                //Add ticks at generation, so pawns don't instantly start lovin' when generated (esp. on scenario start).
                //if (xxx.RoMIsActive && pawn.health.hediffSet.HasHediff(HediffDef.Named("TM_ShapeshiftHD"))) // Rimworld of Magic's polymorph/shapeshift
                //	pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.05f));
                if (!xxx.is_insect(pawn))
                {
                    pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.1f, 1.0f));
                }
                else
                {
                    pawn.mindState.canLovinTick = Find.TickManager.TicksGame + (int)(SexUtility.GenerateMinTicksToNextLovin(pawn) * Rand.Range(0.01f, 0.2f));
                }

                //Log.Message("[RJW] sexualize_pawn( " + xxx.get_pawnname(pawn) + " ) add sexneed");
                if (pawn.RaceProps.Humanlike)
                {
                    var sex_need = pawn.needs.TryGetNeed <Need_Sex>();
                    if (pawn.Faction != null && !(pawn.Faction?.IsPlayer ?? false) && sex_need != null)
                    {
                        sex_need.CurLevel = Rand.Range(0.01f, 0.75f);
                    }
                }
            }
        }
コード例 #10
0
        /// <summary>
        /// handle Psyfocus
        /// </summary>
        public void ChangePsyfocus(Pawn pawn, Thing target)
        {
            if (pawn.jobs?.curDriver is JobDriver_ViolateCorpse)
            {
                if (xxx.is_necrophiliac(pawn) && MeditationFocusTypeAvailabilityCache.PawnCanUse(pawn, DefDatabase <MeditationFocusDef> .GetNamedSilentFail("Morbid")))
                {
                    SexUtility.OffsetPsyfocus(pawn, 0.01f);
                }
            }

            if (target != null)
            {
                var partner = target as Pawn;
                if (partner != null)
                {
                    if (xxx.is_nympho(pawn))
                    {
                        SexUtility.OffsetPsyfocus(pawn, 0.01f);
                    }
                    else if (xxx.is_zoophile(pawn) && xxx.is_animal(partner) && MeditationFocusTypeAvailabilityCache.PawnCanUse(pawn, MeditationFocusDefOf.Natural))
                    {
                        SexUtility.OffsetPsyfocus(pawn, 0.01f);
                    }

                    if (xxx.is_nympho(partner))
                    {
                        SexUtility.OffsetPsyfocus(partner, 0.01f);
                    }
                    else if (xxx.is_zoophile(partner) && xxx.is_animal(pawn) && MeditationFocusTypeAvailabilityCache.PawnCanUse(partner, MeditationFocusDefOf.Natural))
                    {
                        SexUtility.OffsetPsyfocus(partner, 0.01f);
                    }

                    if (xxx.RoMIsActive)
                    {
                        if (pawn.story.traits.HasTrait(TraitDef.Named("Succubus")))
                        {
                            SexUtility.OffsetPsyfocus(pawn, 0.01f);
                        }

                        if (partner.story.traits.HasTrait(TraitDef.Named("Succubus")))
                        {
                            SexUtility.OffsetPsyfocus(partner, 0.01f);
                        }
                    }
                }
            }
        }
コード例 #11
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            // Faster fapping when frustrated.
            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            ticks_left = (int)(xxx.need_some_sex(pawn) > 2f ? 2500.0f * Rand.Range(0.2f, 0.7f) : 2500.0f * Rand.Range(0.2f, 0.4f));

            this.FailOnDespawnedOrNull(ibed);
            this.FailOn(() => pawn.Drafted);
            this.KeepLyingDown(ibed);
            yield return(Toils_Bed.ClaimBedIfNonMedical(ibed));

            yield return(Toils_Bed.GotoBed(ibed));

            Toil do_fappin = Toils_LayDown.LayDown(ibed, true, false, false, false);

            do_fappin.AddPreTickAction(delegate
            {
                --ticks_left;
                xxx.reduce_rest(pawn, 1);
                if (ticks_left <= 0)
                {
                    ReadyForNextToil();
                }
                else if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
            });
            do_fappin.AddFinishAction(delegate
            {
                //Moved satisfy and tick increase to aftersex, since it works with solo acts now.
                SexUtility.Aftersex(pawn, xxx.rjwSextype.Masturbation);
                if (SexUtility.ConsiderCleaning(pawn))
                {
                    LocalTargetInfo own_cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map);

                    Job clean = new Job(JobDefOf.Clean);
                    clean.AddQueuedTarget(TargetIndex.A, own_cum);

                    pawn.jobs.jobQueue.EnqueueFirst(clean);
                }
            });
            do_fappin.socialMode = RandomSocialMode.Off;
            yield return(do_fappin);
        }
コード例 #12
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            // Most things are now checked in the ThinkNode_ConditionalWhore.

            if (pawn.Drafted)
            {
                return(null);
            }
            if (MP.IsInMultiplayer)
            {
                return(null);                                //fix error someday, maybe
            }
            //Log.Message("[RJW] JobGiver_WhoreInvitingVisitors::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called");
            if (!SexUtility.ReadyForLovin(pawn))
            {
                //W****s need rest too, but this'll reduxe the wait a bit every it triggers.
                pawn.mindState.canLovinTick -= 40;
                return(null);
            }

            Building_Bed whorebed = xxx.FindBed(pawn);

            if (whorebed == null || !xxx.CanUse(pawn, whorebed))
            {
                return(null);
            }

            int  price;
            Pawn client = FindAttractivePawn(pawn, out price);

            if (client == null)
            {
                return(null);
            }

            if (!client.CanReach(whorebed, PathEndMode.OnCell, Danger.Some))
            {
                return(null);
            }
            //Log.Message("[RJW] JobGiver_WhoreInvitingVisitors::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) is w***e, " + xxx.get_pawnname(client) + " is client.");
            //whorebed.priceOfWhore = price;
            return(new Job(xxx.whore_inviting_visitors, client, whorebed));
        }
コード例 #13
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            if (pawn.Drafted)
            {
                return(null);
            }

            // Most checks are now done in ThinkNode_ConditionalBestiality
            DebugText("[RJW] JobGiver_Bestiality::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called");

            if (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn))
            {
                return(null);
            }

            Pawn target = BreederHelper.find_breeder_animal(pawn, pawn.Map);

            DebugText("[RJW] JobGiver_Bestiality::TryGiveJob - target is " + (target == null ? "no target found" : xxx.get_pawnname(target)));

            if (target == null)
            {
                return(null);
            }

            if (xxx.can_rape(pawn))
            {
                return(new Job(xxx.bestiality, target));
            }

            Building_Bed bed = pawn.ownership.OwnedBed;

            if (!xxx.can_be_fucked(pawn) || bed == null || !target.CanReach(bed, PathEndMode.OnCell, Danger.Some) || target.Downed)
            {
                return(null);
            }

            // TODO: Should rename this to BestialityInBed or somesuch, since it's not limited to females.
            return(new Job(xxx.bestialityForFemale, target, bed, bed.SleepPosOfAssignedPawn(pawn)));
        }
コード例 #14
0
        protected override Job TryGiveJob(Pawn animal)
        {
            //Log.Message("[RJW] JobGiver_Breed::TryGiveJob( " + xxx.get_pawnname(animal) + " ) called0" + (SexUtility.ReadyForLovin(animal)));

            if (!SexUtility.ReadyForLovin(animal))
            {
                return(null);
            }

            if (xxx.is_healthy(animal) && xxx.can_rape(animal))
            {
                //search for desiganted target to sex
                if (animal.IsDesignatedBreedingAnimal())
                {
                    Pawn designated_target = BreederHelper.find_designated_breeder(animal, animal.Map);
                    if (designated_target != null)
                    {
                        return(JobMaker.MakeJob(xxx.animalBreed, designated_target));
                    }
                }
            }
            return(null);
        }
コード例 #15
0
        //roll how much gender fluid the pawn is.
        //In ideal world this would actually take into account from where to where transition is moving and so on.
        //Same applies to the thought hediffs themselves, but we get what we can get now
        static float RollSexChangeSeverity(Pawn pawn)
        {
            float res = 1;

            if (xxx.is_bisexual(pawn))
            {
                res *= 0.5f;
            }
            if (pawn.story != null && (pawn.story.bodyType == BodyTypeDefOf.Thin || pawn.story.bodyType == BodyTypeDefOf.Fat))
            {
                res *= 0.8f;
            }
            if (!pawn.ageTracker.CurLifeStage.reproductive)
            {
                res *= 0.2f;
            }
            else
            {
                res *= rigidity_from_age.Evaluate(SexUtility.ScaleToHumanAge(pawn));
            }

            return(res);
        }
コード例 #16
0
        public void SexTick(Pawn pawn, Thing target, bool pawnnude = true, bool partnernude = true)
        {
            var partner = target as Pawn;

            if (pawn.IsHashIntervalTick(ticks_between_thrusts))
            {
                ChangePsyfocus(pawn, partner);
                Animate(pawn, partner);
                PlaySexSound();
                if (!isRape)
                {
                    pawn.GainComfortFromCellIfPossible();
                    if (partner != null)
                    {
                        partner.GainComfortFromCellIfPossible();
                    }
                }
            }

            //refresh DrawNude after beating and Notify_MeleeAttackOn
            // Endytophiles prefer clothed sex, everyone else gets nude.
            if (!xxx.has_quirk(pawn, "Endytophile"))
            {
                if (pawnnude)
                {
                    SexUtility.DrawNude(pawn);
                }

                if (partner != null)
                {
                    if (partnernude)
                    {
                        SexUtility.DrawNude(partner);
                    }
                }
            }
        }
コード例 #17
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            if (pawn.Drafted)
            {
                return(null);
            }

            // Most checks are now done in ThinkNode_ConditionalBestiality

            if (!SexUtility.ReadyForLovin(pawn) && !xxx.is_frustrated(pawn))
            {
                return(null);
            }

            Pawn target = BreederHelper.find_breeder_animal(pawn, pawn.Map);

            if (target == null)
            {
                return(null);
            }

            if (xxx.can_rape(pawn))
            {
                return(JobMaker.MakeJob(xxx.bestiality, target));
            }

            Building_Bed bed = pawn.ownership.OwnedBed;

            if (!xxx.can_be_fucked(pawn) || bed == null || !target.CanReach(bed, PathEndMode.OnCell, Danger.Some) || target.Downed)
            {
                return(null);
            }

            // TODO: Should rename this to BestialityInBed or somesuch, since it's not limited to females.
            return(JobMaker.MakeJob(xxx.bestialityForFemale, target, bed));
        }
コード例 #18
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            // Most things are now checked in the ThinkNode_ConditionalWhore.

            if (pawn.Drafted)
            {
                return(null);
            }
            if (MP.IsInMultiplayer)
            {
                return(null);                                //fix error someday, maybe
            }
            if (!SexUtility.ReadyForLovin(pawn))
            {
                //W****s need rest too, but this'll reduxe the wait a bit every it triggers.
                pawn.mindState.canLovinTick -= 40;
                return(null);
            }

            if (RJWSettings.DebugWhoring)
            {
                Log.Message($"[RJW] JobGiver_WhoreInvitingVisitors.TryGiveJob:({xxx.get_pawnname(pawn)})");
            }
            Building_Bed whorebed = xxx.FindBed(pawn);

            if (whorebed == null || !xxx.CanUse(pawn, whorebed))
            {
                if (RJWSettings.DebugWhoring)
                {
                    Log.Message($" {xxx.get_pawnname(pawn)} has no bed or can use it");
                }
                return(null);
            }

            int  price;
            Pawn client = FindAttractivePawn(pawn, out price);

            if (client == null)
            {
                if (RJWSettings.DebugWhoring)
                {
                    Log.Message($" no clients found");
                }
                return(null);
            }

            if (RJWSettings.DebugWhoring)
            {
                Log.Message($" {xxx.get_pawnname(client)} is client");
            }

            if (!client.CanReach(whorebed, PathEndMode.OnCell, Danger.Some))
            {
                if (RJWSettings.DebugWhoring)
                {
                    Log.Message($" {xxx.get_pawnname(client)} cant reach bed");
                }
                return(null);
            }
            //whorebed.priceOfWhore = price;
            return(JobMaker.MakeJob(xxx.whore_inviting_visitors, client, whorebed));
        }
コード例 #19
0
        public static void Doimpregnate(Pawn pawn, Pawn partner)
        {
            if (RJWSettings.DevMode)
            {
                Log.Message("[RJW] Doimpregnate " + xxx.get_pawnname(pawn) + " is a father, " + xxx.get_pawnname(partner) + " is a mother");
            }

            if (AndroidsCompatibility.IsAndroid(pawn) && !AndroidsCompatibility.AndroidPenisFertility(pawn))
            {
                if (RJWSettings.DevMode)
                {
                    Log.Message(" Father is android with no arcotech penis, abort");
                }
                return;
            }
            if (AndroidsCompatibility.IsAndroid(partner) && !AndroidsCompatibility.AndroidVaginaFertility(partner))
            {
                if (RJWSettings.DevMode)
                {
                    Log.Message(" Mother is android with no arcotech v****a, abort");
                }
                return;
            }

            // fertility check
            float fertility = RJWPregnancySettings.humanlike_impregnation_chance / 100f;

            if (xxx.is_animal(partner))
            {
                fertility = RJWPregnancySettings.animal_impregnation_chance / 100f;
            }

            // Interspecies modifier
            if (pawn.def.defName != partner.def.defName)
            {
                if (RJWPregnancySettings.complex_interspecies)
                {
                    fertility *= SexUtility.BodySimilarity(pawn, partner);
                }
                else
                {
                    fertility *= RJWPregnancySettings.interspecies_impregnation_modifier;
                }
            }

            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            float          ReproductionFactor   = Math.Min(pawn.health.capacities.GetLevel(xxx.reproduction), partner.health.capacities.GetLevel(xxx.reproduction));
            float          pregnancy_threshold  = fertility * ReproductionFactor;
            float          non_pregnancy_chance = Rand.Value;
            BodyPartRecord torso = partner.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Torso);

            if (non_pregnancy_chance > pregnancy_threshold || pregnancy_threshold == 0)
            {
                if (RJWSettings.DevMode)
                {
                    Log.Message(" Impregnation failed. Chance: " + pregnancy_threshold.ToStringPercent() + " roll: " + non_pregnancy_chance.ToStringPercent());
                }
                return;
            }
            if (RJWSettings.DevMode)
            {
                Log.Message(" Impregnation succeeded. Chance: " + pregnancy_threshold.ToStringPercent() + " roll: " + non_pregnancy_chance.ToStringPercent());
            }

            PregnancyDecider(partner, pawn);
        }
コード例 #20
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - making toils");
            this.FailOnDespawnedOrNull(PartnerInd);
            this.FailOnDespawnedNullOrForbidden(BedInd);
            //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() fail conditions check " + (Actor is null) + " " + !xxx.CanUse(Actor, Bed) + " " + !Actor.CanReserve(Partner));
            this.FailOn(() => Actor is null || !xxx.CanUse(Actor, Bed) || !Actor.CanReserve(Partner));
            this.FailOn(() => pawn.Drafted);
            int price = WhoringHelper.PriceOfWhore(Actor);

            yield return(Toils_Reserve.Reserve(PartnerInd, 1, 0));

            //yield return Toils_Reserve.Reserve(BedInd, Bed.SleepingSlotsCount, 0);
            bool partnerHasPenis = Genital_Helper.has_penis(Partner) || Genital_Helper.has_penis_infertile(Partner);

            Toil gotoWhoreBed = new Toil
            {
                initAction = delegate
                {
                    //Log.Message("[RJW]JobDriver_WhoreIsServingVisitors::MakeNewToils() - gotoWhoreBed initAction is called");
                    Actor.pather.StartPath(WhoreSleepSpot, PathEndMode.OnCell);
                    Partner.jobs.StopAll();
                    Partner.pather.StartPath(WhoreSleepSpot, PathEndMode.Touch);
                },
                tickAction = delegate
                {
                    if (Partner.IsHashIntervalTick(150))
                    {
                        Partner.pather.StartPath(Actor, PathEndMode.Touch);
                        //Log.Message(xxx.get_pawnname(Partner) + ": I'm following the w***e");
                    }
                },
                defaultCompleteMode = ToilCompleteMode.PatherArrival
            };

            gotoWhoreBed.FailOnWhorebedNoLongerUsable(BedInd, Bed);
            yield return(gotoWhoreBed);

            Toil waitInBed = new Toil
            {
                initAction = delegate
                {
                    //Rand.PopState();
                    //Rand.PushState(RJW_Multiplayer.PredictableSeed());
                    //Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - waitInBed, initAction is called");
                    ticksLeftThisToil = 5000;
                    ticks_left        = (int)(2000.0f * Rand.Range(0.30f, 1.30f));
                    //Actor.pather.StopDead();  //Let's just make w****s standing at the bed
                    //JobDriver curDriver = Actor.jobs.curDriver;
                    //curDriver.layingDown = LayingDownState.LayingInBed;
                    //curDriver.asleep = false;
                    var gettin_loved = new Job(xxx.gettin_loved, Actor, Bed);
                    Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced);
                },
                tickAction = delegate
                {
                    Actor.GainComfortFromCellIfPossible();
                    if (IsInOrByBed(Bed, Partner))
                    {
                        //Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - waitInBed, tickAction pass");
                        ticksLeftThisToil = 0;
                    }
                },
                defaultCompleteMode = ToilCompleteMode.Delay,
            };

            waitInBed.FailOn(() => pawn.GetRoom() == null);
            yield return(waitInBed);

            bool canAfford = WhoringHelper.CanAfford(Partner, Actor, price);

            if (canAfford)
            {
                Toil loveToil = new Toil
                {
                    initAction = delegate
                    {
                        //Actor.jobs.curDriver.ticksLeftThisToil = 1200;
                        //Using ticks_left to control the time of sex
                        //--Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - loveToil, setting initAction");

                        /*
                         * //Hoge: W***e is just work. no feel cheatedOnMe.
                         * if (xxx.HasNonPolyPartner(Actor))
                         * {
                         *      Pawn pawn = LovePartnerRelationUtility.ExistingLovePartner(Actor);
                         *      if (((Partner != pawn) && !pawn.Dead) && ((pawn.Map == Actor.Map) || (Rand.Value < 0.15)))
                         *      {
                         *              pawn.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Actor);
                         *      }
                         * }
                         */
                        if (xxx.HasNonPolyPartnerOnCurrentMap(Partner))
                        {
                            Pawn lover = LovePartnerRelationUtility.ExistingLovePartner(Partner);
                            //Rand.PopState();
                            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
                            // We have to do a few other checks because the pawn might have multiple lovers and ExistingLovePartner() might return the wrong one
                            if (lover != null && Actor != lover && !lover.Dead && (lover.Map == Partner.Map || Rand.Value < 0.25))
                            {
                                lover.needs.mood.thoughts.memories.TryGainMemory(ThoughtDefOf.CheatedOnMe, Partner);
                            }
                        }
                        if (!partnerHasPenis)
                        {
                            Actor.rotationTracker.Face(Partner.DrawPos);
                        }
                    },
                    defaultCompleteMode = ToilCompleteMode.Never,                     //Changed from Delay
                };
                loveToil.AddPreTickAction(delegate
                {
                    //Actor.Reserve(Partner, 1, 0);
                    --ticks_left;
                    xxx.reduce_rest(Partner);
                    xxx.reduce_rest(Actor, 2);

                    if (ticks_left <= 0)
                    {
                        ReadyForNextToil();
                    }
                    else if (pawn.IsHashIntervalTick(ticks_between_hearts))
                    {
                        MoteMaker.ThrowMetaIcon(Actor.Position, Actor.Map, ThingDefOf.Mote_Heart);
                    }
                    Actor.GainComfortFromCellIfPossible();
                    Partner.GainComfortFromCellIfPossible();
                });
                loveToil.AddFinishAction(delegate
                {
                    //Log.Message("[RJW] JobDriver_WhoreIsServingVisitors::MakeNewToils() - finished loveToil");
                    //// Trying to add some interactions and social logs
                    //xxx.processAnalSex(Partner, Actor, ref isAnalSex, partnerHasPenis);
                });
                loveToil.AddFailCondition(() => Partner.Dead || !IsInOrByBed(Bed, Partner));
                loveToil.socialMode = RandomSocialMode.Off;
                yield return(loveToil);

                Toil afterSex = new Toil
                {
                    initAction = delegate
                    {
                        // Adding interactions, social logs, etc
                        SexUtility.ProcessSex(Actor, Partner, false, false, true);

                        //--Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Partner should pay the price now in afterSex.initAction");
                        int remainPrice = WhoringHelper.PayPriceToWhore(Partner, price, Actor);

                        /*if (remainPrice <= 0)
                         * {
                         *      --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price is success");
                         * }
                         * else
                         * {
                         *      --Log.Message("JobDriver_WhoreIsServingVisitors::MakeNewToils() - Paying price failed");
                         * }*/
                        xxx.UpdateRecords(Actor, price - remainPrice);
                        var thought = (Actor.IsPrisoner) ? thought_captive : thought_free;
                        pawn.needs.mood.thoughts.memories.TryGainMemory(thought);
                        if (SexUtility.ConsiderCleaning(pawn))
                        {
                            LocalTargetInfo cum = pawn.PositionHeld.GetFirstThing <Filth>(pawn.Map);

                            Job clean = new Job(JobDefOf.Clean);
                            clean.AddQueuedTarget(TargetIndex.A, cum);

                            pawn.jobs.jobQueue.EnqueueFirst(clean);
                        }
                    },
                    defaultCompleteMode = ToilCompleteMode.Instant
                };
                yield return(afterSex);
            }
        }
コード例 #21
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            int duration              = (int)(2000.0f * Rand.Range(0.50f, 0.90f));
            int ticks_between_hearts  = Rand.RangeInclusive(70, 130);
            int ticks_between_hits    = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits);
            int ticks_between_thrusts = 100;

            //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - setting fail conditions");
            this.FailOnDespawnedNullOrForbidden(PartnerIndex);
            this.FailOn(() => !pawn.CanReserve(Target, BreederHelper.max_animals_at_once, 0));                                      // Fail if someone else reserves the target before the animal arrives.
            this.FailOn(() => !pawn.CanReach(Target, PathEndMode.Touch, Danger.Some));                                              // Fail if animal cannot reach target.
            this.FailOn(() => !(Target.IsDesignatedBreeding() || (RJWSettings.animal_on_animal_enabled && xxx.is_animal(Target)))); // Fail if not designated and not animal-on-animal
            this.FailOn(() => Target.CurJob == null);
            this.FailOn(() => pawn.Drafted);

            // Path to target
            yield return(Toils_Goto.GotoThing(PartnerIndex, PathEndMode.OnCell));

            SexUtility.RapeAttemptAlert(pawn, Target);

            // Breed target
            var breed = new Toil();

            breed.initAction = delegate
            {
                //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Setting victim job driver");
                Job currentJob = Target.jobs.curJob;

                if (currentJob.def != xxx.gettin_raped)
                {
                    Job          gettin_raped = new Job(xxx.gettin_raped, pawn, Target);
                    Building_Bed Bed          = null;
                    //Log.Message(xxx.get_pawnname(pawn) + " LayingInBed:" + pawn.GetPosture());
                    //Log.Message(xxx.get_pawnname(Target) + " LayingInBed:" + Target.GetPosture());
                    if (Target.GetPosture() == PawnPosture.LayingInBed)
                    {
                        Bed = Target.CurrentBed();
                        //Log.Message(xxx.get_pawnname(Target) + ": bed:" + Bed);
                    }

                    Target.jobs.StartJob(gettin_raped, JobCondition.InterruptForced);

                    //var dri = Target.jobs.curDriver as JobDriver_GettinRaped;
                    //if (xxx.is_animal(pawn) && xxx.is_animal(Target)) // No alert spam for animal-on-animal
                    //dri.disable_alert = true;

                    (Target.jobs.curDriver as JobDriver_GettinRaped).increase_time(duration);
                    if (Bed != null)
                    {
                        (Target.jobs.curDriver as JobDriver_GettinRaped)?.set_bed(Bed);
                    }
                }
                else
                {
                    if (Target.jobs.curDriver is JobDriver_GettinRaped dri)
                    {
                        dri.rapist_count += 1;
                        dri.increase_time(duration);
                    }
                }
            };

            breed.tickAction = delegate
            {
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
                if (pawn.IsHashIntervalTick(ticks_between_thrusts))
                {
                    xxx.sexTick(pawn, Target);
                }
                if (!xxx.is_zoophile(Target) && pawn.IsHashIntervalTick(ticks_between_hits))
                {
                    roll_to_hit(pawn, Target);
                }

                if (!Target.Dead)
                {
                    xxx.reduce_rest(Target, 1);
                }
                xxx.reduce_rest(pawn, 2);

                if (Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn))
                {
                    // Face same direction, most of animal sex is likely doggystyle.
                    Target.Rotation = pawn.Rotation;
                }
            };

            breed.AddFinishAction(delegate
            {
                if ((Target.jobs != null) &&
                    (Target.jobs.curDriver != null) &&
                    (Target.jobs.curDriver as JobDriver_GettinRaped != null))
                {
                    (Target.jobs.curDriver as JobDriver_GettinRaped).rapist_count -= 1;
                }
                pawn.stances.StaggerFor(Rand.Range(0, 50));
                Target.stances.StaggerFor(Rand.Range(10, 300));
            });

            breed.defaultCompleteMode = ToilCompleteMode.Delay;
            breed.defaultDuration     = duration;
            yield return(breed);

            yield return(new Toil
            {
                initAction = delegate
                {
                    //Log.Message("JobDriver_Breeding::MakeNewToils() - Calling aftersex");
                    //// Trying to add some interactions and social logs
                    bool violent = !(pawn.relations.DirectRelationExists(PawnRelationDefOf.Bond, Target) ||
                                     (xxx.is_animal(pawn) && (pawn.RaceProps.wildness - pawn.RaceProps.petness + 0.18f) > Rand.Range(0.36f, 1.8f)));
                    SexUtility.ProcessSex(pawn, Target, violent);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #22
0
        private static bool on_cleanup_driver(JobDriver __instance, JobCondition condition)
        {
            if (__instance == null)
            {
                return(true);
            }

            if (condition == JobCondition.Succeeded)
            {
                Pawn pawn    = __instance.pawn;
                Pawn partner = null;

                //Log.Message("[RJW]patches_lovin::on_cleanup_driver" + xxx.get_pawnname(pawn));

                //[RF] Rational Romance [1.0] loving
                if (xxx.RomanceDiversifiedIsActive && __instance.GetType() == JobDriverDoLovinCasual)
                {
                    // not sure RR can even cause pregnancies but w/e
                    var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                    partner = (Pawn)(__instance.GetType().GetProperty("Partner", any_ins).GetValue(__instance, null));
                    Log.Message("[RJW]patches_lovin::on_cleanup_driver RomanceDiversified/RationalRomance:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner));
                }
                //Vanilla loving
                else if (__instance.GetType() == JobDriverLovin)
                {
                    var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                    partner = (Pawn)(__instance.GetType().GetProperty("Partner", any_ins).GetValue(__instance, null));
                    //CnP loving
                    if (xxx.RimWorldChildrenIsActive && RJWPregnancySettings.humanlike_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_human(partner))
                    {
                        Log.Message("[RJW]patches_lovin:: RimWorldChildren/ChildrenAndPregnancy pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner));
                        PregnancyHelper.cleanup_CnP(pawn);
                        PregnancyHelper.cleanup_CnP(partner);
                    }
                    else
                    {
                        Log.Message("[RJW]patches_lovin:: JobDriverLovin pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner));
                    }
                }
                //Vanilla mating
                else if (__instance.GetType() == JobDriverMate)
                {
                    var any_ins = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
                    partner = (Pawn)(__instance.GetType().GetProperty("Female", any_ins).GetValue(__instance, null));
                    Log.Message("[RJW]patches_lovin:: JobDriverMate pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner));
                }
                else
                {
                    return(true);
                }

                // TODO: Doing TryUseCondom here is a bit weird... it should happen before.
                var usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(partner);

                //vanilla will probably be f****d up for non humanlikes... but only humanlikes do loving, right?
                //if rjw pregnancy enabled, remove vanilla for:
                //human-human
                //animal-animal
                //bestiality
                //always remove when someone is insect or mech
                if (RJWPregnancySettings.humanlike_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_human(partner) ||
                    RJWPregnancySettings.animal_pregnancy_enabled && xxx.is_animal(pawn) && xxx.is_animal(partner) ||
                    (RJWPregnancySettings.bestial_pregnancy_enabled && xxx.is_human(pawn) && xxx.is_animal(partner) ||
                     RJWPregnancySettings.bestial_pregnancy_enabled && xxx.is_animal(pawn) && xxx.is_human(partner)) ||
                    xxx.is_insect(pawn) || xxx.is_insect(partner) || xxx.is_mechanoid(pawn) || xxx.is_mechanoid(partner)
                    )
                {
                    Log.Message("[RJW]patches_lovin::on_cleanup_driver vanilla pregnancy:" + xxx.get_pawnname(pawn) + "+" + xxx.get_pawnname(partner));
                    PregnancyHelper.cleanup_vanilla(pawn);
                    PregnancyHelper.cleanup_vanilla(partner);
                }

                SexUtility.ProcessSex(pawn, partner, usedCondom, false, true);
            }
            return(true);
        }
コード例 #23
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called");
            setup_ticks();

            this.FailOnDespawnedNullOrForbidden(iTarget);
            this.FailOn(() => !pawn.CanReserve(Partner, xxx.max_rapists_per_prisoner, 0));             // Fail if someone else reserves the prisoner before the pawn arrives
            this.FailOn(() => pawn.IsFighting());
            this.FailOn(() => Partner.IsFighting());
            this.FailOn(() => pawn.Drafted);
            yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell));

            SexUtility.RapeTargetAlert(pawn, Partner);

            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_raped = JobMaker.MakeJob(xxx.gettin_raped, pawn);
                    Building_Bed Bed          = null;
                    if (Partner.GetPosture() == PawnPosture.LayingInBed)
                    {
                        Bed = Partner.CurrentBed();
                    }

                    Partner.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null);
                    if (Bed != null)
                    {
                        (Partner.jobs.curDriver as JobDriver_SexBaseRecieverRaped)?.Set_bed(Bed);
                    }
                }
            };
            yield return(StartPartnerJob);

            var rape = new Toil();

            rape.FailOn(() => Partner.CurJob == null || Partner.CurJob.def != xxx.gettin_raped || Partner.IsFighting() || pawn.IsFighting());
            rape.defaultCompleteMode = ToilCompleteMode.Delay;
            rape.defaultDuration     = duration;
            rape.handlingFacing      = true;
            rape.initAction          = delegate
            {
                Start();
            };
            rape.tickAction = delegate
            {
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
                if (pawn.IsHashIntervalTick(ticks_between_hits))
                {
                    Roll_to_hit(pawn, Partner);
                }
                SexTick(pawn, Partner);
                SexUtility.reduce_rest(Partner, 1);
                SexUtility.reduce_rest(pawn, 2);
            };
            rape.AddFinishAction(delegate
            {
                End();
            });
            yield return(rape);

            yield return(new Toil
            {
                initAction = delegate
                {
                    //// Trying to add some interactions and social logs
                    SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, sextype: sexType);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #24
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) called0");
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 0 " + SexUtility.ReadyForLovin(pawn));
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 1 " + (xxx.need_some_sex(pawn) <= 1f));
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 2 " + !(SexUtility.ReadyForLovin(pawn) || xxx.need_some_sex(pawn) <= 1f));
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 1 " + Find.TickManager.TicksGame);
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) 2 " + pawn.mindState.canLovinTick);

            if (pawn.Drafted)
            {
                return(null);
            }

            if (pawn.health.hediffSet.HasHediff(HediffDef.Named("Hediff_RapeEnemyCD")) || !pawn.health.capacities.CanBeAwake || !(SexUtility.ReadyForLovin(pawn) || xxx.need_some_sex(pawn) <= 1f))
            {
                //if (pawn.health.hediffSet.HasHediff(HediffDef.Named("Hediff_RapeEnemyCD")) || !pawn.health.capacities.CanBeAwake || (SexUtility.ReadyForLovin(pawn) || xxx.is_human(pawn) ? xxx.need_some_sex(pawn) <= 1f : false))
                return(null);
            }

            if (!xxx.can_rape(pawn))
            {
                return(null);
            }
            //Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) can rape");

            JobDef_RapeEnemy rapeEnemyJobDef = null;
            int?highestPriority = null;

            foreach (JobDef_RapeEnemy job in DefDatabase <JobDef_RapeEnemy> .AllDefs)
            {
                if (job.CanUseThisJobForPawn(pawn))
                {
                    if (highestPriority == null)
                    {
                        rapeEnemyJobDef = job;
                        highestPriority = job.priority;
                    }
                    else if (job.priority > highestPriority)
                    {
                        rapeEnemyJobDef = job;
                        highestPriority = job.priority;
                    }
                }
            }

            //Log.Message("[RJW] JobGiver_RapeEnemy::ChoosedJobDef( " + xxx.get_pawnname(pawn) + " ) - " + rapeEnemyJobDef.ToString() + " choosed");
            Pawn victim = rapeEnemyJobDef?.FindVictim(pawn, pawn.Map);

            //Log.Message("[RJW] JobGiver_RapeEnemy::FoundVictim( " + xxx.get_pawnname(victim) + " )");

            //prevents 10 job stacks error, no idea whats the prob with JobDriver_Rape
            //if (victim != null)
            pawn.health.AddHediff(HediffDef.Named("Hediff_RapeEnemyCD"), null, null, null);

            return(victim != null ? new Job(rapeEnemyJobDef, victim) : null);

            /*
             * else
             * {
             *      //--Log.Message("[RJW]" + this.GetType().ToString() + "::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) - unable to find victim");
             *      pawn.mindState.canLovinTick = Find.TickManager.TicksGame + Rand.Range(75, 150);
             * }
             */
            //else {  //--Log.Message("[RJW] JobGiver_RapeEnemy::TryGiveJob( " + xxx.get_pawnname(pawn) + " ) - too fast to play next"); }
        }
コード例 #25
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            duration              = (int)(2000.0f * Rand.Range(0.50f, 0.90f));
            ticks_between_hearts  = Rand.RangeInclusive(70, 130);
            ticks_between_hits    = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits);
            ticks_between_thrusts = 100;
            bool pawnHasPenis = Genital_Helper.has_penis(pawn) || Genital_Helper.has_penis_infertile(pawn);

            if (xxx.is_bloodlust(pawn))
            {
                ticks_between_hits = (int)(ticks_between_hits * 0.75);
            }
            if (xxx.is_brawler(pawn))
            {
                ticks_between_hits = (int)(ticks_between_hits * 0.90);
            }

            //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - setting fail conditions");
            this.FailOnDespawnedNullOrForbidden(iprisoner);
            //this.FailOn(() => (!Target.health.capacities.CanBeAwake) || (!comfort_prisoners.is_designated(Target)));//this is wrong
            this.FailOn(() => (!Target.IsDesignatedComfort()));
            this.FailOn(() => !pawn.CanReserve(Target, xxx.max_rapists_per_prisoner, 0));             // Fail if someone else reserves the prisoner before the pawn arrives
            this.FailOn(() => pawn.Drafted);
            yield return(Toils_Goto.GotoThing(iprisoner, PathEndMode.OnCell));

            SexUtility.RapeAttemptAlert(pawn, Target);

            Toil rape = new Toil();

            rape.initAction = delegate
            {
                //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - reserving prisoner");
                //pawn.Reserve(Target, comfort_prisoners.max_rapists_per_prisoner, 0);
                if (!pawnHasPenis)
                {
                    Target.rotationTracker.Face(pawn.DrawPos);
                }

                //--Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Setting victim job driver");
                JobDriver_GettinRaped dri = Target.jobs.curDriver as JobDriver_GettinRaped;
                if (dri == null)
                {
                    Job          gettin_raped = new Job(xxx.gettin_raped, pawn, Target);
                    Building_Bed Bed          = null;
                    //Log.Message(xxx.get_pawnname(pawn) + " LayingInBed:" + pawn.GetPosture());
                    //Log.Message(xxx.get_pawnname(Target) + " LayingInBed:" + Target.GetPosture());
                    if (Target.GetPosture() == PawnPosture.LayingInBed)
                    {
                        Bed = Target.CurrentBed();
                        //Log.Message(xxx.get_pawnname(Target) + ": bed:" + Bed);
                    }

                    Target.jobs.StartJob(gettin_raped, JobCondition.InterruptForced, null, false, true, null);
                    (Target.jobs.curDriver as JobDriver_GettinRaped)?.increase_time(duration);
                    if (Bed != null)
                    {
                        (Target.jobs.curDriver as JobDriver_GettinRaped)?.set_bed(Bed);
                    }
                }
                else
                {
                    dri.rapist_count += 1;
                    dri.increase_time(duration);
                }
            };
            rape.tickAction = delegate
            {
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
                if (pawn.IsHashIntervalTick(ticks_between_thrusts))
                {
                    xxx.sexTick(pawn, Target);
                }
                if (pawn.IsHashIntervalTick(ticks_between_hits))
                {
                    roll_to_hit(pawn, Target);
                }
                xxx.reduce_rest(Target, 1);
                xxx.reduce_rest(pawn, 2);
            };
            rape.AddFinishAction(delegate
            {
                //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Clearing victim job");
                if (Target.jobs?.curDriver is JobDriver_GettinRaped)
                {
                    //Log.Message("JobDriver_ComfortPrisonerRapin::MakeNewToils() - Victim present");
                    (Target.jobs.curDriver as JobDriver_GettinRaped).rapist_count -= 1;
                }
            });
            rape.defaultCompleteMode = ToilCompleteMode.Delay;
            rape.defaultDuration     = duration;
            yield return(rape);

            yield return(new Toil
            {
                initAction = delegate
                {
                    // Trying to add some interactions and social logs
                    SexUtility.ProcessSex(pawn, Target, true);
                    Target.records.Increment(xxx.GetRapedAsComfortPrisoner);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #26
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() called");
            setup_ticks();

            this.FailOnDespawnedNullOrForbidden(iTarget);
            this.FailOn(() => !pawn.CanReserve(Target, 1, 0));              // Fail if someone else reserves the prisoner before the pawn arrives
            this.FailOn(() => pawn.IsFighting());
            this.FailOn(() => pawn.Drafted);
            this.FailOn(Target.IsBurning);

            //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - moving towards Target");
            yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell));

            var alert = RJWPreferenceSettings.rape_attempt_alert == RJWPreferenceSettings.RapeAlert.Disabled ?
                        MessageTypeDefOf.SilentInput : MessageTypeDefOf.NeutralEvent;

            Messages.Message(xxx.get_pawnname(pawn) + " is trying to rape a corpse of " + xxx.get_pawnname(Partner), pawn, alert);

            setup_ticks();            // re-setup ticks on arrival

            var rape = new Toil();

            rape.defaultCompleteMode = ToilCompleteMode.Delay;
            rape.defaultDuration     = duration;
            rape.handlingFacing      = true;
            rape.initAction          = delegate
            {
                //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - stripping Target");
                (Target as Corpse).Strip();
                Start();
            };
            rape.tickAction = delegate
            {
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    if (xxx.is_necrophiliac(pawn))
                    {
                        ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                    }
                    else
                    {
                        ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart);
                    }
                }
                //if (pawn.IsHashIntervalTick (ticks_between_hits))
                //	roll_to_hit (pawn, Target);
                SexTick(pawn, Target);
                SexUtility.reduce_rest(pawn, 2);
            };
            rape.AddFinishAction(delegate
            {
                End();
            });
            yield return(rape);

            yield return(new Toil
            {
                initAction = delegate
                {
                    //--Log.Message("[RJW] JobDriver_ViolateCorpse::MakeNewToils() - creating aftersex toil");
                    SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, sextype: sexType);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #27
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            setup_ticks();

            this.FailOnDespawnedOrNull(iTarget);
            this.FailOnDespawnedNullOrForbidden(iBed);
            this.FailOn(() => !pawn.CanReserveAndReach(Partner, PathEndMode.Touch, Danger.Deadly));
            this.FailOn(() => pawn.Drafted);
            this.FailOn(() => Partner.IsFighting());
            this.FailOn(() => !Partner.CanReach(pawn, PathEndMode.Touch, Danger.Deadly));

            yield return(Toils_Reserve.Reserve(iTarget, 1, 0));

            Toil gotoAnimal = Toils_Goto.GotoThing(iTarget, PathEndMode.Touch);

            yield return(gotoAnimal);

            Toil gotoBed = new Toil();

            gotoBed.defaultCompleteMode = ToilCompleteMode.PatherArrival;
            gotoBed.FailOnBedNoLongerUsable(iBed);
            gotoBed.AddFailCondition(() => Partner.Downed);
            gotoBed.initAction = delegate
            {
                pawn.pather.StartPath(SleepSpot, PathEndMode.OnCell);
                Partner.jobs.StopAll();
                Job job = JobMaker.MakeJob(JobDefOf.GotoMindControlled, SleepSpot);
                Partner.jobs.StartJob(job, JobCondition.InterruptForced);
            };
            yield return(gotoBed);

            Toil waitInBed = new Toil();

            waitInBed.FailOn(() => pawn.GetRoom(RegionType.Set_Passable) == null);
            waitInBed.defaultCompleteMode = ToilCompleteMode.Delay;
            waitInBed.initAction          = delegate
            {
                ticksLeftThisToil = 5000;
            };
            waitInBed.tickAction = delegate
            {
                pawn.GainComfortFromCellIfPossible();
                if (IsInOrByBed(Bed, Partner) && pawn.PositionHeld == Partner.PositionHeld)
                {
                    ReadyForNextToil();
                }
            };
            yield return(waitInBed);

            Toil StartPartnerJob = new Toil();

            StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant;
            StartPartnerJob.socialMode          = RandomSocialMode.Off;
            StartPartnerJob.initAction          = delegate
            {
                var gettin_loved = JobMaker.MakeJob(xxx.gettin_loved, pawn, Bed);
                Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced);
            };
            yield return(StartPartnerJob);

            Toil loveToil = new Toil();

            loveToil.AddFailCondition(() => Partner.Dead || !IsInOrByBed(Bed, Partner));
            loveToil.socialMode          = RandomSocialMode.Off;
            loveToil.defaultCompleteMode = ToilCompleteMode.Never;
            loveToil.handlingFacing      = true;
            loveToil.initAction          = delegate
            {
                usedCondom = CondomUtility.TryUseCondom(pawn);
                Start();
            };
            loveToil.AddPreTickAction(delegate
            {
                --ticks_left;
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    if (xxx.is_zoophile(pawn))
                    {
                        ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                    }
                    else
                    {
                        ThrowMetaIcon(pawn.Position, pawn.Map, xxx.mote_noheart);
                    }
                }
                SexTick(pawn, Partner);
                SexUtility.reduce_rest(pawn, 1);
                SexUtility.reduce_rest(Partner, 2);
                if (ticks_left <= 0)
                {
                    ReadyForNextToil();
                }
            });
            loveToil.AddFinishAction(delegate
            {
                End();
            });
            yield return(loveToil);

            Toil afterSex = new Toil
            {
                initAction = delegate
                {
                    //Log.Message("JobDriver_BestialityForFemale::MakeNewToils() - Calling aftersex");
                    SexUtility.ProcessSex(Partner, pawn, usedCondom: usedCondom, sextype: sexType);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            };

            yield return(afterSex);
        }
コード例 #28
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called");

            setup_ticks();

            this.FailOnDespawnedOrNull(iTarget);
            this.FailOnDespawnedOrNull(iBed);
            this.FailOn(() => !Partner.health.capacities.CanBeAwake);
            this.FailOn(() => !(Partner.InBed() || xxx.in_same_bed(Partner, pawn)));
            this.FailOn(() => pawn.Drafted);
            yield return(Toils_Reserve.Reserve(iTarget, xxx.max_rapists_per_prisoner, 0));

            yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell));

            Toil StartPartnerJob = new Toil();

            StartPartnerJob.defaultCompleteMode = ToilCompleteMode.Instant;
            StartPartnerJob.socialMode          = RandomSocialMode.Off;
            StartPartnerJob.initAction          = delegate
            {
                Job gettin_loved = JobMaker.MakeJob(xxx.gettin_loved, pawn, Bed);
                Partner.jobs.StartJob(gettin_loved, JobCondition.InterruptForced);
            };
            yield return(StartPartnerJob);

            Toil do_lovin = new Toil();

            do_lovin.FailOn(() => Partner.CurJob.def != xxx.gettin_loved);
            do_lovin.defaultCompleteMode = ToilCompleteMode.Never;
            do_lovin.socialMode          = RandomSocialMode.Off;
            do_lovin.handlingFacing      = true;
            do_lovin.initAction          = delegate
            {
                usedCondom = CondomUtility.TryUseCondom(pawn) || CondomUtility.TryUseCondom(Partner);
                Start();
            };
            do_lovin.AddPreTickAction(delegate
            {
                --ticks_left;
                if (pawn.IsHashIntervalTick(ticks_between_hearts))
                {
                    ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_Heart);
                }
                SexTick(pawn, Partner);
                SexUtility.reduce_rest(Partner, 1);
                SexUtility.reduce_rest(pawn, 2);
                if (ticks_left <= 0)
                {
                    ReadyForNextToil();
                }
            });
            do_lovin.AddFinishAction(delegate
            {
                End();
            });
            yield return(do_lovin);

            yield return(new Toil
            {
                initAction = delegate
                {
                    // Trying to add some interactions and social logs
                    SexUtility.ProcessSex(pawn, Partner, usedCondom: usedCondom, rape: isRape, whoring: isWhoring, sextype: sexType);
                },
                defaultCompleteMode = ToilCompleteMode.Instant
            });
        }
コード例 #29
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() called");
            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());
            duration              = (int)(2500.0f * Rand.Range(0.50f, 0.90f));
            ticks_between_hearts  = Rand.RangeInclusive(70, 130);
            ticks_between_hits    = Rand.Range(xxx.config.min_ticks_between_hits, xxx.config.max_ticks_between_hits);
            ticks_between_thrusts = 100;

            if (xxx.is_bloodlust(pawn))
            {
                ticks_between_hits = (int)(ticks_between_hits * 0.75);
            }
            if (xxx.is_brawler(pawn))
            {
                ticks_between_hits = (int)(ticks_between_hits * 0.90);
            }

            //this.FailOn (() => (!animal.health.capacities.CanBeAwake) || (!comfort_prisoners.is_designated (animal)));
            // Fail if someone else reserves the prisoner before the pawn arrives or colonist can't reach animal
            this.FailOn(() => !pawn.CanReserveAndReach(animal, PathEndMode.Touch, Danger.Deadly));
            this.FailOn(() => animal.HostileTo(pawn));
            this.FailOnDespawnedNullOrForbidden(target_animal);
            this.FailOn(() => pawn.Drafted);
            yield return(Toils_Reserve.Reserve(target_animal, 1, 0));

            //Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - moving towards animal");
            yield return(Toils_Goto.GotoThing(target_animal, PathEndMode.Touch));

            yield return(Toils_Interpersonal.WaitToBeAbleToInteract(pawn));

            yield return(Toils_Interpersonal.GotoInteractablePosition(target_animal));

            if (xxx.is_kind(pawn) ||
                (xxx.CTIsActive && xxx.has_traits(pawn) && pawn.story.traits.HasTrait(TraitDef.Named("RCT_AnimalLover"))))
            {
                yield return(TalkToAnimal(pawn, animal));

                yield return(TalkToAnimal(pawn, animal));
            }
            if (Rand.Chance(0.6f))
            {
                yield return(TalkToAnimal(pawn, animal));
            }
            yield return(Toils_Goto.GotoThing(target_animal, PathEndMode.OnCell));

            SexUtility.RapeAttemptAlert(pawn, animal);

            Toil rape = new Toil();

            rape.initAction = delegate
            {
                //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - reserving animal");

                //--Log.Message("[RJW] JobDriver_BestialityForMale::MakeNewToils() - Setting animal job driver");
                if (!(animal.jobs.curDriver is JobDriver_GettinRaped dri))
                {
                    //wild animals may flee or attack
                    if (pawn.Faction != animal.Faction && animal.RaceProps.wildness > Rand.Range(0.22f, 1.0f) &&
                        !(pawn.TicksPerMoveCardinal < (animal.TicksPerMoveCardinal / 2) && !animal.Downed && xxx.is_not_dying(animal)))
                    {
                        animal.jobs.StopAll();                         // Wake up if sleeping.

                        float aggro = animal.kindDef.RaceProps.manhunterOnTameFailChance;
                        if (animal.kindDef.RaceProps.predator)
                        {
                            aggro += 0.2f;
                        }
                        else
                        {
                            aggro -= 0.1f;
                        }

                        if (Rand.Chance(aggro) && animal.CanSee(pawn))
                        {
                            animal.rotationTracker.FaceTarget(pawn);
                            LifeStageUtility.PlayNearestLifestageSound(animal, (ls) => ls.soundAngry, 1.4f);
                            MoteMaker.ThrowMetaIcon(animal.Position, animal.Map, ThingDefOf.Mote_IncapIcon);
                            MoteMaker.ThrowMetaIcon(pawn.Position, pawn.Map, ThingDefOf.Mote_ColonistFleeing);                             //red '!'
                            animal.mindState.mentalStateHandler.TryStartMentalState(MentalStateDefOf.Manhunter);
                            if (animal.kindDef.RaceProps.herdAnimal && Rand.Chance(0.2f))
                            {                             // 20% chance of turning the whole herd hostile...
                                List <Pawn> packmates = animal.Map.mapPawns.AllPawnsSpawned.Where(x =>
                                                                                                  x != animal && x.def == animal.def && x.Faction == animal.Faction &&
                                                                                                  x.Position.InHorDistOf(animal.Position, 24f) && x.CanSee(animal)).ToList();

                                foreach (Pawn packmate in packmates)
                                {
                                    packmate.mindState.mentalStateHandler.TryStartMentalState(MentalStateDefOf.Manhunter);
                                }
                            }
                            Messages.Message(pawn.Name.ToStringShort + " is being attacked by " + xxx.get_pawnname(animal) + ".", pawn, MessageTypeDefOf.ThreatSmall);
                        }
                        else
                        {
                            MoteMaker.ThrowMetaIcon(animal.Position, animal.Map, ThingDefOf.Mote_ColonistFleeing);
                            LifeStageUtility.PlayNearestLifestageSound(animal, (ls) => ls.soundCall);
                            animal.mindState.StartFleeingBecauseOfPawnAction(pawn);
                            animal.mindState.mentalStateHandler.TryStartMentalState(DefDatabase <MentalStateDef> .GetNamed("PanicFlee"));
                        }
                        pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
                    }
                    else
                    {
                        Job gettin_bred = new Job(xxx.gettin_bred, pawn, animal);
                        animal.jobs.StartJob(gettin_bred, JobCondition.InterruptForced, null, true);
                        (animal.jobs.curDriver as JobDriver_GettinRaped)?.increase_time(duration);
                    }
                }
コード例 #30
0
        public static void calculateAndApplySemen(Pawn pawn, Pawn partner, xxx.rjwSextype sextype)
        {
            if (!RJWSettings.cum_on_body)
            {
                return;
            }

            Pawn giver, receiver;

            //Rand.PopState();
            //Rand.PushState(RJW_Multiplayer.PredictableSeed());

            //dispenser of the seed
            if (Genital_Helper.has_penis(pawn) || xxx.is_mechanoid(pawn) || xxx.is_insect(pawn))
            {
                giver    = pawn;
                receiver = partner;
            }
            else if (partner != null && (Genital_Helper.has_penis(partner) || xxx.is_mechanoid(partner) || xxx.is_insect(partner)))
            {
                giver    = partner;
                receiver = pawn;
            }
            else            //female on female or genderless - no s***n dispensed; maybe add futa support?
            {
                return;
            }

            //slimes do not waste fluids?
            //if (xxx.is_slime(giver)) return;

            //determine entity:
            int entityType = SemenHelper.CUM_NORMAL;

            if (xxx.is_mechanoid(giver))
            {
                entityType = SemenHelper.CUM_MECHA;
            }
            else if (xxx.is_insect(giver))
            {
                entityType = SemenHelper.CUM_INSECT;
            }

            //get pawn genitalia:
            BodyPartRecord genitals;

            if (xxx.is_mechanoid(giver))
            {
                genitals = giver.RaceProps.body.AllParts.Find(x => string.Equals(x.def.defName, "MechGenitals"));
            }
            else            //insects, animals, humans
            {
                genitals = giver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef);
            }
            //no cum without genitals
            if (genitals == null)
            {
                return;
            }

            //calculate s***n amount:
            Need  sexNeed   = giver.needs.AllNeeds.Find(x => string.Equals(x.def.defName, "Sex"));
            float horniness = 1f;

            if (sexNeed != null)            //non-humans don't have it - therefore just use the default value
            {
                horniness = 1f - sexNeed.CurLevel;
            }

            float ageScale  = Math.Min(80 / SexUtility.ScaleToHumanAge(giver), 1.0f);           //calculation lifted from rjw
            float cumAmount = horniness * giver.BodySize * ageScale * RJWSettings.cum_on_body_amount_adjust;

            ;

            if (xxx.has_quirk(giver, "Messy"))
            {
                cumAmount *= 1.5f;
            }

            //if no partner -> masturbation, apply some cum on self:
            //if (partner == null && sextype == xxx.rjwSextype.Autofellatio)
            //{
            //	if (!xxx.is_slime(giver))
            //		SemenHelper.cumOn(giver, BodyPartDefOf.Jaw, cumAmount, giver);
            //	return;
            //}
            if (partner == null && sextype == xxx.rjwSextype.Masturbation)
            {
                if (!xxx.is_slime(giver))
                {
                    SemenHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver);                    //pawns are usually not super-messy -> only apply 30%
                }
                return;
            }
            else if (partner != null)
            {
                List <BodyPartRecord>        targetParts    = new List <BodyPartRecord>(); //which to apply s***n on
                IEnumerable <BodyPartRecord> availableParts = SemenHelper.getAvailableBodyParts(receiver);
                BodyPartRecord randomPart;                                                 //not always needed

                switch (sextype)
                {
                case rjw.xxx.rjwSextype.Anal:
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef));
                    break;

                case rjw.xxx.rjwSextype.Boobjob:
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.chestDef));
                    break;

                case rjw.xxx.rjwSextype.DoublePenetration:
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef));
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef));
                    break;

                case rjw.xxx.rjwSextype.Fingering:
                    cumAmount = 0;
                    break;

                case rjw.xxx.rjwSextype.Fisting:
                    cumAmount = 0;
                    break;

                case rjw.xxx.rjwSextype.Footjob:
                    //random part:
                    availableParts.TryRandomElement <BodyPartRecord>(out randomPart);
                    targetParts.Add(randomPart);
                    break;

                case rjw.xxx.rjwSextype.Handjob:
                    //random part:
                    availableParts.TryRandomElement <BodyPartRecord>(out randomPart);
                    targetParts.Add(randomPart);
                    break;

                case rjw.xxx.rjwSextype.Masturbation:
                    cumAmount *= 2f;
                    break;

                case rjw.xxx.rjwSextype.MechImplant:
                    //one of the openings:
                    int random = Rand.Range(0, 3);
                    if (random == 0)
                    {
                        targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef));
                    }
                    else if (random == 1)
                    {
                        targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.anusDef));
                    }
                    else if (random == 2)
                    {
                        targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw));
                    }
                    break;

                case rjw.xxx.rjwSextype.MutualMasturbation:
                    //random
                    availableParts.TryRandomElement <BodyPartRecord>(out randomPart);
                    targetParts.Add(randomPart);
                    break;

                case rjw.xxx.rjwSextype.None:
                    cumAmount = 0;
                    break;

                case rjw.xxx.rjwSextype.Oral:
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == BodyPartDefOf.Jaw));
                    break;

                case rjw.xxx.rjwSextype.Scissoring:
                    //I guess if it came to here, a male must be involved?
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef));
                    break;

                case rjw.xxx.rjwSextype.Vaginal:
                    targetParts.Add(receiver.RaceProps.body.AllParts.Find(x => x.def == SemenHelper.genitalsDef));
                    break;
                }

                if (cumAmount > 0)
                {
                    if (xxx.is_slime(receiver))
                    {
                        //slime absorb cum
                        //this needs balancing, since cumamount ranges 0-10(?) which is fine for cum/hentai but not very realistic for feeding
                        //using TransferNutrition for now
                        //Log.Message("cumAmount " + cumAmount);
                        //float nutrition_amount = cumAmount/10;

                        Need_Food need = need = giver.needs.TryGetNeed <Need_Food>();
                        if (need == null)
                        {
                            //Log.Message("xxx::TransferNutrition() " + xxx.get_pawnname(pawn) + " doesn't track nutrition in itself, probably shouldn't feed the others");
                            return;
                        }

                        if (receiver?.needs?.TryGetNeed <Need_Food>() != null)
                        {
                            //Log.Message("xxx::TransferNutrition() " +  xxx.get_pawnname(partner) + " can receive");
                            float nutrition_amount = Math.Min(need.MaxLevel / 15f, need.CurLevel);                             //body size is taken into account implicitly by need.MaxLevel
                            receiver.needs.food.CurLevel += nutrition_amount;
                        }
                    }
                    else
                    {
                        SemenHelper.cumOn(giver, genitals, cumAmount * 0.3f, giver, entityType);                        //cum on self - smaller amount
                        foreach (BodyPartRecord bpr in targetParts)
                        {
                            if (bpr != null)
                            {
                                SemenHelper.cumOn(receiver, bpr, cumAmount, giver, entityType);                                //cum on partner
                            }
                        }
                    }
                }
            }
        }