This commit is contained in:
2026-02-25 17:30:59 +08:00
parent 0509f26c3c
commit fff40b0edb
70 changed files with 3951 additions and 1219 deletions

View File

@@ -0,0 +1,176 @@
// JobDriver_RefuelMech.cs
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using Verse;
using Verse.AI;
using UnityEngine;
namespace WulaFallenEmpire
{
public class JobDriver_RefuelMech : JobDriver
{
private const TargetIndex MechInd = TargetIndex.A;
private const TargetIndex FuelInd = TargetIndex.B;
private const int RefuelingDuration = 240; // 基础加注时间
protected Pawn Mech => job.GetTarget(MechInd).Thing as Pawn;
protected CompMechFuel FuelComp => Mech?.TryGetComp<CompMechFuel>();
protected Thing Fuel => job.GetTarget(FuelInd).Thing;
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
Pawn pawn = this.pawn;
Job job = this.job;
LocalTargetInfo target = job.GetTarget(MechInd);
if (!pawn.Reserve(target, job, 1, -1, null, errorOnFailed))
{
return false;
}
if (!pawn.Reserve(job.GetTarget(FuelInd), job, 1, -1, null, errorOnFailed))
{
return false;
}
return true;
}
protected override IEnumerable<Toil> MakeNewToils()
{
// 检查目标是否有效
this.FailOnDespawnedNullOrForbidden(MechInd);
this.FailOn(() => FuelComp == null);
// 添加结束条件:燃料已满
AddEndCondition(() => {
if (FuelComp.IsFull)
return JobCondition.Succeeded;
return JobCondition.Ongoing;
});
// 如果不是玩家强制命令,检查是否应该自动加注
AddFailCondition(() => {
if (job.playerForced)
return false;
// 获取驾驶员组件
var pilotComp = Mech.TryGetComp<CompMechPilotHolder>();
bool hasPilot = pilotComp != null && pilotComp.HasPilots;
// 如果有驾驶员且不是玩家强制命令,不自动加注
if (hasPilot && !job.playerForced)
return true;
// 检查燃料组件是否允许自动加注
if (!FuelComp.Props.allowAutoRefuel && !job.playerForced)
return true;
return false;
});
// 第一步:计算需要多少燃料
yield return Toils_General.DoAtomic(delegate
{
if (FuelComp != null)
{
job.count = FuelComp.GetFuelCountToFullyRefuel();
}
});
// 第二步:预留燃料
Toil reserveFuel = Toils_Reserve.Reserve(FuelInd);
yield return reserveFuel;
// 第三步:前往燃料位置
yield return Toils_Goto.GotoThing(FuelInd, PathEndMode.ClosestTouch)
.FailOnDespawnedNullOrForbidden(FuelInd)
.FailOnSomeonePhysicallyInteracting(FuelInd);
// 第四步:拿起燃料
yield return Toils_Haul.StartCarryThing(FuelInd, putRemainderInQueue: false, subtractNumTakenFromJobCount: true)
.FailOnDestroyedNullOrForbidden(FuelInd);
// 第五步:检查是否有机会拿更多燃料
yield return Toils_Haul.CheckForGetOpportunityDuplicate(reserveFuel, FuelInd, TargetIndex.None, takeFromValidStorage: true);
// 第六步:前往机甲位置
yield return Toils_Goto.GotoThing(MechInd, PathEndMode.Touch);
// 第七步:等待加注(有进度条)
Toil refuelToil = Toils_General.Wait(RefuelingDuration)
.FailOnDestroyedNullOrForbidden(FuelInd)
.FailOnDestroyedNullOrForbidden(MechInd)
.FailOnCannotTouch(MechInd, PathEndMode.Touch)
.WithProgressBarToilDelay(MechInd);
// 调整加注时间基于燃料组件的速度因子
refuelToil.defaultDuration = Mathf.RoundToInt(RefuelingDuration / FuelComp.Props.refuelSpeedFactor);
yield return refuelToil;
// 第八步:完成加注 - 模仿 RimWorld 原版实现
yield return FinalizeRefueling(MechInd, FuelInd);
}
// 模仿 RimWorld.Toils_Refuel.FinalizeRefueling 的实现
private static Toil FinalizeRefueling(TargetIndex refuelableInd, TargetIndex fuelInd)
{
Toil toil = ToilMaker.MakeToil("FinalizeRefueling");
toil.initAction = delegate
{
Pawn actor = toil.actor;
Job curJob = actor.CurJob;
Thing refuelable = curJob.GetTarget(refuelableInd).Thing;
CompMechFuel fuelComp = refuelable.TryGetComp<CompMechFuel>();
if (fuelComp != null)
{
// 获取所有燃料物品
List<Thing> fuelThings;
if (actor.CurJob.placedThings.NullOrEmpty())
{
// 如果没有 placedThings则使用燃料目标
Thing fuel = curJob.GetTarget(fuelInd).Thing;
if (fuel != null)
{
fuelThings = new List<Thing> { fuel };
}
else
{
fuelThings = null;
}
}
else
{
// 使用 placedThings 中的所有燃料物品
fuelThings = actor.CurJob.placedThings.Select((ThingCountClass p) => p.thing).ToList();
}
if (fuelThings != null)
{
// 计算总燃料量并销毁燃料物品
float totalFuel = 0f;
foreach (Thing fuelThing in fuelThings)
{
if (fuelThing != null && fuelThing.def == fuelComp.FuelType)
{
totalFuel += fuelThing.stackCount;
fuelThing.Destroy(DestroyMode.Vanish);
}
}
// 添加燃料到机甲
if (totalFuel > 0)
{
fuelComp.Refuel(totalFuel);
}
}
}
};
toil.defaultCompleteMode = ToilCompleteMode.Instant;
return toil;
}
}
}

