diff --git a/1.6/1.6/Assemblies/ArachnaeSwarm.dll b/1.6/1.6/Assemblies/ArachnaeSwarm.dll
index 9aac5af..5c8cda1 100644
Binary files a/1.6/1.6/Assemblies/ArachnaeSwarm.dll 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 1859908..8e78c82 100644
--- a/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
+++ b/1.6/1.6/Defs/ThingDef_Races/ARA_RaceBaseSwarm.xml
@@ -22,6 +22,15 @@
+
+
+
+ Plants
+ 10
+ true
+
+
+
ARA_Sowing
diff --git a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
index 8f310ad..fd0e1ae 100644
--- a/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
+++ b/1.6/1.6/Defs/ThinkTreeDefs/ARA_ThinkTrees.xml
@@ -107,7 +107,7 @@
- 30
+ 30
35
@@ -324,6 +324,45 @@
+
+
+ ARA_Sowing
+
+
+
+
+
+
+
+
+
+
+
+
+ ARA_Sowing
+
+
+
+
+
+
+
+
+
+
+
+
+ ARA_PlantCutting
+
+
+
+
+
+
+
+
+
+
@@ -335,31 +374,6 @@
Insect_PreWander
-
-
-
-
- TrainedAnimalBehavior
-
-
-
-
-
-
-
-
-
-
-
-
- TrainedAnimalBehavior
-
-
-
-
-
-
-
diff --git a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
index 7fc9efb..8f83075 100644
--- a/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
+++ b/Source/ArachnaeSwarm/ArachnaeSwarm.csproj
@@ -96,8 +96,10 @@
-
+
+
+
diff --git a/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs b/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs
index 758e74c..6c462cc 100644
--- a/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs
+++ b/Source/ArachnaeSwarm/CompAnimalWorkSettings.cs
@@ -4,6 +4,35 @@ 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;
@@ -15,35 +44,54 @@ namespace ArachnaeSwarm
Pawn pawn = this.parent as Pawn;
if (pawn == null) return;
- // 关键:如果 pawn 没有 workSettings,则为其创建一个
+ // 1. 确保 workSettings 存在
if (pawn.workSettings == null)
{
- // Log.Message($"Initializing Pawn_WorkSettings for animal: {pawn.LabelShort}");
pawn.workSettings = new Pawn_WorkSettings(pawn);
pawn.workSettings.EnableAndInitializeIfNotAlreadyInitialized();
-
- // 注意:Pawn_WorkSettings 的构造函数和 EnableAndInitializeIfNotAlreadyInitialized()
- // 通常会处理所有可用的 WorkTypeDef,并将它们的优先级初始化为 0。
- // 这正是我们想要的初始状态。具体的优先级将由其他逻辑(如你的 CompInstantTrain 或 ThinkNode)来设置。
}
- // 设置工作优先级
- if (pawn.workSettings != null)
+ // 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)
{
- TrainableDef trainable = entry.trainable;
- WorkTypeDef workType = entry.workType;
-
- // 检查动物是否学会了对应的 Trainable
- if (pawn.training != null && pawn.training.HasLearned(trainable))
+ if (entry.trainable != null && entry.workType != null)
{
- // 设置一个默认的非零优先级,例如 3 (Medium)
- // 真正的"开关"由 ThinkNode_Conditional 的 GetWanted 控制
- pawn.workSettings.SetPriority(workType, 3);
+ // 为相关工作类型设置默认优先级
+ // 实际是否执行由 ThinkNode_Conditional 的 GetWanted 控制
+ pawn.workSettings.SetPriority(entry.workType, 3);
}
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/Source/ArachnaeSwarm/CompInstantTrain.cs b/Source/ArachnaeSwarm/CompInstantTrain.cs
index c7c95e8..cfb504d 100644
--- a/Source/ArachnaeSwarm/CompInstantTrain.cs
+++ b/Source/ArachnaeSwarm/CompInstantTrain.cs
@@ -4,6 +4,36 @@ 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();
@@ -13,32 +43,4 @@ namespace ArachnaeSwarm
this.compClass = typeof(CompInstantTrain);
}
}
-
- public class CompInstantTrain : ThingComp
- {
- public CompProperties_InstantTrain Props => (CompProperties_InstantTrain)this.props;
-
- public override void PostSpawnSetup(bool respawningAfterLoad)
- {
- base.PostSpawnSetup(respawningAfterLoad);
-
- if (!respawningAfterLoad) // 只在初次生成时执行
- {
- Pawn pawn = this.parent as Pawn;
- if (pawn == null || pawn.training == null)
- {
- return;
- }
-
- // 瞬间训练技能
- foreach (TrainableDef trainableDef in Props.trainables)
- {
- if (!pawn.training.HasLearned(trainableDef))
- {
- pawn.training.Train(trainableDef, null, true);
- }
- }
- }
- }
- }
-}
\ No newline at end of file
+}
diff --git a/Source/ArachnaeSwarm/CompProperties_AnimalWorkSettings.cs b/Source/ArachnaeSwarm/CompProperties_AnimalWorkSettings.cs
deleted file mode 100644
index a53c0ea..0000000
--- a/Source/ArachnaeSwarm/CompProperties_AnimalWorkSettings.cs
+++ /dev/null
@@ -1,25 +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 CompProperties_AnimalWorkSettings()
- {
- this.compClass = typeof(CompAnimalWorkSettings);
- }
- }
-
- // 定义键值对的结构
- public class WorkTypeMapEntry
- {
- public TrainableDef trainable;
- public WorkTypeDef workType;
- }
-}
\ No newline at end of file
diff --git a/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs b/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs
new file mode 100644
index 0000000..4ea44c1
--- /dev/null
+++ b/Source/ArachnaeSwarm/JobGiver_PlantCutting.cs
@@ -0,0 +1,56 @@
+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
new file mode 100644
index 0000000..13563fe
--- /dev/null
+++ b/Source/ArachnaeSwarm/JobGiver_PlantHarvest.cs
@@ -0,0 +1,63 @@
+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
new file mode 100644
index 0000000..5994d2b
--- /dev/null
+++ b/Source/ArachnaeSwarm/JobGiver_PlantSow.cs
@@ -0,0 +1,41 @@
+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;
+ }
+ }
+}