Пример #1
0
        protected override bool TryCastShot()
        {
            CellRect cellRect = CellRect.CenteredOn(this.currentTarget.Cell, 1);
            Map      map      = base.CasterPawn.Map;

            cellRect.ClipInsideMap(map);

            IntVec3 centerCell      = cellRect.CenterCell;
            Thing   summonableThing = new Thing();
            //FlyingObject flyingPawn = new FlyingObject();
            Pawn summonablePawn = new Pawn();

            bool pflag = true;

            summonableThing = centerCell.GetFirstPawn(map);
            if (summonableThing == null)
            {
                pflag           = false;
                summonableThing = centerCell.GetFirstItem(map);
            }
            else
            {
                pVect          = summonableThing.TrueCenter();
                pVect.x        = base.caster.TrueCenter().x;
                pVect.z        = base.caster.TrueCenter().z;
                pVect.y        = 0f;
                summonablePawn = summonableThing as Pawn;
                if (summonablePawn != base.CasterPawn)
                {
                    //flyingPawn = (FlyingObject)GenSpawn.Spawn(ThingDef.Named("TM_SummonedPawn"), summonableThing.Position, summonableThing.Map);
                }
                else
                {
                    //flyingPawn = null;
                    summonableThing = null;
                    Messages.Message("TM_CantSummonSelf".Translate(), MessageTypeDefOf.NegativeEvent);
                }
            }

            bool result = false;
            bool arg_40_0;

            if (this.currentTarget != null && base.CasterPawn != null)
            {
                IntVec3 arg_29_0 = this.currentTarget.Cell;
                arg_40_0 = this.currentTarget.Cell.IsValid;
            }
            else
            {
                arg_40_0 = false;
            }
            bool flag = arg_40_0;

            if (flag)
            {
                if (summonableThing != null)
                {
                    if (pflag)// && flyingPawn != null)
                    {
                        //Thing p = summonablePawn;
                        if (!summonablePawn.RaceProps.Humanlike || summonablePawn.Faction == this.CasterPawn.Faction)
                        {
                            summonablePawn.DeSpawn();
                            GenSpawn.Spawn(summonablePawn, base.CasterPawn.Position, map);
                        }
                        else if (summonablePawn.RaceProps.Humanlike && summonablePawn.Faction != this.CasterPawn.Faction && Rand.Chance(TM_Calc.GetSpellSuccessChance(this.CasterPawn, summonablePawn, true)))
                        {
                            //summonablePawn.DeSpawn();
                            //GenSpawn.Spawn(p, base.caster.Position, base.CasterPawn.Map, Rot4.North, false);

                            //Pawn p = summonablePawn;
                            summonablePawn.DeSpawn();
                            //p.SetPositionDirect(this.currentTarget.Cell);
                            GenSpawn.Spawn(summonablePawn, base.CasterPawn.Position, map);
                            //flyingPawn = null;

                            //summonablePawn.Position = base.CasterPawn.Position;
                            //p.jobs.StopAll(false);
                        }
                        else
                        {
                            MoteMaker.ThrowText(summonablePawn.DrawPos, summonablePawn.Map, "TM_ResistedSpell".Translate(), -1);
                        }
                    }
                    else
                    {
                        summonableThing.DeSpawn(DestroyMode.Vanish);
                        GenPlace.TryPlaceThing(summonableThing, this.CasterPawn.Position, this.CasterPawn.Map, ThingPlaceMode.Near);
                        //summonableThing.Position = base.CasterPawn.Position;
                        //summonableThing.Rotation = Rot4.North;
                        //summonableThing.SetPositionDirect(base.CasterPawn.InteractionCell);
                    }
                    result = true;
                }
            }
            else
            {
                Log.Warning("failed to TryCastShot");
            }
            this.burstShotsLeft = 0;
            //this.ability.TicksUntilCasting = (int)base.UseAbilityProps.SecondsToRecharge * 60;
            return(result);
        }
