docs(10-03): write data-state-overview, hero-attribute, hero-items

- 数据端总览:state 入口、常用对象表与 L0-L3 分层标注
- 勇士属性:基础/最终属性、修饰器、save 语义、只读与试算
- 勇士道具:四种类别区分与 addItem/useItem/iterateItems 等接口
This commit is contained in:
unanmed 2026-10-17 18:00:04 +08:00
parent 0348c30893
commit 627a40bc4b
3 changed files with 224 additions and 0 deletions

View File

@ -0,0 +1,64 @@
# 数据端总览
数据端的一切都从主对象 `state` 开始。本篇列出作者最常需要的对象与接口,并说明如何从 `state` 拿到它们,作为中级教程其余篇章的查表入口。
## state:一切入口
`state` 是数据端的主对象(类型为 `ICoreState`),地图、勇士、怪物、战斗、Flag 等全部挂在它下面。在数据端代码里,它通常由框架传入——例如道具效果拿到 `(item, state)`、插件拿到 `state`;你也可以从任一数据端对象向外取得它。
```ts
// 从 state 出发访问勇士、地图与 Flag
const hp = state.hero.attribute.getFinalAttribute('hp');
const floorId = state.hero.location.floorId;
const cleared = state.flags.getFieldValue('cleared');
```
## 常用对象与获取方式
下表把最常用的对象与接口列在一起:
| 对象 | 获取方式 | 用途 | 分层 |
| --- | --- | --- | --- |
| `hero` | `state.hero` | 勇士状态(属性、道具、装备、位置) | L1 |
| `maps` | `state.maps` | 楼层集合与楼层激活 | L1 |
| `flags` | `state.flags` | 全局可存档变量 | L1 |
| `enemyManager` | `state.enemyManager` | 怪物创建与查询 | L1 |
| `enemyContext` | `state.enemyContext` | 怪物属性构建与光环 | L2 |
| `combat` | `state.combat` | 战斗流程 | L2 |
| `eventSystem` | `state.eventSystem` | 地图事件执行 | L2 |
| `pathfinding` | `state.pathfinding` | 勇士寻路 | L2 |
| `tileStore` | `state.tileStore` | 图块定义存储 | L0 |
| `itemStore` | `state.itemStore` | 道具定义存储 | L0 |
| `mapStore` | `state.mapStore` | 地图定义存储 | L0 |
| `eventStore` | `state.eventStore` | 游戏事件存储 | L0 |
| `faceManager` | `state.faceManager` | 朝向管理 | L0 |
| `roleFace` | `state.roleFace` | 朝向绑定 | L0 |
| `replaySystem` | `state.replaySystem` | 录像系统 | L0 |
| `loader` | `state.loader` | 数据端加载对象 | L3 |
| `loadManager` | `state.loadManager` | 加载管理器 | L3 |
| `getDataPlugin(id)` | `state.getDataPlugin('xxx')` | 取得已加装的插件 | L3 |
| `emitTip(...)` | `state.emitTip('提示')` | 通知渲染端提示 | L0 |
```ts
const plugin = state.getDataPlugin('main');
state.emitTip('获得黄钥匙');
```
## 分层标注(L0–L3)
上表的「分层」列标注了对象所属的模块层级:L0 公共层、L1 数据层、L2 系统层、L3 顶层。分层的意义在于区分「哪些内容会进存档」「哪些内容负责产生动作」,但**不影响你如何使用它们**——所有对象都能从 `state` 直接访问,调用方式完全一致。
```ts
// 无论哪个分层,访问方式都相同
state.flags.setFieldValue('door-open', true); // L1
const map = state.maps.getActiveMap('floor-1'); // L1
state.emitTip('获得黄钥匙'); // L0
```
## 从这里继续
- 勇士的数值与加成:见[勇士属性](./hero-attribute.md);
- 勇士的道具与装备:见[勇士道具](./hero-items.md);
- 地图的层次结构:见[地图结构](./map-structure.md);
- 全局可存档变量:见[Flag 变量](./flags.md);
- 在关键动作上挂接处理:见[钩子](./hooks.md)。

View File

