This commit is contained in:
salt 2026-05-11 10:17:34 +08:00
parent 728c4af327
commit 32fcdef57b
15 changed files with 445 additions and 152 deletions

File diff suppressed because one or more lines are too long

View File

@ -26,11 +26,15 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"items", "items",
"constants", "constants",
"tools", "tools",
"equips" "equips",
"skillbattle",
"skillremote",
"skillrecover",
"skillupdate"
] ]
}, },
"_docs": "道具类别", "_docs": "道具类别",
"_data": "items(宝石、血瓶) constants(永久物品) tools(消耗道具) equips(装备)" "_data": "items(宝石、血瓶) constants(永久物品) tools(消耗道具) equips(装备)skillbattle/skillremote/skillrecover/skillupdate 为地图回合技能四类 cls见 docs/map-turn-spec.md §3.1"
}, },
"name": { "name": {
"_leaf": true, "_leaf": true,
@ -90,7 +94,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_string": true, "_string": true,
"_lint": true, "_lint": true,
"_docs": "使用效果", "_docs": "使用效果",
"_data": "道具效果,仅对cls为tools或constants有效。" "_data": "道具效果,对 cls 为 tools、constants 或技能四类skillbattle 等)有效。"
}, },
"canUseItemEffect": { "canUseItemEffect": {
"_leaf": true, "_leaf": true,
@ -225,7 +229,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_leaf": true, "_leaf": true,
"_type": "textarea", "_type": "textarea",
"_docs": "特殊属性数值", "_docs": "特殊属性数值",
"_data": "特殊属性的数值\n如领域/阻激/激光怪的伤害值;光环怪增加生命的比例" "_data": "特殊属性的数值(与「特殊属性」勾选配套)"
}, },
"zone": { "zone": {
"_leaf": true, "_leaf": true,
@ -233,35 +237,18 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_docs": "领域伤害", "_docs": "领域伤害",
"_data": "领域怪的伤害值" "_data": "领域怪的伤害值"
}, },
"repulse": { "range": {
"_leaf": true, "_leaf": true,
"_type": "textarea", "_type": "textarea",
"_docs": "阻击伤害", "_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
"_data": "阻击怪的伤害值" "_docs": "领域范围",
"_data": "领域的范围不加默认为1"
}, },
"laser": { "zoneSquare": {
"_leaf": true, "_leaf": true,
"_type": "textarea", "_type": "checkbox",
"_docs": "激光伤害", "_docs": "九宫格",
"_data": "激光怪的伤害值" "_data": "领域怪是否九宫格伤害(与领域范围配合)"
},
"breakArmor": {
"_leaf": true,
"_type": "textarea",
"_docs": "破甲比例",
"_data": "破甲百分比"
},
"counterAttack": {
"_leaf": true,
"_type": "textarea",
"_docs": "反击比例",
"_data": "反击百分比"
},
"vampire": {
"_leaf": true,
"_type": "textarea",
"_docs": "吸血比例",
"_data": "吸血怪的吸血百分比"
}, },
"hpBuff": { "hpBuff": {
"_leaf": true, "_leaf": true,
@ -281,25 +268,6 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_docs": "光环加防", "_docs": "光环加防",
"_data": "光环怪增加防御的比例" "_data": "光环怪增加防御的比例"
}, },
"zoneSquare": {
"_leaf": true,
"_type": "checkbox",
"_docs": "九宫格",
"_data": "领域、阻击或捕捉怪是否九宫格"
},
"haloSquare": {
"_leaf": true,
"_type": "checkbox",
"_docs": "九宫格",
"_data": "光环怪是否九宫格"
},
"range": {
"_leaf": true,
"_type": "textarea",
"_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
"_docs": "领域范围",
"_data": "领域的范围不加默认为1"
},
"haloRange": { "haloRange": {
"_leaf": true, "_leaf": true,
"_type": "textarea", "_type": "textarea",
@ -311,54 +279,14 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_leaf": true, "_leaf": true,
"_type": "checkbox", "_type": "checkbox",
"_docs": "不可炸", "_docs": "不可炸",
"_data": "该怪不可被炸" "_data": "勾选后该怪不可被炸弹消灭"
}, },
"n": { "n": {
"_leaf": true, "_leaf": true,
"_type": "textarea", "_type": "textarea",
"_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null", "_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
"_docs": "连击数", "_docs": "连击数",
"_data": "多连击的连击数,净化怪的净化倍率" "_data": "多连击次数;部分特殊怪作净化倍率等,见文档"
},
"purify": {
"_leaf": true,
"_type": "textarea",
"_range": "(thiseval==~~thiseval && thiseval>0)||thiseval==null",
"_docs": "净化倍率",
"_data": "净化百分比"
},
"add": {
"_leaf": true,
"_type": "checkbox",
"_docs": "吸血加到自身",
"_data": "吸血后是否加到自身"
},
"haloAdd": {
"_leaf": true,
"_type": "checkbox",
"_docs": "光环是否叠加",
"_data": "光环是否叠加"
},
"atkValue": {
"_leaf": true,
"_type": "textarea",
"_range": "thiseval==~~thiseval||thiseval==null",
"_docs": "退化扣攻",
"_data": "退化时勇士下降的攻击力点数"
},
"defValue": {
"_leaf": true,
"_type": "textarea",
"_range": "thiseval==~~thiseval||thiseval==null",
"_docs": "退化扣防",
"_data": "退化时勇士下降的防御力点数"
},
"damage": {
"_leaf": true,
"_type": "textarea",
"_range": "thiseval==~~thiseval||thiseval==null",
"_docs": "固伤",
"_data": "战前扣血的点数"
}, },
"beforeBattle": { "beforeBattle": {
"_leaf": true, "_leaf": true,
@ -373,7 +301,13 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = {
"_event": "afterBattle", "_event": "afterBattle",
"_docs": "战后事件", "_docs": "战后事件",
"_data": "和该怪物战斗后触发的事件列表" "_data": "和该怪物战斗后触发的事件列表"
} },
/*
下列字段不在面板列出可在 project/enemys.js 手写字段名
repulse, laser, breakArmor, counterAttack, vampire, haloSquare,
purify, haloAdd, atkValue, defValue, damage
add吸血加到自身已废弃不在表中出现旧存档若有手写需自行删除键
*/
} }
}, },
"enemys_template": { 'name': '新敌人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'exp': 0, 'point': 0, 'timeCost': null, 'special': [] }, "enemys_template": { 'name': '新敌人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'exp': 0, 'point': 0, 'timeCost': null, 'special': [] },

View File

