public static void Listener(Pawn healer, Pawn patient, ref Thing __result)
            {
                try
                {
                    //On ne soccupe que des patient étant des androids

                    /*if (!)
                     *  return true;*/


                    if (Settings.androidsCanUseOrganicMedicine)
                    {
                        return;
                    }

                    bool patientIsAndroid = Utils.ExceptionAndroidList.Contains(patient.def.defName) || patient.IsCyberAnimal();

                    if (patient.playerSettings == null || patient.playerSettings.medCare <= MedicalCareCategory.NoMeds)
                    {
                        __result = null;
                        return;
                    }
                    if (Medicine.GetMedicineCountToFullyHeal(patient) <= 0)
                    {
                        __result = null;
                        return;
                    }
                    Predicate <Thing> predicate;

                    //COmpatibilité avec pharmacist, le medoc renvoyé doit avoir une quantitée de soin inferieur ou egal à celui renvoyé par les appels précédents
                    float medicalPotency = 0;
                    if (__result != null)
                    {
                        medicalPotency = __result.def.GetStatValueAbstract(StatDefOf.MedicalPotency, null);
                    }

                    if (patientIsAndroid)
                    {
                        predicate = (Thing m) => Utils.ExceptionNanoKits.Contains(m.def.defName) && m.def.GetStatValueAbstract(StatDefOf.MedicalPotency, null) <= medicalPotency && !m.IsForbidden(healer) && patient.playerSettings.medCare.AllowsMedicine(m.def) && healer.CanReserve(m, 10, 1, null, false);
                    }
                    else
                    {
                        predicate = (Thing m) => !Utils.ExceptionNanoKits.Contains(m.def.defName) && m.def.GetStatValueAbstract(StatDefOf.MedicalPotency, null) <= medicalPotency && !m.IsForbidden(healer) && !m.IsForbidden(healer) && patient.playerSettings.medCare.AllowsMedicine(m.def) && healer.CanReserve(m, 10, 1, null, false);
                    }

                    Func <Thing, float> priorityGetter = (Thing t) => t.def.GetStatValueAbstract(StatDefOf.MedicalPotency, null);

                    IntVec3           position       = patient.Position;
                    Map               map            = patient.Map;
                    List <Thing>      searchSet      = patient.Map.listerThings.ThingsInGroup(ThingRequestGroup.Medicine);
                    PathEndMode       peMode         = PathEndMode.ClosestTouch;
                    TraverseParms     traverseParams = TraverseParms.For(healer, Danger.Deadly, TraverseMode.ByPawn, false);
                    Predicate <Thing> validator      = predicate;
                    __result = GenClosest.ClosestThing_Global_Reachable(position, map, searchSet, peMode, traverseParams, 9999f, validator, priorityGetter);
                }
                catch (Exception e)
                {
                    Log.Message("[ATPP] HealthAIUtility.FindBestMedicine(Error) : " + e.Message + " - " + e.StackTrace);
                }
            }
Пример #2
0
        protected override Job TryGiveJob(Pawn pawn)
        {
            Pawn patient = GetTendableColonist(pawn.Position, pawn.Map);

            if (patient != null)
            {
                Thing medicine = null;
                if (Medicine.GetMedicineCountToFullyHeal(patient) > 0)
                {
                    medicine = FindBestUnforbiddenMedicine(pawn, patient);
                }
                if (medicine != null)
                {
                    return(new Job(JobDefOf.TendPatient, patient, medicine));
                }
                return(new Job(JobDefOf.TendPatient, patient));
            }
            else
            {
                Lord lord = pawn.GetLord();
                if (lord != null)
                {
                    lord.ReceiveMemo("HealFinished");
                }
            }
            return(null);
        }
        // Token: 0x0600002D RID: 45 RVA: 0x00002758 File Offset: 0x00000958
        public override ThinkResult TryIssueJobPackage(Pawn pawn, JobIssueParams jobParm)
        {
            bool        flag = !HealthAIUtility.ShouldSeekMedicalRest(pawn);
            ThinkResult result;

            if (flag)
            {
                result = ThinkResult.NoJob;
            }
            else
            {
                bool flag2 = !HealthAIUtility.ShouldBeTendedNowByPlayer(pawn);
                if (flag2)
                {
                    result = ThinkResult.NoJob;
                }
                else
                {
                    bool flag3 = !GenCollection.Any <Apparel>(pawn.apparel.WornApparel, (Apparel x) => x.def.defName.Contains("RRY_Equipment_HunterGauntlet"));
                    if (flag3)
                    {
                        result = ThinkResult.NoJob;
                    }
                    else
                    {
                        Thing thing = RestUtility.FindPatientBedFor(pawn);
                        bool  flag4 = thing == null;
                        if (flag4)
                        {
                            result = ThinkResult.NoJob;
                        }
                        else
                        {
                            Thing thing2 = null;
                            bool  flag5  = Medicine.GetMedicineCountToFullyHeal(pawn) > 0;
                            if (flag5)
                            {
                                thing2 = HealthAIUtility.FindBestMedicine(pawn, pawn);
                            }
                            bool flag6 = thing2 != null;
                            Job  job;
                            if (flag6)
                            {
                                job = new Job(YautjaDefOf.RRY_Yautja_TendSelf, thing, thing2);
                            }
                            else
                            {
                                job = new Job(YautjaDefOf.RRY_Yautja_TendSelf, thing);
                            }
                            result = new ThinkResult(job, this, null, false);
                        }
                    }
                }
            }
            return(result);
        }
