diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
new file mode 100644
index 0000000..9449026
Binary files /dev/null and b/1.6/1.6/Assemblies/ArachnaeSwarm.dll differ
diff --git a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
index f8e3c6a..fbb66f2 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
@@ -79,7 +79,6 @@
Dig
ARA_Sowing
- ARA_PlantCutting
@@ -103,25 +102,20 @@
DeathActionWorker_Vanish
-
- Hauling
- Mining
- Construction
- Crafting
- Smithing
- Tailoring
- Cooking
- Research
- PlantCutting
- Growing
- Cleaning
- Doctor
- Firefighter
-
- 10
-
+
+
+
+ Plants
+ 10
+
+
+
+ ARA_Sowing
+
+ true
+
AnimalInsect
diff --git a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
index fd0e1ae..a5101a2 100644
--- a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
+++ b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
@@ -324,44 +324,19 @@
-
-
- ARA_Sowing
-
-
+
+
+ ARA_Sowing
-
-
+
+
+
+
+
+
+
-
-
-
-
-
- ARA_Sowing
-
-
-
-
-
-
-
-
-
-
-
-
- ARA_PlantCutting
-
-
-
-
-
-
-
-
-
diff --git a/1.6/1.6/Defs/TrainableDefs/ARA_PlantCutting.xml b/1.6/1.6/Defs/TrainableDefs/ARA_PlantCutting.xml
deleted file mode 100644
index 9dcdf64..0000000
--- a/1.6/1.6/Defs/TrainableDefs/ARA_PlantCutting.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-
-
-
-
- ARA_PlantCutting
-
- 允许该生物执行植物割除任务。
-
- true
-
- 3
- Advanced
-
- 1
-
- 99
-
-
-
\ No newline at end of file
diff --git a/1.6/1.6/Defs/TrainableDefs/ARA_Sowing.xml b/1.6/1.6/Defs/TrainableDefs/ARA_Sowing.xml
index 9c3fcde..ca09fab 100644
--- a/1.6/1.6/Defs/TrainableDefs/ARA_Sowing.xml
+++ b/1.6/1.6/Defs/TrainableDefs/ARA_Sowing.xml
@@ -3,8 +3,8 @@
ARA_Sowing
-
- 允许该生物执行播种任务。
+
+ 允许该生物执行种植任务。
true
@@ -14,7 +14,7 @@
Advanced
- 1
+ 3
100
diff --git a/Source/ArachnaeSwarm/AnimalWorkSystemPatcher.cs b/Source/ArachnaeSwarm/AnimalWorkSystemPatcher.cs
deleted file mode 100644
index 6efbef3..0000000
--- a/Source/ArachnaeSwarm/AnimalWorkSystemPatcher.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using System.Collections.Generic;
-using System.Reflection;
-using HarmonyLib;
-using RimWorld;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public static class AnimalWorkSystemPatcher
- {
- static AnimalWorkSystemPatcher()
- {
- var harmony = new Harmony("com.yourname.animalworksystem");
- harmony.PatchAll();
- }
- }
-
- [HarmonyPatch(typeof(Pawn_WorkSettings), "EnableAndInitialize")]
- public static class Patch_Pawn_WorkSettings_EnableAndInitialize
- {
- public static void Postfix(Pawn_WorkSettings __instance, Pawn ___pawn)
- {
- // 检查是否是我们想要启用工作系统的动物,并且它不是机械体
- // 因为原版的 EnableAndInitialize 已经处理了机械体的工作设置
- if (___pawn.Faction != null && ___pawn.Faction.IsPlayer &&
- !___pawn.RaceProps.IsMechanoid &&
- ShouldEnableWorkSystem(___pawn))
- {
- // 获取 CompProperties_WorkForNonMechs
- CompProperties_WorkForNonMechs compProps = null;
- if (___pawn.def.comps != null)
- {
- foreach (var comp in ___pawn.def.comps)
- {
- if (comp is CompProperties_WorkForNonMechs props)
- {
- compProps = props;
- break;
- }
- }
- }
-
- if (compProps != null && compProps.workTypes != null)
- {
- // 设置 CompProperties_WorkForNonMechs 中定义的工作类型优先级
- foreach (var workType in compProps.workTypes)
- {
- if (!__instance.WorkIsActive(workType) && !___pawn.WorkTypeIsDisabled(workType))
- {
- __instance.SetPriority(workType, 3); // 默认优先级
- }
- }
- }
- }
- }
-
- private static bool ShouldEnableWorkSystem(Pawn pawn)
- {
- // 检查 ThingDef 中是否有 CompProperties_WorkForNonMechs 配置
- if (pawn.def.comps != null)
- {
- foreach (var compProperties in pawn.def.comps)
- {
- if (compProperties is CompProperties_WorkForNonMechs)
- {
- return true;
- }
- }
- }
-
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 40d3856..fa0e51d 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -86,26 +86,19 @@
-
-
-
-
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
diff --git a/Source/ArachnaeSwarm/CompAdvancedTraining.cs b/Source/ArachnaeSwarm/CompAdvancedTraining.cs
new file mode 100644
index 0000000..9a0b8c9
--- /dev/null
+++ b/Source/ArachnaeSwarm/CompAdvancedTraining.cs
@@ -0,0 +1,77 @@
+using System.Collections.Generic;
+using Verse;
+using RimWorld;
+
+namespace ArachnaeSwarm
+{
+ public class CompProperties_AdvancedTraining : CompProperties
+ {
+ // 1. 用于设置固定技能等级
+ public List skillLevels = new List();
+
+ // 2. 用于指定生成时立即完成的训练
+ public List instantTrainables = new List();
+
+ // 3. 全局开关:是否阻止所有技能衰减
+ public bool disableAllSkillDecay = false;
+
+ public CompProperties_AdvancedTraining()
+ {
+ this.compClass = typeof(CompAdvancedTraining);
+ }
+ }
+
+ public class SkillLevelEntry
+ {
+ public SkillDef skill;
+ public int level = 0;
+ // 这里的 disableDecay 字段现在是冗余的,因为我们有全局的 disableAllSkillDecay
+ // 但为了兼容性或未来可能的需求,可以保留。
+ // 在当前方案中,它的值将被忽略。
+ public bool disableDecay = true;
+ }
+
+ public class CompAdvancedTraining : ThingComp
+ {
+ public CompProperties_AdvancedTraining Props => (CompProperties_AdvancedTraining)this.props;
+
+ public override void PostSpawnSetup(bool respawningAfterLoad)
+ {
+ base.PostSpawnSetup(respawningAfterLoad);
+
+ Pawn pawn = this.parent as Pawn;
+ if (pawn == null) return;
+
+ // --- 1. 设置固定技能等级 ---
+ if (pawn.skills != null && !Props.skillLevels.NullOrEmpty())
+ {
+ foreach (var entry in Props.skillLevels)
+ {
+ if (entry.skill != null)
+ {
+ var skillRecord = pawn.skills.GetSkill(entry.skill);
+ if (skillRecord != null)
+ {
+ skillRecord.Level = entry.level;
+ // 注意: 激情 (passion) 影响学习速度,不直接阻止衰减。
+ // 实际的衰减阻止逻辑在 TrainingSystem_Patcher.cs 中处理。
+ // 默认情况下,我们不改变 passion,除非有特殊需求。
+ }
+ }
+ }
+ }
+
+ // --- 2. 执行瞬间训练 (只在初次生成时) ---
+ if (!respawningAfterLoad && pawn.training != null && !Props.instantTrainables.NullOrEmpty())
+ {
+ foreach (var trainable in Props.instantTrainables)
+ {
+ if (trainable != null && !pawn.training.HasLearned(trainable))
+ {
+ pawn.training.Train(trainable, null, complete: true);
+ }
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs b/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs
deleted file mode 100644
index 6c462cc..0000000
--- a/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System.Collections.Generic;
-using Verse;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class CompProperties_AnimalWorkSettings : CompProperties
- {
- // 使用列表存储键值对,因为RimWorld的XML解析器对字典有特殊要求
- public List workTypeMap = new List();
- // 定义动物的技能等级
- public List skillLevels = new List();
-
- public CompProperties_AnimalWorkSettings()
- {
- this.compClass = typeof(CompAnimalWorkSettings);
- }
- }
-
- // 定义键值对的结构
- public class WorkTypeMapEntry
- {
- public TrainableDef trainable;
- public WorkTypeDef workType;
- }
-
- // 定义技能和等级的结构
- public class SkillLevelEntry
- {
- public SkillDef skill;
- public int level = 0; // 默认等级为0
- // 可选:是否阻止技能衰减
- public bool disableDecay = true;
- }
-
- public class CompAnimalWorkSettings : ThingComp
- {
- public CompProperties_AnimalWorkSettings Props => (CompProperties_AnimalWorkSettings)this.props;
-
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
-
- Pawn pawn = this.parent as Pawn;
- if (pawn == null) return;
-
- // 1. 确保 workSettings 存在
- if (pawn.workSettings == null)
- {
- pawn.workSettings = new Pawn_WorkSettings(pawn);
- pawn.workSettings.EnableAndInitializeIfNotAlreadyInitialized();
- }
-
- // 2. 设置技能等级 (如果定义了)
- if (pawn.skills != null && Props.skillLevels != null)
- {
- foreach (var entry in Props.skillLevels)
- {
- if (entry.skill != null)
- {
- var skillRecord = pawn.skills.GetSkill(entry.skill);
- if (skillRecord != null)
- {
- // 设置技能等级
- skillRecord.Level = entry.level;
-
- // 可选:阻止技能衰减
- // 在新版本中,将激情设置为 None 可以阻止自然增长和衰减
- if (entry.disableDecay)
- {
- skillRecord.passion = Passion.None;
- // 注意:仅设置 passion=None 可能不足以完全阻止衰减
- // 如果仍有问题,可能需要在 ThinkNode 或其他地方定期重置技能等级
- }
- }
- }
- }
- }
-
- // 3. 设置工作优先级 (如果定义了映射关系)
- // 这里我们不检查 pawn.training.HasLearned,因为这个组件只负责提供"能力"
- // 具体是否执行工作由 ThinkNode_Conditional 控制
- if (pawn.workSettings != null && Props.workTypeMap != null)
- {
- foreach (var entry in Props.workTypeMap)
- {
- if (entry.trainable != null && entry.workType != null)
- {
- // 为相关工作类型设置默认优先级
- // 实际是否执行由 ThinkNode_Conditional 的 GetWanted 控制
- pawn.workSettings.SetPriority(entry.workType, 3);
- }
- }
- }
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/CompInstantTrain.cs b/Source/ArachnaeSwarm/CompInstantTrain.cs
deleted file mode 100644
index cfb504d..0000000
--- a/Source/ArachnaeSwarm/CompInstantTrain.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.Collections.Generic;
-using Verse;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class CompInstantTrain : ThingComp
- {
- public CompProperties_InstantTrain Props => (CompProperties_InstantTrain)this.props;
-
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
-
- // 只在初次生成时执行,加载存档时不需要重新训练
- if (respawningAfterLoad) return;
-
- Pawn pawn = this.parent as Pawn;
- if (pawn?.training == null) return;
-
- // 瞬间训练所有在 Props 中指定的技能
- foreach (var trainable in Props.trainables)
- {
- if (trainable != null && !pawn.training.HasLearned(trainable))
- {
- // 注意:直接调用 Train 方法,它会内部处理 SetWanted 的逻辑
- // 原版的 SetWanted 方法可能已被移除或变为内部方法
- pawn.training.Train(trainable, null, true); // true表示瞬间完成
- }
- }
-
- // CompInstantTrain 的职责到此结束
- // 工作优先级设置由 CompAnimalWorkSettings 负责
- }
- }
-
- public class CompProperties_InstantTrain : CompProperties
- {
- public List trainables = new List();
-
- public CompProperties_InstantTrain()
- {
- this.compClass = typeof(CompInstantTrain);
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/CompNoTrainingDecay.cs b/Source/ArachnaeSwarm/CompNoTrainingDecay.cs
deleted file mode 100644
index f612d2a..0000000
--- a/Source/ArachnaeSwarm/CompNoTrainingDecay.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using Verse;
-
-namespace ArachnaeSwarm
-{
- // 这是一个“标记”组件。它的唯一目的就是在 XML 中被添加到 ThingDef,
- // 以便我们的 Harmony 补丁可以识别哪些 Pawn 的训练不应该衰减。
- // 它本身不需要任何逻辑。
- public class CompProperties_NoTrainingDecay : CompProperties
- {
- public CompProperties_NoTrainingDecay()
- {
- this.compClass = typeof(ThingComp); // 我们可以使用一个通用的、空的 ThingComp
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/CompWorkForNonMechs.cs b/Source/ArachnaeSwarm/CompWorkForNonMechs.cs
deleted file mode 100644
index 3f5b471..0000000
--- a/Source/ArachnaeSwarm/CompWorkForNonMechs.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using System.Collections.Generic;
-using RimWorld;
-using Verse;
-
-namespace ArachnaeSwarm
-{
- public class CompProperties_WorkForNonMechs : CompProperties
- {
- public List workTypes;
-
- public CompProperties_WorkForNonMechs()
- {
- compClass = typeof(CompWorkForNonMechs);
- }
- }
-
- public class CompWorkForNonMechs : ThingComp
- {
- public CompProperties_WorkForNonMechs Props => (CompProperties_WorkForNonMechs)props;
-
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
-
- var pawn = parent as Pawn;
- if (pawn == null || pawn.Faction == null || !pawn.Faction.IsPlayer) return;
-
- // 确保 workSettings 实例存在
- if (pawn.workSettings == null)
- {
- pawn.workSettings = new Pawn_WorkSettings(pawn);
- }
-
- pawn.workSettings.EnableAndInitialize();
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/JobGiver_Grower.cs b/Source/ArachnaeSwarm/JobGiver_Grower.cs
new file mode 100644
index 0000000..2c10f81
--- /dev/null
+++ b/Source/ArachnaeSwarm/JobGiver_Grower.cs
@@ -0,0 +1,99 @@
+using System.Collections.Generic;
+using Verse;
+using Verse.AI;
+using RimWorld;
+
+namespace ArachnaeSwarm
+{
+ // 确保 WorkGiverDefOf 被正确初始化
+ [DefOf]
+ public static class WorkGiverDefOf
+ {
+ public static WorkGiverDef Harvest;
+ public static WorkGiverDef GrowerSow;
+
+ static WorkGiverDefOf()
+ {
+ DefOfHelper.EnsureInitializedInCtor(typeof(WorkGiverDefOf));
+ }
+ }
+
+ public class JobGiver_Grower : ThinkNode_JobGiver
+ {
+ private static WorkGiver_GrowerHarvest _workGiverHarvest;
+ private static WorkGiver_GrowerSow _workGiverSow;
+
+ static JobGiver_Grower()
+ {
+ // 确保在访问 WorkGiverDefOf 之前,它已经被初始化
+ // 尽管 [DefOf] 会自动处理,但显式调用可以避免某些加载时序问题
+ DefOfHelper.EnsureInitializedInCtor(typeof(WorkGiverDefOf));
+ _workGiverHarvest = WorkGiverDefOf.Harvest.Worker as WorkGiver_GrowerHarvest;
+ _workGiverSow = WorkGiverDefOf.GrowerSow.Worker as WorkGiver_GrowerSow;
+ }
+
+ protected override Job TryGiveJob(Pawn pawn)
+ {
+ if (_workGiverHarvest == null || _workGiverSow == null)
+ {
+ Log.ErrorOnce("JobGiver_Grower could not find vanilla Grower WorkGivers.", 123457);
+ return null;
+ }
+
+ // 1. 优先收获
+ Thing bestHarvestable = FindClosestThing(pawn, _workGiverHarvest);
+ if (bestHarvestable != null)
+ {
+ return _workGiverHarvest.JobOnThing(pawn, bestHarvestable);
+ }
+
+ // 2. 其次播种
+ IntVec3 bestSowCell = FindClosestSowableCell(pawn, _workGiverSow);
+ if (bestSowCell.IsValid)
+ {
+ return _workGiverSow.JobOnCell(pawn, bestSowCell);
+ }
+
+ return null;
+ }
+
+ private Thing FindClosestThing(Pawn pawn, WorkGiver_Scanner scanner)
+ {
+ return GenClosest.ClosestThingReachable(
+ pawn.Position,
+ pawn.Map,
+ scanner.PotentialWorkThingRequest,
+ PathEndMode.Touch,
+ TraverseParms.For(pawn),
+ 9999f,
+ t => scanner.HasJobOnThing(pawn, t)
+ );
+ }
+
+ private IntVec3 FindClosestSowableCell(Pawn pawn, WorkGiver_Scanner scanner)
+ {
+ IntVec3 bestCell = IntVec3.Invalid;
+ float bestDistSq = float.MaxValue;
+
+ foreach (Zone zone in pawn.Map.zoneManager.AllZones)
+ {
+ if (zone is Zone_Growing growingZone)
+ {
+ 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))
+ {
+ bestDistSq = distSq;
+ bestCell = cell;
+ }
+ }
+ }
+ }
+ }
+ return bestCell;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs b/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs
deleted file mode 100644
index 4ea44c1..0000000
--- a/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs
+++ /dev/null
@@ -1,56 +0,0 @@
-using System.Collections.Generic;
-using Verse;
-using Verse.AI;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class JobGiver_PlantCutting : ThinkNode_JobGiver
- {
- private WorkGiverDef cutWorkGiverDef = null;
- private bool triedToLoad = false;
-
- protected override Job TryGiveJob(Pawn pawn)
- {
- if (!triedToLoad || cutWorkGiverDef == null)
- {
- triedToLoad = true;
- cutWorkGiverDef = DefDatabase.GetNamed("PlantsCut", false);
- if (cutWorkGiverDef == null)
- {
- Log.ErrorOnce("[ArachnaeSwarm] Could not find WorkGiverDef named 'PlantsCut'. Plant Cutting will not work.", 847595);
- return null;
- }
- }
-
- if (cutWorkGiverDef?.Worker is WorkGiver_Scanner workGiver)
- {
- // ... (你的逻辑,调用 workGiver 的方法) ...
- IEnumerable potentialPlants = workGiver.PotentialWorkThingsGlobal(pawn);
- // ... (后续逻辑,确保都用 workGiver 实例) ...
- if (!workGiver.ShouldSkip(pawn) && workGiver.MissingRequiredCapacity(pawn) == null)
- {
- return workGiver.NonScanJob(pawn);
- }
- // ...
- }
- else
- {
- Log.Warning($"[ArachnaeSwarm] WorkGiverDef 'PlantsCut' Worker is not a WorkGiver_Scanner for pawn {pawn?.LabelShort ?? "NULL"}.");
- }
-
- return null;
- }
-
- // ... (Validator 方法也需要修改) ...
- private static bool Validator(Pawn pawn, WorkGiver_Scanner workGiver, Thing t)
- {
- if (t.IsForbidden(pawn))
- {
- return false;
- }
- // if (workGiver.ShouldSkip(pawn)) { return false; } // 这个检查可以保留或去掉
- return workGiver.JobOnThing(pawn, t) != null; // 使用传入的实例
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/JobGiver_PlantHarvest.cs b/Source/ArachnaeSwarm/JobGiver_PlantHarvest.cs
deleted file mode 100644
index 13563fe..0000000
--- a/Source/ArachnaeSwarm/JobGiver_PlantHarvest.cs
+++ /dev/null
@@ -1,63 +0,0 @@
-using System.Collections.Generic;
-using Verse;
-using Verse.AI;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class JobGiver_PlantHarvest : ThinkNode_JobGiver
- {
- // 声明变量,但不立即初始化
- private WorkGiverDef harvestWorkGiverDef = null;
- // 用一个标志位确保只尝试加载一次
- private bool triedToLoad = false;
-
- protected override Job TryGiveJob(Pawn pawn)
- {
- // 如果还没尝试加载,或者之前加载失败了
- if (!triedToLoad || harvestWorkGiverDef == null)
- {
- triedToLoad = true; // 标记为已尝试
- // 在需要时才查找 Def
- harvestWorkGiverDef = DefDatabase.GetNamed("GrowerHarvest", false);
- if (harvestWorkGiverDef == null)
- {
- // 这个 Log 可以保留,方便调试
- Log.ErrorOnce("[ArachnaeSwarm] Could not find WorkGiverDef named 'GrowerHarvest'. Harvesting will not work.", 847593);
- return null; // 找不到就直接返回
- }
- }
-
- // 现在可以安全地使用 harvestWorkGiverDef 了
- if (harvestWorkGiverDef?.Worker is WorkGiver_Scanner workGiver)
- {
- // ... (你原来的逻辑) ...
- IEnumerable potentialPlants = workGiver.PotentialWorkThingsGlobal(pawn);
- // ... (后续逻辑) ...
- // 确保调用的是 workGiver (已解析的实例)
- if (!workGiver.ShouldSkip(pawn) && workGiver.MissingRequiredCapacity(pawn) == null)
- {
- return workGiver.NonScanJob(pawn);
- }
- // ... 其他逻辑 ...
- }
- else
- {
- Log.Warning($"[ArachnaeSwarm] WorkGiverDef 'GrowerHarvest' Worker is not a WorkGiver_Scanner for pawn {pawn?.LabelShort ?? "NULL"}.");
- }
-
- return null;
- }
-
- // ... (Validator 方法也需要确保使用传入的 workGiver 实例) ...
- private static bool HarvestValidator(Pawn pawn, WorkGiver_Scanner workGiver, Thing t)
- {
- if (t.IsForbidden(pawn))
- {
- return false;
- }
- // 使用传入的已解析实例
- return workGiver.JobOnThing(pawn, t) != null;
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/JobGiver_PlantSow.cs b/Source/ArachnaeSwarm/JobGiver_PlantSow.cs
deleted file mode 100644
index 5994d2b..0000000
--- a/Source/ArachnaeSwarm/JobGiver_PlantSow.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using Verse;
-using Verse.AI;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class JobGiver_PlantSow : ThinkNode_JobGiver
- {
- private WorkGiverDef sowWorkGiverDef = null;
- private bool triedToLoad = false;
-
- protected override Job TryGiveJob(Pawn pawn)
- {
- if (!triedToLoad || sowWorkGiverDef == null)
- {
- triedToLoad = true;
- sowWorkGiverDef = DefDatabase.GetNamed("GrowerSow", false);
- if (sowWorkGiverDef == null)
- {
- Log.ErrorOnce("[ArachnaeSwarm] Could not find WorkGiverDef named 'GrowerSow'. Sowing will not work.", 847594);
- return null;
- }
- }
-
- if (sowWorkGiverDef?.Worker is WorkGiver_Scanner sowerScanner) // 直接用 Scanner 接口
- {
- // ... (你的逻辑,调用 sowerScanner 的方法) ...
- if (!sowerScanner.ShouldSkip(pawn) && sowerScanner.MissingRequiredCapacity(pawn) == null)
- {
- return sowerScanner.NonScanJob(pawn); // 使用 Scanner 接口
- }
- }
- else
- {
- Log.Warning($"[ArachnaeSwarm] WorkGiverDef 'GrowerSow' Worker is not a WorkGiver_Scanner for pawn {pawn?.LabelShort ?? "NULL"}.");
- }
-
- return null;
- }
- }
-}
diff --git a/Source/ArachnaeSwarm/Patch_QualityUtility.cs b/Source/ArachnaeSwarm/Patch_QualityUtility.cs
deleted file mode 100644
index dfa742e..0000000
--- a/Source/ArachnaeSwarm/Patch_QualityUtility.cs
+++ /dev/null
@@ -1,62 +0,0 @@
-using HarmonyLib;
-using RimWorld;
-using Verse;
-using System.Reflection; // For MethodInfo
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public static class QualityUtilityPatch
- {
- static QualityUtilityPatch()
- {
- var harmony = new Harmony("com.yourname.qualityutilitypatch");
- harmony.Patch(
- original: AccessTools.Method(typeof(QualityUtility), nameof(QualityUtility.GenerateQualityCreatedByPawn), new[] { typeof(Pawn), typeof(SkillDef), typeof(bool) }),
- prefix: new HarmonyMethod(typeof(QualityUtilityPatch), nameof(GenerateQualityCreatedByPawn_Prefix))
- );
- }
-
- public static bool GenerateQualityCreatedByPawn_Prefix(Pawn pawn, SkillDef relevantSkill, bool consumeInspiration, ref QualityCategory __result)
- {
- // 检查当前 Pawn 是否是我们的自定义动物(通过检查其 ThingDef 是否拥有 CompProperties_WorkForNonMechs)
- if (pawn != null && pawn.def.comps != null && ShouldEnableWorkSystem(pawn))
- {
- // 如果是,强制使用 mechFixedSkillLevel
- int relevantSkillLevel = pawn.RaceProps.mechFixedSkillLevel;
- bool inspired = consumeInspiration && pawn.InspirationDef == InspirationDefOf.Inspired_Creativity;
-
- // 调用 QualityUtility.GenerateQualityCreatedByPawn 的 int 重载
- __result = QualityUtility.GenerateQualityCreatedByPawn(relevantSkillLevel, inspired);
-
- // 消耗灵感(如果适用)
- if (inspired)
- {
- pawn.mindState.inspirationHandler.EndInspiration(InspirationDefOf.Inspired_Creativity);
- }
-
- // 返回 false,跳过原版方法执行
- return false;
- }
-
- // 返回 true,执行原版方法
- return true;
- }
-
- private static bool ShouldEnableWorkSystem(Pawn pawn)
- {
- // 检查 ThingDef 中是否有 CompProperties_WorkForNonMechs 配置
- if (pawn.def.comps != null)
- {
- foreach (var compProperties in pawn.def.comps)
- {
- if (compProperties is CompProperties_WorkForNonMechs)
- {
- return true;
- }
- }
- }
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Patch_TrainingTracker_TickRare.cs b/Source/ArachnaeSwarm/Patch_TrainingTracker_TickRare.cs
deleted file mode 100644
index e4fa9ac..0000000
--- a/Source/ArachnaeSwarm/Patch_TrainingTracker_TickRare.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Verse;
-using HarmonyLib;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- [HarmonyPatch(typeof(Pawn_TrainingTracker), "TrainingTrackerTickRare")]
- public static class Patch_TrainingTracker_TickRare
- {
- // [HarmonyPrefix] 表示这是一个“前缀”补丁,在原方法执行前运行
- // 它返回一个 bool 值:
- // - return true: 继续执行原方法 (TrainingTrackerTickRare)
- // - return false: 阻止执行原方法,直接跳过
- [HarmonyPrefix]
- public static bool PreventDecayForSpecialAnimals(Pawn_TrainingTracker __instance)
- {
- // __instance 是原方法的实例对象,我们可以通过它访问 pawn
- Pawn pawn = __instance.pawn;
-
- // 检查 Pawn 的 ThingDef 是否有我们的“标记”组件
- if (pawn.def.HasComp(typeof(CompProperties_NoTrainingDecay)))
- {
- // 如果有,则这是一个不应衰减训练度的特殊动物,返回 false 阻止原方法执行
- return false;
- }
-
- // 如果没有,则这是一个普通动物,返回 true 让原版的衰减逻辑正常执行
- return true;
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/Patch_WorkGivers_Growing.cs b/Source/ArachnaeSwarm/Patch_WorkGivers_Growing.cs
deleted file mode 100644
index 4a416ee..0000000
--- a/Source/ArachnaeSwarm/Patch_WorkGivers_Growing.cs
+++ /dev/null
@@ -1,96 +0,0 @@
-using HarmonyLib;
-using RimWorld;
-using Verse;
-using Verse.AI;
-using System.Reflection;
-
-namespace ArachnaeSwarm
-{
- [StaticConstructorOnStartup]
- public static class Patch_WorkGivers_Growing
- {
- static Patch_WorkGivers_Growing()
- {
- var harmony = new Harmony("com.yourname.workgiversgrowingpatch");
-
- // Patch WorkGiver_GrowerSow.JobOnCell
- harmony.Patch(
- original: AccessTools.Method(typeof(WorkGiver_GrowerSow), nameof(WorkGiver_GrowerSow.JobOnCell)),
- prefix: new HarmonyMethod(typeof(Patch_WorkGivers_Growing), nameof(JobOnCell_GrowerSow_Prefix))
- );
-
- // Patch JobDriver_Deconstruct.TickActionInterval
- harmony.Patch(
- original: AccessTools.Method(typeof(JobDriver_Deconstruct), "TickActionInterval"),
- prefix: new HarmonyMethod(typeof(Patch_WorkGivers_Growing), nameof(TickActionInterval_Deconstruct_Prefix))
- );
- }
-
- public static bool JobOnCell_GrowerSow_Prefix(Pawn pawn, IntVec3 c, ref Job __result, WorkGiver_GrowerSow __instance)
- {
- // 检查是否是我们的自定义动物,并且它不是真正的机械体 (因为真正的机械体原版会处理)
- if (ShouldEnableWorkSystem(pawn) && !pawn.RaceProps.IsMechanoid)
- {
- // 使用反射获取 WorkGiver_GrowerSow 实例的 wantedPlantDef 字段
- ThingDef wantedPlantDef = (ThingDef)AccessTools.Field(typeof(WorkGiver_Grower), "wantedPlantDef").GetValue(__instance);
-
- if (wantedPlantDef == null)
- {
- __result = null;
- return false; // 跳过原版方法
- }
-
- // 强制使用 mechFixedSkillLevel 作为相关技能等级
- int relevantSkillLevel = pawn.RaceProps.mechFixedSkillLevel;
-
- // 然后进行原始的 sowMinSkill 检查
- if (wantedPlantDef.plant.sowMinSkill > relevantSkillLevel)
- {
- __result = null; // 技能不足,不生成 Job
- return false; // 跳过原版方法
- }
-
- // 如果技能足够,让原版方法继续执行,处理其他复杂的检查
- // 注意:这里我们只处理了技能检查部分,其他逻辑仍然依赖原版方法。
- // 如果原版方法在其他地方再次访问 pawn.skills,仍然可能出错。
- // 但这是最直接的修复方法,避免了完全复制整个原始方法。
- }
-
- return true; // 执行原版方法
- }
-
- public static bool TickActionInterval_Deconstruct_Prefix(JobDriver_Deconstruct __instance, Pawn ___pawn, int delta)
- {
- // 检查是否是我们的自定义动物,并且它不是真正的机械体
- if (ShouldEnableWorkSystem(___pawn) && !___pawn.RaceProps.IsMechanoid)
- {
- // 模拟技能学习,避免访问 pawn.skills 导致 NullReferenceException
- // 这里我们不实际增加经验值,只是模拟原版方法的行为
- // 避免了对 pawn.skills 的访问
- if (__instance.Building.def.CostListAdjusted(__instance.Building.Stuff).Count > 0)
- {
- // 可以选择在这里添加一些日志,以便调试
- // Log.Message($"Animal {___pawn.LabelShort} is deconstructing, simulating skill gain.");
- }
- return false; // 跳过原版方法
- }
- return true; // 执行原版方法
- }
-
- private static bool ShouldEnableWorkSystem(Pawn pawn)
- {
- // 检查 ThingDef 中是否有 CompProperties_WorkForNonMechs 配置
- if (pawn.def.comps != null)
- {
- foreach (var compProperties in pawn.def.comps)
- {
- if (compProperties is CompProperties_WorkForNonMechs)
- {
- return true;
- }
- }
- }
- return false;
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs b/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs
new file mode 100644
index 0000000..3170615
--- /dev/null
+++ b/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldDoGrowingWork.cs
@@ -0,0 +1,43 @@
+using Verse;
+using Verse.AI;
+using RimWorld;
+
+namespace ArachnaeSwarm
+{
+ // 将 DefOf 类放在这里,以便在命名空间内共享
+ [DefOf]
+ public static class ARA_TrainableDefOf
+ {
+ public static TrainableDef ARA_Sowing;
+ public static TrainableDef ARA_PlantCutting;
+
+ static ARA_TrainableDefOf()
+ {
+ DefOfHelper.EnsureInitializedInCtor(typeof(ARA_TrainableDefOf));
+ }
+ }
+
+ // 这个新的条件节点将检查动物是否应该执行任何农业工作(播种或切割/收获)
+ public class ThinkNode_ConditionalAnimalShouldDoGrowingWork : ThinkNode_Conditional
+ {
+ protected override bool Satisfied(Pawn pawn)
+ {
+ // 首先,进行安全检查,确保 pawn.training 存在
+ if (pawn.training == null)
+ {
+ return false;
+ }
+
+ // 检查动物是否学会并被允许执行“播种”工作
+ bool canSow = pawn.training.HasLearned(ARA_TrainableDefOf.ARA_Sowing) &&
+ pawn.training.GetWanted(ARA_TrainableDefOf.ARA_Sowing);
+
+ // 检查动物是否学会并被允许执行“植物切割”工作
+ bool canCut = pawn.training.HasLearned(ARA_TrainableDefOf.ARA_PlantCutting) &&
+ pawn.training.GetWanted(ARA_TrainableDefOf.ARA_PlantCutting);
+
+ // 只要满足其中任何一个条件,就返回 true
+ return canSow || canCut;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldPlantCut.cs b/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldPlantCut.cs
deleted file mode 100644
index 4489b91..0000000
--- a/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldPlantCut.cs
+++ /dev/null
@@ -1,21 +0,0 @@
-using Verse;
-using Verse.AI;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- public class ThinkNode_ConditionalAnimalShouldPlantCut : ThinkNode_Conditional
- {
- protected override bool Satisfied(Pawn pawn)
- {
- if (pawn.training == null)
- {
- return false;
- }
-
- // 使用我们之前创建的静态 DefOf 类来安全地引用 Def
- return pawn.training.HasLearned(ARA_TrainableDefOf.ARA_PlantCutting) &&
- pawn.training.GetWanted(ARA_TrainableDefOf.ARA_PlantCutting);
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldSow.cs b/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldSow.cs
deleted file mode 100644
index da6319c..0000000
--- a/Source/ArachnaeSwarm/ThinkNode_ConditionalAnimalShouldSow.cs
+++ /dev/null
@@ -1,37 +0,0 @@
-using Verse;
-using Verse.AI;
-using RimWorld;
-
-namespace ArachnaeSwarm
-{
- // 使用 [DefOf] 属性,让游戏在启动时自动为我们填充这些字段
- [DefOf]
- public static class ARA_TrainableDefOf
- {
- // 确保这些字段名与你在 XML 中定义的 defName 完全一致
- public static TrainableDef ARA_Sowing;
- public static TrainableDef ARA_PlantCutting;
-
- // 静态构造函数,确保 DefOf 被初始化
- static ARA_TrainableDefOf()
- {
- DefOfHelper.EnsureInitializedInCtor(typeof(ARA_TrainableDefOf));
- }
- }
-
- public class ThinkNode_ConditionalAnimalShouldSow : ThinkNode_Conditional
- {
- protected override bool Satisfied(Pawn pawn)
- {
- // MCP 已证实:对于野生动物等情况,pawn.training 可能为 null,此检查是必要的。
- if (pawn.training == null)
- {
- return false;
- }
-
- // 使用静态缓存的 Def,检查动物是否学会了该技能,并且玩家是否在“动物”标签页中勾选了允许
- return pawn.training.HasLearned(ARA_TrainableDefOf.ARA_Sowing) &&
- pawn.training.GetWanted(ARA_TrainableDefOf.ARA_Sowing);
- }
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/TrainingSystem_Patcher.cs b/Source/ArachnaeSwarm/TrainingSystem_Patcher.cs
new file mode 100644
index 0000000..6383318
--- /dev/null
+++ b/Source/ArachnaeSwarm/TrainingSystem_Patcher.cs
@@ -0,0 +1,48 @@
+using HarmonyLib;
+using RimWorld;
+using Verse;
+
+namespace ArachnaeSwarm
+{
+ // Patcher 1: 阻止训练退化
+ [HarmonyPatch(typeof(Pawn_TrainingTracker), "TrainingTrackerTickRare")]
+ public static class Patch_TrainingTracker_TickRare
+ {
+ public static bool Prefix(Pawn_TrainingTracker __instance)
+ {
+ Pawn pawn = Traverse.Create(__instance).Field("pawn").GetValue();
+ if (pawn == null) return true;
+
+ var comp = pawn.GetComp();
+ if (comp != null && comp.Props.disableAllSkillDecay)
+ {
+ return false; // 阻止原版方法运行
+ }
+ return true;
+ }
+ }
+
+ // Patcher 2: 阻止特定技能的衰减
+ [HarmonyPatch(typeof(SkillRecord), "Interval")]
+ public static class Patch_SkillRecord_Interval
+ {
+ // 使用 __instance 来获取 SkillRecord 对象, __pawn 为 SkillRecord 内部的私有字段
+ public static bool Prefix(SkillRecord __instance, Pawn ___pawn)
+ {
+ if (___pawn == null) return true;
+
+ var comp = ___pawn.GetComp();
+ if (comp == null || comp.Props.skillLevels.NullOrEmpty())
+ {
+ return true; // 没有组件或配置,正常执行原版衰减
+ }
+
+ // 检查全局开关:如果设置了 disableAllSkillDecay 为 true,则阻止衰减
+ if (comp.Props.disableAllSkillDecay)
+ {
+ return false; // 阻止原版 Interval 方法的执行
+ }
+ return true; // 正常执行原版衰减
+ }
+ }
+}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs b/Source/ArachnaeSwarm/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs
deleted file mode 100644
index 15efebf..0000000
--- a/Source/ArachnaeSwarm/obj/Debug/.NETFramework,Version=v4.8.AssemblyAttributes.cs
+++ /dev/null
@@ -1,4 +0,0 @@
-//
-using System;
-using System.Reflection;
-[assembly: global::System.Runtime.Versioning.TargetFrameworkAttribute(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
diff --git a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.AssemblyReference.cache b/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.AssemblyReference.cache
deleted file mode 100644
index 33b62db..0000000
Binary files a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.AssemblyReference.cache and /dev/null differ
diff --git a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.CoreCompileInputs.cache b/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.CoreCompileInputs.cache
deleted file mode 100644
index a6b0f7a..0000000
--- a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.CoreCompileInputs.cache
+++ /dev/null
@@ -1 +0,0 @@
-70a1ccfa141c7c82eb05a9fac71c32df86f6b34332995c92bb7aac69bc46394b
diff --git a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.FileListAbsolute.txt b/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.FileListAbsolute.txt
deleted file mode 100644
index c17b74f..0000000
--- a/Source/ArachnaeSwarm/obj/Debug/ArachnaeSwarm.csproj.FileListAbsolute.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-C:\Steam\steamapps\common\RimWorld\Mods\ArachnaeSwarm\Source\ArachnaeSwarm\obj\Debug\ArachnaeSwarm.csproj.AssemblyReference.cache
-C:\Steam\steamapps\common\RimWorld\Mods\ArachnaeSwarm\Source\ArachnaeSwarm\obj\Debug\ArachnaeSwarm.csproj.CoreCompileInputs.cache