1
This commit is contained in:
176
Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
Normal file
176
Source/WulaFallenEmpire/Work/RefuelMech/JobDriver_RefuelMech.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
123
Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
Normal file
123
Source/WulaFallenEmpire/Work/RefuelMech/WorkGiver_RefuelMech.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user