Пример #4
0
        //FindBestMedicine Replacement
        private static bool Prefix(Pawn healer, Pawn patient, ref Thing __result)
        {
            if (patient.GetCare() <= MedicalCareCategory.NoMeds || Medicine.GetMedicineCountToFullyHeal(patient) <= 0)
            {
                return(true);
            }

            __result = Find(healer, patient, out int dummy).FirstOrDefault().Thing;
            return(false);
        }
Пример #5
0
 public void SendMedicIfNeeded()
 {
     if (Find.TickManager.TicksGame >= this.nextTendableColonistCheckTick)
     {
         this.nextTendableColonistCheckTick = Find.TickManager.TicksGame + tendableColonistCheckPeriodInTicks;
         // Check if spaceship is about to take off.
         if (IsTakeOffImminent(2 * Util_Spaceship.medicsRecallBeforeTakeOffMarginInTicks))
         {
             return;
         }
         // Get a healthy medic.
         Pawn medic = null;
         foreach (Pawn pawn in this.medics.InRandomOrder())
         {
             if (this.pawnsAboard.Contains(pawn) &&
                 (pawn.health.HasHediffsNeedingTend() == false))
             {
                 medic = pawn;
                 break;
             }
         }
         if (medic == null)
         {
             return;
         }
         // Look for tendable colonist.
         Pawn patient = JobGiver_HealColonists.GetTendableColonist(this.Position, this.Map);
         if (patient == null)
         {
             return;
         }
         // Spawn needed medikits if available.
         if (this.availableMedikitsCount > 0)
         {
             int neededMedikitsCount  = Medicine.GetMedicineCountToFullyHeal(patient);
             int medikitsToSpawnCount = Math.Min(this.availableMedikitsCount, neededMedikitsCount);
             if (medikitsToSpawnCount > 0)
             {
                 SpawnItem(ThingDefOf.MedicineIndustrial, null, medikitsToSpawnCount, this.Position, this.Map, 0f);
                 this.availableMedikitsCount -= medikitsToSpawnCount;
             }
         }
         // Spawn medic.
         GenSpawn.Spawn(medic, this.Position, this.Map);
         this.pawnsAboard.Remove(medic);
         Lord lord = LordMaker.MakeNewLord(Util_Faction.MiningCoFaction, new LordJob_HealColonists(this.Position), this.Map);
         lord.AddPawn(medic);
     }
 }
Пример #6
0
        //Stupid re-write because I want count.
        //public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        public static bool Prefix(Pawn pawn, Thing t, ref Job __result)
        {
            medCount = 0;
            Pawn  patient = t as Pawn;
            Thing thing   = null;

            if (Medicine.GetMedicineCountToFullyHeal(patient) > 0)
            {
                thing = HealthAIUtility.FindBestMedicine(pawn, patient);
            }

            Log.Message("JobOnThing count = " + medCount);
            __result = new Job(JobDefOf.TendPatient, patient, thing)
            {
                count = medCount
            };

            return(false);
        }
