diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index d6e6efbe..14451bc4 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -305,13 +305,13 @@ return code; */; setText_s - : '设置剧情文本的属性' '位置' SetTextPosition_List BGNL? '标题颜色' EvalString? '正文颜色' EvalString? '背景色' EvalString? BGNL? '粗体' B_1_List '打字间隔' EvalString? Newline + : '设置剧情文本的属性' '位置' SetTextPosition_List BGNL? '标题颜色' EvalString? '正文颜色' EvalString? '背景色' EvalString? '粗体' B_1_List BGNL? '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline /* setText_s tooltip : setText:设置剧情文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填 helpUrl : https://ckcz123.github.io/mota-js/#/event?id=settext%EF%BC%9A%E8%AE%BE%E7%BD%AE%E5%89%A7%E6%83%85%E6%96%87%E6%9C%AC%E7%9A%84%E5%B1%9E%E6%80%A7 -default : [null,"","","",null,''] +default : [null,"","","",null,"","",''] SetTextPosition_List_0 =SetTextPosition_List_0==='null'?'': ', "position": "'+SetTextPosition_List_0+'"'; var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/; if (EvalString_0) { @@ -327,11 +327,19 @@ if (EvalString_2) { EvalString_2 = ', "background": ['+EvalString_2+']'; } if (EvalString_3) { - if (!/^\d+$/.test(EvalString_3))throw new Error('打字时间间隔必须是整数或不填'); - EvalString_3 = ', "time": '+EvalString_3; + if (!/^\d+$/.test(EvalString_3))throw new Error('字体大小必须是整数或不填'); + EvalString_3 = ', "titlefont": '+EvalString_3; +} +if (EvalString_4) { + if (!/^\d+$/.test(EvalString_4))throw new Error('字体大小必须是整数或不填'); + EvalString_4 = ', "textfont": '+EvalString_4; +} +if (EvalString_5) { + if (!/^\d+$/.test(EvalString_5))throw new Error('打字时间间隔必须是整数或不填'); + EvalString_5 = ', "time": '+EvalString_5; } B_1_List_0 = ', "bold": '+B_1_List_0; -var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+'},\n'; +var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+'},\n'; return code; */; @@ -1675,7 +1683,7 @@ ActionParser.prototype.parseAction = function() { data.text=setTextfunc(data.text); data.background=setTextfunc(data.background); this.next = MotaActionBlocks['setText_s'].xmlText([ - data.position,data.title,data.text,data.background,data.bold,data.time,this.next]); + data.position,data.title,data.text,data.background,data.bold,data.titlefont,data.textfont,data.time,this.next]); break; case "tip": this.next = MotaActionBlocks['tip_s'].xmlText([ diff --git a/_server/functions.comment.js b/_server/functions.comment.js index 2e5f1735..92080dd7 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -175,6 +175,12 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": false, "_type": "object", "_data": { + "parallelDo": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "并行事件处理" + }, "plugin": { "_leaf": true, "_type": "textarea", diff --git a/docs/event.md b/docs/event.md index 9a38fa19..b2d67f93 100644 --- a/docs/event.md +++ b/docs/event.md @@ -10,8 +10,6 @@ 上述这些默认的事件已经存在处理机制,不需要我们操心。我们真正所需要关心的,其实只是一个自定义的事件。 -**本塔中的所有自定义事件能且只能被其他事件触发。不存在RMXP里面那种,设置了某个变量为true后,一个事件被自动执行的问题。这点和RMXP的区别非常大,请务必注意。** - 所有事件都存在两种状态:启用和禁用。 - 启用状态下,该事件才处于可见状态,可被触发、交互与处理。 - 禁用状态下该事件相当于不存在,不可见、不可被触发、不可交互。 @@ -296,8 +294,8 @@ time为可选项,代表该自动文本的时间。可以不指定,不指定 ``` js "x,y": [ // 实际执行的事件列表 {"type": "setText", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3]}, - {"type": "setText", "position": "up", "bold": true, "time": 70}, - "这段话将显示在上方,标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色,70毫秒速度打字机效果" + {"type": "setText", "position": "up", "bold": true, "titlefont": 26, "textfont": 17, "time": 70}, + "这段话将显示在上方,标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色,标题26px,正文17px,70毫秒速度打字机效果" ] ``` @@ -311,6 +309,10 @@ position为可选项,表示设置文字显示位置。只能为up(上),c bold为可选项,如果设置则为true或false,表示正文是否使用粗体。 默认值:`false` +titlefont为可选项,表示标题字体大小(px为单位)。默认值:`22` + +textfont为可选项,表示正文字体大小(px为单位)。默认值:`16` + time为可选项,表示文字添加的速度。若此项设置为0将直接全部显示,若大于0则会设置为相邻字符依次显示的时间间隔。 默认值:`0` ### tip:显示一段提示文字 @@ -1467,6 +1469,45 @@ core.insertAction([ - 如果弄不清楚系统trigger和自定义事件等的区别,也可以全部覆盖为自定义事件,然后通过type:battle,type:openDoor等来具体进行控制。 - 多事件处理时请不要使用`changeFloor`那一项,而是使用`events`或者`afterXXX`来处理。 +## 并行事件处理 + +从V2.4.3后,H5样板开始支持并行事件处理。 + +在脚本编辑里面提供了一个parallelDo函数,这个函数可以用来做并行处理内容。 + +``` js +"parallelDo": function (timestamp) { + // 并行事件处理,可以在这里写任何需要并行处理的脚本或事件 + // 该函数将被系统反复执行,每次执行间隔视浏览器或设备性能而定,一般约为16.6ms一次 + // 参数timestamp为“从游戏资源加载完毕到当前函数执行时”的时间差,以毫秒为单位 + + // 检查当前是否处于游戏开始状态 + if (!core.isPlaying()) return; + + // 下面是一个并行事件开门的样例 + /* + // 如果某个flag为真 + if (core.hasFlag("xxx")) { + // 千万别忘了将该flag清空!否则下次仍然会执行这段代码。 + core.setFlag("xxx", false); + // 使用insertAction来插入若干自定义事件执行 + core.insertAction([ + {"type":"openDoor", "loc":[0,0], "floorId": "MT0"} + ]) + // 也可以写任意其他的脚本代码 + } + */ +} +``` + +该函数将被系统反复执行,执行间隔试浏览器或设备性能而定,一般约为16.6ms一次。 + +此函数有个参数timestamp,为**从游戏资源加载完毕到当前函数执行时**的时间差,以毫秒为单位。可以使用此参数来制作一些时间相关内容或者特效等。 + +如果要执行并行的自定义事件,请使用if+flag判断的形式,然后insertAction将自定义事件插入到事件列表中。 + +!> 判定flag后千万别忘了将该flag清空!否则下次仍然会执行这段代码。 + ## 加点事件 打败怪物后可以进行加点。 diff --git a/libs/actions.js b/libs/actions.js index 7dd56cad..2bf5694c 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -51,6 +51,14 @@ actions.prototype.onkeyUp = function(e) { core.bookReplay(); else if (e.keyCode==33||e.keyCode==34) core.viewMapReplay(); + else if (e.keyCode>=49 && e.keyCode<=51) + core.setReplaySpeed(e.keyCode-48); + else if (e.keyCode==52) + core.setReplaySpeed(6); + else if (e.keyCode==53) + core.setReplaySpeed(12); + else if (e.keyCode==54) + core.setReplaySpeed(24); return; } @@ -179,7 +187,7 @@ actions.prototype.keyDown = function(keyCode) { } ////// 根据放开键的code来执行一系列操作 ////// -actions.prototype.keyUp = function(keyCode, fromReplay) { +actions.prototype.keyUp = function(keyCode) { 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; @@ -677,10 +685,16 @@ actions.prototype.onclick = function (x, y, stepPostfix) { ////// 滑动鼠标滚轮时的操作 ////// actions.prototype.onmousewheel = function (direct) { - 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; // 向下滚动是 -1 ,向上是 1 + 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') { + // 滚轮控制速度 + if (direct==1) core.speedUpReplay(); + if (direct==-1) core.speedDownReplay(); + return; + } + // 楼层飞行器 if (core.status.lockControl && core.status.event.id == 'fly') { if (direct==1) core.ui.drawFly(core.status.event.data+1); @@ -2247,7 +2261,9 @@ actions.prototype.clickStorageRemove = function (x, y) { switch (selection) { case 0: if (core.platform.useLocalForage) { + core.ui.drawWaiting("正在清空,请稍后..."); localforage.clear(function () { + core.ui.closePanel(); core.drawText("\t[操作成功]你的所有存档已被清空。"); }); } @@ -2257,13 +2273,25 @@ actions.prototype.clickStorageRemove = function (x, y) { } break; case 1: - for (var i=1;i<=5*(main.savePages||30);i++) { - // core.removeLocalStorage("save"+i); - core.removeLocalForage("save"+i); + if (core.platform.useLocalForage) { + core.ui.drawWaiting("正在清空,请稍后..."); + for (var i=1;i<=5*(main.savePages||30);i++) { + // core.removeLocalStorage("save"+i); + core.removeLocalForage("save"+i); + } + core.removeLocalForage("autoSave", function() { + core.ui.closePanel(); + core.drawText("\t[操作成功]当前塔的存档已被清空。"); + }); } - core.removeLocalForage("autoSave", function() { + else { + for (var i=1;i<=5*(main.savePages||30);i++) { + // core.removeLocalStorage("save"+i); + core.removeLocalStorage("save"+i); + } + core.removeLocalStorage("autoSave"); core.drawText("\t[操作成功]当前塔的存档已被清空。"); - }); + } break; case 2: core.status.event.selection=5; diff --git a/libs/control.js b/libs/control.js index a714fc40..c6673075 100644 --- a/libs/control.js +++ b/libs/control.js @@ -186,6 +186,10 @@ control.prototype.setRequestAnimationFrame = function () { core.animateFrame.weather.time = timestamp; } + + // 执行用户的并行事件处理内容 + functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.parallelDo(timestamp); + window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw); @@ -669,6 +673,10 @@ control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { var toAdd = 1; if (core.status.replay.speed>3) toAdd = 2; + if (core.status.replay.speed>6) + toAdd = 4; + if (core.status.replay.speed>12) + toAdd = 8; core.interval.heroMoveInterval = window.setInterval(function () { core.status.heroMoving+=toAdd; @@ -1488,7 +1496,7 @@ control.prototype.setFg = function(color, time, callback) { core.status.replay.animate=false; if (core.isset(callback)) callback(); } - }, time/25); + }, time/25/core.status.replay.speed); } ////// 更新全地图显伤 ////// @@ -1678,9 +1686,13 @@ control.prototype.resumeReplay = function () { control.prototype.speedUpReplay = function () { if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; if (!core.status.replay.replaying) return; - var toAdd = core.status.replay.speed>=3?3:core.status.replay.speed>=2?2:1; - core.status.replay.speed = parseInt(10*core.status.replay.speed + toAdd)/10; - if (core.status.replay.speed>6.0) core.status.replay.speed=6.0; + if (core.status.replay.speed==12) core.status.replay.speed=24.0; + else if (core.status.replay.speed==6) core.status.replay.speed=12.0; + else if (core.status.replay.speed==3) core.status.replay.speed=6.0; + else if (core.status.replay.speed<3) { + var toAdd = core.status.replay.speed>=2?2:1; + core.status.replay.speed = parseInt(10*core.status.replay.speed + toAdd)/10; + } core.drawTip("x"+core.status.replay.speed+"倍"); } @@ -1688,12 +1700,25 @@ control.prototype.speedUpReplay = function () { control.prototype.speedDownReplay = function () { if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; if (!core.status.replay.replaying) return; - var toAdd = core.status.replay.speed>3?3:core.status.replay.speed>2?2:1; - core.status.replay.speed = parseInt(10*core.status.replay.speed - toAdd)/10; + if (core.status.replay.speed==24) core.status.replay.speed=12.0; + else if (core.status.replay.speed==12) core.status.replay.speed=6.0; + else if (core.status.replay.speed==6) core.status.replay.speed=3.0; + else { + var toAdd = core.status.replay.speed>=2?2:1; + core.status.replay.speed = parseInt(10*core.status.replay.speed - toAdd)/10; + } if (core.status.replay.speed<0.3) core.status.replay.speed=0.3; core.drawTip("x"+core.status.replay.speed+"倍"); } +////// 设置播放速度 ////// +control.prototype.setReplaySpeed = function (speed) { + if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; + if (!core.status.replay.replaying) return; + core.status.replay.speed = speed; + core.drawTip("x"+core.status.replay.speed+"倍"); +} + ////// 停止播放 ////// control.prototype.stopReplay = function () { if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; diff --git a/libs/core.js b/libs/core.js index b155f6e5..451ed925 100644 --- a/libs/core.js +++ b/libs/core.js @@ -148,6 +148,8 @@ function core() { "title": [255,215,0,1], "background": [0,0,0,0.85], "text": [255,255,255,1], + "titlefont": 22, + "textfont": 16, "bold": false, "time": 0, }, @@ -1065,6 +1067,11 @@ core.prototype.speedDownReplay = function () { core.control.speedDownReplay(); } +////// 设置播放速度 ////// +core.prototype.setReplaySpeed = function (speed) { + core.control.setReplaySpeed(speed); +} + ////// 回退播放 ////// core.prototype.rewindReplay = function () { core.control.rewindReplay(); diff --git a/libs/events.js b/libs/events.js index 5ea87222..b5bba1b4 100644 --- a/libs/events.js +++ b/libs/events.js @@ -345,18 +345,15 @@ events.prototype.doAction = function() { if (data.position=='up'||data.position=='down'||data.position=='center') { core.status.textAttribute.position=data.position; } + ["bold", "titlefont", "textfont", "time"].forEach(function (t) { + if (core.isset(data[t])) core.status.textAttribute[t]=data[t]; + }); ["background", "title", "text"].forEach(function (t) { if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length>=3) { if (data[t].length==3) data[t].push(1); core.status.textAttribute[t]=data[t]; } - }) - if (core.isset(data.bold)) { - core.status.textAttribute.bold=data.bold; - } - if (core.isset(data.time)) { - core.status.textAttribute.time=data.time; - } + }); core.setFlag('textAttribute', core.status.textAttribute); core.events.doAction(); break; diff --git a/libs/items.js b/libs/items.js index e177be96..82fcd95d 100644 --- a/libs/items.js +++ b/libs/items.js @@ -54,9 +54,6 @@ items.prototype.useItem = function (itemId, callback) { if (itemId in this.useItemEffect) { eval(this.useItemEffect[itemId]); } - - core.updateStatusBar(); - // 记录路线 if (itemId!='book' && itemId!='fly') { core.status.route.push("item:"+itemId); @@ -68,6 +65,8 @@ items.prototype.useItem = function (itemId, callback) { if (core.status.hero.items[itemCls][itemId]==0) delete core.status.hero.items[itemCls][itemId]; + core.updateStatusBar(); + if (core.isset(callback)) callback(); } diff --git a/libs/ui.js b/libs/ui.js index f7984067..9d2ffcd6 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -371,6 +371,9 @@ ui.prototype.drawTextBox = function(content, showAll) { var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + var titlefont = textAttribute.titlefont || 22; + var textfont = textAttribute.textfont || 16; + var position = textAttribute.position, px=null, py=null, ydelta=iconHeight-32; if (content.indexOf("\b[")==0 || content.indexOf("\\b[")==0) { var index = content.indexOf("]"); @@ -416,11 +419,11 @@ ui.prototype.drawTextBox = function(content, showAll) { if (id=='hero' || core.isset(icon)) content_left=left+63; var validWidth = right-(content_left-left)-13; - var font = '16px Verdana'; + var font = textfont + 'px Verdana'; if (textAttribute.bold) font = "bold "+font; var contents = core.splitLines("ui", content, validWidth, font); - var height = 20 + 21*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0); + var height = 20 + (textfont+5)*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?iconHeight-10:0); var xoffset = 6, yoffset = 22; @@ -506,14 +509,14 @@ ui.prototype.drawTextBox = function(content, showAll) { if (id == 'hero') { var heroHeight=core.material.icons.hero.height; core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, borderColor, 2); - core.fillText('ui', name, content_left, top + 30, null, 'bold 22px Verdana'); + core.fillText('ui', name, content_left, top + 30, null, 'bold '+titlefont+'px Verdana'); core.clearMap('ui', left + 15, top + 40, 32, heroHeight); core.fillRect('ui', left + 15, top + 40, 32, heroHeight, background); var heroIcon = core.material.icons.hero['down']; core.canvas.ui.drawImage(core.material.images.hero, heroIcon.stop * 32, heroIcon.loc * heroHeight, 32, heroHeight, left+15, top+40, 32, heroHeight); } else { - core.fillText('ui', name, content_left, top + 30, null, 'bold 22px Verdana'); + core.fillText('ui', name, content_left, top + 30, null, 'bold '+titlefont+'px Verdana'); if (core.isset(icon)) { core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, iconHeight + 2, borderColor, 2); @@ -543,7 +546,7 @@ ui.prototype.drawTextBox = function(content, showAll) { var contents = core.splitLines("ui", content, validWidth, font); for (var i=0;i