if/docs/map-turn-implementation-status.md

118 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 地图回合实现进度(台账)
本文档记录**代码已落地内容**与**待接线任务**,便于在对话上下文变长时单独查阅。规则、伪代码与冻结优先级以 [map-turn-spec.md](map-turn-spec.md) 为唯一口径;本文不写新规则,只写状态与文件指针。**`patch` / `rebuild` / `performEnemyAction` 等与实现对齐的契约说明**见规范 **§6.2、§6.3、§6.7**。
---
## 1. 已完成(截至当前仓库)
### 1.1 数据表(`timeCost` 默认 `null`
| 区域 | 说明 |
|------|------|
| [project/items.js](../project/items.js) | 每条道具在 `"cls"` 下一行含 **`"timeCost": null`**;需消耗地图时间时改为正整数。**样例(已接)**`bigKey``tools`**`timeCost: 3`**,见 §1.3。 |
| [project/enemys.js](../project/enemys.js) | 每条怪物在 **`point``special` 之间**含 **`"timeCost": null`**。 |
| `enemy48` | 与 `enemys` 共用 **`core.material.enemys`** 数值,**无**独立 `libs/enemys48.js` 数据表。 |
### 1.2 引擎初始化缺省补全
| 文件 | 行为 |
|------|------|
| [libs/items.js](../libs/items.js) `items.prototype._init` | 若道具 **`timeCost === undefined`**,补 **`timeCost: null`**(含编辑器新注册道具漏字段)。 |
| [libs/enemys.js](../libs/enemys.js) `enemys.prototype._init` | 若怪物 **`timeCost === undefined`**,补 **`timeCost: null`**。 |
### 1.3 使用道具推进地图时间
| 文件 | 行为 |
|------|------|
| [libs/items.js](../libs/items.js) `items.prototype.useItem` | 在 **`_useItemEffect`**(含 eval `useItemEffect`、并入队 `useItemEvent`**之后**立即结算:若 **`typeof timeCost === "number"``> 0`**,且存在 **`core.plugin.mapTurn.consumeTime`**,则 **`consumeTime(_tc, "item:" + itemId)`**(如 **`item:bigKey`** → 3 tick。**例外****`cls`** 为 **`skillbattle`** / **`skillupdate`**,或 **`mapTurnSkillRole`** 为 **`battle`** / **`update`** 时**不**走本条即时扣时(与规范 §3.1 对齐;工程上可用 **`cls:"tools"`** + **`mapTurnSkillRole`** 代替未注册的 skill cls地图时间语义见 §1.4 / [map-turn-spec.md](map-turn-spec.md) §3.1。`null` 或非正数不推进;**与异步开门动画无关**(规范 §4 tools。总开关关则 **`consumeTime`** 内早退。 |
### 1.4 插件:`core.plugin.mapTurn`
| 文件 | 说明 |
|------|------|
| [project/plugins.js](../project/plugins.js) 插件键 **`"mapTurn"`** | 挂载 **`this.mapTurn = { ... }`**,对外即 **`core.plugin.mapTurn.*`**。 |
已实现的 API名称与 [map-turn-spec.md](map-turn-spec.md) §3.4 / §6 对齐):
- **`isEnabled` / `setEnabled(v)`**:总开关读写 **`flags.mapTurnEnabled`**(随存档);为真时 **`consumeTime` / `advanceMapTurnOne`** 才会推进状态。`setEnabled(true)` 或 **`bootstrapPersistedState()`** 在开关为真时会补齐 `mapTurnState` / `skillState` 缺省结构。
- **`consumeTime(deltaTime, reason)`**`clock += floor(delta)`,再循环 **`deltaTime` 次** **`advanceMapTurnOne`**§2.1)。
- **`advanceMapTurnOne(reason)`**`mapTurn += 1`,调用 **`resolveEnemyActionsForSingleTick`**。
- **`resolveEnemyActionsForSingleTick(reason)`**:已按 §6.2 遍历 **`activeEnemiesByFloor[currentFloor]`**,维护 **`enemyActionGauge[floorId][runtimeId]`**,达阈调用 **`performEnemyAction`**;本函数路径内不调用 **`extractBlocks`**。
- **`performEnemyAction(enemyRef, def, floorId, reason)`**:已挂载;**特殊 29【庇护】测试**`hasSpecial(..., 29)` 时本层所有怪 **`enemyOnPoint.hp += 1`**,不经改图块;否则初版 **`actType === idle`** 无操作;`chase`/`patrol`/`skill` 占位(同步改图块会经引擎 `removeBlock` 触发全表扫描,故不在此 tick 内实现)。
- **`rebuildActiveEnemies(floorId)`**:对该层 **`extractBlocks` 一次** 后遍历 **`map.blocks`**,收录 **`cls``enemy` 开头** 且 **`enemys[id].timeCost` 为正数** 的实例(**`runtimeId` / `x` / `y` / `enemyId` / `def`**),写回 **`activeEnemiesByFloor[floorId]`****`activeEnemiesVersion++`**,并修剪 **`enemyActionGauge[floorId]`**。换层由 [project/plugins.js](../project/plugins.js) 对 **`afterChangeFloor`** 的包装调用。
- **`patchActiveEnemiesForBlockChange(floorId, hint)`**`hint.op` 为 **`removeCell`** / **`syncCell`** / **`migratePoint`** / **`rebuild`**(默认全量 **`rebuildActiveEnemies`**)。已在 **`maps.removeBlock` / `setBlock` / `hideBlock` / `showBlock` / `removeBlockByIndexes`** 与 **`events.moveEnemyOnPoint`** 挂钩;**`moveBlock` / `jumpBlock`** 用深度计数抑制中途 **`removeBlock`/`setBlock`** 的重复同步,**`keep===false`** 结束时补 **`removeCell`** 起点格;**`migratePoint`** 在 **`moveEnemyOnPoint`** 后迁移 **`runtimeId``enemyActionGauge`**。
- **战后成功路径**(同文件内 **「序章追击」** 等对 **`events.prototype.afterBattle`** 的包装):先调用原 **`afterBattle`**;若勇士仍存活且存在 **`mapTurn`**,则 **`consumeTime(settleBattleTimeCost(), "battle")`**,再 **`applyStatusAfterBattle("success")`**。
- **`settleBattleTimeCost`**:返回 **`max(1, M)`**§6.4)。**M** = **`activeStatusSkills`** 各条 **`battleTimeCost`** 中的最大值,与 **`activeBattleSkillId`** 对应道具在 **`cls === "skillbattle"`** 或 **`mapTurnSkillRole === "battle"`** 时的 **`timeCost`** 取较大(二者仅取一层 max再与基础 **1** 取 max
- **`syncBattleSkillItemState` / `resyncBattleSkillItemStates`**:战斗技能道具与 **`flag:skill`**、**`activeBattleSkillId`** 对齐(约定 **`skillN`** 型 id**`useItem`** 末尾与读档 **`bootstrapPersistedState`** 内 **`resync`** 调用。**`migrateSkillItemBuckets`**:读档开头将 **`constants`** 或旧 **`skillbattle`/`skillremote`/`skillrecover`/`skillupdate`** 桶中、但 **`material`** 已改为 **`cls:"tools"`** 且带 **`mapTurnSkillRole`** 的条目迁入 **`tools`**;仍保留从 **`constants`** 迁往 **`skill*`** 桶的旧逻辑以兼容旧表。
- **`applyStatusAfterBattle`**§6.5,按 **`remainBattles`** 等扣减 **`activeStatusSkills`****战后成功路径已调用**)。
- **`clearOnDeath`**§6.6 清理 **`skillState`** 等逻辑已实现;**调用侧仍缺**:需在 **`lose` / 战斗失败** 出口调用(当前仓库未接,见 §3
- **道具栏**[libs/ui.js](../libs/ui.js) **`getToolboxItems("tools")`** 与 **`getToolboxPermanentItems`****`constants`** + 四类技能 **`cls`**)分两行;**地图回合技能线若暂用 `cls:"tools"`**,走 **消耗道具行** 显示(与 **`bigKey`** 同区)。
### 1.5 编辑器 / 新素材注册
| 文件 | 说明 |
|------|------|
| [_server/table/comment.js](../_server/table/comment.js) | 道具表、怪物表 **`timeCost`** 列说明;**`items_template`** / **`enemys_template`** 含 **`timeCost: null`**。道具 **`cls`** 可选 **`skillbattle` / `skillremote` / `skillrecover` / `skillupdate`**(与 [map-turn-spec.md](map-turn-spec.md) §3.1 一致)。**工程临时**:未在编辑器注册 skill cls 时,可用 **`cls:"tools"`** + **`mapTurnSkillRole`**`battle`/`remote`/`recover`/`update`+ **`mapTurnKeepAfterUse: true`**(使用后不占消耗、**`addItem` 上限 1**),与 [libs/items.js](../libs/items.js) **`useItem`** / **`_afterUseItem`** 对齐。 |
### 1.6 当前接线口径补充2026-04
- **总开关开启时机**:已在 [project/data.js](../project/data.js) 的 **`startText` 前两条****`setValue`** 写入 **`flag:mapTurnEnabled`** 为真,再 **`bootstrapPersistedState()`** 补齐结构。开关存于存档,读档后随存档恢复。
- **首次触发路径约束**:新开局统一经过 `startText` 写入总开关;读档后由 [project/functions.js](../project/functions.js) **`loadData`** 调用 **`bootstrapPersistedState()`** 与存档中的 **`mapTurnEnabled`** 对齐。
- **演出移动与地图回合**:事件编辑器「地图处理」中在「无视地形移动勇士」下增加图块 **「移动勇者」**JSON `type`: **`moveHeroMapTurn`**)。运行时由 [libs/events.js](../libs/events.js) **`_action_moveHeroMapTurn`** 将路径拆成每格一次 `eventMoveHero`,每格落点后 **`consumeTime(1, "event:moveHeroMapTurn")`**`speed:` 与 `:0` 段不扣时)。语法见 [_server/MotaAction.g4](../_server/MotaAction.g4) `moveHeroMapTurn_s`
- **分层相对回合约定**`mapTurn` 以楼层相对值使用;**普通切层**后当前层回合计数按 `0` 起算。**读档**导致的换层(`__fromLoad__` 为真)不归零,以保持与存档一致。`clock` 可继续作为全局累计观测值。
---
## 2. 待完成(接线清单,对齐 map-turn-spec §4 / §6 / §8
核心调度接线见 **§1**(含 §1.4、§1.6)。下表 **§2** 为大块任务勾选;细项与「仍缺」见 **§2.1**、**§3**。
- [x] **`resolveEnemyActionsForSingleTick`**:已在 [project/plugins.js](../project/plugins.js) **`mapTurn`** 中实现 §2 该条所列 14 步(含 **`performEnemyAction`**`idle` 已实现,其余 `actType` 占位)。
- [x] **`rebuildActiveEnemies`**:已在 **`mapTurn.rebuildActiveEnemies`** 实现 §2 该条 14 步;**`afterChangeFloor`** 中已调用 **`rebuildActiveEnemies(core.status.floorId || floorId)`**。
- [x] **`patchActiveEnemiesForBlockChange`**:已在 **`mapTurn.patchActiveEnemiesForBlockChange`** 实现 **`removeCell` / `syncCell` / `migratePoint` / `rebuild`**[project/plugins.js](../project/plugins.js) 在 **`mapTurn`** 插件末尾对 **`core.maps`** / **`core.events`** 安装挂钩(含 **`moveBlock`/`jumpBlock`** 与 **`keep===false`** 补清)。
### 2.1 后续扩展接线备忘
对应 [map-turn-spec.md](map-turn-spec.md) 中已有字段或流程的操作指向;**已接与仍缺分列如下**。
**已接(当前仓库)**
- **战斗技能(`skillbattle` 或 `mapTurnSkillRole:"battle"`**:样例 **`skill1`**[project/items.js](../project/items.js),当前 **`cls:"tools"`** + **`mapTurnSkillRole:"battle"`** + **`mapTurnKeepAfterUse`****`timeCost: 3`**id **`skill1`** ↔ **`flag:skill === 1`**[libs/items.js](../libs/items.js) **`useItem`** 对 **`battle`/`update` 角色**跳过即时 **`consumeTime`**;战后 **`settleBattleTimeCost`**、**`syncBattleSkillItemState`** / **`resyncBattleSkillItemStates`**、**`migrateSkillItemBuckets`**§1.4**道具栏**走 **`tools`** 行§1.4)。
- **`bigKey`** **`tools`** + **`timeCost: 3`**§1.3 即时 **`consumeTime`**(已验证)。
**仍待扩展**
- **`skillremote` / `skillrecover` / `skillupdate`(规范 cls**:编辑器注册与 **`activeStatusSkills`** 战后路径仍可按规范扩展;**仓库内示例** **`I347`/`I348`/`I350`** 已用 **`tools` + `mapTurnSkillRole`** 实现拾取/使用时轴与道具栏(**`I350`** 仍为 **`mapTestAtkLayers` + tick 衰减**,非 **`activeStatusSkills`**)。
- **`contactBattleOnly` 与多怪捕捉**:在战斗触发逻辑(如 **`beforeBattle`** 或等价入口)读取怪物字段分支;多怪连续战斗时**每场成功**需调用 **`applyStatusAfterBattle("success")`**(普通单场已接,见 §1.4 **战后路径**)。
- **`actType` / `actArgs`**:在 **`performEnemyAction`**(或由 **`resolveEnemyActionsForSingleTick`** 内联)按怪物表字段分支执行移动/技能等行为(**`chase`/`patrol`/`skill`** 等仍占位§1.4)。
---
## 3. 验收清单映射(对应 map-turn-spec §10
| §10 条目 | 依赖 / 当前状态(台账口径) |
|----------|----------------|
| 状态技能不立即推进时间;战后层数 `-1` | **`applyStatusAfterBattle`** 已在单场战后成功路径调用§1.4)。**规范路径仍缺****`cls:"skillupdate"`** 写入 **`activeStatusSkills`**(含 **`remainBattles`** / **`battleTimeCost`**)的配置与开关脚本。**`I350`** 为测试向 **`mapTestAtkLayers` + tick 衰减**,不覆盖 **`activeStatusSkills`** 验收。 |
| 远程/恢复立即推进;怪物按时间响应 | **`useItem`** 对 **`remote`/`recover` 角色**(或规范 **`skillremote`/`skillrecover`**)与普通 **`tools`** 一样按正数 **`timeCost`** **`consumeTime`**§1.3)。示例 **`I347`/`I348`**§2.1)。**敌调度****`resolveEnemyActionsForSingleTick`** + **`activeEnemies`** 已实装§1.4)。 |
| 战斗耗时 **`max`** | **`afterBattle`** 成功路径已 **`consumeTime(settleBattleTimeCost(), "battle")`**§1.4);含 **`skill1`****`battle` 角色**)与 **`activeStatusSkills`**。回归:全场战斗均走该 **`afterBattle`** 包装即可确认。 |
| 多怪捕捉逐场扣层 | **单场** **`afterBattle`** 已链 **`applyStatusAfterBattle`**。**仍缺**:多怪连战的 **`afterBattle`** 触发次数 / 事件链是否每场独立成功分支(见 §2.1)。 |
| Boss **`contactBattleOnly`** | **仍缺**:战斗触发层读取 **`contactBattleOnly`** 与单场结算分支§2.1)。 |
| 死亡清理 | **`clearOnDeath`** 已实现;**仍缺**:在 **`events.lose`** 或等价失败出口调用§1.4)。 |
| 存档读档连续 | **`flags.mapTurnState` / `skillState`** 等随档;读档后 **`bootstrapPersistedState`** + **`afterChangeFloor`** 侧 **`rebuildActiveEnemies`**§1.6)。 |
| **`timeCost=0`** 不参与调度 | **`rebuildActiveEnemies`** 仅收录 **`timeCost > 0`****`resolveEnemyActionsForSingleTick`** 只扫缓存列表§1.4)。 |
| **`consumeTime(3)`** 恰好 3 tick | **`consumeTime`** 内循环 **`advanceMapTurnOne`** 已实现;**建议**:对 **`bigKey`** 或脚本 **`consumeTime(3)`** 做日志/计数断言回归§1.3)。 |
| **`activeEnemies` 路径无每 tick 全图扫描** | **`resolveEnemyActionsForSingleTick`** 不 **`extractBlocks`**;地图变更走 **`patch`/`rebuild`**§1.4)。**例外****庇护 29** 每次行动 **`extractBlocks`** 一次测试专用§1.4)。 |
---
## 4. 相关路径速查
| 用途 | 路径 |
|------|------|
| 规范全文 | [docs/map-turn-spec.md](map-turn-spec.md) |
| 样板 API | [_docs/api.md](../_docs/api.md) |
| 地图回合插件 | [project/plugins.js](../project/plugins.js) 搜索 **`"mapTurn"`** |