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键查看数据统计