docs(10-11): 迭代修正读者阻断问题(第3轮)

- 地图伤害编号改为对齐后的权威表:领域 13 / 夹击 14 / 阻击 16 / 激光 22 / 捕捉 25
- 伏击统一改为捕捉,明确伤害恒 0 属设计如此;实际结算已接通
- 更新特殊属性与战斗脚本中的编号说明,移除未对齐叙述
- 补充查询注册签名差异,并让「同化」描述与示例逻辑一致
This commit is contained in:
unanmed 2026-10-17 22:20:37 +08:00
parent 2494629f0d
commit beedb185d1
5 changed files with 64 additions and 23 deletions

View File

@ -142,4 +142,49 @@
- 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` → **green**,输出 `build complete`,dead link = 0。
- 非阻断项(N-01..N-18):本轮仍不修,留待用户判断;N-4 已知、待用户提供示例后处理。
---
## 第 3 轮 · 复审问题清单(round 3 recheck)
**触发:** 用户已在 `src/data/enemy/` 对齐特殊属性编号(提交 `2494629 fix: 属性编号问题`),第 2 轮记录的「编号未对齐 / 待补齐」状态解除。据此复核第 2 轮的遗留项,并处理读者新提出的 4 个困惑点。
### 原阻断项复核
| # | 结论 | 说明 |
|---|------|------|
| B-03 | 已消除 | `special.ts` 注册的 0–26 与 `mapDamage.ts` 转换器读取的编号现已一致,文档可直接给出权威编号表。 |
### 新的可操作困惑点(4)
| # | 问题 | 定位 |
|---|------|------|
| R3-01 | 旧文残留「15 双重含义」的冲突叙述,读者仍会以为 15 既可能是仇恨又可能是领域 | `enemy-map-damage.md` |
| R3-02 | 旧文仍写「27 / 伏击」,而现行内置特殊属性是 25 / 捕捉 | `enemy-map-damage.md`、`enemy-specials.md` |
| R3-03 | `registerCommonQueryEffect(code, effect)` 与 `registerSpecialQueryEffect(effect)` 签名不对称,未解释原因 | `enemy-query.md` |
| R3-04 | 「同化」的文字描述(范围内、非数值取索引最小)与示例逻辑(遍历全场、数值加算)不符 | `enemy-query.md` |
## 第 3 轮迭代记录(Task 2 · round 3)
**本轮目标:** 按已对齐的源码修正地图伤害编号与命名,并消除 R3-01..R3-04。本轮为迭代上限内的最后一轮。
### 逐条处置
| # | 处置 | 改动文件 |
|---|------|----------|
| B-03 / R3-01 | 删除两列「转换器读取的 code vs `special.ts` code」对照表与「编号未对齐」warning,改为单列权威表:领域 13、夹击 14、阻击 16、激光 22、捕捉 25;明确「挂上对应内置属性即可生效」;删去 15/16/18/24/27 的全部偏差叙述,15 现在只表示仇恨。 | `enemy-map-damage.md` |
| B-03 | `enemy-specials.md` 的「转换器编号未对齐」warning 替换为一句对齐说明(转换器读取同一组 13/14/16/22/25)。 | `enemy-specials.md` |
| B-03 | `enemy-combat-script.md` 的 code 18 注解改为「18 = 无敌,地图伤害使用同一套编号(阻击是 16),无编号冲突」。 | `enemy-combat-script.md` |
| R3-02 | 全文「伏击」改为「捕捉」(code 25):表项、开篇枚举、实现位置表;并注明视图类名沿用 `AmbushDamageView`(历史命名)。 | `enemy-map-damage.md`、`enemy-specials.md` |
| R3-02 | 明确捕捉伤害恒为 0、类型为 `MapDamageType.Unknown`、只产生 `extra.catch`,这是设计如此,不是未补齐的功能。 | `enemy-map-damage.md` |
| R3-02 | 删去「实际结算仍在补齐」:`hook.ts` 的 `handleMapDamage` 已接通扣血、阻击后退与捕捉强制战斗。 | `enemy-map-damage.md` |
| R3-03 | 补充一句签名差异的原因:常规查询绑定在单个 code 上,引擎需按 code 找到触发它的属性;特殊查询面向整只怪物、由 `shouldQuery` 自行筛选,可一次改动多个属性,故不绑定 code。 | `enemy-query.md` |
| R3-04 | 重写「同化」描述以匹配示例:用 `ctx.iterateEnemy()` 遍历全场(如需范围改用 `ctx.scanRange`);自己没有的属性按位置索引从小到大照抄,已有的数值型属性与场上其他怪物加算叠加;开篇「附近怪物」改为「其他怪物」。 | `enemy-query.md` |
### 校验
- 源码核对:`src/data/enemy/special.ts`(`map.set` 0..26,13 领域 / 14 夹击 / 15 仇恨 / 16 阻击 / 18 无敌 / 20 固伤 / 22 激光 / 25 捕捉)、`src/data/enemy/mapDamage.ts`(转换器读取 13/14/16/22/25;`BetweenDamageView` 对侧 `hasSpecial(14)`;`AmbushDamageView` 读取 25 并返回 0 伤害 + `extra.catch`)、`src/data/enemy/calculator.ts`(18 无敌、20 固伤)、`src/data/enemy/hook.ts`(`handleMapDamage` 已结算)、`packages-user/data-system/src/combat/types.ts`(`registerCommonQueryEffect(code, effect)` / `registerSpecialQueryEffect(effect)`)。
- 结构门禁:24 篇全部 CRLF、单 H1(`STRUCT-DONE`,无 `LF-ONLY` / `H1-COUNT`)。
- 构建门禁:`cmd /c "pnpm exec tsx docs/.vitepress/init.ts && pnpm docs:build"` → **green**,输出 `build complete`,dead link = 0。
- 结论:第 2 轮遗留的 B-03 与 R3-01..R3-04 全部消除;本轮为第 3 轮(上限),未发现新的阻断性理解问题。

View File

@ -84,7 +84,7 @@ state.combat.addCombatScript(new SealCombatScript());
`priority = 100` 让它先于内置脚本执行;返回 `false` 后,后续战前脚本、战后脚本与 `onAfterCombat` 钩子都不会执行。
这里的 18 号在内置属性编号表里就是「无敌」。地图伤害转换器把 18 读作「阻击」是它自身的编号未对齐(见[地图伤害](./enemy-map-damage.md)),与本篇的判定无关。
这里的 18 号在内置属性编号表里就是「无敌」,地图伤害的转换器也使用同一套编号(阻击是 16),所以这个判断与其他系统没有编号冲突。
## 战后示例:战后玩家回复固定量生命值

View File

@ -1,6 +1,6 @@
# 地图伤害
地图伤害不是通过战斗结算的伤害,而是勇士在地图上移动时,根据怪物与位置自动扣减的生命值。常见形式有领域、夹击、阻击、激光与伏击。整体流程见[战斗总览](./combat-overview.md)。
地图伤害不是通过战斗结算的伤害,而是勇士在地图上移动时,根据怪物与位置自动扣减的生命值。常见形式有领域、夹击、阻击、激光与捕捉。整体流程见[战斗总览](./combat-overview.md)。
## 三部分
@ -34,24 +34,20 @@ mapDamage?.useConverter(new MainMapDamageConverter());
`MapDamageType` 定义了 `Unknown`、`Zone`、`Layer`、`Repulse`、`Between` 五种类型。内置视图与转换器在 `src/data/enemy/mapDamage.ts`:
| 类型 | 视图类 | 转换器读取的 code | `special.ts` 中同名属性的 code | 说明 |
|------|--------|-------------------|-------------------------------|------|
| 领域 | `ZoneDamageView` | `getSpecial(15)` | 13 | 范围内自动减血 |
| 夹击 | `BetweenDamageView` | `hasSpecial(16)` | 14 | 两只怪物夹住勇士时扣半血 |
| 阻击 | `RepulseDamageView` | `getSpecial(18)` | 16 | 经过时怪物后退并造成伤害 |
| 激光 | `LaserDamageView` | `getSpecial(24)` | 22 | 同行或同列时造成伤害 |
| 伏击 | `AmbushDamageView` | `hasSpecial(27)` | 未注册 | 返回 0 伤害并附带捕捉标记 |
| 类型 | 视图类 | 内置特殊属性 code | 说明 |
|------|--------|-------------------|------|
| 领域 | `ZoneDamageView` | 13(`ISpecial13Value`) | 范围内自动减血 |
| 夹击 | `BetweenDamageView` | 14 | 两只怪物夹住勇士时扣半血 |
| 阻击 | `RepulseDamageView` | 16 | 经过时怪物后退并造成伤害 |
| 激光 | `LaserDamageView` | 22 | 同行或同列时造成伤害 |
| 捕捉 | `AmbushDamageView` | 25 | 触发强制战斗,本身不造成伤害 |
:::warning 编号与结算:今日可用 vs 待补齐
- **今日可用**:地图伤害系统本身的三个部件——伤害视图、转换器、合并器——都已实现,注册(`useConverter` / `useReducer`)照常可用。只要让特殊属性使用转换器真正读取的 code,或按下方「受地形遮挡的激光」那样自定义属性 + 转换器,地图伤害就能生效。
- **待补齐(编号未对齐)**:上表两组 code 目前并不一致——转换器实际读取的是 15、16、18、24、27,而 `special.ts` 注册的是 13、14、16、22、24,且没有 27。因此按当前 `src/` 代码,直接给怪物挂上内置的「领域 / 夹击 / 阻击 / 激光」特殊属性,并不会产生对应的地图伤害;「伏击」在内置特殊属性里也没有登记。其中 18 号尤其容易混淆:`special.ts` 把 18 定义为「无敌」([战斗脚本](./enemy-combat-script.md)的示例正是用它判断怪物不可战胜),而这里的转换器却把 18 读作「阻击」——同一个数字在被两处代码赋予两种含义,这正是编号未对齐的直接体现;16、24 同样存在转换器与内置表不一致的情况。使用内置编号前,请以你的 `src/data/enemy/mapDamage.ts` 为准二选一:让特殊属性改用转换器真正读取的 code,或修改转换器使其与 `special.ts` 对齐。
- **待补齐(实际结算)**:移动时真正的结算逻辑仍在补齐,见下文「实际结算」。
:::
表中的 code 就是 `src/data/enemy/special.ts` 里同名内置属性注册的编号,转换器读取的也是同一组编号。要启用某类地图伤害,给怪物挂上对应的内置特殊属性即可,不需要再换算编号或修改转换器。
另外两点以当前代码为准:
- `AmbushDamageView` 返回 `MapDamageType.Unknown`,因为 `MapDamageType` 没有「伏击」这一项;它的作用是产生 `extra.catch`,由移动钩子触发强制战斗。
- `BetweenDamageView` 读取全局 flag `betweenAttackMax`,决定夹击伤害是否取「半血、当前怪物伤害、对侧怪物伤害」三者的较小值;对侧怪物通过 `hasSpecial(16)` 识别。
- 「捕捉」的视图类名沿用 `AmbushDamageView`(伏击),它读取的是 code 25「捕捉」。它返回 `MapDamageType.Unknown`,因为 `MapDamageType` 没有「捕捉」这一项;伤害恒为 0,作用是产生 `extra.catch`,由移动钩子触发强制战斗。捕捉本身不造成伤害是设计如此,不是未补齐的功能。
- `BetweenDamageView` 读取全局 flag `betweenAttackMax`,决定夹击伤害是否取「半血、当前怪物伤害、对侧怪物伤害」三者的较小值;对侧怪物通过 `hasSpecial(14)` 识别,与夹击自身使用的是同一个编号。
## 示例:受地形遮挡的激光
@ -208,4 +204,4 @@ mapDamage?.useConverter(new BlockedLaserConverter());
## 实际结算
移动时由 `EnemyMoveHooks.onStepEnd` 调用 `handleMapDamage`:先用 `mapDamage.getReducedDamage(location)` 取合并伤害,再扣减勇士生命、发出提示,并处理阻击后退与捕捉强制战斗。当前 `src/` 中地图伤害的实际结算仍在补齐;以上是移动钩子当前的处理方式,若你使用的版本结算逻辑不同,以当时代码为准。
移动时由 `EnemyMoveHooks.onStepEnd` 调用 `handleMapDamage`:先用 `mapDamage.getReducedDamage(location)` 取合并伤害,再扣减勇士生命、发出提示,并处理阻击后退与捕捉强制战斗。这套结算在当前 `src/data/enemy/hook.ts` 中已经接通:踩到地图伤害格会立即掉血,阻击会推动怪物后退,捕捉会触发强制战斗。

View File

@ -1,6 +1,6 @@
# 怪物查询
有些特殊属性不能只看自己。比如「抱团」要知道周围站了多少同伴,「同化」要看看附近怪物身上有什么属性,「号角」要数一数场上有多少怪物。这类属性需要先读取外部状态,再决定自己怎么变,对应的机制就叫查询(query)。
有些特殊属性不能只看自己。比如「抱团」要知道周围站了多少同伴,「同化」要看看其他怪物身上有什么属性,「号角」要数一数场上有多少怪物。这类属性需要先读取外部状态,再决定自己怎么变,对应的机制就叫查询(query)。
查询在构建计算后怪物时执行:读取周围有哪些怪物、它们带什么特殊属性、勇士在哪里,然后修改怪物自身的基础属性,或增删、修改怪物的特殊属性。基础概念见[战斗总览](./combat-overview.md)。
@ -31,6 +31,8 @@ state.enemyContext.registerCommonQueryEffect(code, effect);
state.enemyContext.registerSpecialQueryEffect(effect);
```
常规查询的效果绑定在某个 `code` 上(引擎要按 code 找到会触发它的那条特殊属性),所以注册时还要传 code;特殊查询面向整只怪物,由修饰器里的 `shouldQuery` 自行筛选目标、可以一次改动多个属性,不绑定单个 code,因此只传 effect。
`IEnemySpecialQueryEffect` 有:
- `priority`:优先级;
@ -104,7 +106,7 @@ state.enemyContext.registerCommonQueryEffect(40, effect);
## 示例:同化
「同化」的规则是:把范围内其他怪物的特殊属性复制到自己身上;数值型属性加算叠加,非数值型属性取位置索引最小的那个。它要增删、改写自己拥有的特殊属性,所以用特殊查询:
「同化」的规则是:把场上其他怪物的特殊属性搬到自己身上——自己还没有的属性直接照抄(先按位置索引从小到大排序,靠前位置的属性先被抄过来);自己已经有的数值型属性则与场上其他怪物的同一属性加算叠加。它要增删、改写自己拥有的特殊属性,所以用特殊查询(示例用 `ctx.iterateEnemy()` 遍历全场;若要限定范围,把遍历换成 `ctx.scanRange`):
```ts
import { IEnemyAttr, IHeroAttr } from '@user/data-common';

View File

@ -42,9 +42,7 @@
| 25 | 捕捉 | 无 |
| 26 | 特殊光环 | `ISpecial26Value` |
:::warning 地图伤害转换器编号未对齐
`src/data/enemy/mapDamage.ts` 里的转换器目前读取的编号与上表**不一致**:它把 15 当作领域、18 当作阻击、24 当作激光(详见[地图伤害](./enemy-map-damage.md))。以**本表**为准理解「编号代表哪种机制」;地图伤害的这条偏差属于转换器尚未对齐,挂上内置属性不一定立刻产生对应效果。
:::
地图伤害使用的也是上表的编号:转换器读取领域 13、夹击 14、阻击 16、激光 22、捕捉 25,挂上对应的内置属性就会生效(详见[地图伤害](./enemy-map-damage.md))。
## 在数据里的样子
@ -160,7 +158,7 @@ map.set(
|----------|----------|------|
| 调参类(先攻、魔攻、连击、破甲、反击、净化、固伤、仇恨、自爆等) | `src/data/enemy/calculator.ts` 的 `MainDamageCalculator.calculate` | 只改变伤害公式的结果 |
| 坚固、模仿 | `src/data/enemy/final.ts` 的 `MainEnemyFinalEffect.apply` | 只修改怪物自身基础属性 |
| 领域、夹击、阻击、激光、伏击 | `src/data/enemy/mapDamage.ts` | 伤害视图 + 转换器 |
| 领域、夹击、阻击、激光、捕捉 | `src/data/enemy/mapDamage.ts` | 伤害视图 + 转换器 |
| 光环、支援、特殊光环 | `src/data/enemy/aura.ts` | 光环视图 + 转换器 |
| 中毒的每步效果 | `src/data/enemy/hook.ts` 的 `EnemyMoveHooks.handlePoison` | 移动钩子 |
| 中毒的瞬移效果 | `src/data/enemy/hook.ts` 的 `EnemyPathfindingHooks.handlePoison` | 寻路钩子 |