This commit is contained in:
2025-09-02 16:36:03 +08:00
parent 6129bb1b50
commit 9acd5aac1e
12 changed files with 704 additions and 397 deletions

View File

@@ -89,6 +89,14 @@
<Compile Include="CompProperties_DelayedTerrainSpawn.cs" />
<Compile Include="CompDelayedTerrainSpawn.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="CompInstantTrain.cs" />
<Compile Include="MainHarmony.cs" />
<Compile Include="Patch_TrainingTracker_TickRare.cs" />
<Compile Include="CompNoTrainingDecay.cs" />
<Compile Include="ThinkNode_ConditionalAnimalShouldSow.cs" />
<Compile Include="ThinkNode_ConditionalAnimalShouldPlantCut.cs" />
</ItemGroup>
<ItemGroup>
<Compile Include="WULA_AutoMechCarrier\CompAutoMechCarrier.cs" />
<Compile Include="WULA_AutoMechCarrier\CompProperties_AutoMechCarrier.cs" />

View File

@@ -0,0 +1,51 @@
using System.Collections.Generic;
using Verse;
using RimWorld;
namespace ArachnaeSwarm
{
// 定义在 XML 中使用的属性
public class CompProperties_InstantTrain : CompProperties
{
public List<TrainableDef> trainables = new List<TrainableDef>();
public CompProperties_InstantTrain()
{
this.compClass = typeof(CompInstantTrain);
}
}
// 实现组件的逻辑
public class CompInstantTrain : ThingComp
{
// 方便地访问属性
public CompProperties_InstantTrain Props => (CompProperties_InstantTrain)this.props;
// 在 Pawn 生成到地图上后被调用
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
// 如果不是在加载存档时重生,则执行训练逻辑
if (!respawningAfterLoad)
{
Pawn pawn = this.parent as Pawn;
if (pawn == null || pawn.training == null)
{
return;
}
// 遍历在 XML 中定义的需要训练的技能列表
foreach (TrainableDef trainableDef in Props.trainables)
{
// 检查 Pawn 是否还未学会此技能
if (!pawn.training.HasLearned(trainableDef))
{
// 调用原版方法,瞬间完成训练
pawn.training.Train(trainableDef, null, true);
}
}
}
}
}
}

View File

@@ -0,0 +1,15 @@
using Verse;
namespace ArachnaeSwarm
{
// 这是一个“标记”组件。它的唯一目的就是在 XML 中被添加到 ThingDef
// 以便我们的 Harmony 补丁可以识别哪些 Pawn 的训练不应该衰减。
// 它本身不需要任何逻辑。
public class CompProperties_NoTrainingDecay : CompProperties
{
public CompProperties_NoTrainingDecay()
{
this.compClass = typeof(ThingComp); // 我们可以使用一个通用的、空的 ThingComp
}
}
}

View File

@@ -0,0 +1,21 @@
using Verse;
using HarmonyLib;
using System.Reflection;
namespace ArachnaeSwarm
{
// [StaticConstructorOnStartup] 属性确保这个类的静态构造函数在游戏启动时被调用
[StaticConstructorOnStartup]
public static class MainHarmony
{
static MainHarmony()
{
// 创建一个 Harmony 实例。ID 应该是唯一的,通常使用 "作者.Mod名称" 的格式。
var harmony = new Harmony("com.kalospacer.arachnaeswarm");
// Harmony 会自动扫描当前整个程序集(我们的 .dll 文件),
// 寻找所有带有 [HarmonyPatch] 属性的类,并应用它们。
harmony.PatchAll(Assembly.GetExecutingAssembly());
}
}
}

View File

@@ -0,0 +1,31 @@
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;
}
}
}

View File

@@ -0,0 +1,21 @@
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);
}
}
}

View File

@@ -0,0 +1,37 @@
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);
}
}
}