diff --git a/README.md b/README.md
index aa6b6e24..ec5f01ec 100644
--- a/README.md
+++ b/README.md
@@ -53,10 +53,12 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
* [x] 同一个点的多事件处理(做法详见文档)。
* [x] 增加新地图后可以接档而不用重新开始。
* [x] 增加可以接收用户输入的事件(type:input)。
+* [x] 滚动字幕;自动剧情文本。
* [x] 可以同时show/hide多个事件。
* [x] 现在可以支持滑冰和推箱子事件了。
* [x] 地图中每个块的可通行方向控制(悬崖效果)。
* [x] 动画支持带旋转和翻转的帧。
+* [x] 长按屏幕可跳过对话。
* [x] 现在可以允许用户丢弃道具了(例如不会再使用的装备)。
* [x] 修复行走时按键会发生动画抖动问题。
* [x] 修复无法打开战斗动画的Bug。
diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4
index efc92009..385f166e 100644
--- a/_server/blockly/MotaAction.g4
+++ b/_server/blockly/MotaAction.g4
@@ -155,6 +155,7 @@ return code;
action
: text_0_s
| text_1_s
+ | autoText_s
| setText_s
| tip_s
| setValue_s
@@ -201,7 +202,7 @@ text_0_s
/* text_0_s
tooltip : text:显示一段文字(剧情)
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=text%ef%bc%9a%e6%98%be%e7%a4%ba%e4%b8%80%e6%ae%b5%e6%96%87%e5%ad%97%ef%bc%88%e5%89%a7%e6%83%85%ef%bc%89
-default : ["欢迎使用事件编辑器"]
+default : ["欢迎使用事件编辑器(双击方块进入多行编辑)"]
var code = '"'+EvalString_0+'",\n';
return code;
*/
@@ -213,7 +214,7 @@ text_1_s
/* text_1_s
tooltip : text:显示一段文字(剧情),选项较多请右键点击帮助
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=text%ef%bc%9a%e6%98%be%e7%a4%ba%e4%b8%80%e6%ae%b5%e6%96%87%e5%ad%97%ef%bc%88%e5%89%a7%e6%83%85%ef%bc%89
-default : ["小妖精","fairy","","欢迎使用事件编辑器"]
+default : ["小妖精","fairy","","欢迎使用事件编辑器(双击方块进入多行编辑)"]
var title='';
if (EvalString_0==''){
if (IdString_0=='')title='';
@@ -230,14 +231,38 @@ var code = '"'+title+EvalString_1+EvalString_2+'",\n';
return code;
*/
+autoText_s
+ : '自动剧情文本: 标题' EvalString? '图像' IdString? '对话框效果' EvalString? '时间' Int BGNL? EvalString Newline
+ ;
+
+/* autoText_s
+tooltip : autoText:自动剧情文本,用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示
+helpUrl : https://ckcz123.github.io/mota-js/#/event?id=autotext%ef%bc%9a%e8%87%aa%e5%8a%a8%e5%89%a7%e6%83%85%e6%96%87%e6%9c%ac
+default : ["小妖精","fairy","",3000,"双击方块进入多行编辑\\n自动剧情文本\\n自动剧情文本\\n自动剧情文本"]
+var title='';
+if (EvalString_0==''){
+ if (IdString_0=='')title='';
+ else title='\\t['+IdString_0+']';
+} else {
+ if (IdString_0=='')title='\\t['+EvalString_0+']';
+ else title='\\t['+EvalString_0+','+IdString_0+']';
+}
+if(EvalString_1 && !(/^(up|down)(,hero)?(,([+-]?\d+),([+-]?\d+))?$/.test(EvalString_1))) {
+ throw new Error('对话框效果的用法请右键点击帮助');
+}
+EvalString_1 = EvalString_1 && ('\\b['+EvalString_1+']');
+var code = '{"type": "autoText", "text": "'+title+EvalString_1+EvalString_2+'", "time" :'+Int_0+'},\n';
+return code;
+*/
+
setText_s
- : '设置剧情文本的属性' '位置' SetTextPosition_List BGNL? '标题颜色' EvalString? '正文颜色' EvalString? '背景色' EvalString? '粗体' B_List Newline
+ : '设置剧情文本的属性' '位置' SetTextPosition_List BGNL? '标题颜色' EvalString? '正文颜色' EvalString? '背景色' EvalString? BGNL? '粗体' B_List '打字间隔' EvalString? Newline
;
/* setText_s
-tooltip : setText:设置剧情文本的属性,颜色为RGB三元组或RGBA四元组
+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'],['上','up'],['中','center'],['下','down']],"255,215,0,1","255,255,255,1","0,0,0,0.85",[['不改变','null'],['设为粗体','true'],['取消粗体','false']]]
+default : [[['不改变','null'],['上','up'],['中','center'],['下','down']],"","","",[['不改变','null'],['设为粗体','true'],['取消粗体','false']],'']
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) {
@@ -252,8 +277,12 @@ if (EvalString_2) {
if (!colorRe.test(EvalString_2))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
EvalString_2 = ', "background": ['+EvalString_2+']';
}
+if (EvalString_3) {
+ if (!/^\d+$/.test(EvalString_3))throw new Error('打字时间间隔必须是整数或不填');
+ EvalString_3 = ', "time": '+EvalString_3;
+}
B_List_0 = ', "bold": '+B_List_0;
-var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_List_0+'},\n';
+var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_List_0+EvalString_3+'},\n';
return code;
*/
@@ -1117,7 +1146,7 @@ ActionParser.prototype.parseAction = function() {
// 如果是文字:显示
if (typeof data == "string") {
- data={"type": "text", "data": data}
+ data={"type": "text", "text": data}
}
this.event.data.type=data.type;
switch (data.type) {
@@ -1127,7 +1156,12 @@ ActionParser.prototype.parseAction = function() {
return;
case "text": // 文字/对话
this.next = MotaActionBlocks['text_0_s'].xmlText([
- this.EvalString(data.data),this.next]);
+ this.EvalString(data.text),this.next]);
+ break;
+ case "autoText": // 自动剧情文本
+ data.time=this.isset(data.time)?data.time:MotaActionBlocks['autoText_s'].fieldDefault[3];
+ this.next = MotaActionBlocks['autoText_s'].xmlText([
+ '','','',data.time,this.EvalString(data.text),this.next]);
break;
case "setText": // 设置剧情文本的属性
var setTextfunc = function(a){return a?JSON.stringify(a).slice(1,-1):null;}
@@ -1135,7 +1169,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,this.next]);
+ data.position,data.title,data.text,data.background,data.bold,data.time,this.next]);
break;
case "tip":
this.next = MotaActionBlocks['tip_s'].xmlText([
diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js
index 7d6da9ea..71f83494 100644
--- a/_server/editor_blockly.js
+++ b/_server/editor_blockly.js
@@ -53,6 +53,13 @@ initscript=String.raw`
'',
MotaActionBlocks['text_0_s'].xmlText(),
MotaActionBlocks['text_1_s'].xmlText(),
+ MotaActionFunctions.actionParser.parseList({"type": "choices", "text": "是否跳过剧情", "choices": [
+ {"text": "是", "action": []},
+ {"text": "否", "action": [
+ {"type": "autoText", "text": "\\t[小妖精,fairy]双击方块进入多行编辑\\n用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示\\n自动剧情文本\\n自动剧情文本\\n自动剧情文本", "time" :3000},
+ {"type": "autoText", "text": "(可以右键方块后点复制)", "time" :3000},
+ ]},
+ ]}),
MotaActionBlocks['setText_s'].xmlText(),
MotaActionBlocks['showImage_0_s'].xmlText(),
MotaActionBlocks['showImage_1_s'].xmlText(),
@@ -372,6 +379,7 @@ editor_blockly.doubleClickBlock = function (blockId){
var textStringDict = {
'text_0_s':'EvalString_0',
'text_1_s':'EvalString_2',
+ 'autoText_s':'EvalString_2',
'choices_s':'EvalString_0',
'function_s':'RawEvalString_0',
}
diff --git a/docs/event.md b/docs/event.md
index b2482c59..879ac5d1 100644
--- a/docs/event.md
+++ b/docs/event.md
@@ -150,14 +150,14 @@
### text:显示一段文字(剧情)
-使用`{"type": "text"}`可以显示一段文字。后面`"data"`可以指定文字内容。
+使用`{"type": "text"}`可以显示一段文字。后面`"text"`可以指定文字内容。
``` js
"events": { // 该楼的所有可能事件列表
// 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号
"x,y": [ // 实际执行的事件列表
- {"type": "text", "data": "在界面上的一段文字"}, // 显示文字事件
- {"type": "text", "data": "这是第二段文字"}, // 显示第二个文字事件
+ {"type": "text", "text": "在界面上的一段文字"}, // 显示文字事件
+ {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件
// ...
// 按顺序写事件,直到结束
]
@@ -171,7 +171,7 @@
// 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号
"x,y": [ // 实际执行的事件列表
"在界面上的一段文字",// 直接简写,和下面写法完全等价
- {"type": "text", "data": "这是第二段文字"}, // 显示第二个文字事件
+ {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件
// ...
// 按顺序写事件,直到结束
]
@@ -261,26 +261,49 @@

+### autoText:自动剧情文本
+
+使用`{"type": "autoText"}`可以使用剧情文本。
+
+``` js
+"x,y": [ // 实际执行的事件列表
+ {"type": "autoText", "text": "一段自动显示的剧情文字", "time": 5000}
+]
+```
+
+text为文本正文内容,和上面的写法完全一致。
+
+time为可选项,代表该自动文本的时间。可以不指定,不指定默认为3000毫秒。
+
+用户无法跳过自动剧情文本,只能等待time时间结束后自动过。
+
+回放录像时将忽略自动剧情文本的显示。
+
+!> 由于用户无法跳过自动剧情文本,因此对于大段剧情文本请自行添加“是否跳过剧情”的提示,否则可能会非常不友好。
+
### setText:设置剧情文本的属性
使用`{"type": "setText"}`可以设置剧情文本的各项属性。
``` js
"x,y": [ // 实际执行的事件列表
- {"type": "setText", "position": "up", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3], "bold": true},
- "这段话将显示在上方,标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色"
+ {"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毫秒速度打字机效果"
]
```
-position为可选项,表示设置文字显示位置。只能为up(上),center(中)和down(下)三者。
+title为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示标题(名字)颜色。 默认值:`[255,215,0,1]`
-title为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示标题(名字)颜色。
+text为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示正文颜色。 默认值:`[255,255,255,1]`
-text为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示正文颜色。
+background为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示背景色。 默认值:`[0,0,0,0.85]`
-background为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示背景色。
+position为可选项,表示设置文字显示位置。只能为up(上),center(中)和down(下)三者。 默认值: `center`
-bold为可选项,如果设置则为true或false,表示正文是否使用粗体。
+bold为可选项,如果设置则为true或false,表示正文是否使用粗体。 默认值:`false`
+
+time为可选项,表示文字添加的速度。若此项设置为0将直接全部显示,若大于0则会设置为相邻字符依次显示的时间间隔。 默认值:`0`
### tip:显示一段提示文字
diff --git a/docs/index.html b/docs/index.html
index 79028c98..f29c2402 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -6,7 +6,9 @@
+
+
diff --git a/editor.html b/editor.html
index 1617c843..ecc3947b 100644
--- a/editor.html
+++ b/editor.html
@@ -192,20 +192,15 @@
资源即将开始加载
-
-
-
+
+
diff --git a/index.html b/index.html
index 5c84fe0c..3d8ecc60 100644
--- a/index.html
+++ b/index.html
@@ -25,20 +25,15 @@
资源即将开始加载
-
-
-
+
+
diff --git a/libs/core.js b/libs/core.js
index 91412644..e61bb02a 100644
--- a/libs/core.js
+++ b/libs/core.js
@@ -17,12 +17,14 @@ function core() {
this.timeout = {
'getItemTipTimeout': null,
'turnHeroTimeout': null,
+ 'onDownTimeout': null,
}
this.interval = {
'heroMoveInterval': null,
"tipAnimate": null,
'openDoorAnimate': null,
'animateInterval': null,
+ 'onDownInterval': null,
}
this.animateFrame = {
'background': null,
@@ -124,6 +126,7 @@ function core() {
'data': null,
'selection': null,
'ui': null,
+ 'interval': null,
},
'textAttribute': {
'position': "center",
@@ -131,6 +134,7 @@ function core() {
"background": [0,0,0,0.85],
"text": [255,255,255,1],
"bold": false,
+ "time": 0,
},
'curtainColor': null,
'usingCenterFly':false,
@@ -775,8 +779,13 @@ core.prototype.clearStatus = function() {
core.prototype.resetStatus = function(hero, hard, floorId, route, maps) {
// 停止各个Timeout和Interval
+ for (var i in core.timeout) {
+ clearTimeout(core.timeout[i]);
+ core.timeout[i] = null;
+ }
for (var i in core.interval) {
clearInterval(core.interval[i]);
+ core.interval[i] = null;
}
// 初始化status
@@ -1229,6 +1238,18 @@ core.prototype.ondown = function (x ,y) {
if (core.isset(core.status.replay)&&core.status.replay.replaying) return;
if (!core.status.played || core.status.lockControl) {
core.onclick(x, y, []);
+ if (core.timeout.onDownTimeout==null) {
+ core.timeout.onDownTimeout = setTimeout(function () {
+ if (core.interval.onDownInterval == null) {
+ core.interval.onDownInterval = setInterval(function () {
+ if (!core.events.longClick()) {
+ clearInterval(core.interval.onDownInterval);
+ core.interval.onDownInterval = null;
+ }
+ }, 40)
+ }
+ }, 500);
+ }
return;
}
@@ -1271,6 +1292,12 @@ core.prototype.onmove = function (x ,y) {
////// 当点击(触摸)事件放开时 //////
core.prototype.onup = function () {
if (core.isset(core.status.replay)&&core.status.replay.replaying) return;
+
+ clearTimeout(core.timeout.onDownTimeout);
+ core.timeout.onDownTimeout = null;
+ clearInterval(core.interval.onDownInterval);
+ core.interval.onDownInterval = null;
+
// core.status.holdingPath=0;
if(core.status.stepPostfix.length>0){
var stepPostfix = [];
@@ -1290,7 +1317,10 @@ core.prototype.onup = function () {
// 长按
if (!core.status.lockControl && stepPostfix.length==0 && core.status.downTime!=null && new Date()-core.status.downTime>=1000) {
- core.events.longClick();
+ core.waitHeroToStop(function () {
+ // 绘制快捷键
+ core.ui.drawKeyBoard();
+ });
}
else {
//posx,posy是寻路的目标点,stepPostfix是后续的移动
diff --git a/libs/events.js b/libs/events.js
index 95a8283d..cc1b05a1 100644
--- a/libs/events.js
+++ b/libs/events.js
@@ -1,7 +1,7 @@
function events() {
}
-
+var eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events;
////// 初始化 //////
events.prototype.init = function () {
this.events = {
@@ -105,52 +105,16 @@ events.prototype.startGame = function (hard) {
}
////// 不同难度分别设置初始属性 //////
-events.prototype.setInitData = function (hard) {
- if (hard=='Easy') { // 简单难度
- core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度
- // 可以在此设置一些初始福利,比如设置初始生命值可以调用:
- // core.setStatus("hp", 10000);
- // 赠送一把黄钥匙可以调用
- // core.setItem("yellowKey", 1);
- }
- if (hard=='Normal') { // 普通难度
- core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度
- }
- if (hard=='Hard') { // 困难难度
- core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度
- }
- this.afterLoadData();
-}
+events.prototype.setInitData = eventdata.setInitData
+// function (hard)
////// 游戏获胜事件 //////
-events.prototype.win = function(reason) {
- core.ui.closePanel();
- var replaying = core.status.replay.replaying;
- core.stopReplay();
- core.waitHeroToStop(function() {
- core.removeGlobalAnimate(0,0,true);
- core.clearMap('all'); // 清空全地图
- core.drawText([
- "\t[恭喜通关]你的分数是${status:hp}。"
- ], function () {
- core.events.gameOver('', replaying);
- })
- });
-}
+events.prototype.win = eventdata.win
+// function(reason)
////// 游戏失败事件 //////
-events.prototype.lose = function(reason) {
- core.ui.closePanel();
- var replaying = core.status.replay.replaying;
- core.stopReplay();
- core.waitHeroToStop(function() {
- core.drawText([
- "\t[结局1]你死了。\n如题。"
- ], function () {
- core.events.gameOver(null, replaying);
- });
- })
-}
+events.prototype.lose = eventdata.lose
+// function(reason)
////// 游戏结束 //////
events.prototype.gameOver = function (ending, fromReplay) {
@@ -230,20 +194,8 @@ events.prototype.gameOver = function (ending, fromReplay) {
}
////// 转换楼层结束的事件 //////
-events.prototype.afterChangeFloor = function (floorId) {
- if (core.isset(core.status.event.id)) return; // 当前存在事件
-
- if (!core.hasFlag("visited_"+floorId)) {
- this.doEvents(core.floors[floorId].firstArrive, null, null, function () {
- //core.autosave();
- });
- core.setFlag("visited_"+floorId, true);
- return;
- }
-
- // 自动存档
- //core.autosave();
-}
+events.prototype.afterChangeFloor = eventdata.afterChangeFloor
+// function (floorId)
////// 开始执行一系列自定义事件 //////
events.prototype.doEvents = function (list, x, y, callback) {
@@ -266,6 +218,8 @@ events.prototype.doEvents = function (list, x, y, callback) {
events.prototype.doAction = function() {
// 清空boxAnimate和UI层
core.status.boxAnimateObjs = [];
+ clearInterval(core.status.event.interval);
+
core.clearMap('ui', 0, 0, 416, 416);
core.setAlpha('ui', 1.0);
@@ -301,7 +255,17 @@ events.prototype.doAction = function() {
if (core.status.replay.replaying)
core.events.doAction();
else
- core.ui.drawTextBox(data.data);
+ core.ui.drawTextBox(data.text);
+ break;
+ case "autoText":
+ if (core.status.replay.replaying)
+ core.events.doAction();
+ else {
+ core.ui.drawTextBox(data.text);
+ setTimeout(function () {
+ core.events.doAction();
+ }, data.time || 3000);
+ }
break;
case "setText": // 设置文本状态
if (data.position=='up'||data.position=='down'||data.position=='center') {
@@ -316,6 +280,9 @@ events.prototype.doAction = function() {
if (core.isset(data.bold)) {
core.status.textAttribute.bold=data.bold;
}
+ if (core.isset(data.time)) {
+ core.status.textAttribute.time=data.time;
+ }
core.events.doAction();
break;
case "tip":
@@ -777,124 +744,16 @@ events.prototype.useItem = function(itemId) {
}
////// 加点事件 //////
-events.prototype.addPoint = function (enemy) {
- var point = enemy.point;
- if (!core.isset(point) || point<=0) return [];
-
- // 加点,返回一个choices事件
- return [
- {"type": "choices",
- "choices": [
- {"text": "攻击+"+(1*point), "action": [
- {"type": "setValue", "name": "status:atk", "value": "status:atk+"+(1*point)}
- ]},
- {"text": "防御+"+(2*point), "action": [
- {"type": "setValue", "name": "status:def", "value": "status:def+"+(2*point)}
- ]},
- {"text": "生命+"+(200*point), "action": [
- {"type": "setValue", "name": "status:hp", "value": "status:hp+"+(200*point)}
- ]},
- ]
- }
- ];
-}
+events.prototype.addPoint = eventdata.addPoint
+// function (enemy)
////// 战斗结束后触发的事件 //////
-events.prototype.afterBattle = function(enemyId,x,y,callback) {
-
- var enemy = core.material.enemys[enemyId];
-
- // 毒衰咒的处理
- var special = enemy.special;
- // 中毒
- if (core.enemys.hasSpecial(special, 12) && !core.hasFlag('poison')) {
- core.setFlag('poison', true);
- }
- // 衰弱
- if (core.enemys.hasSpecial(special, 13) && !core.hasFlag('weak')) {
- core.setFlag('weak', true);
- core.status.hero.atk-=core.values.weakValue;
- core.status.hero.def-=core.values.weakValue;
- }
- // 诅咒
- if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) {
- core.setFlag('curse', true);
- }
- // 仇恨属性:减半
- if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) {
- core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2));
- }
- // 自爆
- if (core.enemys.hasSpecial(special, 19)) {
- core.status.hero.hp = 1;
- }
- // 退化
- if (core.enemys.hasSpecial(special, 21)) {
- core.status.hero.atk -= (enemy.atkValue||0);
- core.status.hero.def -= (enemy.defValue||0);
- if (core.status.hero.atk<0) core.status.hero.atk=0;
- if (core.status.hero.def<0) core.status.hero.def=0;
- }
- // 增加仇恨值
- core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred);
- core.updateStatusBar();
-
-
- // 事件的处理
- var todo = [];
- // 如果不为阻击,且该点存在,且有事件
- if (!core.enemys.hasSpecial(special, 18) && core.isset(x) && core.isset(y)) {
- var event = core.floors[core.status.floorId].afterBattle[x+","+y];
- if (core.isset(event)) {
- // 插入事件
- core.unshift(todo, event);
- }
- }
- // 如果有加点
- var point = core.material.enemys[enemyId].point;
- if (core.isset(point) && point>0) {
- core.unshift(todo, core.events.addPoint(core.material.enemys[enemyId]));
- }
-
- // 如果事件不为空,将其插入
- if (todo.length>0) {
- this.insertAction(todo,x,y);
- }
-
- // 如果已有事件正在处理中
- if (core.status.event.id == null) {
- core.continueAutomaticRoute();
- }
- else {
- core.clearContinueAutomaticRoute();
- }
- if (core.isset(callback)) callback();
-
-}
+events.prototype.afterBattle = eventdata.afterBattle
+// function(enemyId,x,y,callback)
////// 开一个门后触发的事件 //////
-events.prototype.afterOpenDoor = function(doorId,x,y,callback) {
-
- var todo = [];
- if (core.isset(x) && core.isset(y)) {
- var event = core.floors[core.status.floorId].afterOpenDoor[x+","+y];
- if (core.isset(event)) {
- core.unshift(todo, event);
- }
- }
-
- if (todo.length>0) {
- this.insertAction(todo,x,y);
- }
-
- if (core.status.event.id == null) {
- core.continueAutomaticRoute();
- }
- else {
- core.clearContinueAutomaticRoute();
- }
- if (core.isset(callback)) callback();
-}
+events.prototype.afterOpenDoor = eventdata.afterOpenDoor
+// function(doorId,x,y,callback)
////// 经过一个路障 //////
events.prototype.passNet = function (data) {
@@ -945,9 +804,8 @@ events.prototype.changeLight = function(x, y) {
}
////// 改变亮灯之后,可以触发的事件 //////
-events.prototype.afterChangeLight = function(x,y) {
-
-}
+events.prototype.afterChangeLight = eventdata.afterChangeLight
+// function(x,y)
////// 滑冰 //////
events.prototype.ski = function (direction) {
@@ -1024,54 +882,20 @@ events.prototype.pushBox = function (data) {
}
////// 推箱子后的事件 //////
-events.prototype.afterPushBox = function () {
-
- var noBoxLeft = function () {
- // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false
- for (var i=0;i', 270, top+height-13, '#CCCCCC', '13px Verdana');
}
////// 绘制一个选项界面 //////
@@ -400,7 +419,7 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) {
max_length = Math.max(max_length, core.canvas.ui.measureText(contents[i]).width);
}
- var left = Math.min(208 - 40 - max_length / 2, 100);
+ var left = Math.min(208 - 40 - parseInt(max_length / 2), 100);
var top = 140 - (lines-1)*30;
var right = 416 - 2 * left, bottom = 416 - 140 - top;
@@ -418,10 +437,10 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) {
var len=core.canvas.ui.measureText("确定").width;
if (core.status.event.selection==0) {
- core.strokeRect('ui', 208-38-len/2-5, top+bottom-35-20, len+10, 28, "#FFD700", 2);
+ core.strokeRect('ui', 208-38-parseInt(len/2)-5, top+bottom-35-20, len+10, 28, "#FFD700", 2);
}
if (core.status.event.selection==1) {
- core.strokeRect('ui', 208+38-len/2-5, top+bottom-35-20, len+10, 28, "#FFD700", 2);
+ core.strokeRect('ui', 208+38-parseInt(len/2)-5, top+bottom-35-20, len+10, 28, "#FFD700", 2);
}
}
@@ -776,7 +795,7 @@ ui.prototype.drawWaiting = function(text) {
var text_length = core.canvas.ui.measureText(text).width;
var right = Math.max(text_length+50, 220);
- var left = 208-right/2, top = 208 - 32 - 16, bottom = 416 - 2 * top;
+ var left = 208-parseInt(right/2), top = 208 - 32 - 16, bottom = 416 - 2 * top;
core.fillRect('ui', left, top, right, bottom, background);
core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2);
@@ -822,7 +841,7 @@ ui.prototype.drawPagination = function (page, totalPage) {
var length = core.canvas.ui.measureText(page + " / " + page).width;
core.canvas.ui.textAlign = 'left';
- core.fillText('ui', page + " / " + totalPage, (416 - length) / 2, 403);
+ core.fillText('ui', page + " / " + totalPage, parseInt((416 - length) / 2), 403);
core.canvas.ui.textAlign = 'center';
if (page > 1)
@@ -1231,7 +1250,7 @@ ui.prototype.drawSLPanel = function(index) {
core.setAlpha('ui', 1);
core.canvas.ui.textAlign = 'center';
- var u=416/6, size=117;
+ var u=416/6, size=118;
var name=core.status.event.id=='save'?"存档":"读档";
for (var i=0;i<6;i++) {
@@ -1371,33 +1390,7 @@ ui.prototype.drawKeyBoard = function () {
}
////// 绘制“关于”界面 //////
-ui.prototype.drawAbout = function() {
-
- if (!core.isPlaying()) {
- core.status.event = {'id': null, 'data': null};
- core.dom.startPanel.style.display = 'none';
- }
- core.lockControl();
- core.status.event.id = 'about';
-
- core.clearMap('ui', 0, 0, 416, 416);
- var left = 48, top = 36, right = 416 - 2 * left, bottom = 416 - 2 * top;
-
- core.setAlpha('ui', 0.85);
- core.fillRect('ui', left, top, right, bottom, '#000000');
- core.setAlpha('ui', 1);
- core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2);
-
- var text_start = left + 24;
-
- // 名称
- core.canvas.ui.textAlign = "left";
- core.fillText('ui', "HTML5 魔塔样板", text_start, top+35, "#FFD700", "bold 22px Verdana");
- core.fillText('ui', "版本: "+core.firstData.version, text_start, top + 80, "#FFFFFF", "bold 17px Verdana");
- core.fillText('ui', "作者: 艾之葵", text_start, top + 112);
- core.fillText('ui', 'HTML5魔塔交流群:539113091', text_start, top+112+32);
- // TODO: 写自己的“关于”页面,每次增加32像素即可
-}
+ui.prototype.drawAbout = uidata.drawAbout
////// 绘制帮助页面 //////
ui.prototype.drawHelp = function () {
@@ -1424,6 +1417,8 @@ ui.prototype.drawHelp = function () {
"点任意块并拖动: 指定寻路路线\n"+
"单击勇士: 转向\n"+
"双击勇士: 轻按(仅在轻按开关打开时有效)\n"+
- "长按任意位置:打开虚拟键盘"
+ "长按任意位置:跳过剧情对话或打开虚拟键盘\n"
]);
-}
\ No newline at end of file
+}
+
+delete(uidata)
\ No newline at end of file
diff --git a/main.js b/main.js
index bb18530f..c2fb77c8 100644
--- a/main.js
+++ b/main.js
@@ -17,6 +17,7 @@ function main() {
'startTopProgress': document.getElementById('startTopProgress'),
'startTopLoadTips': document.getElementById('startTopLoadTips'),
'startBackground': document.getElementById('startBackground'),
+ 'startLogo': document.getElementById('startLogo'),
'startButtonGroup': document.getElementById('startButtonGroup'),
'floorMsgGroup': document.getElementById('floorMsgGroup'),
'logoLabel': document.getElementById('logoLabel'),
@@ -33,9 +34,6 @@ function main() {
'loadGame': document.getElementById('loadGame'),
'replayGame': document.getElementById('replayGame'),
'levelChooseButtons': document.getElementById('levelChooseButtons'),
- 'easyLevel': document.getElementById('easyLevel'),
- 'normalLevel': document.getElementById('normalLevel'),
- 'hardLevel': document.getElementById('hardLevel'),
'data': document.getElementById('data'),
'statusLabels': document.getElementsByClassName('statusLabel'),
'floorCol': document.getElementById('floorCol'),
@@ -52,7 +50,7 @@ function main() {
'items', 'icons', 'maps', 'enemys', 'events', 'data', 'ui', 'core'
];
this.pureData = [
- "data","enemys","icons","maps","items"
+ "data","enemys","icons","maps","items","functions"
];
this.images = [
'animates', 'enemys', 'hero', 'items', 'npcs', 'terrains'
@@ -128,6 +126,21 @@ main.prototype.init = function (mode) {
main.loadPureData(function(){
var mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main;
for(var ii in mainData)main[ii]=mainData[ii];
+
+ main.dom.startBackground.src="project/images/"+main.startBackground;
+ main.dom.startLogo.style=main.startLogoStyle;
+ main.levelChoose.forEach(function(value){
+ var span = document.createElement('span');
+ span.setAttribute('class','startButton');
+ span.innerText=value[0];
+ (function(span,str_){
+ span.onclick = function () {
+ core.events.startGame(str_);
+ }
+ })(span,value[1]);
+ main.dom.levelChooseButtons.appendChild(span);
+ });
+
main.loaderJs(function () {
var coreData = {};
for (i = 0; i < main.loadList.length; i++) {
@@ -454,20 +467,6 @@ main.dom.replayGame.onclick = function () {
})
}
-////// 点击“简单难度”时 //////
-main.dom.easyLevel.onclick = function() {
- core.events.startGame('Easy');
-}
-
-////// 点击“普通难度”时 //////
-main.dom.normalLevel.onclick = function () {
- core.events.startGame('Normal');
-}
-
-////// 点击“困难难度”时 //////
-main.dom.hardLevel.onclick = function () {
- core.events.startGame('Hard');
-}
}//listen end
diff --git a/project/data.comment.js b/project/data.comment.js
index 7dad7ce9..7a901303 100644
--- a/project/data.comment.js
+++ b/project/data.comment.js
@@ -7,7 +7,10 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"animates": " 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 \n 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 \n \"jianji\", \"thunder\" \n 根据需求自行添加 \n$leaf(true)$end",
"bgms": " 在此存放所有的bgm,和文件名一致。第一项为默认播放项 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end",
"sounds": " 在此存放所有的SE,和文件名一致 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end",
- "bgmRemote" : " 是否使用远程的背景音乐;此项一般不要开启 \n$select({\"values\":[false]})$end"
+ "bgmRemote" : " 是否使用远程的背景音乐;此项一般不要开启 \n$select({\"values\":[false]})$end",
+ "startBackground" : "标题界面的背景,建议使用jpg格式以压缩背景图空间",
+ "startLogoStyle" : "标题样式:可以改变颜色,也可以隐藏标题(如果背景图自带)",
+ "levelChoose" : " 难度选择:每个数组的第一个是其在标题界面显示的难度,第二个是在游戏内部传输的字符串,会显示在状态栏,修改此处后需要在project/functions中作相应更改 \n$leaf(true)$end"
},
"firstData": {
"title": " 游戏名,将显示在标题页面以及切换楼层的界面中 ",
diff --git a/project/data.js b/project/data.js
index d47d1f2c..d8988833 100644
--- a/project/data.js
+++ b/project/data.js
@@ -33,6 +33,10 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
],
"bgmRemote" : false, // 是否使用远程的背景音乐;此项一般不要开启
+ "startBackground" : "bg.png",// 标题界面的背景,建议使用jpg格式以压缩背景图空间
+ "startLogoStyle" : "color: black",// 标题样式:可以改变颜色,也可以隐藏标题(如果背景图自带)
+ "levelChoose" : [["简单","Easy"],["普通","Normal"],["困难","Hard"],["噩梦","Hell"]],
+ //难度选择:每个数组的第一个是其在标题界面显示的难度,第二个是在游戏内部传输的字符串,会显示在状态栏,修改此处后需要在project/functions中作相应更改
},
"firstData" : {
"title": "魔塔样板", // 游戏名,将显示在标题页面以及切换楼层的界面中
diff --git a/project/functions.comment.js b/project/functions.comment.js
new file mode 100644
index 00000000..1540f623
--- /dev/null
+++ b/project/functions.comment.js
@@ -0,0 +1,21 @@
+functions_comment_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
+{
+ "events" : {
+ "setInitData" : "不同难度分别设置初始属性",
+ "win" : "游戏获胜事件",
+ "lose" : "游戏失败事件",
+ "afterChangeFloor":"转换楼层结束的事件",
+ "addPoint":"加点事件",
+ "afterBattle" : "战斗结束后触发的事件",
+ "afterOpenDoor" : "开一个门后触发的事件",
+ "afterChangeLight" : "改变亮灯之后,可以触发的事件",
+ "afterPushBox" : "推箱子后的事件",
+ "afterUseBomb" : "使用炸弹/圣锤后的事件",
+ "beforeSaveData" : "即将存档前可以执行的操作",
+ "afterLoadData" : "读档事件后,载入事件前,可以执行的操作"
+
+ },
+ "ui" : {
+ "drawAbout" : "绘制“关于”界面"
+ }
+}
\ No newline at end of file
diff --git a/project/functions.js b/project/functions.js
new file mode 100644
index 00000000..f93652ee
--- /dev/null
+++ b/project/functions.js
@@ -0,0 +1,267 @@
+functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
+{
+"events":{
+////// 不同难度分别设置初始属性 //////
+"setInitData":function (hard) {
+ if (hard=='Easy') { // 简单难度
+ core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度
+ // 可以在此设置一些初始福利,比如设置初始生命值可以调用:
+ // core.setStatus("hp", 10000);
+ // 赠送一把黄钥匙可以调用
+ // core.setItem("yellowKey", 1);
+ }
+ if (hard=='Normal') { // 普通难度
+ core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度
+ }
+ if (hard=='Hard') { // 困难难度
+ core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度
+ }
+ if (hard=='Hell') { // 噩梦难度
+ core.setFlag('hard', 4); // 可以用flag:hard来获得当前难度
+ }
+ this.afterLoadData();
+},
+////// 游戏获胜事件 //////
+"win" : function(reason) {
+ core.ui.closePanel();
+ var replaying = core.status.replay.replaying;
+ core.stopReplay();
+ core.waitHeroToStop(function() {
+ core.removeGlobalAnimate(0,0,true);
+ core.clearMap('all'); // 清空全地图
+ core.drawText([
+ "\t[恭喜通关]你的分数是${status:hp}。"
+ ], function () {
+ core.events.gameOver('', replaying);
+ })
+ });
+},
+////// 游戏失败事件 //////
+"lose" : function(reason) {
+ core.ui.closePanel();
+ var replaying = core.status.replay.replaying;
+ core.stopReplay();
+ core.waitHeroToStop(function() {
+ core.drawText([
+ "\t[结局1]你死了。\n如题。"
+ ], function () {
+ core.events.gameOver(null, replaying);
+ });
+ })
+},
+////// 转换楼层结束的事件 //////
+"afterChangeFloor" : function (floorId) {
+ if (core.isset(core.status.event.id)) return; // 当前存在事件
+
+ if (!core.hasFlag("visited_"+floorId)) {
+ this.doEvents(core.floors[floorId].firstArrive, null, null, function () {
+ //core.autosave();
+ });
+ core.setFlag("visited_"+floorId, true);
+ return;
+ }
+
+ // 自动存档
+ //core.autosave();
+},
+////// 加点事件 //////
+"addPoint" : function (enemy) {
+ var point = enemy.point;
+ if (!core.isset(point) || point<=0) return [];
+
+ // 加点,返回一个choices事件
+ return [
+ {"type": "choices",
+ "choices": [
+ {"text": "攻击+"+(1*point), "action": [
+ {"type": "setValue", "name": "status:atk", "value": "status:atk+"+(1*point)}
+ ]},
+ {"text": "防御+"+(2*point), "action": [
+ {"type": "setValue", "name": "status:def", "value": "status:def+"+(2*point)}
+ ]},
+ {"text": "生命+"+(200*point), "action": [
+ {"type": "setValue", "name": "status:hp", "value": "status:hp+"+(200*point)}
+ ]},
+ ]
+ }
+ ];
+},
+////// 战斗结束后触发的事件 //////
+"afterBattle" : function(enemyId,x,y,callback) {
+
+ var enemy = core.material.enemys[enemyId];
+
+ // 毒衰咒的处理
+ var special = enemy.special;
+ // 中毒
+ if (core.enemys.hasSpecial(special, 12) && !core.hasFlag('poison')) {
+ core.setFlag('poison', true);
+ }
+ // 衰弱
+ if (core.enemys.hasSpecial(special, 13) && !core.hasFlag('weak')) {
+ core.setFlag('weak', true);
+ core.status.hero.atk-=core.values.weakValue;
+ core.status.hero.def-=core.values.weakValue;
+ }
+ // 诅咒
+ if (core.enemys.hasSpecial(special, 14) && !core.hasFlag('curse')) {
+ core.setFlag('curse', true);
+ }
+ // 仇恨属性:减半
+ if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) {
+ core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2));
+ }
+ // 自爆
+ if (core.enemys.hasSpecial(special, 19)) {
+ core.status.hero.hp = 1;
+ }
+ // 退化
+ if (core.enemys.hasSpecial(special, 21)) {
+ core.status.hero.atk -= (enemy.atkValue||0);
+ core.status.hero.def -= (enemy.defValue||0);
+ if (core.status.hero.atk<0) core.status.hero.atk=0;
+ if (core.status.hero.def<0) core.status.hero.def=0;
+ }
+ // 增加仇恨值
+ core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred);
+ core.updateStatusBar();
+
+
+ // 事件的处理
+ var todo = [];
+ // 如果不为阻击,且该点存在,且有事件
+ if (!core.enemys.hasSpecial(special, 18) && core.isset(x) && core.isset(y)) {
+ var event = core.floors[core.status.floorId].afterBattle[x+","+y];
+ if (core.isset(event)) {
+ // 插入事件
+ core.unshift(todo, event);
+ }
+ }
+ // 如果有加点
+ var point = core.material.enemys[enemyId].point;
+ if (core.isset(point) && point>0) {
+ core.unshift(todo, core.events.addPoint(core.material.enemys[enemyId]));
+ }
+
+ // 如果事件不为空,将其插入
+ if (todo.length>0) {
+ this.insertAction(todo,x,y);
+ }
+
+ // 如果已有事件正在处理中
+ if (core.status.event.id == null) {
+ core.continueAutomaticRoute();
+ }
+ else {
+ core.clearContinueAutomaticRoute();
+ }
+ if (core.isset(callback)) callback();
+
+},
+////// 开一个门后触发的事件 //////
+"afterOpenDoor" : function(doorId,x,y,callback) {
+
+ var todo = [];
+ if (core.isset(x) && core.isset(y)) {
+ var event = core.floors[core.status.floorId].afterOpenDoor[x+","+y];
+ if (core.isset(event)) {
+ core.unshift(todo, event);
+ }
+ }
+
+ if (todo.length>0) {
+ this.insertAction(todo,x,y);
+ }
+
+ if (core.status.event.id == null) {
+ core.continueAutomaticRoute();
+ }
+ else {
+ core.clearContinueAutomaticRoute();
+ }
+ if (core.isset(callback)) callback();
+},
+////// 改变亮灯之后,可以触发的事件 //////
+"afterChangeLight" : function(x,y) {
+
+},
+////// 推箱子后的事件 //////
+"afterPushBox" : function () {
+
+ var noBoxLeft = function () {
+ // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false
+ for (var i=0;i