Merge remote-tracking branch 'refs/remotes/ckcz123/v2.0' into v2.x

This commit is contained in:
YouWei Zhao 2018-07-28 17:22:46 +08:00
commit fa1f6c9bea
18 changed files with 341 additions and 116 deletions

View File

@ -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`内的诸位魔塔爱好者们对本样板的大力支持!

View File

@ -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([

View File

@ -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);

View File

@ -116,6 +116,7 @@ editor_blockly = function () {
'<label text="特效/声音"></label>',
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(),

View File

@ -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",

View File

@ -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跳跃勇士

View File

@ -236,9 +236,11 @@
<option value="tower">全塔属性</option>
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
</select><br>
</select>
<span style="font-size: 12px; margin-left: 10px">
<input type="radio" id="brushMod" name="brushMod" value="line" checked="checked" />画线
<input type="radio" id="brushMod2" name="brushMod" value="rectangle" />画矩形
</span>
<br><br><br>
<select id="selectFloor"></select>
<input type="button" value="保存地图" id='saveFloor'/>

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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)};
}
////// 获得一个或所有怪物数据 //////

View File

@ -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();

View File

@ -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);

View File

@ -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'];

View File

@ -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。

View File

@ -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": "阳光",

View File

@ -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() {
// 获得怪物的特殊属性,每一行定义一个特殊属性。
// 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -1,12 +1,15 @@
HTML5魔塔样板V2.3.3
将怪物特殊属性定义和伤害计算函数移动到脚本编辑中 √
将怪物特殊属性定义和伤害计算函数移动到脚本编辑中
地图编辑器可以使用矩形方式绘制地图
瞬间移动可以指定存在事件的点(如怪物、门、楼梯等)
事件:画面震动
事件:更新怪物数据 √
事件:更新怪物数据
移动事件和跳跃事件增加“不消失”选项
修改默认bgm √
修复读档开启战斗动画等Bug √
大量细节优化 √
获胜结局可以指定“不计入榜单”
修改默认bgm
修复读档开启战斗动画等Bug
大量细节优化
-----------------------------------------------------------------------