Beispiel #1
0
 public static void DrawHediffCare(Hediff hediff, ref Rect iconRect)
 {
     if (PriorityCareComp.Get().TryGetValue(hediff, out MedicalCareCategory heCare))
     {
         Texture2D tex = ((Texture2D[])careTexturesField.GetValue(null))[(int)heCare];
         GUI.DrawTexture(iconRect, tex);
         iconRect.x -= iconRect.width;
     }
 }
Beispiel #2
0
        public static bool Prefix(Hediff __instance, ref float __result)
        {
            if (PriorityCareComp.Get().TryGetValue(__instance, out MedicalCareCategory hediffCare))
            {
                MedicalCareCategory defaultCare = __instance.pawn.GetCare();

                int diff = ((int)hediffCare) - ((int)defaultCare);
                __result += diff * 5;              //Raise priority for higher meds, lower for lower meds.
                return(false);
            }
            return(true);
        }
Beispiel #3
0
        //public virtual bool TendableNow(bool ignoreTimer = false);
        public static bool Prefix(ref bool __result, Hediff __instance, bool ignoreTimer)
        {
            if (ignoreTimer)
            {
                return(true);
            }

            if (PriorityCareComp.Get().TryGetValue(__instance, out MedicalCareCategory heCare) && heCare == MedicalCareCategory.NoCare)
            {
                __result = false;
                return(false);
            }
            return(true);
        }
Beispiel #4
0
        public static bool AllowsMedicineForHediff(Pawn deliveree, ThingDef med)
        {
            if (PriorityCareComp.MaxPriorityCare(deliveree, out MedicalCareCategory heCare))
            {
                //This is uses to allow higher medicine above normal limit below.
                //this is NOT used to stop the job is PriorityCare is lowered
                if (heCare.AllowsMedicine(med))
                {
                    return(true);
                }
            }

            //Not required but hey why dont I patch this in for Pharmacist
            MedicalCareCategory care = deliveree.GetCare();

            return(care.AllowsMedicine(med));
        }
 //public static Rect DrawElementStack<T>(Rect rect, float rowHeight, List<T> elements, StackElementDrawer<T> drawer, StackElementWidthGetter<T> widthGetter, float rowMargin = 4f, float elementMargin = 5f, bool allowOrderOptimization = true)
 public static Rect DrawElementStack2(Rect rect, float rowHeight, List <GenUI.AnonymousStackElement> elements, GenUI.StackElementDrawer <GenUI.AnonymousStackElement> drawer, GenUI.StackElementWidthGetter <GenUI.AnonymousStackElement> widthGetter, float rowMargin, float elementMargin, bool allowOrderOptimization, Hediff hediff)
 {
     if (PriorityCareComp.Get().TryGetValue(hediff, out MedicalCareCategory heCare))
     {
         elements.Add(new GenUI.AnonymousStackElement
         {
             drawer = delegate(Rect r)
             {
                 Texture2D tex = ((Texture2D[])careTexturesField.GetValue(null))[(int)heCare];
                 r             = new Rect(2 * rect.x + rect.width - r.x - 20f, r.y, 20f, 20f);
                 GUI.DrawTexture(r, tex);
             },
             width = 20f
         });
     }
     return(GenUI.DrawElementStack(rect, rowHeight, elements, drawer, widthGetter, rowMargin, elementMargin, allowOrderOptimization));
 }
Beispiel #6
0
        //Filter time-sensitive injuries
        public static void FilterInjuriesForMedCount(List <Hediff> hediffs)
        {
            Log.Message($"Filtering ({hediffs.ToStringSafeEnumerable()})");
            if (PriorityCareComp.MaxPriorityCare(hediffs, out MedicalCareCategory maxPriorityCare))
            {
                MedicalCareCategory defaultCare = hediffs.First().pawn.GetCare();

                //ignore defaultCare if none uses default
                if (PriorityCareComp.AllPriorityCare(hediffs))
                {
                    defaultCare = maxPriorityCare;
                }

                //Find highest care
                MedicalCareCategory highestCare = defaultCare > maxPriorityCare ? defaultCare : maxPriorityCare;
                Log.Message($"maxPriorityCare is {maxPriorityCare}, defaultCare is {defaultCare}, highestCare is {highestCare}");

                //remove anything less than that
                //Should check if medicine is available, but you just set to use it so this will assume you have it
                hediffs.RemoveAll(delegate(Hediff h)
                {
                    if (PriorityCareComp.Get().TryGetValue(h, out MedicalCareCategory heCare))
                    {
                        return(heCare < highestCare);
                    }
                    return(defaultCare < highestCare);
                });
            }

            if (Settings.Get().noMedicineForNonUrgent)
            {
                hediffs.RemoveAll(h => !h.IsUrgent());
            }
            else if (Settings.Get().minimalMedicineForNonUrgent&& __beep_beep_MinimalMedicineAvailable)
            {
                if (hediffs.Any(h => h.IsUrgent()))
                {
                    hediffs.RemoveAll(h => !h.IsUrgent());
                }
            }
            Log.Message($"Filtered to ({hediffs.ToStringSafeEnumerable()})");
            __beep_beep_MinimalMedicineAvailable = true;
        }
Beispiel #7
0
        public static void LabelButton(Rect rect, string text, Hediff hediff)
        {
            Widgets.Label(rect, text);
            if (hediff.TendableNow(true) && Event.current.button == 1 && Widgets.ButtonInvisible(rect))
            {
                List <FloatMenuOption> list = new List <FloatMenuOption>();

                //Default care
                list.Add(new FloatMenuOption("TD.DefaultCare".Translate(), delegate
                {
                    PriorityCareComp.Get().Remove(hediff);
                }));

                for (int i = 0; i < 5; i++)
                {
                    MedicalCareCategory mc = (MedicalCareCategory)i;
                    list.Add(new FloatMenuOption(mc.GetLabel(), delegate
                    {
                        PriorityCareComp.Get()[hediff] = mc;
                    }));
                }
                Find.WindowStack.Add(new FloatMenu(list));
            }
        }
Beispiel #8
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);
        }
Beispiel #9
0
 //public virtual void PostRemoved()
 public static void Prefix(Hediff __instance)
 {
     Log.Message($"removing {__instance} from priorityCare");
     PriorityCareComp.Get().Remove(__instance);
 }