public static Toil FinishRecipeAndStartStoringProduct() { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; JobDriver_DoBill jobDriver_DoBill = (JobDriver_DoBill)actor.jobs.curDriver; if (curJob.RecipeDef.workSkill != null && !curJob.RecipeDef.UsesUnfinishedThing) { float xp = (float)jobDriver_DoBill.ticksSpentDoingRecipeWork * 0.1f * curJob.RecipeDef.workSkillLearnFactor; actor.skills.GetSkill(curJob.RecipeDef.workSkill).Learn(xp, false); } List <Thing> ingredients = Toils_Recipe.CalculateIngredients(curJob, actor); Thing dominantIngredient = Toils_Recipe.CalculateDominantIngredient(curJob, ingredients); List <Thing> list = GenRecipe.MakeRecipeProducts(curJob.RecipeDef, actor, ingredients, dominantIngredient, jobDriver_DoBill.BillGiver).ToList <Thing>(); Toils_Recipe.ConsumeIngredients(ingredients, curJob.RecipeDef, actor.Map); curJob.bill.Notify_IterationCompleted(actor, ingredients); RecordsUtility.Notify_BillDone(actor, list); UnfinishedThing unfinishedThing = curJob.GetTarget(TargetIndex.B).Thing as UnfinishedThing; if (curJob.bill.recipe.WorkAmountTotal((unfinishedThing == null) ? null : unfinishedThing.Stuff) >= 10000f && list.Count > 0) { TaleRecorder.RecordTale(TaleDefOf.CompletedLongCraftingProject, new object[] { actor, list[0].def }); } if (list.Count == 0) { actor.jobs.EndCurrentJob(JobCondition.Succeeded, true); return; } if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.DropOnFloor) { for (int i = 0; i < list.Count; i++) { if (!GenPlace.TryPlaceThing(list[i], actor.Position, actor.Map, ThingPlaceMode.Near, null, null)) { Log.Error(string.Concat(new object[] { actor, " could not drop recipe product ", list[i], " near ", actor.Position }), false); } } actor.jobs.EndCurrentJob(JobCondition.Succeeded, true); return; } if (list.Count > 1) { for (int j = 1; j < list.Count; j++) { if (!GenPlace.TryPlaceThing(list[j], actor.Position, actor.Map, ThingPlaceMode.Near, null, null)) { Log.Error(string.Concat(new object[] { actor, " could not drop recipe product ", list[j], " near ", actor.Position }), false); } } } IntVec3 invalid = IntVec3.Invalid; if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.BestStockpile) { StoreUtility.TryFindBestBetterStoreCellFor(list[0], actor, actor.Map, StoragePriority.Unstored, actor.Faction, out invalid, true); } else if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile) { StoreUtility.TryFindBestBetterStoreCellForIn(list[0], actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetStoreZone().slotGroup, out invalid, true); } else { Log.ErrorOnce("Unknown store mode", 9158246, false); } if (invalid.IsValid) { actor.carryTracker.TryStartCarry(list[0]); curJob.targetB = invalid; curJob.targetA = list[0]; curJob.count = 99999; return; } if (!GenPlace.TryPlaceThing(list[0], actor.Position, actor.Map, ThingPlaceMode.Near, null, null)) { Log.Error(string.Concat(new object[] { "Bill doer could not drop product ", list[0], " near ", actor.Position }), false); } actor.jobs.EndCurrentJob(JobCondition.Succeeded, true); }; return(toil); }
public static Toil PlaceHauledThingInCell(TargetIndex cellInd, Toil nextToilOnPlaceFailOrIncomplete, bool storageMode, bool tryStoreInSameStorageIfSpotCantHoldWholeStack = false) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; IntVec3 cell = curJob.GetTarget(cellInd).Cell; if (actor.carryTracker.CarriedThing == null) { Log.Error(string.Concat(actor, " tried to place hauled thing in cell but is not hauling anything.")); } else { SlotGroup slotGroup = actor.Map.haulDestinationManager.SlotGroupAt(cell); if (slotGroup != null && slotGroup.Settings.AllowedToAccept(actor.carryTracker.CarriedThing)) { actor.Map.designationManager.TryRemoveDesignationOn(actor.carryTracker.CarriedThing, DesignationDefOf.Haul); } Action <Thing, int> placedAction = null; if (curJob.def == JobDefOf.DoBill || curJob.def == JobDefOf.RefuelAtomic || curJob.def == JobDefOf.RearmTurretAtomic) { placedAction = delegate(Thing th, int added) { if (curJob.placedThings == null) { curJob.placedThings = new List <ThingCountClass>(); } ThingCountClass thingCountClass = curJob.placedThings.Find((ThingCountClass x) => x.thing == th); if (thingCountClass != null) { thingCountClass.Count += added; } else { curJob.placedThings.Add(new ThingCountClass(th, added)); } }; } if (!actor.carryTracker.TryDropCarriedThing(cell, ThingPlaceMode.Direct, out var _, placedAction)) { if (storageMode) { if (nextToilOnPlaceFailOrIncomplete != null && ((tryStoreInSameStorageIfSpotCantHoldWholeStack && StoreUtility.TryFindBestBetterStoreCellForIn(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, cell.GetSlotGroup(actor.Map), out var foundCell)) || StoreUtility.TryFindBestBetterStoreCellFor(actor.carryTracker.CarriedThing, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell))) { if (actor.CanReserve(foundCell)) { actor.Reserve(foundCell, actor.CurJob); } actor.CurJob.SetTarget(cellInd, foundCell); actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete); } else { Job job = HaulAIUtility.HaulAsideJobFor(actor, actor.carryTracker.CarriedThing); if (job != null) { curJob.targetA = job.targetA; curJob.targetB = job.targetB; curJob.targetC = job.targetC; curJob.count = job.count; curJob.haulOpportunisticDuplicates = job.haulOpportunisticDuplicates; curJob.haulMode = job.haulMode; actor.jobs.curDriver.JumpToToil(nextToilOnPlaceFailOrIncomplete); } else { Log.Error(string.Concat("Incomplete haul for ", actor, ": Could not find anywhere to put ", actor.carryTracker.CarriedThing, " near ", actor.Position, ". Destroying. This should never happen!")); actor.carryTracker.CarriedThing.Destroy(); } } }
public static Toil FinishRecipeAndStartStoringCorpse(TargetIndex corpseIndex) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; Corpse corpse = actor.jobs.curJob.GetTarget(TargetIndex.B).Thing as Corpse; actor.skills.GetSkill(SkillDefOf.Medicine).Learn(Dissection.Singleton.ExpPerCorpse, Dissection.Singleton.IgnoreDailyLimit); ApplyThoughts(actor, corpse); RecordTale(actor, corpse); bool destroyedBody = RemoveDissectedBodyParts(actor, corpse); curJob.bill.Notify_IterationCompleted(actor, new List <Thing>() { corpse }); RecordsUtility.Notify_BillDone(actor, new List <Thing>() { corpse }); if (destroyedBody) { actor.jobs.EndCurrentJob(JobCondition.Succeeded); return; } IntVec3 bestStoreCell = IntVec3.Invalid; if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.BestStockpile) { StoreUtility.TryFindBestBetterStoreCellFor(corpse, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out bestStoreCell, true); } else if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile) { StoreUtility.TryFindBestBetterStoreCellForIn(corpse, actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetStoreZone().slotGroup, out bestStoreCell, true); } else { Log.ErrorOnce("Unknown store mode", 9158246, false); } if (bestStoreCell.IsValid) { corpse.DeSpawn(); actor.carryTracker.TryStartCarry(corpse); curJob.targetC = bestStoreCell; curJob.targetB = corpse; curJob.count = 99999; curJob.placedThings?.Clear(); } else { actor.jobs.EndCurrentJob(JobCondition.Succeeded); } }; return(toil); }
} // end TryDropProductOnFloor /// <summary> /// Generates the recipe product, then looks for a valid cell in the Bill's output stockpile. /// If a valid cell is found, puts the product into the pawn's arms for transport in a future Toil. /// Uses code from the Toils_Recipe.FinishRecipeAndStartStoringProduct() toil in vanilla. /// </summary> /// <param name="vat"></param> /// <returns></returns> public static Toil StartCarryProductToStockpile(Building_GrowerBase_WorkTable vat) { Toil toil = new Toil(); toil.initAction = delegate { Pawn actor = toil.actor; Job curJob = actor.jobs.curJob; //Skip null checking, as it was done in previous toil Thing product = ThingMaker.MakeThing(vat.activeRecipe.products[0].thingDef); product.stackCount = vat.activeRecipe.products[0].count; Bill_Production activeBill = vat.billProc.ActiveBill; //decrement billstack count if (activeBill.repeatMode == BillRepeatModeDefOf.RepeatCount) { if (activeBill.repeatCount > 0) { activeBill.repeatCount--; } } IntVec3 foundCell = IntVec3.Invalid; //find the best cell to put the product in if (activeBill.GetStoreMode() == BillStoreModeDefOf.BestStockpile) { StoreUtility.TryFindBestBetterStoreCellFor(product, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell); } else if (activeBill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile) { StoreUtility.TryFindBestBetterStoreCellForIn(product, actor, actor.Map, StoragePriority.Unstored, actor.Faction, activeBill.GetStoreZone().slotGroup, out foundCell); } else { Log.ErrorOnce("Unknown bill store mode", 9158246); } //if a cell was found in a stockpile, start a hauling job to move the product from the ground to that cell if (foundCell.IsValid) { bool tryCarrySuccess = actor.carryTracker.TryStartCarry(product); QEEMod.TryLog("Valid stockpile found - haul product to cell " + foundCell + ". TryStartCarry() result for " + actor.LabelShort + ": " + tryCarrySuccess); curJob.targetB = foundCell; curJob.targetA = product; curJob.count = 99999; vat.Notify_ProductExtracted(actor); //the next toil in the JobDriver will now haul the carried object to the stockpile } else { QEEMod.TryLog("No stockpile found to haul " + product.Label + " to. Dropping product on ground."); if (GenPlace.TryPlaceThing(product, actor.Position, actor.Map, ThingPlaceMode.Near)) { vat.Notify_ProductExtracted(actor); } else { QEEMod.TryLog(actor + " could not drop recipe product " + product + " near " + actor.Position + ". Ending extract job."); } actor.jobs.EndCurrentJob(JobCondition.Succeeded); } }; return(toil); } // end StartCarryProductToStockpile
public static Toil FinishRecipeAndStartStoringProduct() { Toil toil = new Toil(); toil.initAction = () => { var actor = toil.actor; var curJob = actor.jobs.curJob; var driver = ((JobDriver_DoBill)actor.jobs.curDriver); //Learn (if the recipe doesn't use unfinished thing) if (curJob.RecipeDef.workSkill != null && !curJob.RecipeDef.UsesUnfinishedThing) { float xp = driver.ticksSpentDoingRecipeWork * SkillTuning.XpPerTickRecipeBase * curJob.RecipeDef.workSkillLearnFactor; actor.skills.GetSkill(curJob.RecipeDef.workSkill).Learn(xp); } //Calculate ingredients List <Thing> ingredients = CalculateIngredients(curJob, actor); Thing dominantIngredient = CalculateDominantIngredient(curJob, ingredients); //Make the products var products = GenRecipe.MakeRecipeProducts(curJob.RecipeDef, actor, ingredients, dominantIngredient, driver.BillGiver).ToList(); //Consume the ingredients ConsumeIngredients(ingredients, curJob.RecipeDef, actor.Map); //Notify bill curJob.bill.Notify_IterationCompleted(actor, ingredients); //Add records RecordsUtility.Notify_BillDone(actor, products); //Add tale var uft = curJob.GetTarget(JobDriver_DoBill.IngredientInd).Thing as UnfinishedThing; if (curJob.bill.recipe.WorkAmountTotal(uft != null ? uft.Stuff : null) >= LongCraftingProjectThreshold && products.Count > 0) { TaleRecorder.RecordTale(TaleDefOf.CompletedLongCraftingProject, actor, products[0].GetInnerIfMinified().def); } //---------------------------------------------------- //Rearrange the job so the bill doer goes and stores the product //---------------------------------------------------- //Nothing to store? End the job now if (products.Count == 0) { actor.jobs.EndCurrentJob(JobCondition.Succeeded); return; } //Bill is set to drop-on-floor mode? //Drop everything and end the job now if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.DropOnFloor) { for (int i = 0; i < products.Count; i++) { if (!GenPlace.TryPlaceThing(products[i], actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error(actor + " could not drop recipe product " + products[i] + " near " + actor.Position); } } actor.jobs.EndCurrentJob(JobCondition.Succeeded); return; } //Place all products except the first one on the ground if (products.Count > 1) { for (int i = 1; i < products.Count; i++) { if (!GenPlace.TryPlaceThing(products[i], actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error(actor + " could not drop recipe product " + products[i] + " near " + actor.Position); } } } //Try find a cell to take the product to IntVec3 storeCell = IntVec3.Invalid; if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.BestStockpile) { StoreUtility.TryFindBestBetterStoreCellFor(products[0], actor, actor.Map, StoragePriority.Unstored, actor.Faction, out storeCell); } else if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile) { StoreUtility.TryFindBestBetterStoreCellForIn(products[0], actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetStoreZone().slotGroup, out storeCell); } else { Log.ErrorOnce("Unknown store mode", 9158246); } if (storeCell.IsValid) { //Start carrying the first product and proceed to the storage toils actor.carryTracker.TryStartCarry(products[0]); curJob.targetB = storeCell; curJob.targetA = products[0]; curJob.count = 99999; } else { //No store cell? Drop the product; we're done. if (!GenPlace.TryPlaceThing(products[0], actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error("Bill doer could not drop product " + products[0] + " near " + actor.Position); } actor.jobs.EndCurrentJob(JobCondition.Succeeded); return; } }; return(toil); }
protected override IEnumerable <Toil> MakeNewToils() { Building_FishingSpot fishingSpot = this.job.GetTarget(FishingSpotIndex).Thing as Building_FishingSpot; int fishingDuration = (int)(baseFishingDuration * Rand.Range(0.2f, 1.8f) * fishingSpot.MapFishTracker.DifficultyMultiplier / (ModController.Settings.FishingEfficiency)); Thing thingCaught = null; yield return(Toils_Goto.GotoThing(FishingSpotIndex, fishingSpot.InteractionCell) .FailOnDespawnedNullOrForbidden(FishingSpotIndex)); Toil fishToil = new Toil() { initAction = () => { if (Find.TickManager.TicksGame > fishingSpot.lastFishingStartTick + 60000 * fishingSpot.FishingFrequency) { fishingSpot.lastFishingStartTick = Find.TickManager.TicksGame; } }, tickAction = () => { this.pawn.skills.Learn(job.def.joySkill, job.def.joyXpPerTick); if (pawn.CurJob.GetTarget(FishingSpotIndex).IsValid) { pawn.rotationTracker.FaceCell(pawn.CurJob.GetTarget(FishingSpotIndex).Cell); } }, handlingFacing = true, defaultDuration = fishingDuration, defaultCompleteMode = ToilCompleteMode.Delay }; yield return(fishToil.FailOnDespawnedNullOrForbidden(FishingSpotIndex)); Toil catchFishToil = new Toil() { initAction = () => { string eventText; if (Rand.Value < pawn.GetStatValue(ResourceBank.StatDefOf.FishingChance)) { if (fishingSpot.FishStock > 0 && fishingSpot.FishByWeight.Count > 0) { FishDef fishDefToCatch = fishingSpot.FishByWeight.RandomElementByWeight(item => item.Item1).Item2; if (fishDefToCatch.fishProperties.CanBite && Rand.Value < pawn.GetStatValue(ResourceBank.StatDefOf.FishBiteChance)) { float damage = Rand.Range(fishDefToCatch.fishProperties.BiteDamageRange.min, fishDefToCatch.fishProperties.BiteDamageRange.max); eventText = string.Format(ResourceBank.Strings.FishingTradegyText.Translate(), this.pawn.Name.ToStringShort.CapitalizeFirst(), fishDefToCatch.label); Find.LetterStack.ReceiveLetter(ResourceBank.Strings.FishingTradegyTitle.Translate(), eventText, LetterDefOf.NegativeEvent, this.pawn); this.pawn.TakeDamage(new DamageInfo(fishDefToCatch.fishProperties.BiteDamageDef, damage, 0f, -1f, this.pawn, null, null, DamageInfo.SourceCategory.ThingOrUnknown, this.pawn)); return; } fishingSpot.FishCaught(); bool roeFish = false; if (fishDefToCatch.fishProperties.HasRoe && fishDefToCatch.fishProperties.RoeDef != null && fishDefToCatch.fishProperties.SpawningYearRange != null) { int day = GenDate.DayOfYear(Find.TickManager.TicksAbs, Find.WorldGrid.LongLatOf(this.Map.Tile).x); if (fishDefToCatch.fishProperties.SpawningYearRange.min <= day && day <= fishDefToCatch.fishProperties.SpawningYearRange.max) { if (Rand.Value < ModController.Settings.roeChance) { roeFish = true; } } } if (roeFish) { thingCaught = ThingMaker.MakeThing(fishDefToCatch.fishProperties.RoeDef, null); } else { thingCaught = ThingMaker.MakeThing(fishDefToCatch, null); } thingCaught.stackCount = 1; eventText = ResourceBank.Strings.FishingSuccess.Translate(this.pawn.Name.ToStringShort.CapitalizeFirst(), fishDefToCatch.label); NotifyFishingSuccess(eventText); } else if (Rand.Value < ModController.Settings.junkChance) { //catch non-fish float treasureChance = ModController.Settings.treasureChanceStandart; if (fishingSpot.DeepTerrain) { treasureChance *= treasureDeepAdditionalChance; } ThingSetMakerParams parms = default(ThingSetMakerParams); parms.countRange = new IntRange(1, 1); if (Rand.Value <= treasureChance) { parms.maxTotalMass = ModController.Settings.MaxTreasureMass; parms.totalMarketValueRange = new FloatRange(100.0f, ModController.Settings.treasureMaxValue); parms.qualityGenerator = QualityGenerator.Reward; List <Thing> list = ThingSetMakerDefOf.Reward_ItemsStandard.root.Generate(parms); thingCaught = list.RandomElement(); eventText = ResourceBank.Strings.FishingCaughtTreasureText.Translate(this.pawn.Name.ToStringShort.CapitalizeFirst(), thingCaught.def.label); NotifyCaughtTreasure(eventText); } else { parms.maxTotalMass = ModController.Settings.MaxJunkMass; parms.qualityGenerator = QualityGenerator.BaseGen; List <Thing> list = ResourceBank.ThingSetMakerDefOf.Fishing_ItemJunk.root.Generate(parms); thingCaught = list.RandomElement(); eventText = ResourceBank.Strings.FishingCaughtJunkText.Translate(this.pawn.Name.ToStringShort.CapitalizeFirst(), thingCaught.def.label); NotifyCaughtJunk(eventText); } } } else { eventText = ResourceBank.Strings.FishingCaughtNothingText.Translate(this.pawn.Name.ToStringShort.CapitalizeFirst()); MoteMaker.ThrowMetaIcon(this.pawn.Position, this.Map, ThingDefOf.Mote_IncapIcon); NotifyCaughtNothing(eventText); this.pawn.jobs.EndCurrentJob(JobCondition.Incompletable); return; } } }; yield return(catchFishToil); //yield return FinishAndStartHaul(fishingCatch); Toil toilFinishAndStartHaul = new Toil(); toilFinishAndStartHaul.initAction = delegate { Pawn actor = toilFinishAndStartHaul.actor; Job curJob = actor.jobs.curJob; Bill bill = curJob.bill; Log.Message(bill.recipe.defName); Log.Message(thingCaught.def.defName); if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.DropOnFloor) { if (!GenPlace.TryPlaceThing(thingCaught, actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error(actor + " could not drop recipe product " + thingCaught + " near " + actor.Position); } actor.jobs.EndCurrentJob(JobCondition.Succeeded); } else { IntVec3 foundCell = IntVec3.Invalid; if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.BestStockpile) { StoreUtility.TryFindBestBetterStoreCellFor(thingCaught, actor, actor.Map, StoragePriority.Unstored, actor.Faction, out foundCell); } else if (curJob.bill.GetStoreMode() == BillStoreModeDefOf.SpecificStockpile) { if (curJob.bill.GetStoreZone().Accepts(thingCaught)) { StoreUtility.TryFindBestBetterStoreCellForIn(thingCaught, actor, actor.Map, StoragePriority.Unstored, actor.Faction, curJob.bill.GetStoreZone().slotGroup, out foundCell); } else { if (!GenPlace.TryPlaceThing(thingCaught, actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error(actor + " could not drop recipe product " + thingCaught + " near " + actor.Position); } actor.jobs.EndCurrentJob(JobCondition.Succeeded); } } else { Log.ErrorOnce("Unknown store mode", 9158246); } if (foundCell.IsValid) { actor.carryTracker.TryStartCarry(thingCaught); curJob.SetTarget(HaulableInd, thingCaught); curJob.SetTarget(StoreCellInd, foundCell); curJob.count = 99999; } else { if (!GenPlace.TryPlaceThing(thingCaught, actor.Position, actor.Map, ThingPlaceMode.Near)) { Log.Error("Bill doer could not drop product " + thingCaught + " near " + actor.Position); } actor.jobs.EndCurrentJob(JobCondition.Succeeded); } } }; yield return(toilFinishAndStartHaul); yield return(Toils_Reserve.Reserve(StoreCellInd)); Toil carryToCell = Toils_Haul.CarryHauledThingToCell(StoreCellInd); yield return(carryToCell); yield return(Toils_Haul.PlaceHauledThingInCell(StoreCellInd, carryToCell, storageMode: true, tryStoreInSameStorageIfSpotCantHoldWholeStack: true)); Toil recount = new Toil(); recount.initAction = delegate { Bill_Production bill_Production = recount.actor.jobs.curJob.bill as Bill_Production; if (bill_Production != null && bill_Production.repeatMode == BillRepeatModeDefOf.TargetCount) { Map.resourceCounter.UpdateResourceCounts(); } }; yield return(recount); }