diff --git a/README.md b/README.md
index 4ea48018..6738ca64 100644
--- a/README.md
+++ b/README.md
@@ -59,7 +59,20 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
## 更新说明
-### 2018.7.9 V2.3.3
+### 2018.7.21 V2.3.3
+
+* [x] 将怪物特殊属性定义和伤害计算函数移动到脚本编辑中
+* [x] 地图编辑器可以使用矩形方式绘制地图
+* [x] 瞬间移动可以指定存在事件的点(如怪物、门、楼梯等)
+* [x] 事件:画面震动
+* [x] 事件:更新怪物数据
+* [x] 移动事件和跳跃事件增加“不消失”选项
+* [x] 获胜结局可以指定“不计入榜单”
+* [x] 修改默认bgm
+* [x] 修复读档开启战斗动画等Bug
+* [x] 大量细节优化
+
+### 2018.7.9 V2.3.2
* [x] 适配手机端的造塔页面
* [x] 启动服务的多开版本
@@ -265,8 +278,27 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
## 联系我们
-本塔由 [`ckcz123`](https://github.com/ckcz123) (百度ID `艾之葵`)编写。
+本样板主要由 [`ckcz123`](https://github.com/ckcz123) (百度ID `艾之葵`)编写。
HTML5魔塔交流群群号: `539113091`
如有其它意见或建议,也可以通过发[issues](https://github.com/ckcz123/mota-js/issues)、或邮件至[ckcz123@126.com](mailto:ckcz123@126.com)联系我。
+
+## 贡献者
+
+感谢对本样板做出贡献的人员:
+
+[@ckcz123](https://github.com/ckcz123) 本样板的的主要编写者。样板的运行时的核心代码,所有常用小工具,以及安卓APP等,都是其所写。
+
+[@Vinlic](https://github.com/Vinlic) 第一个HTML5魔塔[纪元魔塔前传](https://tieba.baidu.com/p/4545234500)([游戏地址](http://vinlic.gitee.io/mota/),[开发记录贴](https://tieba.baidu.com/p/4397526540),[源代码](https://gitee.com/Vinlic/Mota))的编写者。
+该塔的[第三版内核](https://tieba.baidu.com/p/4738973089)是现在HTML5魔塔样板的前身,现在样板的很多核心逻辑控制,以及UI界面等相关代码都是继承于该塔。
+
+[@zhaouv](https://github.com/zhaouv) V2.0的推动者,可视化地图编辑器和事件编辑器的制作者,手机端魔塔制作界面的编写者。现在我们能在V2.0用到方便快捷的可视化地图编辑器,以及通过拖动图块来编写事件,能在手机端造塔等,都需要归功于zhaouv的贡献。
+
+[@iEcho](https://github.com/iEcho) V2.0的推动者,可视化地图编辑器的制作者,游戏界面自适应匹配的编写者。和zhaouv一起推动和开发了V2.0的制作。
+
+[@wadxm](https://github.com/wadxm) iOS平台的APP(因为苹果政策无法上架)和启动服务mac版的开发者。我们现在能在mac上制作魔塔得归功于他。
+
+[@fux4](https://github.com/fux4) 打通了RM和H5之间的障壁(从而使RM动画导出器和怪物数据导出器成为可能),同时也是部分新功能(如跳跃、跟随、画面震动)等的编写者。
+
+以及[百度贴吧魔塔吧](https://tieba.baidu.com/f?kw=%E9%AD%94%E5%A1%94)和H5魔塔交流群`539113091`内的诸位魔塔爱好者们对本样板的大力支持!
diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4
index 16938dcb..3a19e2ac 100644
--- a/_server/blockly/MotaAction.g4
+++ b/_server/blockly/MotaAction.g4
@@ -206,6 +206,7 @@ action
| follow_s
| unfollow_s
| animate_s
+ | viberate_s
| showImage_0_s
| showImage_1_s
| animateImage_0_s
@@ -652,6 +653,20 @@ var code = '{"type": "unfollow"' + EvalString_0 + '},\n';
return code;
*/;
+viberate_s
+ : '画面震动' '时间' Int Newline
+
+
+/* viberate_s
+tooltip : viberate: 画面震动
+helpUrl : https://ckcz123.github.io/mota-js/#/event?id=viberate%ef%bc%9a%e7%94%bb%e9%9d%a2%e9%9c%87%e5%8a%a8
+default : [2000]
+colour : this.soundColor
+Int_0 = Int_0 ?(', "time": '+Int_0):'';
+var code = '{"type": "viberate"' + Int_0 + '},\n';
+return code;
+*/;
+
animate_s
: '显示动画' IdString '位置' EvalString? Newline
@@ -819,20 +834,20 @@ return code;
*/;
move_s
- : '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '消失时无动画时间' Bool BGNL? StepString Newline
+ : '移动事件' 'x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool BGNL? StepString Newline
/* move_s
tooltip : move: 让某个NPC/怪物移动,位置可不填代表当前事件
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=move%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AAnpc%E6%80%AA%E7%89%A9%E7%A7%BB%E5%8A%A8
-default : ["","",500,null,"上右3下2左上左2"]
+default : ["","",500,false,"上右3下2左上左2"]
colour : this.eventColor
var floorstr = '';
if (PosString_0 && PosString_1) {
floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
}
Int_0 = Int_0 ?(', "time": '+Int_0):'';
-var code = '{"type": "move"'+floorstr+''+Int_0+', "steps": '+JSON.stringify(StepString_0)+', "immediateHide": '+Bool_0+'},\n';
+var code = '{"type": "move"'+floorstr+''+Int_0+', "steps": '+JSON.stringify(StepString_0)+', "keep": '+Bool_0+'},\n';
return code;
*/;
@@ -851,13 +866,13 @@ return code;
*/;
jump_s
- : '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? BGNL? '动画时间' Int? '消失时无动画时间' Bool Newline
+ : '跳跃事件' '起始 x' PosString? ',' 'y' PosString? '终止 x' PosString? ',' 'y' PosString? '动画时间' Int? '不消失' Bool Newline
/* jump_s
tooltip : jump: 让某个NPC/怪物跳跃
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=jump%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AANPC%2F%E6%80%AA%E7%89%A9%E8%B7%B3%E8%B7%83
-default : ["","","","",500,null]
+default : ["","","","",500,true]
colour : this.eventColor
var floorstr = '';
if (PosString_0 && PosString_1) {
@@ -867,7 +882,7 @@ if (PosString_2 && PosString_3) {
floorstr += ', "to": ['+PosString_2+','+PosString_3+']';
}
Int_0 = Int_0 ?(', "time": '+Int_0):'';
-var code = '{"type": "jump"'+floorstr+''+Int_0+', "immediateHide": '+Bool_0+'},\n';
+var code = '{"type": "jump"'+floorstr+''+Int_0+', "keep": '+Bool_0+'},\n';
return code;
*/;
@@ -954,14 +969,14 @@ return code;
*/;
win_s
- : '游戏胜利,结局' ':' EvalString? Newline
+ : '游戏胜利,结局' ':' EvalString? '不计入榜单' Bool Newline
/* win_s
tooltip : win: 获得胜利, 该事件会显示获胜页面, 并重新游戏
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=win%EF%BC%9A%E8%8E%B7%E5%BE%97%E8%83%9C%E5%88%A9
-default : [""]
-var code = '{"type": "win", "reason": "'+EvalString_0+'"},\n';
+default : ["",false]
+var code = '{"type": "win", "reason": "'+EvalString_0+'", "norank": '+(Bool_0?1:0)+'},\n';
return code;
*/;
@@ -1235,7 +1250,7 @@ Floor_List
/*Floor_List ['floorId',':before',':next']*/;
Stair_List
- : '坐标'|'上楼'|'下楼'
+ : '坐标'|'上楼梯'|'下楼梯'
/*Stair_List ['loc','upFloor','downFloor']*/;
SetTextPosition_List
@@ -1526,7 +1541,7 @@ ActionParser.prototype.parseAction = function() {
case "move": // 移动事件
data.loc=data.loc||['',''];
this.next = MotaActionBlocks['move_s'].xmlText([
- data.loc[0],data.loc[1],data.time||0,data.immediateHide,this.StepString(data.steps),this.next]);
+ data.loc[0],data.loc[1],data.time||0,data.keep,this.StepString(data.steps),this.next]);
break;
case "moveHero":
this.next = MotaActionBlocks['moveHero_s'].xmlText([
@@ -1536,7 +1551,7 @@ ActionParser.prototype.parseAction = function() {
data.from=data.from||['',''];
data.to=data.to||['',''];
this.next = MotaActionBlocks['jump_s'].xmlText([
- data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.immediateHide,this.next]);
+ data.from[0],data.from[1],data.to[0],data.to[1],data.time||0,data.keep,this.next]);
break;
case "jumpHero": // 跳跃勇士
data.loc=data.loc||['','']
@@ -1569,6 +1584,9 @@ ActionParser.prototype.parseAction = function() {
this.next = MotaActionBlocks['animate_s'].xmlText([
data.name,animate_loc,this.next]);
break;
+ case "viberate": // 画面震动
+ this.next = MotaActionBlocks['viberate_s'].xmlText([data.time||0, this.next]);
+ break;
case "showImage": // 显示图片
if(this.isset(data.name)){
this.next = MotaActionBlocks['showImage_0_s'].xmlText([
@@ -1699,7 +1717,7 @@ ActionParser.prototype.parseAction = function() {
break;
case "win":
this.next = MotaActionBlocks['win_s'].xmlText([
- data.reason,this.next]);
+ data.reason,data.norank?true:false,this.next]);
break;
case "lose":
this.next = MotaActionBlocks['lose_s'].xmlText([
diff --git a/_server/css/editor_mobile.css b/_server/css/editor_mobile.css
index 5beeecdb..5eb06c2f 100644
--- a/_server/css/editor_mobile.css
+++ b/_server/css/editor_mobile.css
@@ -290,13 +290,15 @@ table.col td {
padding: 0;
border-bottom-width: 0px;
border-top-width: 0px;
+ border-left-width: 0.117307vw;
+ border-right-width: 0.117307vw;
}
#mapColMark td:hover .colBlock {
position: absolute;
top: 4vw;
height: 96vw;
- width: 7.15vw;
+ width: 7.384615vw;
z-index: 100;
background-color: rgba(38, 166, 154, .5);
}
@@ -333,12 +335,14 @@ table.row td {
padding: 0;
border-left-width: 0px;
border-right-width: 0px;
+ border-top-width: 0.117307vw;
+ border-bottom-width: 0.117397vw;
}
#mapRowMark td:hover .rowBlock {
position: absolute;
left: 4vw;
- height: 7.15vw;
+ height: 7.384615vw;
width: 96vw;
z-index: 100;
background-color: rgba(76, 34, 27, .5);
diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js
index d5898b3e..b35decf8 100644
--- a/_server/editor_blockly.js
+++ b/_server/editor_blockly.js
@@ -116,6 +116,7 @@ editor_blockly = function () {
'',
MotaActionBlocks['sleep_s'].xmlText(),
MotaActionBlocks['wait_s'].xmlText(),
+ MotaActionBlocks['viberate_s'].xmlText(),
MotaActionBlocks['animate_s'].xmlText(),
MotaActionBlocks['setFg_0_s'].xmlText(),
MotaActionBlocks['setFg_1_s'].xmlText(),
diff --git a/_server/functions.comment.js b/_server/functions.comment.js
index cc426cae..0b2901ae 100644
--- a/_server/functions.comment.js
+++ b/_server/functions.comment.js
@@ -87,19 +87,7 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
}
}
},
- "ui": {
- "_leaf": false,
- "_type": "object",
- "_data": {
- "drawAbout": {
- "_leaf": true,
- "_type": "textarea",
- "_lint": true,
- "_data": "绘制“关于”界面"
- }
- }
- },
- "enemy": {
+ "enemys": {
"_leaf": false,
"_type": "object",
"_data": {
@@ -123,6 +111,18 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
}
}
},
+ "ui": {
+ "_leaf": false,
+ "_type": "object",
+ "_data": {
+ "drawAbout": {
+ "_leaf": true,
+ "_type": "textarea",
+ "_lint": true,
+ "_data": "绘制“关于”界面"
+ }
+ }
+ },
"plugins": {
"_leaf": false,
"_type": "object",
diff --git a/docs/event.md b/docs/event.md
index cfeb84ed..bb7c6d94 100644
--- a/docs/event.md
+++ b/docs/event.md
@@ -201,21 +201,21 @@
}
```
-我们可以给文字加上标题或图标,只要以`\t[...]`开头就可以,大致共有如下几种情况:
+我们可以给文字加上标题或图标,只要以`\t[...]`开头就可以。
-- `\t[hero]` 显示勇士的图标和名字
-- `\t[monster_id]`显示某个怪物的图标和名字。`monster_id`在`enemys`中有定义,请前往参照。
- - 例如:`\t[blackMagician]` 将显示黑暗大法师的图标和名字。
-- `\t[名字,npc_id]` 显示某个NPC的名字和图标。`npc_id`所对应的图标具体在`icons.js`中有定义,请前往参照。
- - 例如:`\t[小妖精,fairy]` 将显示名字为"小妖精",且是仙子的图标。
-- `\t[标题]` 直接显示标题。
- - 如果该中括号内只有一项,且不为`hero`也不为某个怪物的ID,则会直接显示。如 `\t[你死了]` 直接显示一个标题为"你死了"。
+其一般写法是`\t[名字,ID]`,其中名字为你要显示的标题,ID为图块ID,只能为`hero`,或者NPC/怪物的图块ID。
+
+如果不需要可以不写ID,则只会显示标题。
+
+对于hero和怪物,也可以不写名字代表使用默认值。
``` js
"x,y": [ // 实际执行的事件列表
"一段普通文字",
- "\t[hero]这是一段勇士说的话",
- "\t[blackMagician]这是一段黑暗大法师说的话",
+ "\t[勇士,hero]这是一段勇士说的话",
+ "\t[hero]如果使用勇士默认名称也可以直接简写hero",
+ "\t[黑暗大法师,blackMagician]我是黑暗大法师",
+ "\t[blackMagician]如果使用怪物的默认名称也可以简写怪物id",
"\t[小妖精,fairy]这是一段小妖精说的话,使用仙子(fairy)的图标",
"\t[你赢了]直接显示标题为【你赢了】",
]
@@ -655,6 +655,10 @@ name为可选的,是要取消跟随的行走图文件名。
如果name省略,则会取消所有的跟随效果。
+### viberate:画面震动
+
+使用 `{"type": "viberate", "time": 2000}` 可以造成画面震动效果,后面time可以指定震动时间。
+
### animate:显示动画
我们可以使用 `{"type": "animate"}` 来显示一段动画。
@@ -812,7 +816,7 @@ level为天气的强度等级,在1-10之间。1级为最弱,10级为最强
{"type": "move", "time": 750, "loc": [x,y], "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),loc为位置可选,steps为移动数组
{"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失
"down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1
- ], "immediateHide": true }, //immediateHide可选,制定为true则立刻消失,否则渐变消失
+ ], "keep": true }, // keep可选,如果为true则不消失,否则渐变消失
]
```
@@ -824,13 +828,13 @@ steps为一个数组,其每一项为一个 `{"direction" : xxx, "value": n}`
如果只移动一步可以直接简单的写方向字符串(`up/left/down/right`)。
-immediateHide为一个可选项,代表该事件移动完毕后是否立刻消失。如果该项指定了并为true,则移动完毕后直接消失,否则以动画效果消失。
+keep为一个可选项,代表该事件移动完毕后是否消失。如果该项指定了并为true,则移动完毕后将不消失,否则以动画效果消失。
值得注意的是,当调用move事件时,实际上是使事件脱离了原始地点。为了避免冲突,规定:move事件会自动调用该点的hide事件。
换句话说,当move事件被调用后,该点本身的事件将被禁用。
-move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediateHide决定是否立刻消失还是以time作为时间来动画效果消失。
+如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。
如果想让move后的NPC/怪物仍然可以被交互,需采用如下的写法:
@@ -838,11 +842,9 @@ move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediate
"4,3": [ // [4,3]是一个NPC,比如小偷
{"type": "move", "time": 750, "steps": [ // 向上移动两格,每步750毫秒
{"direction": "up", "value": 2},
- ], "immediateHide": true}, // 移动完毕立刻消失
- {"type": "show", "loc": [4,1]} // 指定[4,1]点的NPC立刻生效(显示)
- {"type": "trigger", "loc": [4,1]} // 立刻触发[4,1]点的事件
+ ], "keep": true}, // 移动完毕后不消失
],
-"4,1": { // [4,1]也是这个NPC,而且是向上移动两个的位置
+"4,1": { // [4,1]为目标地点
"enable": false, // 初始时需要是禁用状态,被show调用后将显示出来
"data": [
"\t[杰克,thief]这样看起来就好像移动过去后也可以被交互。"
@@ -879,7 +881,7 @@ move完毕后移动的NPC/怪物一定会消失,只不过可以通过immediate
``` js
"x,y": [ // 实际执行的事件列表
- {"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "immediateHide": true},
+ {"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "keep": true},
]
```
@@ -889,13 +891,9 @@ to为要跳跃到的坐标。可以省略,如果省略则跳跃到当前坐标
time选项必须指定,为全程跳跃所需要用到的时间。
-immediateHide为一个可选项,同上代表该跳跃完毕后是否立刻消失。如果该项指定了并为true,则跳跃完毕后直接消失,否则以动画效果消失。
+keep为一个可选项,同上代表该跳跃完毕后是否不消失。如果该项指定了并为true,则跳跃完毕后不会消失,否则以动画效果消失。
-值得注意的是,当调用jump事件时,实际上是使事件脱离了原始地点。
-
-为了避免冲突,同move事件一样规定:jump事件会自动调用该点的hide事件。
-
-如果是本地跳跃,需要在跳跃完毕后再启用事件。
+如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。
### jumpHero:跳跃勇士
diff --git a/editor.html b/editor.html
index 20d3a0cf..198bbaa7 100644
--- a/editor.html
+++ b/editor.html
@@ -236,9 +236,11 @@
-
+
+
画线
画矩形
+
diff --git a/libs/control.js b/libs/control.js
index f5d6cb94..9daee5eb 100644
--- a/libs/control.js
+++ b/libs/control.js
@@ -377,7 +377,7 @@ control.prototype.clearContinueAutomaticRoute = function () {
////// 瞬间移动 //////
control.prototype.moveDirectly = function (destX, destY) {
var ignoreSteps = core.canMoveDirectly(destX, destY);
- if (ignoreSteps>0) {
+ if (ignoreSteps>=0) {
core.clearMap('hero', 0, 0, 416, 416);
var lastDirection = core.status.route[core.status.route.length-1];
if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0)
@@ -393,6 +393,22 @@ control.prototype.moveDirectly = function (destX, destY) {
return false;
}
+////// 尝试瞬间移动 //////
+control.prototype.tryMoveDirectly = function (destX, destY) {
+ if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1)
+ return false;
+ var testMove = function (dx, dy, dir) {
+ if (dx<0 || dx>12 || dy<0 || dy>12) return false;
+ if (core.control.moveDirectly(dx, dy)) {
+ if (core.isset(dir)) core.moveHero(dir, function() {});
+ return true;
+ }
+ return false;
+ }
+ return testMove(destX,destY) || testMove(destX-1, destY, "right") || testMove(destX,destY-1,"down")
+ || testMove(destX,destY+1,"up") || testMove(destX+1,destY,"left");
+}
+
////// 设置自动寻路路线 //////
control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
if (!core.status.played || core.status.lockControl) {
@@ -406,7 +422,7 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
core.status.automaticRoute.moveDirectly = true;
setTimeout(function () {
if (core.status.automaticRoute.moveDirectly && core.status.heroMoving==0) {
- core.control.moveDirectly(destX, destY);
+ core.control.tryMoveDirectly(destX, destY);
}
core.status.automaticRoute.moveDirectly = false;
}, 100);
@@ -431,7 +447,7 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) {
// 单击瞬间移动
if (core.status.automaticRoute.clickMoveDirectly && core.status.heroStop) {
- if (core.control.moveDirectly(destX, destY))
+ if (core.control.tryMoveDirectly(destX, destY))
return;
}
@@ -715,8 +731,19 @@ control.prototype.moveAction = function (callback) {
}
if (core.status.event.id!='ski')
core.status.route.push(direction);
- core.trigger(core.getHeroLoc('x'), core.getHeroLoc('y'));
+
+ // 检查是不是无事件的道具
+ var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y');
+ var block = core.getBlock(nowx,nowy);
+ var hasTrigger = false;
+ if (block!=null && block.block.event.trigger=='getItem' &&
+ !core.isset(core.floors[core.status.floorId].afterGetItem[nowx+","+nowy])) {
+ hasTrigger = true;
+ core.trigger(nowx, nowy);
+ }
core.checkBlock();
+ if (!hasTrigger && !core.status.gameOver)
+ core.trigger(nowx, nowy);
if (core.isset(callback)) callback();
});
}
@@ -1841,7 +1868,7 @@ control.prototype.replay = function () {
core.useItem(itemId, function () {
core.replay();
});
- }, 750 / core.status.replay.speed);
+ }, 750 / Math.max(1, core.status.replay.speed));
}
return;
}
@@ -1861,7 +1888,7 @@ control.prototype.replay = function () {
core.changeFloor(floorId, stair, null, null, function () {
core.replay();
});
- }, 750 / core.status.replay.speed);
+ }, 750 / Math.max(1, core.status.replay.speed));
return;
}
}
@@ -1894,7 +1921,7 @@ control.prototype.replay = function () {
core.status.event.selection = parseInt(selections.shift());
core.events.openShop(shopId, false);
- }, 750 / core.status.replay.speed);
+ }, 750 / Math.max(1, core.status.replay.speed));
return;
}
}
@@ -1917,10 +1944,17 @@ control.prototype.replay = function () {
}
}
else if (action.indexOf('move:')==0) {
+ while (core.status.replay.toReplay.length>0 &&
+ core.status.replay.toReplay[0].indexOf('move:')==0) {
+ action = core.status.replay.toReplay.shift();
+ }
+
var pos=action.substring(5).split(":");
var x=parseInt(pos[0]), y=parseInt(pos[1]);
if (core.control.moveDirectly(x,y)) {
- core.replay();
+ setTimeout(function () {
+ core.replay();
+ }, 750 / Math.max(1, core.status.replay.speed));
return;
}
}
diff --git a/libs/core.js b/libs/core.js
index e6a35f7f..82fdd9ef 100644
--- a/libs/core.js
+++ b/libs/core.js
@@ -73,6 +73,7 @@ function core() {
}
this.initStatus = {
'played': false,
+ 'gameOver': false,
// 勇士属性
'hero': {},
@@ -144,6 +145,7 @@ function core() {
'curtainColor': null,
'usingCenterFly':false,
'openingDoor': null,
+ 'isSkiing': false,
// 动画
'globalAnimateObjs': [],
@@ -665,13 +667,13 @@ core.prototype.getBlockId = function (x, y, floorId, needEnable) {
}
////// 显示移动某块的动画,达到{“type”:”move”}的效果 //////
-core.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
- core.maps.moveBlock(x,y,steps,time,immediateHide,callback)
+core.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
+ core.maps.moveBlock(x,y,steps,time,keep,callback)
}
////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
-core.prototype.jumpBlock = function(sx,sy,ex,ey,time,immediateHide,callback) {
- core.maps.jumpBlock(sx,sy,ex,ey,time,immediateHide,callback);
+core.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
+ core.maps.jumpBlock(sx,sy,ex,ey,time,keep,callback);
}
////// 显示/隐藏某个块时的动画效果 //////
@@ -764,6 +766,21 @@ core.prototype.updateFg = function () {
core.control.updateFg();
}
+////// 测试是否拥有某个特殊属性 //////
+core.prototype.hasSpecial = function (special, test) {
+ return core.enemys.hasSpecial(special, test);
+}
+
+////// 判断能否战斗 //////
+core.prototype.canBattle = function(enemyId) {
+ return core.enemys.canBattle(enemyId);
+}
+
+////// 获得伤害数值 //////
+core.prototype.getDamage = function(enemy) {
+ return core.enemys.getDamage(enemy);
+}
+
////// 获得某个物品的个数 //////
core.prototype.itemCount = function (itemId) {
return core.items.itemCount(itemId);
diff --git a/libs/enemys.js b/libs/enemys.js
index e6037779..058389a4 100644
--- a/libs/enemys.js
+++ b/libs/enemys.js
@@ -5,8 +5,8 @@ function enemys() {
////// 初始化 //////
enemys.prototype.init = function () {
this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
- this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemy;
- this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)};
+ this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys;
+ if (main.mode=='play') this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)};
}
////// 获得一个或所有怪物数据 //////
diff --git a/libs/events.js b/libs/events.js
index a0eaaee6..877e83b9 100644
--- a/libs/events.js
+++ b/libs/events.js
@@ -30,6 +30,7 @@ events.prototype.init = function () {
heroLoc = {'x': data.event.data.loc[0], 'y': data.event.data.loc[1]};
if (core.isset(data.event.data.direction))
heroLoc.direction = data.event.data.direction;
+ if (core.status.event.id!='action') core.status.event.id=null;
core.changeFloor(data.event.data.floorId, data.event.data.stair,
heroLoc, data.event.data.time, function () {
if (core.isset(callback)) callback();
@@ -115,17 +116,19 @@ events.prototype.setInitData = function (hard) {
}
////// 游戏获胜事件 //////
-events.prototype.win = function (reason) {
- return this.eventdata.win(reason);
+events.prototype.win = function (reason, norank) {
+ core.status.gameOver = true;
+ return this.eventdata.win(reason, norank);
}
////// 游戏失败事件 //////
events.prototype.lose = function (reason) {
+ core.status.gameOver = true;
return this.eventdata.lose(reason);
}
////// 游戏结束 //////
-events.prototype.gameOver = function (ending, fromReplay) {
+events.prototype.gameOver = function (ending, fromReplay, norank) {
// 清空图片和天气
core.clearMap('animate', 0, 0, 416, 416);
@@ -188,6 +191,7 @@ events.prototype.gameOver = function (ending, fromReplay) {
formData.append('money', core.status.hero.money);
formData.append('experience', core.status.hero.experience);
formData.append('steps', core.status.hero.steps);
+ formData.append('norank', norank||0);
formData.append('seed', core.getFlag('seed'));
formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000));
formData.append('route', core.encodeRoute(core.status.route));
@@ -461,7 +465,7 @@ events.prototype.doAction = function() {
x=core.calValue(data.loc[0]);
y=core.calValue(data.loc[1]);
}
- core.moveBlock(x,y,data.steps,data.time,data.immediateHide,function() {
+ core.moveBlock(x,y,data.steps,data.time,data.keep,function() {
core.events.doAction();
})
break;
@@ -481,7 +485,7 @@ events.prototype.doAction = function() {
ex=core.calValue(data.to[0]);
ey=core.calValue(data.to[1]);
}
- core.jumpBlock(sx,sy,ex,ey,data.time,data.immediateHide,function() {
+ core.jumpBlock(sx,sy,ex,ey,data.time,data.keep,function() {
core.events.doAction();
});
break;
@@ -744,7 +748,7 @@ events.prototype.doAction = function() {
core.status.route.push("choices:"+index);
core.events.insertAction(data.choices[index].action);
core.events.doAction();
- }, 750 / core.status.replay.speed)
+ }, 750 / Math.max(1, core.status.replay.speed))
}
else {
core.stopReplay();
@@ -776,14 +780,10 @@ events.prototype.doAction = function() {
this.doAction();
break;
case "win":
- core.events.win(data.reason, function () {
- core.events.doAction();
- });
+ core.events.win(data.reason, data.norank);
break;
case "lose":
- core.events.lose(data.reason, function () {
- core.events.doAction();
- });
+ core.events.lose(data.reason);
break;
case "function":
{
@@ -807,6 +807,11 @@ events.prototype.doAction = function() {
core.updateStatusBar();
this.doAction();
break;
+ case "viberate":
+ core.events.vibrate(data.time, function () {
+ core.events.doAction();
+ })
+ break;
case "sleep": // 等待多少毫秒
if (core.status.replay.replaying)
core.events.doAction();
@@ -866,7 +871,7 @@ events.prototype.doAction = function() {
////// 往当前事件列表之前添加一个或多个事件 //////
events.prototype.insertAction = function (action, x, y, callback) {
- if (core.status.event.id == null) {
+ if (core.status.event.id != 'action') {
this.doEvents(action, x, y, callback);
}
else {
@@ -1017,6 +1022,7 @@ events.prototype.battle = function (id, x, y, force, callback) {
////// 触发(x,y)点的事件 //////
events.prototype.trigger = function (x, y) {
+ core.status.isSkiing = false;
var mapBlocks = core.status.thisMap.blocks;
var noPass;
for (var b = 0; b < mapBlocks.length; b++) {
@@ -1028,6 +1034,8 @@ events.prototype.trigger = function (x, y) {
if (core.isset(mapBlocks[b].event) && core.isset(mapBlocks[b].event.trigger)) {
var trigger = mapBlocks[b].event.trigger;
+ if (trigger == 'ski') core.status.isSkiing = true;
+
// 转换楼层能否穿透
if (trigger=='changeFloor' && !noPass) {
var canCross = core.flags.portalWithoutTrigger;
@@ -1307,6 +1315,65 @@ events.prototype.setVolume = function (value, time, callback) {
}, time / 32);
}
+////// 画面震动 //////
+events.prototype.vibrate = function(time, callback) {
+
+ if (core.isset(core.status.replay)&&core.status.replay.replaying) {
+ if (core.isset(callback)) callback();
+ return;
+ }
+
+ core.status.replay.animate=true;
+
+ var setGameCanvasTranslate=function(x,y){
+ for(var ii=0,canvas;canvas=core.dom.gameCanvas[ii];ii++){
+ if(['data','ui'].indexOf(canvas.getAttribute('id'))!==-1)continue;
+ canvas.style.transform='translate('+x+'px,'+y+'px)';
+ canvas.style.webkitTransform='translate('+x+'px,'+y+'px)';
+ canvas.style.OTransform='translate('+x+'px,'+y+'px)';
+ canvas.style.MozTransform='translate('+x+'px,'+y+'px)';
+ }
+ }
+
+ if (!core.isset(time) || time<1000) time=1000;
+
+ var shake_duration = time*3/50;
+ var shake_speed = 5;
+ var shake_power = 5;
+ var shake_direction = 1;
+ var shake = 0;
+
+ var update = function() {
+ if(shake_duration >= 1 || shake != 0){
+ var delta = (shake_power * shake_speed * shake_direction) / 10.0;
+ if(shake_duration <= 1 && shake * (shake + delta) < 0){
+ shake = 0;
+ }else{
+ shake += delta;
+ }
+ if(shake > shake_power * 2){
+ shake_direction = -1;
+ }
+ if(shake < - shake_power * 2){
+ shake_direction = 1;
+ }
+ if(shake_duration >= 1){
+ shake_duration -= 1
+ }
+ }
+ }
+
+ var animate=setInterval(function(){
+ update();
+ setGameCanvasTranslate(shake,0);
+ if(shake_duration===0) {
+ clearInterval(animate);
+ core.status.replay.animate=false;
+ if (core.isset(callback)) callback();
+ }
+ }, 50/3);
+}
+
////// 打开一个全局商店 //////
events.prototype.openShop = function(shopId, needVisited) {
var shop = core.status.shops[shopId];
@@ -1517,7 +1584,7 @@ events.prototype.ski = function (direction) {
}
else {
core.moveHero(direction, function () {
- if (core.status.event.id=='ski') {
+ if (core.status.event.id=='ski' && !core.status.isSkiing) {
core.status.event.id=null;
core.unLockControl();
core.replay();
diff --git a/libs/maps.js b/libs/maps.js
index 2461a69c..624d68d2 100644
--- a/libs/maps.js
+++ b/libs/maps.js
@@ -257,17 +257,17 @@ maps.prototype.canMoveHero = function(x,y,direction,floorId) {
maps.prototype.canMoveDirectly = function (destX,destY) {
// 不可瞬间移动请返回0
- if (!core.flags.enableMoveDirectly) return 0;
+ if (!core.flags.enableMoveDirectly) return -1;
// 中毒状态:不能
- if (core.hasFlag('poison')) return 0;
+ if (core.hasFlag('poison')) return -1;
var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y');
if (fromX==destX&&fromY==destY) return 0;
// 可以无视起点事件
// if (core.getBlock(fromX,fromY)!=null||core.status.checkBlock.damage[13*fromX+fromY]>0)
- // return 0;
+ // return -1;
// BFS
var visited=[], queue=[];
@@ -286,7 +286,7 @@ maps.prototype.canMoveDirectly = function (destX,destY) {
queue.push(13*nx+ny);
}
}
- return 0;
+ return -1;
}
maps.prototype.drawBlock = function (block, animate, dx, dy) {
@@ -557,9 +557,8 @@ maps.prototype.getBlockId = function (x, y, floorId, needEnable) {
}
////// 显示移动某块的动画,达到{“type”:”move”}的效果 //////
-maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
+maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
time = time || 500;
- core.status.replay.animate=true;
core.clearMap('animate', 0, 0, 416, 416);
@@ -568,6 +567,9 @@ maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
if (core.isset(callback)) callback();
return;
}
+ var id = block.block.id;
+
+ core.status.replay.animate=true;
// 需要删除该块
core.removeBlock(x,y);
@@ -625,7 +627,7 @@ maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
// 已经移动完毕,消失
if (moveSteps.length==0) {
- if (immediateHide) opacityVal=0;
+ if (keep) opacityVal=0;
else opacityVal -= 0.06;
core.setOpacity('animate', opacityVal);
core.clearMap('animate', nowX, nowY-height+32, 32, height);
@@ -634,6 +636,11 @@ maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
clearInterval(animate);
core.clearMap('animate', 0, 0, 416, 416);
core.setOpacity('animate', 1);
+ // 不消失
+ if (keep) {
+ core.setBlock(id, nowX/32, nowY/32);
+ core.showBlock(nowX/32, nowY/32);
+ }
core.status.replay.animate=false;
if (core.isset(callback)) callback();
}
@@ -656,15 +663,17 @@ maps.prototype.moveBlock = function(x,y,steps,time,immediateHide,callback) {
}
////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
-maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,immediateHide,callback) {
+maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
time = time || 500;
- core.status.replay.animate=true;
core.clearMap('animate', 0, 0, 416, 416);
var block = core.getBlock(sx,sy);
if (block==null) {
if (core.isset(callback)) callback();
return;
}
+ var id = block.block.id;
+
+ core.status.replay.animate=true;
// 需要删除该块
core.removeBlock(sx,sy);
@@ -724,7 +733,7 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,immediateHide,callback) {
core.canvas.animate.drawImage(blockImage, animateCurrent * 32, blockIcon * height, 32, height, drawX(), drawY()-height+32, 32, height);
}
else {
- if (immediateHide) opacityVal=0;
+ if (keep) opacityVal=0;
else opacityVal -= 0.06;
core.setOpacity('animate', opacityVal);
core.clearMap('animate', drawX(), drawY()-height+32, 32, height);
@@ -733,6 +742,10 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,immediateHide,callback) {
clearInterval(animate);
core.clearMap('animate', 0, 0, 416, 416);
core.setOpacity('animate', 1);
+ if (keep) {
+ core.setBlock(id, ex, ey);
+ core.showBlock(ex, ey);
+ }
core.status.replay.animate=false;
if (core.isset(callback)) callback();
}
@@ -873,6 +886,7 @@ maps.prototype.removeBlockByIds = function (floorId, ids) {
maps.prototype.setBlock = function (number, x, y, floorId) {
floorId = floorId || core.status.floorId;
if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return;
+ if (x<0 || x>12 || y<0 || y>12) return;
var originBlock=core.getBlock(x,y,floorId,false);
var block = core.maps.initBlock(x,y,number);
diff --git a/libs/ui.js b/libs/ui.js
index ec919d78..5a28b569 100644
--- a/libs/ui.js
+++ b/libs/ui.js
@@ -278,8 +278,10 @@ ui.prototype.drawTextBox = function(content) {
if (ss.length==1) {
// id
id=ss[0];
- // monster
- if (id!='hero') {
+ if (id=='hero') {
+ name = core.status.hero.name;
+ }
+ else {
if (core.isset(core.material.enemys[id])) {
name = core.material.enemys[id].name;
@@ -305,20 +307,35 @@ ui.prototype.drawTextBox = function(content) {
}
}
else {
- id='npc';
name=ss[0];
- if (core.isset(core.material.icons.npc48[ss[1]])) {
+ id = 'npc';
+ if (ss[1]=='hero') {
+ id = 'hero';
+ }
+ else if (core.isset(core.material.icons.npc48[ss[1]])) {
image = core.material.images.npc48;
icon = core.material.icons.npc48[ss[1]];
iconHeight = 48;
animate=4;
}
- else {
+ else if (core.isset(core.material.icons.npcs[ss[1]])){
image = core.material.images.npcs;
icon = core.material.icons.npcs[ss[1]];
iconHeight = 32;
animate=2;
}
+ else if (core.isset(core.material.icons.enemy48[ss[1]])) {
+ image = core.material.images.enemy48;
+ icon = core.material.icons.enemy48[ss[1]];
+ iconHeight = 48;
+ animate=4;
+ }
+ else if (core.isset(core.material.icons.enemys[ss[1]])) {
+ image = core.material.images.enemys;
+ icon = core.material.icons.enemys[ss[1]];
+ iconHeight = 32;
+ animate=2;
+ }
}
}
}
@@ -459,7 +476,7 @@ ui.prototype.drawTextBox = function(content) {
if (id == 'hero') {
var heroHeight=core.material.icons.hero.height;
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, null, 2);
- core.fillText('ui', core.status.hero.name, content_left, top + 30, null, 'bold 22px Verdana');
+ core.fillText('ui', name, content_left, top + 30, null, 'bold 22px 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'];
@@ -542,17 +559,20 @@ ui.prototype.drawChoices = function(content, choices) {
if (core.isset(content)) {
// 获得name, image, icon
- if (content.indexOf("\t[")==0) {
+ if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) {
var index = content.indexOf("]");
if (index>=0) {
var str=content.substring(2, index);
+ if (content.indexOf("\\t[")==0) str=content.substring(3, index);
content=content.substring(index+1);
var ss=str.split(",");
if (ss.length==1) {
// id
id=ss[0];
- // monster
- if (id!='hero') {
+ if (id=='hero') {
+ name = core.status.hero.name;
+ }
+ else {
if (core.isset(core.material.enemys[id])) {
name = core.material.enemys[id].name;
@@ -578,20 +598,35 @@ ui.prototype.drawChoices = function(content, choices) {
}
}
else {
- id='npc';
name=ss[0];
- if (core.isset(core.material.icons.npc48[ss[1]])) {
+ id = 'npc';
+ if (ss[1]=='hero') {
+ id = 'hero';
+ }
+ else if (core.isset(core.material.icons.npc48[ss[1]])) {
image = core.material.images.npc48;
icon = core.material.icons.npc48[ss[1]];
iconHeight = 48;
animate=4;
}
- else {
+ else if (core.isset(core.material.icons.npcs[ss[1]])){
image = core.material.images.npcs;
icon = core.material.icons.npcs[ss[1]];
iconHeight = 32;
animate=2;
}
+ else if (core.isset(core.material.icons.enemy48[ss[1]])) {
+ image = core.material.images.enemy48;
+ icon = core.material.icons.enemy48[ss[1]];
+ iconHeight = 48;
+ animate=4;
+ }
+ else if (core.isset(core.material.icons.enemys[ss[1]])) {
+ image = core.material.images.enemys;
+ icon = core.material.icons.enemys[ss[1]];
+ iconHeight = 32;
+ animate=2;
+ }
}
}
}
@@ -631,7 +666,7 @@ ui.prototype.drawChoices = function(content, choices) {
if (id == 'hero') {
var heroHeight = core.material.icons.hero.height;
core.strokeRect('ui', left + 15 - 1, top + 30 - 1, 34, heroHeight+2, '#DDDDDD', 2);
- core.fillText('ui', core.status.hero.name, title_offset, top + 27, '#FFD700', 'bold 19px Verdana');
+ core.fillText('ui', name, title_offset, top + 27, '#FFD700', 'bold 19px Verdana');
core.clearMap('ui', left + 15, top + 30, 32, heroHeight);
core.fillRect('ui', left + 15, top + 30, 32, heroHeight, background);
var heroIcon = core.material.icons.hero['down'];
diff --git a/main.js b/main.js
index 20ccef09..964ab271 100644
--- a/main.js
+++ b/main.js
@@ -2,7 +2,7 @@ function main() {
//------------------------ 用户修改内容 ------------------------//
- this.version = "2.3.2"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
+ this.version = "2.3.3"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
this.useCompress = false; // 是否使用压缩文件
// 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。
diff --git a/project/data.js b/project/data.js
index 0af6ae06..b8aadbe8 100644
--- a/project/data.js
+++ b/project/data.js
@@ -26,7 +26,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"firstData" : {
"title": "魔塔样板",
"name": "template",
- "version": "Ver 2.3.2",
+ "version": "Ver 2.3.3",
"floorId": "sample0",
"hero": {
"name": "阳光",
diff --git a/project/functions.js b/project/functions.js
index 1800c1c8..9bd9eda5 100644
--- a/project/functions.js
+++ b/project/functions.js
@@ -50,7 +50,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
core.events.afterLoadData();
},
////// 游戏获胜事件 //////
-"win" : function(reason) {
+"win" : function(reason, norank) {
// 游戏获胜事件
core.ui.closePanel();
var replaying = core.status.replay.replaying;
@@ -61,7 +61,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
core.drawText([
"\t[" + (reason||"恭喜通关") + "]你的分数是${status:hp}。"
], function () {
- core.events.gameOver(reason||'', replaying);
+ core.events.gameOver(reason||'', replaying, norank);
})
});
},
@@ -306,7 +306,7 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
core.enemys.updateEnemys();
}
},
-"enemy": {
+"enemys": {
"getSpecials" : function() {
// 获得怪物的特殊属性,每一行定义一个特殊属性。
// 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
diff --git a/project/images/enemys.png b/project/images/enemys.png
index 01d4396f..2c29805b 100644
Binary files a/project/images/enemys.png and b/project/images/enemys.png differ
diff --git a/更新说明.txt b/更新说明.txt
index 27bf7932..acdc3a25 100644
--- a/更新说明.txt
+++ b/更新说明.txt
@@ -1,12 +1,15 @@
HTML5魔塔样板V2.3.3
-将怪物特殊属性定义和伤害计算函数移动到脚本编辑中 √
+将怪物特殊属性定义和伤害计算函数移动到脚本编辑中
+地图编辑器可以使用矩形方式绘制地图
+瞬间移动可以指定存在事件的点(如怪物、门、楼梯等)
事件:画面震动
-事件:更新怪物数据 √
+事件:更新怪物数据
移动事件和跳跃事件增加“不消失”选项
-修改默认bgm √
-修复读档开启战斗动画等Bug √
-大量细节优化 √
+获胜结局可以指定“不计入榜单”
+修改默认bgm
+修复读档开启战斗动画等Bug
+大量细节优化
-----------------------------------------------------------------------