Пример #2
0
        public static bool TryPlaceThing(ref bool __result,
                                         Thing thing,
                                         IntVec3 center,
                                         Map map,
                                         ThingPlaceMode mode,
                                         out Thing lastResultingThing,
                                         Action <Thing, int> placedAction       = null,
                                         Predicate <IntVec3> nearPlaceValidator = null,
                                         Rot4 rot = default(Rot4))
        {
            if (map == null)
            {
                Log.Error("Tried to place thing " + (object)thing + " in a null map.");
                lastResultingThing = (Thing)null;
                __result           = false;
                return(false);
            }
            if (thing == null)
            {
                lastResultingThing = null;
                __result           = false;
                return(false);
            }
            ThingDef def = thing.def;

            if (def == null)
            {
                lastResultingThing = null;
                __result           = false;
                return(false);
            }
            if (def.category == ThingCategory.Filth)
            {
                mode = ThingPlaceMode.Direct;
            }
            if (mode == ThingPlaceMode.Direct)
            {
                return(GenPlace.TryPlaceDirect(thing, center, rot, map, out lastResultingThing, placedAction));
            }
            if (mode != ThingPlaceMode.Near)
            {
                throw new InvalidOperationException();
            }
            lastResultingThing = (Thing)null;
            int stackCount;

            do
            {
                stackCount = thing.stackCount;
                IntVec3 bestSpot;
                if (!GenPlace.TryFindPlaceSpotNear(center, rot, map, thing, true, out bestSpot, nearPlaceValidator))
                {
                    return(false);
                }
                if (GenPlace.TryPlaceDirect(thing, bestSpot, rot, map, out lastResultingThing, placedAction))
                {
                    return(true);
                }
            }while (thing.stackCount != stackCount);
            Log.Error("Failed to place " + (object)thing + " at " + (object)center + " in mode " + (object)mode + ".");
            lastResultingThing = (Thing)null;
            __result           = false;
            return(false);
        }
