feat(Flyover): 天巫集群掠食 — 空投拦截系统

新增天巫种对敌方空投袭击的自动拦截功能:
- GameComponent_DropPodInterceptor: 全局拦截状态管理与核心逻辑
- Harmony Prefix 挂钩 EdgeDrop/CenterDrop Arrive(),拦截 1-3 个运输仓
- 被拦截 Pawn 击杀(Bite)后尸体以空投仓形式落地
- 拦截时生成天巫种 FlyOver 视觉飞越 + PositiveEvent 信件通知
- 引航种新增 ARA_ToggleDropPodIntercept 自释放能力切换开关
- 前置检查:开关启用 + 天巫升空 + 敌对派系,至少保留 1 名袭击者

新增文件:
- Source/.../GameComponent_DropPodInterceptor.cs
- Source/.../Patch_DropPodIntercept.cs
- Source/.../CompAbilityEffect_ToggleDropPodIntercept.cs
- Defs/AbilityDefs/Ability_DropPodIntercept.xml

修改文件:
- ARA_PawnKinds.xml (Skyraider abilities)
- AirStrike_Keys.xml (10 localization keys)
- ArachnaeSwarm.csproj (3 Compile entries)
This commit is contained in:
2026-02-17 15:54:35 +08:00
parent 4c2bf41f19
commit 988967439f
11 changed files with 598 additions and 3 deletions

View File