@ -10,7 +10,7 @@
| 区域 | 说明 | | 区域 | 说明 |
|------|------| |------|------|
| [project/items.js](../project/items.js) | 每条道具在 `"cls"` 下一行含 **`"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`**。 | | [project/enemys.js](../project/enemys.js) | 每条怪物在 **`point``special` 之间**含 **`"timeCost": null`**。 |
| `enemy48` | 与 `enemys` 共用 **`core.material.enemys`** 数值,**无**独立 `libs/enemys48.js` 数据表。 | | `enemy48` | 与 `enemys` 共用 **`core.material.enemys`** 数值,**无**独立 `libs/enemys48.js` 数据表。 |
@ -25,7 +25,7 @@
| 文件 | 行为 | | 文件 | 行为 |
|------|------| |------|------|
| [libs/items.js](../libs/items.js) `items.prototype.useItem` | 在 **`_useItemEffect`** 之后:若 **`typeof timeCost === "number"``> 0`**,且存在 **`core.plugin.mapTurn.consumeTime`**,则调用 **`consumeTime(_tc, "item:" + itemId)`**。`null` 或非正数不推进。 | | [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` ### 1.4 插件:`core.plugin.mapTurn`
@ -39,17 +39,21 @@
- **`consumeTime(deltaTime, reason)`**`clock += floor(delta)`,再循环 **`deltaTime` 次** **`advanceMapTurnOne`**§2.1)。 - **`consumeTime(deltaTime, reason)`**`clock += floor(delta)`,再循环 **`deltaTime` 次** **`advanceMapTurnOne`**§2.1)。
- **`advanceMapTurnOne(reason)`**`mapTurn += 1`,调用 **`resolveEnemyActionsForSingleTick`**。 - **`advanceMapTurnOne(reason)`**`mapTurn += 1`,调用 **`resolveEnemyActionsForSingleTick`**。
- **`resolveEnemyActionsForSingleTick(reason)`**:已按 §6.2 遍历 **`activeEnemiesByFloor[currentFloor]`**,维护 **`enemyActionGauge[floorId][runtimeId]`**,达阈调用 **`performEnemyAction`**;本函数路径内不调用 **`extractBlocks`**。 - **`resolveEnemyActionsForSingleTick(reason)`**:已按 §6.2 遍历 **`activeEnemiesByFloor[currentFloor]`**,维护 **`enemyActionGauge[floorId][runtimeId]`**,达阈调用 **`performEnemyAction`**;本函数路径内不调用 **`extractBlocks`**。
- **`performEnemyAction(enemyRef, def, floorId, reason)`**:已挂载;初版 **`actType === idle`** 无操作;`chase`/`patrol`/`skill` 占位(同步改图块会经引擎 `removeBlock` 触发全表扫描,故不在此 tick 内实现)。 - **`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`** 的包装调用。 - **`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`**。 - **`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`**。
- **`settleBattleTimeCost`**:已实现 **`max(1, 状态技能 battleTimeCost 最大值)`**§6.4)。 - **战后成功路径**(同文件内 **「序章追击」** 等对 **`events.prototype.afterBattle`** 的包装):先调用原 **`afterBattle`**;若勇士仍存活且存在 **`mapTurn`**,则 **`consumeTime(settleBattleTimeCost(), "battle")`**,再 **`applyStatusAfterBattle("success")`**。
- **`applyStatusAfterBattle` / `clearOnDeath`**:已按规范 §6.56.6 操作 **`flags.skillState`**(经 **`core.getFlag` / `core.setFlag`** 维护的 **`mapTurnState` / `skillState`** 结构)。 - **`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 编辑器 / 新素材注册 ### 1.5 编辑器 / 新素材注册
| 文件 | 说明 | | 文件 | 说明 |
|------|------| |------|------|
| [_server/table/comment.js](../_server/table/comment.js) | 道具表、怪物表增加 **`timeCost`** 列说明;**`items_template`** / **`enemys_template`** 含 **`timeCost: null`**,新建行时带该字段。 | | [_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 ### 1.6 当前接线口径补充2026-04
@ -62,7 +66,7 @@
## 2. 待完成(接线清单,对齐 map-turn-spec §4 / §6 / §8 ## 2. 待完成(接线清单,对齐 map-turn-spec §4 / §6 / §8
已完成接线见 **§1**(含 §1.4、§1.6)。以下为尚未实现的步骤说明;完成后在 §3 验收表对应行打勾 核心调度接线见 **§1**(含 §1.4、§1.6)。下表 **§2** 为大块任务勾选;细项与「仍缺」见 **§2.1**、**§3**
- [x] **`resolveEnemyActionsForSingleTick`**:已在 [project/plugins.js](../project/plugins.js) **`mapTurn`** 中实现 §2 该条所列 14 步(含 **`performEnemyAction`**`idle` 已实现,其余 `actType` 占位)。 - [x] **`resolveEnemyActionsForSingleTick`**:已在 [project/plugins.js](../project/plugins.js) **`mapTurn`** 中实现 §2 该条所列 14 步(含 **`performEnemyAction`**`idle` 已实现,其余 `actType` 占位)。
@ -72,28 +76,35 @@
### 2.1 后续扩展接线备忘 ### 2.1 后续扩展接线备忘
对应 [map-turn-spec.md](map-turn-spec.md) 中已有字段或流程、尚未在工程中专项接线时的操作指向: 对应 [map-turn-spec.md](map-turn-spec.md) 中已有字段或流程的操作指向;**已接与仍缺分列如下**。
- **四类技能与 `items`**:在 [project/items.js](../project/items.js) 为道具补 **`skillType` / `timeCost` 等**后,在道具使用效果与 **`flags.skillState`** 写入处接线;状态技能保持 **`timeCost === 0`** 且不调用 **`consumeTime`**;战斗耗时仍走 **`settleBattleTimeCost`** 与战后 **`applyStatusAfterBattle`** 调用链。 **已接(当前仓库)**
- **`contactBattleOnly` 与多怪捕捉**:在战斗触发逻辑(如 **`beforeBattle`** 或等价入口)读取怪物字段分支;多怪连续战斗时每场成功后调用 **`applyStatusAfterBattle("success")`**。
- **`actType` / `actArgs`**:在 **`performEnemyAction`**(或由 **`resolveEnemyActionsForSingleTick`** 内联)按怪物表字段分支执行移动/技能等行为。 - **战斗技能(`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 ## 3. 验收清单映射(对应 map-turn-spec §10
| §10 条目 | 依赖的待办小节 | | §10 条目 | 依赖 / 当前状态(台账口径) |
|----------|----------------| |----------|----------------|
| 状态技能不立即推进时间;战后层数 `-1` | 战斗胜利接线 + **`skillState`** 数据与 **`applyStatusAfterBattle`** 调用时机 | | 状态技能不立即推进时间;战后层数 `-1` | **`applyStatusAfterBattle`** 已在单场战后成功路径调用§1.4)。**规范路径仍缺****`cls:"skillupdate"`** 写入 **`activeStatusSkills`**(含 **`remainBattles`** / **`battleTimeCost`**)的配置与开关脚本。**`I350`** 为测试向 **`mapTestAtkLayers` + tick 衰减**,不覆盖 **`activeStatusSkills`** 验收。 |
| 远程/恢复立即推进;怪物按时间响应 | 道具 **`timeCost`**(已有 `useItem` 钩子)+ **`resolveEnemyActions` / `activeEnemies`** 实装 | | 远程/恢复立即推进;怪物按时间响应 | **`useItem`** 对 **`remote`/`recover` 角色**(或规范 **`skillremote`/`skillrecover`**)与普通 **`tools`** 一样按正数 **`timeCost`** **`consumeTime`**§1.3)。示例 **`I347`/`I348`**§2.1)。**敌调度****`resolveEnemyActionsForSingleTick`** + **`activeEnemies`** 已实装§1.4)。 |
| 战斗耗时 **`max`** | **`settleBattleTimeCost`** 已在插件中;需战斗路径实际调用 | | 战斗耗时 **`max`** | **`afterBattle`** 成功路径已 **`consumeTime(settleBattleTimeCost(), "battle")`**§1.4);含 **`skill1`****`battle` 角色**)与 **`activeStatusSkills`**。回归:全场战斗均走该 **`afterBattle`** 包装即可确认。 |
| 多怪捕捉逐场扣层 | **`afterBattle`** 多场链路与每场成功分支 | | 多怪捕捉逐场扣层 | **单场** **`afterBattle`** 已链 **`applyStatusAfterBattle`**。**仍缺**:多怪连战的 **`afterBattle`** 触发次数 / 事件链是否每场独立成功分支(见 §2.1)。 |
| Boss **`contactBattleOnly`** | 战斗触发层逻辑 + 怪物字段 | | Boss **`contactBattleOnly`** | **仍缺**:战斗触发层读取 **`contactBattleOnly`** 与单场结算分支§2.1)。 |
| 死亡清理 | **`clearOnDeath`** 接入 **`lose` / 失败** | | 死亡清理 | **`clearOnDeath`** 已实现;**仍缺**:在 **`events.lose`** 或等价失败出口调用§1.4)。 |
| 存档读档连续 | **`flags`** 持久化已有方向;读档后 **`rebuildActiveEnemies`** | | 存档读档连续 | **`flags.mapTurnState` / `skillState`** 等随档;读档后 **`bootstrapPersistedState`** + **`afterChangeFloor`** 侧 **`rebuildActiveEnemies`**§1.6)。 |
| **`timeCost=0`** 不参与调度 | **`rebuildActiveEnemies`** 过滤 + **`resolveEnemyActions`** 只扫缓存 | | **`timeCost=0`** 不参与调度 | **`rebuildActiveEnemies`** 仅收录 **`timeCost > 0`****`resolveEnemyActionsForSingleTick`** 只扫缓存列表§1.4)。 |
| **`consumeTime(3)`** 恰好 3 tick | **`consumeTime`** 已实现循环;需集成测试断言 | | **`consumeTime(3)`** 恰好 3 tick | **`consumeTime`** 内循环 **`advanceMapTurnOne`** 已实现;**建议**:对 **`bigKey`** 或脚本 **`consumeTime(3)`** 做日志/计数断言回归§1.3)。 |
| **`activeEnemies` 路径无每 tick 全图扫描** | **`rebuild` / `patch`** 实装 | | **`activeEnemies` 路径无每 tick 全图扫描** | **`resolveEnemyActionsForSingleTick`** 不 **`extractBlocks`**;地图变更走 **`patch`/`rebuild`**§1.4)。**例外****庇护 29** 每次行动 **`extractBlocks`** 一次测试专用§1.4)。 |
--- ---

View File

@ -45,18 +45,29 @@
### 3.1 技能定义items 扩展) ### 3.1 技能定义items 扩展)
技能品类通过 **`cls`** 区分(写入 `project/items.js`,无需另行注册「技能类型枚举」):
| `cls` | 含义 | `timeCost` 与地图回合 |
|-------|------|----------------------|
| **`skillbattle`** | 战斗技能(开关型) | 使用瞬间 **不** `consumeTime`;数值参与战后 **`settleBattleTimeCost`** 与基础耗时的 **max** |
| **`skillremote`** | 远程技能 | 使用后立即按 **`timeCost`** `consumeTime`(规范 §4 |
| **`skillrecover`** | 恢复技能 | 同上 |
| **`skillupdate`** | 状态技能 | **`timeCost` 固定为 `0`**;开关 **不** `consumeTime`;持续层数等走 **`skillState`** |
```js ```js
// project/items.js 每个可用技能道具tools类建议字段 // project/items.js 示例字段(按需)
{ {
skillType: "battle" | "status" | "recover" | "ranged", cls: "skillbattle" | "skillremote" | "skillrecover" | "skillupdate",
timeCost: number, // 统一时间消耗状态技能固定为0 timeCost: number, // 战斗/远程/恢复语义见上表;状态技能为 0
canCancel: boolean, // 可否取消主要用于status canCancel: boolean, // 可否取消(主要用于 skillupdate
exclusiveGroup: string | null, // 战斗技能互斥组,例如 "battleSkill" exclusiveGroup: string | null, // 战斗技能互斥组,例如 "battleSkill"
durationBattles: number | null,// 状态技能持续战斗次数null表示非按战斗计数 durationBattles: number | null,// 状态技能持续战斗次数null表示非按战斗计数
stackPolicy: "refresh" | "stack" | "replace" // 后续扩展 stackPolicy: "refresh" | "stack" | "replace" // 后续扩展
} }
``` ```
与运行时 **`flag:skill`** 对齐时:约定道具 **`id`** 为 **`skill` + 编号**(如 `skill1``flag:skill === 1`),地图回合侧据此同步 **`activeBattleSkillId`**。
### 3.2 怪物定义enemys/enemy48 扩展) ### 3.2 怪物定义enemys/enemy48 扩展)
```js ```js
@ -122,9 +133,10 @@ flags.skillState = {
- 轻按拾取(不移动):推进,默认 `+1` - 轻按拾取(不移动):推进,默认 `+1`
- 使用 tools 类道具(如 bigKey按道具 `timeCost` 推进。 - 使用 tools 类道具(如 bigKey按道具 `timeCost` 推进。
- 单场战斗:推进,按 `battleFinalTimeCost` - 单场战斗:推进,按 `battleFinalTimeCost`
- 远程技能(不可撤回):立即按技能 `timeCost` 推进。 - 远程技能:立即按 `timeCost` 推进;工程上对应道具 **`cls: "skillremote"`**(见 §3.1)。
- 恢复技能:视同远程技能,立即按 `timeCost` 推进。 - 恢复技能:视同远程;对应 **`cls: "skillrecover"`**。
- 状态技能:`timeCost=0`,不推进地图时间。 - 状态技能:`timeCost=0`,不推进;对应 **`cls: "skillupdate"`**。
- 战斗技能(开关型):使用瞬间不推进;战后按 **`settleBattleTimeCost`** 与基础耗时取 max对应 **`cls: "skillbattle"`**。
- 纯 UI 操作(菜单、手册、预览模拟):不推进。 - 纯 UI 操作(菜单、手册、预览模拟):不推进。
**说明**:矩阵中的「推进 `+n`」均指调用 `consumeTime(n, ...)`;引擎内部必须把 `n` 拆成 `n``advanceMapTurnOne`§2.1)。 **说明**:矩阵中的「推进 `+n`」均指调用 `consumeTime(n, ...)`;引擎内部必须把 `n` 拆成 `n``advanceMapTurnOne`§2.1)。

View File

@ -1516,7 +1516,7 @@ actions.prototype._keyUpQuickShop = function (keycode) {
////// 工具栏界面时的点击操作 ////// ////// 工具栏界面时的点击操作 //////
actions.prototype._clickToolbox = function (x, y) { actions.prototype._clickToolbox = function (x, y) {
var tools = core.getToolboxItems('tools'), var tools = core.getToolboxItems('tools'),
constants = core.getToolboxItems('constants'); constants = core.ui.getToolboxPermanentItems();
// 装备栏 // 装备栏
if (x >= this.LAST - 2 && y == 0) { if (x >= this.LAST - 2 && y == 0) {
@ -1580,7 +1580,7 @@ actions.prototype._clickToolbox = function (x, y) {
////// 选择工具栏界面中某个Index后的操作 ////// ////// 选择工具栏界面中某个Index后的操作 //////
actions.prototype._clickToolboxIndex = function (index) { actions.prototype._clickToolboxIndex = function (index) {
var tools = core.getToolboxItems('tools'), var tools = core.getToolboxItems('tools'),
constants = core.getToolboxItems('constants'); constants = core.ui.getToolboxPermanentItems();
var items = null; var items = null;
var select; var select;
@ -1612,7 +1612,7 @@ actions.prototype._keyDownToolbox = function (keycode) {
var last_index = this.LAST - 1; var last_index = this.LAST - 1;
var tools = core.getToolboxItems('tools'), var tools = core.getToolboxItems('tools'),
constants = core.getToolboxItems('constants'); constants = core.ui.getToolboxPermanentItems();
var index = core.status.event.selection; var index = core.status.event.selection;
var toolsPage = core.status.event.data.toolsPage; var toolsPage = core.status.event.data.toolsPage;
var constantsPage = core.status.event.data.constantsPage; var constantsPage = core.status.event.data.constantsPage;

View File

@ -1732,7 +1732,7 @@ control.prototype._replayAction_item = function (action) {
return true; return true;
} }
var tools = core.getToolboxItems('tools'), var tools = core.getToolboxItems('tools'),
constants = core.getToolboxItems('constants'); constants = core.ui.getToolboxPermanentItems();
var index, per = core._WIDTH_ - 1; var index, per = core._WIDTH_ - 1;
if ((index = tools.indexOf(itemId)) >= 0) { if ((index = tools.indexOf(itemId)) >= 0) {
core.status.event.data = { "toolsPage": Math.floor(index / per) + 1, "constantsPage": 1 }; core.status.event.data = { "toolsPage": Math.floor(index / per) + 1, "constantsPage": 1 };

View File

@ -89,12 +89,17 @@ items.prototype.useItem = function (itemId, noRoute, callback) {
} }
// 执行道具效果 // 执行道具效果
this._useItemEffect(itemId); this._useItemEffect(itemId);
// 地图回合:按 project/items.js 中 timeCostnull 不推进);见 docs/map-turn-spec.md // 地图回合:见 docs/map-turn-spec.md §3.1 / §4。skillbattle、skillupdate 使用瞬间不 consumeTimeskillbattle 的 timeCost 战后 settleBattleTimeCost 取 max。
try { try {
var _item = core.material.items[itemId]; var _item = core.material.items[itemId];
var _tc = _item && _item.timeCost; var _tc = _item && _item.timeCost;
if (typeof _tc === "number" && _tc > 0 && core.plugin && core.plugin.mapTurn && typeof core.plugin.mapTurn.consumeTime === "function") var _cls = _item && _item.cls;
var _role = _item && _item.mapTurnSkillRole;
var _skipTick = _cls === "skillbattle" || _cls === "skillupdate" || _role === "battle" || _role === "update";
if (!_skipTick && typeof _tc === "number" && _tc > 0 && core.plugin && core.plugin.mapTurn && typeof core.plugin.mapTurn.consumeTime === "function")
core.plugin.mapTurn.consumeTime(_tc, "item:" + itemId); core.plugin.mapTurn.consumeTime(_tc, "item:" + itemId);
if ((_cls === "skillbattle" || _role === "battle") && core.plugin && core.plugin.mapTurn && typeof core.plugin.mapTurn.syncBattleSkillItemState === "function")
core.plugin.mapTurn.syncBattleSkillItemState(itemId);
} catch (e) { } } catch (e) { }
// 执行完毕 // 执行完毕
this._afterUseItem(itemId); this._afterUseItem(itemId);
@ -125,9 +130,10 @@ items.prototype._useItemEffect = function (itemId) {
} }
items.prototype._afterUseItem = function (itemId) { items.prototype._afterUseItem = function (itemId) {
// 道具使用完毕:删除 // 道具使用完毕:删除mapTurnKeepAfterUse地图回合测试用技能占 tools 栏但不扣数量)
var itemCls = core.material.items[itemId].cls; var itemCls = core.material.items[itemId].cls;
if (itemCls == 'tools') var _keep = (core.material.items[itemId] || {}).mapTurnKeepAfterUse;
if (itemCls == 'tools' && !_keep)
core.status.hero.items[itemCls][itemId]--; core.status.hero.items[itemCls][itemId]--;
if (core.status.hero.items[itemCls][itemId] <= 0) if (core.status.hero.items[itemCls][itemId] <= 0)
delete core.status.hero.items[itemCls][itemId]; delete core.status.hero.items[itemCls][itemId];
@ -205,8 +211,8 @@ items.prototype.addItem = function (itemId, itemNum) {
if (core.status.hero.items[itemCls][itemId] <= 0) { if (core.status.hero.items[itemCls][itemId] <= 0) {
delete core.status.hero.items[itemCls][itemId]; delete core.status.hero.items[itemCls][itemId];
} }
// 永久道具只能有一个 // 永久道具只能有一个(含技能 cls地图回合测试用 tools+mapTurnKeepAfterUse 同上限 1
if (itemCls == 'constants' && core.status.hero.items[itemCls][itemId] > 1) if ((itemCls == 'constants' || itemCls == 'skillbattle' || itemCls == 'skillremote' || itemCls == 'skillrecover' || itemCls == 'skillupdate' || (itemCls == 'tools' && itemData.mapTurnKeepAfterUse)) && core.status.hero.items[itemCls][itemId] > 1)
core.status.hero.items[itemCls][itemId] = 1; core.status.hero.items[itemCls][itemId] = 1;
core.updateStatusBar(); core.updateStatusBar();
} }

View File

@ -2701,13 +2701,25 @@ ui.prototype.getToolboxItems = function (cls) {
.sort(); .sort();
} }
////// 永久道具栏constants + 技能四类 cls与 docs/map-turn-spec.md §3.1 一致) //////
ui.prototype.getToolboxPermanentItems = function () {
var keys = ["constants", "skillbattle", "skillremote", "skillrecover", "skillupdate"];
var out = [];
for (var i = 0; i < keys.length; i++) {
var sub = this.getToolboxItems(keys[i]);
if (sub && sub.length) out = out.concat(sub);
}
out.sort();
return out;
};
ui.prototype._drawToolbox_getInfo = function (index) { ui.prototype._drawToolbox_getInfo = function (index) {
// 设定eventdata // 设定eventdata
if (!core.status.event.data || core.status.event.data.toolsPage == null) if (!core.status.event.data || core.status.event.data.toolsPage == null)
core.status.event.data = { "toolsPage": 1, "constantsPage": 1, "selectId": null } core.status.event.data = { "toolsPage": 1, "constantsPage": 1, "selectId": null }
// 获取物品列表 // 获取物品列表
var tools = core.getToolboxItems('tools'), var tools = core.getToolboxItems('tools'),
constants = core.getToolboxItems('constants'); constants = core.ui.getToolboxPermanentItems();
// 处理页数 // 处理页数
var n = core._WIDTH_ - 1; var n = core._WIDTH_ - 1;
var toolsPage = core.status.event.data.toolsPage; var toolsPage = core.status.event.data.toolsPage;

View File

@ -7,7 +7,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
"bat": {"name":"小蝙蝠","hp":30,"atk":12,"def":3,"money":2,"exp":0,"point":0,"timeCost":null,"special":[4]}, "bat": {"name":"小蝙蝠","hp":30,"atk":12,"def":3,"money":2,"exp":0,"point":0,"timeCost":null,"special":[4]},
"bigBat": {"name":"大蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "bigBat": {"name":"大蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"redBat": {"name":"红蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":[]}, "redBat": {"name":"红蝙蝠","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":[]},
"vampire": {"name":"冥灵魔王","hp":888,"atk":888,"def":888,"money":888,"exp":888,"point":0,"timeCost":null,"special":[],"n":8}, "vampire": {"name":"冥灵魔王","hp":888,"atk":888,"def":888,"money":888,"exp":888,"point":0,"timeCost":1,"special":[29],"n":null},
"skeleton": {"name":"骷髅人","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "skeleton": {"name":"骷髅人","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"skeletonCaptain": {"name":"骷髅队长","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "skeletonCaptain": {"name":"骷髅队长","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"zombie": {"name":"兽人","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "zombie": {"name":"兽人","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
@ -49,7 +49,7 @@ var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
"yellowGateKeeper": {"name":"初级卫兵","hp":100,"atk":120,"def":0,"money":10,"exp":0,"point":0,"timeCost":null,"special":0}, "yellowGateKeeper": {"name":"初级卫兵","hp":100,"atk":120,"def":0,"money":10,"exp":0,"point":0,"timeCost":null,"special":0},
"blueGateKeeper": {"name":"中级卫兵","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "blueGateKeeper": {"name":"中级卫兵","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"redGateKeeper": {"name":"高级卫兵","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "redGateKeeper": {"name":"高级卫兵","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"magicMaster": {"name":"黑暗大法师","hp":100,"atk":120,"def":0,"money":12,"exp":0,"point":0,"timeCost":null,"special":11,"value":0.3333333333333333,"add":true,"notBomb":true}, "magicMaster": {"name":"黑暗大法师","hp":100,"atk":120,"def":0,"money":12,"exp":0,"point":0,"timeCost":null,"special":11,"value":0.3333333333333333,"notBomb":true},
"devilWarrior": {"name":"魔神武士","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "devilWarrior": {"name":"魔神武士","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"fairyEnemy": {"name":"仙子","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0}, "fairyEnemy": {"name":"仙子","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0},
"dragon": {"name":"魔龙","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0,"bigImage":"dragon_0.png"}, "dragon": {"name":"魔龙","hp":0,"atk":0,"def":0,"money":0,"exp":0,"point":0,"timeCost":null,"special":0,"bigImage":"dragon_0.png"},

View File

@ -49,15 +49,15 @@ main.floors.C0_B03=
[ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], [ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
[ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], [ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
[ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17], [ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17],
[20164, 0, 32, 0,20164, 22, 0,201, 17, 17, 17, 17, 17, 17, 17], [20164, 0, 32,350,20164, 22, 0,201, 17, 17, 17, 17, 17, 17, 17],
[20164, 27, 0,205, 0, 0,20164, 0, 31, 0,201, 0, 0, 17, 17], [20164, 27,348,205,347, 0,20164, 0, 31, 0,201,208, 0, 17, 17],
[20164,20164,20164,20164,20145,20164,20164, 0,20164,20164, 0,20164, 30, 17, 17], [20164,20164,20164,20164,20145,20164,20164, 0,20164,20164, 0,20164, 30, 17, 17],
[ 92, 83,203, 0,20164, 0, 0,202, 0, 0,201,20164, 0, 17, 17], [ 92, 83,203, 0,20164, 0, 0,202, 0, 0,201,20164, 0, 17, 17],
[20164,20164,20164,205,20164,201,20164,20157, 0,20164, 0, 0,201, 22,20164], [20164,20164,20164,205,20164,201,20164,20157, 0,20164, 0, 0,201, 22,20164],
[20164, 0,202, 0,20164, 0, 21,20164, 0, 17, 0, 17, 17, 31,20164], [20164, 0,202, 0,20164, 0, 21,20164, 0, 17, 0, 17, 17, 31,20164],
[20164,201,20164,20164,20164, 32, 0, 0,203, 17, 0, 17, 17, 0,20164], [20164,201,20164,20164,20164, 32, 0, 0,203, 17, 0, 17, 17, 0,20164],
[20164, 0, 82, 81, 0, 0,20164,20164, 0, 31, 0,205, 0, 82, 94], [20164, 0, 82, 81, 0, 0,20164,20164, 0, 31, 0,205, 0, 82, 94],
[20172,20164,20164, 0,202,20164, 21, 0, 0, 0,201,20164,20164, 0,20164], [20172,20164,20164, 26,202,20164, 21, 0, 0, 0,201,20164,20164, 0,20164],
[20164, 31, 0, 28, 0,20164, 0, 29, 0,20164, 0, 0, 0, 81,20164], [20164, 31, 0, 28, 0,20164, 0, 29, 0,20164, 0, 0, 0, 81,20164],
[20164,20164,20164,20164,20164,20164, 17, 17, 17,20164, 93,20164,20164,20164,20164] [20164,20164,20164,20164,20164,20164, 17, 17, 17,20164, 93,20164,20164,20164,20164]
], ],

View File

@ -518,7 +518,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
[25, "光环", function (enemy) { return (enemy.range != null ? ((enemy.haloSquare ? "该怪物九宫格" : "该怪物十字") + enemy.haloRange + "格范围内") : "同楼层所有") + "怪物生命提升" + (enemy.hpBuff || 0) + "%,攻击提升" + (enemy.atkBuff || 0) + "%,防御提升" + (enemy.defBuff || 0) + "%" + (enemy.haloAdd ? "可叠加" : "不可叠加"); }, "#e6e099", 1], [25, "光环", function (enemy) { return (enemy.range != null ? ((enemy.haloSquare ? "该怪物九宫格" : "该怪物十字") + enemy.haloRange + "格范围内") : "同楼层所有") + "怪物生命提升" + (enemy.hpBuff || 0) + "%,攻击提升" + (enemy.atkBuff || 0) + "%,防御提升" + (enemy.defBuff || 0) + "%" + (enemy.haloAdd ? "可叠加" : "不可叠加"); }, "#e6e099", 1],
[26, "支援", "当周围一圈的怪物受到攻击时将上前支援,并组成小队战斗。", "#77c0b6", 1], [26, "支援", "当周围一圈的怪物受到攻击时将上前支援,并组成小队战斗。", "#77c0b6", 1],
[27, "捕捉", function (enemy) { return "当走到怪物周围" + (enemy.zoneSquare ? "九宫格" : "十字") + "时会强制进行战斗。"; }, "#c0ddbb"], [27, "捕捉", function (enemy) { return "当走到怪物周围" + (enemy.zoneSquare ? "九宫格" : "十字") + "时会强制进行战斗。"; }, "#c0ddbb"],
[28, "追击", "追击", "#cc8866"] [28, "追击", "追击", "#cc8866"],
// 29 庇护:测试用;正式版地图回合类技能序号从 101 起
[29, "庇护", "(测试)地图回合每推进一次,本层所有怪物最大生命+1数值写入存档换层不重置。", "#99ccee", 0]
]; ];
}, },
"getEnemyInfo": function (enemy, hero, x, y, floorId) { "getEnemyInfo": function (enemy, hero, x, y, floorId) {
@ -1588,7 +1590,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
"ui": { "ui": {
"getToolboxItems": function (cls) { "getToolboxItems": function (cls) {
// 获得道具栏中当前某类型道具的显示项和显示顺序 // 获得道具栏中当前某类型道具的显示项和显示顺序
// cls为道具类型,只可能是 tools, constants 和 equips // cls 为 tools、constants、equips 或技能四类skillbattle 等),见 map-turn-spec §3.1
// 返回一个数组,代表当前某类型道具的显示内容和顺序 // 返回一个数组,代表当前某类型道具的显示内容和顺序
// 默认按id升序排列您可以取消下面的注释改为按名称排列 // 默认按id升序排列您可以取消下面的注释改为按名称排列

View File

@ -273,7 +273,18 @@ var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 =
"jumpShoes": 49, "jumpShoes": 49,
"skill1": 30, "skill1": 30,
"wand": 10, "wand": 10,
"pack": 46 "pack": 46,
"I344": 5,
"I345": 7,
"I346": 26,
"I347": 31,
"I348": 32,
"I349": 34,
"I350": 35,
"I351": 36,
"I352": 37,
"I353": 38,
"I354": 39
}, },
"autotile": { "autotile": {
"autotile": 0, "autotile": 0,

View File

@ -505,7 +505,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
}, },
"centerFly": { "centerFly": {
"cls": "tools", "cls": "tools",
"timeCost": null, "timeCost": 3,
"name": "中心对称飞行器", "name": "中心对称飞行器",
"text": "可以飞向当前楼层中心对称的位置", "text": "可以飞向当前楼层中心对称的位置",
"useItemEffect": "core.playSound('centerFly.mp3');\ncore.clearMap('hero');\ncore.setHeroLoc('x', core.bigmap.width - 1 - core.getHeroLoc('x'));\ncore.setHeroLoc('y', core.bigmap.height - 1 - core.getHeroLoc('y'));\ncore.drawHero();\ncore.drawTip(core.material.items[itemId].name + '使用成功');", "useItemEffect": "core.playSound('centerFly.mp3');\ncore.clearMap('hero');\ncore.setHeroLoc('x', core.bigmap.width - 1 - core.getHeroLoc('x'));\ncore.setHeroLoc('y', core.bigmap.height - 1 - core.getHeroLoc('y'));\ncore.drawHero();\ncore.drawTip(core.material.items[itemId].name + '使用成功');",
@ -641,10 +641,12 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"canUseItemEffect": "(function () {\n\tvar nx = core.nextX(2),\n\t\tny = core.nextY(2);\n\treturn nx >= 0 && nx < core.bigmap.width && ny >= 0 && ny < core.bigmap.height && core.getBlockId(nx, ny) == null;\n})();" "canUseItemEffect": "(function () {\n\tvar nx = core.nextX(2),\n\t\tny = core.nextY(2);\n\treturn nx >= 0 && nx < core.bigmap.width && ny >= 0 && ny < core.bigmap.height && core.getBlockId(nx, ny) == null;\n})();"
}, },
"skill1": { "skill1": {
"cls": "constants", "cls": "tools",
"mapTurnSkillRole": "battle",
"mapTurnKeepAfterUse": true,
"timeCost": 3, "timeCost": 3,
"name": "技能:二倍斩", "name": "技能:二倍斩",
"text": "可以打开或关闭主动技能二倍斩", "text": "可以打开或关闭主动技能二倍斩(暂用 tools 栏位:拾取/轻拾与消耗道具同地图时轴;使用后不占消耗)。",
"hideInReplay": true, "hideInReplay": true,
"useItemEffect": "(function () {\n\tvar skillValue = 1; // 技能的flag:skill值可用于当前开启技能的判定对于新技能可以依次改成23等等\n\tvar skillNeed = 5; // 技能的需求\n\tvar skillName = '二倍斩'; // 技能的名称\n\n\tif (core.getFlag('skill', 0) != skillValue) { // 判断当前是否已经开了技能\n\t\tif (core.getStatus('mana') >= skillNeed) { // 这里要写当前能否开技能的条件判断,比如魔力值至少要多少\n\t\t\tcore.playSound('打开界面');\n\t\t\tcore.setFlag('skill', skillValue); // 开技能1\n\t\t\tcore.setFlag('skillName', skillName); // 设置技能名\n\t\t} else {\n\t\t\tcore.playSound('操作失败');\n\t\t\tcore.drawTip('魔力不足,无法开启技能');\n\t\t}\n\t} else { // 关闭技能\n\t\tcore.setFlag('skill', 0); // 关闭技能状态\n\t\tcore.setFlag('skillName', '无');\n\t}\n})();", "useItemEffect": "(function () {\n\tvar skillValue = 1; // 技能的flag:skill值可用于当前开启技能的判定对于新技能可以依次改成23等等\n\tvar skillNeed = 5; // 技能的需求\n\tvar skillName = '二倍斩'; // 技能的名称\n\n\tif (core.getFlag('skill', 0) != skillValue) { // 判断当前是否已经开了技能\n\t\tif (core.getStatus('mana') >= skillNeed) { // 这里要写当前能否开技能的条件判断,比如魔力值至少要多少\n\t\t\tcore.playSound('打开界面');\n\t\t\tcore.setFlag('skill', skillValue); // 开技能1\n\t\t\tcore.setFlag('skillName', skillName); // 设置技能名\n\t\t} else {\n\t\t\tcore.playSound('操作失败');\n\t\t\tcore.drawTip('魔力不足,无法开启技能');\n\t\t}\n\t} else { // 关闭技能\n\t\tcore.setFlag('skill', 0); // 关闭技能状态\n\t\tcore.setFlag('skillName', '无');\n\t}\n})();",
"canUseItemEffect": "true" "canUseItemEffect": "true"
@ -660,5 +662,88 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"name": "钱袋", "name": "钱袋",
"itemEffect": "core.status.hero.money += 500", "itemEffect": "core.status.hero.money += 500",
"itemEffectTip": ",金币+500" "itemEffectTip": ",金币+500"
},
"I344": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I345": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I346": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I347": {
"cls": "tools",
"mapTurnSkillRole": "recover",
"mapTurnKeepAfterUse": true,
"timeCost": 2,
"name": "恢复技能1",
"text": "恢复100点生命不超过上限使用后推进2个地图回合。暂用 tools 栏位,拾取与消耗道具同地图时轴。",
"hideInReplay": true,
"useItemEffect": "(function () {\n\tvar hpmax = core.getRealStatus(\"hpmax\");\n\tvar h = core.status.hero.hp + 100;\n\tif (h > hpmax) h = hpmax;\n\tcore.status.hero.hp = h;\n\tcore.playSound(\"回血\");\n\tcore.updateStatusBar(false, true);\n\tcore.drawTip(\"恢复生命至\" + h + \"/\" + hpmax);\n})();",
"canUseItemEffect": "true"
},
"I348": {
"cls": "tools",
"mapTurnSkillRole": "remote",
"mapTurnKeepAfterUse": true,
"timeCost": 1,
"name": "远程技能1",
"text": "对主角朝向正前方射线上的第一个敌人造成当前攻击100%伤害非战斗击杀使用后推进1个地图回合。暂用 tools 栏位,拾取与消耗道具同地图时轴。",
"hideInReplay": true,
"useItemEffect": "(function () {\n\tvar floorId = core.status.floorId;\n\tvar d = core.getHeroLoc(\"direction\");\n\tvar sc = core.utils.scan[d];\n\tif (!sc) {\n\t\tcore.drawTip(\"朝向无效\");\n\t\treturn;\n\t}\n\tvar hx = core.getHeroLoc(\"x\"),\n\t\thy = core.getHeroLoc(\"y\");\n\tvar atk = Math.max(0, Math.floor(core.getRealStatus(\"atk\")));\n\tif (atk <= 0) {\n\t\tcore.drawTip(\"攻击为0\");\n\t\treturn;\n\t}\n\tvar hit = false;\n\tfor (var n = 1; n < 500; n++) {\n\t\tvar x = hx + sc.x * n,\n\t\t\ty = hy + sc.y * n;\n\t\tif (x < 0 || y < 0 || x >= core.bigmap.width || y >= core.bigmap.height) break;\n\t\tvar block = core.getBlock(x, y, floorId);\n\t\tif (!block || block.disable) continue;\n\t\tvar ev = block.event;\n\t\tif (ev && ev.cls && String(ev.cls).indexOf(\"enemy\") === 0) {\n\t\t\tvar curHp = core.enemys.getEnemyValue(ev.id, \"hp\", x, y, floorId);\n\t\t\tif (typeof curHp !== \"number\") curHp = (core.material.enemys[ev.id] || {}).hp || 0;\n\t\t\tif (curHp <= atk) {\n\t\t\t\tcore.removeBlock(x, y, floorId);\n\t\t\t\tcore.drawTip(\"远程击杀\");\n\t\t\t} else {\n\t\t\t\tcore.events.setEnemyOnPoint(x, y, floorId, \"hp\", atk, \"-=\", undefined, false);\n\t\t\t\tcore.drawTip(\"远程伤害\" + atk);\n\t\t\t}\n\t\t\tcore.playSound(\"爆炸\");\n\t\t\thit = true;\n\t\t\tbreak;\n\t\t}\n\t\tif (ev && ev.noPass) break;\n\t}\n\tif (!hit) core.drawTip(\"前方无敌人\");\n})();",
"canUseItemEffect": "true"
},
"I349": {
"cls": "tools",
"mapTurnSkillRole": "update",
"mapTurnKeepAfterUse": true,
"name": "新物品",
"timeCost": 0,
"canUseItemEffect": "true"
},
"I350": {
"cls": "tools",
"mapTurnSkillRole": "update",
"mapTurnKeepAfterUse": true,
"timeCost": 0,
"name": "状态技能1",
"text": "叠加3层攻击强化每层+50%攻击乘区状态栏攻击数字直接提高层数随地图回合每tick减1。暂用 tools 栏位;不与战后 activeStatusSkills 混用。",
"hideInReplay": true,
"useItemEffect": "(function () {\n\tvar L = core.getFlag(\"mapTestAtkLayers\", 0);\n\tif (typeof L !== \"number\") L = 0;\n\tcore.setFlag(\"mapTestAtkLayers\", L + 3);\n\tcore.addBuff(\"atk\", 1.5);\n\tcore.updateStatusBar(false, true);\n\tvar a = core.getRealStatus(\"atk\");\n\tcore.drawTip(\"强化+3层当前攻击\" + a);\n\tcore.playSound(\"打开界面\");\n})();",
"canUseItemEffect": "true"
},
"I351": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I352": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I353": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
},
"I354": {
"cls": "items",
"name": "新物品",
"timeCost": null,
"canUseItemEffect": "true"
} }
} }

View File

@ -266,12 +266,6 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"329": {"cls":"enemy48","id":"bearRight"}, "329": {"cls":"enemy48","id":"bearRight"},
"330": {"cls":"enemy48","id":"bearUp"}, "330": {"cls":"enemy48","id":"bearUp"},
"331": {"cls":"terrains","id":"T331"}, "331": {"cls":"terrains","id":"T331"},
"20360": {"cls":"tileset","id":"X20360","canPass":true},
"20361": {"cls":"tileset","id":"X20361","canPass":true},
"20368": {"cls":"tileset","id":"X20368","canPass":true},
"20369": {"cls":"tileset","id":"X20369","canPass":true},
"20376": {"cls":"tileset","id":"X20376","canPass":true},
"20377": {"cls":"tileset","id":"X20377","canPass":true},
"332": {"cls":"items","id":"yellowKey2","name":"黄钥匙×2"}, "332": {"cls":"items","id":"yellowKey2","name":"黄钥匙×2"},
"333": {"cls":"items","id":"blueKey2","name":"蓝钥匙×2"}, "333": {"cls":"items","id":"blueKey2","name":"蓝钥匙×2"},
"334": {"cls":"items","id":"redKey2","name":"红钥匙×2"}, "334": {"cls":"items","id":"redKey2","name":"红钥匙×2"},
@ -283,5 +277,22 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"340": {"cls":"items","id":"redPotion2","name":"大红血瓶"}, "340": {"cls":"items","id":"redPotion2","name":"大红血瓶"},
"341": {"cls":"items","id":"bluePotion2","name":"大蓝血瓶"}, "341": {"cls":"items","id":"bluePotion2","name":"大蓝血瓶"},
"342": {"cls":"items","id":"yellowPotion2","name":"大黄血瓶"}, "342": {"cls":"items","id":"yellowPotion2","name":"大黄血瓶"},
"343": {"cls":"items","id":"greenPotion2","name":"大绿血瓶"} "343": {"cls":"items","id":"greenPotion2","name":"大绿血瓶"},
"344": {"cls":"items","id":"I344"},
"345": {"cls":"items","id":"I345"},
"346": {"cls":"items","id":"I346"},
"347": {"cls":"items","id":"I347"},
"348": {"cls":"items","id":"I348"},
"349": {"cls":"items","id":"I349"},
"350": {"cls":"items","id":"I350"},
"351": {"cls":"items","id":"I351"},
"352": {"cls":"items","id":"I352"},
"353": {"cls":"items","id":"I353"},
"354": {"cls":"items","id":"I354"},
"20360": {"cls":"tileset","id":"X20360","canPass":true},
"20361": {"cls":"tileset","id":"X20361","canPass":true},
"20368": {"cls":"tileset","id":"X20368","canPass":true},
"20369": {"cls":"tileset","id":"X20369","canPass":true},
"20376": {"cls":"tileset","id":"X20376","canPass":true},
"20377": {"cls":"tileset","id":"X20377","canPass":true}
} }

View File

@ -2738,9 +2738,74 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
core.setFlag("mapTurnEnabled", !!v); core.setFlag("mapTurnEnabled", !!v);
if (v) ensureFlags(); if (v) ensureFlags();
}, },
/** 读档或 setValue 写入 flag 后调用,在 flag 为真时补齐 mapTurnState / skillState */ /** 读档或 setValue 写入 flag 后调用先迁移道具桶cls 从 constants 改为 skill* 的旧存档),再按需补齐 mapTurnState / skillState */
bootstrapPersistedState: function () { bootstrapPersistedState: function () {
if (mapTurnEnabled()) ensureFlags(); if (typeof this.migrateSkillItemBuckets === "function") this.migrateSkillItemBuckets();
if (mapTurnEnabled()) {
ensureFlags();
if (typeof this.resyncBattleSkillItemStates === "function") this.resyncBattleSkillItemStates();
}
},
/** 旧存档constants 或旧 skill* 桶中的条目,按当前 material 迁到正确桶(含 cls:tools + mapTurnSkillRole 的地图回合技能线) */
migrateSkillItemBuckets: function () {
if (!core.status.hero || !core.status.hero.items) return;
var mat = core.material.items || {};
var hi = core.status.hero.items;
var skillClses = ["skillbattle", "skillremote", "skillrecover", "skillupdate"];
var old = hi.constants || {};
for (var itemId in old) {
var def = mat[itemId];
if (!def) continue;
var n = old[itemId];
if (typeof n !== "number" || n <= 0) continue;
if (def.cls === "tools" && def.mapTurnSkillRole) {
if (!hi.tools) hi.tools = {};
hi.tools[itemId] = (hi.tools[itemId] || 0) + n;
delete old[itemId];
continue;
}
var c = def.cls;
if (skillClses.indexOf(c) < 0) continue;
if (!hi[c]) hi[c] = {};
hi[c][itemId] = (hi[c][itemId] || 0) + n;
delete old[itemId];
}
for (var bi = 0; bi < skillClses.length; bi++) {
var b = skillClses[bi];
var buck = hi[b];
if (!buck) continue;
for (var iid in buck) {
var d2 = mat[iid];
var n2 = buck[iid];
if (typeof n2 !== "number" || n2 <= 0) continue;
if (!d2 || d2.cls !== "tools" || !d2.mapTurnSkillRole) continue;
if (!hi.tools) hi.tools = {};
hi.tools[iid] = (hi.tools[iid] || 0) + n2;
delete buck[iid];
}
}
},
/** 与 project/items 中 battle 技能cls:skillbattle 或 mapTurnSkillRole:battle及 id「skillN」对齐 flag:skill读档后由 bootstrapPersistedState 全量校正 */
syncBattleSkillItemState: function (itemId) {
ensureFlags();
var it = core.material.items[itemId];
if (!it || (it.cls !== "skillbattle" && it.mapTurnSkillRole !== "battle")) return;
var m = typeof itemId === "string" && /^skill(\d+)$/.exec(itemId);
var fv = m ? parseInt(m[1], 10) : null;
if (fv == null || isNaN(fv)) return;
var ss = core.getFlag("skillState");
var cur = core.getFlag("skill", 0);
if (cur === fv) ss.activeBattleSkillId = itemId;
else if (ss.activeBattleSkillId === itemId) ss.activeBattleSkillId = null;
core.setFlag("skillState", ss);
},
resyncBattleSkillItemStates: function () {
var items = core.material.items || {};
for (var id in items) {
var idm = items[id];
if (idm && (idm.cls === "skillbattle" || idm.mapTurnSkillRole === "battle"))
this.syncBattleSkillItemState(id);
}
}, },
consumeTime: function (deltaTime, reason) { consumeTime: function (deltaTime, reason) {
if (!mapTurnEnabled() || !deltaTime || deltaTime <= 0) return; if (!mapTurnEnabled() || !deltaTime || deltaTime <= 0) return;
@ -2757,6 +2822,16 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
var s = core.getFlag("mapTurnState"); var s = core.getFlag("mapTurnState");
s.mapTurn = (s.mapTurn || 0) + 1; s.mapTurn = (s.mapTurn || 0) + 1;
this.resolveEnemyActionsForSingleTick(reason); this.resolveEnemyActionsForSingleTick(reason);
// 测试道具 I350每层强化随「地图 tick」跌落由任意 consumeTime 推进触发;远程击杀不另扣层)
this.mapTurnTickDecayMapTestAtkLayers();
},
/** I350 地图回合驱动:每 tick 层数 -1atk 乘区 -0.5(与每层 +50% 对齐) */
mapTurnTickDecayMapTestAtkLayers: function () {
var layers = core.getFlag("mapTestAtkLayers", 0);
if (typeof layers !== "number" || layers <= 0) return;
core.setFlag("mapTestAtkLayers", layers - 1);
if (typeof core.addBuff === "function") core.addBuff("atk", -0.5);
core.updateStatusBar(false, true);
}, },
/** 单 tick 怪物调度:仅扫 activeEnemiesByFloor不调用 extractBlocksmap-turn-spec §6.2 */ /** 单 tick 怪物调度:仅扫 activeEnemiesByFloor不调用 extractBlocksmap-turn-spec §6.2 */
resolveEnemyActionsForSingleTick: function (reason) { resolveEnemyActionsForSingleTick: function (reason) {
@ -2789,8 +2864,26 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
/** /**
* 达阈行动初版仅实现 actType === idle无操作 * 达阈行动初版仅实现 actType === idle无操作
* chase/patrol/skill 等若在此同步改图块会经引擎 removeBlock 触发 extractBlocks违反单 tick 约束后续用 insertAction 链或专用无扫描迁移 API 再接 * chase/patrol/skill 等若在此同步改图块会经引擎 removeBlock 触发 extractBlocks违反单 tick 约束后续用 insertAction 链或专用无扫描迁移 API 再接
* 特殊 29庇护测试仅改 flags.enemyOnPoint不经 removeBlock/setBlock
*/ */
performEnemyAction: function (enemyRef, def, floorId, reason) { performEnemyAction: function (enemyRef, def, floorId, reason) {
if (def && core.enemys && typeof core.enemys.hasSpecial === "function" && core.enemys.hasSpecial(def.special, 29)) {
floorId = floorId || core.status.floorId;
if (floorId && core.floors && core.floors[floorId]) {
core.extractBlocks(floorId);
var _mapShelter = core.status.maps && core.status.maps[floorId];
var _blocksShelter = (_mapShelter && _mapShelter.blocks) || [];
for (var _si = 0; _si < _blocksShelter.length; _si++) {
var _b = _blocksShelter[_si];
if (!_b || _b.disable) continue;
var _ev = _b.event;
if (!_ev || !_ev.cls || String(_ev.cls).indexOf("enemy") !== 0) continue;
core.events.setEnemyOnPoint(_b.x, _b.y, floorId, "hp", 1, "+=", undefined, true);
}
core.updateStatusBar();
}
return;
}
var actType = def.actType || "idle"; var actType = def.actType || "idle";
if (actType === "idle") return; if (actType === "idle") return;
/* chase / patrol / skill占位不在此 tick 内改图块 */ /* chase / patrol / skill占位不在此 tick 内改图块 */
@ -2934,6 +3027,18 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
var v = st && st.battleTimeCost; var v = st && st.battleTimeCost;
if (typeof v === "number" && v > statusBattleTimeCostMax) statusBattleTimeCostMax = v; if (typeof v === "number" && v > statusBattleTimeCostMax) statusBattleTimeCostMax = v;
} }
var ss = core.getFlag("skillState");
var bid = ss.activeBattleSkillId;
if (bid) {
var bit = core.material.items[bid];
if (
bit &&
(bit.cls === "skillbattle" || bit.mapTurnSkillRole === "battle") &&
typeof bit.timeCost === "number" &&
bit.timeCost > statusBattleTimeCostMax
)
statusBattleTimeCostMax = bit.timeCost;
}
return Math.max(baseBattleTimeCost, statusBattleTimeCostMax); return Math.max(baseBattleTimeCost, statusBattleTimeCostMax);
}, },
applyStatusAfterBattle: function (battleResult) { applyStatusAfterBattle: function (battleResult) {
@ -3045,6 +3150,110 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
mtCall({ op: "migratePoint", fromX: fromX, fromY: fromY, toX: toX, toY: toY }, floorId || core.status.floorId); mtCall({ op: "migratePoint", fromX: fromX, fromY: fromY, toX: toX, toY: toY }, floorId || core.status.floorId);
}; };
})(); })();
},
"瞬移轨迹": function () {
// 在此增加新插件
function popMove() {
var ctx = core.getContextByName("popMove");
if (!ctx)
ctx = core.createCanvas(
"popMove",
0,
0,
core.__PIXELS__,
core.__PIXELS__,
71
);
ctx.canvas.classList.add("gameCanvas", "anti-aliasing");
core.clearMap(ctx);
if (core.status.replay.speed <= 3 && !flags.stopPop) {
var list = core.status.popMove || [];
var count = 0;
list.forEach(function (one) {
// 由frame计算出dy
one.frame++;
// 绘制
if (one.frame >= 0) core.setAlpha(ctx, 1 - one.frame / 30);
else core.setAlpha(ctx, 1);
var length = Math.sqrt(
Math.pow(one.px2 - one.px, 2) + Math.pow(one.py2 - one.py, 2)
);
//console.log(length)
var li = length / 16;
var lx = (one.px2 - one.px) / li;
var ly = (one.py2 - one.py) / li;
for (var i = 0; i < li; i += 1) {
core.setAlpha(ctx, (1 - one.frame / 30) * ((i / li) * 0.8 + 0.2));
core.drawLine(
"popMove",
one.px + i * lx,
one.py + i * ly,
one.px + (i + 0.5) * lx,
one.py + (i + 0.5) * ly,
"#E1E1E1",
6
);
if (i == 0)
core.strokeCircle("popMove", one.px, one.py, 6, "#E1E1E1", 3);
}
core.strokeCircle("popMove", one.px2, one.py2, 6, "#E1E1E1", 3);
core.strokeCircle(
"popMove",
one.px2,
one.py2,
6 + (16 * one.frame) / 30,
"#E1E1E1",
6 * (1 - one.frame / 30)
);
//core.drawLine('popMove', one.px, one.py, one.px2, one.py2, '#E1E1E1', 6);
if (one.frame >= 30) count++;
});
if (count > 0) list.splice(0, count);
}
} }
if (!main.replayChecking) {
core.registerAnimationFrame("popMove", true, popMove);
}
this.addPopMove = function (px, py, px2, py2, frame) {
var data = { px: px, py: py, px2: px2, py2: py2, frame: frame || 0 };
if (core.status.replay.speed <= 3) {
if (!core.status.popMove) core.status.popMove = [data];
else core.status.popMove.push(data);
}
};
},
"伤害跳字": //将下面的代码粘贴到脚本编辑 - 插件编写中
this.tiaozi = function (neirong, yanse) { //跳字
if (core.status.replay.replaying) {} else {
var shangsheng = 1;
var gaodu = 0;
var tiaozizhong = 0;
var herox = core.status.hero.loc.x,
heroy = core.status.hero.loc.y;
var name = "tiaozi" + Math.floor(Math.random() * 1000000); //如不需要连续跳字可不加随机数
core.createCanvas(name, (herox - 1) * 32 - 13, (heroy - 1) * 32 + gaodu, 96, 64, 74);
core.fillText(name, neirong, 32, 32, yanse, "bold 17px Verdana");
var fade = setInterval(function () {
if (gaodu >= -6 && shangsheng == 1) {
gaodu = gaodu - 1;
if (gaodu == -6) { shangsheng = 0 }
} else if (gaodu <= 12) {
gaodu = gaodu + 1;
if (gaodu == 12) { tiaozizhong = 1; }
};
core.relocateCanvas(name, (herox - 1) * 32 - 13, (heroy - 1) * 32 + gaodu);
if (tiaozizhong == 1) {
delete core.animateFrame.asyncId[fade];
clearInterval(fade);
core.deleteCanvas(name);
}
}, 16);
core.animateFrame.asyncId[fade] = true;
}
}
} }