Files
ArachnaeSwarm/Source/Documents/SpawnPawnFromList_Design.md
2025-09-05 12:57:38 +08:00

180 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# CompSpawnPawnFromList 功能设计文档
## 1. 功能概述
`CompSpawnPawnFromList` 是一个 `ThingComp` 组件,它允许一个特定的 Pawn 通过右键菜单与一个物体交互,从一个可配置的列表中选择一个 Pawn并在经过一段可配置的延迟后生成这个 Pawn。在延迟期间剩余时间会显示在建筑的检查面板上。可以选择在生成 Pawn 后是否摧毁建筑。
## 2. XML 配置
### 2.1. 配置属性
* `pawnKinds` (`List<PawnKindDef>`): 一个 `PawnKindDef` 的列表,用于填充右键菜单的选项。
* `whitelist` (`List<PawnKindDef>`): 一个 `PawnKindDef` 的白名单,只有在这个列表中的 Pawn 才能看到并使用这个右键菜单。
* `delay` (`int`): 延迟时间,单位为 Ticks (1秒 = 60 Ticks)。
* `destroyOnSpawn` (`bool`): (可选, 默认为 `false`) 如果为 `true`,则在生成 Pawn 后摧毁建筑。
* `lordJob` (`Type`): (可选) 生成的 Pawn 要执行的集体任务。
### 2.2. XML 示例
```xml
<ThingDef ParentName="BuildingBase">
<defName>ARA_PawnSpawner</defName>
<label>Pawn Spawner</label>
<description>A device that can be used to spawn pawns after a delay.</description>
<!-- 其他属性 -->
<comps>
<li Class="ArachnaeSwarm.CompProperties_SpawnPawnFromList">
<pawnKinds>
<li>Megascarab</li>
<li>Spelopede</li>
</pawnKinds>
<whitelist>
<li>Colonist</li>
</whitelist>
<delay>300</delay> <!-- 5秒 -->
<destroyOnSpawn>true</destroyOnSpawn>
<lordJob>RimWorld.LordJob_AssaultColony</lordJob>
</li>
</comps>
</ThingDef>
```
## 3. 类设计
### 3.1. `CompProperties_SpawnPawnFromList.cs`
```csharp
using System;
using System.Collections.Generic;
using Verse;
namespace ArachnaeSwarm
{
public class CompProperties_SpawnPawnFromList : CompProperties
{
public List<PawnKindDef> pawnKinds;
public List<PawnKindDef> whitelist;
public int delay = 0;
public bool destroyOnSpawn = false;
public Type lordJob;
public CompProperties_SpawnPawnFromList()
{
compClass = typeof(CompSpawnPawnFromList);
}
public override IEnumerable<string> 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<FloatMenuOption> 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` 建筑被摧毁。