diff --git a/API列表.txt b/API列表.txt index dd1f5990..9c8b2129 100644 --- a/API列表.txt +++ b/API列表.txt @@ -1,4 +1,4 @@ -附录:API列表(V2.6版) +附录:API列表(V2.6.3版) 这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。 diff --git a/README.md b/README.md index 290b38b3..4d83c518 100644 --- a/README.md +++ b/README.md @@ -57,12 +57,17 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ### 2019.7.5 V2.6.3 +* [x] 标题界面大幅美化,支持键盘开始游戏 * [x] 事件编辑器支持自动补全,能对flag和API列表等进行补全 * [x] 剧情文本中\\c修改字体大小,\\d和\\e切换粗体和斜体 +* [x] 可以指定每个选择项的出现条件,动态生成 * [x] 楼层传送器的平面传送模式(哪里离开飞回到哪里) -* [x] UI绘制事件增添绘制圆和绘制圆边框 -* [x] 所有的UI绘制事件均可以双击预览 +* [x] UI绘制事件增添绘制圆(边框),且可直接双击预览 +* [x] 播放BGM事件可以一直持续播放直到下次调用 * [x] \f立绘支持alpha值 +* [x] 只有一个全局商店时V键能直接打开 +* [x] 支持在脚本编辑中直接flags.xxx调用自定义变量 +* [x] 首次获得道具将给予提示 * [x] 等待用户操作支持滚轮,视为PgUp和PgDn * [x] 脚本编辑器语法错误将禁止保存 * [x] 录像播放时B键查看数据统计 diff --git a/_docs/event.md b/_docs/event.md index 080108e4..eef54da8 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1433,6 +1433,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 目前支持mp3/ogg/wav等多种格式的音乐播放。 +从V2.6.3开始,还提供了keep项。如果此项为真,则会记录该bgm,并且持续到下次调用本事件位置(楼层切换不改变bgm,读档也有效)。 + 有关BGM播放的详细说明参见[背景音乐](element#背景音乐) ### pauseBgm:暂停背景音乐 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 92a7a378..27bacb0f 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -1468,15 +1468,16 @@ return code; */; playBgm_s - : '播放背景音乐' EvalString Newline + : '播放背景音乐' EvalString '持续到下个本事件' Bool Newline /* playBgm_s tooltip : playBgm: 播放背景音乐 helpUrl : https://h5mota.com/games/template/_docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90 -default : ["bgm.mp3"] +default : ["bgm.mp3", true] colour : this.soundColor -var code = '{"type": "playBgm", "name": "'+EvalString_0+'"},\n'; +Bool_0 = Bool_0 ? ', "keep": true' : ''; +var code = '{"type": "playBgm", "name": "'+EvalString_0+'"'+Bool_0+'},\n'; return code; */; @@ -1716,13 +1717,13 @@ return code; */; choicesContext - : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour BGNL? Newline action+ + : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour '出现条件' EvalString? BGNL? Newline action+ /* choicesContext tooltip : 选项的选择 helpUrl : https://h5mota.com/games/template/_docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9 -default : ["提示文字:红钥匙","",""] +default : ["提示文字:红钥匙","","",""] colour : this.subColor if (EvalString_1) { var colorRe = MotaActionFunctions.pattern.colorRe; @@ -1731,8 +1732,9 @@ if (EvalString_1) { else EvalString_1 = ', "color": "'+EvalString_1+'"'; } +EvalString_2 = EvalString_2 && (', "condition": "'+EvalString_2+'"') IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):''; -var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']},\n'; +var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+EvalString_2+', "action": [\n'+action_0+']},\n'; return code; */; @@ -3068,7 +3070,7 @@ ActionParser.prototype.parseAction = function() { break; case "playBgm": this.next = MotaActionBlocks['playBgm_s'].xmlText([ - data.name,this.next]); + data.name,data.keep||false,this.next]); break case "pauseBgm": this.next = MotaActionBlocks['pauseBgm_s'].xmlText([ @@ -3169,7 +3171,7 @@ ActionParser.prototype.parseAction = function() { for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) { choice.color = this.Colour(choice.color); text_choices=MotaActionBlocks['choicesContext'].xmlText([ - choice.text,choice.icon,choice.color,'rgba('+choice.color+')',this.insertActionList(choice.action),text_choices]); + choice.text,choice.icon,choice.color,'rgba('+choice.color+')',choice.condition||'',this.insertActionList(choice.action),text_choices]); } if (!this.isset(data.text)) data.text = ''; var info = this.getTitleAndPosition(data.text); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index afe04fe2..ebd20df0 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -76,9 +76,9 @@ editor_blockly = function () { MotaActionBlocks['confirm_s'].xmlText(), MotaActionBlocks['choices_s'].xmlText([ '选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([ - '剑','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), + '剑','','',null,'',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), MotaActionBlocks['choicesContext'].xmlText([ - '盾','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), + '盾','','',null,'',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), ]) ]) ]), diff --git a/_server/table/data.comment.js b/_server/table/data.comment.js index f6457473..3e1bacf1 100644 --- a/_server/table/data.comment.js +++ b/_server/table/data.comment.js @@ -63,6 +63,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_string": true, "_data": "标题样式:可以改变颜色,也可以写\"display: none\"来隐藏标题" }, + "startButtonsStyle": { + "_leaf": true, + "_type": "textarea", + "_string": true, + "_data": "标题界面按钮的样式;caret-color指的是当前选中项的边框颜色" + }, "levelChoose": { "_leaf": true, "_type": "textarea", diff --git a/libs/actions.js b/libs/actions.js index 3814f333..51eefbab 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -137,6 +137,7 @@ actions.prototype._sys_onkeyDown = function (e) { return; } } + e.preventDefault(); core.status.holdingKeys.push(e.keyCode); this.pressKey(e.keyCode); } else { @@ -198,6 +199,7 @@ actions.prototype._sys_onkeyUp = function (e) { break; } } + e.preventDefault(); this.keyUp(e.keyCode, e.altKey); } else { if (e.keyCode == 17) core.status.ctrlDown = false; diff --git a/libs/control.js b/libs/control.js index 67f930f1..50d25713 100644 --- a/libs/control.js +++ b/libs/control.js @@ -337,6 +337,8 @@ control.prototype._showStartAnimate_resetDom = function () { control.prototype._showStartAnimate_finished = function (start, callback) { core.dom.startTop.style.display = 'none'; core.dom.startButtonGroup.style.display = 'block'; + main.selectedButton = null; + main.selectButton(0); if (start) core.startGame(); if (callback) callback(); } @@ -1317,7 +1319,7 @@ control.prototype._replay_finished = function () { control.prototype._replay_save = function () { core.status.replay.steps++; - if (core.status.replay.steps%50==0) { + if (core.status.replay.steps%40==1) { if (core.status.replay.save.length == 30) core.status.replay.save.shift(); core.status.replay.save.push({"data": core.saveData(), "replay": { diff --git a/libs/events.js b/libs/events.js index 8326714d..4d61b05a 100644 --- a/libs/events.js +++ b/libs/events.js @@ -458,6 +458,24 @@ events.prototype.getItem = function (id, num, x, y, callback) { if (num > 1) text += "x" + num; if (itemCls === 'items') text += core.items.getItemEffectTip(id); core.drawTip(text, id); + + // --- 首次获得道具的提示 + if (!core.hasFlag("__itemHint__")) core.setFlag("__itemHint__", []); + var itemHint = core.getFlag("__itemHint__"); + if (itemHint.indexOf(id) < 0 && itemCls != 'items') { + var hint = core.material.items[id].text || "该道具暂无描述"; + try { + hint = core.replaceText(hint); + } catch (e) {} + core.insertAction("\t["+core.material.items[id].name+","+id+"]" + hint + "\n" + + (itemCls == 'keys' || id == 'greenKey' || id == 'steelKey' ? "(钥匙类道具,遇到对应的门时自动打开)" + : itemCls == 'tools' ? "(消耗类道具,请按T在道具栏使用)" + : itemCls == 'constants' ? "(永久类道具,请按T在道具栏使用)" + : itemCls == 'equips' ? "(装备类道具,请按Q在装备栏进行装备)" : "")) + itemHint.push(id); + } + + core.updateStatusBar(); this.afterGetItem(id, x, y, callback); @@ -510,6 +528,8 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback core.stopAutomaticRoute(); core.clearContinueAutomaticRoute(); core.status.replay.animate = true; + clearInterval(core.interval.onDownInterval); + core.interval.onDownInterval = 'tmp'; this._changeFloor_beforeChange(info, callback); } @@ -1243,6 +1263,7 @@ events.prototype._action_insert = function (data, x, y, prefix) { events.prototype._action_playBgm = function (data, x, y, prefix) { core.playBgm(data.name); + core.setFlag("__bgm__", data.keep ? data.name : null); core.doAction(); } @@ -1385,6 +1406,11 @@ events.prototype._action_switch = function (data, x, y, prefix) { } events.prototype._action_choices = function (data, x, y, prefix) { + data.choices = data.choices.filter(function (x) { + if (x.condition == null || x.condition == '') return true; + try { return core.calValue(x.condition, prefix); } catch (e) { return true; } + }) + if (data.choices.length == 0) return this.doAction(); if (core.isReplaying()) { var action = core.status.replay.toReplay.shift(), index; // --- 忽略可能的turn事件 @@ -1796,6 +1822,25 @@ events.prototype.openToolbox = function (fromUserAction) { ////// 点击快捷商店按钮时的打开操作 ////// events.prototype.openQuickShop = function (fromUserAction) { if (core.isReplaying()) return; + + if (Object.keys(core.status.shops).length == 0) { + core.drawTip("本塔没有快捷商店!"); + return; + } + + // --- 如果只有一个商店,则直接打开之 + if (Object.keys(core.status.shops).length == 1) { + var shopId = Object.keys(core.status.shops)[0]; + if (core.status.event.id != null || !this._checkStatus('shop', false)) return; + var reason = core.events.canUseQuickShop(shopId); + if (!core.flags.enableDisabledShop && reason) { + core.drawText(reason); + return; + } + core.events.openShop(shopId, true); + return; + } + if (!this._checkStatus('selectShop', fromUserAction)) return; core.ui.drawQuickShop(); } diff --git a/libs/utils.js b/libs/utils.js index daea03ea..6c99e3bb 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -914,7 +914,8 @@ utils.prototype.myconfirm = function (hint, yesCallback, noCallback) { main.dom.inputDiv.style.display = 'block'; main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); main.dom.inputBox.style.display = 'none'; - main.dom.inputYes.focus(); + main.dom.inputYes.blur(); + main.dom.inputNo.blur(); core.status.holdingKeys = []; core.platform.successCallback = yesCallback; @@ -927,6 +928,8 @@ utils.prototype.myprompt = function (hint, value, callback) { main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); main.dom.inputBox.style.display = 'block'; main.dom.inputBox.value = value==null?"":value; + main.dom.inputYes.blur(); + main.dom.inputNo.blur(); setTimeout(function () { main.dom.inputBox.focus(); }); diff --git a/main.js b/main.js index 18a16b97..e19c4143 100644 --- a/main.js +++ b/main.js @@ -204,6 +204,7 @@ main.prototype.init = function (mode, callback) { main.dom.startBackground.src="project/images/"+main.startBackground; main.dom.startLogo.style=main.startLogoStyle; + main.dom.startButtonGroup.style = main.startButtonsStyle; main.levelChoose.forEach(function(value){ var span = document.createElement('span'); span.setAttribute('class','startButton'); @@ -327,6 +328,31 @@ main.prototype.log = function (e) { } } +////// 选项 ////// +main.prototype.selectButton = function (index) { + var select = function (children) { + index = (index + children.length) % children.length; + for (var i = 0;i < children.length; ++i) { + children[i].style.borderColor = 'transparent'; + } + children[index].style.borderColor = main.dom.startButtonGroup.style.caretColor || '#FFD700'; + if (main.selectedButton == index) { + children[index].click(); + } + else { + main.selectedButton = index; + } + } + + if (core.dom.startPanel.style.display != 'block') return; + + if (main.dom.startButtons.style.display == 'block') { + select(main.dom.startButtons.children); + } + else if (main.dom.levelChooseButtons.style.display == 'block') { + select(main.dom.levelChooseButtons.children); + } +} main.prototype.listen = function () { @@ -349,8 +375,32 @@ main.dom.body.onkeydown = function(e) { ////// 在界面上放开某按键时 ////// main.dom.body.onkeyup = function(e) { try { - if (main.dom.inputDiv.style.display == 'block') return; - if (main.core && (main.core.isPlaying() || main.core.status.lockControl)) + if (main.dom.startPanel.style.display == 'block' && + (main.dom.startButtons.style.display == 'block' || main.dom.levelChooseButtons.style.display == 'block')) { + if (e.keyCode == 38 || e.keyCode == 33) // up/pgup + main.selectButton((main.selectedButton||0) - 1); + else if (e.keyCode == 40 || e.keyCode == 34) // down/pgdn + main.selectButton((main.selectedButton||0) + 1); + else if (e.keyCode == 67 || e.keyCode == 13 || e.keyCode == 32) // C/Enter/Space + main.selectButton(main.selectedButton); + e.stopPropagation(); + return; + } + if (main.dom.inputDiv.style.display == 'block') { + if (e.keyCode == 13) { + setTimeout(function () { + main.dom.inputYes.click(); + }, 50); + } + else if (e.keyCode == 27) { + setTimeout(function () { + main.dom.inputNo.click(); + }, 50); + } + return; + } + if (main.core && main.core.isPlaying && main.core.status && + (main.core.isPlaying() || main.core.status.lockControl)) main.core.onkeyUp(e); } catch (ee) { main.log(ee); } } @@ -649,6 +699,8 @@ main.dom.playGame.onclick = function () { } else { main.dom.levelChooseButtons.style.display='block'; + main.selectedButton = null; + main.selectButton(0); } } @@ -693,19 +745,6 @@ main.dom.inputNo.onclick = function () { if (func) func(null); } -main.dom.inputDiv.onkeyup = function (e) { - if (e.keyCode == 13) { - setTimeout(function () { - main.dom.inputYes.click(); - }, 50); - } - else if (e.keyCode == 27) { - setTimeout(function () { - main.dom.inputNo.click(); - }, 50); - } -} - }//listen end var main = new main(); \ No newline at end of file diff --git a/project/data.js b/project/data.js index 9469147f..29c59b80 100644 --- a/project/data.js +++ b/project/data.js @@ -72,7 +72,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "hardLabelColor": "red", "floorChangingBackground": "black", "floorChangingTextColor": "white", - "font": "Verdana" + "font": "Verdana", + "startButtonsStyle": "background-color: #32369F; opacity: 0.85; color: #FFFFFF; border: #FFFFFF 2px solid; caret-color: #FFD700;" }, "firstData": { "title": "魔塔样板", diff --git a/project/functions.js b/project/functions.js index 65b5e6f0..774e6b9e 100644 --- a/project/functions.js +++ b/project/functions.js @@ -15,6 +15,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.played = true; // 初始化人物,图标,统计信息 core.status.hero = core.clone(hero); + window.flags = core.status.hero.flags; core.events.setHeroIcon(core.getFlag('heroIcon', 'hero.png'), true); core.control._initStatistics(core.animateFrame.totalTime); core.status.hero.statistics.totalTime = core.animateFrame.totalTime = @@ -141,7 +142,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.status.maps[floorId].bgm) { var bgm = core.status.maps[floorId].bgm; if (bgm instanceof Array) bgm = bgm[0]; - core.playBgm(bgm); + if (!core.hasFlag("__bgm__")) core.playBgm(bgm); } // 更改画面色调 var color = core.getFlag('__color__', null); @@ -1003,7 +1004,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 切换到对应的楼层 core.changeFloor(data.floorId, null, data.hero.loc, 0, function () { // TODO:可以在这里设置读档后播放BGM - // if (core.getFlag("bgm", 0)==1) core.playBgm("bgm.mp3"); + if (core.hasFlag("__bgm__")) { // 持续播放 + core.playBgm(core.getFlag("__bgm__")); + } if (callback) callback(); }, true); diff --git a/project/items.js b/project/items.js index bc656898..1c5b4c7f 100644 --- a/project/items.js +++ b/project/items.js @@ -3,15 +3,18 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "items": { "yellowKey": { "cls": "keys", - "name": "黄钥匙" + "name": "黄钥匙", + "text": "可以打开一扇黄门" }, "blueKey": { "cls": "keys", - "name": "蓝钥匙" + "name": "蓝钥匙", + "text": "可以打开一扇蓝门" }, "redKey": { "cls": "keys", - "name": "红钥匙" + "name": "红钥匙", + "text": "可以打开一扇红门" }, "redJewel": { "cls": "items", diff --git a/styles.css b/styles.css index a1d6649e..ccdb83cb 100644 --- a/styles.css +++ b/styles.css @@ -117,16 +117,25 @@ } #startButtonGroup { - width: 100%; + width: auto; position: absolute; text-align: center; font-size: 1.4rem; - background-color: #000; - opacity: 0.85; display: none; z-index: 310; bottom: 0; - margin-bottom: 7%; + margin-bottom: 5%; + left: 50%; + transform: translateX(-50%); + padding: 15px 25px; + min-width: 20%; + /* default value */ + background-color: #32369F; + opacity: 0.85; + color: #FFFFFF; + border: #FFFFFF 2px solid; + caret-color: #FFD700; + border-radius: 10px; } #startButtons { @@ -139,15 +148,15 @@ .startButton { width: 100%; - margin: 20px 0; - color: #fff; + margin: 0; font-weight: bold; display: block; cursor: pointer; -} - -.startButton:hover { - color: #ff0000; + padding: 4px 0; + border-color: transparent; + border-width: 2px; + border-style: solid; + border-radius: 6px; } #floorMsgGroup { diff --git a/更新说明.txt b/更新说明.txt index 1ad4ea48..8e690e8e 100644 --- a/更新说明.txt +++ b/更新说明.txt @@ -1,11 +1,16 @@ HTML5魔塔样板V2.6.3 +标题界面大幅美化,支持键盘开始游戏 事件编辑器支持自动补全,能对flag和API列表等进行补全 剧情文本中\\c修改字体大小,\\d和\\e切换粗体和斜体 +可以指定每个选择项的出现条件,动态生成 楼层传送器的平面传送模式(哪里离开飞回到哪里) UI绘制事件增添绘制圆和绘制圆边框 所有的UI绘制事件均可以双击预览 +播放BGM事件可以一直持续播放直到下次调用 \f立绘支持alpha值 +支持在脚本编辑中直接flags.xxx调用自定义变量 +首次获得道具将给予提示 等待用户操作支持滚轮,视为PgUp和PgDn 脚本编辑器语法错误将禁止保存 录像播放时B键查看数据统计