public static WorkTarget Closest(IEnumerable <WorkTarget> targets, Pawn pawn, float maxSearchDistance = 9999f) { WorkTarget best = null; float bestDistance = float.MaxValue; float bestPriority = float.MinValue; float maxDistance = maxSearchDistance * maxSearchDistance; foreach (var target in targets) { var distance = target.Distance; var priority = target.Priority; var prioritized = target.WorkGiver.Prioritized; if (distance < maxDistance && // higher priority (prioritized && priority > bestPriority || // not prioritized or same priority, and smaller distance (!prioritized || priority == bestPriority) && distance < bestDistance) && target.Valid) { best = target; bestDistance = distance; bestPriority = priority; } } return(best); }
private ThinkResult GetJobFromBatch(Pawn pawn, List <WorkGiver_Scanner> batch, bool debug = false) { var priorityBatches = batch .SelectMany(wg => PotentialTargets(wg, pawn)) .GroupBy(wt => new { spatialPriority = wt.SpatialPriority, workGiver = wt.WorkGiver.def, }) .OrderByDescending(g => g.Key.spatialPriority) .ThenByDescending(g => g.Key.workGiver.priorityInType); if (debug) { Debug.Log("batch: " + batch.Select(wg => wg.def.defName).StringJoin(", ")); } // step 4; iterate over priorities until a job is found foreach (var priorityBatch in priorityBatches) { if (debug) { Debug.Log($"priority {priorityBatch.Key.spatialPriority} " + $"| {priorityBatch.Key.workGiver.priorityInType}:\n " + $"{priorityBatch.Select( wt => $"{wt.WorkGiver.def.defName} :: {wt.LocalTarget} :: {( wt.Valid ? "Valid" : "Invalid" )} :: {( wt.Job != null ? "HasJob" : "NO JOB" )} :: {wt.WorkGiver.GetPriority( pawn, wt.Target )}" ).StringJoin( "\n " )}"); } var target = WorkTarget.Closest(priorityBatch, pawn); if (target != null) { // we found a target! pawn.mindState.lastGivenWorkType = target.WorkGiver.def.workType; var job = target.Job; if (job == null) { Log.Error(string.Concat(target.WorkGiver, " provided target ", target.Target, " but yielded no actual job for pawn ", pawn, ". The CanGiveJob and JobOnX methods may not be synchronized.")); } else { return(new ThinkResult(job, this, target.WorkGiver.def.tagToGive)); } } } return(ThinkResult.NoJob); }