Пример #3
0
        // Always use this if you are placing an item.
        /// <summary>
        /// Place a Thing (onto the ground or into a proper receptacle)
        /// Any time ANY PRF building tries to place an item, this is THE way to do it:
        ///   It checks if the space is clear, it checks for conveyor belts, in checks
        ///   for other storage mods (well, Deep Storage, anyway).  It does all the
        ///   things!
        /// </summary>
        /// <returns><c>true</c>, if item was placed, <c>false</c> if it could not.</returns>
        /// <param name="placer">The PRF_Building doing the placing</param>
        /// <param name="t">Thing to place.</param>
        /// <param name="cell">Where to place.</param>
        /// <param name="map">Map.</param>
        /// <param name="forcePlace">If set to <c>true</c>, forces placing. For when
        ///   you absolutely positively have to put it down.</param>
        public static bool PRFTryPlaceThing(this IPRF_Building placer, Thing t, IntVec3 cell, Map map,
                                            bool forcePlace = false)
        {
            // Storage:
            SlotGroup slotGroup = cell.GetSlotGroup(map);

            if (slotGroup != null)
            {
                Debug.Warning(Debug.Flag.PlaceThing, "Placing " + t + " in slotGroup: " + slotGroup.parent + " at " + cell);
                if (slotGroup.parent is IPRF_Building)
                {
                    if (placer.PlaceThingNextBuilding((slotGroup.parent as IPRF_Building),
                                                      t, cell, map))
                    {
                        Debug.Message(Debug.Flag.PlaceThing, "  which is owned by PRF " + slotGroup.parent);
                        return(true);
                    }
                    if (forcePlace)
                    {
                        goto ForcePlace;
                    }
                    return(false);
                }
                if (placer.PlaceThingInSlotGroup(t, slotGroup, cell, map))
                {
                    return(true);
                }
                if (forcePlace)
                {
                    goto ForcePlace;
                }
                return(false);
            }
            Debug.Warning(Debug.Flag.PlaceThing, "Place request: " + placer == null ? "NoPlacer" : placer.ToString() + " is trying to place " + t + " at " + cell);
            // Search through all items in cell: see if any will absorb
            //   our thing.  If we find a PRF_Building, stop looking and
            //   try to pass it on.
            bool cellIsImpassible = false;

            foreach (Thing otherThing in map.thingGrid.ThingsListAt(cell))
            {
                if (otherThing.TryAbsorbStack(t, true))
                {
                    Debug.Message(Debug.Flag.PlaceThing, "  absorbed by " + otherThing);
                    placer.EffectOnPlaceThing(otherThing); // I think?
                    return(true);
                }
                if (otherThing.def.passability == Traversability.Impassable)
                {
                    cellIsImpassible = true;
                }
                if (otherThing is IPRF_Building)
                {
                    if (placer.PlaceThingNextBuilding((otherThing as IPRF_Building),
                                                      t, cell, map))
                    {
                        Debug.Message(Debug.Flag.PlaceThing, placer +
                                      " gave " + t + " to " + otherThing);
                        placer.EffectOnPlaceThing(t);
                        return(true);
                    }
                    // Continue loop - may be more than 1 PRF_Building here
                }
            }
            // There is no IPRF Building to take this from us
            if (cellIsImpassible)
            {
                Debug.Message(Debug.Flag.PlaceThing, "  cell is impassable.");
                if (forcePlace)
                {
                    goto ForcePlace;
                }
                return(false);
            }
            // The cell is not impassible! Try to place:
            if (CallNoStorageBlockersIn(cell, map, t))
            {
                Debug.Message(Debug.Flag.PlaceThing, "  placing directly.");
                bool wasSpawned = t.Spawned;
                if (wasSpawned)
                {
                    t.DeSpawn();
                }
                if (!GenPlace.TryPlaceThing(t, cell, map, ThingPlaceMode.Direct))
                {
                    // some of the stack
                    Debug.Message(Debug.Flag.PlaceThing, "  some absorbed, still have " + t.stackCount + " left");
                    // I think this is safe, as it shoudl still have its position?
                    if (wasSpawned)
                    {
                        GenPlace.TryPlaceThing(t, t.Position, map, ThingPlaceMode.Near);
                    }
                    placer.EffectOnPlaceThing(t);
                    if (forcePlace)
                    {
                        goto ForcePlace;
                    }
                    return(false);
                }
                placer.EffectOnPlaceThing(t);
                if (placer.ForbidOnPlacing(t))
                {
                    t.SetForbidden(true, false);
                }
                return(true);
            }
            if (!forcePlace)
            {
                return(false);
            }
ForcePlace:
            Debug.Warning(Debug.Flag.PlaceThing, "  Placement is forced!");
            if (t.Spawned)
            {
                t.DeSpawn();
            }
            GenPlace.TryPlaceThing(t, cell, map, ThingPlaceMode.Near);
            placer.EffectOnPlaceThing(t);
            if (placer.ForbidOnPlacing(t))
            {
                t.SetForbidden(true, false);
            }
            return(true);
        }