@@ -0,0 +1,112 @@
# 落地交付文档:天巫集群掠食 - 空投拦截系统
## 1. 目标与结论
- 目标:实现“敌方空投袭击可被天巫种拦截”的完整闭环(开关控制、拦截逻辑、视觉反馈、通知、持久化)。
- 结论:核心功能已完成并通过编译,已具备交由 planer 进行方案审阅与验收测试的条件。
## 2. 实现范围(按 plan.md 对齐)
### 2.1 GameComponent 全局状态与拦截逻辑
- 新增文件:`Source/ArachnaeSwarm/Flyover/GameComponent_DropPodInterceptor.cs`
- 已实现:
- `bool interceptEnabled` 持久化(`ExposeData` + `Scribe_Values.Look`)。
- `ToggleIntercept()` 开关切换与日志。
- `HasAirborneTianwu()` 检查 `WorldComponent_AircraftManager.GetAvailableAircraftCount(...) > 0`
- `TryInterceptDropPods(...)`
- 前置检查:开关、敌对派系、可用天巫、至少保留 1 名袭击者。
- 随机拦截 1-3 名(上限由 `pawns.Count - 1` 约束)。
- 拦截对象执行 `Pawn.Kill(DamageInfo)`,收集 `Corpse`
-`DropPodUtility.DropThingsNear(...)` 以空投仓形式落尸。
- 触发 FlyOver复用 `ARA_HiveCorvette_Fake`)与信件通知。
### 2.2 Harmony 补丁
- 新增文件:`Source/ArachnaeSwarm/HarmonyPatches/Patch_DropPodIntercept.cs`
- 已实现:
- Prefix 挂钩:
- `PawnsArrivalModeWorker_EdgeDrop.Arrive`
- `PawnsArrivalModeWorker_CenterDrop.Arrive`
- 两个入口共用 `InterceptPrefix(...)`
- **不跳过原方法**`return true`),原方法继续处理剩余 `pawns`
### 2.3 引航种能力(开关)
- 新增文件:`Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ToggleDropPodIntercept.cs`
- 已实现:
- `CompProperties_ToggleDropPodIntercept`
- `CompAbilityEffect_ToggleDropPodIntercept`
- `Apply`:切换全局开关 + 消息提示。
- `Valid`:无可用天巫时拒绝施放并提示。
- `ExtraLabelMouseAttachment`:显示“开启/关闭”状态文本。
### 2.4 Ability Def
- 新增文件:`1.6/1.6/Defs/AbilityDefs/Ability_DropPodIntercept.xml`
- 已实现:
- 新能力 `ARA_ToggleDropPodIntercept`
- 自施放、`targetRequired=false``targetable=false`、无冷却切换。
### 2.5 挂载到 Skyraider
- 修改文件:`1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml`
- 已实现:
-`ArachnaeNode_Race_Skyraider``abilities` 中追加:`ARA_ToggleDropPodIntercept`
### 2.6 本地化
- 修改文件:`1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml`
- 已实现 key
- `ARA_ToggleDropPodIntercept_Label`
- `ARA_ToggleDropPodIntercept_Desc`
- `ARA_InterceptDropPod_Enabled`
- `ARA_InterceptDropPod_Disabled`
- `ARA_InterceptDropPod_NoAircraft`
- `ARA_InterceptDropPod_Status`
- `ARA_InterceptDropPod_StatusOn`
- `ARA_InterceptDropPod_StatusOff`
- `ARA_InterceptDropPod_LetterLabel`
- `ARA_InterceptDropPod_LetterText`
### 2.7 工程文件同步
- 修改文件:`Source/ArachnaeSwarm/ArachnaeSwarm.csproj`
- 已实现:新增 3 个 C# 文件的 `<Compile Include="..." />`
## 3. 与 plan.md 的差异说明(供 planer 决策)
- FlyOver Def按 plan 的“优先复用”策略,当前复用 `ARA_HiveCorvette_Fake`**未新增** `ARA_HiveCorvette_Intercept` ThingDef。
- `CompAbilityEffect_ToggleDropPodIntercept.Valid` 使用单目标签名(与现项目其他 Ability 风格一致),未采用数组签名版本。
- 能力 label/description 当前写在 AbilityDef 内key 已补全;若需严格 DefInjected 化,可由 planer 决定是否二次整理。
## 4. 构建与验证
- 构建命令(已执行):
- `MSBuild ArachnaeSwarm.csproj -p:Configuration=Release -verbosity:minimal`
- 结果:通过。
- 输出:
- `1.6/1.6/Assemblies/ArachnaeSwarm.dll`
- `1.6/1.6/Assemblies/ArachnaeSwarm.pdb`
## 5. 建议的审阅清单(给 planer
- 逻辑正确性:
- 是否接受“至少保留 1 名袭击者”的平衡策略。
- 是否接受“仅敌对派系 + EdgeDrop/CenterDrop 生效”的作用域。
- 体验反馈:
- FlyOver 速度、出现时机、信件文案是否符合预期。
- 兼容性:
- 与其他修改袭击到场逻辑的 Harmony 补丁是否可能冲突。
- 本地化策略:
- 是否要求将 AbilityDef `label/description` 进一步改为 DefInjected。
## 6. 建议测试用例(未在本轮自动化执行)
- Dev 触发 `Raid (EdgeDrop)`:验证拦截 1-3尸体空投、FlyOver、信件。
- Dev 触发 `Raid (CenterDrop)`:同上。
- 关闭拦截后再触发空投:验证不拦截。
- 触发 `EdgeWalkIn`:验证不拦截。
- 触发友军空投:验证不拦截。
- 存档/读档:验证 `interceptEnabled` 状态持久化。
## 7. 当前改动文件清单
- `Source/ArachnaeSwarm/Flyover/GameComponent_DropPodInterceptor.cs`(新增)
- `Source/ArachnaeSwarm/HarmonyPatches/Patch_DropPodIntercept.cs`(新增)
- `Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ToggleDropPodIntercept.cs`(新增)
- `1.6/1.6/Defs/AbilityDefs/Ability_DropPodIntercept.xml`(新增)
- `1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml`(修改)
- `1.6/1.6/Languages/ChineseSimplified (简体中文)/Keyed/AirStrike_Keys.xml`(修改)
- `Source/ArachnaeSwarm/ArachnaeSwarm.csproj`(修改)
---
如需我继续可下一步直接输出“planer审阅意见处理版”补丁按审阅结论二改

134
.snow/plan.md Normal file
View File

