This commit is contained in:
2025-09-05 13:35:41 +08:00
parent c87c88a681
commit 3a3c30087a
11 changed files with 284 additions and 17 deletions

View File

@@ -0,0 +1,16 @@
using Verse;
using RimWorld;
namespace ArachnaeSwarm
{
[DefOf]
public static class ARA_TrainableDefOf_Cleaning
{
public static TrainableDef ARA_Cleaning;
static ARA_TrainableDefOf_Cleaning()
{
DefOfHelper.EnsureInitializedInCtor(typeof(ARA_TrainableDefOf_Cleaning));
}
}
}

View File

@@ -0,0 +1,50 @@
using Verse;
using Verse.AI;
using RimWorld;
namespace ArachnaeSwarm
{
public class JobGiver_Cleaner : ThinkNode_JobGiver
{
private WorkGiver_ArachnaeClean _workGiver;
public override void ResolveReferences()
{
base.ResolveReferences();
// We instantiate our custom WorkGiver here.
// It doesn't need a Def because it's not a standard game WorkGiver.
_workGiver = new WorkGiver_ArachnaeClean();
}
protected override Job TryGiveJob(Pawn pawn)
{
if (_workGiver == null)
{
Log.ErrorOnce("JobGiver_Cleaner's WorkGiver is null. ResolveReferences was not called.", 91354);
return null;
}
// The WorkGiver will handle both filth and snow.
// We just need to find the closest potential job.
// The logic is simplified here; the real work is in the WorkGiver.
// Find the closest filth to clean
Thing closestFilth = _workGiver.FindClosestFilth(pawn);
if (closestFilth != null)
{
Job filthJob = _workGiver.JobOnThing(pawn, closestFilth);
if (filthJob != null) return filthJob;
}
// If no filth, find the closest snow/sand to clear
IntVec3 closestSnowCell = _workGiver.FindClosestSnow(pawn);
if (closestSnowCell.IsValid)
{
Job snowJob = _workGiver.JobOnCell(pawn, closestSnowCell);
if (snowJob != null) return snowJob;
}
return null;
}
}
}

View File

@@ -0,0 +1,21 @@
using Verse;
using Verse.AI;
using RimWorld;
namespace ArachnaeSwarm
{
public class ThinkNode_ConditionalAnimalShouldDoCleaningWork : ThinkNode_Conditional
{
protected override bool Satisfied(Pawn pawn)
{
if (pawn.training == null)
{
return false;
}
// Check if the animal has learned and is set to perform "Cleaning"
return pawn.training.HasLearned(ARA_TrainableDefOf_Cleaning.ARA_Cleaning) &&
pawn.training.GetWanted(ARA_TrainableDefOf_Cleaning.ARA_Cleaning);
}
}
}

View File

@@ -0,0 +1,82 @@
using System.Collections.Generic;
using Verse;
using Verse.AI;
using RimWorld;
namespace ArachnaeSwarm
{
public class WorkGiver_ArachnaeClean : WorkGiver_Scanner
{
private const int MinTicksSinceThickened = 600;
public override PathEndMode PathEndMode => PathEndMode.Touch;
// --- Filth Cleaning Logic ---
public Thing FindClosestFilth(Pawn pawn)
{
return GenClosest.ClosestThing_Global(
pawn.Position,
pawn.Map.listerFilthInHomeArea.FilthInHomeArea,
maxDistance: 9999f,
validator: t => HasJobOnThing(pawn, t)
);
}
public override bool HasJobOnThing(Pawn pawn, Thing t, bool forced = false)
{
if (!(t is Filth filth)) return false;
if (!filth.Map.areaManager.Home[filth.Position]) return false;
if (filth.Fogged() || !pawn.CanReserve(t, 1, -1, null, forced)) return false;
if (filth.TicksSinceThickened < MinTicksSinceThickened) return false;
return true;
}
public override Job JobOnThing(Pawn pawn, Thing t, bool forced = false)
{
Job job = JobMaker.MakeJob(JobDefOf.Clean);
job.AddQueuedTarget(TargetIndex.A, t);
// Simplified multi-clean logic from original WorkGiver_CleanFilth
int num = 15;
for (int i = 0; i < 100; i++)
{
IntVec3 c = t.Position + GenRadial.RadialPattern[i];
if (c.InBounds(pawn.Map))
{
List<Thing> thingList = c.GetThingList(pawn.Map);
foreach(var thing in thingList)
{
if (thing != t && HasJobOnThing(pawn, thing, forced))
{
job.AddQueuedTarget(TargetIndex.A, thing);
}
}
}
if (job.GetTargetQueue(TargetIndex.A).Count >= num) break;
}
return job;
}
// --- Snow Clearing Logic ---
public IntVec3 FindClosestSnow(Pawn pawn)
{
return CellFinder.RandomClosewalkCellNear(pawn.Position, pawn.Map, 100,
c => HasJobOnCell(pawn, c) && pawn.CanReach(c, PathEndMode.Touch, Danger.Deadly));
}
public override bool HasJobOnCell(Pawn pawn, IntVec3 c, bool forced = false)
{
if (pawn.Map.snowGrid.GetDepth(c) < 0.2f) return false;
if (!pawn.Map.areaManager.SnowOrSandClear[c]) return false; // Must be in the clear zone
if (!pawn.CanReserve(c, 1, -1, null, forced)) return false;
return true;
}
public override Job JobOnCell(Pawn pawn, IntVec3 c, bool forced = false)
{
return JobMaker.MakeJob(JobDefOf.ClearSnow, c);
}
}
}

View File

@@ -118,6 +118,12 @@
<Compile Include="ARA_HuggingFace\CompAbilityEffect_Possess.cs" />
<Compile Include="ARA_HuggingFace\CompProperties_AbilityPossess.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="ARA_TrainingWork\JobClean\ARA_TrainableDefOf_Cleaning.cs" />
<Compile Include="ARA_TrainingWork\JobClean\JobGiver_Cleaner.cs" />
<Compile Include="ARA_TrainingWork\JobClean\ThinkNode_ConditionalAnimalShouldDoCleaningWork.cs" />
<Compile Include="ARA_TrainingWork\JobClean\WorkGiver_ArachnaeClean.cs" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- 自定义清理任务删除obj文件夹中的临时文件 -->
<Target Name="CleanDebugFiles" AfterTargets="Build">