public static bool PreFix(ref Toil __result, TargetIndex targetInd, Action hitAction)
        {
            Toil followAndAttack = new Toil();

            followAndAttack.tickAction = delegate()
            {
                Pawn      actor     = followAndAttack.actor;
                Job       curJob    = actor.jobs.curJob;
                JobDriver curDriver = actor.jobs.curDriver;
                Thing     thing     = curJob.GetTarget(targetInd).Thing;
                Pawn      pawn      = thing as Pawn;
                if (thing.Spawned && !ReachabilityImmediate.CanReachImmediate(actor, pawn, PathEndMode.Touch))
                {
                    bool flag;
                    if (actor == null)
                    {
                        flag = (null != null);
                    }
                    else
                    {
                        Pawn_MindState mindState = actor.mindState;
                        flag = ((mindState?.meleeThreat) != null);
                    }
                    if (!flag && pawn != null && pawn != null && CamoUtility.IsTargetHidden(pawn, actor))
                    {
                        CamoAIUtility.CorrectJob(actor, pawn);
                    }
                }
                if (!thing.Spawned)
                {
                    curDriver.ReadyForNextToil();
                    return;
                }
                if (thing != actor.pather.Destination.Thing || (!actor.pather.Moving && !ReachabilityImmediate.CanReachImmediate(actor, thing, PathEndMode.Touch)))
                {
                    actor.pather.StartPath(thing, PathEndMode.Touch);
                    return;
                }
                if (ReachabilityImmediate.CanReachImmediate(actor, thing, PathEndMode.Touch))
                {
                    if (pawn != null && pawn.Downed && !curJob.killIncappedTarget)
                    {
                        curDriver.ReadyForNextToil();
                        return;
                    }
                    hitAction();
                }
            };
            followAndAttack.defaultCompleteMode = ToilCompleteMode.Never;
            __result = followAndAttack;
            return(false);
        }
Exemplo n.º 2
0
        public static Toil UninstallIfMinifiable(TargetIndex thingInd)
        {
            Toil uninstallIfMinifiable = new Toil().FailOnDestroyedNullOrForbidden(thingInd);

            uninstallIfMinifiable.initAction = delegate
            {
                Pawn      actor     = uninstallIfMinifiable.actor;
                JobDriver curDriver = actor.jobs.curDriver;
                Thing     thing     = actor.CurJob.GetTarget(thingInd).Thing;
                if (thing.def.Minifiable)
                {
                    curDriver.uninstallWorkLeft = thing.def.building.uninstallWork;
                }
                else
                {
                    curDriver.ReadyForNextToil();
                }
            };
            uninstallIfMinifiable.tickAction = delegate
            {
                Pawn      actor     = uninstallIfMinifiable.actor;
                JobDriver curDriver = actor.jobs.curDriver;
                Job       curJob    = actor.CurJob;
                curDriver.uninstallWorkLeft -= actor.GetStatValue(StatDefOf.ConstructionSpeed, true);
                if (curDriver.uninstallWorkLeft <= 0f)
                {
                    Thing         thing         = curJob.GetTarget(thingInd).Thing;
                    MinifiedThing minifiedThing = thing.MakeMinified();
                    GenSpawn.Spawn(minifiedThing, thing.Position, uninstallIfMinifiable.actor.Map, WipeMode.Vanish);
                    curJob.SetTarget(thingInd, minifiedThing);
                    actor.jobs.curDriver.ReadyForNextToil();
                    return;
                }
            };
            uninstallIfMinifiable.defaultCompleteMode = ToilCompleteMode.Never;
            uninstallIfMinifiable.WithProgressBar(thingInd, () => 1f - uninstallIfMinifiable.actor.jobs.curDriver.uninstallWorkLeft / uninstallIfMinifiable.actor.CurJob.targetA.Thing.def.building.uninstallWork, false, -0.5f);
            return(uninstallIfMinifiable);
        }
