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

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

No files matched your search

+1 -1
View File
@@ -84,7 +84,7 @@ state.combat.addCombatScript(new SealCombatScript());
`priority = 100` 让它先于内置脚本执行;返回 `false` 后,后续战前脚本、战后脚本与 `onAfterCombat` 钩子都不会执行。
这里的 18 号在内置属性编号表里就是「无敌」。地图伤害转换器把 18 读作「阻击」是它自身的编号未对齐(见[地图伤害](./enemy-map-damage.md)),与本篇的判定无关。
这里的 18 号在内置属性编号表里就是「无敌」,地图伤害的转换器也使用同一套编号(阻击是 16),所以这个判断与其他系统没有编号冲突。
## 战后示例:战后玩家回复固定量生命值
+12 -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` 中已经接通:踩到地图伤害格会立即掉血,阻击会推动怪物后退,捕捉会触发强制战斗。
+4 -2
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';
+2 -4
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` | 寻路钩子 |