Merge pull request #178 from ckcz123/v2.0

V2.0
This commit is contained in:
Zhang Chen 2018-07-22 14:56:15 +08:00 committed by GitHub
commit d0b09a13e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 580 additions and 292 deletions

View File

@ -59,7 +59,21 @@ HTML5 canvas制作的魔塔样板支持全平台游戏
## 更新说明
### 2018.7.9 V2.3.3
### 2018.7.21 V2.3.3
HTML5魔塔样板V2.3.3
* [x] 将怪物特殊属性定义和伤害计算函数移动到脚本编辑中
* [x] 地图编辑器可以使用矩形方式绘制地图
* [x] 瞬间移动可以指定存在事件的点(如怪物、门、楼梯等)
* [x] 事件:画面震动
* [x] 事件:更新怪物数据
* [x] 移动事件和跳跃事件增加“不消失”选项
* [x] 修改默认bgm
* [x] 修复读档开启战斗动画等Bug
* [x] 大量细节优化
### 2018.7.9 V2.3.2
* [x] 适配手机端的造塔页面
* [x] 启动服务的多开版本

View File

@ -193,6 +193,7 @@ action
| setBlock_s
| setHeroIcon_s
| update_s
| updateEnemys_s
| sleep_s
| wait_s
| battle_s
@ -205,6 +206,7 @@ action
| follow_s
| unfollow_s
| animate_s
| viberate_s
| showImage_0_s
| showImage_1_s
| animateImage_0_s
@ -496,6 +498,18 @@ var code = '{"type": "update"},\n';
return code;
*/;
updateEnemys_s
: '更新怪物数据' Newline
/* updateEnemys_s
tooltip : updateEnemys: 立刻更新怪物数据
helpUrl : https://ckcz123.github.io/mota-js/#/event?id=updateEnemys%ef%bc%9a%e6%9b%b4%e6%96%b0%e6%80%aa%e7%89%a9%e6%95%b0%e6%8d%ae
colour : this.dataColor
var code = '{"type": "updateEnemys"},\n';
return code;
*/;
sleep_s
: '等待' Int '毫秒' Newline
@ -639,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
@ -806,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;
*/;
@ -838,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) {
@ -854,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;
*/;
@ -1222,7 +1250,7 @@ Floor_List
/*Floor_List ['floorId',':before',':next']*/;
Stair_List
: '坐标'|'上楼'|'下楼'
: '坐标'|'上楼'|'下楼'
/*Stair_List ['loc','upFloor','downFloor']*/;
SetTextPosition_List
@ -1513,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([
@ -1523,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||['','']
@ -1556,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([
@ -1702,6 +1733,10 @@ ActionParser.prototype.parseAction = function() {
this.next = MotaActionBlocks['update_s'].xmlText([
this.next]);
break;
case "updateEnemys":
this.next = MotaActionBlocks['updateEnemys_s'].xmlText([
this.next]);
break;
case "sleep": // 等待多少毫秒
this.next = MotaActionBlocks['sleep_s'].xmlText([
data.time,this.next]);

View File

@ -495,6 +495,12 @@ data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_bool": "bool",
"_data": "夹击方式是向上取整还是向下取整。如果此项为true则为向上取整为false则为向下取整"
},
"useLoop": {
"_leaf": true,
"_type": "checkbox",
"_bool": "bool",
"_data": "是否循环计算临界如果此项为true则使用循环法而不是回合数计算法来算临界"
},
"startDirectly": {
"_leaf": true,
"_type": "checkbox",

View File

@ -1,6 +1,7 @@
function editor() {
this.version = "2.0";
this.material = {};
this.brushMod = "line";//["line","rectangle"]
}
editor.prototype.init = function (callback) {
@ -503,6 +504,20 @@ editor.prototype.listen = function () {
e.stopPropagation();
if (stepPostfix && stepPostfix.length) {
preMapData = JSON.parse(JSON.stringify(editor.map));
if(editor.brushMod==='rectangle'){
var x0=stepPostfix[0].x;
var y0=stepPostfix[0].y;
var x1=stepPostfix[stepPostfix.length-1].x;
var y1=stepPostfix[stepPostfix.length-1].y;
if(x0>x1){x0^=x1;x1^=x0;x0^=x1;}//swap
if(y0>y1){y0^=y1;y1^=y0;y0^=y1;}//swap
stepPostfix=[];
for(var ii=x0;ii<=x1;ii++){
for(var jj=y0;jj<=y1;jj++){
stepPostfix.push({x:ii,y:jj})
}
}
}
currDrawData.pos = JSON.parse(JSON.stringify(stepPostfix));
currDrawData.info = JSON.parse(JSON.stringify(editor.info));
reDo = null;
@ -839,6 +854,16 @@ editor.prototype.listen = function () {
});
}
var brushMod=document.getElementById('brushMod');
brushMod.onchange=function(){
editor.brushMod=brushMod.value;
}
var brushMod2=document.getElementById('brushMod2');
if(brushMod2)brushMod2.onchange=function(){
editor.brushMod=brushMod2.value;
}
}//绑定事件
/*

View File

@ -87,6 +87,7 @@ editor_blockly = function () {
MotaActionBlocks['setValue_s'].xmlText(),
MotaActionBlocks['input_s'].xmlText(),
MotaActionBlocks['update_s'].xmlText(),
MotaActionBlocks['updateEnemys_s'].xmlText(),
MotaActionBlocks['moveHero_s'].xmlText(),
MotaActionBlocks['jumpHero_s'].xmlText(),
MotaActionBlocks['changeFloor_s'].xmlText(),
@ -115,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,6 +87,30 @@ functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
}
}
},
"enemys": {
"_leaf": false,
"_type": "object",
"_data": {
"getSpecials": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "怪物特殊属性的定义(获得怪物的特殊属性)"
},
"getDamageInfo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "获得战斗伤害信息(实际伤害计算函数)"
},
"updateEnemys": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "更新怪物数据,可以在这里对怪物属性和数据进行动态更新"
}
}
},
"ui": {
"_leaf": false,
"_type": "object",

View File

@ -24,7 +24,7 @@ document.body.onmousedown = function (e) {
}
});
if (clickpath.indexOf('edit') === -1 && clickpath.indexOf('tip') === -1) {
if (clickpath.indexOf('edit') === -1 && clickpath.indexOf('tip') === -1 && clickpath.indexOf('brushMod') === -1 && clickpath.indexOf('brushMod2') === -1) {
if (clickpath.indexOf('eui') === -1) {
if (selectBox.isSelected) {
editor_mode.onmode('');

View File

@ -338,7 +338,7 @@ core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef)
core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef)
计算战斗伤害实际返回的是上面getDamageInfo中伤害的数值。
获得在某个勇士属性下怪物伤害实际返回的是上面getDamageInfo中伤害的数值。
core.enemys.getCurrentEnemys(floorId)

View File

@ -509,6 +509,12 @@ name是可选的代表目标行走图的文件名。
如果你需要刷新状态栏和地图显伤,只需要简单地调用 `{"type": "update"}` 即可。
### updateEnemys更新怪物数据
使用 `{"type": "updateEnemys"}` 可以动态修改怪物数据。
详见[怪物数据的动态修改](#怪物数据的动态修改)。
### sleep等待多少毫秒
等价于RMXP中的"等待x帧",不过是以毫秒来计算。
@ -649,6 +655,10 @@ name为可选的是要取消跟随的行走图文件名。
如果name省略则会取消所有的跟随效果。
### viberate画面震动
使用 `{"type": "viberate", "time": 2000}` 可以造成画面震动效果后面time可以指定震动时间。
### animate显示动画
我们可以使用 `{"type": "animate"}` 来显示一段动画。
@ -806,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则不消失,否则渐变消失
]
```
@ -818,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/怪物仍然可以被交互,需采用如下的写法:
@ -832,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]这样看起来就好像移动过去后也可以被交互。"
@ -873,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},
]
```
@ -883,13 +891,9 @@ to为要跳跃到的坐标。可以省略如果省略则跳跃到当前坐标
time选项必须指定为全程跳跃所需要用到的时间。
immediateHide为一个可选项同上代表该跳跃完毕后是否立刻消失。如果该项指定了并为true则跳跃完毕后直接消失,否则以动画效果消失。
keep为一个可选项同上代表该跳跃完毕后是否不消失。如果该项指定了并为true则跳跃完毕后不会消失,否则以动画效果消失。
值得注意的是当调用jump事件时实际上是使事件脱离了原始地点。
为了避免冲突同move事件一样规定jump事件会自动调用该点的hide事件。
如果是本地跳跃,需要在跳跃完毕后再启用事件。
如果指定了`"keep": true`,则相当于会在目标地点触发一个`setBlock`事件;如需能继续对话交互请在目标地点再写事件。
### jumpHero跳跃勇士
@ -1591,25 +1595,33 @@ core.insertAction([
而在我们的存档中是不会对怪物数据进行存储的只会存各个变量和Flag因此我们需要在读档后根据变量或Flag来调整怪物数据。
我们可以在脚本编辑中的`afterLoadData`进行处理。
我们可以在脚本编辑中的`updateEnemys`进行处理。
``` js
////// 读档事件后,载入事件前,可以执行的操作 //////
"afterLoadData" : function(data) {
// 读档事件后,载入事件前,可以执行的操作
if (core.hasFlag("fengyin")) { // 如果存在封印flag为真
core.material.enemys.blackKing.hp/=10; // 将怪物的血量变成原来的十分之一
// ...
"updateEnemys" : function () {
// 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改
// 比如下面这个例子如果flag:xxx为真则将绿头怪的攻击设为100红头怪的金币设为20
// 推荐写变化后的具体数值,以免多次变化导致冲突
/*
// 如果flag:xxx为真你也可以写其他判断语句比如core.hasItem(...)等等
if (core.hasFlag('xxx')) {
core.material.enemys.greenSlime.atk = 100;
core.material.enemys.redSlime.money = 20;
}
// 同样难度分歧可以类似写 if (core.getFlag('hard', 0)==3) {...
*/
// 别忘了在事件中调用“更新怪物数据”事件!
}
```
// 在封印时可以调用setValue将该flag置为真然后调用自定义脚本 core.afterLoadData() 即可。
当我们获得一个道具(或者触发某个事件等)后,需要在事件中调用“更新怪物数据”事件。
``` js
// 调用`updateEnemys`(更新怪物数据)事件就可以触发了
"x,y": [
{"type": "setValue", "name": "flag:fengyin", "value": "true"}, // 封印
{"type": "function", "function": function() { // 手动调用自定义JS脚本 core.afterLoadData()
core.afterLoadData();
}}
"将flag:xxx置为真就可以让怪物数据发生改变",
{"type": "setValue", "name": "flag:xxx", "value": "true"}, // 将flag:xxx置为真
{"type": "updateEnemys"} // 更新怪物数据此时绿头怪攻击就会变成100了
]
```

View File

@ -244,6 +244,7 @@
<input type="button" value="数据区"/>
<input type="button" value="地图区"/>
<input type="button" value="素材库"/>
<input type="button" value="前往游戏" onclick="window.location='./index.html'"/>
</span>
<div id="menuDiv">
<div id="midMenu" style="display:none">
@ -263,15 +264,18 @@
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
</select>
<select id="brushMod">
<option value="line">画线</option>
<option value="rectangle">画矩形</option>
</select>
<br>
<select id="selectFloor"></select>
<input type="button" value="保存地图" id='saveFloor'/>
<span id='mobileeditdata' style="display:none">
<input type="button" value="编辑"/>
<input type="button" value="显示完整名称"/>
<input type="button" value="显示完整名称" style="display: none;"/>
<input type="button" value="显示完整注释"/>
</span>
<input type="button" value="前往游戏" onclick="window.location='./index.html'"/>
<!-- -->
<div id="bgSelect" v-cloak style="display:none">
<span>当前地板: </span>

View File

@ -237,7 +237,11 @@
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
</select>
<br><br><br><br>
<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

@ -1188,8 +1188,8 @@ actions.prototype.clickToolbox = function(x,y) {
}
// 下一页
if ((x == 8 || x == 9) && y == 12) {
var toolPage = parseInt(Object.keys(core.status.hero.items.tools).length/12)+1,
constantPage = parseInt(Object.keys(core.status.hero.items.constants).length/12)+1;
var toolPage = Math.ceil(Object.keys(core.status.hero.items.tools).length/12),
constantPage = Math.ceil(Object.keys(core.status.hero.items.constants).length/12);
if (page<toolPage) {
core.ui.drawToolbox(12*page);
}

View File

@ -292,10 +292,7 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value
core.values = core.clone(values);
else core.values = core.clone(core.data.values);
core.flags = core.clone(core.data.flags);
core.events.initGame();
}
////// 开始游戏 //////
@ -380,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)
@ -396,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) {
@ -409,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);
@ -434,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;
}
@ -1663,14 +1676,14 @@ control.prototype.startReplay = function (list) {
////// 更改播放状态 //////
control.prototype.triggerReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (core.status.replay.pausing) this.resumeReplay();
else this.pauseReplay();
}
////// 暂停播放 //////
control.prototype.pauseReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.pausing = true;
core.updateStatusBar();
@ -1679,7 +1692,7 @@ control.prototype.pauseReplay = function () {
////// 恢复播放 //////
control.prototype.resumeReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.pausing = false;
core.updateStatusBar();
@ -1689,7 +1702,7 @@ control.prototype.resumeReplay = function () {
////// 加速播放 //////
control.prototype.speedUpReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
var toAdd = core.status.replay.speed>=3?3:core.status.replay.speed>=2?2:1;
core.status.replay.speed = parseInt(10*core.status.replay.speed + toAdd)/10;
@ -1699,7 +1712,7 @@ control.prototype.speedUpReplay = function () {
////// 减速播放 //////
control.prototype.speedDownReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
var toAdd = core.status.replay.speed>3?3:core.status.replay.speed>2?2:1;
core.status.replay.speed = parseInt(10*core.status.replay.speed - toAdd)/10;
@ -1709,7 +1722,7 @@ control.prototype.speedDownReplay = function () {
////// 停止播放 //////
control.prototype.stopReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
core.status.replay.toReplay = [];
core.status.replay.totalList = [];
@ -1724,7 +1737,7 @@ control.prototype.stopReplay = function () {
////// 回退 //////
control.prototype.rewindReplay = function () {
if (core.status.event.id=='save') return;
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -1759,6 +1772,7 @@ control.prototype.rewindReplay = function () {
////// 回放时存档 //////
control.prototype.saveReplay = function () {
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -1779,6 +1793,7 @@ control.prototype.saveReplay = function () {
////// 回放时查看怪物手册 //////
control.prototype.bookReplay = function () {
if (core.status.event.id=='save' || core.status.event.id=='book') return;
if (!core.status.replay.replaying) return;
if (!core.status.replay.pausing) {
core.drawTip("请先暂停录像");
@ -1842,7 +1857,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;
}
@ -1862,7 +1877,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;
}
}
@ -1895,7 +1910,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;
}
}
@ -1918,10 +1933,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)) {
setTimeout(function () {
core.replay();
}, 750 / Math.max(1, core.status.replay.speed));
return;
}
}
@ -2331,7 +2353,8 @@ control.prototype.getStatus = function (statusName) {
////// 获得某个等级的名称 //////
control.prototype.getLvName = function () {
if (core.status.hero.lv>core.firstData.levelUp.length) return core.status.hero.lv;
if (!core.isset(core.firstData.levelUp) || core.status.hero.lv<=0
|| core.status.hero.lv>core.firstData.levelUp.length) return core.status.hero.lv;
return core.firstData.levelUp[core.status.hero.lv-1].name || core.status.hero.lv;
}

View File

@ -171,10 +171,11 @@ core.prototype.init = function (coreData, callback) {
core.setLocalStorage('battleAnimate', false);
}
// core.initStatus.shops = core.firstData.shops;
if (core.isset(core.firstData.shops)) {
core.firstData.shops.forEach(function (t) {
core.initStatus.shops[t.id] = t;
})
}
core.dom.versionLabel.innerHTML = core.firstData.version;
core.dom.logoLabel.innerHTML = core.firstData.title;
@ -310,7 +311,7 @@ core.prototype.resetStatus = function(hero, hard, floorId, route, maps, values)
////// 开始游戏 //////
core.prototype.startGame = function (hard, callback) {
core.control.startGame(hard, callback);huo
core.control.startGame(hard, callback);
}
////// 重新开始游戏;此函数将回到标题页面 //////
@ -664,13 +665,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);
}
////// 显示/隐藏某个块时的动画效果 //////

View File

@ -4,9 +4,9 @@ function enemys() {
////// 初始化 //////
enemys.prototype.init = function () {
// 怪物属性初始化定义:
this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80;
//delete(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80);
this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys;
this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)};
}
////// 获得一个或所有怪物数据 //////
@ -41,129 +41,112 @@ enemys.prototype.hasSpecial = function (special, test) {
return false;
}
enemys.prototype.getSpecials = function () {
return this.enemydata.getSpecials();
}
enemys.prototype.calContent = function (enemy, content) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (typeof content == 'string') return content;
if (content instanceof Function) {
return content(enemy);
}
return "";
}
////// 获得所有特殊属性的名称 //////
enemys.prototype.getSpecialText = function (enemyId) {
var enemy = core.material.enemys[enemyId];
enemys.prototype.getSpecialText = function (enemy) {
// 移动到了脚本编辑 - getSpecials中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (!core.isset(enemy)) return [];
var special = enemy.special;
var text = [];
if (this.hasSpecial(special, 1)) text.push("先攻");
if (this.hasSpecial(special, 2)) text.push("魔攻");
if (this.hasSpecial(special, 3)) text.push("坚固");
if (this.hasSpecial(special, 4)) text.push("2连击");
if (this.hasSpecial(special, 5)) text.push("3连击");
if (this.hasSpecial(special, 6)) text.push((enemy.n||4)+"连击");
if (this.hasSpecial(special, 7)) text.push("破甲");
if (this.hasSpecial(special, 8)) text.push("反击");
if (this.hasSpecial(special, 9)) text.push("净化");
if (this.hasSpecial(special, 10)) text.push("模仿");
if (this.hasSpecial(special, 11)) text.push("吸血");
if (this.hasSpecial(special, 12)) text.push("中毒");
if (this.hasSpecial(special, 13)) text.push("衰弱");
if (this.hasSpecial(special, 14)) text.push("诅咒");
if (this.hasSpecial(special, 15)) text.push("领域");
if (this.hasSpecial(special, 16)) text.push("夹击");
if (this.hasSpecial(special, 17)) text.push("仇恨");
if (this.hasSpecial(special, 18)) text.push("阻击");
if (this.hasSpecial(special, 19)) text.push("自爆");
if (this.hasSpecial(special, 20)) text.push("无敌");
if (this.hasSpecial(special, 21)) text.push("退化");
if (this.hasSpecial(special, 22)) text.push("固伤");
if (this.hasSpecial(special, 23)) text.push("重生");
var specials=this.getSpecials();
if (core.isset(specials)) {
for (var i=0;i<specials.length;i++) {
if (this.hasSpecial(special, specials[i][0]))
text.push(this.calContent(enemy, specials[i][1]));
}
}
return text;
}
////// 获得每个特殊属性的说明 //////
enemys.prototype.getSpecialHint = function (enemy, special) {
// 移动到了脚本编辑 - getSpecials中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var specials=this.getSpecials();
if (!core.isset(special)) {
if (!core.isset(specials)) return [];
var hints = [];
for (var i=1;i<100;i++) {
if (this.hasSpecial(enemy.special, i)) {
var hint=this.getSpecialHint(enemy, i);
if (hint!='')
hints.push(hint);
}
for (var i=0;i<specials.length;i++) {
if (this.hasSpecial(enemy, specials[i][0]))
hints.push(this.calContent(enemy, specials[i][1])+""+this.calContent(enemy, specials[i][2]));
}
return hints;
}
switch (special) {
case 1: return "先攻:怪物首先攻击";
case 2: return "魔攻:怪物无视勇士的防御";
case 3: return "坚固勇士每回合最多只能对怪物造成1点伤害";
case 4: return "2连击怪物每回合攻击2次";
case 5: return "3连击怪物每回合攻击3次";
case 6: return (enemy.n||4)+"连击: 怪物每回合攻击"+(enemy.n||4)+"次";
case 7: return "破甲:战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害";
case 8: return "反击:战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御";
case 9: return "净化:战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害";
case 10: return "模仿:怪物的攻防和勇士攻防相等";
case 11: return "吸血:战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");
case 12: return "中毒:战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点";
case 13: return "衰弱:战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%");
case 14: return "诅咒:战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验";
case 15: return "领域:经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";
case 16: return "夹击:经过两只相同的怪物中间,勇士生命值变成一半";
case 17: return "仇恨:战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)";
case 18: return "阻击:经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";
case 19: return "自爆战斗后勇士的生命值变成1";
case 20: return "无敌:勇士无法打败怪物,除非拥有十字架";
case 21: return "退化:战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";
case 22: return "固伤:战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";
case 23: return "重生:怪物被击败后,角色转换楼层则怪物将再次出现";
default: break;
if (!core.isset(specials)) return "";
for (var i=0;i<specials.length;i++) {
if (special == specials[i][0])
return this.calContent(enemy, specials[i][1])+""+this.calContent(enemy, specials[i][2]);
}
return "";
}
////// 能否获胜 //////
enemys.prototype.canBattle = function (monsterId) {
var damage = this.getDamage(monsterId);
enemys.prototype.canBattle = function (enemyId) {
var damage = this.getDamage(enemyId);
return damage != null && damage < core.status.hero.hp;
}
////// 获得某个怪物的伤害 //////
enemys.prototype.getDamage = function (monsterId) {
var monster = core.material.enemys[monsterId];
var damage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
enemys.prototype.getDamage = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var damage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (damage == null) return null;
return damage + this.getExtraDamage(monster);
return damage + this.getExtraDamage(enemy);
}
////// 获得某个怪物的额外伤害 //////
enemys.prototype.getExtraDamage = function (monster) {
enemys.prototype.getExtraDamage = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var extra_damage = 0;
if (this.hasSpecial(monster.special, 17)) { // 仇恨
if (this.hasSpecial(enemy.special, 17)) { // 仇恨
extra_damage += core.getFlag('hatred', 0);
}
if (this.hasSpecial(monster.special, 22)) { // 固伤
extra_damage += monster.damage||0;
if (this.hasSpecial(enemy.special, 22)) { // 固伤
extra_damage += enemy.damage||0;
}
return extra_damage;
}
////// 接下来N个临界值和临界减伤计算 //////
enemys.prototype.nextCriticals = function (monsterId, number) {
enemys.prototype.nextCriticals = function (enemy, number) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var useTurn = true; // 是否使用回合法计算临界值如果要用循环法则直接改为false。
var useTurn = !core.flags.useLoop; // 是否使用回合法计算临界值如果要用循环法则直接改为false。
number = number||1;
var monster = core.material.enemys[monsterId];
if (this.hasSpecial(monster.special, 3)) {
if (core.status.hero.atk<=monster.def) {
return [[monster.def+1-core.status.hero.atk,'?']];
if (this.hasSpecial(enemy.special, 3)) {
if (core.status.hero.atk<=enemy.def) {
return [[enemy.def+1-core.status.hero.atk,'?']];
}
return [];
}
// 坚固、模仿怪物没有临界!
if (this.hasSpecial(monster.special, 10)) return [];
var info = this.getDamageInfo(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (this.hasSpecial(enemy.special, 10)) return [];
var info = this.getDamageInfo(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
if (info == null) {
if (core.status.hero.atk<=monster.def) {
return [[monster.def+1-core.status.hero.atk,'?']];
if (core.status.hero.atk<=enemy.def) {
return [[enemy.def+1-core.status.hero.atk,'?']];
}
return [];
}
@ -173,14 +156,14 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
}
var list = [], pre = null;
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = monster.def, turn = info.turn;
var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = enemy.def, turn = info.turn;
if (useTurn) { // 回合数计算法
for (var t = turn-1;t>=1;t--) {
var nextAtk = Math.ceil(mon_hp/t) + mon_def;
if (nextAtk<=hero_atk) break;
if (nextAtk!=pre) {
var nextInfo = this.getDamageInfo(monster, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef);
var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef);
if (nextInfo==null) break;
list.push([nextAtk-hero_atk,info.damage-nextInfo.damage]);
if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break;
@ -193,7 +176,7 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
else { // 暴力for循环法
pre = info.damage;
for (var atk=hero_atk+1;atk<=mon_hp+mon_def;atk++) {
var nextInfo = this.getDamageInfo(monster, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef);
var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef);
if (nextInfo==null) break;
if (pre>nextInfo.damage) {
pre = nextInfo.damage;
@ -208,115 +191,34 @@ enemys.prototype.nextCriticals = function (monsterId, number) {
}
////// N防减伤计算 //////
enemys.prototype.getDefDamage = function (monsterId, k) {
enemys.prototype.getDefDamage = function (enemy, k) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
k = k || 1;
var monster = core.material.enemys[monsterId];
var nowDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
var nextDamage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + k, core.status.hero.mdef);
var nowDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
var nextDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + k, core.status.hero.mdef);
if (nowDamage == null || nextDamage ==null) return "???";
return nowDamage - nextDamage;
}
////// 获得战斗伤害信息 //////
enemys.prototype.getDamageInfo = function(monster, hero_hp, hero_atk, hero_def, hero_mdef) {
if (typeof monster == 'string') {
monster = core.material.enemys[monster];
}
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special;
hero_hp=Math.max(0, hero_hp);
hero_atk=Math.max(0, hero_atk);
hero_def=Math.max(0, hero_def);
hero_mdef=Math.max(0, hero_mdef);
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) // 如果是无敌属性,且勇士未持有十字架
return null; // 返回不可战斗
var initDamage = 0; // 战前伤害
// 吸血
if (this.hasSpecial(mon_special, 11)) {
var vampireDamage = hero_hp * monster.value;
// 如果有神圣盾免疫吸血等可以在这里写
vampireDamage = Math.floor(vampireDamage) || 0;
// 加到自身
if (monster.add) // 如果加到自身
mon_hp += vampireDamage;
initDamage += vampireDamage;
}
// 模仿
if (this.hasSpecial(mon_special,10)) {
mon_atk = hero_atk;
mon_def = hero_def;
}
// 坚固
if (this.hasSpecial(mon_special,3) && mon_def < hero_atk - 1) mon_def = hero_atk - 1;
if (hero_atk <= mon_def) return null; // 不可战斗时请直接返回null
var per_damage = mon_atk - hero_def;
// 魔攻
if (this.hasSpecial(mon_special,2)) per_damage = mon_atk;
if (per_damage < 0) per_damage = 0;
// 2连击 & 3连击 & N连击
if (this.hasSpecial(mon_special, 4)) per_damage *= 2;
if (this.hasSpecial(mon_special, 5)) per_damage *= 3;
if (this.hasSpecial(mon_special, 6)) per_damage *= (monster.n||4);
var counterDamage = 0;
// 反击
if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk);
// 先攻
if (this.hasSpecial(mon_special, 1))
initDamage += per_damage;
// 破甲
if (this.hasSpecial(mon_special, 7))
initDamage += Math.floor(core.values.breakArmor * hero_def);
// 净化
if (this.hasSpecial(mon_special, 9))
initDamage += Math.floor(core.values.purify * hero_mdef);
// turn: 勇士攻击回合数
var turn = Math.ceil(mon_hp / (hero_atk - mon_def));
var ans = initDamage + (turn - 1) * per_damage + turn * counterDamage;
ans -= hero_mdef;
if (!core.flags.enableNegativeDamage)
ans=Math.max(0, ans);
return {
"hero_atk": hero_atk,
"hero_def": hero_def,
"hero_mdef": hero_mdef,
"mon_hp": mon_hp,
"mon_atk": mon_atk,
"mon_def": mon_def,
"per_damage": per_damage,
"initDamage": initDamage,
"turn": turn,
"damage": ans
};
////// 获得战斗伤害信息(实际伤害计算函数) //////
enemys.prototype.getDamageInfo = function(enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
// 移动到了脚本编辑 - getDamageInfo中
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
return this.enemydata.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef);
}
////// 具体的伤害计算公式 //////
enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) {
////// 获得在某个勇士属性下怪物伤害 //////
enemys.prototype.calDamage = function (enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (typeof monster == 'string') {
monster = core.material.enemys[monster];
}
var info = this.getDamageInfo(monster, hero_hp, hero_atk, hero_def, hero_mdef);
var info = this.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef);
if (info == null) return null;
return info.damage;
}
////// 更新怪物数据 //////
enemys.prototype.updateEnemys = function () {
return this.enemydata.updateEnemys();
}
////// 获得当前楼层的怪物列表 //////
@ -328,42 +230,42 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
for (var b = 0; b < mapBlocks.length; b++) {
if (core.isset(mapBlocks[b].event) && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)
&& mapBlocks[b].event.cls.indexOf('enemy')==0) {
var monsterId = mapBlocks[b].event.id;
if (core.isset(used[monsterId])) continue;
var enemyId = mapBlocks[b].event.id;
if (core.isset(used[enemyId])) continue;
var monster = core.material.enemys[monsterId];
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def;
if (this.hasSpecial(monster.special, 10)) {
var enemy = core.material.enemys[enemyId];
var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def;
if (this.hasSpecial(enemy.special, 10)) {
mon_atk=core.status.hero.atk;
mon_def=core.status.hero.def;
}
if (this.hasSpecial(monster.special, 3) && mon_def < core.status.hero.atk - 1)
if (this.hasSpecial(enemy.special, 3) && mon_def < core.status.hero.atk - 1)
mon_def = core.status.hero.atk - 1;
var specialText = core.enemys.getSpecialText(monsterId);
var specialText = core.enemys.getSpecialText(enemyId);
if (specialText.length>=3) specialText = "多属性...";
else specialText = specialText.join(" ");
var critical = this.nextCriticals(monsterId);
var critical = this.nextCriticals(enemyId);
if (critical.length>0) critical=critical[0];
enemys.push({
'id': monsterId,
'name': monster.name,
'id': enemyId,
'name': enemy.name,
'hp': mon_hp,
'atk': mon_atk,
'def': mon_def,
'money': monster.money,
'experience': monster.experience,
'point': monster.point||0, // 加点
'money': enemy.money,
'experience': enemy.experience,
'point': enemy.point||0, // 加点
'special': specialText,
'damage': this.getDamage(monsterId),
'damage': this.getDamage(enemyId),
'critical': critical[0],
'criticalDamage': critical[1],
'defDamage': this.getDefDamage(monsterId)
'defDamage': this.getDefDamage(enemyId)
});
used[monsterId] = true;
used[enemyId] = true;
}
}

View File

@ -461,7 +461,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 +481,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 +744,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();
@ -802,6 +802,16 @@ events.prototype.doAction = function() {
core.updateStatusBar();
this.doAction();
break;
case "updateEnemys":
core.enemys.updateEnemys();
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();
@ -1302,6 +1312,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];
@ -1376,7 +1445,8 @@ events.prototype.setHeroIcon = function (name) {
////// 检查升级事件 //////
events.prototype.checkLvUp = function () {
if (!core.flags.enableLevelUp || core.status.hero.lv>=core.firstData.levelUp.length) return;
if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp)
|| core.status.hero.lv>=core.firstData.levelUp.length) return;
// 计算下一个所需要的数值
var need=core.firstData.levelUp[core.status.hero.lv].need;
if (!core.isset(need)) return;

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

@ -1307,10 +1307,10 @@ ui.prototype.drawBook = function (index) {
damage = core.formatBigNumber(damage);
if (core.enemys.hasSpecial(core.material.enemys[enemy.id], 19))
damage += "+";
}
if (core.material.enemys[enemy.id].notBomb)
damage += "[b]";
}
core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px Verdana');
core.canvas.ui.textAlign = "left";
@ -1490,7 +1490,7 @@ ui.prototype.drawToolbox = function(index) {
}
var page = parseInt((index%1000)/12)+1;
var totalPage = parseInt(Math.max(tools.length, constants.length)/12)+1;
var totalPage = Math.ceil(Math.max(tools.length, constants.length)/12);
if (!core.hasItem(selectId)) selectId=null;
@ -1791,8 +1791,8 @@ ui.prototype.drawStatistics = function () {
'count': 0, 'money': 0, 'experience': 0, 'point': 0,
},
'count': {
'yellowDoor': 0, 'blueDoor': 0, 'redDoor': 0, 'steelDoor': 0,
'yellowKey': 0, 'blueKey': 0, 'redKey': 0, 'steelKey': 0,
'yellowDoor': 0, 'blueDoor': 0, 'redDoor': 0, 'greenDoor': 0, 'steelDoor': 0,
'yellowKey': 0, 'blueKey': 0, 'redKey': 0, 'greenKey': 0, 'steelKey': 0,
'redJewel': 0, 'blueJewel': 0, 'greenJewel': 0, 'yellowJewel': 0,
'redPotion': 0, 'bluePotion': 0, 'greenPotion': 0, 'yellowPotion': 0, 'superPotion': 0,
'pickaxe': 0, 'bomb': 0, 'centerFly': 0,
@ -1895,6 +1895,7 @@ ui.prototype.drawStatistics = function () {
if (key=='yellowDoor') name="黄门";
else if (key=='blueDoor') name="蓝门";
else if (key=='redDoor') name="红门";
else if (key=='greenDoor') name="绿门";
else if (key=='steelDoor') name="铁门";
else name=core.material.items[key].name;
if (core.isset(name)) {

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": "阳光",
@ -152,9 +152,10 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"enableNegativeDamage": false,
"hatredDecrease": true,
"betweenAttackCeil": false,
"useLoop": false,
"startDirectly": false,
"canOpenBattleAnimate": true,
"showBattleAnimateConfirm": true,
"showBattleAnimateConfirm": false,
"battleAnimate": false,
"displayEnemyDamage": true,
"displayCritical": true,

View File

@ -301,9 +301,145 @@ functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a =
////// 读档事件后,载入事件前,可以执行的操作 //////
"afterLoadData" : function(data) {
// 读档事件后,载入事件前,可以执行的操作
// 可以在这里对怪物数据进行动态修改,详见文档——事件——怪物数据的动态修改
// 怪物数据的动态修改迁移到了“脚本编辑 - updateEnemys”中详见文档说明
core.enemys.updateEnemys();
}
},
"enemys": {
"getSpecials" : function() {
// 获得怪物的特殊属性,每一行定义一个特殊属性。
// 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
// 可以直接写字符串也可以写个function将怪物传进去
return [
[1, "先攻", "怪物首先攻击"],
[2, "魔攻", "怪物无视勇士的防御"],
[3, "坚固", "勇士每回合最多只能对怪物造成1点伤害"],
[4, "2连击", "怪物每回合攻击2次"],
[5, "3连击", "怪物每回合攻击3次"],
[6, function(enemy) {return (enemy.n||4)+"连击";}, function(enemy) {return "怪物每回合攻击"+(enemy.n||4)+"次";}],
[7, "破甲", "战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害"],
[8, "反击", "战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御"],
[9, "净化", "战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害"],
[10, "模仿", "怪物的攻防和勇士攻防相等"],
[11, "吸血", function (enemy) {return "吸血:战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");}],
[12, "中毒", "战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点"],
[13, "衰弱", "战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%")],
[14, "诅咒", "战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验"],
[15, "领域", function (enemy) {return "经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";}],
[16, "夹击", "经过两只相同的怪物中间,勇士生命值变成一半"],
[17, "仇恨", "战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)"],
[18, "阻击", function (enemy) {return "经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";}],
[19, "自爆", "战斗后勇士的生命值变成1"],
[20, "无敌", "勇士无法打败怪物,除非拥有十字架"],
[21, "退化", function (enemy) {return "战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";}],
[22, "固伤", function (enemy) {return "战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";}],
[23, "重生", "怪物被击败后,角色转换楼层则怪物将再次出现"]
];
},
"getDamageInfo" : function (enemy, hero_hp, hero_atk, hero_def, hero_mdef) {
// 获得战斗伤害信息(实际伤害计算函数)
// 怪物生命,怪物攻击、防御、特殊属性
var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def, mon_special = enemy.special;
// 勇士的负属性都按0计算
hero_hp=Math.max(0, hero_hp); hero_atk=Math.max(0, hero_atk); hero_def=Math.max(0, hero_def); hero_mdef=Math.max(0, hero_mdef);
// 如果是无敌属性,且勇士未持有十字架
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross"))
return null; // 不可战斗
// 战前造成的额外伤害(可被魔防抵消)
var init_damage = 0;
// 吸血
if (this.hasSpecial(mon_special, 11)) {
var vampire_damage = hero_hp * enemy.value;
// 如果有神圣盾免疫吸血等可以在这里写
// if (core.hasFlag('shield5')) vampire_damage = 0;
vampire_damage = Math.floor(vampire_damage) || 0;
// 加到自身
if (enemy.add) // 如果加到自身
mon_hp += vampire_damage;
init_damage += vampire_damage;
}
// 模仿
if (this.hasSpecial(mon_special, 10)) {
mon_atk = hero_atk;
mon_def = hero_def;
}
// 坚固
if (this.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1)
mon_def = hero_atk - 1;
// 检查是否破防;否则直接返回不可战斗
if (hero_atk <= mon_def) return null;
// 每回合怪物对勇士造成的战斗伤害
var per_damage = mon_atk - hero_def;
// 魔攻:战斗伤害就是怪物攻击力
if (this.hasSpecial(mon_special, 2)) per_damage = mon_atk;
// 战斗伤害不能为负值
if (per_damage < 0) per_damage = 0;
// 2连击 & 3连击 & N连击
if (this.hasSpecial(mon_special, 4)) per_damage *= 2;
if (this.hasSpecial(mon_special, 5)) per_damage *= 3;
if (this.hasSpecial(mon_special, 6)) per_damage *= (enemy.n||4);
// 每回合的反击伤害;反击是按照勇士的攻击次数来计算回合
var counterDamage = 0;
if (this.hasSpecial(mon_special, 8)) counterDamage += Math.floor(core.values.counterAttack * hero_atk);
// 先攻
if (this.hasSpecial(mon_special, 1)) init_damage += per_damage;
// 破甲
if (this.hasSpecial(mon_special, 7))
init_damage += Math.floor(core.values.breakArmor * hero_def);
// 净化
if (this.hasSpecial(mon_special, 9))
init_damage += Math.floor(core.values.purify * hero_mdef);
// 勇士每回合对怪物造成的伤害
var hero_per_damage = hero_atk - mon_def;
// 勇士的攻击回合数;为怪物生命除以每回合伤害向上取整
var turn = Math.ceil(mon_hp / hero_per_damage);
// 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害
var damage = init_damage + (turn - 1) * per_damage + turn * counterDamage;
// 再扣去魔防
damage -= hero_mdef;
// 检查是否允许负伤
if (!core.flags.enableNegativeDamage)
damage=Math.max(0, damage);
return {
"mon_hp": mon_hp,
"mon_atk": mon_atk,
"mon_def": mon_def,
"init_damage": init_damage,
"per_damage": per_damage,
"hero_per_damage": hero_per_damage,
"turn": turn,
"damage": damage
};
},
"updateEnemys" : function () {
// 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改
// 比如下面这个例子如果flag:xxx为真则将绿头怪的攻击设为100金币设为20
/*
if (core.hasFlag('xxx')) {
core.material.enemys.greenSlime.atk = 100;
core.material.enemys.greenSlime.money = 20;
}
*/
// 别忘了在事件中调用“更新怪物数据”事件!
}
},
"ui":{

Binary file not shown.

View File

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