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; } }
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); }
//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); }
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)); }
//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; }
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)); } }
//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); }
//public virtual void PostRemoved() public static void Prefix(Hediff __instance) { Log.Message($"removing {__instance} from priorityCare"); PriorityCareComp.Get().Remove(__instance); }