@ -0,0 +1,95 @@
# 勇士属性
勇士属性决定战斗数值的最终结果。本篇讲解如何读取基础与最终属性、如何修改基础属性,以及如何用修饰器施加临时或永久的加成。访问勇士属性的入口见[数据端总览](./data-state-overview.md)。
## 基础属性与最终属性
勇士属性(`state.hero.attribute`)区分**基础值**与**最终值**:
- `getBaseAttribute(name)`:基础属性,即未经任何 Buff 或装备加成的原始值;
- `getFinalAttribute(name)`:最终属性,即基础值经所有修饰器加成后的结果。
```ts
const base = state.hero.attribute.getBaseAttribute('atk');
const finalAtk = state.hero.attribute.getFinalAttribute('atk');
```
属性名与勇士属性接口 `IHeroAttr` 的字段一致,常用的有 `hp`、`hpmax`、`atk`、`def`、`mdef`、`money`、`exp` 等。
## 修改基础属性
要修改勇士的基础属性,先取到可修改对象 `getModifiableAttribute()`,再调用:
- `set(name, value)`:直接设置;
- `add(name, value)`:增减;
- `mul(name, value)`:乘以某个数;
- `div(name, value)`:除以某个数。
```ts
const attr = state.hero.getModifiableAttribute();
attr.add('atk', 10); // 攻击 +10
attr.set('hp', 1000); // 生命值设为 1000
attr.mul('money', 2); // 金币翻倍
```
只读访问(只想读取、不加修改)可用 `state.hero.attribute`;需要修改时统一走 `getModifiableAttribute()`。
## 修饰器:临时的加减与百分比
直接改基础属性会永久改变勇士数值。如果只想施加一段**临时**的加成,应使用**修饰器**。属性包内置了两种:
- `ValueModifier`(type `@system/value`):数值加减,最终值 = 原值 + 修饰值;
- `PercentageModifier`(type `@system/percentage`):按**基础值**计算百分比,最终值 = 原值 + 基础值 × 修饰值。
用 `addModifier(name, modifier, save?)` 挂上修饰器,用 `deleteModifier(name, modifier)` 移除:
```ts
import { ValueModifier, PercentageModifier } from '@user/data-base';
const attr = state.hero.getModifiableAttribute();
// 攻击永久 +5:加一个数值修饰器
attr.addModifier('atk', new ValueModifier(5));
// 防御临时 -30%:按基础防御算的百分比修饰器
const defDown = new PercentageModifier(-0.3);
attr.addModifier('def', defDown);
// 需要移除时,传回同一个修饰器对象
attr.deleteModifier('def', defDown);
```
`PercentageModifier` 的百分比以**基础值**为基数,而非当前最终值,因此多个百分比修饰器不会彼此叠乘。装备产生的加成走的也是同一套修饰器机制,见[勇士装备](./hero-equipment.md)。
## save 参数与读档一致性
`addModifier(name, modifier, save?)` 的 `save` 参数默认为 `true`,表示该修饰器会进入存档、读档后自动恢复;传 `false` 则表示**不进入存档**。
:::warning
当修饰器不进入存档时,读档后它不会自动恢复。此时应由负责分配该修饰器的**外部系统**在读档后重新分配,否则会出现「存档前有加成、读档后消失」的不一致。仅在加成完全由外部系统掌控时才使用 `save: false`。
:::
## 只读与试算
- `getAttribute()`:取只读属性对象,只能读、不能改;
- `getIsolatedAttribute()`:取一份**独立的**属性副本,修改它不会影响勇士本身,适合在不改动实际数值的前提下试算某个效果。
```ts
// 试算:把攻击 +999 后最终攻击会是多少
const trial = state.hero.getIsolatedAttribute();
trial.add('atk', 999);
const preview = trial.getFinalAttribute('atk');
```
## 示例
```ts
// 攻击 +15 永久:直接改基础属性
state.hero.getModifiableAttribute().add('atk', 15);
// 防御 -20% 临时:挂一个百分比修饰器,战斗结束后再删除
const weaken = new PercentageModifier(-0.2);
state.hero.getModifiableAttribute().addModifier('def', weaken);
```
想在属性变化时收到通知,可以用属性钩子族的 `onUpdateAttribute`,见[钩子](./hooks.md)。

View File

@ -0,0 +1,65 @@
# 勇士道具
勇士道具(`state.hero.items`)负责管理勇士拥有的除装备外的所有道具,并提供增加、查询、使用等接口。装备虽然也是道具,但归独立的装备系统,见[勇士装备](./hero-equipment.md)。
## 四种类别
道具的类别由 `ItemCategory` 定义,决定它被拾取或使用时的行为:
| 类别 | 含义 |
| --- | --- |
| `Constant` | 永久道具,使用后不消耗 |
| `Consumable` | 一次性道具,使用后消耗一个 |
| `Pick` | 即捡即用道具,拾取时立刻生效 |
| `Equipment` | 装备类道具,走装备系统 |
`Unknown` 表示尚未归类。`Pick` 道具不会进入背包:`addItem` 到 `Pick` 道具时会直接触发它的效果。
## 常用接口
- `addItem(item, count?)`:增加道具数量,`count` 可以填负数以扣除道具,默认为 1;对 `Pick` 道具会立刻执行其效果。
- `getItemState(item)`:获取指定道具的状态,不存在返回 `null`。
- `iterateItems()`:迭代勇士拥有的所有道具。
- `useItem(item)`:使用道具,**仅对 `Constant` 与 `Consumable` 生效**,`Consumable` 使用后数量减一。
- `itemCount(item)`:获取指定道具的持有数量。
`item` 参数可以传道具的图块数字或字符串 id。
```ts
// 发一把黄钥匙(+1)
state.hero.items.addItem('yellow-key');
// 扣减道具(数量传负数)
state.hero.items.addItem('yellow-key', -2);
// 使用道具
state.hero.items.useItem('yellow-key');
// 查询数量
const count = state.hero.items.itemCount('yellow-key');
```
## 迭代背包
```ts
for (const [num, item] of state.hero.items.iterateItems()) {
// num 为道具图块数字,item 为道具状态
state.emitTip(`${item.id}: ${item.count}`);
}
```
## 道具效果属内容层
道具的**使用效果本身**写在内容层的 `src/content/item.ts`,通过 `IItemEffect` 描述:`useEffect` 在 `Pick` 拾取或 `Constant`/`Consumable` 使用时触发,`canUse` 决定能否使用,`useEvent` 关联使用事件。道具效果可以调用 `state`(数据端主对象)与道具数据,因而能修改勇士属性、设置 Flag、发送提示等。
```ts
// src/content/item.ts(内容层)
export const item200: ItemEffect = {
useEffect(item, state) {
state.hero.getModifiableAttribute().add('atk', 5); // [!code ++]
state.emitTip('攻击力提升!'); // [!code ++]
}
};
```
想了解从 `state` 能取到哪些对象,见[数据端总览](./data-state-overview.md)。