public Toil Cultivate()
        {
            var targetCell = CurJob.targetA.Cell;

            var toil = new Toil();
            toil.initAction = () =>
            {
                workTicks = Mathf.RoundToInt(terrainReplacements[targetCell.GetTerrain()].GetStatValueAbstract(StatDefOf.WorkToMake) * pawn.GetStatValue(StatDefOf.PlantWorkSpeed));
                pawn.jobs.curDriver.ticksLeftThisToil = workTicks;
            };
            toil.tickAction = () =>
            {
                if (--pawn.jobs.curDriver.ticksLeftThisToil < 0)
                {
                    // remove designation
                    var designation = Find.DesignationManager.DesignationAt(targetCell,
                        DefDatabase<DesignationDef>.GetNamed("CultivateLand"));
                    if (designation != null)
                    {
                        Find.DesignationManager.RemoveDesignation(designation);
                    }

                    // replace terrain
                    Find.TerrainGrid.SetTerrain(targetCell, terrainReplacements[targetCell.GetTerrain()]);

                    ReadyForNextToil();
                }
            };
            toil.defaultCompleteMode = ToilCompleteMode.Never;
            toil.FailOnCellMissingDesignation(CellInd, DefDatabase<DesignationDef>.GetNamed("CultivateLand"));
            toil.WithEffect(() => EffecterDef.Named("CutStone"), CellInd);
            toil.PlaySustainerOrSound(() => DefDatabase<SoundDef>.GetNamedSilentFail("Recipe_Surgery"));
            toil.WithProgressBar(CellInd, () => 1f - (float) pawn.jobs.curDriver.ticksLeftThisToil/workTicks);
            return toil;
        }
        public Toil CollectSand(int ticksToCollect)
        {
            var targetCell = CurJob.targetA.Cell;

            var toil = new Toil();
            toil.initAction = () =>
            {
                pawn.jobs.curDriver.ticksLeftThisToil =
                    Mathf.RoundToInt(ticksToCollect*pawn.GetStatValue(StatDef.Named("CollectingSpeed")));
            };
            toil.AddFinishAction(() =>
            {
                // remove designation
                var designation = Find.DesignationManager.DesignationAt(targetCell,
                    DefDatabase<DesignationDef>.GetNamed("CollectSand"));
                if (designation != null)
                {
                    Find.DesignationManager.RemoveDesignation(designation);
                }

                // replace terrain
                if (Find.TerrainGrid.TerrainAt(targetCell) == TerrainDef.Named("Sand"))
                    Find.TerrainGrid.SetTerrain(targetCell, DefDatabase<TerrainDef>.GetNamed("Gravel"));

                // spawn resources
                var SandYellow = ThingMaker.MakeThing(ThingDef.Named("PileSandYellow"));
                SandYellow.stackCount = Rand.RangeInclusive(20, 30);
                GenPlace.TryPlaceThing(SandYellow, targetCell, ThingPlaceMode.Near);

                // Rand.Value = Rand.Range(0, 1)
                if (Rand.Value < RareResourceSpawnChance)
                {
                    var SandWhite = ThingMaker.MakeThing(ThingDef.Named("PileSandWhite"));
                    SandWhite.stackCount = Rand.RangeInclusive(5, 10);
                    GenPlace.TryPlaceThing(SandWhite, targetCell, ThingPlaceMode.Near);
                }
            });
            toil.defaultCompleteMode = ToilCompleteMode.Delay;
            toil.FailOnCellMissingDesignation(CellInd, DefDatabase<DesignationDef>.GetNamed("CollectSand"));
            toil.WithEffect(() => EffecterDef.Named("CutStone"), CellInd);
            return toil;
        }
        public Toil CollectClay(int ticksToCollect)
        {
            var targetCell = CurJob.targetA.Cell;

            var toil = new Toil();
            toil.initAction = () =>
            {
                pawn.jobs.curDriver.ticksLeftThisToil =
                    Mathf.RoundToInt(ticksToCollect*pawn.GetStatValue(StatDef.Named("CollectingSpeed")));
                totalWork = pawn.jobs.curDriver.ticksLeftThisToil;
            };
            toil.tickAction = () =>
            {
                if (--pawn.jobs.curDriver.ticksLeftThisToil < 0)
                {
                    // remove designation
                    var designation = Find.DesignationManager.DesignationAt(targetCell,
                        DefDatabase<DesignationDef>.GetNamed("CollectClay"));
                    if (designation != null)
                    {
                        Find.DesignationManager.RemoveDesignation(designation);
                    }

                    // replace terrain
                    if (Find.TerrainGrid.TerrainAt(targetCell) == TerrainDef.Named("Mud"))
                        Find.TerrainGrid.SetTerrain(targetCell, DefDatabase<TerrainDef>.GetNamed("Soil"));
                    if (Find.TerrainGrid.TerrainAt(targetCell) == TerrainDef.Named("SoilRich"))
                        Find.TerrainGrid.SetTerrain(targetCell, DefDatabase<TerrainDef>.GetNamed("Soil"));
                    if (Find.TerrainGrid.TerrainAt(targetCell) == TerrainDef.Named("WaterShallow"))
                    {
                        Find.TerrainGrid.SetTerrain(targetCell, DefDatabase<TerrainDef>.GetNamed("WaterDeep"));

                        var list = new List<Thing>(Find.ThingGrid.ThingsListAtFast(targetCell)
                            .Where(thing => thing.def.category == ThingCategory.Item ||
                                            thing.def.category == ThingCategory.Pawn));
                        foreach (var thing in list)
                        {
                            Thing dummy;
                            // despawn thing to spawn again with TryPlaceThing
                            thing.DeSpawn();
                            if (!GenPlace.TryPlaceThing(thing, thing.Position, ThingPlaceMode.Near, out dummy))
                            {
                                Log.Error("No free spot for " + thing);
                            }
                        }
                    }

                    // spawn resources
                    var clayRed = ThingMaker.MakeThing(ThingDef.Named("ClumpClayGray"));
                    clayRed.stackCount = Rand.RangeInclusive(25, 75);
                    GenPlace.TryPlaceThing(clayRed, targetCell, ThingPlaceMode.Near);

                    // Rand.Value = Rand.Range(0, 1)
                    if (Rand.Value < RareResourceSpawnChance)
                    {
                        var clayWhite = ThingMaker.MakeThing(ThingDef.Named("ClumpClayWhite"));
                        clayWhite.stackCount = Rand.RangeInclusive(5, 10);
                        GenPlace.TryPlaceThing(clayWhite, targetCell, ThingPlaceMode.Near);
                    }

                    ReadyForNextToil();
                }
            };
            toil.defaultCompleteMode = ToilCompleteMode.Never;
            toil.FailOnCellMissingDesignation(CellInd, DefDatabase<DesignationDef>.GetNamed("CollectClay"));
            toil.WithEffect(() => EffecterDef.Named("CutStone"), CellInd);
            toil.PlaySustainerOrSound(() => DefDatabase<SoundDef>.GetNamedSilentFail("Recipe_Surgery"));
            toil.WithProgressBar(CellInd, () => 1f - (float) pawn.jobs.curDriver.ticksLeftThisToil/totalWork);
            return toil;
        }