Пример #7
0
        public override void DesignateSingleCell(IntVec3 c)
        {
            List <Thing> thingList = c.GetThingList();

            foreach (var thing in thingList)
            {
                Pawn pawn = thing as Pawn;
                if (pawn != null && pawn.health.ShouldBeTendedNow)
                {
                    Job jobNew = new Job(DefDatabase <JobDef> .GetNamed("ApplyMedicine"));
                    jobNew.targetA       = pawn;
                    jobNew.targetB       = medicine;
                    jobNew.maxNumToCarry = Medicine.GetMedicineCountToFullyHeal(jobNew.targetA.Thing as Pawn);
                    doctor.drafter.TakeOrderedJob(jobNew);
                    break;
                }
            }
            DesignatorManager.Deselect();
        }
Пример #8
0
        //Stupid re-write because I want count.
        //public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
        public static bool Prefix(Pawn pawn, Thing t, ref Job __result)
        {
            Pawn patient = t as Pawn;

            if (Medicine.GetMedicineCountToFullyHeal(patient) > 0)
            {
                List <ThingCount> meds = FindBestMedicine.Find(pawn, patient, out int medCount);
                Job job = new Job(JobDefOf.TendPatient, patient, meds.FirstOrDefault().Thing);
                job.count = medCount;
                if (meds.Count() > 1)
                {
                    job.targetQueueA = meds.Skip(1).Select(med => new LocalTargetInfo(med.Thing)).ToList();
                    job.countQueue   = meds.Skip(1).Select(med => med.Count).ToList();
                }
                __result = job;
            }
            else
            {
                __result = new Job(JobDefOf.TendPatient, patient);
            }

            return(false);
        }
        public override void DesignateSingleCell(IntVec3 c)
        {
            List <Thing> thingList = c.GetThingList();

            foreach (Thing thing in thingList)
            {
                Pawn pawn = thing as Pawn;
                if (pawn != null && pawn.health.ShouldBeTendedNow)
                {
                    Job jobNew = new Job(HaulJobDefOf.ApplyMedicine);
                    jobNew.targetA = pawn;

                    Thing dummy;
                    SlotsBackpackComp.slots.TryDrop(medicine, doctor.Position, ThingPlaceMode.Direct, Medicine.GetMedicineCountToFullyHeal(jobNew.targetA.Thing as Pawn), out dummy);

                    jobNew.targetB = dummy;

                    jobNew.maxNumToCarry = Medicine.GetMedicineCountToFullyHeal(jobNew.targetA.Thing as Pawn);
                    doctor.drafter.TakeOrderedJob(jobNew);
                    break;
                }
            }
            DesignatorManager.Deselect();
        }
