diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index c03b589c..591b0136 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -231,6 +231,7 @@ action | setFloor_s | setGlobalAttribute_s | setGlobalValue_s + | setGlobalFlag_s | show_s | hide_s | trigger_s @@ -500,6 +501,20 @@ return code; */; +setGlobalFlag_s + : '设置系统开关' ':' Global_Flag_List Bool Newline + + +/* setGlobalFlag_s +tooltip : setGlobalFlag:设置系统开关 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=setGlobalFlag%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e7%b3%bb%e7%bb%9f%e5%bc%80%e5%85%b3 +default : ["enableFloor","true"] +colour : this.dataColor +var code = '{"type": "setGlobalFlag", "name": "'+Global_Flag_List_0+'", "value": '+Bool_0+'},\n'; +return code; +*/; + + show_s : '显示事件' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '动画时间' Int? '不等待执行完毕' Bool? Newline @@ -842,15 +857,16 @@ return code; */; sleep_s - : '等待' Int '毫秒' Newline + : '等待' Int '毫秒' '不可被Ctrl跳过' Bool Newline /* sleep_s tooltip : sleep: 等待多少毫秒 helpUrl : https://h5mota.com/games/template/docs/#/event?id=sleep%EF%BC%9A%E7%AD%89%E5%BE%85%E5%A4%9A%E5%B0%91%E6%AF%AB%E7%A7%92 -default : [500] +default : [500, false] colour : this.soundColor -var code = '{"type": "sleep", "time": '+Int_0+'},\n'; +Bool_0 = Bool_0?', "noSkip": true':''; +var code = '{"type": "sleep", "time": '+Int_0+Bool_0+'},\n'; return code; */; @@ -1643,7 +1659,6 @@ colour : this.idstring_eColor default : [null,"自定义flag"] //todo 将其output改成'idString_e' var code = Id_List_0+':'+IdText_0; -if (Id_List_0 === 'flag0') code = "flag:__"+IdText_0+"__"; return [code, Blockly.JavaScript.ORDER_ATOMIC]; */; @@ -1667,7 +1682,7 @@ evFlag_e /* evFlag_e colour : this.idstring_eColor default : ["A"] -var code = "flag:__"+Letter_List_0+"__"; +var code = "switch:"+Letter_List_0; return [code, Blockly.JavaScript.ORDER_ATOMIC]; */; @@ -1744,6 +1759,11 @@ Global_Value_List : '血网伤害'|'中毒伤害'|'衰弱效果'|'红宝石效果'|'蓝宝石效果'|'绿宝石效果'|'红血瓶效果'|'蓝血瓶效果'|'黄血瓶效果'|'绿血瓶效果'|'破甲比例'|'反击比例'|'净化比例'|'仇恨增加值'|'行走速度'|'动画时间'|'楼层切换时间' /*Global_Value_List ['lavaDamage','poisonDamage','weakValue', 'redJewel', 'blueJewel', 'greenJewel', 'redPotion', 'bluePotion', 'yellowPotion', 'greenPotion', 'breakArmor', 'counterAttack', 'purify', 'hatred', 'moveSpeed', 'animateSpeed', 'floorChangeTime']*/; + +Global_Flag_List + : '显示当前楼层'|'显示勇士图标'|'显示当前等级'|'启用生命上限'|'显示魔力值'|'显示魔防值'|'显示金币值'|'显示经验值'|'允许等级提升'|'升级扣除模式'|'显示钥匙数量'|'显示破炸飞'|'显示毒衰咒'|'显示当前技能'|'楼梯边才能楼传'|'开启加点'|'开启负伤'|'循环计算临界'|'允许轻按'|'允许走到将死领域'|'允许瞬间移动'|'阻激夹域后禁用快捷商店' + /*Global_Flag_List ['enableFloor','enableName','enableLv', 'enableHPMax', 'enableMana', 'enableMDef', 'enableMoney', 'enableExperience', 'enableLevelUp', 'levelUpLeftMode', 'enableKeys', 'enablePZF', 'enableDebuff', 'enableSkill', 'flyNearStair', 'enableAddPoint', 'enableNegativeDamage', 'useLoop', 'enableGentleClick', 'canGoDeadZone', 'enableMoveDirectly', 'disableShopOnDamage']*/; + Colour : 'sdeirughvuiyasdeb'+ //为了被识别为复杂词法规则 ; @@ -1759,8 +1779,8 @@ Bool: 'TRUE' Int : '0' | [1-9][0-9]* ; // no leading zeros Letter_List - : 'A'|'B'|'C'|'D'|'E'|'F'|'G'|'H'|'I'|'J'|'K'|'L'|'M'|'N'|'O'|'P'|'Q'|'R'|'S'|'T'|'U'|'V'|'W'|'X'|'Y'|'Z' - /*Letter_List ['A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z']*/; + : 'A'|'B'|'C'|'D'|'E'|'F' + /*Letter_List ['A','B','C','D','E','F']*/; Number @@ -1792,7 +1812,7 @@ FixedId_List Id_List : '变量' | '状态' | '物品' | '独立开关' - /*Id_List ['flag','status','item', 'flag0']*/; + /*Id_List ['flag','status','item', 'switch']*/; //转blockly后不保留需要加" EvalString @@ -1853,6 +1873,7 @@ this.evisitor.commentColor=285; delete(this.block('negate_e').inputsInline); this.block('idString_1_e').output='idString_e'; this.block('idString_2_e').output='idString_e'; +this.block('evFlag_e').output='idString_e'; */ /* Functions @@ -2239,7 +2260,8 @@ ActionParser.prototype.parseAction = function() { break case "setValue": this.next = MotaActionBlocks['setValue_s'].xmlText([ - MotaActionBlocks['idString_e'].xmlText([data.name]), + // MotaActionBlocks['idString_e'].xmlText([data.name]), + this.tryToUseEvFlag_e('idString_e', [data.name]), MotaActionBlocks['evalString_e'].xmlText([data.value]), this.next]); break; @@ -2255,6 +2277,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['setGlobalValue_s'].xmlText([ data.name, data.value, this.next]); break; + case "setGlobalFlag": + this.next = MotaActionBlocks['setGlobalFlag_s'].xmlText([ + data.name, data.value, this.next]); + break; case "input": this.next = MotaActionBlocks['input_s'].xmlText([ data.text,this.next]); @@ -2265,7 +2291,8 @@ ActionParser.prototype.parseAction = function() { break; case "if": // 条件判断 this.next = MotaActionBlocks['if_s'].xmlText([ - MotaActionBlocks['evalString_e'].xmlText([data.condition]), + // MotaActionBlocks['evalString_e'].xmlText([data.condition]), + this.tryToUseEvFlag_e('evalString_e', [data.condition]), this.insertActionList(data["true"]), this.insertActionList(data["false"]), this.next]); @@ -2277,7 +2304,9 @@ ActionParser.prototype.parseAction = function() { this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",this.insertActionList(caseNow.action),case_caseList]); } this.next = MotaActionBlocks['switch_s'].xmlText([ - MotaActionBlocks['evalString_e'].xmlText([data.condition]),case_caseList,this.next]); + // MotaActionBlocks['evalString_e'].xmlText([data.condition]), + this.tryToUseEvFlag_e('evalString_e', [data.condition]), + case_caseList,this.next]); break; case "choices": // 提供选项 var text_choices = null; @@ -2290,7 +2319,8 @@ ActionParser.prototype.parseAction = function() { break; case "while": // 循环处理 this.next = MotaActionBlocks['while_s'].xmlText([ - MotaActionBlocks['evalString_e'].xmlText([data.condition]), + // MotaActionBlocks['evalString_e'].xmlText([data.condition]), + this.tryToUseEvFlag_e('evalString_e', [data.condition]), this.insertActionList(data["data"]), this.next]); break; @@ -2334,7 +2364,7 @@ ActionParser.prototype.parseAction = function() { break; case "sleep": // 等待多少毫秒 this.next = MotaActionBlocks['sleep_s'].xmlText([ - data.time||0,this.next]); + data.time||0,data.noSkip||false,this.next]); break; case "wait": // 等待用户操作 this.next = MotaActionBlocks['wait_s'].xmlText([ @@ -2400,6 +2430,15 @@ ActionParser.prototype.EvalString = function(EvalString) { return EvalString.split('\b').join('\\b').split('\t').join('\\t').split('\n').join('\\n'); } +ActionParser.prototype.tryToUseEvFlag_e = function(defaultType, args, isShadow, comment) { + var match=/^switch:([A-F])$/.exec(args[0]) + if(match){ + args[0]=match[1] + return MotaActionBlocks['evFlag_e'].xmlText(args, isShadow, comment); + } + return MotaActionBlocks[defaultType||'evalString_e'].xmlText(args, isShadow, comment); +} + MotaActionFunctions.actionParser = new ActionParser(); MotaActionFunctions.workspace = function(){return workspace} diff --git a/_server/data.comment.js b/_server/data.comment.js index 9be56e8a..fc341189 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -480,7 +480,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "checkbox", "_bool": "bool", - "_data": "是否涉及毒衰咒;如果此项为false则不会在状态栏中显示毒衰咒的debuff" + "_data": "是否在状态栏显示毒衰咒" }, "enableSkill": { "_leaf": true, diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index f882467f..2339341e 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -88,6 +88,7 @@ editor_blockly = function () { MotaActionBlocks['setFloor_s'].xmlText(), MotaActionBlocks['setGlobalAttribute_s'].xmlText(), MotaActionBlocks['setGlobalValue_s'].xmlText(), + MotaActionBlocks['setGlobalFlag_s'].xmlText(), MotaActionBlocks['input_s'].xmlText(), MotaActionBlocks['input2_s'].xmlText(), MotaActionBlocks['update_s'].xmlText(), diff --git a/docs/api.md b/docs/api.md index da0b22a5..ed2c4914 100644 --- a/docs/api.md +++ b/docs/api.md @@ -168,6 +168,10 @@ core.nextY(n) 获得勇士面向的第n个位置的y坐标,n可以省略默认为1(即正前方) +core.nearHero(x, y) +判断某个点是否和勇士的距离不超过1。 + + core.openDoor(id, x, y, needKey, callback) [异步] 尝试开门操作。id为目标点的ID,x和y为坐标,needKey表示是否需要使用钥匙,callback为开门完毕后的回调函数。 id可为null代表使用地图上的值。 @@ -330,9 +334,15 @@ control.js主要用来进行游戏控制,比如行走控制、自动寻路、 core.control.setGameCanvasTranslate(canvasId, x, y) 设置大地图的偏移量 + core.control.updateViewport() 更新大地图的可见区域 + +core.control.gatherFollowers() +立刻聚集所有的跟随者 + + core.control.replay() 回放下一个操作 @@ -463,6 +473,17 @@ core.maps.removeBlockByIds(floorId, ids) 根据索引删除或禁用若干块。 +core.maps.drawAnimate(name, x, y, callback) +播放一段动画,name为动画名(需在全塔属性注册),x和y为坐标(0-12之间),callback可选,为播放完毕的回调函数。 +播放过程是异步的,如需等待播放完毕请使用insertAction插入一条type:waitAsync事件。 +此函数将随机返回一个数字id,为此异步动画的唯一标识符。 + + +core.maps.stopAnimate(id, doCallback) +立刻停止一个异步动画。 +id为该动画的唯一标识符(由drawAnimate函数返回),doCallback可选,若为true则会执行该动画所绑定的回调函数。 + + ========== core.ui.XXX 和对话框绘制相关的函数 ========== ui.js主要用来进行UI窗口的绘制,比如对话框、怪物手册、楼传器、存读档界面等等。 diff --git a/docs/event.md b/docs/event.md index 5cfcebb8..fba5dc7e 100644 --- a/docs/event.md +++ b/docs/event.md @@ -481,6 +481,23 @@ name必填项,代表要修改的全局数值,其和全塔属性中的values value为必填项,代表要修改到的结果。该项必须是个数值。 +### setGlobalFlag:设置一个系统开关 + +使用`{"type":"setGlobalFlag"}`可以设置一个系统开关。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "setGlobalFlag", "name": "enableMDef", "value": false}, // 不在状态栏显示魔防值 +] +``` + +name必填项,代表要修改的系统开关,其是全塔属性中的flags中的一部分。目前只能为`"enableFloor", "enableName", "enableLv", +"enableHPMax", "enableMana", "enableMDef", "enableMoney", "enableExperience", "enableLevelUp", "levelUpLeftMode", +"enableKeys", "enablePZF", "enableDebuff", "enableSkill", "flyNearStair", "enableAddPoint", "enableNegativeDamage", +"useLoop", "enableGentleClick", "canGoDeadZone", "enableMoveDirectly", "disableShopOnDamage"`。 + +value为必填项,只能为true或false,代表要修改到的结果。 + ### show:将一个禁用事件启用 我们上面提到了,所有事件都必须靠其他事件驱动来完成,不存在当某个flag为true时自动执行的说法。那么,我们自然要有启用事件的写法。 @@ -1693,12 +1710,12 @@ core.insertAction([ 从V2.5.3开始,针对每个事件都提供了独立开关。 -独立开关的写法是`flag:__A__`, `flag:__B__`直到`flag:__Z__`,共计26个。 +独立开关的写法是`switch:A`, `switch:A`直到`switch:Z`,共计26个;不过样板中的值块默认只提供前6个。 -独立开关算是特殊的flag,它在事件中使用时会和事件的楼层及坐标进行绑定;换句话说每个事件对应的`flag:__A__`都是不同的。 +独立开关算是特殊的flag,它在事件中使用时会和事件的楼层及坐标进行绑定;换句话说每个事件对应的`switch:A`都是不同的。 -事实上,在某个楼层某个点的事件的独立开关对应的系统flag为`floorId@x@y__X__`, -比如在`MT0`层的`[2,5]`点事件,对应的`flag:__B__`独立开关,实际会被映射到`flag:MT0@2@5__B__`。 +事实上,在某个楼层某个点的事件的独立开关A对应的系统flag为`floorId@x@y@A`, +比如在`MT0`层的`[2,5]`点事件,对应的`switch:B`独立开关,实际会被映射到`flag:MT0@2@5@B`。 如果在事件外想访问某个事件的独立开关也需要通过上面这个方式。 @@ -2206,9 +2223,9 @@ if (core.getFlag("door",0)==2) { if (hard=='Easy') { // 简单难度 core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 // 可以在此设置一些初始福利,比如设置初始生命值可以调用: - // core.setStatus("hp", 10000); + // core.setStatus('hp', 10000); // 赠送一把黄钥匙可以调用 - // core.setItem("yellowKey", 1); + // core.setItem('yellowKey', 1); } if (hard=='Normal') { // 普通难度 core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度 diff --git a/docs/personalization.md b/docs/personalization.md index 98c8bdd2..6209c2dd 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -959,7 +959,7 @@ this.getAchievements = function () { - **`flag:equip_atk_buff`**, **`flag:equip_def_buff`**, **`flag:equip_mdef_buff`**: 当前攻防魔防的实际计算比例加成。 - **`flag:forceSave`**: 是否允许事件中强制自动存档。如果将此项置为true并调用core.autosave()即可在事件中强制自动存档,读档时会自动执行该楼层的`eachArrive`事件。 - **`flag:__color__`**, **`flag:__weather__`**, **`flag:__volume__`**: 当前的画面色调、天气和音量。 -- **`flag:textAttribute`**, **`flag:globalAttribute`**: 当前的剧情文本属性,当前的全局属性。 +- **`flag:textAttribute`**, **`flag:globalAttribute`**, **`flag:globalFlags`**: 当前的剧情文本属性,当前的全局属性,当前的全局开关。 - **`flag:cannotMoveDirectly`**, **`flag:clickMove`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。 - **`flag:hideStatusBar`**, **`flag:showToolbox`**: 是否隐藏状态栏,是否显示工具栏。 - **`flag:debug`**, **`flag:consoleOpened`**: 当前是否开启了调试模式,是否开启了控制台。 diff --git a/libs/actions.js b/libs/actions.js index a538b37f..1ece88dc 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -698,6 +698,14 @@ actions.prototype.keyDownCtrl = function () { core.doAction(); return; } + if (core.status.event.id=='action' && core.status.event.data.type=='sleep' + && !core.status.event.data.current.noSkip) { + if (core.isset(core.timeout.sleepTimeout)) { + clearTimeout(core.timeout.sleepTimeout); + core.timeout.sleepTimeout = null; + core.events.doAction(); + } + } } ////// diff --git a/libs/control.js b/libs/control.js index 17225c96..9afa5a06 100644 --- a/libs/control.js +++ b/libs/control.js @@ -419,7 +419,13 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value core.values = core.clone(values); else core.values = core.clone(core.data.values); + core.flags = core.clone(core.data.flags); + var systemFlags = core.getFlag("globalFlags", {}); + for (var key in systemFlags) + core.flags[key] = systemFlags[key]; + core.events.initGame(); + core.resize(); this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show', core.getFlag("showToolbox")); core.status.played = true; @@ -1124,6 +1130,11 @@ control.prototype.nextY = function (n) { return core.getHeroLoc('y')+core.utils.scan[core.getHeroLoc('direction')].y*(n||1); } +////// 某个点是否在勇士旁边 ////// +control.prototype.nearHero = function (x, y) { + return Math.abs(x-core.getHeroLoc('x'))+Math.abs(y-core.getHeroLoc('y'))<=1; +} + ////// 聚集跟随者 ////// control.prototype.gatherFollowers = function () { if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return; @@ -2634,7 +2645,7 @@ control.prototype.triggerStatusBar = function (name, showToolbox) { if (name!='hide') name='show'; // 如果是隐藏 -> 显示工具栏,则先显示 - if (name == 'hide' && showToolbox && !core.domStyle.showStatusBar && !core.hasFlag("showToolbox")) { + if (name == 'hide' && !core.domStyle.showStatusBar) { this.triggerStatusBar("show"); this.triggerStatusBar("hide", showToolbox); return; @@ -2808,6 +2819,9 @@ control.prototype.needDraw = function(id) { control.prototype.resize = function(clientWidth, clientHeight) { if (main.mode=='editor')return; + clientWidth = clientWidth || main.dom.body.clientWidth; + clientHeight = clientHeight || main.dom.body.clientHeight; + // 默认画布大小 var DEFAULT_CANVAS_WIDTH = 422; // 默认边栏宽度 diff --git a/libs/core.js b/libs/core.js index f6db94ca..d5d6c9df 100644 --- a/libs/core.js +++ b/libs/core.js @@ -20,6 +20,7 @@ function core() { 'getItemTipTimeout': null, 'turnHeroTimeout': null, 'onDownTimeout': null, + 'sleepTimeout': null, } this.interval = { 'heroMoveInterval': null, @@ -602,6 +603,11 @@ core.prototype.nextY = function (n) { return core.control.nextY(n); } +////// 某个点是否在勇士旁边 ////// +core.prototype.nearHero = function (x, y) { + return core.control.nearHero(x, y); +} + /////////// 自动行走 & 行走控制 END /////////// @@ -892,7 +898,12 @@ core.prototype.drawBoxAnimate = function () { ////// 绘制动画 ////// core.prototype.drawAnimate = function (name, x, y, callback) { - core.maps.drawAnimate(name, x, y, callback); + return core.maps.drawAnimate(name, x, y, callback); +} + +////// 停止动画 ////// +core.prototype.stopAnimate = function (id, doCallback) { + return core.maps.stopAnimate(id, doCallback); } ////// 更新领域、夹击、阻击的伤害地图 ////// diff --git a/libs/events.js b/libs/events.js index 5065d511..d58d217e 100644 --- a/libs/events.js +++ b/libs/events.js @@ -965,9 +965,11 @@ events.prototype.doAction = function() { } // flag if (data.name.indexOf("flag:")==0) { - var flag = data.name.substring(5); - if (/^__[A-Z]__$/.test(flag)) flag = (prefix||"")+flag; - core.setFlag(flag, value); + core.setFlag(data.name.substring(5), value); + } + // switch + if (data.name.indexOf("switch:")==0) { + core.setFlag((prefix||"global")+"@"+data.name.substring(7), value); } } catch (e) {console.log(e)} @@ -994,6 +996,16 @@ events.prototype.doAction = function() { core.values[data.name] = data.value; this.doAction(); break; + case "setGlobalFlag": + { + var flags = core.getFlag("globalFlags", {}); + flags[data.name] = data.value; + core.flags[data.name] = data.value; + core.setFlag("globalFlags", flags); + core.resize(); + this.doAction(); + break; + } case "setHeroIcon": { this.setHeroIcon(data.name); @@ -1166,7 +1178,8 @@ events.prototype.doAction = function() { } break; case "sleep": // 等待多少毫秒 - setTimeout(function() { + core.timeout.sleepTimeout = setTimeout(function() { + core.timeout.sleepTimeout = null; core.events.doAction(); }, core.status.replay.replaying?20:data.time); break; @@ -1270,7 +1283,6 @@ events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { if (itemNum > 1) text += "x" + itemNum; if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); core.drawTip(text, core.material.icons.items[itemId]); - core.clearMap('event', itemX * 32, itemY * 32, 32, 32); core.updateStatusBar(); this.eventdata.afterGetItem(itemId, itemX, itemY, callback); diff --git a/libs/loader.js b/libs/loader.js index 0715d5df..209b790d 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -264,6 +264,9 @@ loader.prototype.freeBgm = function (name) { core.material.bgms[name].removeAttribute("src"); core.material.bgms[name].load(); core.material.bgms[name] = null; + if (name == core.musicStatus.playingBgm) { + core.musicStatus.playingBgm = null; + } // 三秒后重新加载 setTimeout(function () { core.loader.loadOneMusic(name); diff --git a/libs/maps.js b/libs/maps.js index 78b8d5a3..154a75d8 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -587,6 +587,8 @@ maps.prototype.drawMap = function (floorId, callback) { } } else { drawEvent(); + if (core.isset(core.status.curtainColor)) + core.fillRect('curtain',0,0,416,416,core.arrayToRGBA(core.status.curtainColor)); core.setGlobalAnimate(core.values.animateSpeed); core.drawHero(); core.updateStatusBar(); @@ -1357,13 +1359,13 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { // 正在播放录像:不显示动画 if (core.isset(core.status.replay) && core.status.replay.replaying) { if (core.isset(callback)) callback(); - return; + return -1; } // 检测动画是否存在 if (!core.isset(core.material.animates[name]) || !core.isset(x) || !core.isset(y)) { if (core.isset(callback)) callback(); - return; + return -1; } // 开始绘制 @@ -1382,6 +1384,30 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { }); core.animateFrame.asyncId[animateId] = true; + return animateId; +} + +////// 停止动画 ////// +maps.prototype.stopAnimate = function (id, doCallback) { + for (var i=0;i=0", - "pickaxe": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1 && \n\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t// 四个方向\n\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\tids.push(i);\n\t\telse id2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "icePickaxe": "var able=false;\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\tcore.status.event.data = [i];\n\t\table=true;\n\t}\n}\nable", - "bomb": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.getHeroLoc('x'))+Math.abs(block.y-core.getHeroLoc('y'))<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "hammer": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.getHeroLoc('x'))+Math.abs(block.y-core.getHeroLoc('y'))<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "earthquake": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable &&\n\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\tids.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nable", - "centerFly": "var toX = (core.bigmap.width||13)-1-core.getHeroLoc('x'), toY = (core.bigmap.height||13)-1-core.getHeroLoc('y');\ncore.getBlockId(toX, toY) == null", - "upFly": "var able=false;\nvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\nif (index=0 && toX=0 && toY0) {\n\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\tvar mw = core.floors[toId].width||13, mh = core.floors[toId].height||13;\n\tif (toX>=0 && toX=0 && toY0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "bigKey": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n\t\tids.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nable", - "poisonWine": "core.hasFlag('poison')", - "weakWine": "core.hasFlag('weak')", - "curseWine": "core.hasFlag('curse')", - "superWine": "core.hasFlag('poison') || core.hasFlag('weak') || core.hasFlag('curse')", + "fly": "(function () {\n\treturn core.status.hero.flyRange.indexOf(core.status.floorId)>=0;\n})();", + "pickaxe": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.data = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.data = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "icePickaxe": "(function() {\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.data = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();", + "bomb": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.data = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.data = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "hammer": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.data = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.data = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "earthquake": "(function () {\n\tvar able=false;\n\tvar ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable &&\n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.data = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", + "centerFly": "(function () {\n\tvar toX = (core.bigmap.width||13)-1-core.getHeroLoc('x'), toY = (core.bigmap.height||13)-1-core.getHeroLoc('y');\n\tvar id = core.getBlockId(toX, toY);\n\treturn id == null;\n})();", + "upFly": "(function() {\n\tvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\n\tif (index=0 && toX=0 && toY0) {\n\t\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\t\tvar mw = core.floors[toId].width||13, mh = core.floors[toId].height||13;\n\t\tif (toX>=0 && toX=0 && toY0) {\n\t\tcore.status.event.data = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.data = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "bigKey": "(function() {\n\tvar able=false, ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.data = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", + "poisonWine": "core.hasFlag('poison');", + "weakWine": "core.hasFlag('weak');", + "curseWine": "core.hasFlag('curse');", + "superWine": "(function() {\n\treturn core.hasFlag('poison') || core.hasFlag('weak') || core.hasFlag('curse');\n})();", "lifeWand": "true", - "jumpShoes": "var nx=core.nextX(2),ny=core.nextY(2);nx>=0&&nx=0&&ny=0 && nx=0 && ny