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); } }
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 }); }
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 }); }
protected override IEnumerable <Toil> MakeNewToils() { //Rand.PopState(); //Rand.PushState(RJW_Multiplayer.PredictableSeed()); //Log.Message("[RJW]" + this.GetType().ToString() + "::MakeNewToils() called"); 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; 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.FailOnDespawnedNullOrForbidden(iTarget); 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.IsFighting()); this.FailOn(() => Target.IsFighting()); this.FailOn(() => pawn.Drafted); yield return(Toils_Goto.GotoThing(iTarget, PathEndMode.OnCell)); SexUtility.RapeAttemptAlert(pawn, Target); //Log.Message("[RJW] JobDriver_Rape::make toils() called"); var rape = new Toil(); rape.initAction = delegate { //Log.Message("[RJW]" + this.GetType().ToString() + "::initAction() called"); //pawn.Reserve(Target, comfort_prisoners.max_rapists_per_prisoner, 0); //if (!pawnHasPenis) // Target.rotationTracker.Face(pawn.DrawPos); 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.FailOn(() => Target.CurJob == null || Target.CurJob.def != xxx.gettin_raped || Target.IsFighting() || pawn.IsFighting()); }; rape.tickAction = delegate { //Log.Message("[RJW] JobDriver_Rape::tickAction() called"); 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, false); } if (pawn.IsHashIntervalTick(ticks_between_hits)) { roll_to_hit(pawn, Target); } xxx.reduce_rest(Target, 1); xxx.reduce_rest(pawn, 2); }; rape.AddFinishAction(delegate { if (Target.jobs?.curDriver is JobDriver_GettinRaped) { (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 { //Log.Message("[RJW] JobDriver_Rape::aftersex() called"); //// Trying to add some interactions and social logs SexUtility.ProcessSex(pawn, Target, true); }, defaultCompleteMode = ToilCompleteMode.Instant }); }