Пример #10
0
        //public static Thing FindBestMedicine(Pawn healer, Pawn patient)
        public static List <ThingCount> Find(Pawn healer, Pawn patient, out int totalCount)
        {
            totalCount = 0;
            Log.Message($"{healer} is tending to {patient}");

            float sufficientQuality = maxMedicineQuality + 1;             // nothing is sufficient!

            if (Settings.Get().minimalMedicineForNonUrgent)
            {
                if (patient.health.hediffSet.hediffs.All(h => !h.TendableNow() || !h.IsUrgent()))
                {
                    sufficientQuality = minMedicineQuality;
                    Log.Message($"Sufficient medicine for non-urgent care is {sufficientQuality}");
                }
            }

            MedicalCareCategory defaultCare = patient.GetCare();

            //Care setting
            MedicalCareCategory finalCare = MedicalCareCategory.NoCare;
            var           hediffCare      = PriorityCareComp.Get();
            List <Hediff> hediffsToTend   = HediffsToTend(patient);

            Log.Message($"Tending ({hediffsToTend.ToStringSafeEnumerable()})");
            foreach (Hediff h in hediffsToTend)
            {
                MedicalCareCategory toUse = defaultCare;
                if (hediffCare.TryGetValue(h, out MedicalCareCategory heCare))
                {
                    toUse = heCare;
                }

                finalCare = toUse > finalCare ? toUse : finalCare;
            }
            Log.Message($"defaultCare = {defaultCare}, care = {finalCare}");

            //Android Droid support;
            Predicate <Thing> validatorDroid = t => true;
            Type extMechanicalPawn           = AccessTools.TypeByName("Androids.MechanicalPawnProperties");
            bool isDroid = extMechanicalPawn != null && (patient.def.modExtensions?.Any(e => extMechanicalPawn.IsAssignableFrom(e.GetType())) ?? false);

            if (isDroid)
            {
                Log.Message($"{patient} is a droid");
                Type extRepair = AccessTools.TypeByName("Androids.DroidRepairProperties");
                validatorDroid = t => t.def.modExtensions?.Any(e => extRepair.IsAssignableFrom(e.GetType())) ?? false;
            }

            //Med
            Predicate <Thing> validatorMed = t => finalCare.AllowsMedicine(t.def) && validatorDroid(t);

            //Ground
            Map               map            = patient.Map;
            TraverseParms     traverseParams = TraverseParms.For(healer, Danger.Deadly, TraverseMode.ByPawn, false);
            Predicate <Thing> validator      = (Thing t) => validatorMed(t) &&
                                               map.reachability.CanReach(patient.Position, t, PathEndMode.ClosestTouch, traverseParams) &&
                                               !t.IsForbidden(healer) && healer.CanReserve(t, FindBestMedicine.maxPawns, 1);//can reserve at least 1
            Func <Thing, float> priorityGetter  = (Thing t) => MedicineRating(t, sufficientQuality);
            List <Thing>        groundMedicines = patient.Map.listerThings.ThingsInGroup(isDroid?ThingRequestGroup.HaulableEver:ThingRequestGroup.Medicine).FindAll(t => validator(t));

            //Pawns
            Predicate <Pawn> validatorHolder = (Pawn p) =>
                                               map.reachability.CanReach(patient.Position, p, PathEndMode.ClosestTouch, traverseParams);

            List <Pawn> pawns = healer.Map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer).ListFullCopy();

            if (!Settings.Get().useDoctorMedicine)
            {
                pawns.Remove(healer);
            }
            if (!Settings.Get().usePatientMedicine)
            {
                pawns.Remove(patient);
            }
            if (!Settings.Get().useColonistMedicine)
            {
                pawns.RemoveAll(p => p.IsFreeColonist && p != healer && p != patient);
            }
            if (!Settings.Get().useAnimalMedicine)
            {
                pawns.RemoveAll(p => !p.IsColonist);
            }

            int minDistance = DistanceTo(healer, patient);

            if (!Settings.Get().useOtherEvenIfFar)
            {
                pawns.RemoveAll(p => DistanceTo(p, healer, patient) > minDistance + Settings.Get().distanceToUseFromOther * 2);                 //*2, there and back
            }
            pawns.RemoveAll(p => !validatorHolder(p));

            //Evaluate them all
            List <MedicineEvaluator> allMeds = new List <MedicineEvaluator>();

            //Add each ground
            foreach (Thing t in groundMedicines)
            {
                allMeds.Add(new MedicineEvaluator()
                {
                    thing    = t,
                    pawn     = null,
                    rating   = MedicineRating(t, sufficientQuality),
                    distance = DistanceTo(t, healer, patient)
                });
            }

            List <MedicineEvaluator> groundEvaluators = allMeds.ListFullCopy();

            //Add best from each pawn
            foreach (Pawn p in pawns)
            {
                Thing t = FindBestMedicineInInventory(p, patient, validatorMed, sufficientQuality, p == healer);
                if (t == null)
                {
                    continue;
                }
                allMeds.Add(new MedicineEvaluator()
                {
                    thing    = t,
                    pawn     = p,
                    rating   = MedicineRating(t, sufficientQuality),
                    distance = DistanceTo(p, healer, patient)
                });
            }

            //Find best
            allMeds.Sort();


            foreach (MedicineEvaluator tryMed in allMeds)
            {
                tryMed.DebugLog();
            }

            MedicineEvaluator bestMed = allMeds.LastOrDefault();

            List <ThingCount> result = new List <ThingCount>();

            if (bestMed.thing != null)
            {
                allMeds.RemoveLast();
                if (Settings.Get().useCloseMedicine&& bestMed.pawn != null)
                {
                    bestMed.DebugLog("Best: ");
                    Log.Message($"checking nearby:");
                    List <MedicineEvaluator> equalMedicines = groundEvaluators.FindAll(eval => eval.rating == bestMed.rating);
                    if (equalMedicines.Count > 0)
                    {
                        MedicineEvaluator closeMed = equalMedicines.MinBy(eval => eval.distance);
                        closeMed.DebugLog("Nearby med on the way there: ");
                        if (closeMed.distance <= minDistance + Settings.Get().distanceToUseEqualOnGround * 2)                         //*2, there and back
                        {
                            bestMed = closeMed;
                        }
                    }
                }

                //Check if any minimal medicine exists
                if (allMeds.Count == 0 || bestMed.rating == allMeds.MinBy(m => m.rating).rating)
                {
                    GetMedicineCountToFullyHeal_Patch.__beep_beep_MinimalMedicineAvailable = false;
                    Log.Message($"No minimal medicine available");
                }
                int count = Medicine.GetMedicineCountToFullyHeal(patient);

                totalCount = count;
                Log.Message($"Medicine count = {count}");

                bestMed.DebugLog("Best Med on " + (bestMed.pawn == null ? "ground" : "hand") + ":");

                int usedCount = Mathf.Min(bestMed.thing.stackCount, count);
                result.Add(new ThingCount(bestMed.thing, usedCount));
                count -= usedCount;
                //Find some more needed nearby
                if (count > 0)
                {
                    List <MedicineEvaluator> equalMedicines = allMeds.FindAll(eval => eval.rating == bestMed.rating);
                    equalMedicines.SortBy(eval => DistanceTo(bestMed.pawn ?? bestMed.thing, eval.pawn ?? eval.thing));
                    Thing droppedMedicine = null;
                    Log.Message($"But needs {count} more");
                    while (count > 0 && equalMedicines.Count > 0)
                    {
                        MedicineEvaluator closeMed = equalMedicines.First();
                        equalMedicines.RemoveAt(0);

                        closeMed.DebugLog("More: ");

                        if (DistanceTo(droppedMedicine ?? bestMed.pawn ?? bestMed.thing, closeMed.pawn ?? closeMed.thing) > 8f)                         //8f as defined in CheckForGetOpportunityDuplicate
                        {
                            break;
                        }

                        usedCount = Mathf.Min(closeMed.thing.stackCount, count);
                        closeMed.DebugLog("Using: ({usedCount})");

                        result.Add(new ThingCount(closeMed.thing, usedCount));
                        count -= usedCount;
                    }
                }
            }
            return(result);
        }
