From 2b1dd2ffe73b648b6953f6a2c03c9c7fb7f3a70b Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 29 Oct 2018 16:47:51 +0800 Subject: [PATCH 1/9] drawPaint --- libs/actions.js | 79 ++++++++++++------------------------------------- libs/core.js | 1 + libs/ui.js | 16 +++++++++- libs/utils.js | 52 ++++++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 61 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 5b6c1ee5..4c5fa4c7 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -362,10 +362,15 @@ actions.prototype.keyUp = function(keyCode, altKey) { } break; case 33: case 34: // PAGEUP/PAGEDOWN - if (core.status.heroStop) { - core.ui.drawMaps(); - } - break; + if (core.status.heroStop) + core.ui.drawMaps(); + break; + case 77: // M + if (core.status.heroStop) { + core.ui.drawPaint(); + core.drawTip("打开画图模式"); + } + break; case 37: // UP break; case 38: // DOWN @@ -1924,13 +1929,16 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawQuickShop(); break; case 2: - core.ui.drawMaps(); + core.ui.drawPaint(); break; case 3: + core.ui.drawMaps(); + break; + case 4: core.status.event.selection=0; core.ui.drawSyncSave(); break; - case 4: + case 5: core.status.event.selection=1; core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () { core.ui.closePanel(); @@ -1940,65 +1948,16 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawSettings(); }); break; - case 5: - core.ui.drawStatistics(); - /* - core.ui.drawWaiting("正在拉取统计信息,请稍后..."); - - var formData = new FormData(); - formData.append('type', 'statistics'); - formData.append('name', core.firstData.name); - formData.append('version', core.firstData.version); - - var xhr = new XMLHttpRequest(); - xhr.open("POST", "/games/upload.php"); - - xhr.onload = function(e) { - if (xhr.status==200) { - var response = JSON.parse(xhr.response); - if (response.code<0) { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:"+response.msg); - } - else { - var text="\t[本塔统计信息]"; - var toAdd=false; - response.data.forEach(function (t) { - if (toAdd) text+="\n\n"; - toAdd=true; - if (t.hard!='') text+=t.hard+"难度: " - text+="已有"+t.people+"人次游戏,"+t.score+"人次通关。"; - t.info.forEach(function(ending) { - if (ending.ending!='') { - text+="\n"+ending.ending+": 已有"+ending.score+"人次通关。"; - } - if (core.isset(ending.max) && ending.max>0) { - text+="\n当前MAX为"+ending.max+",最早由 "+(ending.username||"匿名")+" 于"+core.formatDate(new Date(1000*ending.timestamp))+"打出。"; - } - }) - }) - core.drawText(text); - } - } - else { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:HTTP "+xhr.status); - } - }; - xhr.ontimeout = function() { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:Timeout"); - } - xhr.onerror = function() { - core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:XHR Error"); - } - xhr.send(formData); - */ - break; case 6: - core.ui.drawHelp(); + core.ui.drawStatistics(); break; case 7: - core.ui.drawAbout(); + core.ui.drawHelp(); break; case 8: + core.ui.drawAbout(); + break; + case 9: core.ui.closePanel(); break; } diff --git a/libs/core.js b/libs/core.js index d15765ae..e47d56ce 100644 --- a/libs/core.js +++ b/libs/core.js @@ -81,6 +81,7 @@ function core() { height: 13, tempCanvas: null, // A temp canvas for drawing } + this.paint = {} this.initStatus = { 'played': false, 'gameOver': false, diff --git a/libs/ui.js b/libs/ui.js index 381536ab..3bb36e91 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -836,7 +836,7 @@ ui.prototype.drawSettings = function () { core.status.event.id = 'settings'; this.drawChoices(null, [ - "系统设置", "快捷商店", "浏览地图", "同步存档", "返回标题", "数据统计", "操作帮助", "关于本塔", "返回游戏" + "系统设置", "快捷商店", "浏览地图", "打开画板", "同步存档", "返回标题", "数据统计", "操作帮助", "关于本塔", "返回游戏" ]); } @@ -2417,6 +2417,20 @@ ui.prototype.drawAbout = function () { return this.uidata.drawAbout(); } +////// 绘制“画图”界面 ////// +ui.prototype.drawPaint = function () { + + core.lockControl(); + core.status.event.id = 'paint'; + + core.clearMap('ui'); + core.clearMap('route'); + + // 将已有的内容绘制到route上 + core.utils.decodeCanvas(core.paint[core.status.floorId], 32*core.bigmap.width, 32*core.bigmap.height); + core.canvas.route.drawImage(core.bigmap.tempCanvas, 0, 0); +} + ////// 绘制帮助页面 ////// ui.prototype.drawHelp = function () { core.drawText([ diff --git a/libs/utils.js b/libs/utils.js index ee7a845c..f5bd1ffd 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -726,6 +726,58 @@ utils.prototype.hide = function (obj, speed, callback) { }, speed); } +utils.prototype.encodeCanvas = function (ctx) { + var list = []; + var width = ctx.canvas.width, height = ctx.canvas.height; + ctx.mozImageSmoothingEnabled = false; + ctx.webkitImageSmoothingEnabled = false; + ctx.msImageSmoothingEnabled = false; + ctx.imageSmoothingEnabled = false; + + var imgData = ctx.getImageData(0, 0, width, height); + for (var i=0;i threshold; From 6488b355e879f8f501ca338f53877aea54793d83 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 29 Oct 2018 20:23:10 +0800 Subject: [PATCH 2/9] paint on route --- libs/actions.js | 69 +++++++++++++++++++++++++++++++++++++++++++------ libs/core.js | 12 ++++----- libs/ui.js | 17 ++++++++++-- main.js | 25 +++++++++--------- 4 files changed, 95 insertions(+), 28 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 4c5fa4c7..0546b0a4 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -368,7 +368,6 @@ actions.prototype.keyUp = function(keyCode, altKey) { case 77: // M if (core.status.heroStop) { core.ui.drawPaint(); - core.drawTip("打开画图模式"); } break; case 37: // UP @@ -443,9 +442,18 @@ actions.prototype.keyUp = function(keyCode, altKey) { } ////// 点击(触摸)事件按下时 ////// -actions.prototype.ondown = function (x ,y) { +actions.prototype.ondown = function (loc) { if (core.isset(core.status.replay)&&core.status.replay.replaying &&core.status.event.id!='save'&&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') return; + + // 画板 + if (core.status.played && (core.status.event||{}).id=='paint') { + this.ondownPaint(loc.x, loc.y); + return; + } + + var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); + if (!core.status.played || core.status.lockControl) { this.onclick(x, y, []); if (core.timeout.onDownTimeout==null) { @@ -472,11 +480,18 @@ actions.prototype.ondown = function (x ,y) { } ////// 当在触摸屏上滑动时 ////// -actions.prototype.onmove = function (x ,y) { +actions.prototype.onmove = function (loc) { if (core.isset(core.status.replay)&&core.status.replay.replaying &&core.status.event.id!='save'&&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') return; - // if (core.status.holdingPath==0){return;} - //core.status.mouseOutCheck =1; + + // 画板 + if (core.status.played && (core.status.event||{}).id=='paint') { + this.onmovePaint(loc.x, loc.y) + return; + } + + var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); + var pos={'x':x,'y':y}; var pos0=core.status.stepPostfix[core.status.stepPostfix.length-1]; var directionDistance=[pos.y-pos0.y,pos0.x-pos.x,pos0.y-pos.y,pos.x-pos0.x]; @@ -497,10 +512,18 @@ actions.prototype.onmove = function (x ,y) { } ////// 当点击(触摸)事件放开时 ////// -actions.prototype.onup = function () { +actions.prototype.onup = function (loc) { if (core.isset(core.status.replay)&&core.status.replay.replaying &&core.status.event.id!='save'&&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') return; + // 画板 + if (core.status.played && (core.status.event||{}).id=='paint') { + this.onupPaint(loc.x, loc.y) + return; + } + + var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); + clearTimeout(core.timeout.onDownTimeout); core.timeout.onDownTimeout = null; clearInterval(core.interval.onDownInterval); @@ -1929,10 +1952,10 @@ actions.prototype.clickSettings = function (x,y) { core.ui.drawQuickShop(); break; case 2: - core.ui.drawPaint(); + core.ui.drawMaps(); break; case 3: - core.ui.drawMaps(); + core.ui.drawPaint(); break; case 4: core.status.event.selection=0; @@ -2507,3 +2530,33 @@ actions.prototype.clickAbout = function () { else core.restart(); } + +actions.prototype.ondownPaint = function (x, y) { + console.log("ondown: ("+x+","+y+")"); + + core.canvas.route.beginPath(); + core.canvas.route.moveTo(x+core.bigmap.offsetX, y+core.bigmap.offsetY); + core.status.event.data.x = x; + core.status.event.data.y = y; +} + +actions.prototype.onmovePaint = function (x, y) { + if (core.status.event.data.x==null) return; + var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; + core.canvas.route.quadraticCurveTo(midx, midy, x, y); + core.canvas.route.stroke(); + core.status.event.data.x = x; + core.status.event.data.y = y; +} + +actions.prototype.onupPaint = function (x,y) { + console.log("onup: ("+x+","+y+")"); + var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; + core.canvas.route.quadraticCurveTo(midx, midy, x, y); + core.canvas.route.stroke(); + + core.status.event.data.x = null; + core.status.event.data.y = null; + // 保存 + core.paint[core.status.floorId] = LZString.compress(core.utils.encodeCanvas(core.canvas.route).join(",")); +} diff --git a/libs/core.js b/libs/core.js index e47d56ce..38f0f4d8 100644 --- a/libs/core.js +++ b/libs/core.js @@ -396,18 +396,18 @@ core.prototype.keyUp = function(keyCode, altKey) { } ////// 点击(触摸)事件按下时 ////// -core.prototype.ondown = function (x ,y) { - return core.actions.ondown(x,y); +core.prototype.ondown = function (loc) { + return core.actions.ondown(loc); } ////// 当在触摸屏上滑动时 ////// -core.prototype.onmove = function (x ,y) { - return core.actions.onmove(x,y); +core.prototype.onmove = function (loc) { + return core.actions.onmove(loc); } ////// 当点击(触摸)事件放开时 ////// -core.prototype.onup = function () { - return core.actions.onup(); +core.prototype.onup = function (loc) { + return core.actions.onup(loc); } ////// 获得点击事件相对左上角的坐标(0到12之间) ////// diff --git a/libs/ui.js b/libs/ui.js index 3bb36e91..2a620b81 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2420,15 +2420,28 @@ ui.prototype.drawAbout = function () { ////// 绘制“画图”界面 ////// ui.prototype.drawPaint = function () { + console.log("drawPaint"); + + core.drawTip("打开绘图模式,现在可以任意在界面上绘图标记"); + core.lockControl(); core.status.event.id = 'paint'; + core.status.event.data = {"x": null, "y": null, "erase": false}; core.clearMap('ui'); core.clearMap('route'); + core.setAlpha('route', 1); + core.setOpacity('route', 1); + // 将已有的内容绘制到route上 - core.utils.decodeCanvas(core.paint[core.status.floorId], 32*core.bigmap.width, 32*core.bigmap.height); - core.canvas.route.drawImage(core.bigmap.tempCanvas, 0, 0); + var value = core.paint[core.status.floorId]; + if (core.isset(value) && typeof value == 'string') value = LZString.decompress(value).split(","); + core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); + core.canvas.route.drawImage(core.bigmap.tempCanvas.canvas, 0, 0); + + core.setLineWidth('route', 3); + core.setStrokeStyle('route', '#FF0000'); } ////// 绘制帮助页面 ////// diff --git a/main.js b/main.js index d411900b..792cca37 100644 --- a/main.js +++ b/main.js @@ -317,8 +317,7 @@ main.dom.data.onmousedown = function (e) { } var loc = main.core.getClickLoc(e.clientX, e.clientY); if (loc == null) return; - var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); - main.core.ondown(x, y); + main.core.ondown(loc); } catch (ee) {} } @@ -328,15 +327,17 @@ main.dom.data.onmousemove = function (e) { e.stopPropagation(); var loc = main.core.getClickLoc(e.clientX, e.clientY); if (loc == null) return; - var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); - main.core.onmove(x, y); + main.core.onmove(loc); }catch (ee) {} } ////// 鼠标放开时 ////// -main.dom.data.onmouseup = function () { +main.dom.data.onmouseup = function (e) { try { - main.core.onup(); + e.stopPropagation(); + var loc = main.core.getClickLoc(e.clientX, e.clientY); + if (loc == null) return; + main.core.onup(loc); }catch (e) {} } @@ -356,9 +357,7 @@ main.dom.data.ontouchstart = function (e) { e.preventDefault(); var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); if (loc == null) return; - var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); - //main.core.onclick(x, y, []); - main.core.ondown(x, y); + main.core.ondown(loc); }catch (ee) {} } @@ -368,15 +367,17 @@ main.dom.data.ontouchmove = function (e) { e.preventDefault(); var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); if (loc == null) return; - var x = parseInt(loc.x / loc.size), y = parseInt(loc.y / loc.size); - main.core.onmove(x, y); + main.core.onmove(loc); }catch (ee) {} } ////// 手指离开触摸屏时 ////// main.dom.data.ontouchend = function () { try { - main.core.onup(); + e.preventDefault(); + var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); + if (loc == null) return; + main.core.onup(loc); } catch (e) { } } From de972f87f407b24b34dbba1002b51c789bb969ba Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 30 Oct 2018 02:26:18 +0800 Subject: [PATCH 3/9] Paint Mode --- docs/element.md | 19 +++++++ libs/actions.js | 110 +++++++++++++++++++++++++++++++++++---- libs/ui.js | 91 +++++++++++++++++++------------- libs/utils.js | 24 ++++++++- main.js | 41 +++++++++++++++ project/images/icons.png | Bin 17595 -> 22029 bytes 6 files changed, 239 insertions(+), 46 deletions(-) diff --git a/docs/element.md b/docs/element.md index bd743bef..75633a11 100644 --- a/docs/element.md +++ b/docs/element.md @@ -369,6 +369,20 @@ HTML5魔塔一大亮点就是存在录像系统,可以很方便进行录像回 如果录像出现问题,请加群539113091找小艾反馈Bug。 +## 绘图模式 + +从V2.5开始,样板提供了绘图模式,可以让玩家在画布上任意进行绘制,标记等。 + +使用M键,或在菜单栏中可以进入绘图模式。 + +**绘图的内容会自动保存,且以页面为生命周期,和存读档无关,返回标题并重新开始游戏后绘制的内容仍有效,但刷新页面就会消失。** + +你可以将绘制内容保存到文件,也可以从文件读取保存的绘制内容。 + +绘图模式下,状态栏的图标也会相应改变,铅笔为绘制模式,橡皮为擦除模式,存读档为保存和读取绘图文件,退出为返回默认值。 + +在浏览地图页面中也可以按楼传按钮或M键来开启/关闭该层的绘图显示。 + ## 操作说明 本塔主要支持鼠标(触摸屏)操作和键盘操作。 @@ -397,10 +411,15 @@ HTML5魔塔一大亮点就是存在录像系统,可以很方便进行录像回 - **[B]** 打开数据统计 - **[H]** 打开帮助页面 - **[R]** 回放录像 +- **[E]** 显示光标 - **[SPACE]** 轻按(仅在轻按开关打开时有效) +- **[M]** 绘图模式 +- **[PgUp/PgDn]** 浏览地图 - **[1]** 快捷使用破墙镐 - **[2]** 快捷使用炸弹/圣锤 - **[3]** 快捷使用中心对称飞行器 +- **[4]** 快捷使用其他道具 +- **[Alt+0~9]** 快捷换装 以上快捷键也能在游戏菜单中的操作说明中看到。 diff --git a/libs/actions.js b/libs/actions.js index 0546b0a4..5b4fff35 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -282,6 +282,9 @@ actions.prototype.keyUp = function(keyCode, altKey) { this.keyUpCenterFly(keyCode); return; } + if (core.status.event.id=='paint') { + this.keyUpPaint(keyCode); + } return; } @@ -1137,10 +1140,17 @@ actions.prototype.keyUpViewMaps = function (keycode) { core.clearMap('data'); core.setOpacity('data', 1); core.ui.closePanel(); + return; } if (keycode==86) { core.status.event.data.damage = !core.status.event.data.damage; - core.ui.drawMaps(core.status.event.data.index, core.status.event.data.x, core.status.event.data.y); + core.ui.drawMaps(core.status.event.data); + return; + } + if (keycode==77) { + core.status.event.data.paint = !core.status.event.data.paint; + core.ui.drawMaps(core.status.event.data); + return; } if (keycode==88 || (core.status.replay.replaying && keycode==67)) { if (core.isset(core.status.replay)&&core.status.replay.replaying) { @@ -1148,6 +1158,7 @@ actions.prototype.keyUpViewMaps = function (keycode) { } else { core.openBook(false); } + return; } return; } @@ -2531,17 +2542,28 @@ actions.prototype.clickAbout = function () { core.restart(); } -actions.prototype.ondownPaint = function (x, y) { - console.log("ondown: ("+x+","+y+")"); - core.canvas.route.beginPath(); - core.canvas.route.moveTo(x+core.bigmap.offsetX, y+core.bigmap.offsetY); +////// 绘图相关 ////// + +actions.prototype.ondownPaint = function (x, y) { + x+=core.bigmap.offsetX; + y+=core.bigmap.offsetY; + if (!core.status.event.data.erase) { + core.canvas.route.beginPath(); + core.canvas.route.moveTo(x, y); + } core.status.event.data.x = x; core.status.event.data.y = y; } actions.prototype.onmovePaint = function (x, y) { if (core.status.event.data.x==null) return; + x+=core.bigmap.offsetX; + y+=core.bigmap.offsetY; + if (core.status.event.data.erase) { + core.clearMap('route', x-10, y-10, 20, 20); + return; + } var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; core.canvas.route.quadraticCurveTo(midx, midy, x, y); core.canvas.route.stroke(); @@ -2550,13 +2572,83 @@ actions.prototype.onmovePaint = function (x, y) { } actions.prototype.onupPaint = function (x,y) { - console.log("onup: ("+x+","+y+")"); - var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; - core.canvas.route.quadraticCurveTo(midx, midy, x, y); - core.canvas.route.stroke(); + x+=core.bigmap.offsetX; + y+=core.bigmap.offsetY; + if (core.status.event.data.erase) { + core.clearMap('route', x-5, y-5, 10, 10); + } + else if (core.status.event.data.x!=null) { + var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; + core.canvas.route.quadraticCurveTo(midx, midy, x, y); + core.canvas.route.stroke(); + } core.status.event.data.x = null; core.status.event.data.y = null; // 保存 core.paint[core.status.floorId] = LZString.compress(core.utils.encodeCanvas(core.canvas.route).join(",")); } + +actions.prototype.setPaintMode = function (mode) { + if (mode == 'paint') core.status.event.data.erase = false; + else if (mode == 'erase') core.status.event.data.erase = true; + else return; + + core.drawTip("进入"+(core.status.event.data.erase?"擦除":"绘图")+"模式"); +} + +actions.prototype.savePaint = function () { + var data = {}; + for (var floorId in core.paint) { + if (core.isset(core.paint[floorId])) + data[floorId] = LZString.decompress(core.paint[floorId]); + } + core.download(core.firstData.name+".h5paint", JSON.stringify({ + 'name': core.firstData.name, + 'paint': data + })); +} + +actions.prototype.loadPaint = function () { + core.readFile(function (obj) { + if (obj.name!=core.firstData.name) { + alert("绘图文件和游戏不一致!"); + return; + } + if (!core.isset(obj.paint)) { + alert("无效的绘图文件!"); + return; + } + core.paint = {}; + for (var floorId in obj.paint) { + if (core.isset(obj.paint[floorId])) + core.paint[floorId] = LZString.compress(obj.paint[floorId]); + } + + core.clearMap('route'); + var value = core.paint[core.status.floorId]; + if (core.isset(value)) value = LZString.decompress(value).split(","); + core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); + core.canvas.route.drawImage(core.bigmap.tempCanvas.canvas, 0, 0); + + core.drawTip("读取绘图文件成功"); + }) +} + +actions.prototype.exitPaint = function () { + core.clearMap('route'); + core.ui.closePanel(); + core.statusBar.image.shop.style.opacity = 1; + core.statusBar.image.toolbox.style.opacity = 1; + core.updateStatusBar(); + core.drawTip("退出绘图模式"); +} + +actions.prototype.keyUpPaint = function (keycode) { + if (keycode==27 || keycode==88 || keycode==77 || keycode==13 || keycode==32 || keycode==67) { + this.exitPaint(); + return; + } +} + +////// 绘图相关 END ////// diff --git a/libs/ui.js b/libs/ui.js index 2a620b81..9636e447 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1645,6 +1645,10 @@ ui.prototype.drawMaps = function (index, x, y) { core.clearMap('animate'); core.setOpacity('animate', 1); + var damage = (core.status.event.data||{}).damage, paint = (core.status.event.data||{}).paint; + if (core.isset(index.damage)) damage=index.damage; + if (core.isset(index.paint)) paint=index.paint; + if (core.isset(index.index)) { x=index.x; y=index.y; @@ -1661,19 +1665,27 @@ ui.prototype.drawMaps = function (index, x, y) { if (y<6) y=6; if (y>mh-7) y=mh-7; - core.status.event.data = {"index": index, "x": x, "y": y, "damage": (core.status.event.data||{"damage":false}).damage}; + core.status.event.data = {"index": index, "x": x, "y": y, "damage": damage, "paint": paint}; clearTimeout(core.interval.tipAnimate); core.clearMap('ui'); core.setAlpha('ui', 1); this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 0, 0, 416, x, y); + // 绘图 + if (core.status.event.data.paint) { + var offsetX = core.clamp(x-6, 0, mw-13), offsetY = core.clamp(y-6, 0, mh-13); + var value = core.paint[floorId]; + if (core.isset(value)) value = LZString.decompress(value).split(","); + core.utils.decodeCanvas(value, 32*mw, 32*mh); + core.canvas.ui.drawImage(core.bigmap.tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, 0, 0, 416, 416); + } + core.clearMap('data'); core.setOpacity('data', 0.2); core.canvas.data.textAlign = 'left'; core.setFont('data', '16px Arial'); - var text = core.status.maps[floorId].title; if (mw>13 || mh>13) text+=" ["+(x-6)+","+(y-6)+"]"; var textX = 16, textY = 18, width = textX + core.canvas.data.measureText(text).width + 16, height = 42; @@ -2420,52 +2432,61 @@ ui.prototype.drawAbout = function () { ////// 绘制“画图”界面 ////// ui.prototype.drawPaint = function () { - console.log("drawPaint"); + core.drawText( + "\t[进入绘图模式]你可以在此页面上任意进行绘图和标记操作。\nM键可以进入或退出此模式。\n\n"+ + "绘图的内容会自动保存,且以页面为生命周期,和存读档无关,重新开始游戏或读档后绘制的内容仍有效,但刷新页面就会消失。\n"+ + "你可以将绘制内容保存到文件,也可以从文件读取保存的绘制内容。\n"+ + "浏览地图页面可以按楼传按钮或M键来开启/关闭该层的绘图显示。\n\n更多功能请详见文档-元件-绘图模式。", + function () { + core.drawTip("打开绘图模式,现在可以任意在界面上绘图标记"); - core.drawTip("打开绘图模式,现在可以任意在界面上绘图标记"); + core.lockControl(); + core.status.event.id = 'paint'; + core.status.event.data = {"x": null, "y": null, "erase": false}; - core.lockControl(); - core.status.event.id = 'paint'; - core.status.event.data = {"x": null, "y": null, "erase": false}; + core.clearMap('ui'); + core.clearMap('route'); - core.clearMap('ui'); - core.clearMap('route'); + core.setAlpha('route', 1); + core.setOpacity('route', 1); - core.setAlpha('route', 1); - core.setOpacity('route', 1); + // 将已有的内容绘制到route上 + var value = core.paint[core.status.floorId]; + if (core.isset(value)) value = LZString.decompress(value).split(","); + core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); + core.canvas.route.drawImage(core.bigmap.tempCanvas.canvas, 0, 0); - // 将已有的内容绘制到route上 - var value = core.paint[core.status.floorId]; - if (core.isset(value) && typeof value == 'string') value = LZString.decompress(value).split(","); - core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); - core.canvas.route.drawImage(core.bigmap.tempCanvas.canvas, 0, 0); + core.setLineWidth('route', 3); + core.setStrokeStyle('route', '#FF0000'); - core.setLineWidth('route', 3); - core.setStrokeStyle('route', '#FF0000'); + core.statusBar.image.shop.style.opacity = 0; + core.statusBar.image.toolbox.style.opacity = 0; + + core.statusBar.image.book.src = core.statusBar.icons.paint.src; + core.statusBar.image.fly.src = core.statusBar.icons.erase.src; + core.statusBar.image.settings.src = core.statusBar.icons.exit.src; + core.statusBar.image.book.style.opacity = 1; + core.statusBar.image.fly.style.opacity = 1; + } + ); } ////// 绘制帮助页面 ////// ui.prototype.drawHelp = function () { core.drawText([ "\t[键盘快捷键列表]"+ - "[CTRL] 跳过对话\n" + - "[Z] 转向\n" + - "[X] 打开/关闭怪物手册\n" + - "[G] 打开/关闭楼层传送器\n" + - "[A] 读取自动存档(回退)\n" + + "[CTRL] 跳过对话 [Z] 转向\n" + + "[X] 怪物手册 [G] 楼层传送\n" + + "[A] 读取自动存档 [S/D] 存读档页面\n" + "[S/D] 打开/关闭存/读档页面\n" + - "[K/V] 打开/关闭快捷商店选择列表\n" + - "[T] 打开/关闭工具栏\n" + - "[ESC] 打开/关闭系统菜单\n" + - "[B] 打开数据统计\n" + - // "[E] 显示光标\n" + - "[H] 打开帮助页面\n"+ - "[R] 回放\n"+ - "[SPACE] 轻按(仅在轻按开关打开时有效)\n" + + "[K/V] 快捷商店 [ESC] 系统菜单\n" + + "[T] 道具页面 [Q] 装备页面\n" + + "[B] 数据统计 [H] 帮助页面\n" + + "[R] 回放录像 [E] 显示光标\n" + + "[SPACE] 轻按 [M] 绘图模式\n" + "[PgUp/PgDn] 浏览地图\n"+ - "[1] 快捷使用破墙镐\n" + - "[2] 快捷使用炸弹/圣锤\n" + - "[3] 快捷使用中心对称飞行器", + "[1~4] 快捷使用破炸飞和其他道具\n"+ + "[Alt+0~9] 快捷换装", "\t[鼠标操作]"+ "点状态栏中图标: 进行对应的操作\n"+ "点任意块: 寻路并移动\n"+ @@ -2473,7 +2494,7 @@ ui.prototype.drawHelp = function () { "双击空地: 瞬间移动\n"+ "单击勇士: 转向\n"+ "双击勇士: 轻按(仅在轻按开关打开时有效)\n"+ - "长按任意位置:跳过剧情对话或打开虚拟键盘\n" + "长按任意位置:跳过剧情对话或打开虚拟键盘" ]); } diff --git a/libs/utils.js b/libs/utils.js index f5bd1ffd..b347f524 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -253,14 +253,14 @@ utils.prototype.cropImage = function (image, size) { ////// 格式化时间为字符串 ////// utils.prototype.formatDate = function(date) { if (!core.isset(date)) return ""; - return date.getFullYear()+"-"+core.setTwoDigits(date.getMonth()+1)+"-"+core.setTwoDigits(date.getDate())+" " + return ""+date.getFullYear()+"-"+core.setTwoDigits(date.getMonth()+1)+"-"+core.setTwoDigits(date.getDate())+" " +core.setTwoDigits(date.getHours())+":"+core.setTwoDigits(date.getMinutes())+":"+core.setTwoDigits(date.getSeconds()); } ////// 格式化时间为最简字符串 ////// utils.prototype.formatDate2 = function (date) { if (!core.isset(date)) return ""; - return date.getFullYear()+core.setTwoDigits(date.getMonth()+1)+core.setTwoDigits(date.getDate()) + return ""+date.getFullYear()+core.setTwoDigits(date.getMonth()+1)+core.setTwoDigits(date.getDate()) +core.setTwoDigits(date.getHours())+core.setTwoDigits(date.getMinutes())+core.setTwoDigits(date.getSeconds()); } @@ -460,6 +460,26 @@ utils.prototype.decodeBase64 = function (str) { }).join('')); } +////// 任意进制转换 ////// +utils.prototype.convertBase = function (str, fromBase, toBase) { + var map = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]\\|:;<>,.?/"; + if (fromBase==toBase) return str; + var len = str.length, ans=""; + var t = []; + for (var i=0;i0) { + for (var i=len; i>=1; i--) { + t[i-1]+=t[i]%toBase*fromBase; + t[i]=parseInt(t[i]/toBase); + } + ans+=map.charAt(t[0]%toBase); + t[0]=parseInt(t[0]/toBase); + while (len>0 && t[len-1]==0) len--; + } + return ans; +} + utils.prototype.__init_seed = function () { var rand = new Date().getTime()%34834795 + 3534; rand = this.__next_rand(rand); diff --git a/main.js b/main.js index 792cca37..1abb2b91 100644 --- a/main.js +++ b/main.js @@ -122,6 +122,11 @@ function main() { 'speedUp': 21, 'rewind': 22, 'equipbox': 23, + 'mana': 24, + 'skill': 25, + 'paint': 26, + 'erase': 27, + 'exit': 28, }, 'floor': document.getElementById('floor'), 'name': document.getElementById('name'), @@ -389,6 +394,11 @@ main.statusBar.image.book.onclick = function () { return; } + if (main.core.isPlaying() && (core.status.event||{}).id=='paint') { + core.actions.setPaintMode('paint'); + return; + } + if (main.core.isPlaying()) main.core.openBook(true); } @@ -396,11 +406,27 @@ main.statusBar.image.book.onclick = function () { ////// 点击状态栏中的楼层传送器/装备栏时 ////// main.statusBar.image.fly.onclick = function () { + // 播放录像时 if (core.isset(core.status.replay) && core.status.replay.replaying) { core.stopReplay(); return; } + // 绘图模式 + if (main.core.isPlaying() && (core.status.event||{}).id=='paint') { + core.actions.setPaintMode('erase'); + return; + } + + // 浏览地图时 + if (main.core.isPlaying() && (core.status.event||{}).id=='viewMaps') { + if (core.isset(core.status.event.data)) { + core.status.event.data.paint = !core.status.event.data.paint; + core.ui.drawMaps(core.status.event.data); + } + return; + } + if (main.core.isPlaying()) { if (!main.core.flags.equipboxButton) { main.core.useFly(true); @@ -457,6 +483,11 @@ main.statusBar.image.save.onclick = function () { return; } + if (main.core.isPlaying() && (core.status.event||{}).id=='paint') { + core.actions.savePaint(); + return; + } + if (main.core.isPlaying()) main.core.save(true); } @@ -469,6 +500,11 @@ main.statusBar.image.load.onclick = function () { return; } + if (main.core.isPlaying() && (core.status.event||{}).id=='paint') { + core.actions.loadPaint(); + return; + } + if (main.core.isPlaying()) main.core.load(true); } @@ -481,6 +517,11 @@ main.statusBar.image.settings.onclick = function () { return; } + if (main.core.isPlaying() && (core.status.event||{}).id=='paint') { + core.actions.exitPaint(); + return; + } + if (main.core.isPlaying()) main.core.openSettings(true); } diff --git a/project/images/icons.png b/project/images/icons.png index cbf4aee4195ddee73487210731d22e59cbdff491..538a2c8f7210626cd09d93cb3b4beb326a629395 100644 GIT binary patch literal 22029 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 l3ZWH{iqWSKDuPV*{{YfGhA Date: Tue, 30 Oct 2018 02:58:21 +0800 Subject: [PATCH 4/9] mana & skill --- _server/data.comment.js | 17 ++++++++++++ docs/personalization.md | 57 +++++++++++++++++++---------------------- editor-mobile.html | 8 ++++++ editor.html | 8 ++++++ index.html | 8 ++++++ libs/control.js | 14 ++++++++++ main.js | 6 +++++ project/data.js | 3 +++ project/functions.js | 14 +++++++++- 9 files changed, 104 insertions(+), 31 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index 7afe0f36..43080322 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -153,6 +153,11 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_data": "初始生命值" }, + "mana": { + "_leaf": true, + "_type": "textarea", + "_data": "初始魔力值,只在enableMana开启时才有效" + }, "atk": { "_leaf": true, "_type": "textarea", @@ -389,6 +394,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否是否启用生命上限" }, + "enableMana": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否开启魔力值" + }, "enableMDef": { "_leaf": true, "_type": "checkbox", @@ -431,6 +442,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否涉及毒衰咒;如果此项为false则不会在状态栏中显示毒衰咒的debuff" }, + "enableSkill": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否启用技能栏" + }, "flyNearStair": { "_leaf": true, "_type": "checkbox", diff --git a/docs/personalization.md b/docs/personalization.md index 30260cd3..c72a346f 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -554,6 +554,8 @@ this.myfunc = function(x) { 通过这种,将脚本和自定义事件混用的方式,可以达到和RM中公共事件类似的效果,即一个调用触发一系列事件。 + + ## 技能塔的支持 其实,在HTML5上制作技能塔是完全可行的。 要支持技能塔,可能需要如下几个方面: -- 魔力(和上限)的定义添加 +- 魔力(和上限)的添加;技能的定义 - 状态栏的显示 - 技能的触发(按键与录像问题) - 技能的效果 -下面依次进行描述。 +从V2.5开始,魔力和技能的定义被内置到了样板中,因此十分方便。 -### 魔力的定义添加 +### 魔力的定义添加;技能的定义 -当我们定义了魔力的ID,比如`mana`后,要使用它,一般有两种方式:属性获取`status:mana`或者flag标记`flag:mana`。 +从V2.5开始,提供了status:mana选项,可以直接代表当前魔力值。 -如果要属性获取,则需要打开`data.js`文件,并在`hero`中添加定义。 +如果要启用,需要开启全塔属性的enableMana选项。 -通过这种方式定义的,可以通过`core.setStatus('mana', 0)`以及`core.getStatus('mana')`来设置或获取。 +如果需要魔力上限,则可以使用flag:manaMax来表示当前的魔力最大值。 -``` js -'hero': { - // ... 上略 - 'mana': 0, // 增添mana定义,可以放在experience之后。同理可定义manaMax表示当前最大魔力值。 -} -``` +同时,我们可以使用flag:skill表示当前开启的技能编号,flag:skillName表示当前开启的技能名称。 -如果要flag标记,则无需额外在任何地方进行定义。只需要在设置或取用的时候使用 `core.setFlag('mana', 0)` 或 `core.getFlag('mana', 0)` 即可。 - -下面我都使用属性获取的方式来进行说明。 +如果flag:skill不为0,则代表当前处于某个技能开启状态,且状态栏显示flag:skillName值。伤害计算函数中只需要对flag:skill进行处理即可。 ### 状态栏的显示 -首先我们需要额外新增一个状态栏;请参见[自定义状态栏(新增显示项)](#自定义状态栏(新增显示项))。 +从V2.5开始,魔力值和技能名的状态栏项目已经被添加,可以直接使用。 -我们可以在魔力那一行显示当前值和最大值: +在脚本编辑-updateStatusBar中,可以对状态栏显示内容进行修改。 ``` js -core.setStatus('mana', Math.min(core.getStatus('mana'), core.getStatus('manaMax'))); // 如果魔力存在上限,则不能超过其上限值 -core.statusBar.mana.innerHTML = core.getStatus('mana') + '/' + core.getStatus('manaMax', 0); // 显示比如 6/30 这样 -``` - -如果我们还需要显示当前使用的技能名,也是可以的;定义一个ID为skill,然后按照上面的做法新增一行。 - -请注意,如果是中文字符,需要取消斜体(不然会非常难看的)! - -``` js -core.statusBar.skill.style.fontStyle = 'normal'; // 取消斜体显示 -core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); // 使用flag:skillName表示当前激活的技能名。 + // 设置魔力值 + if (core.flags.enableMana) { + // 也可以使用flag:manaMax来表示最大魔力值 + // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); + // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); + } + // 设置技能栏 + if (core.flags.enableSkill) { + // 可以用flag:kill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 + core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); + } ``` ### 技能的触发 @@ -716,7 +713,7 @@ case 87: // W 举个例子,我设置一个勇士的技能:二倍斩,开启技能消耗5点魔力,下一场战斗攻击力翻倍。 -那么,直接在`getDamageInfo`中进行判断: +那么,直接在脚本编辑的`getDamageInfo`中进行判断: ``` js if (core.getFlag('skill', 0)==1) { // 开启了技能1 @@ -724,7 +721,7 @@ if (core.getFlag('skill', 0)==1) { // 开启了技能1 } ``` -然后在脚本编辑的战后事件中进行魔力值的扣除: +然后在脚本编辑的`afterBattle`中进行魔力值的扣除: ``` js if (core.getFlag('skill', 0)==1) { // 开启了技能1 diff --git a/editor-mobile.html b/editor-mobile.html index 161e7897..cd51f4ed 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -355,6 +355,10 @@

