# CompSpawnPawnFromList 功能设计文档 ## 1. 功能概述 `CompSpawnPawnFromList` 是一个 `ThingComp` 组件,它允许一个特定的 Pawn 通过右键菜单与一个物体交互,从一个可配置的列表中选择一个 Pawn,并在经过一段可配置的延迟后,生成这个 Pawn。在延迟期间,剩余时间会显示在建筑的检查面板上。可以选择在生成 Pawn 后是否摧毁建筑。 ## 2. XML 配置 ### 2.1. 配置属性 * `pawnKinds` (`List`): 一个 `PawnKindDef` 的列表,用于填充右键菜单的选项。 * `whitelist` (`List`): 一个 `PawnKindDef` 的白名单,只有在这个列表中的 Pawn 才能看到并使用这个右键菜单。 * `delay` (`int`): 延迟时间,单位为 Ticks (1秒 = 60 Ticks)。 * `destroyOnSpawn` (`bool`): (可选, 默认为 `false`) 如果为 `true`,则在生成 Pawn 后摧毁建筑。 * `lordJob` (`Type`): (可选) 生成的 Pawn 要执行的集体任务。 ### 2.2. XML 示例 ```xml ARA_PawnSpawner A device that can be used to spawn pawns after a delay.
  • Megascarab
  • Spelopede
  • Colonist
  • 300 true RimWorld.LordJob_AssaultColony
    ``` ## 3. 类设计 ### 3.1. `CompProperties_SpawnPawnFromList.cs` ```csharp using System; using System.Collections.Generic; using Verse; namespace ArachnaeSwarm { public class CompProperties_SpawnPawnFromList : CompProperties { public List pawnKinds; public List whitelist; public int delay = 0; public bool destroyOnSpawn = false; public Type lordJob; public CompProperties_SpawnPawnFromList() { compClass = typeof(CompSpawnPawnFromList); } public override IEnumerable ConfigErrors(ThingDef parentDef) { foreach (string item in base.ConfigErrors(parentDef)) { yield return item; } if (lordJob != null && !typeof(RimWorld.LordJob).IsAssignableFrom(lordJob)) { yield return $"lordJob {lordJob} must be of type LordJob"; } } } } ``` ### 3.2. `CompSpawnPawnFromList.cs` ```csharp using System.Collections.Generic; using Verse; using RimWorld; namespace ArachnaeSwarm { public class CompSpawnPawnFromList : ThingComp { private CompProperties_SpawnPawnFromList Props => (CompProperties_SpawnPawnFromList)props; private int spawnUntilTick = -1; private PawnKindDef spawningPawnKind; public override IEnumerable CompFloatMenuOptions(Pawn selPawn) { if (spawnUntilTick > 0) { yield break; // 正在延迟中,不显示菜单 } if (Props.whitelist == null || !Props.whitelist.Contains(selPawn.kindDef)) { yield break; } if (Props.pawnKinds != null) { foreach (PawnKindDef pawnKind in Props.pawnKinds) { yield return new FloatMenuOption($"Spawn {pawnKind.label}", () => { StartDelayedSpawn(pawnKind); }); } } } private void StartDelayedSpawn(PawnKindDef pawnKind) { spawningPawnKind = pawnKind; spawnUntilTick = Find.TickManager.TicksGame + Props.delay; } public override void CompTick() { base.CompTick(); if (spawnUntilTick > 0 && Find.TickManager.TicksGame >= spawnUntilTick) { SpawnPawn(spawningPawnKind); spawnUntilTick = -1; spawningPawnKind = null; } } private void SpawnPawn(PawnKindDef pawnKind) { Pawn pawn = PawnGenerator.GeneratePawn(new PawnGenerationRequest(pawnKind, parent.Faction)); GenSpawn.Spawn(pawn, parent.Position, parent.Map); if (Props.lordJob != null) { Lord lord = LordMaker.MakeNewLord(parent.Faction, (LordJob)System.Activator.CreateInstance(Props.lordJob), parent.Map); lord.AddPawn(pawn); } if (Props.destroyOnSpawn) { parent.Destroy(DestroyMode.Vanish); } } public override string CompInspectStringExtra() { if (spawnUntilTick > 0) { int remainingTicks = spawnUntilTick - Find.TickManager.TicksGame; return $"Spawning in: {remainingTicks.ToStringTicksToPeriod()}"; } return base.CompInspectStringExtra(); } public override void PostExposeData() { base.PostExposeData(); Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1); Scribe_Defs.Look(ref spawningPawnKind, "spawningPawnKind"); } } } ``` ## 4. 使用示例 1. 一个 `Colonist` 右键点击 `ARA_PawnSpawner`,选择 "Spawn Megascarab"。 2. `ARA_PawnSpawner` 进入延迟状态。当玩家选中它时,检查面板会显示 "Spawning in: 5 seconds"。 3. 5 秒后,一个新的 `Megascarab` 被生成。 4. 由于 `destroyOnSpawn` 为 `true`,`ARA_PawnSpawner` 建筑被摧毁。