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,5 +1,4 @@
using System.Collections.Generic;
using UnityEngine;
using Verse;
using Verse.AI;
using RimWorld;
@@ -11,17 +10,16 @@ namespace WulaFallenEmpire
private const TargetIndex FoodSourceInd = TargetIndex.A;
private const TargetIndex PatientInd = TargetIndex.B;
private Thing FoodSource => job.GetTarget(FoodSourceInd).Thing;
private Pawn Patient => (Pawn)job.GetTarget(PatientInd).Thing;
protected Thing Food => job.GetTarget(FoodSourceInd).Thing;
protected Pawn Patient => (Pawn)job.GetTarget(PatientInd).Thing;
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
// 预留食物来源和病患
if (!pawn.Reserve(FoodSource, job, 1, -1, null, errorOnFailed))
if (!pawn.Reserve(Patient, job, 1, -1, null, errorOnFailed))
{
return false;
}
if (!pawn.Reserve(Patient, job, 1, -1, null, errorOnFailed))
if (!pawn.Reserve(Food, job, 1, -1, null, errorOnFailed))
{
return false;
}
@@ -30,110 +28,22 @@ namespace WulaFallenEmpire
protected override IEnumerable<Toil> MakeNewToils()
{
// 失败条件:如果病患被摧毁、为空或不在床上
this.FailOn(() => Patient.DestroyedOrNull());
this.FailOn(() => !Patient.InBed());
this.FailOnDespawnedNullOrForbidden(PatientInd);
this.FailOn(() => !FeedPatientUtility.ShouldBeFed(Patient));
// Toil 0: 检查医生库存中是否有能量核心
Toil checkInventoryToil = ToilMaker.MakeToil("CheckInventory");
checkInventoryToil.initAction = delegate
if (pawn.inventory != null && pawn.inventory.Contains(Food))
{
Thing inventoryFood = null;
foreach (Thing t in pawn.inventory.innerContainer)
{
ThingDefExtension_EnergySource energySourceExt = t.def.GetModExtension<ThingDefExtension_EnergySource>();
if (energySourceExt != null && t.IngestibleNow)
{
inventoryFood = t;
break;
}
}
if (inventoryFood != null)
{
// 如果库存中有食物则将Job的目标设置为库存食物并跳过拾取步骤直接前往病患
job.SetTarget(FoodSourceInd, inventoryFood);
pawn.jobs.curDriver.JumpToToil(Toils_Goto.GotoThing(PatientInd, PathEndMode.Touch)); // 跳转到前往病患的Toil
}
// 如果库存中没有则继续执行下一个Toil前往地图上的食物来源
};
yield return checkInventoryToil;
// Toil 1: 前往食物来源 (如果库存中没有则执行此Toil)
yield return Toils_Goto.GotoThing(FoodSourceInd, PathEndMode.ClosestTouch)
.FailOnDespawnedNullOrForbidden(FoodSourceInd)
.FailOn(() => !pawn.CanReserve(FoodSource, 1, -1, null, false)); // 在这里预留食物来源
// Toil 2: 拾取食物来源 (如果库存中没有则执行此Toil)
yield return Toils_Haul.StartCarryThing(FoodSourceInd); // 使用 StartCarryThing 拾取物品
// Toil 3: 前往病患
yield return Toils_Goto.GotoThing(PatientInd, PathEndMode.Touch)
.FailOnDespawnedOrNull(PatientInd);
// Toil 4: 喂食病患
Toil feedToil = ToilMaker.MakeToil("FeedWulaPatient");
feedToil.initAction = delegate
yield return Toils_Misc.TakeItemFromInventoryToCarrier(pawn, FoodSourceInd);
}
else
{
Pawn actor = feedToil.actor;
Thing food = actor.carryTracker.CarriedThing; // 医生携带的食物 (从地图拾取)
yield return Toils_Goto.GotoThing(FoodSourceInd, PathEndMode.ClosestTouch).FailOnForbidden(FoodSourceInd);
yield return Toils_Ingest.PickupIngestible(FoodSourceInd, pawn);
}
// 如果医生没有携带食物,检查是否在库存中 (从库存获取)
if (food == null)
{
food = job.GetTarget(FoodSourceInd).Thing; // 此时FoodSourceInd应该指向库存中的物品
if (food == null || !actor.inventory.innerContainer.Contains(food))
{
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
return;
}
}
// 获取乌拉能量需求
Need_WulaEnergy energyNeed = Patient.needs.TryGetNeed<Need_WulaEnergy>();
if (energyNeed == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 检查食物来源是否有自定义能量扩展
ThingDefExtension_EnergySource ext = food.def.GetModExtension<ThingDefExtension_EnergySource>();
if (ext == null)
{
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 补充乌拉的能量
energyNeed.CurLevel += ext.energyAmount;
// 消耗物品
if (actor.carryTracker.CarriedThing == food) // 如果是携带的物品
{
food.Destroy(DestroyMode.Vanish); // 销毁医生携带的物品
actor.carryTracker.innerContainer.ClearAndDestroyContents(); // 移除医生携带的物品
}
else if (actor.inventory.innerContainer.Contains(food)) // 如果是库存中的物品
{
food.stackCount--; // 减少库存物品数量
if (food.stackCount <= 0)
{
food.Destroy(DestroyMode.Vanish); // 如果数量为0销毁物品
}
}
else
{
// 理论上不应该发生
actor.jobs.EndCurrentJob(JobCondition.Errored);
return;
}
// 记录能量摄入 (可选)
// Patient.records.AddTo(RecordDefOf.NutritionEaten, ext.energyAmount);
};
feedToil.defaultCompleteMode = ToilCompleteMode.Instant;
yield return feedToil;
yield return Toils_Goto.GotoThing(PatientInd, PathEndMode.Touch);
yield return Toils_Ingest.ChewIngestible(Patient, 1.5f, FoodSourceInd, TargetIndex.None).FailOnCannotTouch(PatientInd, PathEndMode.Touch);
yield return Toils_Ingest.FinalizeIngest(Patient, FoodSourceInd);
}
}
}