This commit is contained in:
2025-07-22 19:07:21 +08:00
parent 4f524845a9
commit 15494e8a8e
26 changed files with 318 additions and 963 deletions

View File

@@ -1,28 +1,14 @@
using RimWorld;
using System.Collections.Generic;
using System.Linq;
using Verse;
using Verse.AI;
using System.Collections.Generic;
using System.Linq;
namespace WulaFallenEmpire
{
public class WorkGiver_FeedWulaPatient : WorkGiver_Scanner
{
private WorkGiverDefExtension_FeedWula ext;
private WorkGiverDefExtension_FeedWula Ext
{
get
{
if (ext == null)
{
ext = def.GetModExtension<WorkGiverDefExtension_FeedWula>();
}
return ext;
}
}
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForDef(ThingDef.Named("WulaSpecies"));
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.Pawn);
public override PathEndMode PathEndMode => PathEndMode.ClosestTouch;
@@ -30,52 +16,47 @@ namespace WulaFallenEmpire
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
{
// Mimic vanilla: Scan all pawns in bed.
return pawn.Map.mapPawns.AllPawns.Where(p => p.InBed());
return pawn.Map.mapPawns.AllPawns.Where(p => p.needs.TryGetNeed<Need_WulaEnergy>() != null && FeedPatientUtility.ShouldBeFed(p));
}
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn patient = t as Pawn;
// Basic validation, similar to vanilla
if (patient == null || patient == pawn || !patient.InBed() || patient.def.defName != "WulaSpecies")
if (!(t is Pawn patient) || patient == pawn)
{
return false;
}
// 如果病患正在充能,则不需要喂食
if (patient.health.hediffSet.HasHediff(DefDatabase<HediffDef>.GetNamed("WULA_ChargingHediff")))
{
return false;
}
// Our custom check: Is the Wula in shutdown?
Need_WulaEnergy energyNeed = patient.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null || !energyNeed.IsShutdown)
var extension = def.GetModExtension<WorkGiverDefExtension_FeedWula>();
if (energyNeed == null || energyNeed.CurLevelPercentage >= extension.feedThreshold)
{
return false;
}
// CRITICAL vanilla check: If the patient is a prisoner, this is a warden's job, not a doctor's.
// This prevents conflicts between two different work types trying to do the same thing.
if (!FeedPatientUtility.ShouldBeFed(patient))
{
return false;
}
if (WardenFeedUtility.ShouldBeFed(patient))
{
return false;
}
// CRITICAL vanilla check: Can the doctor reserve the patient?
// This prevents multiple doctors from trying to feed the same patient at the same time.
if (!pawn.CanReserve(patient, 1, -1, null, forced))
{
return false;
}
// Check for our energy source
if (Ext == null || Ext.energySourceDef == null)
if (!TryFindBestEnergySourceFor(pawn, patient, out _, out _))
{
Log.ErrorOnce("WorkGiver_FeedWulaPatient is missing the DefModExtension with a valid energySourceDef.", def.GetHashCode());
return false;
}
if (!FindBestEnergySourceFor(pawn, patient, out _, out _))
{
// Mimic vanilla: Provide a reason for failure.
JobFailReason.Is("NoFood".Translate()); // Using vanilla translation key for simplicity
JobFailReason.Is("NoWulaEnergyToFeed".Translate(patient.LabelShort, patient));
return false;
}
@@ -85,39 +66,30 @@ namespace WulaFallenEmpire
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Pawn patient = (Pawn)t;
if (FindBestEnergySourceFor(pawn, patient, out Thing energySource, out _))
if (TryFindBestEnergySourceFor(pawn, patient, out Thing energySource, out _))
{
Job job = JobMaker.MakeJob(DefDatabase<JobDef>.GetNamed("WULA_FeedWulaPatient"), energySource, patient);
job.count = 1; // Energy cores are single-use.
job.count = 1;
return job;
}
return null;
}
private bool FindBestEnergySourceFor(Pawn getter, Pawn eater, out Thing foodSource, out ThingDef foodDef)
private bool TryFindBestEnergySourceFor(Pawn getter, Pawn eater, out Thing energySource, out ThingDef energyDef)
{
foodSource = null;
foodDef = null;
energySource = null;
energyDef = null;
if (Ext == null || Ext.energySourceDef == null)
var allowedThings = getter.Map.listerThings.ThingsInGroup(ThingRequestGroup.HaulableEver)
.Where(x => x.def.GetModExtension<ThingDefExtension_EnergySource>() != null);
Thing thing = GenClosest.ClosestThing_Global(eater.Position, allowedThings, 99999f,
t => t.IngestibleNow && !t.IsForbidden(getter) && getter.CanReserve(t));
if (thing != null)
{
return false;
}
// CRITICAL vanilla check is embedded here: CanReserve(x) on the food source itself.
foodSource = GenClosest.ClosestThingReachable(
getter.Position,
getter.Map,
ThingRequest.ForDef(Ext.energySourceDef),
PathEndMode.OnCell,
TraverseParms.For(getter),
9999f,
(Thing x) => !x.IsForbidden(getter) && getter.CanReserve(x)
);
if (foodSource != null)
{
foodDef = foodSource.def;
energySource = thing;
energyDef = thing.def;
return true;
}