View File

@@ -0,0 +1,123 @@
// WorkGiver_RefuelMech.cs
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using Verse;
using Verse.AI;
namespace WulaFallenEmpire
{
public class WorkGiver_RefuelMech : WorkGiver_Scanner
{
public override PathEndMode PathEndMode => PathEndMode.Touch;
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
{
// 返回所有需要燃料的机甲
// 修复:使用 LINQ 的 Where 方法而不是 FindAll
var mechs = pawn.Map.mapPawns.AllPawnsSpawned.Where(p =>
p.TryGetComp<CompMechFuel>() != null);
foreach (Pawn mech in mechs)
{
yield return mech;
}
}
public override bool ShouldSkip(Pawn pawn, bool forced = false)
{
// 如果没有需要燃料的机甲,跳过
return !PotentialWorkThingsGlobal(pawn).Any();
}
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
if (!(t is Pawn mech))
return false;
var fuelComp = mech.TryGetComp<CompMechFuel>();
if (fuelComp == null)
return false;
// 检查机甲是否已加满燃料
if (fuelComp.IsFull)
return false;
// 检查是否有可用的燃料
if (FindFuel(pawn, fuelComp) == null)
return false;
// 检查是否能接触到机甲
if (!pawn.CanReserveAndReach(t, PathEndMode.Touch, Danger.Some))
return false;
// 检查机甲状态
var pilotComp = mech.TryGetComp<CompMechPilotHolder>();
bool hasPilot = pilotComp != null && pilotComp.HasPilots;
// 如果有驾驶员且不是强制命令,不自动加注
if (hasPilot && !forced)
return false;
// 检查燃料组件是否允许自动加注
if (!fuelComp.Props.allowAutoRefuel && !forced)
return false;
// 检查是否达到自动加注阈值
if (!forced && !fuelComp.NeedsRefueling)
return false;
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
var fuelComp = t.TryGetComp<CompMechFuel>();
if (fuelComp == null)
return null;
// 寻找燃料
Thing fuel = FindFuel(pawn, fuelComp);
if (fuel == null)
return null;
// 创建加注工作
Job job = JobMaker.MakeJob(Wula_JobDefOf.WULA_RefuelMech, t, fuel);
job.count = fuelComp.GetFuelCountToFullyRefuel();
return job;
}
// 修改方法:返回 Thing 而不是 bool
private Thing FindFuel(Pawn pawn, CompMechFuel fuelComp)
{
if (fuelComp.FuelType == null)
return null;
// 在库存中寻找燃料
Thing fuel = FindFuelInInventory(pawn, fuelComp.FuelType);
if (fuel != null)
return fuel;
// 在地图上寻找燃料
fuel = GenClosest.ClosestThingReachable(
pawn.Position,
pawn.Map,
ThingRequest.ForDef(fuelComp.FuelType),
PathEndMode.ClosestTouch,
TraverseParms.For(pawn),
9999f,
validator: thing => !thing.IsForbidden(pawn) && pawn.CanReserve(thing)
);
return fuel;
}
private Thing FindFuelInInventory(Pawn pawn, ThingDef fuelType)
{
if (pawn.inventory == null)
return null;
return pawn.inventory.innerContainer.FirstOrDefault(t => t.def == fuelType);
}
}
}