Пример #11
0
        private static bool Prefix(Pawn healer, Pawn patient, ref Thing __result)
        {
            if (patient.playerSettings == null || patient.playerSettings.medCare <= MedicalCareCategory.NoMeds ||
                !healer.Faction.IsPlayer)
            {
                return(true);
            }

            Log.Message(healer + " is tending to " + patient);

            float sufficientQuality = maxMedicineQuality + 1;             // nothing is sufficient!

            if (Settings.Get().downgradeExcessiveMedicine)
            {
                sufficientQuality = CalculateSufficientQuality(healer, patient);
                Log.Message("Sufficient medicine for best treatment is " + sufficientQuality + "(" + Settings.Get().goodEnoughDowngradeFactor + ")");
            }
            if (Settings.Get().minimalMedicineForNonUrgent)
            {
                if (patient.health.hediffSet.hediffs.All(h => !h.TendableNow || !h.IsUrgent()))
                {
                    sufficientQuality = minMedicineQuality;
                    Log.Message("Sufficient medicine for non-urgent care is " + sufficientQuality);
                }
            }

            //Med
            Predicate <Thing> validatorMed = t => patient.playerSettings.medCare.AllowsMedicine(t.def);

            try
            {
                ((Action)(() =>
                {
                    MedicalCareCategory pharmacistAdvice = Pharmacist.PharmacistUtility.TendAdvice(patient);
                    validatorMed = t => pharmacistAdvice.AllowsMedicine(t.def);
                }))();
            }
            catch (Exception) { }

            //Ground
            Map               map            = patient.Map;
            TraverseParms     traverseParams = TraverseParms.For(healer, Danger.Deadly, TraverseMode.ByPawn, false);
            Predicate <Thing> validator      = (Thing t) => validatorMed(t) &&
                                               map.reachability.CanReach(patient.Position, t, PathEndMode.ClosestTouch, traverseParams) &&
                                               !t.IsForbidden(healer) && healer.CanReserve(t, FindBestMedicine.maxPawns, 1);//can reserve at least 1
            Func <Thing, float> priorityGetter  = (Thing t) => MedicineRating(t, sufficientQuality);
            List <Thing>        groundMedicines = patient.Map.listerThings.ThingsInGroup(ThingRequestGroup.Medicine).FindAll(t => validator(t));

            //Pawns
            Predicate <Pawn> validatorHolder = (Pawn p) =>
                                               map.reachability.CanReach(patient.Position, p, PathEndMode.ClosestTouch, traverseParams);

            List <Pawn> pawns = healer.Map.mapPawns.SpawnedPawnsInFaction(Faction.OfPlayer).ListFullCopy();

            if (!Settings.Get().useDoctorMedicine)
            {
                pawns.Remove(healer);
            }
            if (!Settings.Get().usePatientMedicine)
            {
                pawns.Remove(patient);
            }
            if (!Settings.Get().useColonistMedicine)
            {
                pawns.RemoveAll(p => p.IsFreeColonist && p != healer && p != patient);
            }
            if (!Settings.Get().useAnimalMedicine)
            {
                pawns.RemoveAll(p => !p.IsColonist);
            }

            int minDistance = DistanceTo(healer, patient);

            if (!Settings.Get().useOtherEvenIfFar)
            {
                pawns.RemoveAll(p => DistanceTo(p, healer, patient) > minDistance + Settings.Get().distanceToUseFromOther * 2);                 //*2, there and back
            }
            pawns.RemoveAll(p => !validatorHolder(p));

            //Evaluate them all
            List <MedicineEvaluator> allMeds = new List <MedicineEvaluator>();

            //Add each ground
            foreach (Thing t in groundMedicines)
            {
                allMeds.Add(new MedicineEvaluator()
                {
                    thing    = t,
                    pawn     = null,
                    rating   = MedicineRating(t, sufficientQuality),
                    distance = DistanceTo(t, healer, patient)
                });
            }

            List <MedicineEvaluator> groundEvaluators = allMeds.ListFullCopy();

            //Add best from each pawn
            foreach (Pawn p in pawns)
            {
                Thing t = FindBestMedicineInInventory(p, patient, validatorMed, sufficientQuality, p == healer);
                if (t == null)
                {
                    continue;
                }
                allMeds.Add(new MedicineEvaluator()
                {
                    thing    = t,
                    pawn     = p,
                    rating   = MedicineRating(t, sufficientQuality),
                    distance = DistanceTo(p, healer, patient)
                });
            }

            //Find best
            allMeds.Sort();


            foreach (MedicineEvaluator tryMed in allMeds)
            {
                tryMed.DebugLog();
            }

            MedicineEvaluator bestMed = allMeds.LastOrDefault();

            if (bestMed.thing != null)
            {
                allMeds.RemoveLast();
                if (Settings.Get().useCloseMedicine&& bestMed.pawn != null)
                {
                    bestMed.DebugLog("Best: ");
                    Log.Message("checking nearby:");
                    List <MedicineEvaluator> equalMedicines = groundEvaluators.FindAll(eval => eval.rating == bestMed.rating);
                    if (equalMedicines.Count > 0)
                    {
                        MedicineEvaluator closeMed = equalMedicines.MinBy(eval => eval.distance);
                        closeMed.DebugLog("Nearby med on the way there: ");
                        if (closeMed.distance <= minDistance + Settings.Get().distanceToUseEqualOnGround * 2)                         //*2, there and back
                        {
                            bestMed = closeMed;
                        }
                    }
                }

                //Check if any minimal medicine exists
                if (allMeds.Count == 0 || bestMed.rating == allMeds.MinBy(m => m.rating).rating)
                {
                    GetMedicineCountToFullyHeal_Patch.__beep_beep_MinimalMedicineAvailable = false;
                    Log.Message("No minimal medicine available");
                }
                int count = Medicine.GetMedicineCountToFullyHeal(patient);

                JobOnThing_Patch.medCount = count;
                Log.Message("FindBestMedicine count = " + count);

                if (bestMed.pawn == null)
                {
                    bestMed.DebugLog("Best Med on ground:");
                    __result = bestMed.thing;
                }
                else
                {
                    // because The Toil to get this medicine is FailOnDespawnedNullOrForbidden
                    // And Medicine in inventory is despawned
                    // You can't set the job to use already carried medicine.
                    // Editing the toil would be more difficult.
                    // But we can drop it so the normal job picks it back it  ¯\_(ツ)_/¯
                    bestMed.DebugLog("Best Med on hand: ");

                    //Drop it!
                    int dropCount = Mathf.Min(bestMed.thing.stackCount, count);
                    count   -= dropCount;
                    __result = bestMed.thing;
                    //	return true;

                    //Todo: mid-job getting new medicine fails since this isn't dropped mid-toil. Sokay since it just fails and restarts.
                    //if healer job is tend maybe?

                    //Find some more needed nearby
                    //bestMed is dropped in Notify_Start, but these aren't tracked there so they are dropped now.

                    //In a very odd case that you right-click assign a tend and a second pawn's medicine is needed, he might drop his entire inventory
                    // That's a vanilla thing though that calls JobOnThing over and over instead of HasJobOnThing
                    if (count > 0)
                    {
                        List <MedicineEvaluator> equalMedicines = allMeds.FindAll(eval => eval.rating == bestMed.rating);
                        equalMedicines.SortBy(eval => DistanceTo(bestMed.pawn, eval.pawn ?? eval.thing));
                        Thing droppedMedicine = null;
                        Log.Message("But needs " + count + " more");
                        while (count > 0 && equalMedicines.Count > 0)
                        {
                            MedicineEvaluator closeMed = equalMedicines.First();
                            equalMedicines.RemoveAt(0);

                            closeMed.DebugLog("More: ");

                            if (DistanceTo(droppedMedicine ?? bestMed.pawn, closeMed.pawn ?? closeMed.thing) > 8f)                             //8f as defined in CheckForGetOpportunityDuplicate
                            {
                                return(false);
                            }

                            dropCount = Mathf.Min(closeMed.thing.stackCount, count);
                            closeMed.DebugLog("Using: (" + dropCount + ")");

                            closeMed.pawn?.inventory.innerContainer.TryDrop(closeMed.thing, ThingPlaceMode.Near, dropCount, out droppedMedicine);
                            if (droppedMedicine != null && !droppedMedicine.IsForbidden(healer) && healer.CanReserve(droppedMedicine, maxPawns, count))
                            {
                                count -= dropCount;
                            }
                            //else return false;
                        }
                    }
                }

                //Use it!
                //Log.Message("using inventory " + medicine);
                //healer.carryTracker.innerContainer.TryAddOrTransfer(medicine, count);
                //__result = medicine;
            }
            return(__result == null);
        }
            public static void Listener(Pawn healer, Pawn patient, ref Thing __result)
            {
                try
                {
                    /*if (!)
                     *  return true;*/


                    if (Settings.androidsCanUseOrganicMedicine)
                    {
                        return;
                    }

                    var patientIsAndroid = Utils.ExceptionAndroidList.Contains(patient.def.defName) || patient.IsCyberAnimal();

                    if (patient.playerSettings == null || patient.playerSettings.medCare <= MedicalCareCategory.NoMeds)
                    {
                        __result = null;
                        return;
                    }

                    if (Medicine.GetMedicineCountToFullyHeal(patient) <= 0)
                    {
                        __result = null;
                        return;
                    }

                    Predicate <Thing> predicate;


                    float medicalPotency = 0;
                    if (__result != null)
                    {
                        medicalPotency = __result.def.GetStatValueAbstract(StatDefOf.MedicalPotency);
                    }

                    if (patientIsAndroid)
                    {
                        predicate = m => Utils.ExceptionNanoKits.Contains(m.def.defName) && m.def.GetStatValueAbstract(StatDefOf.MedicalPotency) <= medicalPotency &&
                                    !m.IsForbidden(healer) && patient.playerSettings.medCare.AllowsMedicine(m.def) && healer.CanReserve(m, 10, 1);
                    }
                    else
                    {
                        predicate = m => !Utils.ExceptionNanoKits.Contains(m.def.defName) && m.def.GetStatValueAbstract(StatDefOf.MedicalPotency) <= medicalPotency &&
                                    !m.IsForbidden(healer) && !m.IsForbidden(healer) && patient.playerSettings.medCare.AllowsMedicine(m.def) && healer.CanReserve(m, 10, 1);
                    }

                    Func <Thing, float> priorityGetter = t => t.def.GetStatValueAbstract(StatDefOf.MedicalPotency);

                    var position       = patient.Position;
                    var map            = patient.Map;
                    var searchSet      = patient.Map.listerThings.ThingsInGroup(ThingRequestGroup.Medicine);
                    var peMode         = PathEndMode.ClosestTouch;
                    var traverseParams = TraverseParms.For(healer);
                    var validator      = predicate;
                    __result = GenClosest.ClosestThing_Global_Reachable(position, map, searchSet, peMode, traverseParams, 9999f, validator, priorityGetter);
                }
                catch (Exception e)
                {
                    Log.Message("[ATPP] HealthAIUtility.FindBestMedicine(Error) : " + e.Message + " - " + e.StackTrace);
                }
            }