燃料装填

This commit is contained in:
2025-10-04 14:52:13 +08:00
parent 6f9996c5df
commit 7bf28aa66b
7 changed files with 186 additions and 4 deletions

View File

@@ -146,6 +146,8 @@
<Compile Include="Building_Comps\WULA_MutiFuelSpawner\Patch_CompRefuelableWithKey.cs" />
<Compile Include="Building_Comps\CompNutritionToFuelConverter.cs" />
<Compile Include="Building_Comps\CompAutoEjector.cs" />
<Compile Include="Jobs\JobDriver_Refuel_Nutrition.cs" />
<Compile Include="WorkGivers\WorkGiver_Refuel_Nutrition.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\Hediff_ConfigurableMutant.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\Hediff_NecroticVirus_Configurable.cs" />
<Compile Include="Hediffs\ARA_ConfigurableMutant\HediffComp_NecroticTransformation.cs" />

View File

@@ -63,10 +63,7 @@ namespace ArachnaeSwarm
fuelNeeded = TargetFuelLevel - Fuel;
}
if (totalNutritionGained > 0 && Props.fuelGizmoLabel != null)
{
Messages.Message("MessageRefueled".Translate(parent.LabelShort, totalNutritionGained.ToString("0.##"), Props.fuelGizmoLabel), parent, MessageTypeDefOf.PositiveEvent);
}
// Let the job driver handle the message. This component should only handle logic.
}
public void ReceiveFuel(float amount)

View File

@@ -0,0 +1,88 @@
using System.Collections.Generic;
using RimWorld;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class JobDriver_Refuel_Nutrition : JobDriver
{
private const TargetIndex RefuelableInd = TargetIndex.A;
private const TargetIndex FuelInd = TargetIndex.B;
private const int RefuelingDuration = 240;
protected Thing Refuelable => job.GetTarget(RefuelableInd).Thing;
// --- KEY CHANGE HERE ---
// We specifically target CompRefuelableNutrition and its children.
protected CompRefuelableNutrition RefuelableComp => Refuelable.TryGetComp<CompRefuelableNutrition>();
protected Thing Fuel => job.GetTarget(FuelInd).Thing;
public override bool TryMakePreToilReservations(bool errorOnFailed)
{
if (pawn.Reserve(Refuelable, job, 1, -1, null, errorOnFailed))
{
return pawn.Reserve(Fuel, job, 1, -1, null, errorOnFailed);
}
return false;
}
protected override IEnumerable<Toil> MakeNewToils()
{
this.FailOnDespawnedNullOrForbidden(RefuelableInd);
AddEndCondition(() => !RefuelableComp.IsFull ? JobCondition.Ongoing : JobCondition.Succeeded);
AddFailCondition(() => !job.playerForced && !RefuelableComp.ShouldAutoRefuelNowIgnoringFuelPct);
AddFailCondition(() => !RefuelableComp.allowAutoRefuel && !job.playerForced);
yield return Toils_General.DoAtomic(delegate
{
job.count = RefuelableComp.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(RefuelableInd, PathEndMode.Touch);
yield return Toils_General.Wait(RefuelingDuration)
.FailOnDestroyedNullOrForbidden(FuelInd)
.FailOnDestroyedNullOrForbidden(RefuelableInd)
.FailOnCannotTouch(RefuelableInd, PathEndMode.Touch)
.WithProgressBarToilDelay(RefuelableInd);
// Use our custom Refuel toil for CompRefuelableNutrition
yield return FinalizeRefueling_Nutrition();
}
// Custom Finalize Toil that uses the specific Refuel method from CompRefuelableNutrition
public Toil FinalizeRefueling_Nutrition()
{
Toil toil = new Toil();
toil.initAction = delegate()
{
Pawn actor = toil.GetActor();
Job curJob = actor.jobs.curJob;
Thing refuelableThing = curJob.GetTarget(RefuelableInd).Thing;
CompRefuelableNutrition refuelableComp = refuelableThing.TryGetComp<CompRefuelableNutrition>();
if (actor.carryTracker.CarriedThing == null)
{
Log.Error(actor + " is not carrying anything to refuel with.");
// The correct way to end the job from within a Toil's action.
actor.jobs.EndCurrentJob(JobCondition.Incompletable);
return;
}
// Call the specific Refuel method from our custom component
refuelableComp.Refuel(new List<Thing> { actor.carryTracker.CarriedThing });
};
toil.defaultCompleteMode = ToilCompleteMode.Instant;
return toil;
}
}
}

View File

@@ -0,0 +1,70 @@
using System.Collections.Generic;
using System.Linq;
using RimWorld;
using Verse;
using Verse.AI;
namespace ArachnaeSwarm
{
public class WorkGiver_Refuel_Nutrition : WorkGiver_Scanner
{
public override ThingRequest PotentialWorkThingRequest => ThingRequest.ForGroup(ThingRequestGroup.BuildingArtificial);
public override PathEndMode PathEndMode => PathEndMode.Touch;
public override IEnumerable<Thing> PotentialWorkThingsGlobal(Pawn pawn)
{
// Find all buildings that have our special component.
return pawn.Map.listerBuildings.allBuildingsColonist.Where(b =>
b.GetComp<CompRefuelableNutrition>() != null);
}
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
var building = t as Building;
if (building == null) return false;
// --- KEY CHANGE HERE ---
// Target the specific nutrition component
var refuelableComp = building.GetComp<CompRefuelableNutrition>();
if (refuelableComp == null || refuelableComp.IsFull) return false;
if (!refuelableComp.ShouldAutoRefuelNow && !forced) return false;
if (building.IsForbidden(pawn) || !pawn.CanReserve(building, 1, -1, null, forced)) return false;
var fuel = FindBestFuel(pawn, refuelableComp);
if (fuel == null)
{
JobFailReason.Is("NoFuelToRefuel".Translate(refuelableComp.Props.fuelFilter.Summary));
return false;
}
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
var building = t as Building;
var refuelableComp = building.GetComp<CompRefuelableNutrition>();
var fuel = FindBestFuel(pawn, refuelableComp);
// Return our custom Job
return new Job(DefDatabase<JobDef>.GetNamed("ARA_Refuel_Nutrition"), building, fuel);
}
private Thing FindBestFuel(Pawn pawn, CompRefuelable refuelable)
{
var fuelFilter = refuelable.Props.fuelFilter;
return GenClosest.ClosestThingReachable(
pawn.Position,
pawn.Map,
ThingRequest.ForGroup(ThingRequestGroup.HaulableEver),
PathEndMode.ClosestTouch,
TraverseParms.For(pawn),
9999f,
thing => !thing.IsForbidden(pawn) && fuelFilter.Allows(thing) && pawn.CanReserve(thing)
);
}
}
}