docs(10-08): 引导式重写 calculator/script/status-hooks

- enemy-calculator:从「属性换算成伤害」引入,保留公式导读与临界约定
- enemy-combat-script:从「战斗前后的规则」引入,保留脚本/钩子选型表
- enemy-status-hooks:从「状态要反复生效」引入,强调多钩子协同
This commit is contained in:
unanmed 2026-10-17 21:05:18 +08:00
parent f5e432d04f
commit de5e9e1229
3 changed files with 15 additions and 5 deletions

View File

@ -1,6 +1,8 @@
# 伤害计算
伤害计算器决定一次战斗的伤害与回合数。它实现的是 `f(enemy, hero)`:输入计算后的怪物与勇士属性,输出 `{ damage, turn }`。本篇导读内置公式,并说明要改公式时应该动哪里。整体流程见[战斗总览](./combat-overview.md)。
属性算准之后,战斗还差最后一步换算:这些 `hp`、`atk`、`def` 到底意味着勇士会掉多少血、要打几回合?负责这件事的就是伤害计算器。
它实现的是 `f(enemy, hero)`:输入计算后的怪物与勇士属性,输出 `{ damage, turn }`。本篇导读内置公式,并说明要改公式时应该动哪里。整体流程见[战斗总览](./combat-overview.md)。
## 接口
@ -27,7 +29,7 @@ state.enemyContext.getDamageSystem()?.useCalculator(new MainDamageCalculator());
## 内置公式逐段导读
`MainDamageCalculator.calculate`(`src/data/enemy/calculator.ts`)按以下顺序计算:
与其一次背下整条公式,不如按顺序看每一段在算什么。`MainDamageCalculator.calculate`(`src/data/enemy/calculator.ts`)按以下顺序计算:
1. **读取属性**:从 `hero` 读 `hp`、`atk`、`def`、`mdef`,从 `enemy` 读 `atk`、`def`、`hp`。
2. **无敌分支**:满足条件时直接返回 `{ damage: Infinity, turn: 0 }`,表示无法击败。
@ -53,6 +55,8 @@ state.enemyContext.getDamageSystem()?.useCalculator(new MainDamageCalculator());
## 示例:等差数列属性
有时公式本身要随回合变化,而光环、查询、最终效果都做不到这一点——它们改的是一次计算里的固定属性。这时就该动计算器。
「等差数列属性」指怪物攻击每回合按固定值递增。属性本身在一次计算中是常量,所以不能靠给 `atk` 加值实现;要在 `calculate` 里把「每回合伤害」按等差数列求和:
```ts

View File

@ -1,6 +1,8 @@
# 战斗脚本
战斗脚本(combat script)挂在战斗流程上,在战前或战后执行一段逻辑。战前脚本可以决定「这场战斗是否发生」,战后脚本负责结算奖励或修改状态。脚本与钩子的分工见下方选型表,整体流程见[战斗总览](./combat-overview.md)。
战斗前后常有一些规则要跑:有的怪物「不许打」,有的战斗要「打完回血」,还有的要在结算奖励前调整状态。这些规则不适合塞进伤害公式,而是在战斗流程上挂一段逻辑——这就是战斗脚本(combat script)。
战前脚本可以决定「这场战斗是否发生」,战后脚本负责结算奖励或修改状态。脚本与钩子的分工见下方选型表,整体流程见[战斗总览](./combat-overview.md)。
## 接口
@ -36,6 +38,8 @@ state.combat.addCombatScript(new MainCombatScript());
## 脚本 vs 钩子
战斗前后能做事的除了脚本,还有钩子。两者的区别主要在「能不能改变战斗的走向」和「多个监听者如何共存」:
| 需求 | 用脚本 | 用钩子 |
|------|--------|--------|
| 决定这场战斗是否发生 | 是,`before` 返回 `false` | 否,`onBeforeCombat` 不能阻止战斗 |

View File

@ -1,6 +1,8 @@
# 状态钩子
状态类特殊属性(中毒、衰弱、重生等)不会在一次计算里结束:它们要在移动、战斗、切换楼层等时机反复生效。这类属性必须借助钩子实现,而且一个状态往往需要**多个钩子**协同。钩子本身的用法见[钩子](./hooks.md),整体流程见[战斗总览](./combat-overview.md)。
中毒、衰弱、重生这类状态有个共同点:它们不会在一次计算里结束,而是要在移动、战斗、切换楼层等时机反复生效。只靠一次属性调整实现不了,必须挂到这些时机上——这就是钩子(hook)。
而且这类状态往往不能只挂一个钩子。中毒要同时管正常走路与瞬移,重生要同时管战后与切层。钩子本身的用法见[钩子](./hooks.md),整体流程见[战斗总览](./combat-overview.md)。
## 为什么一个状态要用多个钩子
@ -58,7 +60,7 @@ state.hero.location.addHook(new EnemyChangeFloorHooks(state));
## 示例:下次战斗伤害乘二
这个状态需要两处配合:战斗钩子负责「挂上状态」,伤害计算器负责「消费状态」。先定义一个无参数特殊属性(code 45):
钩子能改状态,但「伤害乘二」最终要由伤害公式来兑现。这个例子正好展示一个状态如何跨两个系统:战斗钩子负责「挂上状态」,伤害计算器负责「消费状态」。先定义一个无参数特殊属性(code 45):
```ts
// special.ts:45 - 蓄力