public BeatingInProgress GetOrStartBeatingInProgress(Pawn beatee, Pawn beater = null) { BeatingInProgress beating = GetBeatingInProgress(beatee); if (beating == null) { beating = new BeatingInProgress(); beating.beatee = beatee; beatingsInProgress.Add(beating); Logger.MessageFormat(this, "Started a new beating for {0}", beatee); } if (beater != null) { beating.AddBeater(beater); BeatingCounter counter = beatingCounters.Find(bc => bc.beater == beater); if (counter == null) { counter = new BeatingCounter(); counter.beater = beater; counter.nextBeatingTick = Find.TickManager.TicksGame + minimumBeatingInterval; } } return(beating); }
public override void Interacted(Pawn initiator, Pawn recipient, List <RulePackDef> extraSentencePacks, out string letterText, out string letterLabel, out LetterDef letterDef, out LookTargets lookTargets) { letterText = null; letterLabel = null; letterDef = null; lookTargets = null; BeatingInProgress beating = Current.Game.World.GetComponent <BeatingTracker>()?.GetBeatingInProgress(recipient); if (beating == null) { return; } float currentPainLevel = recipient.health.hediffSet.PainTotal; float painInflicted = beating.GetAndResetPainInflicted(currentPainLevel); float painFactor = ResistanceImpactFactorCurve_Pain.Evaluate(painInflicted); float resistanceReduction = 1f; Logger.StartMessage(this, "{0} beat {1}, base resistance reduction = {2}", initiator, recipient, resistanceReduction); Logger.AddToMessage(" pain inflicted: {0}, pain factor: {1}", painInflicted, painFactor); resistanceReduction *= painFactor; resistanceReduction = FactorInInitiatorTraits(initiator, resistanceReduction); resistanceReduction = FactorInRecipientTraits(recipient, resistanceReduction); Logger.AddToMessage("Final resistance reduction: {0}", resistanceReduction); Logger.DisplayMessage(); resistanceReduction = Mathf.Min(resistanceReduction, recipient.guest.resistance); float resistance = recipient.guest.resistance; recipient.guest.resistance = Mathf.Max(0f, recipient.guest.resistance - resistanceReduction); float resistanceReduced = resistance - recipient.guest.resistance; string text = "TextMote_ResistanceReduced".Translate(resistance.ToString("F1"), recipient.guest.resistance.ToString("F1")); MoteMaker.ThrowText((initiator.DrawPos + recipient.DrawPos) / 2f, initiator.Map, text, 8f); if (recipient.guest.resistance == 0f) { TaggedString taggedString = "MessagePrisonerResistanceBroken".Translate(recipient.LabelShort, initiator.LabelShort, initiator.Named("WARDEN"), recipient.Named("PRISONER")); if (recipient.guest.interactionMode == PrisonerInteractionModeDefOf.AttemptRecruit) { taggedString += " " + "MessagePrisonerResistanceBroken_RecruitAttempsWillBegin".Translate(); } Messages.Message(taggedString, recipient, MessageTypeDefOf.PositiveEvent); } }
public void StopBeating(Pawn beatee, Pawn beater) { BeatingInProgress beating = GetBeatingInProgress(beatee); if (beating != null) { beating.RemoveBeater(beater); if (beating.beaters.Count == 0) { beatingsInProgress.Remove(beating); Logger.MessageFormat(this, "Ended beating for {0}", beatee); } } }
protected override IEnumerable <Toil> MakeNewToils() { Toil toil = new Toil(); toil.defaultCompleteMode = ToilCompleteMode.Delay; toil.defaultDuration = 1200; toil.initAction = delegate { pawn.pather.StopDead(); }; toil.tickAction = delegate { if (pawn.IsHashIntervalTick(35)) { BeatingInProgress beating = Current.Game.World.GetComponent <BeatingTracker>()?.GetBeatingInProgress(pawn); if (beating != null && beating.fightingBack) { EndJobWith(JobCondition.InterruptForced); } } }; yield return(toil); }
protected override IEnumerable <Toil> MakeNewToils() { Toil beatingContinues = Toils_General.Label(); Toil beatingComplete = Toils_General.Label(); Toil beatingCancelled = Toils_General.Label(); yield return(Toils_General.Do(delegate { Messages.Message("CM_Beat_Prisoners_Break_Attempt".Translate(pawn, Victim), Victim, MessageTypeDefOf.NeutralEvent); })); yield return(beatingContinues); yield return(GotoPrisoner(pawn, Victim)); yield return(Toils_Interpersonal.GotoInteractablePosition(TargetIndex.A)); yield return(ThreatenPrisoner(pawn, Victim)); yield return(Toils_General.Do(delegate { BeatingInProgress beating = Current.Game.World.GetComponent <BeatingTracker>()?.GetOrStartBeatingInProgress(Victim, pawn); if (beating != null) { beating.TryFightBack(); } })); yield return(Toils_Misc.ThrowColonistAttackingMote(TargetIndex.A)); yield return(Toils_Combat.FollowAndMeleeAttack(TargetIndex.A, delegate { if (Victim == null || !Victim.Spawned || Victim.InMentalState || !Victim.IsPrisonerOfColony || !Victim.guest.PrisonerIsSecure || Victim.guest.interactionMode != PrisonerInteractionModeDefOf.ReduceResistance) { pawn.jobs.curDriver.JumpToToil(beatingCancelled); } if (Victim.Downed) { pawn.jobs.curDriver.JumpToToil(beatingComplete); } if (pawn.meleeVerbs.TryMeleeAttack(Victim, job.verbToUse) && pawn.CurJob != null && pawn.jobs.curDriver == this) { numMeleeAttacksMade++; BeatingInProgress beating = Current.Game.World.GetComponent <BeatingTracker>()?.GetBeatingInProgress(Victim); // Keep going if there is a fight, otherwise do the requested number of attacks if ((beating != null && beating.fightingBack) || numMeleeAttacksMade < job.maxNumMeleeAttacks) { pawn.jobs.curDriver.JumpToToil(beatingContinues); } else { pawn.jobs.curDriver.JumpToToil(beatingComplete); } } })); yield return(beatingComplete); Toil giveThoughts = Toils_General.Do(delegate { pawn.records.Increment(BeatPrisonersDefOf.CM_Beat_Prisoners_Record_Prisoners_Beaten); BeatPrisonersUtility.GiveThoughtsForPrisonerBeaten(Victim, pawn); // This never seems to get called, because if the initiator goes down, the job is interrupted // Leaving it anyway to show desired behavior. This needs to go in JobDriver_Patches for Cleanup if (pawn.Downed || pawn.Dead) { // If this became a fight, losing might trigger a prison break Current.Game.World.GetComponent <BeatingTracker>()?.BeaterDowned(Victim, pawn); pawn.jobs.curDriver.JumpToToil(beatingCancelled); } }); yield return(giveThoughts); //yield return Toils_Interpersonal.SetLastInteractTime(TargetIndex.A); yield return(BreakResistance(TargetIndex.A)); yield return(beatingCancelled); yield return(Toils_General.Do(delegate { Current.Game.World.GetComponent <BeatingTracker>()?.StopBeating(Victim, pawn); })); }