@@ -0,0 +1,134 @@
# Plan: 天巫集群掠食 — 空投拦截系统
**TL;DR**:通过 Harmony Prefix 补丁拦截原版 `EdgeDrop``CenterDrop``Arrive()` 方法,在敌方空投仓落地前由天巫种拦截 1-3 个运输仓。击杀后尸体仍以运输仓形式落地。使用 `GameComponent` 全局管理开关状态,引航种 Pawn 通过自释放 `AbilityDef` 切换开关。拦截时生成天巫种 FlyOver 作为视觉反馈。
## 架构概览
```
[敌方袭击触发]
IncidentWorker_RaidEnemy → Arrive(pawns, parms)
↓ Harmony Prefix
[新增] Patch_DropPodIntercept
→ GameComponent_DropPodInterceptor.TryIntercept()
├── 检查 interceptEnabled (引航种toggle)
├── 检查 WorldComponent_AircraftManager 有可用天巫
├── 验证 parms.faction.HostileTo(Player)
├── 随机选取 1-3 pawns → Kill → 获取 Corpse
├── 用 DropPodUtility.DropThingsNear 投掷尸体
├── FlyOver.MakeFlyOver() 生成拦截飞越视觉
└── ReceiveLetter 通知玩家
→ 原 Arrive 继续执行(剩余 pawn 正常空投)
[引航种能力]
ArachnaeNode_Race_Skyraider → AbilityDef: ARA_ToggleDropPodIntercept
→ CompAbilityEffect_ToggleDropPodIntercept.Apply()
→ GameComponent_DropPodInterceptor.ToggleIntercept()
```
---
## Steps
### 1. 创建全局状态管理 `GameComponent_DropPodInterceptor`
新文件:`Source/ArachnaeSwarm/Flyover/GameComponent_DropPodInterceptor.cs`
- 继承 `GameComponent`,序列化字段 `bool interceptEnabled`
- 属性 `IsInterceptEnabled` — 外部查询开关状态
- 方法 `ToggleIntercept()` — 翻转开关 + `ArachnaeLog.Debug`
- 方法 `HasAirborneTianwu()` — 查询 `WorldComponent_AircraftManager`:检查 `GetAvailableAircraftCount(ThingDef ARA_HiveCorvette_Entity, Faction.OfPlayer) > 0`(非全部冷却中即可,不消耗资源)
- 核心方法 `TryInterceptDropPods(List<Pawn> pawns, IncidentParms parms, out List<Pawn> interceptedPawns)` — 完整拦截逻辑:
- 前置条件检查(`interceptEnabled` && `HasAirborneTianwu()` && `parms.faction.HostileTo(Faction.OfPlayer)`
-`pawns` 中随机移除 `Rand.RangeInclusive(1, Mathf.Min(3, pawns.Count - 1))` 个 Pawn至少保留 1 个 pawn 正常空投,避免完全吞掉袭击)
- 对每个被拦截的 Pawn调用 `pawn.Kill(new DamageInfo(DamageDefOf.Bomb, 9999f))`,收集 `pawn.Corpse` 到尸体列表
- 将尸体通过 `DropPodUtility.DropThingsNear(parms.spawnCenter, map, corpses, leaveSlag: true)` 投掷到同一空投区域
- 调用 `SpawnInterceptionFlyOver(map, parms.spawnCenter)` 生成天巫飞越视觉
- 调用 `SendInterceptionLetter(map, interceptedCount, parms.spawnCenter)` 发送信件
- 方法 `SpawnInterceptionFlyOver(Map, IntVec3)` — 调用 `FlyOver.MakeFlyOver()` 生成 `ARA_HiveCorvette_Fake`(复用现有视觉 FlyOver ThingDef起点从地图边缘到空投中心飞越
- 方法 `SendInterceptionLetter(Map, int count, IntVec3)` — 发送自定义 `LetterDefOf.PositiveEvent` 信件,告知玩家拦截了多少运输仓
- `ExposeData()``Scribe_Values.Look(ref interceptEnabled, "interceptEnabled", false)`
### 2. 创建 Harmony 补丁 `Patch_DropPodIntercept`
新文件:`Source/ArachnaeSwarm/HarmonyPatches/Patch_DropPodIntercept.cs`
- `[HarmonyPatch(typeof(PawnsArrivalModeWorker_EdgeDrop), "Arrive")]` — Prefix
- `[HarmonyPatch(typeof(PawnsArrivalModeWorker_CenterDrop), "Arrive")]` — Prefix
- 两个 Prefix 共用同一个静态方法 `InterceptPrefix(List<Pawn> pawns, IncidentParms parms)`
- Prefix 逻辑:获取 `Current.Game.GetComponent<GameComponent_DropPodInterceptor>()`,调用 `TryInterceptDropPods(pawns, parms)`
- **不 skip 原方法**`return true`),原方法继续用被修改过的 `pawns` 列表正常空投剩余敌人
### 3. 创建引航种切换能力 `CompAbilityEffect_ToggleDropPodIntercept`
新文件:`Source/ArachnaeSwarm/Abilities/CompAbilityEffect_ToggleDropPodIntercept.cs`
- `CompProperties_ToggleDropPodIntercept` 继承 `CompProperties_AbilityEffect`,包含字段:
- `string enabledMessage` / `disabledMessage` — 开启/关闭时的消息文本 key
- `ThingDef requiredAircraftType` — 需要检查的战机类型(`ARA_HiveCorvette_Entity`
- `CompAbilityEffect_ToggleDropPodIntercept` 继承 `CompAbilityEffect`
- `Apply(LocalTargetInfo, LocalTargetInfo)` — 获取 `GameComponent_DropPodInterceptor`,调用 `ToggleIntercept()`,发送 `Messages.Message` 通知当前状态
- `Valid(LocalTargetInfo[], bool)` — 检查 `WorldComponent_AircraftManager.HasAvailableAircraft` 是否有天巫升空;无天巫时禁用能力并显示 "无可用天巫种" 提示
- `ExtraLabelMouseAttachment(LocalTargetInfo)` — 返回当前状态文本("掠食巡航: 开启/关闭"
### 4. 创建拦截 FlyOver 视觉 ThingDef
修改现有文件 `1.6/1.6/Defs/Thing_Misc/ARA_Flyover_Item.xml`,新增 `ARA_HiveCorvette_Intercept` ThingDef
-`ARA_HiveCorvette_Fake` 为模板(纯视觉 FlyOver无攻击 Comp
- `thingClass="ArachnaeSwarm.FlyOver"`
- 设置较快的 `flightSpeed`(拦截应该是快速掠过)
- 可选添加 `CompProperties_SendLetterAfterTicks` 以在飞越后发出完成通知
- 或直接复用 `ARA_HiveCorvette_Fake` defName不新建 ThingDef
### 5. 创建能力 XML 定义
新文件:`1.6/1.6/Defs/AbilityDefs/Ability_DropPodIntercept.xml`
- `AbilityDef` defName: `ARA_ToggleDropPodIntercept`
- `label`: 掠食巡航(或类似命名)
- `targetRequired: false`(自释放,无需目标)
- `cooldownTicksRange: 0`(无冷却,即时切换)
- `comps`:
- `CompProperties_ToggleDropPodIntercept``requiredAircraftType: ARA_HiveCorvette_Entity`
### 6. 将能力添加到引航种
查找并修改引航种 `ArachnaeNode_Race_Skyraider` 的能力列表定义(可能在 `1.6/1.6/Defs/PawnKindDef/ARA_PawnKinds.xml` 或 Race ThingDef 中),在 `abilities` 列表中添加 `ARA_ToggleDropPodIntercept`
### 7. 添加本地化文本
修改 `1.6/1.6/Languages/ChineseSimplified/Keyed/` 下的翻译文件,添加:
- `ARA_ToggleDropPodIntercept_Label` — "掠食巡航"
- `ARA_ToggleDropPodIntercept_Desc` — 能力描述
- `ARA_InterceptDropPod_Enabled` — "掠食巡航已启动"
- `ARA_InterceptDropPod_Disabled` — "掠食巡航已关闭"
- `ARA_InterceptDropPod_LetterLabel` — "天巫种拦截空投"
- `ARA_InterceptDropPod_LetterText` — "天巫种在空中拦截了{0}个敌方运输仓…"
- `ARA_InterceptDropPod_NoAircraft` — "没有可用的天巫种兽虫"
---
## Verification
1. MSBuild 编译:`cd "ArachnaeSwarm\Source\ArachnaeSwarm" && MSBuild ArachnaeSwarm.csproj -p:Configuration=Release`
2. 游戏内测试流程:
- 建造天巫种机库 → 起飞(注册战机到 WorldComponent_AircraftManager
- 使用引航种能力开启"掠食巡航"
- 使用 dev console 触发 `Raid (EdgeDrop)` → 验证 1-3 个运输仓被拦截(尸体掉落 + FlyOver 视觉 + 信件)
- 使用 dev console 触发 `Raid (CenterDrop)` → 同上
- 关闭"掠食巡航" → 再次触发空投 → 验证不拦截
- 触发非空投袭击EdgeWalkIn → 验证不触发拦截
- 触发友方空投 → 验证不拦截HostileTo 检查)
3. 存档/读档测试:验证 `interceptEnabled` 状态持久化
---
## Decisions
- **Harmony 挂钩点**:选 `PawnsArrivalModeWorker_EdgeDrop.Arrive` + `CenterDrop.Arrive` 而非底层 `DropPodUtility`,因为只需响应这两种袭击到场模式,不影响其他空投场景(贸易、任务奖励等)
- **GameComponent vs MapComponent**:选 `GameComponent`(全局,跨地图),因为用户明确说"全局管理"
- **不消耗战机资源**:只检查 `HasAvailableAircraft` 判断天巫是否升空,不调用 `TryUseAircraft`
- **至少保留 1 个 pawn**`Mathf.Min(3, pawns.Count - 1)` 确保不会完全吞掉袭击,玩家仍需应战
- **Kill + Corpse 方案**:调用 `Pawn.Kill(DamageInfo)` 后获取 `Corpse`,再通过 `DropPodUtility.DropThingsNear` 以运输仓形式投掷尸体,既有"被击杀"的反馈感,又能剥削敌方装备
- **复用 `ARA_HiveCorvette_Fake`**:优先复用现有纯视觉 FlyOver避免新增无意义 ThingDef若需要不同飞行参数再另建