+
+ +

+

@@ -379,6 +383,10 @@

+
+ +

+
diff --git a/editor.html b/editor.html index cce7d36c..0ae3917b 100644 --- a/editor.html +++ b/editor.html @@ -341,6 +341,10 @@

+
+ +

+

@@ -365,6 +369,10 @@

+
+ +

+
diff --git a/index.html b/index.html index 62182c53..2a05eb95 100644 --- a/index.html +++ b/index.html @@ -62,6 +62,10 @@

+
+ +

+

@@ -86,6 +90,10 @@

+
+ +

+
diff --git a/libs/control.js b/libs/control.js index 0a6ce796..d69826b6 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2807,6 +2807,8 @@ control.prototype.resize = function(clientWidth, clientHeight) { if (!core.flags.enableKeys) count--; if (!core.flags.enablePZF) count--; if (!core.flags.enableName) count--; + if (!core.flags.enableMana) count--; + if (!core.flags.enableSkill) count--; var statusLineHeight = BASE_LINEHEIGHT * 9 / count; var statusLineFontSize = DEFAULT_FONT_SIZE; @@ -3086,6 +3088,12 @@ control.prototype.resize = function(clientWidth, clientHeight) { display: core.flags.enableHPMax ? 'block': 'none' } }, + { + id: 'manaCol', + rules: { + display: core.flags.enableMana ? 'block': 'none' + } + }, { id: 'mdefCol', rules: { @@ -3110,6 +3118,12 @@ control.prototype.resize = function(clientWidth, clientHeight) { display: core.flags.enableLevelUp ? 'block': 'none' } }, + { + id: 'skillCol', + rules: { + display: core.flags.enableSkill ? 'block': 'none' + } + }, { id: 'keyCol', rules: { diff --git a/main.js b/main.js index 1abb2b91..cee1293a 100644 --- a/main.js +++ b/main.js @@ -55,6 +55,7 @@ function main() { 'nameCol': document.getElementById('nameCol'), 'lvCol': document.getElementById('lvCol'), 'hpmaxCol': document.getElementById('hpmaxCol'), + 'manaCol': document.getElementById('manaCol'), 'mdefCol': document.getElementById('mdefCol'), 'moneyCol': document.getElementById('moneyCol'), 'expCol': document.getElementById('expCol'), @@ -62,6 +63,7 @@ function main() { 'keyCol': document.getElementById('keyCol'), 'pzfCol': document.getElementById('pzfCol'), 'debuffCol': document.getElementById('debuffCol'), + 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), }; this.mode = 'play'; @@ -82,12 +84,14 @@ function main() { 'lv': document.getElementById('img-lv'), 'hpmax': document.getElementById('img-hpmax'), 'hp': document.getElementById("img-hp"), + 'mana': document.getElementById("img-mana"), 'atk': document.getElementById("img-atk"), 'def': document.getElementById("img-def"), 'mdef': document.getElementById("img-mdef"), 'money': document.getElementById("img-money"), 'experience': document.getElementById("img-experience"), 'up': document.getElementById("img-up"), + 'skill': document.getElementById('img-skill'), 'book': document.getElementById("img-book"), 'fly': document.getElementById("img-fly"), 'toolbox': document.getElementById("img-toolbox"), @@ -133,12 +137,14 @@ function main() { 'lv': document.getElementById('lv'), 'hpmax': document.getElementById('hpmax'), 'hp': document.getElementById('hp'), + 'mana': document.getElementById('mana'), 'atk': document.getElementById('atk'), 'def': document.getElementById("def"), 'mdef': document.getElementById('mdef'), 'money': document.getElementById("money"), 'experience': document.getElementById("experience"), 'up': document.getElementById('up'), + 'skill': document.getElementById('skill'), 'yellowKey': document.getElementById("yellowKey"), 'blueKey': document.getElementById("blueKey"), 'redKey': document.getElementById("redKey"), diff --git a/project/data.js b/project/data.js index 74c27764..ef3da6f1 100644 --- a/project/data.js +++ b/project/data.js @@ -75,6 +75,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "lv": 1, "hpmax": 9999, "hp": 1000, + "mana": 0, "atk": 100, "def": 100, "mdef": 100, @@ -197,6 +198,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableName": false, "enableLv": false, "enableHPMax": false, + "enableMana": false, "enableMDef": true, "enableMoney": true, "enableExperience": false, @@ -204,6 +206,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableKeys": true, "enablePZF": false, "enableDebuff": false, + "enableSkill": false, "flyNearStair": true, "pickaxeFourDirections": false, "bombFourDirections": false, diff --git a/project/functions.js b/project/functions.js index fff7e6bb..4cc5e5fa 100644 --- a/project/functions.js +++ b/project/functions.js @@ -617,7 +617,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = else core.statusBar.lv.style.fontStyle = 'normal'; // 设置生命上限、生命值、攻防魔防金币和经验值 - var statusList = ['hpmax', 'hp', 'atk', 'def', 'mdef', 'money', 'experience']; + var statusList = ['hpmax', 'hp', 'mana', 'atk', 'def', 'mdef', 'money', 'experience']; statusList.forEach(function (item) { // 向下取整 if (core.isset(core.status.hero[item])) @@ -632,6 +632,18 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.statusBar.def.innerHTML = core.formatBigNumber(Math.floor(core.getFlag('equip_def_buff',1)*core.getStatus('def'))); core.statusBar.mdef.innerHTML = core.formatBigNumber(Math.floor(core.getFlag('equip_mdef_buff',1)*core.getStatus('mdef'))); } + + // 设置魔力值 + if (core.flags.enableMana) { + // 也可以使用flag:manaMax来表示最大魔力值;详见文档-个性化-技能塔的支持 + // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); + // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); + } + // 设置技能栏 + if (core.flags.enableSkill) { + // 可以用flag:kill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 + core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); + } // 可以在这里添加自己额外的状态栏信息,比如想攻击显示 +0.5 可以这么写: // if (core.hasFlag('halfAtk')) core.statusBar.atk.innerHTML += "+0.5"; From 3f151acbc7e16ffdfc1900d16f8e67fbd11e963a Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 30 Oct 2018 03:00:46 +0800 Subject: [PATCH 5/9] mana & skill --- docs/personalization.md | 22 +++++++++++----------- project/functions.js | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index c72a346f..a9087224 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -630,17 +630,17 @@ core.statusBar.mana.style.fontStyle = 'normal'; // 这一行会取消斜体。 在脚本编辑-updateStatusBar中,可以对状态栏显示内容进行修改。 ``` js - // 设置魔力值 - if (core.flags.enableMana) { - // 也可以使用flag:manaMax来表示最大魔力值 - // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); - // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); - } - // 设置技能栏 - if (core.flags.enableSkill) { - // 可以用flag:kill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 - core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); - } +// 设置魔力值 +if (core.flags.enableMana) { + // 也可以使用flag:manaMax来表示最大魔力值 + // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); + // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); +} +// 设置技能栏 +if (core.flags.enableSkill) { + // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 + core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); +} ``` ### 技能的触发 diff --git a/project/functions.js b/project/functions.js index 4cc5e5fa..4ddd76b8 100644 --- a/project/functions.js +++ b/project/functions.js @@ -641,7 +641,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 设置技能栏 if (core.flags.enableSkill) { - // 可以用flag:kill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 + // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); } From 3ce1c2e4687a71fdfc1a0e0860c884c6250e0137 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 30 Oct 2018 03:01:03 +0800 Subject: [PATCH 6/9] mana & skill --- docs/personalization.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/personalization.md b/docs/personalization.md index a9087224..e3d9dc8e 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -638,7 +638,7 @@ if (core.flags.enableMana) { } // 设置技能栏 if (core.flags.enableSkill) { - // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 + // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名 core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); } ``` From 5b1bf618c245df0f215236dfaffabe8e4d074a0a Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 30 Oct 2018 14:19:24 +0800 Subject: [PATCH 7/9] Skill --- _server/functions.comment.js | 12 +++ docs/personalization.md | 55 ++++++------ libs/actions.js | 147 +------------------------------ project/data.js | 10 +-- project/functions.js | 165 +++++++++++++++++++++++++++++++++++ project/icons.js | 3 +- project/items.js | 11 ++- project/maps.js | 1 + 8 files changed, 223 insertions(+), 181 deletions(-) diff --git a/_server/functions.comment.js b/_server/functions.comment.js index 92080dd7..9bd96f61 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -129,6 +129,18 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } } }, + "actions": { + "_leaf": false, + "_type": "object", + "_data": { + "onKeyUp": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "按键处理;可以在这里自定义快捷键,详见文档-个性化-自定义快捷键" + } + } + }, "control": { "_leaf": false, "_type": "object", diff --git a/docs/personalization.md b/docs/personalization.md index e3d9dc8e..bc2d9791 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -496,34 +496,28 @@ this.useEquipment = function (itemId) { // 使用装备 如果需要绑定某个快捷键为处理一段事件,也是可行的。 -要修改按键,我们可以在`actions.js`的`keyUp`进行处理: +要修改按键,我们可以在脚本编辑的`onKeyUp`进行处理: -比如,我们设置一个快捷键进行绑定,比如`W`,其keycode是87。(有关每个键的keycode搜一下就能得到) +比如,我们设置一个快捷键进行绑定,比如`Y`,其keycode是89。(有关每个键的keycode搜一下就能得到) -然后在`actions.js`的`keyUp`函数的`switch`中进行处理。 +然后在脚本编辑的`onKeyUp`函数的`switch`中进行处理。 ``` js -case 87: // W - if (core.status.heroStop) { - // ... 在这里写你要执行脚本 - // 请使用同步脚本,请勿执行任何异步代码,否则可能导致游戏过程或录像出现问题。 - core.insertAction([...]) // 例如,插入一段自定义事件并执行。 - - // core.status.route.push("key:"+keyCode); // 录像的支持,这句话加不加最好仔细进行测试 +case 89: // 使用该按键的keyCode,比如Y键就是89 + // 还可以再判定altKey是否被按下,即 if (altKey) { ... + + // ... 在这里写你要执行脚本 + // **强烈建议所有新增的自定义快捷键均能给个对应的道具可点击,以方便手机端的行为** + if (core.hasItem('...')) { + core.useItem('...'); } + break; ``` +强烈建议所有新增的自定义快捷键均给个对应的永久道具可点击,以方便手机端的行为。 -在勇士处于停止的条件下,按下W键时,将执行你写的脚本代码。请只使用同步脚本而不要使用异步代码,不然可能导致游戏出现问题。 - -`core.status.route.push("key:"+keyCode);` 这句话是对录像的支持。 - -**录像的支持可能比较诡异,在不同条件下都是不同的;因此加不加最好分开独立进行测试。** - -!> H5不支持组合快捷键,所以不存在`W+1`这种组合快捷键的说法! - -!> 手机端可以通过长按任何位置调出虚拟键盘,再进行按键,和键盘按键是等价的效果! +可以使用altKey来判断Alt键是否被同时按下。 ## 公共事件 @@ -609,7 +603,7 @@ core.statusBar.mana.style.fontStyle = 'normal'; // 这一行会取消斜体。 - 技能的触发(按键与录像问题) - 技能的效果 -从V2.5开始,魔力和技能的定义被内置到了样板中,因此十分方便。 +从V2.5开始,内置了"二倍斩"技能,可以仿照其制作自己的技能。 ### 魔力的定义添加;技能的定义 @@ -684,11 +678,10 @@ else { // 关闭技能 下面是一个很简单的例子,当勇士按下W后,触发我们上面定义的二倍斩技能。 ``` js -case 87: // W - if (core.status.heroStop) { // 当前停止状态;这个if需要加,不能在行走过程中触发不然容易出错。 - if (core.hasItem('skill1')) { // 判定该技能道具是否存在 - core.useItem('skill1'); // 使用道具(该技能) - } +case 87: // W:开启技能“二倍斩” + // 检测技能栏是否开启,是否拥有“二倍斩”这个技能道具 + if (core.flags.enableSkill && core.hasItem('skill1')) { + core.useItem('skill1'); } break; ``` @@ -724,9 +717,15 @@ if (core.getFlag('skill', 0)==1) { // 开启了技能1 然后在脚本编辑的`afterBattle`中进行魔力值的扣除: ``` js -if (core.getFlag('skill', 0)==1) { // 开启了技能1 - core.status.hero.mana -= 5; // 扣除5点魔力值 - core.setFlag('skill', 0); // 自动关闭技能 +// 战后的技能处理,比如扣除魔力值 +if (core.flags.enableSkill) { + // 检测当前开启的技能类型 + var skill = core.getFlag('skill', 0); + if (skill==1) { // 技能1:二倍斩 + core.status.hero.mana-=5; // 扣除5点魔力值 + } + // 关闭技能 + core.setFlag('skill', 0); core.setFlag('skillName', '无'); } ``` diff --git a/libs/actions.js b/libs/actions.js index 5b4fff35..a2af8038 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -8,7 +8,7 @@ function actions() { } actions.prototype.init = function () { - + this.actionsdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.actions; } ////// 按下某个键时 ////// @@ -291,150 +291,7 @@ actions.prototype.keyUp = function(keyCode, altKey) { if(!core.status.played) return; - // 0~9的AltKey - if (altKey && keyCode>=48 && keyCode<=57 && core.status.heroStop) { - core.items.quickLoadEquip(keyCode-48); - return; - } - - switch (keyCode) { - case 27: // ESC - if (core.status.heroStop) - core.openSettings(true); - break; - case 71: // G - if (core.status.heroStop) - core.useFly(true); - break; - case 81: // Q - if (core.status.heroStop) - core.openEquipbox(true); - break; - case 88: // X - if (core.status.heroStop) - core.openBook(true); - break; - case 65: // A - if (core.status.heroStop) - core.doSL("autoSave", "load"); - break; - case 66: // B - if (core.status.heroStop) - core.ui.drawStatistics(); - break; - case 83: // S - if (core.status.heroStop) - core.save(true); - break; - case 68: // D - if (core.status.heroStop) - core.load(true); - break; - case 69: // E - if (core.status.heroStop) - core.ui.drawCursor(); - break; - case 84: // T - if (core.status.heroStop) - core.openToolbox(true); - break; - case 90: // Z - if (core.status.heroStop) - core.turnHero(); - break; - case 75: case 86: // K/V - if (core.status.heroStop) - core.openQuickShop(true); - break; - case 32: // SPACE - if (core.status.heroStop) - core.getNextItem(); - break; - case 72: // H - if (core.status.heroStop) - core.ui.drawHelp(); - break; - case 82: // R - if (core.status.heroStop) { - if (core.hasFlag('debug')) { - core.drawText("\t[系统提示]调试模式下无法回放录像"); - } - else { - core.ui.drawReplay(); - } - } - break; - case 33: case 34: // PAGEUP/PAGEDOWN - if (core.status.heroStop) - core.ui.drawMaps(); - break; - case 77: // M - if (core.status.heroStop) { - core.ui.drawPaint(); - } - break; - case 37: // UP - break; - case 38: // DOWN - break; - case 39: // RIGHT - break; - case 40: // DOWN - break; - case 49: // 快捷键1: 破 - if (core.status.heroStop && core.hasItem('pickaxe')) { - if (core.canUseItem('pickaxe')) { - core.useItem('pickaxe'); - } - else { - core.drawTip('当前不能使用破墙镐'); - } - } - break; - case 50: // 快捷键2: 炸 - if (core.status.heroStop) { - if (core.hasItem('bomb')) { - if (core.canUseItem('bomb')) { - core.useItem('bomb'); - } - else { - core.drawTip('当前不能使用炸弹'); - } - } - else if (core.hasItem('hammer')) { - if (core.canUseItem('hammer')) { - core.useItem('hammer'); - } - else { - core.drawTip('当前不能使用圣锤'); - } - - } - } - break; - case 51: // 快捷键3: 飞 - if (core.status.heroStop && core.hasItem('centerFly')) { - core.events.useItem('centerFly'); - } - break; - case 52: // 快捷键4:破冰/冰冻/地震/上下楼器/... - if (core.status.heroStop) { - var list = ["icePickaxe", "snow", "earthquake", "upFly", "downFly", "jumpShoes", "lifeWand", "poisonWine", "weakWine", "curseWine", "superWine"]; - for (var i=0;i=48 && keyCode<=57) { + core.items.quickLoadEquip(keyCode-48); + return; + } + + // 根据keyCode值来执行对应操作 + switch (keyCode) { + case 27: // ESC:打开菜单栏 + core.openSettings(true); + break; + case 88: // X:使用怪物手册 + core.openBook(true); + break; + case 71: // G:使用楼传器 + core.useFly(true); + break; + case 65: // A:读取自动存档(回退) + core.doSL("autoSave", "load"); + break; + case 83: // S:存档 + core.save(true); + break; + case 68: // D:独挡 + core.load(true); + break; + case 69: // E:打开光标 + core.ui.drawCursor(); + break; + case 84: // T:打开道具栏 + core.openToolbox(true); + break; + case 81: // Q:打开装备栏 + core.openEquipbox(true); + break; + case 90: // Z:转向 + core.turnHero(); + break; + case 75: case 86: // K/V:打开快捷商店列表 + core.openQuickShop(true); + break; + case 32: // SPACE:轻按 + core.getNextItem(); + break; + case 82: // R:回放录像 + if (core.hasFlag('debug')) { + core.drawText("\t[系统提示]调试模式下无法回放录像"); + } + else { + core.ui.drawReplay(); + } + break; + case 33: case 34: // PgUp/PgDn:浏览地图 + core.ui.drawMaps(); + break; + case 77: // M:绘图模式 + core.ui.drawPaint(); + break; + case 66: // B:打开数据统计 + core.ui.drawStatistics(); + break; + case 72: // H:打开帮助页面 + core.ui.drawHelp(); + break; + case 49: // 快捷键1: 破 + if (core.hasItem('pickaxe')) { + if (core.canUseItem('pickaxe')) { + core.useItem('pickaxe'); + } + else { + core.drawTip('当前不能使用破墙镐'); + } + } + break; + case 50: // 快捷键2: 炸 + if (core.hasItem('bomb')) { + if (core.canUseItem('bomb')) { + core.useItem('bomb'); + } + else { + core.drawTip('当前不能使用炸弹'); + } + } + else if (core.hasItem('hammer')) { + if (core.canUseItem('hammer')) { + core.useItem('hammer'); + } + else { + core.drawTip('当前不能使用圣锤'); + } + + } + break; + case 51: // 快捷键3: 飞 + if (core.hasItem('centerFly')) { + core.events.useItem('centerFly'); + } + break; + case 52: // 快捷键4:破冰/冰冻/地震/上下楼器/... 其他道具依次判断 + { + var list = ["icePickaxe", "snow", "earthquake", "upFly", "downFly", "jumpShoes", "lifeWand", "poisonWine", "weakWine", "curseWine", "superWine"]; + for (var i=0;i=5) { // 这里要写当前能否开技能的条件判断,比如魔力值至少要多少\n\t\tcore.setFlag('skill', 1); // 开技能1\n\t\tcore.setFlag('skillName', '二倍斩'); // 设置技能名\n\t}\n\telse {\n\t\tcore.drawTip(\"魔力不足,无法开启技能\");\n\t}\n}\nelse { // 关闭技能\n\tcore.setFlag('skill', 0); // 关闭技能状态\n\tcore.setFlag('skillName', '无');\n}" }, "canUseItemEffect": { "book": "true", @@ -401,6 +407,7 @@ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "redJewel": "true", "blueJewel": "true", "greenJewel": "true", - "yellowJewel": "true" + "yellowJewel": "true", + "skill1": "true" } } \ No newline at end of file diff --git a/project/maps.js b/project/maps.js index 6fee9b19..66ef81d1 100644 --- a/project/maps.js +++ b/project/maps.js @@ -79,6 +79,7 @@ maps_90f36752_8815_4be8_b32b_d7fad1d0542e = '65':{'cls': 'items', 'id': 'hammer'}, // 圣锤 '68':{'cls': 'items', 'id': 'lifeWand'}, // 生命魔杖 '69':{'cls': 'items', 'id': 'jumpShoes'}, // 生命魔杖 + '70':{'cls': 'items', 'id': 'skill1'}, // 技能:二倍斩 ////////////////////////// 门、楼梯、传送点部分 ////////////////////////// From b0b6c0be99a8ee07fbe366ad5c32589aea89215d Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 30 Oct 2018 14:23:57 +0800 Subject: [PATCH 8/9] Skill --- docs/personalization.md | 2 ++ project/data.js | 6 +++--- project/functions.js | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/personalization.md b/docs/personalization.md index bc2d9791..2a6a15b0 100644 --- a/docs/personalization.md +++ b/docs/personalization.md @@ -730,6 +730,8 @@ if (core.flags.enableSkill) { } ``` +!> 开启技能后,建议将全塔属性的useLoop置为true,即改用循环计算临界值,这样临界计算才不会出问题! +   通过上述这几种方式,我们就能成功的让H5支持技能啦! diff --git a/project/data.js b/project/data.js index 9489a95e..15eba994 100644 --- a/project/data.js +++ b/project/data.js @@ -75,7 +75,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "lv": 1, "hpmax": 9999, "hp": 1000, - "mana": 10, + "mana": 0, "atk": 100, "def": 100, "mdef": 0, @@ -198,7 +198,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableName": false, "enableLv": false, "enableHPMax": false, - "enableMana": true, + "enableMana": false, "enableMDef": true, "enableMoney": true, "enableExperience": false, @@ -206,7 +206,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableKeys": true, "enablePZF": false, "enableDebuff": false, - "enableSkill": true, + "enableSkill": false, "flyNearStair": true, "pickaxeFourDirections": false, "bombFourDirections": false, diff --git a/project/functions.js b/project/functions.js index fc590af6..59ad43f7 100644 --- a/project/functions.js +++ b/project/functions.js @@ -708,8 +708,8 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.debug(); break; case 87: // W:开启技能“二倍斩” - // 检测技能栏是否开启,是否拥有“二倍斩”这个技能道具 - if (core.flags.enableSkill && core.hasItem('skill1')) { + // 检测是否拥有“二倍斩”这个技能道具 + if (core.hasItem('skill1')) { core.useItem('skill1'); } break; From ca1c5a00ece2573afc287eede9adee9408316cd6 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 30 Oct 2018 14:39:15 +0800 Subject: [PATCH 9/9] QuickShop common times --- _server/blockly/MotaAction.g4 | 7 ++++--- libs/actions.js | 2 ++ libs/events.js | 2 ++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 18cd0c30..892bd536 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -63,18 +63,19 @@ return code; */; shopsub - : '商店 id' IdString '标题' EvalString '图标' IdString BGNL? Newline '快捷商店栏中名称' EvalString BGNL? Newline '使用' ShopUse_List '消耗' EvalString BGNL? Newline '显示文字' EvalString BGNL? Newline shopChoices+ BEND + : '商店 id' IdString '标题' EvalString '图标' IdString BGNL? Newline '快捷商店栏中名称' EvalString '共用times' Bool BGNL? Newline '使用' ShopUse_List '消耗' EvalString BGNL? Newline '显示文字' EvalString BGNL? Newline shopChoices+ BEND /* shopsub tooltip : 全局商店,消耗填-1表示每个选项的消耗不同,正数表示消耗数值 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97 -default : ["shop1","贪婪之神","blueShop","1F金币商店",null,"20+10*times*(times+1)","勇敢的武士啊, 给我${need}金币就可以:"] +default : ["shop1","贪婪之神","blueShop","1F金币商店",false,null,"20+10*times*(times+1)","勇敢的武士啊, 给我${need}金币就可以:"] var code = { 'id': IdString_0, 'name': EvalString_0, 'icon': IdString_1, 'textInList': EvalString_1, + 'commonTimes': Bool_0, 'use': ShopUse_List_0, 'need': EvalString_2, 'text': EvalString_3, @@ -1638,7 +1639,7 @@ ActionParser.prototype.parse = function (obj,type) { choice.text,choice.need||'',text_effect,text_choices]); } return MotaActionBlocks['shopsub'].xmlText([ - obj.id,obj.name,obj.icon,obj.textInList,obj.use,obj.need,parser.EvalString(obj.text),text_choices,next + obj.id,obj.name,obj.icon,obj.textInList,obj.commonTimes,obj.use,obj.need,parser.EvalString(obj.text),text_choices,next ]); } var next=null; diff --git a/libs/actions.js b/libs/actions.js index a2af8038..9c70ab75 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1056,6 +1056,8 @@ actions.prototype.clickShop = function(x,y) { }); core.updateStatusBar(); shop.times++; + if (shop.commonTimes) + core.setFlag('commonTimes', shop.times); core.events.openShop(core.status.event.data.id); } // 离开 diff --git a/libs/events.js b/libs/events.js index 56907f27..73397f40 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1532,6 +1532,8 @@ events.prototype.vibrate = function(time, callback) { events.prototype.openShop = function(shopId, needVisited) { var shop = core.status.shops[shopId]; shop.times = shop.times || 0; + if (shop.commonTimes) + shop.times = core.getFlag('commonTimes', 0); shop.visited = shop.visited || false; if (needVisited && !shop.visited) { if (shop.times==0) core.drawTip("该商店尚未开启");