Пример #4
0
        protected override IEnumerable <Toil> MakeNewToils()
        {
            Init();
            yield return(Toils_JobTransforms.MoveCurrentTargetIntoQueue(TargetIndex.A));

            Toil initExtractTargetFromQueue = Toils_JobTransforms.ClearDespawnedNullOrForbiddenQueuedTargets(TargetIndex.A);

            yield return(initExtractTargetFromQueue);

            yield return(Toils_JobTransforms.SucceedOnNoTargetInQueue(TargetIndex.A));

            yield return(Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A, true));

            yield return(Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch).JumpIfDespawnedOrNullOrForbidden(TargetIndex.A, initExtractTargetFromQueue));

            Toil  cut   = new Toil();
            Plant plant = (Plant)Thing;
            CompHarvestableReagent reagent = Thing.TryGetComp <CompHarvestableReagent>();

            cut.tickAction = delegate
            {
                Pawn actor = cut.actor;
                if (actor.skills != null)
                {
                    actor.skills.Learn(DefDatabase <SkillDef> .GetNamed("Alchemy", true), xpPerTick, false);
                }
                float statValue = actor.GetStatValue(DefDatabase <StatDef> .GetNamed("ReagentHarvestingSpeed"), true);
                float num       = statValue;
                workDone += num;
                if (!reagent.IsSecondaryHarvest)
                {
                    if (plant != null)
                    {
                        if (workDone >= plant.def.plant.harvestWork)
                        {
                            if (plant.def.plant.harvestedThingDef != null)
                            {
                                if (actor.RaceProps.Humanlike && plant.def.plant.harvestFailable && Rand.Value > actor.GetStatValue(DefDatabase <StatDef> .GetNamed("ReagentHarvestingYield"), true))
                                {
                                    Vector3 loc = (pawn.DrawPos + plant.DrawPos) / 2f;
                                    MoteMaker.ThrowText(loc, Map, "TextMote_ReagentHarvestFailed".Translate(), 3.65f);
                                }
                                else
                                {
                                    int num2 = plant.YieldNow();
                                    if (num2 > 0)
                                    {
                                        Thing harvestedThing = ThingMaker.MakeThing(plant.def.plant.harvestedThingDef, null);
                                        harvestedThing.stackCount = num2;
                                        if (actor.Faction != Faction.OfPlayer)
                                        {
                                            harvestedThing.SetForbidden(true, true);
                                        }
                                        GenPlace.TryPlaceThing(harvestedThing, actor.Position, Map, ThingPlaceMode.Near, null);
                                        actor.records.Increment(DefDatabase <RecordDef> .GetNamed("ReagentsHarvested"));
                                    }
                                }
                            }
                            plant.def.plant.soundHarvestFinish.PlayOneShot(actor);
                            plant.PlantCollected();
                            workDone = 0f;
                            ReadyForNextToil();
                            return;
                        }
                    }
                    // Animal
                    // Inanimate
                }
                else
                {
                    if (workDone >= reagent.HarvestWork)
                    {
                        if (reagent.HarvestedThingDef != null)
                        {
                            if (actor.RaceProps.Humanlike && reagent.HarvestFailable && Rand.Value > actor.GetStatValue(DefDatabase <StatDef> .GetNamed("ReagentHarvestingYield"), true))
                            {
                                Vector3 loc = (pawn.DrawPos + reagent.parent.DrawPos) / 2f;
                                MoteMaker.ThrowText(loc, Map, "TextMote_ReagentHarvestFailed".Translate(), 3.65f);
                            }
                            else
                            {
                                int num2 = reagent.YieldNow();
                                if (num2 > 0)
                                {
                                    Thing harvestedThing = ThingMaker.MakeThing(reagent.HarvestedThingDef, null);
                                    harvestedThing.stackCount = num2;
                                    if (actor.Faction != Faction.OfPlayer)
                                    {
                                        harvestedThing.SetForbidden(true, true);
                                    }
                                    GenPlace.TryPlaceThing(harvestedThing, actor.Position, Map, ThingPlaceMode.Near, null);
                                    actor.records.Increment(DefDatabase <RecordDef> .GetNamed("ReagentsHarvested"));
                                }
                            }
                        }
                        if (plant != null)
                        {
                            plant.def.plant.soundHarvestFinish.PlayOneShot(actor);
                        }

                        reagent.ReagentCollected(actor);
                        workDone = 0f;
                        ReadyForNextToil();
                        return;
                    }
                }
            };
            cut.FailOnDespawnedNullOrForbidden(TargetIndex.A);
            cut.FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);
            cut.defaultCompleteMode = ToilCompleteMode.Never;
            cut.WithEffect(EffecterDefOf.Harvest, TargetIndex.A);
            if (!reagent.IsSecondaryHarvest)
            {
                if (plant != null)
                {
                    cut.WithProgressBar(TargetIndex.A, () => workDone / plant.def.plant.harvestWork, true, -0.5f);
                    cut.PlaySustainerOrSound(() => plant.def.plant.soundHarvesting);
                }

                // Animals
            }
            else
            {
                cut.WithProgressBar(TargetIndex.A, () => workDone / reagent.HarvestWork, true, -0.5f);
                if (plant != null)
                {
                    cut.PlaySustainerOrSound(() => plant.def.plant.soundHarvesting);
                }
            }

            yield return(cut);

            Toil workDoneToil = WorkDoneToil();

            if (workDoneToil != null)
            {
                yield return(workDoneToil);
            }
            yield return(Toils_Jump.Jump(initExtractTargetFromQueue));
        }
