mirror of
https://github.com/motajs/template.git
synced 2026-11-03 07:24:30 +08:00
docs(10-11): 用户修订循环 batch2(代码讲解/修正)
按用户领域视角修订循环 batch 2(U-12/U-13/U-16/U-17/U-18/U-19)修正战斗各篇: - U-12/U-16:转换器 / 视图 / 效果 / 计算器 / 脚本 / 钩子代码块补逐行中文注释,并用 [模板] / [需改] 标出可照抄与必须修改的部分 - U-13:新增「注册在哪里」,给出 initializeEnemy 函数体(无关行省略)与注册调用位置 - U-17:每篇明确「改内置实现」vs「写自己的类」的区别与各自效果 - U-18:enemy-map-damage 的「受地形遮挡的激光」示例替换为更简单的「八方向激光」(FaceGroup.Dir8) - U-19:enemy-calculator 补「计算器必须无副作用」;enemy-status-hooks 的「下次战斗伤害乘二」改为钩子挂状态 + 计算器只读 + 战斗脚本消费 docs 8 篇;10-11-READER-REVIEW.md 追加 batch 2 记录。
This commit is contained in:
1 parent
8c5e8979e1
commit
5c77676bca
9 files changed
+444
-80
No files matched your search
@@ -36,6 +36,13 @@ state.combat.addCombatScript(new MainCombatScript());
|
||||
- **战前**:非强制战斗时,如果勇士当前生命小于本次伤害,返回 `false`,阻止战斗;
|
||||
- **战后**:把怪物与支援者的经验、金币加到勇士身上;`curse` flag 为 `true` 时不加;最后发出一次全局提示。
|
||||
|
||||
### 改内置,还是自己写
|
||||
|
||||
- **改内置脚本**:直接改 `src/data/enemy/script.ts` 的 `MainCombatScript`(内置的战前拦截与战后结算就写在里面)。
|
||||
- **写自己的脚本**:实现 `ICombatScript` 接口,再用 `addCombatScript` 追加。适合额外规则,或不想改动内置文件时。
|
||||
|
||||
`addCombatScript` 是**追加**而不是替换:内置脚本仍会执行,新脚本按 `priority` 与它一起排序;但同优先级的脚本不能重复注册。
|
||||
|
||||
## 脚本 vs 钩子
|
||||
|
||||
战斗前后能做事的除了脚本,还有钩子。两者的区别主要在「能不能改变战斗的走向」和「多个监听者如何共存」:
|
||||
@@ -52,9 +59,10 @@ state.combat.addCombatScript(new MainCombatScript());
|
||||
|
||||
## 战前示例:拥有某特殊属性时无法战斗
|
||||
|
||||
下面的脚本检查怪物是否拥有 code 18 的特殊属性(无敌,编号见[特殊属性](./enemy-specials.md)的「内置属性编号表」),有则直接放弃战斗(示例里的 `@motajs/*`、`@user/*` 是包名,含义见 [src 导览](./src-tour.md) 的「包从哪来」):
|
||||
下面的脚本检查怪物是否拥有 code 18 的特殊属性(无敌,编号见[特殊属性](./enemy-specials.md)的「内置属性编号表」),有则直接放弃战斗(示例里的 `@motajs/*`、`@user/*` 是包名,含义见 [src 导览](./src-tour.md) 的「包从哪来」)。代码中用 `[模板]` 标出可原样照抄的行,用 `[需改]` 标出必须按需求修改的行。
|
||||
|
||||
```ts
|
||||
// [模板] 依赖导入:类型分别来自 @user/data-common 与 @user/data-system
|
||||
import { IEnemyAttr, IHeroAttr } from '@user/data-common';
|
||||
import {
|
||||
ICombatFlowHandler,
|
||||
@@ -62,23 +70,32 @@ import {
|
||||
IEnemyDamageInfo
|
||||
} from '@user/data-system';
|
||||
|
||||
// [需改] 类名:换成你的脚本名
|
||||
export class SealCombatScript implements ICombatScript<IEnemyAttr, IHeroAttr> {
|
||||
// [需改] priority:越大越先执行;内置脚本是 0
|
||||
readonly priority = 100;
|
||||
|
||||
// [模板] before 签名固定:战前执行,返回 false 即放弃战斗
|
||||
async before(
|
||||
info: IEnemyDamageInfo<IEnemyAttr, IHeroAttr>,
|
||||
handler: ICombatFlowHandler<IEnemyAttr, IHeroAttr>
|
||||
): Promise<boolean> {
|
||||
// [需改] 判断条件:怪物带「无敌」(code 18)就拦下
|
||||
if (handler.enemy.hasSpecial(18)) {
|
||||
// [需改] 向玩家提示(可换成别的处理)
|
||||
handler.state.emitTip('这个怪物无法被击败。');
|
||||
// [模板] 返回 false:放弃本次战斗
|
||||
return false;
|
||||
}
|
||||
// [模板] 返回 true:允许继续
|
||||
return true;
|
||||
}
|
||||
|
||||
// [模板] after 也必须实现;本脚本战后不做任何事,留空即可
|
||||
async after(): Promise<void> {}
|
||||
}
|
||||
|
||||
// [需改] 注册这行要挪进 initializeEnemy(见文末「注册在哪里」)
|
||||
state.combat.addCombatScript(new SealCombatScript());
|
||||
```
|
||||
|
||||
@@ -91,6 +108,7 @@ state.combat.addCombatScript(new SealCombatScript());
|
||||
下面的脚本在每场战斗后给勇士回复 20 点生命:
|
||||
|
||||
```ts
|
||||
// [模板] 依赖导入
|
||||
import { IEnemyAttr, IHeroAttr } from '@user/data-common';
|
||||
import {
|
||||
ICombatFlowHandler,
|
||||
@@ -98,27 +116,58 @@ import {
|
||||
IEnemyDamageInfo
|
||||
} from '@user/data-system';
|
||||
|
||||
// [需改] 类名:换成你的脚本名
|
||||
export class HealAfterCombatScript implements ICombatScript<
|
||||
IEnemyAttr,
|
||||
IHeroAttr
|
||||
> {
|
||||
// [需改] priority:设成负值,排在内置脚本之后执行
|
||||
readonly priority = -10;
|
||||
|
||||
// [模板] before 也要实现;本脚本不拦截战斗,直接返回 true
|
||||
async before(): Promise<boolean> {
|
||||
return true;
|
||||
}
|
||||
|
||||
// [模板] after 签名固定:战后执行
|
||||
async after(
|
||||
info: IEnemyDamageInfo<IEnemyAttr, IHeroAttr>,
|
||||
handler: ICombatFlowHandler<IEnemyAttr, IHeroAttr>
|
||||
): Promise<void> {
|
||||
// [需改] 真正做的事:给勇士回 20 点血
|
||||
handler.hero.add('hp', 20);
|
||||
}
|
||||
}
|
||||
|
||||
// [需改] 注册
|
||||
state.combat.addCombatScript(new HealAfterCombatScript());
|
||||
```
|
||||
|
||||
`priority = -10` 让它在内置脚本之后执行,避免在奖励结算之前改动勇士状态。`handler.hero` 是可修改对象,直接 `add` 即可。
|
||||
|
||||
`priority` 只需要记住一句:数值越大越先执行;战前与战后各自按这个顺序遍历脚本列表。
|
||||
|
||||
## 注册在哪里
|
||||
|
||||
`addCombatScript` 要写进 `initializeEnemy`。下面是 `src/data/enemy/initialize.ts` 中该函数的样子(省略了无关的行):
|
||||
|
||||
```ts
|
||||
export function initializeEnemy(
|
||||
state: ICoreState
|
||||
): IEnemyInitializationReturns {
|
||||
// ...省略:怪物管理器、特殊属性、上下文、伤害系统、地图伤害的初始化...
|
||||
|
||||
const ctx = state.enemyContext;
|
||||
|
||||
// ...省略:光环转换器与最终效果的注册...
|
||||
|
||||
// 添加默认战前战后脚本 —— 内置脚本在这里注册
|
||||
state.combat.addCombatScript(new MainCombatScript());
|
||||
// [需改] 你自己的脚本紧接着追加即可:
|
||||
// state.combat.addCombatScript(new SealCombatScript());
|
||||
|
||||
// ...省略:钩子的注册...
|
||||
}
|
||||
```
|
||||
|
||||
把 `addCombatScript(...)` 放在内置脚本那一行之后,你的脚本就会随 `initializeEnemy` 一起生效。
|
||||
Reference in new issue
Block a user