diff --git a/.gitignore b/.gitignore index 359a1962..94816db6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,8 @@ .vscode *ce5eec52_2fa1_447b_8dad_764e267a7fab* +**/.DS_Store + # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 99783b0b..6a1a0f9f 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -202,6 +202,8 @@ action | changePos_1_s | openShop_s | disableShop_s + | follow_s + | unfollow_s | animate_s | showImage_0_s | showImage_1_s @@ -338,7 +340,7 @@ return code; */; setValue_s - : '变量操作' ':' '名称' idString_e '值' expression Newline + : '变量设置' ':' '名称' idString_e '值' expression Newline /* setValue_s @@ -591,6 +593,7 @@ openShop_s /* openShop_s tooltip : 全局商店 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=openshop%EF%BC%9A%E6%89%93%E5%BC%80%E4%B8%80%E4%B8%AA%E5%85%A8%E5%B1%80%E5%95%86%E5%BA%97 +colour : this.dataColor default : ["shop1"] var code = '{"type": "openShop", "id": "'+IdString_0+'"},\n'; return code; @@ -609,6 +612,33 @@ var code = '{"type": "disableShop", "id": "'+IdString_0+'"},\n'; return code; */; +follow_s + : '跟随勇士' '行走图' EvalString Newline + + +/* follow_s +tooltip : follow: 跟随勇士 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=follow%ef%bc%9a%e8%b7%9f%e9%9a%8f%e5%8b%87%e5%a3%ab +default : ["npc.png"] +colour : this.dataColor +var code = '{"type": "follow", "name": "'+EvalString_0+'"},\n'; +return code; +*/; + +unfollow_s + : '取消跟随' '行走图' EvalString? Newline + + +/* unfollow_s +tooltip : unfollow: 取消跟随 +helpUrl : https://ckcz123.github.io/mota-js/#/event?id=unfollow%ef%bc%9a%e5%8f%96%e6%b6%88%e8%b7%9f%e9%9a%8f +default : [""] +colour : this.dataColor +EvalString_0 = EvalString_0 ? (', "name": "' + EvalString_0 + '"') : ""; +var code = '{"type": "unfollow"' + EvalString_0 + '},\n'; +return code; +*/; + animate_s : '显示动画' IdString '位置' EvalString? Newline @@ -1513,6 +1543,12 @@ ActionParser.prototype.parseAction = function() { data.direction,this.next]); } break; + case "follow": // 跟随勇士 + this.next = MotaActionBlocks['follow_s'].xmlText([data.name||"", this.next]); + break; + case "unfollow": // 取消跟随 + this.next = MotaActionBlocks['unfollow_s'].xmlText([data.name||"", this.next]); + break; case "animate": // 显示动画 var animate_loc = data.loc||''; if(animate_loc && animate_loc!=='hero')animate_loc = animate_loc[0]+','+animate_loc[1]; diff --git a/_server/comment.js b/_server/comment.js index 858dcb03..982424a4 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -27,11 +27,13 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "name": { "_leaf": true, "_type": "textarea", + "_string": true, "_data": "名称" }, "text": { "_leaf": true, "_type": "textarea", + "_string": true, "_data": "道具在道具栏中显示的描述" } } @@ -39,26 +41,30 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "itemEffect": { "_leaf": true, "_type": "textarea", + "_string": true, "_lint": true, - "_data": "cls为items的即捡即用类物品的效果,如需设置可以先将其设置为空字符串\"\",然后双击进行编辑。" + "_data": "cls为items的即捡即用类物品的效果。" }, "itemEffectTip": { "_leaf": true, "_type": "textarea", + "_string": true, "_lint": true, - "_data": "cls为items的即捡即用类物品,在获得时左上角额外显示的文字,如需设置可以先将其设置为空字符串\"\",然后双击进行编辑。" + "_data": "cls为items的即捡即用类物品,在获得时左上角额外显示的文字。" }, "useItemEffect": { "_leaf": true, "_type": "textarea", + "_string": true, "_lint": true, - "_data": "cls为tools或contants时的使用物品效果,如需设置可以先将其设置为空字符串\"\",然后双击进行编辑。" + "_data": "cls为tools或contants时的使用物品效果。" }, "canUseItemEffect": { "_leaf": true, "_type": "textarea", + "_string": true, "_lint": true, - "_data": "cls为tools或contants时对当前能否使用该物品的判断,如需设置可以先将其设置为空字符串\"\",然后双击进行编辑。" + "_data": "cls为tools或contants时对当前能否使用该物品的判断。" } } }, @@ -70,6 +76,7 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "name": { "_leaf": true, "_type": "textarea", + "_string": true, "_data": "名称" }, "hp": { diff --git a/_server/editor.js b/_server/editor.js index 549d5c55..ebbbd889 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -674,8 +674,8 @@ editor.prototype.listen = function () { var locStr='('+editor.lastRightButtonPos[1].x+','+editor.lastRightButtonPos[1].y+')'; var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft; var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; - copyLoc.children[0].innerHTML='复制此事件到'+locStr; - moveLoc.children[0].innerHTML='移动此事件到'+locStr; + copyLoc.children[0].innerHTML='复制事件'+locStr+'到此处'; + moveLoc.children[0].innerHTML='交换事件'+locStr+'与此事件的位置'; midMenu.style='top:'+(y+scrollTop)+'px;left:'+(x+scrollLeft)+'px;'; } editor.hideMidMenu=function(){midMenu.style='display:none';} @@ -730,21 +730,22 @@ editor.prototype.listen = function () { e.stopPropagation(); preMapData = null; reDo = null; - var thisevent = editor.map[editor.pos.y][editor.pos.x]; - if(thisevent==0){ - editor.info = 0; - } else { - var ids=editor.indexs[thisevent.idnum]; - ids=ids[0]?ids[0]:ids; - editor.info=editor.ids[ids]; - } editor_mode.onmode(''); var now = editor.pos; var last = editor.lastRightButtonPos[1]; - editor.map[last.y][last.x]=editor.info; + var lastevent = editor.map[last.y][last.x]; + var lastinfo = 0; + if(lastevent==0){ + lastinfo = 0; + } else { + var ids=editor.indexs[lastevent.idnum]; + ids=ids[0]?ids[0]:ids; + lastinfo=editor.ids[ids]; + } + editor.map[now.y][now.x]=lastinfo; editor.updateMap(); fields.forEach(function(v){ - editor.currentFloorData[v][last.x+','+last.y]=editor.currentFloorData[v][now.x+','+now.y] + editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y] }) editor.file.saveFloorFile(function (err) { if (err) { diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index c547ebef..a128b493 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -18,17 +18,17 @@ editor_blockly = function () { {"type": "hide", "time": 500}, ],'event'), MotaActionBlocks['changeFloor_m'].xmlText(), - MotaActionFunctions.actionParser.parse({"type": "choices", "choices": [ - {"text": "攻击+\${point}", "action": [ - {"type": "setValue", "name": "status:atk", "value": "status:atk+\${point}"}, - ]}, - {"text": "防御+\${2*point}", "action": [ - {"type": "setValue", "name": "status:def", "value": "status:def+\${2*point}"}, - ]}, - {"text": "生命+\${200*point}", "action": [ - {"type": "setValue", "name": "status:hp", "value": "status:hp+\${200*point}"}, - ]}, - ]},'point'), + //MotaActionFunctions.actionParser.parse({"type": "choices", "choices": [ + // {"text": "攻击+\${point}", "action": [ + // {"type": "setValue", "name": "status:atk", "value": "status:atk+\${point}"}, + // ]}, + // {"text": "防御+\${2*point}", "action": [ + // {"type": "setValue", "name": "status:def", "value": "status:def+\${2*point}"}, + // ]}, + // {"text": "生命+\${200*point}", "action": [ + // {"type": "setValue", "name": "status:hp", "value": "status:hp+\${200*point}"}, + // ]}, + //]},'point'), MotaActionFunctions.actionParser.parse([{ "id": "moneyShop1", "name": "贪婪之神", @@ -69,7 +69,6 @@ editor_blockly = function () { MotaActionBlocks['showGif_1_s'].xmlText(), MotaActionBlocks['moveImage_0_s'].xmlText(), MotaActionBlocks['tip_s'].xmlText(), - MotaActionBlocks['openShop_s'].xmlText(), MotaActionBlocks['win_s'].xmlText(), MotaActionBlocks['lose_s'].xmlText(), MotaActionBlocks['choices_s'].xmlText([ @@ -91,8 +90,11 @@ editor_blockly = function () { MotaActionBlocks['changePos_1_s'].xmlText(), MotaActionBlocks['battle_s'].xmlText(), MotaActionBlocks['openDoor_s'].xmlText(), + MotaActionBlocks['openShop_s'].xmlText(), MotaActionBlocks['setBlock_s'].xmlText(), MotaActionBlocks['setHeroIcon_s'].xmlText(), + MotaActionBlocks['follow_s'].xmlText(), + MotaActionBlocks['unfollow_s'].xmlText(), '', MotaActionBlocks['if_s'].xmlText(), MotaActionBlocks['while_s'].xmlText(), @@ -269,6 +271,18 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ } } } + if(editor_blockly.workspace.topBlocks_.length>=2){ + codeAreaHL.setValue('入口方块只能有一个'); + return; + } + var eventType = document.getElementById('entryType').value; + if(editor_blockly.workspace.topBlocks_.length==1){ + var blockType = editor_blockly.workspace.topBlocks_[0].type; + if(blockType!==eventType+'_m'){ + codeAreaHL.setValue('入口方块类型错误'); + return; + } + } try { var code = Blockly.JavaScript.workspaceToCode(workspace); codeAreaHL.setValue(code); @@ -413,6 +427,18 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ editor_blockly.id = ''; return; } + if(editor_blockly.workspace.topBlocks_.length>=2){ + codeAreaHL.setValue('入口方块只能有一个'); + return; + } + var eventType = document.getElementById('entryType').value; + if(editor_blockly.workspace.topBlocks_.length==1){ + var blockType = editor_blockly.workspace.topBlocks_[0].type; + if(blockType!==eventType+'_m'){ + codeAreaHL.setValue('入口方块类型错误'); + return; + } + } var setvalue = function (value) { var thisTr = document.getElementById(editor_blockly.id); editor_blockly.id = ''; @@ -422,7 +448,7 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){ input.onchange(); } if (codeAreaHL.getValue() === '') { - setvalue('null'); + eventType==='shop'?setvalue('[]'):setvalue('null'); return; } var code = Blockly.JavaScript.workspaceToCode(editor_blockly.workspace); diff --git a/_server/editor_mode.js b/_server/editor_mode.js index bc8ff3e1..8b263262 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -120,7 +120,7 @@ editor_mode = function (editor) { } input.ondblclick = function () { if (cobj._type === 'event') editor_blockly.import(guid, {type: cobj._event}); - if (cobj._type === 'textarea') editor_multi.import(guid, {lint: cobj._lint}); + if (cobj._type === 'textarea') editor_multi.import(guid, {lint: cobj._lint, string: cobj._string}); } }); diff --git a/_server/editor_multi.js b/_server/editor_multi.js index 739ae55d..2c426991 100644 --- a/_server/editor_multi.js +++ b/_server/editor_multi.js @@ -72,7 +72,7 @@ editor_multi = function () { editor_multi.lintAutocomplete = false; if (args.lint === true) editor_multi.lintAutocomplete = true; if (field.indexOf('Effect') !== -1) editor_multi.lintAutocomplete = true; - if (input.value.slice(0, 1) === '"') { + if (input.value.slice(0, 1) === '"' || args.string) { editor_multi.isString = true; codeEditor.setValue(JSON.parse(input.value) || ''); } else { diff --git a/docs/event.md b/docs/event.md index 814a2ff7..3e83793f 100644 --- a/docs/event.md +++ b/docs/event.md @@ -617,6 +617,38 @@ time为可选的,指定的话将作为楼层切换动画的时间。 使用disableShop可以永久禁用全局商店直到再次被openShop打开为止。有关全局商店的说明可参见[全局商店](#全局商店)。 +### follow:跟随勇士 + +使用 `{"type": "follow"}` 可以让一个npc加入跟随。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "follow", "name": "npc.png"}, // 将 npc.png 这个行走图加入跟随 + {"type": "follow", "name": "hero.png"}, // 再将另一个行走图加入跟随 +] +``` + +name为必须的,是要加入跟随的行走图文件名。 + +name所指定的图片必须存在,在全塔属性中的images中被定义过,且是一个合法的行走图(宽为128像素,高不限。) + +### unfollow:取消跟随 + +使用 `{"type": "unfollow"}` 来取消一个跟随。 + +``` js +"x,y": [ // 实际执行的事件列表 + {"type": "unfollow", "name": "npc.png"}, // 将 npc.png 这个行走图取消跟随 + {"type": "follow"}, // 取消所有跟随 +] +``` + +name为可选的,是要取消跟随的行走图文件名。 + +如果name指定了,则会检查所有当前正在跟随的行走图,并删除第一个文件名是name的跟随效果。 + +如果name省略,则会取消所有的跟随效果。 + ### animate:显示动画 我们可以使用 `{"type": "animate"}` 来显示一段动画。 diff --git a/libs/control.js b/libs/control.js index b848ec69..51622c78 100644 --- a/libs/control.js +++ b/libs/control.js @@ -92,10 +92,10 @@ control.prototype.setRequestAnimationFrame = function () { if (timestamp-core.animateFrame.moveTime>16 && core.isset(core.status.heroMoving) && core.status.heroMoving>0) { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); if (core.status.heroMoving<=4) { - core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); + core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving); } else if (core.status.heroMoving<=8) { - core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving*scan[direction].x, 4*core.status.heroMoving*scan[direction].y); + core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving); } core.animateFrame.moveTime = timestamp; } @@ -379,6 +379,25 @@ control.prototype.clearContinueAutomaticRoute = function () { core.status.automaticRoute.moveStepBeforeStop=[]; } +////// 瞬间移动 ////// +control.prototype.moveDirectly = function (destX, destY) { + var ignoreSteps = core.canMoveDirectly(destX, destY); + if (ignoreSteps>0) { + core.clearMap('hero', 0, 0, 416, 416); + var lastDirection = core.status.route[core.status.route.length-1]; + if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0) + core.setHeroLoc('direction', lastDirection); + core.setHeroLoc('x', destX); + core.setHeroLoc('y', destY); + core.drawHero(); + core.status.route.push("move:"+destX+":"+destY); + core.status.hero.statistics.moveDirectly++; + core.status.hero.statistics.ignoreSteps+=ignoreSteps; + return true; + } + return false; +} + ////// 设置自动寻路路线 ////// control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { if (!core.status.played || core.status.lockControl) { @@ -392,19 +411,7 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { core.status.automaticRoute.moveDirectly = true; setTimeout(function () { if (core.status.automaticRoute.moveDirectly && core.status.heroMoving==0) { - var ignoreSteps = core.canMoveDirectly(destX, destY); - if (ignoreSteps>0) { - core.clearMap('hero', 0, 0, 416, 416); - var lastDirection = core.status.route[core.status.route.length-1]; - if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0) - core.setHeroLoc('direction', lastDirection); - core.setHeroLoc('x', destX); - core.setHeroLoc('y', destY); - core.drawHero(); - core.status.route.push("move:"+destX+":"+destY); - core.status.hero.statistics.moveDirectly++; - core.status.hero.statistics.ignoreSteps+=ignoreSteps; - } + core.control.moveDirectly(destX, destY); } core.status.automaticRoute.moveDirectly = false; }, 100); @@ -429,17 +436,8 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { // 单击瞬间移动 if (core.status.automaticRoute.clickMoveDirectly && core.status.heroStop) { - var ignoreSteps = core.canMoveDirectly(destX, destY); - if (ignoreSteps>0) { - core.clearMap('hero', 0, 0, 416, 416); - core.setHeroLoc('x', destX); - core.setHeroLoc('y', destY); - core.drawHero(); - core.status.route.push("move:"+destX+":"+destY); - core.status.hero.statistics.moveDirectly++; - core.status.hero.statistics.ignoreSteps+=ignoreSteps; + if (core.control.moveDirectly(destX, destY)) return; - } } var step = 0; @@ -656,8 +654,9 @@ control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { core.interval.heroMoveInterval = window.setInterval(function () { core.status.heroMoving+=toAdd; if (core.status.heroMoving>=8) { - core.setHeroLoc('x', x+scan[direction].x); - core.setHeroLoc('y', y+scan[direction].y); + core.setHeroLoc('x', x+scan[direction].x, true); + core.setHeroLoc('y', y+scan[direction].y, true); + core.control.updateFollowers(); core.moveOneStep(); core.clearMap('hero', 0, 0, 416, 416); core.drawHero(direction); @@ -837,15 +836,16 @@ control.prototype.eventMoveHero = function(steps, time, callback) { core.setHeroLoc('direction', direction); step++; if (step <= 4) { - core.drawHero(direction, x, y, 'leftFoot', 4 * step * scan[direction].x, 4 * step * scan[direction].y); + core.drawHero(direction, x, y, 'leftFoot', 4 * step); } else if (step <= 8) { - core.drawHero(direction, x, y, 'rightFoot', 4 * step * scan[direction].x, 4 * step * scan[direction].y); + core.drawHero(direction, x, y, 'rightFoot', 4 * step); } if (step == 8) { step = 0; - core.setHeroLoc('x', x + scan[direction].x); - core.setHeroLoc('y', y + scan[direction].y); + core.setHeroLoc('x', x + scan[direction].x, true); + core.setHeroLoc('y', y + scan[direction].y, true); + core.control.updateFollowers(); moveSteps.shift(); } } @@ -891,12 +891,16 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { curry = (curry * jump_count + ey) / (jump_count + 1.0); } + if (core.isset(core.status.hero.followers) && core.status.hero.followers.length>0) + core.clearMap('hero'); + var animate=window.setInterval(function() { if (jump_count>0) { core.clearMap('hero', drawX(), drawY()-height+32, 32, height); updateJump(); - core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, drawX(), drawY() + 32-height, 32, height); } + core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, drawX(), drawY() + 32-height, 32, height); + } else { clearInterval(animate); core.setHeroLoc('x', ex); @@ -954,33 +958,72 @@ control.prototype.stopHero = function () { } ////// 绘制勇士 ////// -control.prototype.drawHero = function (direction, x, y, status, offsetX, offsetY) { - offsetX = offsetX || 0; - offsetY = offsetY || 0; - var dx=offsetX==0?0:offsetX/Math.abs(offsetX), dy=offsetY==0?0:offsetY/Math.abs(offsetY); +control.prototype.drawHero = function (direction, x, y, status, offset) { + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + if (!core.isset(x)) x = core.getHeroLoc('x'); if (!core.isset(y)) y = core.getHeroLoc('y'); - core.clearAutomaticRouteNode(x+dx, y+dy); - x = x * 32; - y = y * 32; status = status || 'stop'; - var heroIcon = core.material.icons.hero[direction || core.getHeroLoc('direction')]; - core.canvas.hero.clearRect(x - 32, y - 32, 96, 96); - var height=core.material.icons.hero.height; - core.canvas.hero.drawImage(core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, x + offsetX, y + offsetY + 32-height, 32, height); + direction = direction || core.getHeroLoc('direction'); + offset = offset || 0; + var dx=offset==0?0:scan[direction].x, dy=offset==0?0:scan[direction].y; + core.clearAutomaticRouteNode(x+dx, y+dy); + core.canvas.hero.clearRect(32 * x - 32, 32 * y - 32, 96, 96); + + var heroIconArr = core.material.icons.hero; + var drawObjs = []; + // add hero + drawObjs.push({ + "img": core.material.images.hero, + "height": core.material.icons.hero.height, + "heroIcon": heroIconArr[direction], + "posx": 32 * x + scan[direction].x*offset, + "posy": 32 * y + scan[direction].y*offset, + "status": status, + "index": 0, + }); + + // Add other followers + if (core.isset(core.status.hero.followers)) { + var index=1; + core.status.hero.followers.forEach(function (t) { + core.canvas.hero.clearRect(32*t.x-32, 32*t.y-32, 96, 96); + if (core.isset(core.material.images.images[t.img])) { + drawObjs.push({ + "img": core.material.images.images[t.img], + "height": core.material.images.images[t.img].height/4, + "heroIcon": heroIconArr[t.direction], + "posx": 32*t.x + (t.stop?0:scan[t.direction].x*offset), + "posy": 32*t.y + (t.stop?0:scan[t.direction].y*offset), + "status": t.stop?"stop":status, + "index": index++ + }); + } + }); + } + + drawObjs.sort(function (a, b) { + return a.posy==b.posy?b.index-a.index:a.posy-b.posy; + }) + + drawObjs.forEach(function (block) { + core.canvas.hero.drawImage(block.img, block.heroIcon[block.status]*32, + block.heroIcon.loc * block.height, 32, block.height, + block.posx, block.posy+32-block.height, 32, block.height); + }) } ////// 设置勇士的位置 ////// -control.prototype.setHeroLoc = function (itemName, itemVal) { - if (itemVal == '++') { - core.status.hero.loc[itemName]++; - return; - } - else if (itemVal == '--') { - core.status.hero.loc[itemName]--; - return; - } +control.prototype.setHeroLoc = function (itemName, itemVal, noGather) { core.status.hero.loc[itemName] = itemVal; + if ((itemName=='x' || itemName=='y') && !noGather) { + this.gatherFollowers(); + } } ////// 获得勇士的位置 ////// @@ -1011,6 +1054,62 @@ control.prototype.nextY = function (n) { return core.getHeroLoc('y')+scan[core.getHeroLoc('direction')].y*(n||1); } +////// 聚集跟随者 ////// +control.prototype.gatherFollowers = function () { + if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return; + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), dir=core.getHeroLoc('direction'); + core.status.hero.followers.forEach(function (t) { + t.x = x; + t.y = y; + t.stop = true; + t.direction = dir; + }); +} + +////// 更新跟随者坐标 ////// +control.prototype.updateFollowers = function () { + if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return; + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; + core.status.hero.followers.forEach(function (t) { + if (!t.stop) { + t.x += scan[t.direction].x; + t.y += scan[t.direction].y; + } + }) + + var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y'); + core.status.hero.followers.forEach(function (t) { + if (t.x == nowx && t.y == nowy) { + t.stop = true; + } + else { + var dx = nowx-t.x, dy = nowy-t.y; + if (dx==-1) { + t.stop=false; + t.direction='left'; + } + else if (dx==1) { + t.stop=false; + t.direction='right'; + } + else if (dy==-1) { + t.stop=false; + t.direction='up'; + } + else if (dy==1) { + t.stop=false; + t.direction='down'; + } + } + nowx=t.x; nowy=t.y; + }) +} + ////// 更新领域、夹击、阻击的伤害地图 ////// control.prototype.updateCheckBlock = function() { core.status.checkBlock = {}; @@ -1509,25 +1608,26 @@ control.prototype.updateFg = function () { } ////// 执行一个表达式的effect操作 ////// -control.prototype.doEffect = function (expression) { - // 必须使用"+=" - var arr = expression.split("+="); - if (arr.length!=2) return; - var name=arr[0], value=core.calValue(arr[1]); - if (name.indexOf("status:")==0) { - var status=name.substring(7); - core.setStatus(status, core.getStatus(status)+value); - } - else if (name.indexOf("item:")==0) { - var itemId=name.substring(5); - core.setItem(itemId, core.itemCount(itemId)+value); - } +control.prototype.doEffect = function (effect) { + effect.split(";").forEach(function (expression) { + var arr = expression.split("+="); + if (arr.length!=2) return; + var name=arr[0], value=core.calValue(arr[1]); + if (name.indexOf("status:")==0) { + var status=name.substring(7); + core.setStatus(status, core.getStatus(status)+value); + } + else if (name.indexOf("item:")==0) { + var itemId=name.substring(5); + core.setItem(itemId, core.itemCount(itemId)+value); + } + }); } ////// 开启debug模式 ////// control.prototype.debug = function() { core.setFlag('debug', true); - core.insertAction(["\t[调试模式开启]此模式下按住Ctrl键可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"]); + core.insertAction(["\t[调试模式开启]此模式下按住Ctrl键(或Ctrl+Shift键)可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"]); /* core.setStatus('hp', 999999); core.setStatus('atk', 10000); @@ -1822,16 +1922,7 @@ control.prototype.replay = function () { else if (action.indexOf('move:')==0) { var pos=action.substring(5).split(":"); var x=parseInt(pos[0]), y=parseInt(pos[1]); - - var ignoreSteps = core.canMoveDirectly(x, y); - if (ignoreSteps>0) { - core.clearMap('hero', 0, 0, 416, 416); - core.setHeroLoc('x', x); - core.setHeroLoc('y', y); - core.drawHero(); - core.status.route.push("move:"+x+":"+y); - core.status.hero.statistics.moveDirectly++; - core.status.hero.statistics.ignoreSteps+=ignoreSteps; + if (core.control.moveDirectly(x,y)) { core.replay(); return; } @@ -2225,6 +2316,7 @@ control.prototype.loadData = function (data, callback) { ////// 设置勇士属性 ////// control.prototype.setStatus = function (statusName, statusVal) { + if (statusName == 'exp') statusName = 'experience'; if (core.isset(core.status.hero.loc[statusName])) core.status.hero.loc[statusName] = statusVal; else @@ -2236,6 +2328,7 @@ control.prototype.getStatus = function (statusName) { // support status:x if (core.isset(core.status.hero.loc[statusName])) return core.status.hero.loc[statusName]; + if (statusName == 'exp') statusName = 'experience'; return core.status.hero[statusName]; } @@ -2446,7 +2539,6 @@ control.prototype.updateStatusBar = function () { core.statusBar.hard.innerHTML = core.status.hard; - // 回放 if (core.status.replay.replaying) { core.statusBar.image.book.src = core.status.replay.pausing?core.statusBar.icons.play.src:core.statusBar.icons.pause.src; diff --git a/libs/core.js b/libs/core.js index ed43bd8a..4ae431dc 100644 --- a/libs/core.js +++ b/libs/core.js @@ -484,13 +484,13 @@ core.prototype.stopHero = function () { } ////// 绘制勇士 ////// -core.prototype.drawHero = function (direction, x, y, status, offsetX, offsetY) { - core.control.drawHero(direction, x, y, status, offsetX, offsetY); +core.prototype.drawHero = function (direction, x, y, status, offset) { + core.control.drawHero(direction, x, y, status, offset); } ////// 设置勇士的位置 ////// -core.prototype.setHeroLoc = function (itemName, itemVal) { - core.control.setHeroLoc(itemName, itemVal); +core.prototype.setHeroLoc = function (itemName, itemVal, noGather) { + core.control.setHeroLoc(itemName, itemVal, noGather); } ////// 获得勇士的位置 ////// diff --git a/libs/enemys.js b/libs/enemys.js index 8cb4b43f..d02cdef3 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -254,13 +254,13 @@ enemys.prototype.getDamageInfo = function(monster, hero_hp, hero_atk, hero_def, mon_atk = hero_atk; mon_def = hero_def; } - // 魔攻 - if (this.hasSpecial(mon_special,2)) hero_def = 0; // 坚固 if (this.hasSpecial(mon_special,3) && mon_def < hero_atk - 1) mon_def = hero_atk - 1; if (hero_atk <= mon_def) return null; // 不可战斗时请直接返回null var per_damage = mon_atk - hero_def; + // 魔攻 + if (this.hasSpecial(mon_special,2)) per_damage = mon_atk; if (per_damage < 0) per_damage = 0; // 2连击 & 3连击 & N连击 diff --git a/libs/events.js b/libs/events.js index b82df54e..f8ff8424 100644 --- a/libs/events.js +++ b/libs/events.js @@ -405,6 +405,42 @@ events.prototype.doAction = function() { this.doAction(); break; } + case "follow": // 跟随 + if (core.isset(core.material.images.images[data.name]) + && core.material.images.images[data.name].width==128) { + if (!core.isset(core.status.hero.followers)) + core.status.hero.followers = []; + core.status.hero.followers.push({"img": data.name}); + core.control.gatherFollowers(); + core.clearMap('hero'); + core.drawHero(); + } + this.doAction(); + break; + case "unfollow": // 取消跟随 + if (core.isset(core.status.hero.followers)) { + var remove = false; + if (!core.isset(data.name) && core.status.hero.followers.length>0) { + core.status.hero.followers = []; + remove=true; + } + if (core.isset(data.name)) { + for (var i=0;i0) - return 0; + // 可以无视起点事件 + // if (core.getBlock(fromX,fromY)!=null||core.status.checkBlock.damage[13*fromX+fromY]>0) + // return 0; // BFS var visited=[], queue=[]; diff --git a/libs/utils.js b/libs/utils.js index 71da66d9..13a9f677 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -631,7 +631,7 @@ utils.prototype.hide = function (obj, speed, callback) { }, speed); } -utils.prototype.export = function (floorIds) { +utils.prototype._export = function (floorIds) { if (!core.isset(floorIds)) floorIds = [core.status.floorId]; else if (floorIds=='all') floorIds = core.clone(core.floorIds); else if (typeof floorIds == 'string') floorIds = [floorIds]; diff --git a/project/items.js b/project/items.js index 7ef11789..1d877352 100644 --- a/project/items.js +++ b/project/items.js @@ -315,15 +315,15 @@ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "canUseItemEffect": { "book": "true", "fly": "core.status.hero.flyRange.indexOf(core.status.floorId)>=0", - "pickaxe": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) &&\n (block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) // 能破哪些墙\n {\n // 四个方向\n if (core.flags.pickaxeFourDirections) {\n if (Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n ids.push(i);\n }\n }\n else {\n if (block.x == core.nextX() && block.y == core.nextY()) {\n ids.push(i);\n }\n }\n }\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", - "icePickaxe": "var able=false;\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n core.status.event.data = [i];\n able=true;\n }\n}\nable", - "bomb": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n var enemy = core.material.enemys[block.event.id];\n if ((core.isset(enemy.bomb) && !enemy.bomb) || (core.isset(enemy.notBomb) && enemy.notBomb)) continue;\n if (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n ids.push(i);\n }\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", - "hammer": "var able=false;\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && block.x==core.nextX() && block.y==core.nextY()) {\n var enemy = core.material.enemys[block.event.id];\n ((core.isset(enemy.bomb) && !enemy.bomb) || (core.isset(enemy.notBomb) && enemy.notBomb)) continue;\n core.status.event.data = [i];\n able=true;\n }\n}\nable", + "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) && !(core.isset(block.enable) && !block.enable) \n\t\t&& Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1\n\t\t&& (block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) // 能破哪些墙\n\t{\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) && !(core.isset(block.enable) && !block.enable) && 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) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && \n\t\tMath.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.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) && !(core.isset(block.enable) && !block.enable) && block.event.cls.indexOf('enemy')==0 && \n\t\tMath.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.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 var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && (block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) // 能炸的墙壁\n ids.push(i);\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", "centerFly": "var able=false;\nvar toX = 12 - core.getHeroLoc('x'), toY = 12-core.getHeroLoc('y');\nvar block = core.getBlock(toX, toY);\nif (block==null) {\n core.status.event.data = {'x': toX, 'y': toY};\n able = true;\n}\nable", "upFly": "var able=false;\nvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\nif (index0) {\n\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\tif (core.getBlock(toX, toY, toId)==null) {\n\t\tcore.status.event.data = {'id': toId, 'x': toX, 'y': toY};\n\t\table=true;\n\t}\n}\nable", - "snow": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.id == 'lava') {\n\t\tif (core.flags.snowFourDirections) {\n if (Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n ids.push(i);\n }\n }\n else {\n if (block.x == core.nextX() && block.y == core.nextY()) {\n ids.push(i);\n }\n }\n }\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", + "snow": "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) && !(core.isset(block.enable) && !block.enable) \n\t\t&& block.event.id == 'lava' && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n\t\tif (core.flags.snowFourDirections || (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", "bigKey": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable) && block.event.id == 'yellowDoor') {\n ids.push(i);\n }\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", "poisonWine": "core.hasFlag('poison')", "weakWine": "core.hasFlag('weak')", diff --git a/styles.css b/styles.css index 2021c874..2cf08287 100644 --- a/styles.css +++ b/styles.css @@ -195,6 +195,7 @@ margin: 0; color: white; font: bold italic 1.1em Verdana; + white-space: nowrap; } #toolBar { position: absolute; diff --git a/启动服务.exe b/启动服务.exe index 95d5d1f7..9c706675 100644 Binary files a/启动服务.exe and b/启动服务.exe differ diff --git a/更新说明.txt b/更新说明.txt index ef07cf76..8a977687 100644 --- a/更新说明.txt +++ b/更新说明.txt @@ -1,4 +1,18 @@ -HTML5魔塔样板V2.3.1 +HTML5魔塔样板V2.3.2 + +启动服务的多开版本 √ +跟随效果 √ +怪物数据导出器 +gif播放可随着分辨率自动放缩 √ +状态栏可随文字长度自动调整放缩 √ +也可以用status:exp来代替经验值的写法 √ +破炸在周围只有一个目标时无需转向面对它 √ +道具效果中,无需再将null改成""才能双击编辑了 √ +各个已知Bug的修复,部分细节优化 √ + +----------------------------------------------------------------------- + +HTML5魔塔样板V2.3.1 存档采用高比率压缩,单个大小是原来的1/10! 默认存档数改成100页500个