diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll index 652d822..d270c71 100644 Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj index fa0e51d..97942aa 100644 --- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj +++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj @@ -86,20 +86,17 @@ + + + + + - - - - - - - - diff --git a/Source/ArachnaeSwarm/JobGiver_Grower.cs b/Source/ArachnaeSwarm/JobGiver_Grower.cs index 2447445..29e70f5 100644 --- a/Source/ArachnaeSwarm/JobGiver_Grower.cs +++ b/Source/ArachnaeSwarm/JobGiver_Grower.cs @@ -8,7 +8,7 @@ namespace ArachnaeSwarm public class JobGiver_Grower : ThinkNode_JobGiver { private WorkGiver_GrowerHarvest _workGiverHarvest; - private WorkGiver_GrowerSow _workGiverSow; + private WorkGiver_ArachnaeSow _workGiverArachnaeSow; // 修改为我们的新 WorkGiver protected override Job TryGiveJob(Pawn pawn) { @@ -16,11 +16,11 @@ namespace ArachnaeSwarm if (_workGiverHarvest == null) { _workGiverHarvest = WorkGiverDefOf.GrowerHarvest.Worker as WorkGiver_GrowerHarvest; - _workGiverSow = WorkGiverDefOf.GrowerSow.Worker as WorkGiver_GrowerSow; + _workGiverArachnaeSow = new WorkGiver_ArachnaeSow(); // 直接实例化我们的 WorkGiver - if (_workGiverHarvest == null || _workGiverSow == null) + if (_workGiverHarvest == null || _workGiverArachnaeSow == null) { - Log.ErrorOnce("JobGiver_Grower: Failed to get WorkGiver_GrowerHarvest or WorkGiver_GrowerSow. DefOfs might not be initialized or DefNames are incorrect.", 123457); + Log.ErrorOnce("JobGiver_Grower: Failed to get WorkGiver_GrowerHarvest or WorkGiver_ArachnaeSow. DefOfs might not be initialized or WorkGiver_ArachnaeSow could not be instantiated.", 123457); return null; } } @@ -29,14 +29,16 @@ namespace ArachnaeSwarm Thing bestHarvestable = FindClosestThing(pawn, _workGiverHarvest); if (bestHarvestable != null) { - return _workGiverHarvest.JobOnThing(pawn, bestHarvestable); + // 调用 JobOnCell 以利用 WorkGiver_GrowerHarvest 的多目标打包逻辑 + return _workGiverHarvest.JobOnCell(pawn, bestHarvestable.Position); } // 2. 其次播种 - IntVec3 bestSowCell = FindClosestSowableCell(pawn, _workGiverSow); - if (bestSowCell.IsValid) + (IntVec3 bestSowCell, ThingDef plantToSow) = FindClosestSowableCellAndPlant(pawn, _workGiverArachnaeSow); // 使用我们的新 WorkGiver + if (bestSowCell.IsValid && plantToSow != null) { - return _workGiverSow.JobOnCell(pawn, bestSowCell); + // 现在直接调用 WorkGiver_ArachnaeSow 的 JobOnCell,它会处理 Job 的创建和 plantDefToSow 的设置 + return _workGiverArachnaeSow.JobOnCell(pawn, bestSowCell); } return null; @@ -55,30 +57,37 @@ namespace ArachnaeSwarm ); } - private IntVec3 FindClosestSowableCell(Pawn pawn, WorkGiver_Scanner scanner) + private (IntVec3, ThingDef) FindClosestSowableCellAndPlant(Pawn pawn, WorkGiver_ArachnaeSow scanner) // 修改为我们的新 WorkGiver 类型 { IntVec3 bestCell = IntVec3.Invalid; + ThingDef bestPlantToSow = null; float bestDistSq = float.MaxValue; foreach (Zone zone in pawn.Map.zoneManager.AllZones) { if (zone is Zone_Growing growingZone) { + ThingDef wantedPlant = growingZone.GetPlantDefToGrow(); + if (wantedPlant == null) continue; + foreach (IntVec3 cell in growingZone.Cells) { float distSq = pawn.Position.DistanceToSquared(cell); if (distSq < bestDistSq && pawn.CanReach(cell, PathEndMode.ClosestTouch, Danger.Deadly)) { - if (scanner.HasJobOnCell(pawn, cell)) + // 这里不再需要 WorkGiver_Grower.wantedPlantDef 的复杂处理 + // 因为 WorkGiver_ArachnaeSow.JobOnCell 会直接使用它计算出的 wantedPlantDef + if (scanner.HasJobOnCell(pawn, cell)) // HasJobOnCell 内部会根据 wantedPlant 计算 { bestDistSq = distSq; bestCell = cell; + bestPlantToSow = wantedPlant; // 确保返回正确的 plantDef } } } } } - return bestCell; + return (bestCell, bestPlantToSow); } } } diff --git a/Source/ArachnaeSwarm/WorkGiver_ArachnaeSow.cs b/Source/ArachnaeSwarm/WorkGiver_ArachnaeSow.cs new file mode 100644 index 0000000..ca6c4a3 --- /dev/null +++ b/Source/ArachnaeSwarm/WorkGiver_ArachnaeSow.cs @@ -0,0 +1,218 @@ +using System.Collections.Generic; +using Verse; +using Verse.AI; +using RimWorld; + +namespace ArachnaeSwarm +{ + public class WorkGiver_ArachnaeSow : WorkGiver_Grower + { + protected static string CantSowCavePlantBecauseOfLightTrans; + protected static string CantSowCavePlantBecauseUnroofedTrans; + + public override PathEndMode PathEndMode => PathEndMode.ClosestTouch; + + public static void ResetStaticData() + { + CantSowCavePlantBecauseOfLightTrans = "CantSowCavePlantBecauseOfLight".Translate(); + CantSowCavePlantBecauseUnroofedTrans = "CantSowCavePlantBecauseUnroofed".Translate(); + } + + protected override bool ExtraRequirements(IPlantToGrowSettable settable, Pawn pawn) + { + if (!settable.CanAcceptSowNow()) + { + return false; + } + IntVec3 c; + if (settable is Zone_Growing zone_Growing) + { + if (!zone_Growing.allowSow) + { + return false; + } + c = zone_Growing.Cells[0]; + } + else + { + c = ((Thing)settable).Position; + } + ThingDef wantedPlantDef = WorkGiver_Grower.CalculateWantedPlantDef(c, pawn.Map); + if (wantedPlantDef == null) + { + return false; + } + return true; + } + + public override Job JobOnCell(Pawn pawn, IntVec3 c, bool forced = false) + { + Map map = pawn.Map; + if (c.GetVacuum(pawn.Map) >= 0.5f) + { + return null; + } + + // 直接计算 wantedPlantDef,不再依赖静态字段 + ThingDef wantedPlantDefLocal = WorkGiver_Grower.CalculateWantedPlantDef(c, map); + if (wantedPlantDefLocal == null) + { + return null; + } + + if (!PlantUtility.GrowthSeasonNow(c, map, wantedPlantDefLocal)) + { + return null; + } + List thingList = c.GetThingList(map); + Zone_Growing zone_Growing = c.GetZone(map) as Zone_Growing; + bool flag = false; + for (int i = 0; i < thingList.Count; i++) + { + Thing thing = thingList[i]; + if (thing.def == wantedPlantDef) + { + return null; + } + if ((thing is Blueprint || thing is Frame) && thing.Faction == pawn.Faction) + { + flag = true; + } + } + if (flag) + { + Thing edifice = c.GetEdifice(map); + if (edifice == null || edifice.def.fertility < 0f) + { + return null; + } + } + if (wantedPlantDefLocal.plant.diesToLight) + { + if (!c.Roofed(map) && !map.GameConditionManager.IsAlwaysDarkOutside) + { + JobFailReason.Is(CantSowCavePlantBecauseUnroofedTrans); + return null; + } + if (map.glowGrid.GroundGlowAt(c, ignoreCavePlants: true) > 0f) + { + JobFailReason.Is(CantSowCavePlantBecauseOfLightTrans); + return null; + } + } + if (wantedPlantDefLocal.plant.interferesWithRoof && c.Roofed(pawn.Map)) + { + return null; + } + Plant plant = c.GetPlant(map); + if (plant != null && plant.def.plant.blockAdjacentSow) + { + if (!pawn.CanReserve(plant, 1, -1, null, forced) || plant.IsForbidden(pawn)) + { + return null; + } + if (zone_Growing != null && !zone_Growing.allowCut) + { + return null; + } + if (!forced && plant.TryGetComp(out var comp) && comp.PreventCutting) + { + return null; + } + if (!PlantUtility.PawnWillingToCutPlant_Job(plant, pawn)) + { + return null; + } + return JobMaker.MakeJob(JobDefOf.CutPlant, plant); + } + Thing thing2 = PlantUtility.AdjacentSowBlocker(wantedPlantDefLocal, c, map); + if (thing2 != null) + { + if (thing2 is Plant plant2 && pawn.CanReserveAndReach(plant2, PathEndMode.Touch, Danger.Deadly, 1, -1, null, forced) && !plant2.IsForbidden(pawn)) + { + IPlantToGrowSettable plantToGrowSettable = plant2.Position.GetPlantToGrowSettable(plant2.Map); + if (plantToGrowSettable == null || plantToGrowSettable.GetPlantDefToGrow() != plant2.def) + { + Zone_Growing zone_Growing2 = c.GetZone(map) as Zone_Growing; + Zone_Growing zone_Growing3 = plant2.Position.GetZone(map) as Zone_Growing; + if ((zone_Growing2 != null && !zone_Growing2.allowCut) || (zone_Growing3 != null && !zone_Growing3.allowCut && plant2.def == zone_Growing3.GetPlantDefToGrow())) + { + return null; + } + } + if (!forced && thing2.TryGetComp(out CompPlantPreventCutting comp2) && comp2.PreventCutting) + { + return null; + } + if (PlantUtility.TreeMarkedForExtraction(plant2)) + { + return null; + } + if (!PlantUtility.PawnWillingToCutPlant_Job(plant2, pawn)) + { + return null; + } + return JobMaker.MakeJob(JobDefOf.CutPlant, plant2); + } + if (thing2.def.EverHaulable) + { + return HaulAIUtility.HaulAsideJobFor(pawn, thing2); + } + return null; + } + if (wantedPlantDefLocal.plant.sowMinSkill > 0 && ((pawn.skills != null && pawn.skills.GetSkill(SkillDefOf.Plants).Level < wantedPlantDefLocal.plant.sowMinSkill) || (pawn.IsColonyMech && pawn.RaceProps.mechFixedSkillLevel < wantedPlantDefLocal.plant.sowMinSkill))) + { + JobFailReason.Is("UnderAllowedSkill".Translate(wantedPlantDefLocal.plant.sowMinSkill), def.label); + return null; + } + for (int j = 0; j < thingList.Count; j++) + { + Thing thing3 = thingList[j]; + if (!thing3.def.BlocksPlanting()) + { + continue; + } + if (!pawn.CanReserve(thing3, 1, -1, null, forced)) + { + return null; + } + if (thing3.def.category == ThingCategory.Plant) + { + if (thing3.IsForbidden(pawn)) + { + return null; + } + if (zone_Growing != null && !zone_Growing.allowCut) + { + return null; + } + if (!forced && plant.TryGetComp(out var comp3) && comp3.PreventCutting) + { + return null; + } + if (!PlantUtility.PawnWillingToCutPlant_Job(thing3, pawn)) + { + return null; + } + if (PlantUtility.TreeMarkedForExtraction(thing3)) + { + return null; + } + return JobMaker.MakeJob(JobDefOf.CutPlant, thing3); + } + if (thing3.def.EverHaulable) + { + return HaulAIUtility.HaulAsideJobFor(pawn, thing3); + } + return null; + } + if (!wantedPlantDefLocal.CanNowPlantAt(c, map) || !PlantUtility.GrowthSeasonNow(c, map, wantedPlantDefLocal) || !pawn.CanReserve(c, 1, -1, null, forced)) + { + return null; + } + Job job = JobMaker.MakeJob(JobDefOf.Sow, c); + job.plantDefToSow = wantedPlantDefLocal; + return job; + } + } +} \ No newline at end of file