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);
        }
Exemple #2
0
        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);
            }));
        }