Пример #5
0
        protected virtual void Impact(Thing hitThing)
        {
            bool flag = hitThing == null;

            if (flag)
            {
                Pawn pawn;
                bool flag2 = (pawn = (base.Position.GetThingList(base.Map).FirstOrDefault((Thing x) => x == this.assignedTarget) as Pawn)) != null;
                if (flag2)
                {
                    hitThing = pawn;
                }
            }
            bool hasValue = this.impactDamage.HasValue;

            if (hasValue)
            {
                hitThing.TakeDamage(this.impactDamage.Value);
            }
            try
            {
                SoundDefOf.Ambient_AltitudeWind.sustainFadeoutTime.Equals(30.0f);

                GenSpawn.Spawn(this.flyingThing, base.Position, base.Map);

                if (this.flyingThing is Pawn)
                {
                    Pawn p = this.flyingThing as Pawn;
                    if (p.IsColonist && this.drafted)
                    {
                        p.drafter.Drafted = true;
                    }
                    if (this.earlyImpact)
                    {
                        damageEntities(p, this.impactForce, DamageDefOf.Blunt);
                        damageEntities(p, 2 * this.impactForce, DamageDefOf.Stun);
                    }
                }
                else if (flyingThing.def.thingCategories != null && (flyingThing.def.thingCategories.Contains(ThingCategoryDefOf.Chunks) || flyingThing.def.thingCategories.Contains(ThingCategoryDef.Named("StoneChunks"))))
                {
                    float   radius = 4f;
                    Vector3 center = this.ExactPosition;
                    if (this.earlyImpact)
                    {
                        bool    wallFlag90neg = false;
                        IntVec3 wallCheck     = (center + (Quaternion.AngleAxis(-90, Vector3.up) * this.direction)).ToIntVec3();
                        MoteMaker.ThrowMicroSparks(wallCheck.ToVector3Shifted(), base.Map);
                        wallFlag90neg = wallCheck.Walkable(base.Map);

                        wallCheck = (center + (Quaternion.AngleAxis(90, Vector3.up) * this.direction)).ToIntVec3();
                        MoteMaker.ThrowMicroSparks(wallCheck.ToVector3Shifted(), base.Map);
                        bool wallFlag90 = wallCheck.Walkable(base.Map);

                        if ((!wallFlag90 && !wallFlag90neg) || (wallFlag90 && wallFlag90neg))
                        {
                            //fragment energy bounces in reverse direction of travel
                            center = center + ((Quaternion.AngleAxis(180, Vector3.up) * this.direction) * 3);
                        }
                        else if (wallFlag90)
                        {
                            center = center + ((Quaternion.AngleAxis(90, Vector3.up) * this.direction) * 3);
                        }
                        else if (wallFlag90neg)
                        {
                            center = center + ((Quaternion.AngleAxis(-90, Vector3.up) * this.direction) * 3);
                        }
                    }

                    List <IntVec3> damageRing  = GenRadial.RadialCellsAround(base.Position, radius, true).ToList();
                    List <IntVec3> outsideRing = GenRadial.RadialCellsAround(base.Position, radius, false).Except(GenRadial.RadialCellsAround(base.Position, radius - 1, true)).ToList();
                    for (int i = 0; i < damageRing.Count; i++)
                    {
                        List <Thing> allThings = damageRing[i].GetThingList(base.Map);
                        for (int j = 0; j < allThings.Count; j++)
                        {
                            if (allThings[j] is Pawn)
                            {
                                damageEntities(allThings[j], Rand.Range(14, 22), DamageDefOf.Blunt);
                            }
                            else if (allThings[j] is Building)
                            {
                                damageEntities(allThings[j], Rand.Range(56, 88), DamageDefOf.Blunt);
                            }
                            else
                            {
                                if (Rand.Chance(.1f))
                                {
                                    GenPlace.TryPlaceThing(ThingMaker.MakeThing(ThingDefOf.Filth_RubbleRock), damageRing[i], base.Map, ThingPlaceMode.Near);
                                }
                            }
                        }
                    }
                    for (int i = 0; i < outsideRing.Count; i++)
                    {
                        IntVec3 intVec = outsideRing[i];
                        if (intVec.IsValid && intVec.InBounds(base.Map))
                        {
                            Vector3 moteDirection = TM_Calc.GetVector(this.ExactPosition.ToIntVec3(), intVec);
                            TM_MoteMaker.ThrowGenericMote(ThingDef.Named("Mote_Rubble"), this.ExactPosition, base.Map, Rand.Range(.3f, .6f), .2f, .02f, .05f, Rand.Range(-100, 100), Rand.Range(8f, 13f), (Quaternion.AngleAxis(90, Vector3.up) * moteDirection).ToAngleFlat(), 0);
                            TM_MoteMaker.ThrowGenericMote(ThingDefOf.Mote_Smoke, this.ExactPosition, base.Map, Rand.Range(.9f, 1.2f), .3f, .02f, Rand.Range(.25f, .4f), Rand.Range(-100, 100), Rand.Range(5f, 8f), (Quaternion.AngleAxis(90, Vector3.up) * moteDirection).ToAngleFlat(), 0);
                            GenExplosion.DoExplosion(intVec, base.Map, .4f, DamageDefOf.Blunt, pawn, 0, 0, SoundDefOf.Pawn_Melee_Punch_HitBuilding, null, null, null, ThingDefOf.Filth_RubbleRock, .4f, 1, false, null, 0f, 1, 0, false);
                            //MoteMaker.ThrowSmoke(intVec.ToVector3Shifted(), base.Map, Rand.Range(.6f, 1f));
                        }
                    }
                    //damageEntities(this.flyingThing, 305, DamageDefOf.Blunt);
                    this.flyingThing.Destroy(DestroyMode.Vanish);
                }
                this.Destroy(DestroyMode.Vanish);
            }
            catch
            {
                if (!this.flyingThing.Spawned)
                {
                    GenSpawn.Spawn(this.flyingThing, base.Position, base.Map);
                }
                if (this.flyingThing is Pawn)
                {
                    Pawn p = this.flyingThing as Pawn;
                }
                this.Destroy(DestroyMode.Vanish);
            }
        }
        protected override IEnumerable <Toil> MakeNewToils()
        {
            this.Init();
            yield return(Toils_JobTransforms.MoveCurrentTargetIntoQueue(TargetIndex.A));

            Toil initExtractTargetFromQueue = Toils_JobTransforms.ClearDespawnedNullOrForbiddenQueuedTargets(TargetIndex.A, (this.RequiredDesignation == null) ? null : new Func <Thing, bool>((Thing t) => this.Map.designationManager.DesignationOn(t, this.RequiredDesignation) != null));

            yield return(initExtractTargetFromQueue);

            yield return(Toils_JobTransforms.SucceedOnNoTargetInQueue(TargetIndex.A));

            yield return(Toils_JobTransforms.ExtractNextTargetFromQueue(TargetIndex.A, true));

            Toil gotoThing = Toils_Goto.GotoThing(TargetIndex.A, PathEndMode.Touch).JumpIfDespawnedOrNullOrForbidden(TargetIndex.A, initExtractTargetFromQueue);

            if (this.RequiredDesignation != null)
            {
                gotoThing.FailOnThingMissingDesignation(TargetIndex.A, this.RequiredDesignation);
            }
            yield return(gotoThing);

            Toil cut = new Toil();

            cut.tickAction = delegate()
            {
                Pawn actor = cut.actor;
                SurvivalToolUtility.TryDegradeTool(actor, ST_StatDefOf.TreeFellingSpeed);
                if (actor.skills != null)
                {
                    actor.skills.Learn(SkillDefOf.Plants, this.xpPerTick, false);
                }
                float statValue = actor.GetStatValue(ST_StatDefOf.TreeFellingSpeed, true);
                float num       = statValue;
                Plant plant     = this.Plant;
                num           *= Mathf.Lerp(3.3f, 1f, plant.Growth);
                this.workDone += num;
                if (this.workDone >= plant.def.plant.harvestWork)
                {
                    if (plant.def.plant.harvestedThingDef != null)
                    {
                        if (actor.RaceProps.Humanlike && plant.def.plant.harvestFailable && Rand.Value > actor.GetStatValue(StatDefOf.PlantHarvestYield, true))
                        {
                            Vector3 loc = (this.pawn.DrawPos + plant.DrawPos) / 2f;
                            MoteMaker.ThrowText(loc, this.Map, "TextMote_HarvestFailed".Translate(), 3.65f);
                        }
                        else
                        {
                            int num2 = plant.YieldNow();
                            if (num2 > 0)
                            {
                                Thing thing = ThingMaker.MakeThing(plant.def.plant.harvestedThingDef, null);
                                thing.stackCount = num2;
                                if (actor.Faction != Faction.OfPlayer)
                                {
                                    thing.SetForbidden(true, true);
                                }
                                GenPlace.TryPlaceThing(thing, actor.Position, this.Map, ThingPlaceMode.Near, null, null);
                                actor.records.Increment(RecordDefOf.PlantsHarvested);
                            }
                        }
                    }
                    plant.def.plant.soundHarvestFinish.PlayOneShot(actor);
                    plant.PlantCollected();
                    this.workDone = 0f;
                    this.ReadyForNextToil();
                    return;
                }
            };
            cut.FailOnDespawnedNullOrForbidden(TargetIndex.A);
            if (this.RequiredDesignation != null)
            {
                cut.FailOnThingMissingDesignation(TargetIndex.A, this.RequiredDesignation);
            }
            cut.FailOnCannotTouch(TargetIndex.A, PathEndMode.Touch);
            cut.defaultCompleteMode = ToilCompleteMode.Never;
            cut.WithEffect(EffecterDefOf.Harvest, TargetIndex.A);
            cut.WithProgressBar(TargetIndex.A, () => this.workDone / this.Plant.def.plant.harvestWork, true, -0.5f);
            cut.PlaySustainerOrSound(() => this.Plant.def.plant.soundHarvesting);
            cut.activeSkill = (() => SkillDefOf.Plants);
            yield return(cut);

            Toil plantWorkDoneToil = this.PlantWorkDoneToil();

            if (plantWorkDoneToil != null)
            {
                yield return(plantWorkDoneToil);
            }
            yield return(Toils_Jump.Jump(initExtractTargetFromQueue));

            yield break;
        }
        protected override Toil DoBill()
        {
            var tableThing           = job.GetTarget(BillGiverInd).Thing as Building_WorkTable;
            var tablePowerTraderComp = tableThing.GetComp <CompPowerTrader> ();

            var toil = new Toil();

            toil.initAction = delegate {
                var objectThing = job.GetTarget(IngredientInd).Thing;

                job.bill.Notify_DoBillStarted(pawn);

                costHitPointsPerCycle = (int)(objectThing.MaxHitPoints * Settings.costFromMaxHitPoints);
                processedHitPoints    = 0;

                workCycleProgress = workCycle = Math.Max(job.bill.recipe.workAmount, 10f);
            };
            toil.tickAction = delegate {
                var objectThing = job.GetTarget(IngredientInd).Thing;

                if (objectThing == null || objectThing.Destroyed)
                {
                    pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
                }

                workCycleProgress -= StatExtension.GetStatValue(pawn, StatDefOf.WorkToMake, true);

                tableThing.UsedThisTick();
                if (!tableThing.CurrentlyUsableForBills())
                {
                    pawn.jobs.EndCurrentJob(JobCondition.Incompletable);
                }

                if (workCycleProgress <= 0)
                {
                    objectThing.HitPoints -= costHitPointsPerCycle;

                    if (tablePowerTraderComp != null && tablePowerTraderComp.PowerOn)
                    {
                        processedHitPoints += costHitPointsPerCycle;
                    }
                    else
                    {
                        processedHitPoints += costHitPointsPerCycle / 2;
                    }

                    float skillPerc = 0.5f;

                    var skillDef = job.RecipeDef.workSkill;
                    if (skillDef != null)
                    {
                        var skill = pawn.skills.GetSkill(skillDef);

                        if (skill != null)
                        {
                            skillPerc = (float)skill.Level / 20f;

                            skill.Learn(0.11f * job.RecipeDef.workSkillLearnFactor);
                        }
                    }

                    if (Settings.chances[objectThing.def.techLevel] > 1 - Mathf.Pow(Rand.Value, 1 + skillPerc * 3f))
                    {
                        objectThing.HitPoints -= Rand.RangeInclusive(costHitPointsPerCycle, costHitPointsPerCycle * 4);

                        MoteMaker.ThrowText(pawn.DrawPos, pawn.Map, "Failed");
                    }

                    pawn.GainComfortFromCellIfPossible();

                    if (objectThing.HitPoints <= 0)
                    {
                        pawn.Map.reservationManager.Release(job.targetB, pawn, job);
                        objectThing.Destroy(DestroyMode.Vanish);

                        float skillFactor  = Mathf.Lerp(0.5f, 1.5f, skillPerc);
                        float healthPerc   = (float)processedHitPoints / (float)objectThing.MaxHitPoints;
                        float healthFactor = Mathf.Lerp(0f, 0.4f, healthPerc);

                        var list = JobDriverUtils.Reclaim(objectThing, skillFactor * healthFactor);

                        if (list.Count > 1)
                        {
                            for (int j = 1; j < list.Count; j++)
                            {
                                if (!GenPlace.TryPlaceThing(list [j], pawn.Position, pawn.Map, ThingPlaceMode.Near, null))
                                {
                                    Log.Error("MendAndRecycle :: " + pawn + " could not drop recipe product " + list [j] + " near " + pawn.Position);
                                }
                            }
                        }

                        if (list.Count >= 1)
                        {
                            list [0].SetPositionDirect(pawn.Position);

                            job.bill.Notify_IterationCompleted(pawn, list);
                            job.SetTarget(IngredientInd, list[0]);

                            pawn.Map.reservationManager.Reserve(pawn, job, job.GetTarget(IngredientInd), 1);

                            ReadyForNextToil();
                        }
                        else
                        {
                            Log.Message("MendAndRecycle :: " + pawn + " could not reclaim anything from " + objectThing);

                            pawn.jobs.EndCurrentJob(JobCondition.Succeeded);
                        }
                    }

                    workCycleProgress = workCycle;
                }
            };
            toil.defaultCompleteMode = ToilCompleteMode.Never;
            toil.WithEffect(() => job.bill.recipe.effectWorking, BillGiverInd);
            toil.PlaySustainerOrSound(() => toil.actor.CurJob.bill.recipe.soundWorking);
            toil.WithProgressBar(BillGiverInd, delegate {
                var objectThing = job.GetTarget(IngredientInd).Thing;

                return((float)objectThing.HitPoints / (float)objectThing.MaxHitPoints);
            }, false, 0.5f);
            toil.FailOn(() => {
                return(toil.actor.CurJob.bill.suspended || !tableThing.CurrentlyUsableForBills());
            });
            return(toil);
        }