From 53f109a461fbb500268fe89c183f2e97cae1f5ab Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Wed, 14 Jul 2021 18:18:00 +0800 Subject: [PATCH] setEnemy operator & searchBlockWithFilter --- _docs/api.md | 18 +++++++++++++----- _docs/editor.md | 3 ++- _server/CodeMirror/defs.js | 16 ++++++++++------ _server/MotaAction.g4 | 7 +++++-- _server/MotaActionParser.js | 2 +- libs/events.js | 32 ++++++++++++++++---------------- libs/maps.js | 20 ++++++++++++++++++++ project/functions.js | 3 +++ runtime.d.ts | 15 +++++++++++++-- 9 files changed, 83 insertions(+), 33 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index 17b30fb2..1eb62d8d 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -903,10 +903,9 @@ callback: 门完全关上后的回调函数,可选 confirmRestart: fn() 询问是否需要重新开始 -doAction: fn(keepUI?: true) +doAction: fn() 执行下一个事件指令,常作为回调 例如:core.setCurtain([0,0,0,1], undefined, core.doAction); // 事件中的原生脚本,配合勾选“不自动执行下一个事件”来达到此改变色调只持续到下次场景切换的效果 -keepUI: true表示不清除UI画布和选择光标 doEvent: fn(data?: ?, x?: number, y?: number, prefix?: string) 执行一个自定义事件 @@ -1073,12 +1072,13 @@ restart: fn() save: fn(fromUserAction?: bool) 点击存档按钮时的打开操作 -setEnemy: fn(id: string, name: string, value: ?, prefix?: string) +setEnemy: fn(id: string, name: string, value: ?, operator?: string, prefix?: string) 设置一项敌人属性并计入存档 例如:core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0 id: 敌人id name: 属性的英文缩写 value: 属性的新值,可选 +operator: 运算操作符,可选 prefix: 独立开关前缀,一般不需要,下同 setEvents: fn(list?: [?], x?: number, y?: number, callback?: fn()) @@ -1658,14 +1658,22 @@ resizeMap: fn(floorId?: string) saveMap: fn(floorId?: string) 将当前地图重新变成数字,以便于存档 -searchBlock: fn(id: string, floorId?: string, showDisable?: bool) -> [{floorId: string, index: number, x: number, y: number, block: block}] +searchBlock: fn(id: string, floorId?: string|[string], showDisable?: bool) -> [{floorId: string, index: number, x: number, y: number, block: block}] 搜索图块, 支持通配符和正则表达式 例如:core.searchBlock('*Door'); // 搜索当前地图的所有门 id: 图块id,支持星号表示任意多个(0个起)字符 -floorId: 地图id,不填视为当前地图 +floorId: 地图id或数组,不填视为当前地图 showDisable: 隐藏点是否计入,true表示计入 返回值:一个详尽的数组,一般只用到其长度 +searchBlockWithFilter: fn(blockFilter: fn(block: block) -> bool, floorId?: string|[string], showDisable?: bool): [{floorId: string, index: number, x: number, y: number, block: block}] +根据给定的筛选函数搜索全部满足条件的图块 +例如:core.searchBlockWithFilter(function (block) { return block.event.id.endsWith('Door'); }); // 搜索当前地图的所有门 +blockFilter: 筛选函数,可接受block输入,应当返回一个boolean值 +floorId: 地图id或数组,不填视为当前地图 +showDisable: 隐藏点是否计入,true表示计入 +返回值:一个详尽的数组 + setBgFgBlock: fn(name: string, number: number|string, x: number, y: number, floorId?: string) 转变图层块 例如:core.setBgFgBlock('bg', 167, 6, 6); // 把当前地图背景层的中心块改为滑冰 diff --git a/_docs/editor.md b/_docs/editor.md index 4018861d..e8e9e6ae 100644 --- a/_docs/editor.md +++ b/_docs/editor.md @@ -302,11 +302,12 @@ return code; case "playBgm": this.next = MotaActionBlocks['playBgm_s'].xmlText([ data.name,data.startTime||0,data.keep||false,this.next]); - break + break; case "meteorite": data.color = this.Colour(data.color) this.next = MotaActionBlocks['meteorite_s'].xmlText([ data.color,'rgba('+data.color+')',data.loc[0],data.loc[1],data.range,this.next]); + break; case "pauseBgm": 最后在editor_blocklyconfig.js中将其加入到工具栏中 diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index 3e18762e..7e263318 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -3178,8 +3178,12 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(id?: string) -> string" }, "searchBlock": { - "!doc": "搜索图块, 支持通配符和正则表达式
例如:core.searchBlock('*Door'); // 搜索当前地图的所有门
id: 图块id,支持星号表示任意多个(0个起)字符
floorId: 地图id,不填视为当前地图
showDisable: 隐藏点是否计入,true表示计入
返回值:一个详尽的数组,一般只用到其长度", - "!type": "fn(id: string, floorId?: string, showDisable?: bool) -> [{floorId: string, index: number, x: number, y: number, block: block}]" + "!doc": "搜索图块, 支持通配符和正则表达式
例如:core.searchBlock('*Door'); // 搜索当前地图的所有门
id: 图块id,支持星号表示任意多个(0个起)字符
floorId: 地图id或数组,不填视为当前地图
showDisable: 隐藏点是否计入,true表示计入
返回值:一个详尽的数组,一般只用到其长度", + "!type": "fn(id: string, floorId?: string|[string], showDisable?: bool) -> [{floorId: string, index: number, x: number, y: number, block: block}]" + }, + "searchBlockWithFilter": { + "!doc": "根据给定的筛选函数搜索全部满足条件的图块
例如:core.searchBlockWithFilter(function (block) { return block.event.id.endsWith('Door'); }); // 搜索当前地图的所有门
blockFilter: 筛选函数,可接受block输入,应当返回一个boolean值
floorId: 地图id或数组,不填视为当前地图
showDisable: 隐藏点是否计入,true表示计入
返回值:一个详尽的数组", + "!type": "fn(blockFilter: fn(block: block) -> bool, floorId?: string|[string], showDisable?: bool): [{floorId: string, index: number, x: number, y: number, block: block}]" }, "hideBgFgMap": { "!doc": "隐藏前景/背景地图", @@ -3749,8 +3753,8 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(id?: string, x?: number, y?: number, isGentleClick?: bool)" }, "doAction": { - "!doc": "执行下一个事件指令,常作为回调
例如:core.setCurtain([0,0,0,1], undefined, core.doAction); // 事件中的原生脚本,配合勾选“不自动执行下一个事件”来达到此改变色调只持续到下次场景切换的效果
keepUI: true表示不清除UI画布和选择光标", - "!type": "fn(keepUI?: true)" + "!doc": "执行下一个事件指令,常作为回调
例如:core.setCurtain([0,0,0,1], undefined, core.doAction); // 事件中的原生脚本,配合勾选“不自动执行下一个事件”来达到此改变色调只持续到下次场景切换的效果", + "!type": "fn()" }, "openBook": { "!doc": "点击怪物手册时的打开操作", @@ -3901,8 +3905,8 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(x: number, y: number, needKey?: bool, callback?: fn())" }, "setEnemy": { - "!doc": "设置一项敌人属性并计入存档
例如:core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0
id: 敌人id
name: 属性的英文缩写
value: 属性的新值,可选
prefix: 独立开关前缀,一般不需要,下同", - "!type": "fn(id: string, name: string, value: ?, prefix?: string)" + "!doc": "设置一项敌人属性并计入存档
例如:core.setEnemy('greenSlime', 'def', 0); // 把绿头怪的防御设为0
id: 敌人id
name: 属性的英文缩写
value: 属性的新值,可选
operator: 运算操作符如+=,可选
prefix: 独立开关前缀,一般不需要,下同", + "!type": "fn(id: string, name: string, value: ?, operator?: string, prefix?: string)" }, "autoEventExecuting": { "!doc": "当前是否在执行某个自动事件", diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index fc61c98a..d6ff541e 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -1000,7 +1000,7 @@ return code; setEnemy_s - : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List '为' expression Newline + : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List AssignOperator_List expression Newline /* setEnemy_s @@ -1009,7 +1009,10 @@ helpUrl : /_docs/#/instruction default : ["greenSlime", "atk", "0"] allEnemys : ['IdString_0'] colour : this.dataColor -var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'", "value": "'+expression_0+'"},\n'; +if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { + AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; +} else AssignOperator_List_0 = ''; +var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"},\n'; return code; */; diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index 451e2c39..92b3a03b 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -626,7 +626,7 @@ ActionParser.prototype.parseAction = function() { break; case "setEnemy": this.next = MotaActionBlocks['setEnemy_s'].xmlText([ - MotaActionFunctions.replaceToName_token(data.id), data.name, this.expandEvalBlock([data.value]), this.next]); + MotaActionFunctions.replaceToName_token(data.id), data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); break; case "setFloor": this.next = MotaActionBlocks['setFloor_s'].xmlText([ diff --git a/libs/events.js b/libs/events.js index 139eb5f1..1e133275 100644 --- a/libs/events.js +++ b/libs/events.js @@ -727,7 +727,6 @@ events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) { } events.prototype._changeFloor_beforeChange = function (info, callback) { - core.playSound('floor.mp3'); // 需要 setTimeout 执行,不然会出错 window.setTimeout(function () { if (info.time == 0) @@ -926,14 +925,12 @@ events.prototype.startEvents = function (list, x, y, callback) { } ////// 执行当前自定义事件列表中的下一个事件 ////// -events.prototype.doAction = function (keepUI) { - if (!keepUI) { - // 清空boxAnimate和UI层 - core.clearUI(); - clearInterval(core.status.event.interval); - clearTimeout(core.status.event.interval); - core.status.event.interval = null; - } +events.prototype.doAction = function () { + // 清空boxAnimate和UI层 + core.clearUI(); + clearInterval(core.status.event.interval); + clearTimeout(core.status.event.interval); + core.status.event.interval = null; // 判定是否执行完毕 if (this._doAction_finishEvents()) return; var floorId = core.status.event.data.floorId || core.status.floorId; @@ -1747,7 +1744,7 @@ events.prototype._action_addValue = function (data, x, y, prefix) { } events.prototype._action_setEnemy = function (data, x, y, prefix) { - this.setEnemy(data.id, data.name, data.value, prefix); + this.setEnemy(data.id, data.name, data.value, data.operator, prefix); core.doAction(); } @@ -2648,10 +2645,7 @@ events.prototype.unfollow = function (name) { core.clearRouteFolding(); } -////// 数值操作 ////// -events.prototype.setValue = function (name, operator, value, prefix) { - value = core.calValue(value, prefix); - var originValue = core.calValue(name, prefix); +events.prototype._updateValueByOperator = function (value, originValue, operator) { switch (operator) { case '+=': value = originValue + value; break; case '-=': value = originValue - value; break; @@ -2664,6 +2658,12 @@ events.prototype.setValue = function (name, operator, value, prefix) { case 'max=': value = Math.max(originValue, value); break; default: break; } + return value; +} + +////// 数值操作 ////// +events.prototype.setValue = function (name, operator, value, prefix) { + value = this._updateValueByOperator(core.calValue(value, prefix), core.calValue(name, prefix), operator); this._setValue_setStatus(name, value); this._setValue_setItem(name, value); this._setValue_setFlag(name, value); @@ -2705,13 +2705,13 @@ events.prototype._setValue_setGlobal = function (name, value) { } ////// 设置一个怪物属性 ////// -events.prototype.setEnemy = function (id, name, value, prefix) { +events.prototype.setEnemy = function (id, name, value, operator, prefix) { if (!core.hasFlag('enemyInfo')) { core.setFlag('enemyInfo', {}); } var enemyInfo = core.getFlag('enemyInfo'); if (!enemyInfo[id]) enemyInfo[id] = {}; - value = core.calValue(value, prefix); + value = this._updateValueByOperator(core.calValue(value, prefix), (core.material.enemys[id]||{})[name], operator); enemyInfo[id][name] = value; (core.material.enemys[id]||{})[name] = core.clone(value); core.updateStatusBar(); diff --git a/libs/maps.js b/libs/maps.js index 02a7f09a..fc8dc62b 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1712,6 +1712,26 @@ maps.prototype.searchBlock = function (id, floorId, showDisable) { return result; } +////// 给定筛选函数,搜索某个图块出现的所有位置 ////// +maps.prototype.searchBlockWithFilter = function (blockFilter, floorId, showDisable) { + floorId = floorId || core.status.floorId; + var result = []; + if (floorId instanceof Array) { + floorId.forEach(function (floorId) { + result = result.concat(core.searchBlockWithFilter(blockFilter, floorId, showDisable)); + }); + return result; + } + core.extractBlocks(floorId); + for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) { + var block = core.status.maps[floorId].blocks[i]; + if ((showDisable || !block.disable) && blockFilter(block)) { + result.push({floorId: floorId, x: block.x, y: block.y, block: block}); + } + } + return result; +} + // -------- 启用/禁用图块,楼层贴图 -------- // ////// 将某个块从禁用变成启用状态 ////// diff --git a/project/functions.js b/project/functions.js index ae468e3c..3322ac01 100644 --- a/project/functions.js +++ b/project/functions.js @@ -110,6 +110,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // core.deleteAllCanvas(); // } + // 播放换层音效 + core.playSound('floor.mp3'); + // 根据分区信息自动砍层与恢复 if (core.autoRemoveMaps) core.autoRemoveMaps(floorId); diff --git a/runtime.d.ts b/runtime.d.ts index 5e23a11b..9ad6248b 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -905,9 +905,10 @@ declare class events { * @param id 敌人id * @param name 属性的英文缩写 * @param value 属性的新值,可选 + * @param operator 操作符,可选 * @param prefix 独立开关前缀,一般不需要,下同 */ - setEnemy(id: string, name: K, value?: Enemy[K], prefix?: string): void + setEnemy(id: string, name: K, value?: Enemy[K], operator?: string, prefix?: string): void /** * 设置一项楼层属性并刷新状态栏 @@ -1582,8 +1583,18 @@ declare class maps { * @param showDisable 隐藏点是否计入,true表示计入 * @returns 一个详尽的数组,一般只用到其长度 */ - searchBlock(id: string, floorId?: string, showDisable?: boolean): Array<{ floorId: string, index: number, x: number, y: number, block: Block }> + searchBlock(id: string, floorId?: string|Array, showDisable?: boolean): Array<{ floorId: string, index: number, x: number, y: number, block: Block }> + /** + * 根据给定的筛选函数搜索全部满足条件的图块 + * @example core.searchBlockWithFilter(function (block) { return block.event.id.endsWith('Door'); }); // 搜索当前地图的所有门 + * @param blockFilter 筛选函数,可接受block输入,应当返回一个boolean值 + * @param floorId 地图id,不填视为当前地图 + * @param showDisable 隐藏点是否计入,true表示计入 + * @returns 一个详尽的数组 + */ + searchBlockWithFilter(blockFilter: (Block) => boolean, floorId?: string|Array, showDisable?: boolean): Array<{ floorId: string, index: number, x: number, y: number, block: Block }> + /** * 显示(隐藏或显示的)图块,此函数将被“显示事件”指令和勾选了“不消失”的“移动/跳跃事件”指令(如阻击怪)的终点调用 * @example core.showBlock(0, 0); // 显示地图左上角的图块