private bool TrainingCompleted(Pawn meeseeks, Pawn targetPawn, SavedTargetInfo jobTarget) { TrainableDef desiredTrainable = jobTarget.trainable; if (targetPawn.training.HasLearned(desiredTrainable)) { return(true); } else if (!targetPawn.training.GetWanted(desiredTrainable)) { targetPawn.training.SetWantedRecursive(desiredTrainable, true); } return(false); }
public void ForceNewJob(Job newJob, SavedTargetInfo targetInfo) { jobTargets = new List <SavedTargetInfo> { targetInfo }; givenTask = true; startedTask = true; taskCompleted = false; savedJob = new SavedJob(newJob); givenTaskTick = Find.TickManager.TicksGame; potentialTargetCache.Clear(); }
public override void SortAndFilterJobTargets(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob) { Map map = meeseeks.MapHeld; WorkGiver_RemoveRoof scanner = savedJob.workGiverDef.Worker as WorkGiver_RemoveRoof; SavedTargetInfo bestTarget = null; float bestPriority = float.MinValue; float bestDistanceSquared = float.MaxValue; for (int i = memory.jobTargets.Count - 1; i >= 0; --i) { SavedTargetInfo target = memory.jobTargets[i]; if (!target.Cell.Roofed(map)) { CollectNewTargets(meeseeks, memory, target.Cell, map); memory.jobTargets.RemoveAt(i); } } foreach (SavedTargetInfo target in memory.jobTargets) { if (meeseeks.CanReach(target.Cell, scanner.PathEndMode, Danger.Deadly) && meeseeks.CanReserve(target.Cell, 1, -1, ReservationLayerDefOf.Ceiling, false)) { float priority = scanner.GetPriority(meeseeks, target.Cell); float distanceSquared = (target.Cell - meeseeks.Position).LengthHorizontalSquared; if (priority > bestPriority || (priority == bestPriority && distanceSquared < bestDistanceSquared)) { bestTarget = target; bestPriority = priority; bestDistanceSquared = distanceSquared; } } } if (bestTarget != null) { memory.jobTargets.Remove(bestTarget); memory.jobTargets.Insert(0, bestTarget); } }
public void SortJobTargets() { if (jobTargets.Count == 0) { return; } jobTargets.Sort((a, b) => (int)(Meeseeks.PositionHeld.DistanceToSquared(a.Cell) - Meeseeks.PositionHeld.DistanceToSquared(b.Cell))); // If it is a kill job, kill self last if (savedJob != null && savedJob.def == MeeseeksDefOf.CM_Meeseeks_Box_Job_Kill) { int indexOfSelf = jobTargets.FindIndex(target => target.Thing == Meeseeks); if (indexOfSelf >= 0) { SavedTargetInfo selfTarget = jobTargets[indexOfSelf]; jobTargets.RemoveAt(indexOfSelf); jobTargets.Add(selfTarget); } } }
private Job GetDeconstructingJob(Pawn meeseeks, SavedTargetInfo jobTarget, Map map) { BuildableDef buildableDef = jobTarget.BuildableDef; if (buildableDef == null) { return(null); } CellRect cellRect = GenAdj.OccupiedRect(jobTarget.Cell, jobTarget.blueprintRotation, buildableDef.Size); foreach (IntVec3 cell in cellRect) { foreach (Thing thing in cell.GetThingList(map)) { if (!GenConstruct.CanPlaceBlueprintOver(buildableDef, thing.def)) { return(JobMaker.MakeJob(JobDefOf.Deconstruct, thing)); } } } return(null); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Job job = null; if (jobTarget != null && jobTarget.HasThing && !jobTarget.ThingDestroyed) { CompHasButton hasButton = jobTarget.Thing.TryGetComp <CompHasButton>(); if (!hasButton.WantsPress) { jobAvailabilty = JobAvailability.Complete; } } else { Logger.WarningFormat(this, "Unable to get scanner or target for job."); } if (job != null) { jobAvailabilty = JobAvailability.Available; } return(job); }
private Job GetNextJob(Pawn meeseeks, CompMeeseeksMemory memory) { Job nextJob = null; SavedJob savedJob = memory.savedJob; if (savedJob == null) { Logger.MessageFormat(this, "No saved job..."); return(null); } if (memory.jobStuck) { Logger.MessageFormat(this, "Wait a tick..."); return(JobMaker.MakeJob(JobDefOf.Wait_MaintainPosture, 1)); } //Logger.MessageFormat(this, "Job target count: {0}", memory.jobTargets.Count); Map map = meeseeks.MapHeld; List <SavedTargetInfo> delayedTargets = new List <SavedTargetInfo>(); MeeseeksJobSelector jobSelector = defaultJobSelector; foreach (MeeseeksJobSelector eachJobSelector in jobSelectors) { if (eachJobSelector.UseForJob(meeseeks, memory, savedJob)) { jobSelector = eachJobSelector; break; } } try { jobSelector.SortAndFilterJobTargets(meeseeks, memory, savedJob); while (memory.jobTargets.Count > 0 && nextJob == null) { JobAvailability jobAvailabilty = JobAvailability.Invalid; SavedTargetInfo jobTarget = memory.jobTargets.FirstOrDefault(); if (jobTarget == null || !jobTarget.IsValid) { Logger.WarningFormat(this, "Invalid or null target in queue"); memory.jobTargets.RemoveAt(0); continue; } nextJob = jobSelector.GetJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty); //Logger.MessageFormat(this, "Job selector: {0}, result: {1}", jobSelector.GetType().ToString(), jobAvailabilty.ToString()); if (nextJob != null) { bool reservationsMade = nextJob.TryMakePreToilReservations(meeseeks, false); if (!reservationsMade) { jobAvailabilty = JobAvailability.Delayed; Logger.MessageFormat(this, "Delaying job for {0} because reservations could not be made.", jobTarget.ToString()); nextJob = null; } } if (jobAvailabilty == JobAvailability.Delayed) { delayedTargets.Add(jobTarget); memory.jobTargets.RemoveAt(0); } else if (nextJob == null) { memory.jobTargets.RemoveAt(0); } } if (delayedTargets.Count > 0 && nextJob == null) { nextJob = jobSelector.GetJobDelayed(meeseeks, memory, savedJob, delayedTargets[0]); } } finally { // Put delayed targets back on the target list memory.jobTargets.AddRange(delayedTargets); } return(nextJob); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { bool wait = true; IntVec3 guardPosition = memory.guardPosition; if (memory.guardPosition.IsValid && meeseeks.Position != guardPosition) { guardPosition = RCellFinder.BestOrderedGotoDestNear(memory.guardPosition, meeseeks); if (guardPosition.IsValid && meeseeks.Position != guardPosition) { wait = false; } } Job job = null; if (wait) { Logger.MessageFormat(this, "Wait"); job = JobMaker.MakeJob(JobDefOf.Wait_Combat, memory.guardPosition); job.expiryInterval = 600; } else { Logger.MessageFormat(this, "Goto spot"); job = JobMaker.MakeJob(JobDefOf.Goto, guardPosition); job.expiryInterval = 120; } return(job); }
protected Job GetJobOnTarget(Pawn meeseeks, SavedTargetInfo targetInfo, WorkGiver_Scanner workGiverScanner, bool scanAllThingsOnCell = false) { Job job = null; try { DesignatorUtility.ForceAllDesignationsOnCell(targetInfo.Cell, meeseeks.MapHeld); if (targetInfo.HasThing && !targetInfo.ThingDestroyed) { // Special case for uninstall, the workgiver doesn't check to see if its already uninstalled if (workGiverScanner as WorkGiver_Uninstall != null && !targetInfo.Thing.Spawned) { Logger.WarningFormat(this, "Target is inside {0}", targetInfo.Thing.ParentHolder); DesignatorUtility.RestoreDesignationsOnCell(targetInfo.Cell, meeseeks.MapHeld); return(null); } // Have to try-catch all these damn things because other mods arent't doing null checks :( try { //Logger.MessageFormat(this, "Checking {0} for job on {1}", workGiverScanner, targetInfo.Thing); if (workGiverScanner.HasJobOnThing(meeseeks, targetInfo.Thing, true)) { //Logger.MessageFormat(this, "Getting {0} for job on {1}", workGiverScanner, targetInfo.Thing); job = workGiverScanner.JobOnThing(meeseeks, targetInfo.Thing, true); } } catch (Exception e) { } finally { } } else { // Have to try-catch all these damn things because other mods arent't doing null checks :( try { //Logger.MessageFormat(this, "Checking {0} for job on {1}", workGiverScanner, targetInfo.Cell); if (job == null && workGiverScanner.HasJobOnCell(meeseeks, targetInfo.Cell, true)) { job = workGiverScanner.JobOnCell(meeseeks, targetInfo.Cell, true); } } catch (Exception e) { } finally { } } if (job == null && scanAllThingsOnCell) { var thingsAtCell = meeseeks.MapHeld.thingGrid.ThingsAt(targetInfo.Cell); foreach (Thing thing in thingsAtCell) { //Logger.MessageFormat(this, "Checking {0} for {1}.", thing, workGiverScanner.def.defName); // Have to try-catch all these damn things because other mods arent't doing null checks :( try { Logger.MessageFormat(this, "Checking {0} for job on {1}", workGiverScanner, thing); if (workGiverScanner.HasJobOnThing(meeseeks, thing, true)) { job = workGiverScanner.JobOnThing(meeseeks, thing, true); } } catch (Exception e) { } finally { } if (job != null) { break; } } } } finally { DesignatorUtility.RestoreDesignationsOnCell(targetInfo.Cell, meeseeks.MapHeld); } return(job); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Bill bill = jobTarget.bill; Logger.MessageFormat(this, "Checking for bill job..."); if (bill == null) { return(ScanForJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty)); } if (bill.deleted) { jobAvailabilty = JobAvailability.Complete; return(null); } if (bill is Bill_Medical) { return(GetMedicalBillJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty)); } else if (bill is Bill_Production) { return(GetProductionBillJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty)); } return(null); }
public override Job GetJobDelayed(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget) { Pawn targetPawn = jobTarget.Thing as Pawn; Job job = JobMaker.MakeJob(MeeseeksDefOf.CM_Meeseeks_Box_Job_WaitNear, targetPawn); job.locomotionUrgency = LocomotionUrgency.Walk; job.checkOverrideOnExpire = true; job.expiryInterval = 120; return(job); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Job job = null; ConstructionStatus status = jobTarget.TargetConstructionStatus(meeseeks.MapHeld); Logger.MessageFormat(this, "Checking for blocker, construction status: {0}", status); if (status == ConstructionStatus.None) { BuildableDef buildableDef = jobTarget.BuildableDef; if (buildableDef != null && GenConstruct.PlaceBlueprintForBuild(buildableDef, jobTarget.Cell, meeseeks.MapHeld, jobTarget.blueprintRotation, meeseeks.Faction, jobTarget.blueprintStuff) != null) { status = ConstructionStatus.InProgress; } } if (status == ConstructionStatus.Blocked) { job = GetDeconstructingJob(meeseeks, jobTarget, meeseeks.MapHeld); if (job == null) { jobAvailabilty = JobAvailability.Delayed; } else { jobAvailabilty = JobAvailability.Available; } } else if (status == ConstructionStatus.InProgress) { job = ScanForJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty, true); if (job == null) { jobAvailabilty = JobAvailability.Delayed; } else { jobAvailabilty = JobAvailability.Available; } } else if (status == ConstructionStatus.Complete) { jobAvailabilty = JobAvailability.Complete; } return(job); }
public void AddJobTarget(SavedTargetInfo target, bool firstTarget = false) { if (jobTargets.Contains(target)) { return; } if (target.HasThing && savedJob.bill != null) { MeeseeksBillStorage billStorage = Current.Game.World.GetComponent <MeeseeksBillStorage>(); if (firstTarget) { billStorage.SaveBill(savedJob.bill); savedJob.bill = billStorage.GetDuplicateBillFromOriginal(savedJob.bill); savedJob.bill.billStack.billGiver = target.Thing as IBillGiver; } WorkGiver_Scanner workGiverScanner = savedJob.workGiverDef.Worker as WorkGiver_Scanner; if (workGiverScanner != null) { Job job = workGiverScanner.JobOnThing(Meeseeks, target.Thing, true); if (job != null && job.bill != null) { billStorage.SaveBill(job.bill); target.bill = billStorage.GetDuplicateBillFromOriginal(job.bill); target.bill.billStack.billGiver = target.Thing as IBillGiver; } } } else if (target.HasThing && savedJob.IsConstruction) { ThingDef thingDefToBuild = null; TerrainDef terrainDefToBuild = null; ThingDef stuffDefToUse = null; Blueprint_Build blueprint = target.Thing as Blueprint_Build; Frame frame = target.Thing as Frame; if (blueprint != null) { thingDefToBuild = blueprint.def.entityDefToBuild as ThingDef; terrainDefToBuild = blueprint.def.entityDefToBuild as TerrainDef; stuffDefToUse = blueprint.stuffToUse; } else if (frame != null) { thingDefToBuild = frame.def.entityDefToBuild as ThingDef; terrainDefToBuild = frame.def.entityDefToBuild as TerrainDef; stuffDefToUse = frame.Stuff; } if (thingDefToBuild != null) { target.blueprintThingDef = thingDefToBuild; } else if (terrainDefToBuild != null) { target.blueprintTerrainDef = terrainDefToBuild; } target.blueprintStuff = stuffDefToUse; target.blueprintRotation = target.Thing.Rotation; // Redirect job to the cell so that we can continue various construction phases and replace blueprint if needed target.target = target.Cell; } else if (target.HasThing && savedJob.IsTraining) { target.trainable = (target.Thing as Pawn).training.NextTrainableToTrain(); } jobTargets.Add(target); }
private Job GetMedicalBillJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Bill_Medical bill = jobTarget.bill as Bill_Medical; Job job = null; if (jobTarget != null && jobTarget.HasThing && !jobTarget.ThingDestroyed && jobTarget.Thing is Pawn && !(jobTarget.Thing as Pawn).Dead) { Pawn targetPawn = jobTarget.Thing as Pawn; if (targetPawn == null || targetPawn.Dead || !bill.CompletableEver) { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; } else { MeeseeksBillStorage billStorage = Current.Game.World.GetComponent <MeeseeksBillStorage>(); BillStack billStack = targetPawn.BillStack; jobAvailabilty = JobAvailability.Delayed; if (targetPawn.UsableForBillsAfterFueling() && meeseeks.CanReserve(targetPawn, 1, -1, null, true)) { List <ThingCount> chosenIngredients = new List <ThingCount>(); // Screw you I need this function bool result = (bool)typeof(WorkGiver_DoBill).GetMethod("TryFindBestBillIngredients", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { bill, meeseeks, targetPawn, chosenIngredients }); if (result) { Job haulOffJob; job = WorkGiver_DoBill.TryStartNewDoBillJob(meeseeks, bill, targetPawn, chosenIngredients, out haulOffJob); bill.billStack.billGiver = targetPawn as IBillGiver; } if (job == null) { jobAvailabilty = JobAvailability.Delayed; } else { jobAvailabilty = JobAvailability.Available; } } } } else { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; } return(job); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Job job = null; WorkGiver_Scanner scanner = savedJob.WorkGiverScanner; if (scanner != null && jobTarget != null && jobTarget.HasThing && !jobTarget.ThingDestroyed && jobTarget.Thing is Pawn) { Pawn targetPawn = jobTarget.Thing as Pawn; if (targetPawn.Dead) { Logger.MessageFormat(this, "{0} dead.", targetPawn); jobAvailabilty = JobAvailability.Complete; } else if (this.TrainingCompleted(meeseeks, targetPawn, jobTarget)) { jobAvailabilty = JobAvailability.Complete; } else if (targetPawn.RaceProps.EatsFood && !HasFoodToInteractAnimal(meeseeks, targetPawn)) { job = TakeFoodForAnimalInteractJob(meeseeks, targetPawn); } else if (TrainableUtility.TrainedTooRecently(targetPawn)) { jobAvailabilty = JobAvailability.Delayed; } else if (targetPawn.MapHeld != meeseeks.MapHeld) { Logger.MessageFormat(this, "{0} not on map with {1}.", targetPawn); job = ExitMapJob(meeseeks); } else if (targetPawn.Spawned) { job = this.GetJobOnTarget(meeseeks, jobTarget, scanner); if (job == null) { jobAvailabilty = JobAvailability.Delayed; } } else { Logger.WarningFormat(this, "Could not get handling job for {0}.", targetPawn); jobAvailabilty = JobAvailability.Delayed; } } else { Logger.WarningFormat(this, "Unable to get scanner or target for job."); } if (job != null) { jobAvailabilty = JobAvailability.Available; } return(job); }
public virtual Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { return(ScanForJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty)); }
public virtual Job GetJobDelayed(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget) { return(null); }
public override Job GetJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Map map = meeseeks.MapHeld; Job job = ScanForJob(meeseeks, memory, savedJob, jobTarget, ref jobAvailabilty); // Mark them now because building a roof will cover most if them, and we will need a chance to check their neighbors CollectNewTargets(meeseeks, memory, jobTarget.Cell, map); if (job != null) { jobAvailabilty = JobAvailability.Available; } return(job); }
protected Job ScanForJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty, bool scanAllThingsOnCell = false) { Job job = null; if (savedJob.workGiverDef != null && savedJob.workGiverDef.Worker != null) { WorkGiver_Scanner workGiverScanner = savedJob.workGiverDef.Worker as WorkGiver_Scanner; if (workGiverScanner != null) { List <WorkGiver_Scanner> workGivers = WorkerDefUtility.GetCombinedWorkGiverScanners(workGiverScanner); foreach (WorkGiver_Scanner scanner in workGivers) { job = this.GetJobOnTarget(meeseeks, jobTarget, scanner, scanAllThingsOnCell); if (job != null) { if (memory.JobStuckRepeat(job)) { Logger.ErrorFormat(this, "Stuck job detected and removed on {0}.", jobTarget); jobAvailabilty = JobAvailability.Delayed; job = null; } else { //Logger.MessageFormat(this, "Job WAS found for {0}.", scanner.def.defName); jobAvailabilty = JobAvailability.Available; return(job); } } //Logger.MessageFormat(this, "No {0} job found.", scanner.def.defName); } } else { Logger.WarningFormat(this, "No work scanner"); } } else { Logger.WarningFormat(this, "Missing saved job workGiverDef or Worker for savedJob: {0}", savedJob.def.defName); } return(job); }
public bool Equals(SavedTargetInfo other) { return(this == other); }
private Job GetProductionBillJob(Pawn meeseeks, CompMeeseeksMemory memory, SavedJob savedJob, SavedTargetInfo jobTarget, ref JobAvailability jobAvailabilty) { Bill_Production bill = jobTarget.bill as Bill_Production; Job job = null; Logger.MessageFormat(this, "Checking for production bill job..."); if (bill.repeatMode == BillRepeatModeDefOf.RepeatCount && bill.repeatCount < 1) { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; return(null); } else if (bill.repeatMode == BillRepeatModeDefOf.TargetCount) { // Might be here without a billgiver (after a save?) so try to set the current target if (jobTarget.Thing != null) { bill.billStack.billGiver = jobTarget.Thing as IBillGiver; } // Otherwise count them later I guess :P if (bill.Map != null) { int productCount = bill.recipe.WorkerCounter.CountProducts(bill); if (productCount >= bill.targetCount) { bill.deleted = true; jobAvailabilty = JobAvailability.Complete; return(null); } } } Logger.MessageFormat(this, "Checking workstations..."); bool workStationValid = (jobTarget.HasThing && !jobTarget.ThingDestroyed && meeseeks.CanReserve(jobTarget.Thing, 1, -1, null, false) && ((jobTarget.Thing as IBillGiver).CurrentlyUsableForBills() || (jobTarget.Thing as IBillGiver).UsableForBillsAfterFueling())); if (!workStationValid) { Logger.MessageFormat(this, "We think the workstation is invalid looking for new one"); List <Building> buildings = meeseeks.MapHeld.listerBuildings.allBuildingsColonist.Where(building => building is IBillGiver && savedJob.workGiverDef.fixedBillGiverDefs.Contains(building.def) && meeseeks.CanReserve(building, 1, -1, null, false) && ((building as IBillGiver).CurrentlyUsableForBills() || (building as IBillGiver).UsableForBillsAfterFueling())).ToList(); if (buildings.Count > 0) { Logger.MessageFormat(this, "Found new one"); buildings.Sort((a, b) => (int)(meeseeks.PositionHeld.DistanceTo(a.Position) - meeseeks.PositionHeld.DistanceTo(b.Position))); jobTarget.target = buildings[0]; workStationValid = true; } else { Logger.MessageFormat(this, "Found no alternate workstations..."); } } else { Logger.MessageFormat(this, "We think the workstation is valid..."); } if (workStationValid) { IBillGiver billGiver = jobTarget.Thing as IBillGiver; bill.billStack.billGiver = billGiver; Bill_ProductionWithUft bill_ProductionWithUft = bill as Bill_ProductionWithUft; if (bill_ProductionWithUft != null) { if (bill_ProductionWithUft.BoundUft != null) { if (bill_ProductionWithUft.BoundUft.Creator.kindDef == MeeseeksDefOf.MeeseeksKind && meeseeks.CanReserveAndReach(bill_ProductionWithUft.BoundUft, PathEndMode.Touch, Danger.Deadly)) { job = FinishUftJob(meeseeks, bill_ProductionWithUft.BoundUft, bill_ProductionWithUft, billGiver); } } else { Predicate <Thing> validator = (Thing t) => ((UnfinishedThing)t).Recipe == bill.recipe && ((UnfinishedThing)t).Creator.kindDef == MeeseeksDefOf.MeeseeksKind && ((UnfinishedThing)t).ingredients.TrueForAll((Thing x) => bill.IsFixedOrAllowedIngredient(x.def)) && meeseeks.CanReserve(t); UnfinishedThing unfinishedThing = (UnfinishedThing)GenClosest.ClosestThingReachable(meeseeks.Position, meeseeks.Map, ThingRequest.ForDef(bill.recipe.unfinishedThingDef), PathEndMode.InteractionCell, TraverseParms.For(meeseeks), 9999f, validator); if (unfinishedThing != null) { job = FinishUftJob(meeseeks, unfinishedThing, bill_ProductionWithUft, billGiver); } } } if (job == null) { List <ThingCount> chosenIngredients = new List <ThingCount>(); // Screw you I need this function bool result = (bool)typeof(WorkGiver_DoBill).GetMethod("TryFindBestBillIngredients", BindingFlags.NonPublic | BindingFlags.Static).Invoke(null, new object[] { bill, meeseeks, jobTarget.Thing, chosenIngredients }); if (result) { Job haulOffJob = null; job = WorkGiver_DoBill.TryStartNewDoBillJob(meeseeks, bill, billGiver, chosenIngredients, out haulOffJob); } } } if (job == null) { jobAvailabilty = JobAvailability.Delayed; } else { jobAvailabilty = JobAvailability.Available; } return(job); }