Exemplo n.º 3
0
        public static IEnumerable <Toil> MakeFeedToils(JobDriver thisDriver, Pawn actor, LocalTargetInfo TargetA, float workLeft, Action effect, Func <Pawn, Pawn, bool> stopCondition)
        {
            yield return(Toils_Reserve.Reserve(TargetIndex.A));

            Toil gotoToil = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);

            yield return(gotoToil);

            Toil grappleToil = new Toil()
            {
                initAction = delegate
                {
                    MoteMaker.MakeColonistActionOverlay(actor, ThingDefOf.Mote_ColonistAttacking);

                    workLeft = JobDriver_Feed.BaseFeedTime;
                    Pawn victim = (Pawn)TargetA.Thing;
                    if (victim != null)
                    {
                        if (victim.InAggroMentalState || victim.Faction != actor.Faction)
                        {
                            if (!JecsTools.GrappleUtility.CanGrapple(actor, victim))
                            {
                                thisDriver.EndJobWith(JobCondition.Incompletable);
                            }
                        }
                        GenClamor.DoClamor(actor, 10f, ClamorDefOf.Harm);
                        if (!AllowFeeding(actor, victim))
                        {
                            actor.jobs.EndCurrentJob(JobCondition.Incompletable);
                        }
                        if (actor?.VampComp()?.Bloodline?.bloodlineHediff?.CompProps <HediffCompProperties_VerbGiver>()?.verbs is List <VerbProperties> verbProps)
                        {
                            if (actor?.VerbTracker?.AllVerbs is List <Verb> verbs)
                            {
                                if (verbs.Find(x => verbProps.Contains(x.verbProps)) is Verb_MeleeAttack v)
                                {
                                    victim.TakeDamage(new DamageInfo(v.verbProps.meleeDamageDef, v.verbProps.meleeDamageBaseAmount, 0, -1, actor));
                                }
                            }
                        }
                        victim.stances.stunner.StunFor((int)BaseFeedTime);
                    }
                }
            };

            yield return(grappleToil);

            Toil feedToil = new Toil()
            {
                tickAction = delegate
                {
                    Pawn victim = (Pawn)TargetA.Thing;
                    if (victim == null || !victim.Spawned || victim.Dead)
                    {
                        thisDriver.ReadyForNextToil();
                    }
                    workLeft--;

                    if (workLeft <= 0f)
                    {
                        if (actor?.VampComp() is CompVampire v && v.IsVampire && actor.Faction == Faction.OfPlayer)
                        {
                            MoteMaker.ThrowText(actor.DrawPos, actor.Map, "XP +" + 15);
                            v.XP += 15;
                        }
                        workLeft = BaseFeedTime;
                        MoteMaker.MakeColonistActionOverlay(actor, ThingDefOf.Mote_ColonistAttacking);
                        effect();
                        if ((victim.HostileTo(actor.Faction) || victim.IsPrisoner) && !JecsTools.GrappleUtility.CanGrapple(actor, victim))
                        {
                            thisDriver.EndJobWith(JobCondition.Incompletable);
                        }

                        if (!stopCondition(actor, victim))
                        {
                            thisDriver.ReadyForNextToil();
                        }
                        else
                        {
                            if (victim != null && !victim.Dead)
                            {
                                victim.stances.stunner.StunFor((int)BaseFeedTime);
                                PawnUtility.ForceWait((Pawn)TargetA.Thing, (int)BaseFeedTime, actor);
                            }
                        }
                    }
                },
Exemplo n.º 4
0
        public static bool DriverTick(JobDriver __instance)
        {
            try
            {
                __instance.ticksLeftThisToil--;
                __instance.debugTicksSpentThisToil++;
                if (get_CurToil2(__instance) == null)
                {
                    if (!__instance.pawn.stances.FullBodyBusy || get_CanStartNextToilInBusyStance2(__instance))
                    {
                        __instance.ReadyForNextToil();
                    }
                }
                else
                {
                    if (CheckCurrentToilEndOrFail2(__instance))
                    {
                        return(false);
                    }

                    if (curToilCompleteMode(__instance) == ToilCompleteMode.Delay)
                    {
                        if (__instance.ticksLeftThisToil > 0)
                        {
                            goto IL_0099;
                        }

                        __instance.ReadyForNextToil();
                    }
                    else
                    {
                        if (curToilCompleteMode(__instance) != ToilCompleteMode.FinishedBusy || __instance.pawn.stances.FullBodyBusy)
                        {
                            goto IL_0099;
                        }

                        __instance.ReadyForNextToil();
                    }

                    return(false);
                }

                goto end_IL_0000;
IL_01b8:
                if (__instance.job.mote != null)
                {
                    __instance.job.mote.Maintain();
                }

                goto end_IL_0000;
IL_0099:
                if (wantBeginNextToil(__instance))
                {
                    TryActuallyStartNextToil(__instance);
                    return(false);
                }

                if (curToilCompleteMode(__instance) == ToilCompleteMode.Instant && __instance.debugTicksSpentThisToil > 300)
                {
                    Log.Error(string.Concat(__instance.pawn, " had to be broken from frozen state. He was doing job ", __instance.job, ", toilindex=", curToilIndex));
                    __instance.ReadyForNextToil();
                    return(false);
                }

                Job startingJob   = __instance.pawn.CurJob;
                int startingJobId = startingJob.loadID;
                if (get_CurToil2(__instance) != null && get_CurToil2(__instance).preTickActions != null)
                {
                    Toil curToil = get_CurToil2(__instance);
                    for (int i = 0; i < curToil.preTickActions.Count; i++)
                    {
                        curToil.preTickActions[i]();
                        if (JobChanged() || get_CurToil2(__instance) != curToil || wantBeginNextToil(__instance))
                        {
                            return(false);
                        }
                    }
                }
                Toil gct = get_CurToil2(__instance);
                if (gct.tickAction == null)
                {
                    goto IL_01b8;
                }

                gct.tickAction();
                if (!JobChanged())
                {
                    goto IL_01b8;
                }

end_IL_0000:
                bool JobChanged()
                {
                    if (__instance.pawn.CurJob == startingJob)
                    {
                        return(__instance.pawn.CurJob.loadID != startingJobId);
                    }

                    return(true);
                }
            }
            catch (Exception exception)
            {
                JobUtility.TryStartErrorRecoverJob(__instance.pawn, "Exception in JobDriver tick for pawn " + __instance.pawn.ToStringSafe(), exception, __instance);
            }
            return(false);
        }
Exemplo n.º 5
0
        public static bool TryActuallyStartNextToil(JobDriver __instance)
        {
            if (!__instance.pawn.Spawned || (__instance.pawn.stances.FullBodyBusy && !get_CanStartNextToilInBusyStance2(__instance)) || __instance.job == null || __instance.pawn.CurJob != __instance.job)
            {
                return(false);
            }

            /*
             * if (get_HaveCurToil2(__instance))
             * {
             *  get_CurToil2(__instance).Cleanup(curToilIndex(__instance), __instance);
             * }
             */
            if (curToilIndex(__instance) >= 0 && curToilIndex(__instance) < toils(__instance).Count&& __instance.job != null)
            {
                if (__instance.pawn.CurJob == __instance.job)
                {
                    Toil curToil2 = toils(__instance)[curToilIndex(__instance)];
                    if (curToil2 != null)
                    {
                        curToil2.Cleanup(curToilIndex(__instance), __instance);
                    }
                }
            }

            if (nextToilIndex(__instance) >= 0)
            {
                curToilIndex(__instance)  = nextToilIndex(__instance);
                nextToilIndex(__instance) = -1;
            }
            else
            {
                curToilIndex(__instance)++;
            }

            wantBeginNextToil(__instance) = false;

            if (!get_HaveCurToil2(__instance))
            {
                if (__instance.pawn.stances != null && __instance.pawn.stances.curStance.StanceBusy)
                {
                    Log.ErrorOnce(__instance.pawn.ToStringSafe() + " ended job " + __instance.job.ToStringSafe() + " due to running out of toils during a busy stance.", 6453432);
                }

                __instance.EndJobWith(JobCondition.Succeeded);
                return(false);
            }


            __instance.debugTicksSpentThisToil = 0;
            Toil curToil = get_CurToil2(__instance);

            if (curToil != null)
            {
                __instance.ticksLeftThisToil    = curToil.defaultDuration;
                curToilCompleteMode(__instance) = curToil.defaultCompleteMode;
            }
            if (CheckCurrentToilEndOrFail2(__instance))
            {
                return(false);
            }

            curToil = get_CurToil2(__instance);
            Toil gct = get_CurToil2(__instance);

            if (gct != null && gct.preInitActions != null)
            {
                List <Action> preInitActions = gct.preInitActions;
                for (int i = 0; i < preInitActions.Count; i++)
                {
                    try
                    {
                        gct = get_CurToil2(__instance);
                        if (gct != null)
                        {
                            preInitActions = gct.preInitActions;
                        }
                        else
                        {
                            break;
                        }
                        preInitActions[i]();
                    }
                    catch (Exception exception)
                    {
                        JobUtility.TryStartErrorRecoverJob(__instance.pawn, "JobDriver threw exception in preInitActions[" + i + "] for pawn " + __instance.pawn.ToStringSafe(), exception, __instance);
                        return(false);
                    }

                    if (get_CurToil2(__instance) != curToil)
                    {
                        break;
                    }
                    gct = get_CurToil2(__instance);
                    if (gct != null)
                    {
                        preInitActions = gct.preInitActions;
                    }
                    else
                    {
                        break;
                    }
                }
            }

            Toil gct2 = get_CurToil2(__instance);

            if (gct2 == curToil)
            {
                if (gct2 != null)
                {
                    if (gct2.initAction != null)
                    {
                        try
                        {
                            gct2.initAction();
                        }
                        catch (Exception exception2)
                        {
                            JobUtility.TryStartErrorRecoverJob(__instance.pawn, "JobDriver threw exception in initAction for pawn " + __instance.pawn.ToStringSafe(), exception2, __instance);
                            return(false);
                        }
                    }

                    if (!__instance.ended && curToilCompleteMode(__instance) == ToilCompleteMode.Instant && get_CurToil2(__instance) == curToil)
                    {
                        __instance.ReadyForNextToil();
                    }
                }
            }
            return(false);
        }
Exemplo n.º 6
0
 public static bool StartJob(Pawn_JobTracker __instance,
                             Job newJob,
                             JobCondition lastJobEndCondition = JobCondition.None,
                             ThinkNode jobGiver          = null,
                             bool resumeCurJobAfterwards = false,
                             bool cancelBusyStances      = true,
                             ThinkTreeDef thinkTree      = null,
                             JobTag?tag                 = null,
                             bool fromQueue             = false,
                             bool canReturnCurJobToPool = false)
 {
     __instance.startingNewJob = true;
     try
     {
         if (!fromQueue && (!Find.TickManager.Paused || __instance.lastJobGivenAtFrame == RealTime.frameCount))
         {
             ++__instance.jobsGivenThisTick;
             if (Prefs.DevMode)
             {
                 __instance.jobsGivenThisTickTextual = __instance.jobsGivenThisTickTextual + "(" + newJob.ToString() + ") ";
             }
         }
         __instance.lastJobGivenAtFrame = RealTime.frameCount;
         if (__instance.jobsGivenThisTick > 10)
         {
             string givenThisTickTextual = __instance.jobsGivenThisTickTextual;
             __instance.jobsGivenThisTick        = 0;
             __instance.jobsGivenThisTickTextual = "";
             __instance.startingNewJob           = false;
             __instance.pawn.ClearReservationsForJob(newJob);
             JobUtility.TryStartErrorRecoverJob(__instance.pawn, __instance.pawn.ToStringSafe <Pawn>() + " started 10 jobs in one tick. newJob=" + newJob.ToStringSafe <Job>() + " jobGiver=" + jobGiver.ToStringSafe <ThinkNode>() + " jobList=" + givenThisTickTextual);
         }
         else
         {
             if (__instance.debugLog)
             {
                 __instance.DebugLogEvent("StartJob [" + (object)newJob + "] lastJobEndCondition=" + (object)lastJobEndCondition + ", jobGiver=" + (object)jobGiver + ", cancelBusyStances=" + cancelBusyStances.ToString());
             }
             Pawn_StanceTracker stances = __instance.pawn.stances;             //changed
             if (cancelBusyStances && stances != null && stances.FullBodyBusy) //changed
             {
                 stances.CancelBusyStanceHard();
             }
             if (__instance.curJob != null)
             {
                 if (lastJobEndCondition == JobCondition.None)
                 {
                     Log.Warning(__instance.pawn.ToString() + " starting job " + (object)newJob + " from JobGiver " + (object)newJob.jobGiver + " while already having job " + (object)__instance.curJob + " without a specific job end condition.");
                     lastJobEndCondition = JobCondition.InterruptForced;
                 }
                 if (resumeCurJobAfterwards && __instance.curJob.def.suspendable)
                 {
                     __instance.jobQueue.EnqueueFirst(__instance.curJob);
                     if (__instance.debugLog)
                     {
                         __instance.DebugLogEvent("   JobQueue EnqueueFirst curJob: " + (object)__instance.curJob);
                     }
                     __instance.CleanupCurrentJob(lastJobEndCondition, false, cancelBusyStances);
                 }
                 else
                 {
                     __instance.CleanupCurrentJob(lastJobEndCondition, true, cancelBusyStances, canReturnCurJobToPool);
                 }
             }
             if (newJob == null)
             {
                 Log.Warning(__instance.pawn.ToString() + " tried to start doing a null job.");
             }
             else
             {
                 newJob.startTick = Find.TickManager.TicksGame;
                 if (__instance.pawn.Drafted || newJob.playerForced)
                 {
                     newJob.ignoreForbidden    = true;
                     newJob.ignoreDesignations = true;
                 }
                 __instance.curJob = newJob;
                 __instance.curJob.jobGiverThinkTree = thinkTree;
                 __instance.curJob.jobGiver          = jobGiver;
                 JobDriver cDriver = __instance.curJob.MakeDriver(__instance.pawn); //changed
                 __instance.curDriver = cDriver;                                    //changed
                 bool flag = fromQueue;
                 if (__instance.curDriver.TryMakePreToilReservations(!flag))
                 {
                     Job newJob1 = __instance.TryOpportunisticJob(newJob);
                     if (newJob1 != null)
                     {
                         __instance.jobQueue.EnqueueFirst(newJob);
                         __instance.curJob    = (Job)null;
                         __instance.curDriver = (JobDriver)null;
                         __instance.StartJob(newJob1);
                     }
                     else
                     {
                         if (tag.HasValue)
                         {
                             __instance.pawn.mindState.lastJobTag = tag.Value;
                         }
                         cDriver.SetInitialPosture(); //changed
                         cDriver.Notify_Starting();   //changed
                         cDriver.SetupToils();        //changed
                         cDriver.ReadyForNextToil();  //changed
                     }
                 }
                 else if (flag)
                 {
                     __instance.EndCurrentJob(JobCondition.QueuedNoLongerValid);
                 }
                 else
                 {
                     Log.Warning("TryMakePreToilReservations() returned false for a non-queued job right after StartJob(). This should have been checked before. curJob=" + __instance.curJob.ToStringSafe <Job>());
                     __instance.EndCurrentJob(JobCondition.Errored);
                 }
             }
         }
     }
     finally
     {
         __instance.startingNewJob = false;
     }
     return(false);
 }
        public static IEnumerable <Toil> MakeFeedToils(JobDef job, JobDriver thisDriver, Pawn actor, LocalTargetInfo TargetA, ThoughtDef victimThoughtDef, ThoughtDef actorThoughtDef, float workLeft, Action effect, Func <Pawn, Pawn, bool> stopCondition, bool needsGrapple = true, bool cleansWound = true, bool neverGiveUp = false)
        {
            yield return(Toils_Reserve.Reserve(TargetIndex.A));

            Toil gotoToil = actor?.Faction == TargetA.Thing?.Faction && (!actor.InAggroMentalState && !((Pawn)TargetA.Thing).InAggroMentalState) ? Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.ClosestTouch) : Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch);

            yield return(gotoToil);

            Toil grappleToil = new Toil()
            {
                initAction = delegate
                {
                    MoteMaker.MakeColonistActionOverlay(actor, ThingDefOf.Mote_ColonistAttacking);

                    workLeft = BaseFeedTime;
                    Pawn victim = TargetA.Thing as Pawn;
                    if (victim != null)
                    {
//                        if (!AllowFeeding(actor, victim))
//                        {
//                            actor.jobs.EndCurrentJob(JobCondition.Incompletable);
//                        }
                        if (actor.InAggroMentalState || victim.InAggroMentalState || victim.Faction != actor.Faction)
                        {
                            if (needsGrapple)
                            {
                                int grappleBonus = actor is PawnTemporary ? 100 : 0;
                                if (!JecsTools.GrappleUtility.TryGrapple(actor, victim, grappleBonus))
                                {
                                    thisDriver.EndJobWith(JobCondition.Incompletable);
                                    PawnUtility.ForceWait(actor, (int)(BaseFeedTime * 0.15f));
                                    return;
                                }
                            }
                        }
                        if (actor.IsVampire())
                        {
                            VampireBiteUtility.MakeNew(actor, victim);
                        }
                        victim.stances.stunner.StunFor((int)BaseFeedTime, actor);
                    }
                }
            };

            yield return(grappleToil);

            Toil feedToil = new Toil()
            {
                tickAction = delegate
                {
                    //try
                    //{
                    if (TargetA.Thing is Pawn victim && victim.Spawned && !victim.Dead)
                    {
                        workLeft--;
                        VampireWitnessUtility.HandleWitnessesOf(job, actor, victim);
                        if (victim?.needs?.mood?.thoughts?.memories != null)
                        {
                            Thought_Memory victimThought = null;
                            if (victimThoughtDef != null)
                            {
                                victimThought = (Thought_Memory)ThoughtMaker.MakeThought(victimThoughtDef);
                            }
                            if (victimThought != null)
                            {
                                victim.needs.mood.thoughts.memories.TryGainMemory(victimThought);
                            }
                        }
                        if (actor?.needs?.mood?.thoughts?.memories != null)
                        {
                            Thought_Memory actorThought = null;
                            if (actorThoughtDef != null)
                            {
                                actorThought = (Thought_Memory)ThoughtMaker.MakeThought(actorThoughtDef);
                            }
                            if (actorThought != null)
                            {
                                actor.needs.mood.thoughts.memories.TryGainMemory(actorThought);
                            }
                        }


                        if (workLeft <= 0f)
                        {
                            if (actor?.VampComp() is CompVampire v && v.IsVampire && actor.Faction == Faction.OfPlayer)
                            {
                                MoteMaker.ThrowText(actor.DrawPos, actor.Map, "XP +" + 15);
                                v.XP    += 15;
                                workLeft = BaseFeedTime;
                                MoteMaker.MakeColonistActionOverlay(actor, ThingDefOf.Mote_ColonistAttacking);
                            }

                            effect();
                            if (victim != null && !victim.Dead && needsGrapple)
                            {
                                int victimBonus = (victim.VampComp() is CompVampire victimVampComp) ? -victimVampComp.Generation + 14 : 0;
                                int actorBonus  = 0;
                                if (actor?.VampComp() is CompVampire v2 && v2.IsVampire)
                                {
                                    actorBonus = -v2.Generation + 14;
                                }
                                if (!JecsTools.GrappleUtility.TryGrapple(actor, victim, actorBonus, victimBonus))
                                {
                                    thisDriver.EndJobWith(JobCondition.Incompletable);
                                }
                            }

                            if (!stopCondition(actor, victim))
                            {
                                thisDriver.ReadyForNextToil();
                                if (actor.IsVampire() && cleansWound)
                                {
                                    VampireBiteUtility.CleanBite(actor, victim);
                                }
                            }
                            else
                            {
                                if (victim != null && !victim.Dead)
                                {
                                    victim.stances.stunner.StunFor((int)BaseFeedTime, actor);
                                    PawnUtility.ForceWait((Pawn)TargetA.Thing, (int)BaseFeedTime, actor);
                                }
                            }
                        }
                    }