Merge remote-tracking branch 'refs/remotes/ckcz123/master'
12
.idea/mota-js.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<excludeFolder url="file://$MODULE_DIR$/.tmp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/temp" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/tmp" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
29
LICENSE.md
Normal file
@ -0,0 +1,29 @@
|
||||
BSD 3-Clause License
|
||||
|
||||
Copyright (c) 2018, Zhang Chen
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the name of the copyright holder nor the names of its
|
||||
contributors may be used to endorse or promote products derived from
|
||||
this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
15
README.md
@ -45,6 +45,21 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
|
||||
|
||||
## 更新说明
|
||||
|
||||
### 2018.1.21 V1.3.2
|
||||
|
||||
* [x] 增加录像和回放功能。
|
||||
* [x] 增加统计功能,现在能看到每部塔的游戏人数、通关人数和当前MAX了。
|
||||
* [x] 增加浏览地图功能,玩家可以快速查看每层楼的地图。
|
||||
* [x] 现在保存文件到本地,以及从本地文件读档了。
|
||||
* [x] 可以在全局开关中设置剑盾是否作为装备存在。
|
||||
* [x] 修复了部分已知Bug。
|
||||
|
||||
### 2018.1.12 V1.3.1
|
||||
|
||||
* [x] 增加虚拟键盘
|
||||
* [x] 增加自动存档(回退),A键可快速读档
|
||||
* [x] 修复几处较为严重的Bug
|
||||
|
||||
### 2018.1.1 V1.3
|
||||
|
||||
* [x] 支持全键盘操作。
|
||||
|
||||
@ -47,6 +47,7 @@ body{
|
||||
white-space: pre;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 2px;
|
||||
overflow: auto;
|
||||
}
|
||||
#editTip{
|
||||
position: absolute;
|
||||
@ -68,7 +69,6 @@ body{
|
||||
margin-right: 20px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
#mid{
|
||||
position: absolute;
|
||||
left: 448px;
|
||||
|
||||
1
_server/vendor/polyfill.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n():"function"==typeof define&&define.amd?define(n):n()}(0,function(){"use strict";function e(){}function n(e,n){for(;3===e._state;)e=e._value;0!==e._state?(e._handled=!0,f._immediateFn(function(){var i=1===e._state?n.onFulfilled:n.onRejected;if(null!==i){var r;try{r=i(e._value)}catch(e){return void o(n.promise,e)}t(n.promise,r)}else(1===e._state?t:o)(n.promise,e._value)})):e._deferreds.push(n)}function t(e,n){try{if(n===e)throw new TypeError("A promise cannot be resolved with itself.");if(n&&("object"==typeof n||"function"==typeof n)){var t=n.then;if(n instanceof f)return e._state=3,e._value=n,void i(e);if("function"==typeof t)return void r(function(e,n){return function(){e.apply(n,arguments)}}(t,n),e)}e._state=1,e._value=n,i(e)}catch(n){o(e,n)}}function o(e,n){e._state=2,e._value=n,i(e)}function i(e){2===e._state&&0===e._deferreds.length&&f._immediateFn(function(){e._handled||f._unhandledRejectionFn(e._value)});for(var t=0,o=e._deferreds.length;o>t;t++)n(e,e._deferreds[t]);e._deferreds=null}function r(e,n){var i=!1;try{e(function(e){i||(i=!0,t(n,e))},function(e){i||(i=!0,o(n,e))})}catch(e){if(i)return;i=!0,o(n,e)}}function f(e){if(!(this instanceof f))throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=0,this._handled=!1,this._value=void 0,this._deferreds=[],r(e,this)}var u=setTimeout,c=f.prototype;c.catch=function(e){return this.then(null,e)},c.then=function(t,o){var i=new this.constructor(e);return n(this,new function(e,n,t){this.onFulfilled="function"==typeof e?e:null,this.onRejected="function"==typeof n?n:null,this.promise=t}(t,o,i)),i},f.all=function(e){return new f(function(n,t){function o(e,f){try{if(f&&("object"==typeof f||"function"==typeof f)){var u=f.then;if("function"==typeof u)return void u.call(f,function(n){o(e,n)},t)}i[e]=f,0==--r&&n(i)}catch(e){t(e)}}if(!e||void 0===e.length)throw new TypeError("Promise.all accepts an array");var i=Array.prototype.slice.call(e);if(0===i.length)return n([]);for(var r=i.length,f=0;i.length>f;f++)o(f,i[f])})},f.resolve=function(e){return e&&"object"==typeof e&&e.constructor===f?e:new f(function(n){n(e)})},f.reject=function(e){return new f(function(n,t){t(e)})},f.race=function(e){return new f(function(n,t){for(var o=0,i=e.length;i>o;o++)e[o].then(n,t)})},f._immediateFn="function"==typeof setImmediate&&function(e){setImmediate(e)}||function(e){u(e,0)},f._unhandledRejectionFn=function(e){void 0!==console&&console&&console.warn("Possible Unhandled Promise Rejection:",e)};var a=function(){if("undefined"!=typeof self)return self;if("undefined"!=typeof window)return window;if(void 0!==a)return a;throw Error("unable to locate global object")}();a.Promise||(a.Promise=f)});
|
||||
@ -1,23 +1,14 @@
|
||||
// vue 相关处理
|
||||
|
||||
document.body.onmousedown = function(e){
|
||||
selectBox.isSelected = false;
|
||||
editor.info = {};
|
||||
}
|
||||
iconLib.onmousedown = function(e){
|
||||
e.stopPropagation();
|
||||
}
|
||||
var exportM = new Vue({
|
||||
el: '#exportM',
|
||||
|
||||
data: {
|
||||
isExport: false,
|
||||
},
|
||||
methods: {
|
||||
exportMap: function(){
|
||||
editor.updateMap();
|
||||
if(editArea.error) {
|
||||
tip.whichShow = 3;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var filestr='';
|
||||
for (var yy = 0; yy < 13; yy++){
|
||||
filestr+='['
|
||||
@ -42,7 +33,9 @@ var exportM = new Vue({
|
||||
filestr += ']'+(yy==12?'':',\n');
|
||||
}
|
||||
pout.value = filestr;
|
||||
|
||||
editArea.mapArr = filestr;
|
||||
this.isExport = true;
|
||||
editArea.error = 0;
|
||||
tip.whichShow = 2;
|
||||
}
|
||||
}
|
||||
@ -64,10 +57,15 @@ var editArea = new Vue({
|
||||
mapArr: function (val, oldval) {
|
||||
var that = this;
|
||||
if(val=='') return;
|
||||
if(exportM.isExport){
|
||||
exportM.isExport = false;
|
||||
return;
|
||||
}
|
||||
if(that.formatArr()){
|
||||
that.error = 0;
|
||||
clearTimeout(that.formatTimer);
|
||||
|
||||
setTimeout(function(){
|
||||
that.mapArr = that.formatArr();
|
||||
that.drawMap();
|
||||
tip.whichShow = 8
|
||||
}, 1000);
|
||||
@ -107,7 +105,8 @@ var editArea = new Vue({
|
||||
},
|
||||
formatArr: function(){
|
||||
var formatArrStr = '';
|
||||
|
||||
var that = this;
|
||||
clearTimeout(that.formatTimer);
|
||||
if(this.mapArr.split(/\D+/).join(' ').trim().split(' ').length != 169) return false;
|
||||
var arr = this.mapArr.replace(/\s+/g, '').split('],[');
|
||||
|
||||
@ -128,7 +127,6 @@ var editArea = new Vue({
|
||||
}
|
||||
formatArrStr += ']'+(i==12?'':',\n');
|
||||
}
|
||||
|
||||
return formatArrStr;
|
||||
}
|
||||
}
|
||||
|
||||
21
docs/api.md
@ -35,7 +35,7 @@ main.statusBar.image.load.onclick // 点击状态栏中的读档按钮时
|
||||
main.statusBar.image.settings.onclick // 点击状态栏中的系统菜单时
|
||||
main.dom.playGame.onclick // 点击“开始游戏”时
|
||||
main.dom.loadGame.onclick // 点击“载入游戏”时
|
||||
main.dom.aboutGame.onclick // 点击“关于本塔”时
|
||||
main.dom.replayGame.onclick // 点击“录像回放”时
|
||||
main.dom.easyLevel.onclick // 点击“简单难度”时
|
||||
main.dom.normalLevel.onclick // 点击“普通难度”时
|
||||
main.dom.hardLevel.onclick // 点击“困难难度”时
|
||||
@ -56,6 +56,7 @@ core.hideStartAnimate // 隐藏游戏开始界面
|
||||
core.setStartProgressVal // 设置加载进度条进度
|
||||
core.setStartLoadTipText // 设置加载进度条提示文字
|
||||
core.loader // 加载图片和音频
|
||||
core.loadAutotile // 加载Autotile
|
||||
core.loadImage // 加载图片
|
||||
core.loadMusic // 加载音频
|
||||
core.isPlaying // 游戏是否已经开始
|
||||
@ -93,6 +94,7 @@ core.setAutoHeroMove // 设置勇士的自动行走路线
|
||||
core.autoHeroMove // 让勇士开始自动行走
|
||||
core.setHeroMoveInterval // 设置行走的效果动画
|
||||
core.setHeroMoveTriggerInterval // 设置勇士行走过程中对事件的触发检测
|
||||
core.moveAction // 实际每一步的行走过程
|
||||
* core.turnHero(direction) // 设置勇士的方向(转向)
|
||||
core.canMoveHero // 勇士能否前往某方向
|
||||
core.moveHero // 让勇士开始移动
|
||||
@ -176,18 +178,25 @@ core.getLocalStorage // 获得本地存储
|
||||
core.removeLocalStorage // 移除本地存储
|
||||
core.clone // 深拷贝一个对象
|
||||
core.formatDate // 格式化时间为字符串
|
||||
core.formatDate2 // 格式化时间为最简字符串
|
||||
core.setTwoDigits // 两位数显示
|
||||
core.debug // 进入Debug模式,攻防血和钥匙都调成很高的数值
|
||||
core.replay // 开始回放
|
||||
core.checkStatus // 判断当前能否进入某个事件
|
||||
core.openBook // 点击怪物手册时的打开操作
|
||||
core.useFly // 点击楼层传送器时的打开操作
|
||||
core.openToolbox // 点击工具栏时的打开操作
|
||||
core.openQuickShop // 点击快捷商店时的打开操作
|
||||
core.save // 点击保存按钮时的打开操作
|
||||
core.load // 点击读取按钮时的打开操作
|
||||
core.openSettings // 点击设置按钮时的打开操作
|
||||
core.autosave // 自动存档
|
||||
core.doSL // 实际进行存读档事件
|
||||
core.syncSave // 存档同步操作
|
||||
core.saveData // 存档到本地
|
||||
core.loadData // 从本地读档
|
||||
core.encodeRoute // 将路线压缩
|
||||
core.decodeRoute // 将路线解压缩
|
||||
* core.setStatus // 设置勇士属性
|
||||
* core.getStatus // 获得勇士属性
|
||||
core.getLvName // 获得某个等级的名称
|
||||
@ -198,6 +207,9 @@ core.insertAction // 往当前事件列表之前插入一系列事件
|
||||
* core.lockControl // 锁定状态栏,常常用于事件处理
|
||||
* core.unlockControl // 解锁状态栏
|
||||
* core.isset // 判断某对象是否不为undefined也不会null
|
||||
core.readFile // 读取一个本地文件内容
|
||||
core.download // 下载文件到本地
|
||||
core.copy // 复制一段文字到剪切板
|
||||
* core.playBgm // 播放背景音乐
|
||||
* core.pauseBgm // 暂停背景音乐的播放
|
||||
* core.resumeBgm // 恢复背景音乐的播放
|
||||
@ -240,6 +252,7 @@ core.events.startGame // 游戏开始事件
|
||||
* core.events.setInitData // 不同难度分别设置初始属性
|
||||
* core.events.win // 游戏获胜事件
|
||||
* core.events.lose // 游戏失败事件
|
||||
core.evens.gameOver // 游戏结束
|
||||
core.events.afterChangeFloor // 转换楼层结束的事件
|
||||
core.events.doEvents // 开始执行一系列自定义事件
|
||||
core.events.doAction // 执行当前自定义事件列表中的下一个事件
|
||||
@ -260,6 +273,7 @@ core.events.changeLight // 改变亮灯(感叹号)的事件
|
||||
* core.events.afterLoadData // 读档事件后,载入事件前,可以执行的操作
|
||||
|
||||
// ------ 点击事件和键盘事件的处理 ------
|
||||
core.events.longClick // 长按
|
||||
core.events.keyDownCtrl // 按下Ctrl键时(快捷跳过对话)
|
||||
core.events.clickConfirmBox // 确认框界面时的点击操作
|
||||
core.events.keyUpConfirmBox // 确认框界面时,放开某个键的操作
|
||||
@ -273,6 +287,9 @@ core.events.clickBookDetail // 怪物手册属性显示界面时的点击操作
|
||||
core.events.clickFly // 楼层传送器界面时的点击操作
|
||||
core.events.keyDownFly // 楼层传送器界面时,按下某个键的操作
|
||||
core.events.keyUpFly // 楼层传送器界面时,放开某个键的操作
|
||||
core.events.clickViewMaps // 浏览地图界面时的点击操作
|
||||
core.events.keyDownViewMaps // 浏览地图界面时,按下某个键的操作
|
||||
core.events.keyUpViewMaps // 浏览地图界面时,放开某个键的操作
|
||||
core.events.clickShop // 商店界面时的点击操作
|
||||
core.events.keyDownShop // 商店界面时,按下某个键的操作
|
||||
core.events.keyUpShop // 商店界面时,放开某个键的操作
|
||||
@ -295,6 +312,7 @@ core.events.keyUpSettings // 系统菜单栏界面时,放开某个键的操作
|
||||
core.events.clickSyncSave // 同步存档界面时的点击操作
|
||||
core.events.keyDownSyncSave // 同步存档界面时,按下某个键的操作
|
||||
core.events.keyUpSyncSave // 同步存档界面时,放开某个键的操作
|
||||
core.events.clickKeyBoard // 虚拟键盘界面时的点击操作
|
||||
core.events.clickAbout // “关于”界面时的点击操作
|
||||
```
|
||||
|
||||
@ -341,6 +359,7 @@ core.ui.drawPagination // 绘制分页
|
||||
core.ui.drawEnemyBook // 绘制怪物手册
|
||||
core.ui.drawBookDetail // 绘制怪物属性的详细信息
|
||||
core.ui.drawFly // 绘制楼层传送器
|
||||
core.ui.drawMaps // 绘制浏览地图界面
|
||||
core.ui.drawToolbox // 绘制道具栏
|
||||
core.ui.drawSLPanel // 绘制存档/读档界面
|
||||
core.ui.drawThumbnail // 绘制一个缩略图
|
||||
|
||||
@ -12,9 +12,9 @@
|
||||
|
||||
本塔目前支持的所有道具列表在样板0层中已全部给出。当你在样板0层中拿到某个宝物时会有提示,这里不再赘述,详见拿到该道具的说明。
|
||||
|
||||
大多数宝物都有默认的效果,十字架和屠龙匕首暂未定义,如有自己的需求可参见[自定义道具效果](personalization#自定义道具效果)。
|
||||
大多数宝物都有默认的效果,屠龙匕首暂未定义,如有自己的需求可参见[自定义道具效果](personalization#自定义道具效果)。
|
||||
|
||||
!> 请注意,本塔没有"装备"的说法,所有剑盾拿到后将立刻作为攻防数值直接加到勇士的属性上。
|
||||
如需让剑盾变成装备,可以直接在`data.js`中设置`'equipment': true`即可。
|
||||
|
||||
拿到道具后将触发`afterGetItem`事件,有关事件的详细介绍请参见[事件](event)。
|
||||
|
||||
@ -65,6 +65,7 @@ enemys.prototype.getSpecialText = function (enemyId) {
|
||||
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("退化");
|
||||
return text.join(" ");
|
||||
}
|
||||
```
|
||||
@ -94,6 +95,8 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数
|
||||
|
||||
吸血怪需要在怪物后添加value,代表吸血的比例。
|
||||
|
||||
可以给吸血怪添加`'add': true`来将吸血的数值加到自身上。
|
||||
|
||||

|
||||
|
||||
中毒怪让勇士中毒后,每步扣减的生命值由`data.js`中的values定义。
|
||||
@ -106,7 +109,7 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数
|
||||
|
||||
领域怪需要在怪物后添加value,代表领域伤害的数值。如果勇士生命值扣减到0,则直接死亡触发lose事件。
|
||||
|
||||
领域是十字伤害还是九宫格伤害由data.js中的全局变量`zoneSquare`设定。你也可以对该怪物自行进行设定。
|
||||
领域是十字伤害还是九宫格伤害由`zoneSquare`设定,如设置为true则为九宫格伤害,不指定或为false则为十字伤害。
|
||||
|
||||
`range`选项可选,代表该领域怪的范围,不写则默认为1。
|
||||
|
||||
@ -118,6 +121,10 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数
|
||||
|
||||
请注意如果吸血、领域、阻击中任何两个同时存在,则value会冲突。**因此请勿将吸血、领域或阻击放置在同一个怪物身上。**
|
||||
|
||||
退化怪需要在后面增加'atkValue'和'defValue'表示退化的数值。
|
||||
|
||||

|
||||
|
||||
如有额外需求,可参见[自定义怪物属性](personalization#自定义自定义怪物属性),里面讲了如何设置一个新的怪物属性。
|
||||
|
||||
## 路障,楼梯,传送门
|
||||
@ -142,10 +149,6 @@ floorId指定的是目标楼层的唯一标识符(ID)。
|
||||
|
||||
可以指定time,指定后切换动画时长为指定的数值。
|
||||
|
||||
楼梯和传送门默认可`"穿透"`。所谓穿透,就是当寻路穿过一个楼梯/传送门后,不会触发楼层传送事件,而是继续前进。通过系统Flag可以指定是否穿透,你也可以对每个传送点单独设置该项。
|
||||
|
||||

|
||||
|
||||
## 背景音乐
|
||||
|
||||
本塔支持BGM和SE的播放。
|
||||
@ -169,6 +172,8 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
|
||||
|
||||
!> mid格式是通过数学方法模拟出来的音乐效果,质量可能会和实际效果差距较大。
|
||||
|
||||
!> **警告!** mid格式在手机端播放可能会特别卡,仍推荐直接使用mp3/ogg来播放。
|
||||
|
||||
定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。
|
||||
|
||||
**另外,考虑到用户的流量问题,将遵循如下规则:**
|
||||
@ -190,17 +195,21 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
|
||||
- **点任意块并拖动:** 指定寻路路线
|
||||
- **单击勇士:** 转向
|
||||
- **双击勇士:** 轻按(仅在轻按开关打开时有效)
|
||||
- **长按任意位置:** 打开虚拟键盘
|
||||
|
||||
键盘操作快捷键如下:
|
||||
|
||||
- **[CTRL]** 跳过对话
|
||||
- **[X]** 打开/关闭怪物手册
|
||||
- **[G]** 打开/关闭楼层传送器
|
||||
- **[A]** 读取自动存档
|
||||
- **[S/D]** 打开/关闭存/读档页面
|
||||
- **[K]** 打开/关闭快捷商店选择列表
|
||||
- **[T]** 打开/关闭工具栏
|
||||
- **[ESC]** 打开/关闭系统菜单
|
||||
- **[H]** 打开帮助页面
|
||||
- **[Z]** 转向
|
||||
- **[R]** 回退
|
||||
- **[SPACE]** 轻按(仅在轻按开关打开时有效)
|
||||
- **[1]** 快捷使用破墙镐
|
||||
- **[2]** 快捷使用炸弹/圣锤
|
||||
|
||||
@ -16,7 +16,8 @@
|
||||
- 启用状态下,该事件才处于可见状态,可被触发、交互与处理。
|
||||
- 禁用状态下该事件相当于不存在,不可见、不可被触发、不可交互。
|
||||
|
||||
所有事件默认情况下都是启用的,除非指定了`enable: false`。
|
||||
所有事件默认情况下都是启用的,除非指定了`enable: false`。
|
||||
|
||||
在事件列表中使用`type: show`和`type: hide`可以将一个禁用事件启用,或将一个启用事件给禁用。
|
||||
|
||||
|
||||
@ -465,6 +466,8 @@ direction为可选的,指定的话将使勇士的朝向变成该方向
|
||||
|
||||
time为可选的,指定的话将作为楼层切换动画的时间。
|
||||
|
||||
**time也可以置为0,如果为0则没有楼层切换动画。**
|
||||
|
||||
!> **changeFloor到达一个新的楼层,将不会执行firstArrive事件!如有需求请在到达点设置自定义事件,然后使用type: trigger立刻调用之。**
|
||||
|
||||
### changePos: 当前位置切换/勇士转向
|
||||
@ -844,8 +847,9 @@ events.prototype.addPoint = function (enemy) {
|
||||
全局商店定义在`data.js`中,找到shops一项。
|
||||
|
||||
``` js
|
||||
"shops": { // 定义全局商店(即快捷商店)
|
||||
"moneyShop1": { // 商店唯一ID
|
||||
"shops": [ // 定义全局商店(即快捷商店)
|
||||
{
|
||||
"id": "moneyShop1", // 商店唯一ID
|
||||
"name": "贪婪之神", // 商店名称(标题)
|
||||
"icon": "blueShop", // 商店图标,blueShop为蓝色商店,pinkShop为粉色商店
|
||||
"textInList": "1F金币商店", // 在快捷商店栏中显示的名称
|
||||
@ -870,7 +874,8 @@ events.prototype.addPoint = function (enemy) {
|
||||
// "status:hp+=2*(status:atk+status:def)" 将生命提升攻防和的数值的两倍
|
||||
]
|
||||
},
|
||||
"expShop1": { // 商店唯一ID
|
||||
{
|
||||
"id": "expShop1", // 商店唯一ID
|
||||
"name": "经验之神",
|
||||
"icon": "pinkShop",
|
||||
"textInList": "1F经验商店",
|
||||
@ -885,15 +890,15 @@ events.prototype.addPoint = function (enemy) {
|
||||
{"text": "攻击+5", "need": "30", "effect": "status:atk+=5"},
|
||||
{"text": "防御+5", "need": "30", "effect": "status:def+=5"},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
```
|
||||
|
||||
全局商店全部定义在`data.js`中的shops一项里。
|
||||
每个全局商店有一个唯一标识符(ID),然后是一系列对该商店的定义。
|
||||
全局商店全部定义在`data.js`中的shops一项里。商店以数组形式存放,每一个商店都是其中的一个对象。
|
||||
|
||||
- id 为商店的唯一标识符(ID),请确保任何两个商店的id都不相同
|
||||
- name 为商店的名称(打开商店后的标题)
|
||||
- icon 为商店的图标,blueShop为蓝色商店,pinkShop为粉色商店
|
||||
- icon 为商店的图标,在icons.js的npcs中定义。如woman可代表一个商人。
|
||||
- textInList 为其在快捷商店栏中显示的名称,如"3楼金币商店"等
|
||||
- use 为消耗的类型,是金币(money)还是经验(experience)。
|
||||
- need 是一个表达式,计算商店所需要用到的数值。
|
||||
@ -967,6 +972,26 @@ events.prototype.addPoint = function (enemy) {
|
||||
|
||||
当且仅当勇士第一次到达某层时,将会触发此事件。可以利用此事件来显示一些剧情,或再让它调用 `{"type": "trigger"}` 来继续调用其他的事件。
|
||||
|
||||
## 使用炸弹后的事件
|
||||
|
||||
上面的afterBattle事件只对和怪物进行战斗后才有会被处理。
|
||||
|
||||
如果我们想在使用炸弹后也能触发一些事件(如开门),则可以在`events.js`里面的`afterUseBomb`函数进行处理:
|
||||
|
||||
``` js
|
||||
////// 使用炸弹/圣锤后的事件 //////
|
||||
events.prototype.afterUseBomb = function () {
|
||||
// 这是一个使用炸弹也能开门的例子
|
||||
if (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在
|
||||
&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在
|
||||
{
|
||||
core.insertAction([ // 插入事件
|
||||
{"type": "openDoor", "loc": [x0,y0]} // 开门
|
||||
])
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 战前剧情
|
||||
|
||||
有时候光战后事件`afterBattle`是不够的,我们可能还需要战前剧情,例如Boss战之前和Boss进行一段对话。
|
||||
|
||||
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 4.3 KiB |
BIN
docs/img/tuihua.png
Normal file
|
After Width: | Height: | Size: 8.8 KiB |
@ -9,7 +9,7 @@
|
||||
你需要有满足如下条件才能进行制作:
|
||||
|
||||
- Windows 8以上操作系统;Windows 7需要安装.Net Framework 4.0。(能打开同目录下的“启动服务.exe”即可)
|
||||
- 任一款现代浏览器。强烈推荐Chrome。
|
||||
- Chrome浏览器。其他浏览器可能会导致本地服务器产生闪退等现象。
|
||||
- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。
|
||||
- ([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。)
|
||||
|
||||
@ -28,6 +28,8 @@
|
||||
* “JS代码压缩工具”能对JS代码进行压缩,从而减少IO请求数和文件大小。
|
||||
* “伤害和临界值计算器”是一个很便捷的小工具,能对怪物的伤害和临界值进行计算。
|
||||
|
||||
!> **警告:** 非Chrome浏览器(如Edge/IE等)下本地服务器可能表现不正常,会出现闪退等现象。请务必下载安装Chrome浏览器。
|
||||
|
||||
## 新建剧本
|
||||
|
||||
类似于RMXP,本塔每层楼都是一个“剧本”,剧本内主要定义了本层的地图和各种事件。主函数将读取每个剧本,并生成实际的地图供游戏使用。
|
||||
@ -147,7 +149,7 @@
|
||||
|
||||
只需要修改自己用到的怪物属性即可,其他没有用到的怪物完全无所谓。
|
||||
|
||||
做完后保存所有文件,然后右键,选择使用chrome浏览器打开`index.html`,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!
|
||||
做完后保存所有文件,在本地服务器中“启动游戏”,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!
|
||||
|
||||

|
||||
|
||||
|
||||
104
drawMapGUI.html
@ -77,31 +77,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// 生成定位编号
|
||||
(function(){
|
||||
var colNum = ' ';
|
||||
for(var i=0; i<13; i++){
|
||||
var tpl = '<td>'+i+'<div class="colBlock" style="left:'+(i*32+1)+'px;"></div></td>';
|
||||
colNum += tpl;
|
||||
}
|
||||
arrColMark.innerHTML = '<tr>'+colNum+'</tr>';
|
||||
mapColMark.innerHTML = '<tr>'+colNum+'</tr>';
|
||||
var rowNum = ' ';
|
||||
for(var i=0; i<13; i++){
|
||||
var tpl = '<tr><td>'+i+'<div class="rowBlock" style="top:'+(i*32+1)+'px;"></div></td></tr>';
|
||||
rowNum += tpl;
|
||||
}
|
||||
arrRowMark.innerHTML = rowNum;
|
||||
mapRowMark.innerHTML = rowNum;
|
||||
})();
|
||||
// 生成定位编号
|
||||
(function(){
|
||||
var colNum = ' ';
|
||||
for(var i=0; i<13; i++){
|
||||
var tpl = '<td>'+i+'<div class="colBlock" style="left:'+(i*32+1)+'px;"></div></td>';
|
||||
colNum += tpl;
|
||||
}
|
||||
arrColMark.innerHTML = '<tr>'+colNum+'</tr>';
|
||||
mapColMark.innerHTML = '<tr>'+colNum+'</tr>';
|
||||
var rowNum = ' ';
|
||||
for(var i=0; i<13; i++){
|
||||
var tpl = '<tr><td>'+i+'<div class="rowBlock" style="top:'+(i*32+1)+'px;"></div></td></tr>';
|
||||
rowNum += tpl;
|
||||
}
|
||||
arrRowMark.innerHTML = rowNum;
|
||||
mapRowMark.innerHTML = rowNum;
|
||||
})();
|
||||
</script>
|
||||
|
||||
<!-- =========================================================== -->
|
||||
|
||||
<script src='_server/vendor/vue.min.js'></script>
|
||||
<script src='_server/vendor/polyfill.min.js'></script>
|
||||
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
|
||||
<script src='_server/fs.js'></script>
|
||||
<!-- <script src='_server/editor_file.js'></script> -->
|
||||
<script src='_server/vm.js'></script>
|
||||
<script>
|
||||
|
||||
@ -119,7 +122,7 @@ var main={'instance':{}};
|
||||
var core={};
|
||||
|
||||
function editor() {
|
||||
this.version = "1.2";
|
||||
this.version = "1.3.2";
|
||||
this.material = {};
|
||||
}
|
||||
// 重构这一堆回调
|
||||
@ -144,7 +147,8 @@ editor.prototype.init = function(){
|
||||
});
|
||||
|
||||
Promise.all([p1, p2, p3])
|
||||
.then(function([maps, icons, img]){
|
||||
.then(function(results){
|
||||
var maps = results[0], icons = results[1];
|
||||
editor.idsInit(maps, icons); // 初始化图片素材信息
|
||||
editor.drawInitData(icons); // 初始化绘图
|
||||
editor.listen(); // 开始监听事件
|
||||
@ -176,7 +180,6 @@ editor.prototype.loadImg = function(url){
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
editor.prototype.loadAllImgs = function(icons){
|
||||
editor.material.images = {};
|
||||
var imgs = Object.keys(icons);
|
||||
@ -317,7 +320,6 @@ editor.prototype.drawMapBg = function(img){
|
||||
bgc.drawImage(img, 0, 0, 416, 416);
|
||||
}
|
||||
}
|
||||
|
||||
editor.prototype.updateMap = function(){
|
||||
|
||||
var drawTile = function(ctx, x, y, tileInfo){ // 绘制一个普通块
|
||||
@ -439,7 +441,6 @@ editor.prototype.updateMap = function(){
|
||||
}
|
||||
// 绘制地图 end
|
||||
}
|
||||
|
||||
editor.prototype.listen = function() {
|
||||
|
||||
var uc = ui.getContext('2d');
|
||||
@ -450,9 +451,11 @@ editor.prototype.listen = function() {
|
||||
}//在格子内画一个随机色块
|
||||
|
||||
function eToLoc(e) {
|
||||
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
|
||||
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
|
||||
editor.loc = {
|
||||
'x': document.documentElement.scrollLeft+e.clientX - mid.offsetLeft-mapEdit.offsetLeft,
|
||||
'y': document.documentElement.scrollTop+e.clientY - mid.offsetTop-mapEdit.offsetTop,
|
||||
'x': scrollLeft+e.clientX - mid.offsetLeft-mapEdit.offsetLeft,
|
||||
'y': scrollTop+e.clientY - mid.offsetTop-mapEdit.offsetTop,
|
||||
'size': 32
|
||||
};
|
||||
return editor.loc; }//返回可用的组件内坐标
|
||||
@ -580,9 +583,11 @@ editor.prototype.listen = function() {
|
||||
|
||||
data.onmousedown = function (e) {
|
||||
e.stopPropagation();
|
||||
var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
|
||||
var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
|
||||
var loc = {
|
||||
'x': document.documentElement.scrollLeft + e.clientX + iconLib.scrollLeft - right.offsetLeft-iconLib.offsetLeft,
|
||||
'y': document.documentElement.scrollTop + e.clientY + iconLib.scrollTop - right.offsetTop-iconLib.offsetTop,
|
||||
'x': scrollLeft + e.clientX + iconLib.scrollLeft - right.offsetLeft-iconLib.offsetLeft,
|
||||
'y': scrollTop + e.clientY + iconLib.scrollTop - right.offsetTop-iconLib.offsetTop,
|
||||
'size': 32
|
||||
};
|
||||
editor.loc = loc;
|
||||
@ -635,9 +640,17 @@ editor.prototype.listen = function() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.body.onmousedown = function(e){
|
||||
selectBox.isSelected = false;
|
||||
editor.info = {};
|
||||
}
|
||||
iconLib.onmousedown = function(e){
|
||||
e.stopPropagation();
|
||||
}
|
||||
}//绑定事件
|
||||
editor.prototype.locInfo = function(){
|
||||
|
||||
}
|
||||
/*
|
||||
editor.updateMap
|
||||
|
||||
@ -649,14 +662,37 @@ editor.info
|
||||
*/
|
||||
var editor = new editor();
|
||||
editor.init();
|
||||
|
||||
editor.fs=fs;
|
||||
// editor.file=editor_file;
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
//Vue
|
||||
//var listenByVue = function() {
|
||||
|
||||
//}
|
||||
//listenByVue()
|
||||
<script>
|
||||
// 文件相关操作
|
||||
// var promisify = function (fn, receiver) {
|
||||
// return function () {
|
||||
// for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
|
||||
// args[_key] = arguments[_key];
|
||||
// }
|
||||
// return new Promise(function (resolve, reject) {
|
||||
// fn.apply(receiver, [].concat(args, [function (res, err) {
|
||||
// return err ? reject(err) : resolve(res);
|
||||
// }]));
|
||||
// });
|
||||
// };
|
||||
// };
|
||||
// var fns = Object.keys(editor.file);
|
||||
// var promiseFns = {};
|
||||
// fns.forEach(function(fn){
|
||||
// promiseFns[fn] = promisify(editor.file[fn], editor.file)
|
||||
// });
|
||||
// editor.promiseFiles = Object.assign(promiseFns);
|
||||
|
||||
// editor.promiseFiles.getFloorFileList(editor)
|
||||
// .then(function(filelist){
|
||||
// editFile4map.filelist = filelist;
|
||||
// })
|
||||
// .catch(function(err){
|
||||
// console.log(err);
|
||||
// })
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
BIN
images/items.png
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
BIN
images/yewai.png
|
Before Width: | Height: | Size: 39 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/animates2:四方门.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 26 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/items1:方块宝石.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/四方机关门.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/宝石1.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/宝石2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/宝石3.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/宝石4.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
images/常用素材:如需使用请直接替换目录中的对应文件/旋转机关门.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
@ -32,7 +32,7 @@
|
||||
<div id='startButtons'>
|
||||
<span class='startButton' id='playGame'>开始游戏</span>
|
||||
<span class='startButton' id='loadGame'>载入游戏</span>
|
||||
<span class='startButton' id='aboutGame'>关于本塔</span>
|
||||
<span class='startButton' id='replayGame'>录像回放</span>
|
||||
</div>
|
||||
<div id='levelChooseButtons'>
|
||||
<span class='startButton' id='easyLevel'>简单</span>
|
||||
|
||||
1003
libs/core.js
31
libs/data.js
@ -6,7 +6,7 @@ data.prototype.init = function() {
|
||||
this.firstData = {
|
||||
"title": "魔塔样板", // 游戏名,将显示在标题页面以及切换楼层的界面中
|
||||
"name": "template", // 游戏的唯一英文标识符。由英文、数字、下划线组成,不能超过20个字符。
|
||||
"version": "Ver 1.0.0 (Beta)", // 当前游戏版本;版本不一致的存档不能通用。
|
||||
"version": "Ver 1.3.2", // 当前游戏版本;版本不一致的存档不能通用。
|
||||
"floorId": "sample0", // 初始楼层ID
|
||||
"hero": { // 勇士初始数据
|
||||
"name": "阳光", // 勇士名;可以改成喜欢的
|
||||
@ -32,17 +32,19 @@ data.prototype.init = function() {
|
||||
"poison": false, // 毒
|
||||
"weak": false, // 衰
|
||||
"curse": false, // 咒
|
||||
}
|
||||
},
|
||||
"steps": 0, // 行走步数统计
|
||||
},
|
||||
"startText": [ // 游戏开始前剧情。如果无剧情直接留一个空数组即可。
|
||||
"Hi,欢迎来到 HTML5 魔塔样板!\n\n本样板由艾之葵制作,可以让你在不会写任何代码\n的情况下也能做出属于自己的H5魔塔!",
|
||||
"这里游戏开始时的剧情。\n定义在data.js的startText处。\n\n你可以在这里写上自己的内容。",
|
||||
"赶快来试一试吧!"
|
||||
],
|
||||
"shops": { // 定义全局商店(即快捷商店)
|
||||
"moneyShop1": { // 商店唯一ID
|
||||
"shops": [ // 定义全局商店(即快捷商店)
|
||||
{
|
||||
"id": "moneyShop1", // 商店唯一ID
|
||||
"name": "贪婪之神", // 商店名称(标题)
|
||||
"icon": "blueShop", // 商店图标,blueShop为蓝色商店,pinkShop为粉色商店
|
||||
"icon": "blueShop", // 商店图标,在icons.js中的npc一项定义
|
||||
"textInList": "1F金币商店", // 在快捷商店栏中显示的名称
|
||||
"use": "money", // 商店所要使用的。只能是"money"或"experience"。
|
||||
"need": "20+10*times*(times+1)", // 商店需要的金币/经验数值;可以是一个表达式,以times作为参数计算。
|
||||
@ -65,7 +67,8 @@ data.prototype.init = function() {
|
||||
// "status:hp+=2*(status:atk+status:def)" 将生命提升攻防和的数值的两倍
|
||||
]
|
||||
},
|
||||
"expShop1": { // 商店唯一ID
|
||||
{
|
||||
"id": "expShop1", // 商店唯一ID
|
||||
"name": "经验之神",
|
||||
"icon": "pinkShop",
|
||||
"textInList": "1F经验商店",
|
||||
@ -80,8 +83,8 @@ data.prototype.init = function() {
|
||||
{"text": "攻击+5", "need": "30", "effect": "status:atk+=5"},
|
||||
{"text": "防御+5", "need": "30", "effect": "status:def+=5"},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
"levelUp": [ // 经验升级所需要的数值,是一个数组
|
||||
{}, // 第一项为初始等级,可以简单留空,也可以写name
|
||||
|
||||
@ -94,7 +97,7 @@ data.prototype.init = function() {
|
||||
|
||||
// effect也允许写一个function,代表本次升级将会执行的操作
|
||||
{"need": 40, "effect": function () {
|
||||
core.drawText("恭喜升级!");
|
||||
core.insertAction("恭喜升级!");
|
||||
core.status.hero.hp *= 2;
|
||||
core.status.hero.atk += 100;
|
||||
core.status.hero.def += 100;
|
||||
@ -118,6 +121,8 @@ data.prototype.init = function() {
|
||||
"bluePotion": 250, // 蓝血瓶加血数值
|
||||
"yellowPotion": 500, // 黄血瓶加血数值
|
||||
"greenPotion": 800, // 绿血瓶加血数值
|
||||
"sword0": 0, // 默认装备折断的剑的攻击力
|
||||
"shield0": 0, // 默认装备残破的盾的防御力
|
||||
"sword1": 10, // 铁剑加攻数值
|
||||
"shield1": 10, // 铁盾加防数值
|
||||
"sword2": 20, // 银剑加攻数值
|
||||
@ -153,19 +158,21 @@ data.prototype.init = function() {
|
||||
"pickaxeFourDirections": true, // 使用破墙镐是否四个方向都破坏;如果false则只破坏面前的墙壁
|
||||
"bombFourDirections": true, // 使用炸弹是否四个方向都会炸;如果false则只炸面前的怪物(即和圣锤等价)
|
||||
"bigKeyIsBox": false, // 如果此项为true,则视为钥匙盒,红黄蓝钥匙+1;若为false,则视为大黄门钥匙
|
||||
"equipment": false, // 剑和盾是否直接作为装备。如果此项为true,则作为装备,需要在道具栏使用,否则将直接加属性。
|
||||
/****** 怪物相关 ******/
|
||||
"enableNegativeDamage": true, // 是否支持负伤害(回血)
|
||||
"zoneSquare": false, // 领域类型。如果此项为true则为九宫格伤害,为false则为十字伤害
|
||||
"hatredDecrease": true, // 是否在和仇恨怪战斗后减一半的仇恨值,此项为false则和仇恨怪不会扣减仇恨值。
|
||||
"betweenAttackCeil": false, // 夹击方式是向上取整还是向下取整。如果此项为true则为向上取整,为false则为向下取整
|
||||
/****** 系统相关 ******/
|
||||
"startDirectly": false, // 点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面
|
||||
"canOpenBattleAnimate": true, // 是否允许用户开启战斗过程;如果此项为false,则下面两项均强制视为false
|
||||
"showBattleAnimateConfirm": true, // 是否在游戏开始时提供“是否开启战斗动画”的选项
|
||||
"battleAnimate": true, // 是否默认显示战斗动画;用户可以手动在菜单栏中开关
|
||||
"displayEnemyDamage": true, // 是否地图怪物显伤;用户可以手动在菜单栏中开关
|
||||
"displayExtraDamage": false, // 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关
|
||||
"displayExtraDamage": true, // 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关
|
||||
"enableGentleClick": true, // 是否允许轻触(获得面前物品)
|
||||
"portalWithoutTrigger": true, // 经过楼梯、传送门时是否能“穿透”。穿透的意思是,自动寻路得到的的路径中间经过了楼梯,行走时是否触发楼层转换事件
|
||||
"potionWhileRouting": false, // 寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶
|
||||
"enableViewMaps": true, // 是否支持在菜单栏中查看所有楼层的地图
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
108
libs/enemys.js
@ -21,11 +21,11 @@ enemys.prototype.init = function () {
|
||||
'zombie': {'name': '兽人', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'zombieKnight': {'name': '兽人武士', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'rock': {'name': '石头人', 'hp': 100, 'atk': 120, 'def': 0, 'money': 4, 'experience': 0, 'special': 3},
|
||||
'slimeMan': {'name': '影子战士', 'hp': 100, 'atk': 0, 'def': 0, 'money': 11, 'experience': 0, 'special': 10}, // 模仿怪的攻防设为0就好
|
||||
'slimeMan': {'name': '影子战士', 'hp': 100, 'atk': 0, 'def': 0, 'money': 11, 'experience': 0, 'special': [10,21], 'atkValue': 2, 'defValue': 3}, // 退化怪可以在后面写atkValue和defValue表示退化的数值
|
||||
'bluePriest': {'name': '初级法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 3, 'experience': 0, 'special': 2, 'point': 1}, // 'point'可以在打败怪物后进行加点,详见文档说明。
|
||||
'redPriest': {'name': '高级法师', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'brownWizard': {'name': '初级巫师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 16, 'experience': 0, 'special': 15, 'value': 100, 'zoneSquare': true}, // 领域怪需要加value表示领域伤害的数值;zoneSquare代表是否九宫格伤害
|
||||
'redWizard': {'name': '高级巫师', 'hp': 1000, 'atk': 1200, 'def': 0, 'money': 160, 'experience': 0, 'special': 15, 'value': 200, 'range': 2}, // range可选,代表领域伤害的范围;不加默认为1
|
||||
'brownWizard': {'name': '初级巫师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 16, 'experience': 0, 'special': 15, 'value': 100, 'range': 2}, // 领域怪需要加value表示领域伤害的数值;range可选,代表领域伤害的范围;不加默认为1
|
||||
'redWizard': {'name': '高级巫师', 'hp': 1000, 'atk': 1200, 'def': 0, 'money': 160, 'experience': 0, 'special': 15, 'value': 200, 'zoneSquare': true}, // zoneSquare可选,代表是否九宫格伤害,true为是九宫格伤害,false或不设置为十字伤害
|
||||
'yellowGuard': {'name': '初级卫兵', 'hp': 100, 'atk': 120, 'def': 0, 'money': 10, 'experience': 0, 'special': 0},
|
||||
'blueGuard': {'name': '中级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'redGuard': {'name': '高级卫兵', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
@ -52,7 +52,7 @@ enemys.prototype.init = function () {
|
||||
'goldHornSlime': {'name': '金角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'redKing': {'name': '红衣魔王', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'whiteKing': {'name': '白衣武士', 'hp': 100, 'atk': 120, 'def': 0, 'money': 17, 'experience': 0, 'special': 16},
|
||||
'blackMagician': {'name': '黑暗大法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 12, 'experience': 0, 'special': 11, 'value': 1/3, 'bomb': false}, // 吸血怪需要在后面添加value代表吸血比例
|
||||
'blackMagician': {'name': '黑暗大法师', 'hp': 100, 'atk': 120, 'def': 0, 'money': 12, 'experience': 0, 'special': 11, 'value': 1/3, 'add': true, 'bomb': false}, // 吸血怪需要在后面添加value代表吸血比例;添加add: true可以将吸血的伤害加到自身
|
||||
'silverSlime': {'name': '银头怪', 'hp': 100, 'atk': 120, 'def': 0, 'money': 15, 'experience': 0, 'special': 14},
|
||||
'swordEmperor': {'name': '剑圣', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
'whiteHornSlime': {'name': '尖角怪', 'hp': 0, 'atk': 0, 'def': 0, 'money': 0, 'experience': 0, 'special': 0},
|
||||
@ -79,7 +79,16 @@ enemys.prototype.getEnemys = function (enemyId) {
|
||||
|
||||
////// 判断是否含有某特殊属性 //////
|
||||
enemys.prototype.hasSpecial = function (special, test) {
|
||||
return (special instanceof Array)?special.indexOf(test)>=0:(special!=0&&(special%100==test||this.hasSpecial(parseInt(special/100), test)));
|
||||
|
||||
if (special instanceof Array) {
|
||||
return special.indexOf(test)>=0;
|
||||
}
|
||||
|
||||
if (typeof special == 'number') {
|
||||
return special!=0 && (special%100==test||this.hasSpecial(parseInt(special/100), test));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
////// 获得所有特殊属性的名称 //////
|
||||
@ -108,6 +117,7 @@ enemys.prototype.getSpecialText = function (enemyId) {
|
||||
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("退化");
|
||||
return text;
|
||||
}
|
||||
|
||||
@ -136,16 +146,17 @@ enemys.prototype.getSpecialHint = function (enemy, special) {
|
||||
case 8: return "反击:战斗时,怪物每回合附加角色攻击的"+parseInt(100*core.values.counterAttack)+"%作为伤害,无视角色防御";
|
||||
case 9: return "净化:战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害";
|
||||
case 10: return "模仿:怪物的攻防和勇士攻防相等";
|
||||
case 11: return "吸血:战斗前,怪物首先吸取角色的"+parseInt(100*enemy.value)+"%生命作为伤害";
|
||||
case 11: return "吸血:战斗前,怪物首先吸取角色的"+parseInt(100*enemy.value)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");
|
||||
case 12: return "中毒:战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点";
|
||||
case 13: return "衰弱:战斗后,勇士陷入衰弱状态,攻防暂时下降"+core.values.weakValue+"点";
|
||||
case 14: return "诅咒:战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验";
|
||||
case 15: return "领域:经过怪物周围"+(enemy.range||1)+"格时自动减生命"+enemy.value+"点";
|
||||
case 16: return "夹击:经过两只相同的怪物中间,勇士生命值变成一半";
|
||||
case 17: return "仇恨:战斗前,怪物附加之前积累的仇恨值作为伤害;战斗后,释放一半的仇恨值。(每杀死一个怪物获得"+core.values.hatred+"点仇恨值)";
|
||||
case 17: return "仇恨:战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+core.values.hatred+"点仇恨值)";
|
||||
case 18: return "阻击:经过怪物的十字领域时自动减生命"+enemy.value+"点,同时怪物后退一格";
|
||||
case 19: return "自爆:战斗后勇士的生命值变成1";
|
||||
case 20: return "无敌:勇士无法打败怪物,除非拥有十字架";
|
||||
case 21: return "退化:战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";
|
||||
default: break;
|
||||
}
|
||||
return ""
|
||||
@ -154,21 +165,14 @@ enemys.prototype.getSpecialHint = function (enemy, special) {
|
||||
////// 获得某个怪物的伤害 //////
|
||||
enemys.prototype.getDamage = function (monsterId) {
|
||||
var monster = core.material.enemys[monsterId];
|
||||
var hero_atk = core.status.hero.atk, hero_def = core.status.hero.def, hero_mdef = core.status.hero.mdef;
|
||||
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special;
|
||||
var damage = this.calDamage(hero_atk, hero_def, hero_mdef, mon_hp, mon_atk, mon_def, mon_special, monster.n);
|
||||
if (damage == 999999999) return damage;
|
||||
var damage = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
|
||||
if (damage >= 999999999) return damage;
|
||||
return damage + this.getExtraDamage(monster);
|
||||
}
|
||||
|
||||
////// 获得某个怪物的额外伤害 //////
|
||||
enemys.prototype.getExtraDamage = function (monster) {
|
||||
var extra_damage = 0;
|
||||
if (this.hasSpecial(monster.special, 11)) { // 吸血
|
||||
// 吸血的比例
|
||||
extra_damage = core.status.hero.hp * monster.value;
|
||||
extra_damage = parseInt(extra_damage);
|
||||
}
|
||||
if (this.hasSpecial(monster.special, 17)) { // 仇恨
|
||||
extra_damage += core.getFlag('hatred', 0);
|
||||
}
|
||||
@ -178,14 +182,15 @@ enemys.prototype.getExtraDamage = function (monster) {
|
||||
////// 临界值计算 //////
|
||||
enemys.prototype.getCritical = function (monsterId) {
|
||||
var monster = core.material.enemys[monsterId];
|
||||
// 坚固、模仿怪物没有临界!
|
||||
if (this.hasSpecial(monster.special, 3) || this.hasSpecial(monster.special, 10)) return "???";
|
||||
var last = this.calDamage(core.status.hero.atk, core.status.hero.def, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
|
||||
var last = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
|
||||
|
||||
if (last <= 0) return 0;
|
||||
|
||||
for (var i = core.status.hero.atk + 1; i <= monster.hp + monster.def; i++) {
|
||||
var damage = this.calDamage(i, core.status.hero.def, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
var damage = this.calDamage(monster, core.status.hero.hp, i, core.status.hero.def, core.status.hero.mdef);
|
||||
if (damage < last)
|
||||
return i - core.status.hero.atk;
|
||||
last = damage;
|
||||
@ -199,31 +204,45 @@ enemys.prototype.getCriticalDamage = function (monsterId) {
|
||||
if (c == '???') return '???';
|
||||
if (c <= 0) return 0;
|
||||
var monster = core.material.enemys[monsterId];
|
||||
var last = this.calDamage(core.status.hero.atk, core.status.hero.def, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
if (last == 999999999) return '???';
|
||||
var last = this.calDamage(monster, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef);
|
||||
if (last >= 999999999) return '???';
|
||||
|
||||
return last - this.calDamage(core.status.hero.atk + c, core.status.hero.def, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
return last - this.calDamage(monster, core.status.hero.hp, core.status.hero.atk + c, core.status.hero.def, core.status.hero.mdef);
|
||||
}
|
||||
|
||||
////// 1防减伤计算 //////
|
||||
enemys.prototype.getDefDamage = function (monsterId) {
|
||||
var monster = core.material.enemys[monsterId];
|
||||
var nowDamage = this.calDamage(core.status.hero.atk, core.status.hero.def, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
var nextDamage = this.calDamage(core.status.hero.atk, core.status.hero.def + 1, core.status.hero.mdef,
|
||||
monster.hp, monster.atk, monster.def, monster.special, monster.n);
|
||||
if (nowDamage == 999999999 || nextDamage == 999999999) return "???";
|
||||
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 + 1, core.status.hero.mdef);
|
||||
if (nowDamage >= 999999999 || nextDamage >= 999999999) return "???";
|
||||
return nowDamage - nextDamage;
|
||||
}
|
||||
|
||||
////// 具体的伤害计算公式 //////
|
||||
enemys.prototype.calDamage = function (hero_atk, hero_def, hero_mdef, mon_hp, mon_atk, mon_def, mon_special, n) {
|
||||
enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) {
|
||||
|
||||
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_special = monster.special;
|
||||
|
||||
if (this.hasSpecial(mon_special, 20) && !core.hasItem("cross")) // 如果是无敌属性,且勇士未持有十字架
|
||||
return 999999999; // 返回无限大
|
||||
|
||||
var initDamage = 0; // 战前伤害
|
||||
|
||||
// 吸血
|
||||
if (this.hasSpecial(mon_special, 11)) {
|
||||
var vampireDamage = hero_hp * monster.value;
|
||||
|
||||
// 如果有神圣盾免疫吸血等可以在这里写
|
||||
|
||||
vampireDamage = parseInt(vampireDamage);
|
||||
// 加到自身
|
||||
if (monster.add) // 如果加到自身
|
||||
mon_hp += vampireDamage;
|
||||
|
||||
initDamage += vampireDamage;
|
||||
}
|
||||
|
||||
// 模仿
|
||||
if (this.hasSpecial(mon_special,10)) {
|
||||
mon_atk = hero_atk;
|
||||
@ -237,28 +256,36 @@ enemys.prototype.calDamage = function (hero_atk, hero_def, hero_mdef, mon_hp, mo
|
||||
|
||||
var per_damage = mon_atk - hero_def;
|
||||
if (per_damage < 0) per_damage = 0;
|
||||
// 2连击 & 3连击
|
||||
|
||||
// 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 *= (n||4);
|
||||
if (this.hasSpecial(mon_special, 6)) per_damage *= (monster.n||4);
|
||||
|
||||
var counterDamage = 0;
|
||||
// 反击
|
||||
if (this.hasSpecial(mon_special, 8)) counterDamage += parseInt(core.values.counterAttack * hero_atk);
|
||||
|
||||
// 先攻
|
||||
var damage = mon_special == 1 ? per_damage : 0;
|
||||
if (this.hasSpecial(mon_special, 1))
|
||||
initDamage += per_damage;
|
||||
|
||||
// 破甲
|
||||
if (this.hasSpecial(mon_special, 7)) damage += parseInt(core.values.breakArmor * hero_def);
|
||||
if (this.hasSpecial(mon_special, 7))
|
||||
initDamage += parseInt(core.values.breakArmor * hero_def);
|
||||
|
||||
// 净化
|
||||
if (this.hasSpecial(mon_special, 9)) damage = core.values.purify * hero_mdef;
|
||||
if (this.hasSpecial(mon_special, 9))
|
||||
initDamage += parseInt(core.values.purify * hero_mdef);
|
||||
|
||||
var turn = parseInt((mon_hp - 1) / (hero_atk - mon_def));
|
||||
var ans = damage + turn * per_damage + (turn + 1) * counterDamage;
|
||||
var ans = initDamage + turn * per_damage + (turn + 1) * counterDamage;
|
||||
ans -= hero_mdef;
|
||||
|
||||
return core.flags.enableNegativeDamage?ans:Math.max(0, ans);
|
||||
if (!core.flags.enableNegativeDamage)
|
||||
ans=Math.max(0, ans);
|
||||
|
||||
return ans;
|
||||
}
|
||||
|
||||
////// 获得当前楼层的怪物列表 //////
|
||||
@ -272,7 +299,7 @@ enemys.prototype.getCurrentEnemys = function () {
|
||||
if (core.isset(used[monsterId])) continue;
|
||||
|
||||
var monster = core.material.enemys[monsterId];
|
||||
var mon_atk = monster.atk, mon_def = monster.def;
|
||||
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def;
|
||||
// 坚固
|
||||
if (this.hasSpecial(monster.special, 3) && mon_def < core.status.hero.atk - 1)
|
||||
mon_def = core.status.hero.atk - 1;
|
||||
@ -288,11 +315,12 @@ enemys.prototype.getCurrentEnemys = function () {
|
||||
enemys.push({
|
||||
'id': monsterId,
|
||||
'name': monster.name,
|
||||
'hp': monster.hp,
|
||||
'hp': mon_hp,
|
||||
'atk': mon_atk,
|
||||
'def': mon_def,
|
||||
'money': monster.money,
|
||||
'experience': monster.experience,
|
||||
'point': monster.point||0, // 加点
|
||||
'special': specialText,
|
||||
'damage': this.getDamage(monsterId),
|
||||
'critical': this.getCritical(monsterId),
|
||||
|
||||
564
libs/events.js
@ -6,6 +6,7 @@ function events() {
|
||||
events.prototype.init = function () {
|
||||
this.events = {
|
||||
'battle': function (data, core, callback) {
|
||||
core.autosave(true);
|
||||
core.battle(data.event.id, data.x, data.y);
|
||||
if (core.isset(callback))
|
||||
callback();
|
||||
@ -16,9 +17,11 @@ events.prototype.init = function () {
|
||||
callback();
|
||||
},
|
||||
'openDoor': function (data, core, callback) {
|
||||
core.openDoor(data.event.id, data.x, data.y, true);
|
||||
if (core.isset(callback))
|
||||
callback();
|
||||
core.autosave(true);
|
||||
core.openDoor(data.event.id, data.x, data.y, true, function () {
|
||||
if (core.isset(callback)) callback();
|
||||
core.replay();
|
||||
});
|
||||
},
|
||||
'changeFloor': function (data, core, callback) {
|
||||
var heroLoc = {};
|
||||
@ -27,7 +30,10 @@ events.prototype.init = function () {
|
||||
if (core.isset(data.event.data.direction))
|
||||
heroLoc.direction = data.event.data.direction;
|
||||
core.changeFloor(data.event.data.floorId, data.event.data.stair,
|
||||
heroLoc, data.event.data.time, callback);
|
||||
heroLoc, data.event.data.time, function () {
|
||||
if (core.isset(callback)) callback();
|
||||
core.replay();
|
||||
});
|
||||
},
|
||||
'passNet': function (data, core, callback) {
|
||||
core.events.passNet(data);
|
||||
@ -107,44 +113,136 @@ events.prototype.setInitData = function (hard) {
|
||||
|
||||
////// 游戏获胜事件 //////
|
||||
events.prototype.win = function(reason) {
|
||||
core.ui.closePanel();
|
||||
var replaying = core.status.replay.replaying;
|
||||
core.status.replay.replaying=false;
|
||||
core.waitHeroToStop(function() {
|
||||
core.removeGlobalAnimate(0,0,true);
|
||||
core.clearMap('all'); // 清空全地图
|
||||
core.drawText([
|
||||
"\t[结局2]恭喜通关!你的分数是${status:hp}。"
|
||||
"\t[恭喜通关]你的分数是${status:hp}。"
|
||||
], function () {
|
||||
core.restart();
|
||||
core.events.gameOver(true, replaying);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
////// 游戏失败事件 //////
|
||||
events.prototype.lose = function(reason) {
|
||||
core.ui.closePanel();
|
||||
var replaying = core.status.replay.replaying;
|
||||
core.status.replay.replaying=false;
|
||||
core.waitHeroToStop(function() {
|
||||
core.status.replay.replaying=false;
|
||||
core.drawText([
|
||||
"\t[结局1]你死了。\n如题。"
|
||||
], function () {
|
||||
core.restart();
|
||||
core.events.gameOver(false, replaying);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
////// 游戏结束 //////
|
||||
events.prototype.gameOver = function (success, fromReplay) {
|
||||
|
||||
// 上传成绩
|
||||
var confirmUpload = function () {
|
||||
|
||||
if (!success) {
|
||||
core.restart();
|
||||
return;
|
||||
}
|
||||
|
||||
var doUpload = function(username) {
|
||||
if (username==null) username="";
|
||||
|
||||
// upload
|
||||
var formData = new FormData();
|
||||
formData.append('type', 'score');
|
||||
formData.append('name', core.firstData.name);
|
||||
formData.append('version', core.firstData.version);
|
||||
formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":"");
|
||||
formData.append('hard', core.status.hard);
|
||||
formData.append('username', username);
|
||||
formData.append('lv', core.status.hero.lv);
|
||||
formData.append('hp', core.status.hero.hp);
|
||||
formData.append('atk', core.status.hero.atk);
|
||||
formData.append('def', core.status.hero.def);
|
||||
formData.append('mdef', core.status.hero.mdef);
|
||||
formData.append('money', core.status.hero.money);
|
||||
formData.append('experience', core.status.hero.experience);
|
||||
formData.append('steps', core.status.hero.steps);
|
||||
formData.append('route', core.encodeRoute(core.status.route));
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/games/upload.php");
|
||||
xhr.send(formData);
|
||||
|
||||
core.restart();
|
||||
}
|
||||
|
||||
core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () {
|
||||
doUpload(prompt("请输入你的ID:"));
|
||||
}, function () {
|
||||
doUpload("");
|
||||
})
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// 下载录像
|
||||
var confirmDownload = function () {
|
||||
core.ui.closePanel();
|
||||
core.ui.drawConfirmBox("你想下载录像吗?", function () {
|
||||
var obj = {
|
||||
'name': core.firstData.name,
|
||||
'version': core.firstData.version,
|
||||
'hard': core.status.hard,
|
||||
'route': core.encodeRoute(core.status.route)
|
||||
}
|
||||
core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj));
|
||||
confirmUpload();
|
||||
}, function () {
|
||||
confirmUpload();
|
||||
})
|
||||
}
|
||||
|
||||
if (fromReplay) {
|
||||
core.drawText("录像回放完毕!", function () {
|
||||
core.restart();
|
||||
});
|
||||
}
|
||||
else {
|
||||
confirmDownload();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
////// 转换楼层结束的事件 //////
|
||||
events.prototype.afterChangeFloor = function (floorId) {
|
||||
if (!core.isset(core.status.event.id) && !core.hasFlag("visited_"+floorId)) {
|
||||
this.doEvents(core.floors[floorId].firstArrive);
|
||||
if (core.isset(core.status.event.id)) return; // 当前存在事件
|
||||
|
||||
if (!core.hasFlag("visited_"+floorId)) {
|
||||
this.doEvents(core.floors[floorId].firstArrive, null, null, function () {
|
||||
core.autosave();
|
||||
});
|
||||
core.setFlag("visited_"+floorId, true);
|
||||
return;
|
||||
}
|
||||
|
||||
// 自动存档
|
||||
core.autosave();
|
||||
}
|
||||
|
||||
////// 开始执行一系列自定义事件 //////
|
||||
events.prototype.doEvents = function (list, x, y, callback) {
|
||||
if (!core.isset(list)) return;
|
||||
if (!(list instanceof Array)) {
|
||||
list = [list];
|
||||
}
|
||||
|
||||
// 停止勇士
|
||||
core.waitHeroToStop(function() {
|
||||
if (!core.isset(list)) return;
|
||||
if (!(list instanceof Array)) {
|
||||
list = [list];
|
||||
}
|
||||
core.lockControl();
|
||||
core.status.event = {'id': 'action', 'data': {
|
||||
'list': core.clone(list), 'x': x, 'y': y, 'callback': callback
|
||||
@ -165,6 +263,7 @@ events.prototype.doAction = function() {
|
||||
if (core.isset(core.status.event.data.callback))
|
||||
core.status.event.data.callback();
|
||||
core.ui.closePanel();
|
||||
core.replay();
|
||||
return;
|
||||
}
|
||||
|
||||
@ -178,13 +277,20 @@ events.prototype.doAction = function() {
|
||||
// 如果是文字:显示
|
||||
if (typeof data == "string") {
|
||||
core.status.event.data.type='text';
|
||||
core.ui.drawTextBox(data);
|
||||
// 如果是正在回放中,不显示
|
||||
if (core.status.replay.replaying)
|
||||
core.events.doAction();
|
||||
else
|
||||
core.ui.drawTextBox(data);
|
||||
return;
|
||||
}
|
||||
core.status.event.data.type=data.type;
|
||||
switch (data.type) {
|
||||
case "text": // 文字/对话
|
||||
core.ui.drawTextBox(data.data);
|
||||
if (core.status.replay.isreplaying)
|
||||
core.events.doAction();
|
||||
else
|
||||
core.ui.drawTextBox(data.data);
|
||||
break;
|
||||
case "tip":
|
||||
core.drawTip(core.replaceText(data.text));
|
||||
@ -270,7 +376,12 @@ events.prototype.doAction = function() {
|
||||
this.doAction();
|
||||
break;
|
||||
case "openShop": // 打开一个全局商店
|
||||
core.events.openShop(data.id);
|
||||
if (core.status.replay.replaying) { // 正在播放录像,简单将visited置为true
|
||||
core.status.shops[data.id].visited=true;
|
||||
this.doAction();
|
||||
}
|
||||
else
|
||||
core.events.openShop(data.id);
|
||||
break;
|
||||
case "disableShop": // 禁用一个全局商店
|
||||
core.events.disableQuickShop(data.id);
|
||||
@ -351,13 +462,41 @@ events.prototype.doAction = function() {
|
||||
this.doAction();
|
||||
break;
|
||||
case "choices": // 提供选项
|
||||
if (core.status.replay.replaying) {
|
||||
if (core.status.replay.toReplay.length==0) { // 回放完毕
|
||||
core.status.replay.replaying=false;
|
||||
core.drawTip("录像回放完毕");
|
||||
}
|
||||
else {
|
||||
var action = core.status.replay.toReplay.shift(), index;
|
||||
if (action.indexOf("choices:")==0 && ((index=parseInt(action.substring(8)))>=0) && index<data.choices.length) {
|
||||
//core.status.route.push("choices:"+index);
|
||||
//this.insertAction(data.choices[index].action);
|
||||
//this.doAction();
|
||||
core.status.event.selection=index;
|
||||
setTimeout(function () {
|
||||
core.status.route.push("choices:"+index);
|
||||
core.events.insertAction(data.choices[index].action);
|
||||
core.events.doAction();
|
||||
}, 500)
|
||||
}
|
||||
else {
|
||||
core.status.replay.replaying=false;
|
||||
core.drawTip("录像文件出错");
|
||||
}
|
||||
}
|
||||
}
|
||||
core.ui.drawChoices(data.text, data.choices);
|
||||
break;
|
||||
case "win":
|
||||
core.events.win(data.reason);
|
||||
core.events.win(data.reason, function () {
|
||||
core.events.doAction();
|
||||
});
|
||||
break;
|
||||
case "lose":
|
||||
core.events.lose(data.reason);
|
||||
core.events.lose(data.reason, function () {
|
||||
core.events.doAction();
|
||||
});
|
||||
break;
|
||||
case "function":
|
||||
var func = data["function"];
|
||||
@ -401,12 +540,15 @@ events.prototype.doAction = function() {
|
||||
}
|
||||
|
||||
////// 往当前事件列表之前添加一个或多个事件 //////
|
||||
events.prototype.insertAction = function (action) {
|
||||
events.prototype.insertAction = function (action, x, y, callback) {
|
||||
if (core.status.event.id == null) {
|
||||
this.doEvents(action);
|
||||
this.doEvents(action, x, y, callback);
|
||||
}
|
||||
else {
|
||||
core.unshift(core.status.event.data.list, action)
|
||||
if (core.isset(x)) core.status.event.data.x=x;
|
||||
if (core.isset(y)) core.status.event.data.y=y;
|
||||
if (core.isset(callback)) core.status.event.data.callback=callback;
|
||||
}
|
||||
}
|
||||
|
||||
@ -423,11 +565,15 @@ events.prototype.openShop = function(shopId, needVisited) {
|
||||
shop.visited = true;
|
||||
|
||||
var selection = core.status.event.selection;
|
||||
var actions = [];
|
||||
if (core.isset(core.status.event.data) && core.isset(core.status.event.data.actions))
|
||||
actions=core.status.event.data.actions;
|
||||
|
||||
core.ui.closePanel();
|
||||
core.lockControl();
|
||||
// core.status.event = {'id': 'shop', 'data': {'id': shopId, 'shop': shop}};
|
||||
core.status.event.id = 'shop';
|
||||
core.status.event.data = {'id': shopId, 'shop': shop};
|
||||
core.status.event.data = {'id': shopId, 'shop': shop, 'actions': actions};
|
||||
core.status.event.selection = selection;
|
||||
|
||||
// 拼词
|
||||
@ -458,7 +604,7 @@ events.prototype.disableQuickShop = function (shopId) {
|
||||
}
|
||||
|
||||
////// 能否使用快捷商店 //////
|
||||
events.prototype.canUseQuickShop = function(shopIndex) {
|
||||
events.prototype.canUseQuickShop = function(shopId) {
|
||||
if (core.isset(core.floors[core.status.floorId].canUseQuickShop) && !core.isset(core.floors[core.status.floorId].canUseQuickShop))
|
||||
return '当前不能使用快捷商店。';
|
||||
|
||||
@ -543,8 +689,10 @@ events.prototype.addPoint = function (enemy) {
|
||||
////// 战斗结束后触发的事件 //////
|
||||
events.prototype.afterBattle = function(enemyId,x,y,callback) {
|
||||
|
||||
var enemy = core.material.enemys[enemyId];
|
||||
|
||||
// 毒衰咒的处理
|
||||
var special = core.material.enemys[enemyId].special;
|
||||
var special = enemy.special;
|
||||
// 中毒
|
||||
if (core.enemys.hasSpecial(special, 12) && !core.hasFlag('poison')) {
|
||||
core.setFlag('poison', true);
|
||||
@ -560,13 +708,20 @@ events.prototype.afterBattle = function(enemyId,x,y,callback) {
|
||||
core.setFlag('curse', true);
|
||||
}
|
||||
// 仇恨属性:减半
|
||||
if (core.enemys.hasSpecial(special, 17)) {
|
||||
if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) {
|
||||
core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2));
|
||||
}
|
||||
// 自爆
|
||||
if (core.enemys.hasSpecial(special, 19)) {
|
||||
core.status.hero.hp = 1;
|
||||
}
|
||||
// 退化
|
||||
if (core.enemys.hasSpecial(special, 21)) {
|
||||
core.status.hero.atk -= (enemy.atkValue||0);
|
||||
core.status.hero.def -= (enemy.defValue||0);
|
||||
if (core.status.hero.atk<0) core.status.hero.atk=0;
|
||||
if (core.status.hero.def<0) core.status.hero.def=0;
|
||||
}
|
||||
// 增加仇恨值
|
||||
core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred);
|
||||
core.updateStatusBar();
|
||||
@ -678,6 +833,16 @@ events.prototype.afterChangeLight = function(x,y) {
|
||||
////// 使用炸弹/圣锤后的事件 //////
|
||||
events.prototype.afterUseBomb = function () {
|
||||
|
||||
// 这是一个使用炸弹也能开门的例子
|
||||
/*
|
||||
if (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在
|
||||
&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在
|
||||
{
|
||||
core.insertAction([ // 插入事件
|
||||
{"type": "openDoor", "loc": [x0,y0]} // 开门
|
||||
])
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
@ -696,6 +861,14 @@ events.prototype.afterLoadData = function(data) {
|
||||
/********** 点击事件、键盘事件 ************/
|
||||
/****************************************/
|
||||
|
||||
////// 长按 //////
|
||||
events.prototype.longClick = function () {
|
||||
core.waitHeroToStop(function () {
|
||||
// 绘制快捷键
|
||||
core.ui.drawKeyBoard();
|
||||
});
|
||||
}
|
||||
|
||||
////// 按下Ctrl键时(快捷跳过对话) //////
|
||||
events.prototype.keyDownCtrl = function () {
|
||||
if (core.status.event.id=='text') {
|
||||
@ -756,6 +929,8 @@ events.prototype.clickAction = function (x,y) {
|
||||
if (x >= 5 && x <= 7) {
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
if (y>=topIndex && y<topIndex+choices.length) {
|
||||
// 选择
|
||||
core.status.route.push("choices:"+(y-topIndex));
|
||||
this.insertAction(choices[y-topIndex].action);
|
||||
this.doAction();
|
||||
}
|
||||
@ -771,12 +946,10 @@ events.prototype.keyDownAction = function (keycode) {
|
||||
if (choices.length>0) {
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -794,6 +967,7 @@ events.prototype.keyUpAction = function (keycode) {
|
||||
var choices = data.choices;
|
||||
if (choices.length>0) {
|
||||
if (keycode==13 || keycode==32 || keycode==67) {
|
||||
core.status.route.push("choices:"+core.status.event.selection);
|
||||
this.insertAction(choices[core.status.event.selection].action);
|
||||
this.doAction();
|
||||
}
|
||||
@ -870,6 +1044,7 @@ events.prototype.clickFly = function(x,y) {
|
||||
var index=core.status.hero.flyRange.indexOf(core.status.floorId);
|
||||
var stair=core.status.event.data<index?"upFloor":"downFloor";
|
||||
var floorId=core.status.event.data;
|
||||
core.status.route.push("fly:"+core.status.hero.flyRange[floorId]);
|
||||
core.changeFloor(core.status.hero.flyRange[floorId], stair);
|
||||
core.ui.closePanel();
|
||||
}
|
||||
@ -892,6 +1067,38 @@ events.prototype.keyUpFly = function (keycode) {
|
||||
return;
|
||||
}
|
||||
|
||||
////// 查看地图界面时的点击操作 //////
|
||||
events.prototype.clickViewMaps = function (x,y) {
|
||||
if(y<=4) {
|
||||
core.ui.drawMaps(core.status.event.data+1);
|
||||
}
|
||||
else if (y>=8) {
|
||||
core.ui.drawMaps(core.status.event.data-1);
|
||||
}
|
||||
else {
|
||||
core.clearMap('data', 0, 0, 416, 416);
|
||||
core.setOpacity('data', 1);
|
||||
core.ui.closePanel();
|
||||
}
|
||||
}
|
||||
|
||||
////// 查看地图界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownViewMaps = function (keycode) {
|
||||
if (keycode==37 || keycode==38) core.ui.drawMaps(core.status.event.data+1);
|
||||
else if (keycode==39 || keycode==40) core.ui.drawMaps(core.status.event.data-1);
|
||||
return;
|
||||
}
|
||||
|
||||
////// 查看地图界面时,放开某个键的操作 //////
|
||||
events.prototype.keyUpViewMaps = function (keycode) {
|
||||
if (keycode==27 || keycode==88 || keycode==13 || keycode==32 || keycode==67) {
|
||||
core.clearMap('data', 0, 0, 416, 416);
|
||||
core.setOpacity('data', 1);
|
||||
core.ui.closePanel();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
////// 商店界面时的点击操作 //////
|
||||
events.prototype.clickShop = function(x,y) {
|
||||
var shop = core.status.event.data.shop;
|
||||
@ -899,6 +1106,9 @@ events.prototype.clickShop = function(x,y) {
|
||||
if (x >= 5 && x <= 7) {
|
||||
var topIndex = 6 - parseInt(choices.length / 2);
|
||||
if (y>=topIndex && y<topIndex+choices.length) {
|
||||
|
||||
core.status.event.selection=y-topIndex;
|
||||
|
||||
//this.insertAction(choices[y-topIndex].action);
|
||||
//this.doAction();
|
||||
var money = core.getStatus('money'), experience = core.getStatus('experience');
|
||||
@ -912,11 +1122,12 @@ events.prototype.clickShop = function(x,y) {
|
||||
|
||||
if (need > eval(use)) {
|
||||
core.drawTip("你的"+use_text+"不足");
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
eval(use+'-='+need);
|
||||
core.status.event.data.actions.push(y-topIndex);
|
||||
|
||||
eval(use+'-='+need);
|
||||
core.setStatus('money', money);
|
||||
core.setStatus('experience', experience);
|
||||
|
||||
@ -930,27 +1141,29 @@ events.prototype.clickShop = function(x,y) {
|
||||
}
|
||||
// 离开
|
||||
else if (y==topIndex+choices.length) {
|
||||
if (core.status.event.data.actions.length>0) {
|
||||
core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join(""));
|
||||
}
|
||||
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.setBoxAnimate();
|
||||
if (core.status.event.data.fromList)
|
||||
core.ui.drawQuickShop();
|
||||
else core.ui.closePanel();
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
////// 商店界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownShop = function (keycode) {
|
||||
var shop = core.status.event.data.shop;
|
||||
var choices = shop.choices;
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>choices.length) core.status.event.selection=choices.length;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -982,7 +1195,7 @@ events.prototype.clickQuickShop = function(x, y) {
|
||||
if (x >= 5 && x <= 7) {
|
||||
var topIndex = 6 - parseInt(keys.length / 2);
|
||||
if (y>=topIndex && y<topIndex+keys.length) {
|
||||
var reason = core.events.canUseQuickShop(y-topIndex);
|
||||
var reason = core.events.canUseQuickShop(keys[y - topIndex]);
|
||||
if (core.isset(reason)) {
|
||||
core.drawText(reason);
|
||||
return;
|
||||
@ -999,15 +1212,12 @@ events.prototype.clickQuickShop = function(x, y) {
|
||||
|
||||
////// 快捷商店界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownQuickShop = function (keycode) {
|
||||
var shopList = core.status.shops, keys = Object.keys(shopList);
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>keys.length) core.status.event.selection=keys.length;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -1141,13 +1351,17 @@ events.prototype.keyUpToolbox = function (keycode) {
|
||||
|
||||
////// 存读档界面时的点击操作 //////
|
||||
events.prototype.clickSL = function(x,y) {
|
||||
|
||||
var index=core.status.event.data;
|
||||
var page = parseInt(index/10), offset=index%10;
|
||||
|
||||
// 上一页
|
||||
if ((x == 3 || x == 4) && y == 12) {
|
||||
core.ui.drawSLPanel(core.status.event.data - 6);
|
||||
core.ui.drawSLPanel(10*(page-1)+offset);
|
||||
}
|
||||
// 下一页
|
||||
if ((x == 8 || x == 9) && y == 12) {
|
||||
core.ui.drawSLPanel(core.status.event.data + 6);
|
||||
core.ui.drawSLPanel(10*(page+1)+offset);
|
||||
}
|
||||
// 返回
|
||||
if (x>=10 && x<=12 && y==12) {
|
||||
@ -1158,50 +1372,77 @@ events.prototype.clickSL = function(x,y) {
|
||||
return;
|
||||
}
|
||||
|
||||
var page=parseInt((core.status.event.data-1)/6);
|
||||
var index=6*page+1;
|
||||
if (y>=1 && y<=4) {
|
||||
if (x>=1 && x<=3) core.doSL(index, core.status.event.id);
|
||||
if (x>=5 && x<=7) core.doSL(index+1, core.status.event.id);
|
||||
if (x>=9 && x<=11) core.doSL(index+2, core.status.event.id);
|
||||
if (x>=1 && x<=3) core.doSL("autoSave", core.status.event.id);
|
||||
if (x>=5 && x<=7) core.doSL(5*page+1, core.status.event.id);
|
||||
if (x>=9 && x<=11) core.doSL(5*page+2, core.status.event.id);
|
||||
}
|
||||
if (y>=7 && y<=10) {
|
||||
if (x>=1 && x<=3) core.doSL(index+3, core.status.event.id);
|
||||
if (x>=5 && x<=7) core.doSL(index+4, core.status.event.id);
|
||||
if (x>=9 && x<=11) core.doSL(index+5, core.status.event.id);
|
||||
if (x>=1 && x<=3) core.doSL(5*page+3, core.status.event.id);
|
||||
if (x>=5 && x<=7) core.doSL(5*page+4, core.status.event.id);
|
||||
if (x>=9 && x<=11) core.doSL(5*page+5, core.status.event.id);
|
||||
}
|
||||
}
|
||||
|
||||
////// 存读档界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownSL = function(keycode) {
|
||||
|
||||
var index=core.status.event.data;
|
||||
var page = parseInt(index/10), offset=index%10;
|
||||
|
||||
if (keycode==37) { // left
|
||||
core.ui.drawSLPanel(core.status.event.data - 1);
|
||||
if (offset==0) {
|
||||
core.ui.drawSLPanel(10*(page-1) + 5);
|
||||
}
|
||||
else {
|
||||
core.ui.drawSLPanel(index - 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (keycode==38) { // up
|
||||
core.ui.drawSLPanel(core.status.event.data - 3);
|
||||
if (offset<3) {
|
||||
core.ui.drawSLPanel(10*(page-1) + offset + 3);
|
||||
}
|
||||
else {
|
||||
core.ui.drawSLPanel(index - 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (keycode==39) { // right
|
||||
core.ui.drawSLPanel(core.status.event.data + 1);
|
||||
if (offset==5) {
|
||||
core.ui.drawSLPanel(10*(page+1)+1);
|
||||
}
|
||||
else {
|
||||
core.ui.drawSLPanel(index + 1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (keycode==40) { // down
|
||||
core.ui.drawSLPanel(core.status.event.data + 3);
|
||||
if (offset>=3) {
|
||||
core.ui.drawSLPanel(10*(page+1) + offset - 3);
|
||||
}
|
||||
else {
|
||||
core.ui.drawSLPanel(index + 3);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (keycode==33) { // PAGEUP
|
||||
core.ui.drawSLPanel(core.status.event.data - 6);
|
||||
core.ui.drawSLPanel(10*(page-1) + offset);
|
||||
return;
|
||||
}
|
||||
if (keycode==34) { // PAGEDOWN
|
||||
core.ui.drawSLPanel(core.status.event.data + 6);
|
||||
core.ui.drawSLPanel(10*(page+1) + offset);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
////// 存读档界面时,放开某个键的操作 //////
|
||||
events.prototype.keyUpSL = function (keycode) {
|
||||
|
||||
var index=core.status.event.data;
|
||||
var page = parseInt(index/10), offset=index%10;
|
||||
|
||||
if (keycode==27 || keycode==88 || (core.status.event.id == 'save' && keycode==83) || (core.status.event.id == 'load' && keycode==68)) {
|
||||
core.ui.closePanel();
|
||||
if (!core.isPlaying()) {
|
||||
@ -1210,7 +1451,12 @@ events.prototype.keyUpSL = function (keycode) {
|
||||
return;
|
||||
}
|
||||
if (keycode==13 || keycode==32 || keycode==67) {
|
||||
core.doSL(core.status.event.data, core.status.event.id);
|
||||
if (offset==0) {
|
||||
core.doSL("autoSave", core.status.event.id);
|
||||
}
|
||||
else {
|
||||
core.doSL(5*page+offset, core.status.event.id);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -1219,7 +1465,7 @@ events.prototype.keyUpSL = function (keycode) {
|
||||
events.prototype.clickSwitchs = function (x,y) {
|
||||
if (x<5 || x>7) return;
|
||||
var choices = [
|
||||
"背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "返回主菜单"
|
||||
"背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "下载离线版本", "返回主菜单"
|
||||
];
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
if (y>=topIndex && y<topIndex+choices.length) {
|
||||
@ -1262,8 +1508,11 @@ events.prototype.clickSwitchs = function (x,y) {
|
||||
core.ui.drawSwitchs();
|
||||
break;
|
||||
case 5:
|
||||
window.open(core.firstData.name+".zip", "_blank");
|
||||
break;
|
||||
case 6:
|
||||
core.status.event.selection=0;
|
||||
core.ui.drawSettings(false);
|
||||
core.ui.drawSettings();
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1271,17 +1520,12 @@ events.prototype.clickSwitchs = function (x,y) {
|
||||
|
||||
////// 系统设置界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownSwitchs = function (keycode) {
|
||||
var choices = [
|
||||
"背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "返回主菜单"
|
||||
];
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -1290,11 +1534,11 @@ events.prototype.keyDownSwitchs = function (keycode) {
|
||||
events.prototype.keyUpSwitchs = function (keycode) {
|
||||
if (keycode==27 || keycode==88) {
|
||||
core.status.event.selection=0;
|
||||
core.ui.drawSettings(false);
|
||||
core.ui.drawSettings();
|
||||
return;
|
||||
}
|
||||
var choices = [
|
||||
"背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "返回主菜单"
|
||||
"背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "下载离线版本", "返回主菜单"
|
||||
];
|
||||
if (keycode==13 || keycode==32 || keycode==67) {
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
@ -1307,7 +1551,7 @@ events.prototype.keyUpSwitchs = function (keycode) {
|
||||
events.prototype.clickSettings = function (x,y) {
|
||||
if (x<5 || x>7) return;
|
||||
var choices = [
|
||||
"系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏"
|
||||
"系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏"
|
||||
];
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
if (y>=topIndex && y<topIndex+choices.length) {
|
||||
@ -1323,26 +1567,80 @@ events.prototype.clickSettings = function (x,y) {
|
||||
core.ui.drawQuickShop();
|
||||
break;
|
||||
case 2:
|
||||
if (!core.flags.enableViewMaps) {
|
||||
core.drawTip("本塔不允许浏览地图!");
|
||||
}
|
||||
else {
|
||||
core.drawText("\t[系统提示]即将进入浏览地图模式。\n\n点击地图上半部分,或按[↑]键可查看前一张地图\n点击地图下半部分,或按[↓]键可查看后一张地图\n点击地图中间,或按[ESC]键可离开浏览地图模式", function () {
|
||||
core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId));
|
||||
})
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
core.status.event.selection=0;
|
||||
core.ui.drawSyncSave();
|
||||
break;
|
||||
case 3:
|
||||
case 4:
|
||||
core.status.event.selection=1;
|
||||
core.ui.drawConfirmBox("你确定要重新开始吗?", function () {
|
||||
core.ui.closePanel();
|
||||
core.restart();
|
||||
}, function () {
|
||||
core.status.event.selection=3;
|
||||
core.ui.drawSettings(false);
|
||||
core.ui.drawSettings();
|
||||
});
|
||||
break;
|
||||
case 4:
|
||||
core.ui.drawHelp();
|
||||
break;
|
||||
case 5:
|
||||
core.ui.drawAbout();
|
||||
core.ui.drawWaiting("正在拉取统计信息,请稍后...");
|
||||
|
||||
var formData = new FormData();
|
||||
formData.append('type', 'getinfo');
|
||||
formData.append('name', core.firstData.name);
|
||||
formData.append('version', core.firstData.version);
|
||||
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", "/games/upload.php");
|
||||
|
||||
xhr.onload = function(e) {
|
||||
if (xhr.status==200) {
|
||||
var response = JSON.parse(xhr.response);
|
||||
if (response.code<0) {
|
||||
core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:"+response.msg);
|
||||
}
|
||||
else {
|
||||
var text="\t[本塔统计信息]";
|
||||
var toAdd=false;
|
||||
response.data.forEach(function (t) {
|
||||
if (toAdd) text+="\n\n";
|
||||
toAdd=true;
|
||||
if (t.hard!='') text+=t.hard+"难度: "
|
||||
text+="已有"+t.people+"人次游戏,"+t.score+"人次通关。";
|
||||
if (core.isset(t.max) && t.max>0) {
|
||||
text+="\n当前MAX为"+t.max+",最早由 "+(t.username||"匿名")+" 于"+core.formatDate(new Date(1000*t.timestamp))+"打出。";
|
||||
}
|
||||
})
|
||||
core.drawText(text);
|
||||
}
|
||||
}
|
||||
else {
|
||||
core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:HTTP "+xhr.status);
|
||||
}
|
||||
};
|
||||
xhr.ontimeout = function() {
|
||||
core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:Timeout");
|
||||
}
|
||||
xhr.onerror = function() {
|
||||
core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:XHR Error");
|
||||
}
|
||||
xhr.send(formData);
|
||||
break;
|
||||
case 6:
|
||||
core.ui.drawHelp();
|
||||
break;
|
||||
case 7:
|
||||
core.ui.drawAbout();
|
||||
break;
|
||||
case 8:
|
||||
core.ui.closePanel();
|
||||
break;
|
||||
}
|
||||
@ -1352,17 +1650,12 @@ events.prototype.clickSettings = function (x,y) {
|
||||
|
||||
////// 系统菜单栏界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownSettings = function (keycode) {
|
||||
var choices = [
|
||||
"系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏"
|
||||
];
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -1374,7 +1667,7 @@ events.prototype.keyUpSettings = function (keycode) {
|
||||
return;
|
||||
}
|
||||
var choices = [
|
||||
"系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏"
|
||||
"系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏"
|
||||
];
|
||||
if (keycode==13 || keycode==32 || keycode==67) {
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
@ -1386,7 +1679,7 @@ events.prototype.keyUpSettings = function (keycode) {
|
||||
events.prototype.clickSyncSave = function (x,y) {
|
||||
if (x<5 || x>7) return;
|
||||
var choices = [
|
||||
"同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单"
|
||||
"同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单"
|
||||
];
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
if (y>=topIndex && y<topIndex+choices.length) {
|
||||
@ -1399,18 +1692,61 @@ events.prototype.clickSyncSave = function (x,y) {
|
||||
core.syncSave("load");
|
||||
break;
|
||||
case 2:
|
||||
var saves = [];
|
||||
for (var i=1;i<=150;i++) {
|
||||
var data = core.getLocalStorage("save"+i, null);
|
||||
if (core.isset(data)) {
|
||||
saves.push(data);
|
||||
}
|
||||
}
|
||||
var content = {
|
||||
"name": core.firstData.name,
|
||||
"version": core.firstData.version,
|
||||
"data": saves
|
||||
}
|
||||
core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5save", JSON.stringify(content));
|
||||
break;
|
||||
case 3:
|
||||
core.readFile(function (obj) {
|
||||
if (obj.name!=core.firstData.name) {
|
||||
alert("存档和游戏不一致!");
|
||||
return;
|
||||
}
|
||||
if (obj.version!=core.firstData.version) {
|
||||
alert("游戏版本不一致!");
|
||||
return;
|
||||
}
|
||||
if (!core.isset(obj.data)) {
|
||||
alert("无效的存档!");
|
||||
return;
|
||||
}
|
||||
var data=obj.data;
|
||||
for (var i=1;i<=150;i++) {
|
||||
if (i<=data.length) {
|
||||
core.setLocalStorage("save"+i, data[i-1]);
|
||||
}
|
||||
else {
|
||||
core.removeLocalStorage("save"+i);
|
||||
}
|
||||
}
|
||||
core.drawText("读取成功!\n你的本地所有存档均已被覆盖。");
|
||||
}, function () {
|
||||
|
||||
});
|
||||
break;
|
||||
case 4:
|
||||
core.status.event.selection=1;
|
||||
core.ui.drawConfirmBox("你确定要清空所有本地存档吗?", function() {
|
||||
core.ui.drawConfirmBox("你确定要清空所有存档吗?", function() {
|
||||
localStorage.clear();
|
||||
core.drawText("\t[操作成功]你的本地所有存档已被清空。");
|
||||
core.drawText("\t[操作成功]你的所有存档已被清空。");
|
||||
}, function() {
|
||||
core.status.event.selection=2;
|
||||
core.ui.drawSyncSave(false);
|
||||
})
|
||||
break;
|
||||
case 3:
|
||||
core.status.event.selection=2;
|
||||
core.ui.drawSettings(false);
|
||||
case 5:
|
||||
core.status.event.selection=3;
|
||||
core.ui.drawSettings();
|
||||
break;
|
||||
|
||||
}
|
||||
@ -1420,17 +1756,12 @@ events.prototype.clickSyncSave = function (x,y) {
|
||||
|
||||
////// 同步存档界面时,按下某个键的操作 //////
|
||||
events.prototype.keyDownSyncSave = function (keycode) {
|
||||
var choices = [
|
||||
"同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单"
|
||||
];
|
||||
if (keycode==38) {
|
||||
core.status.event.selection--;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
if (keycode==40) {
|
||||
core.status.event.selection++;
|
||||
if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1;
|
||||
core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices);
|
||||
}
|
||||
}
|
||||
@ -1439,11 +1770,11 @@ events.prototype.keyDownSyncSave = function (keycode) {
|
||||
events.prototype.keyUpSyncSave = function (keycode) {
|
||||
if (keycode==27 || keycode==88) {
|
||||
core.status.event.selection=2;
|
||||
core.ui.drawSettings(false);
|
||||
core.ui.drawSettings();
|
||||
return;
|
||||
}
|
||||
var choices = [
|
||||
"同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单"
|
||||
"同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单"
|
||||
];
|
||||
if (keycode==13 || keycode==32 || keycode==67) {
|
||||
var topIndex = 6 - parseInt((choices.length - 1) / 2);
|
||||
@ -1451,6 +1782,65 @@ events.prototype.keyUpSyncSave = function (keycode) {
|
||||
}
|
||||
}
|
||||
|
||||
////// “虚拟键盘”界面时的点击操作 //////
|
||||
events.prototype.clickKeyBoard = function (x, y) {
|
||||
if (y==3 && x>=1 && x<=11) {
|
||||
core.ui.closePanel();
|
||||
core.keyUp(112+x-1); // F1-F12: 112-122
|
||||
}
|
||||
if (y==4 && x>=1 && x<=10) {
|
||||
core.ui.closePanel();
|
||||
core.keyUp(x==10?48:48+x); // 1-9: 49-57; 0: 48
|
||||
}
|
||||
// 字母
|
||||
var lines = [
|
||||
["Q","W","E","R","T","Y","U","I","O","P"],
|
||||
["A","S","D","F","G","H","J","K","L"],
|
||||
["Z","X","C","V","B","N","M"],
|
||||
];
|
||||
if (y==5 && x>=1 && x<=10) {
|
||||
core.ui.closePanel();
|
||||
core.keyUp(lines[0][x-1].charCodeAt(0));
|
||||
}
|
||||
if (y==6 && x>=1 && x<=9) {
|
||||
core.ui.closePanel();
|
||||
core.keyUp(lines[1][x-1].charCodeAt(0));
|
||||
}
|
||||
if (y==7 && x>=1 && x<=7) {
|
||||
core.ui.closePanel();
|
||||
core.keyUp(lines[2][x-1].charCodeAt(0));
|
||||
}
|
||||
if (y==8 && x>=1 && x<=11) {
|
||||
core.ui.closePanel();
|
||||
if (x==1) core.keyUp(189); // -
|
||||
if (x==2) core.keyUp(187); // =
|
||||
if (x==3) core.keyUp(219); // [
|
||||
if (x==4) core.keyUp(221); // ]
|
||||
if (x==5) core.keyUp(220); // \
|
||||
if (x==6) core.keyUp(186); // ;
|
||||
if (x==7) core.keyUp(222); // '
|
||||
if (x==8) core.keyUp(188); // ,
|
||||
if (x==9) core.keyUp(190); // .
|
||||
if (x==10) core.keyUp(191); // /
|
||||
if (x==11) core.keyUp(192); // `
|
||||
}
|
||||
if (y==9 && x>=1 && x<=10) {
|
||||
core.ui.closePanel();
|
||||
if (x==1) core.keyUp(27); // ESC
|
||||
if (x==2) core.keyUp(9); // TAB
|
||||
if (x==3) core.keyUp(20); // CAPS
|
||||
if (x==4) core.keyUp(16); // SHIFT
|
||||
if (x==5) core.keyUp(17); // CTRL
|
||||
if (x==6) core.keyUp(18); // ALT
|
||||
if (x==7) core.keyUp(32); // SPACE
|
||||
if (x==8) core.keyUp(8); // BACKSPACE
|
||||
if (x==9) core.keyUp(13); // ENTER
|
||||
if (x==10) core.keyUp(46); // DEL
|
||||
}
|
||||
if (y==10 && x>=9 && x<=11)
|
||||
core.ui.closePanel();
|
||||
}
|
||||
|
||||
////// “关于”界面时的点击操作 //////
|
||||
events.prototype.clickAbout = function () {
|
||||
if (core.isPlaying())
|
||||
|
||||
@ -50,7 +50,6 @@ main.floors.sample0 = {
|
||||
"\t[老人,womanMagician]这些是路障、楼梯、传送门。",
|
||||
"\t[老人,womanMagician]血网的伤害数值、中毒后每步伤害数值、衰弱时攻防下降的数值,都在 data.js 内定义。\n\n路障同样会尽量被自动寻路绕过。",
|
||||
"\t[老人,womanMagician]楼梯和传送门需要在changeFloor中定义目标楼层和位置,可参见样板里已有的的写法。",
|
||||
"\t[老人,womanMagician]楼梯和传送门是否可“穿透”,由data.js中的全局变量所决定,你也可以单独设置。\n穿透的意思是,自动寻路得到的路径中间经过了楼梯,行走时是否触发楼层转换事件。\n例如,下面的“下箭头”就是不能穿透的。",
|
||||
{"type": "hide", "time": 500}
|
||||
],
|
||||
"2,8": [ // 守着第一批怪物的老人
|
||||
@ -75,7 +74,6 @@ main.floors.sample0 = {
|
||||
{"type": "hide", "time": 500}
|
||||
]
|
||||
},
|
||||
|
||||
},
|
||||
"changeFloor": { // 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖
|
||||
"6,0": {"floorId": "sample1", "stair": "downFloor"}, // 目标点:sample1层的下楼梯位置
|
||||
@ -85,8 +83,8 @@ main.floors.sample0 = {
|
||||
"2,12": {"floorId": "sample0", "loc": [2,12]},
|
||||
"3,12": {"floorId": "sample0", "loc": [6,1], "direction": "up"}, // 切换楼层后勇士面对上方
|
||||
"4,12": {"floorId": "sample0", "loc": [0,9], "direction": "left", "time": 1000}, // 切换楼层后勇士面对左边,切换动画1000ms
|
||||
"5,12": {"floorId": "sample0", "loc": [6,10], "portalWithoutTrigger": false}, // 不能穿透
|
||||
"6,12": {"floorId": "sample0", "loc": [10,10], "direction": "left", "time": 1000, "portalWithoutTrigger": false},
|
||||
"5,12": {"floorId": "sample0", "loc": [6,10], "time": 0}, // time=0表示无切换时间
|
||||
"6,12": {"floorId": "sample0", "loc": [10,10], "direction": "left", "time": 1000},
|
||||
},
|
||||
"afterBattle": { // 战斗后可能触发的事件列表
|
||||
"2,6": ["\t[ghostSkeleton]不可能,你怎么可能打败我!\n(一个打败怪物触发的事件)"]
|
||||
|
||||
@ -258,18 +258,34 @@ main.floors.sample1 = {
|
||||
"\t[老人,womanMagician]使用 {\"type\":\"function\"} 可以写自定义的JS脚本。\n本塔支持的所有主要API会在doc文档内给出。",
|
||||
"\t[老人,womanMagician]例如这个例子:即将弹出一个输入窗口,然后会将你的输入结果直接加到你的攻击力上。",
|
||||
{"type": "function", "function": function() { // 自己写JS脚本并执行
|
||||
var value = prompt("请输入你要加攻击力的数值:"); // 弹出一个输入框让用户输入数据
|
||||
if (value!=null) {
|
||||
value=parseInt(value);
|
||||
if (value>0) { // 检查
|
||||
core.setStatus("atk", core.getStatus("atk")+value);
|
||||
// core.updateStatusBar(); // 和下面的 {"type": "update"} 等价,立即更新状态栏和地图显伤
|
||||
core.drawTip("操作成功,攻击+"+value); // 左上角气泡提示
|
||||
core.events.insertAction([ // 往当前事件列表前插入两条事件
|
||||
{"type": "update"}, // 更新状态栏和地图显伤
|
||||
"操作成功,攻击+"+value // 对话框提示
|
||||
]);
|
||||
|
||||
// 注意一下prompt对于录像是如何处理的
|
||||
var value;
|
||||
if (core.status.replay.replaying) {
|
||||
var action = core.status.replay.toReplay.shift();
|
||||
if (action.indexOf("input:")==0 ) {
|
||||
value=parseInt(action.substring(6));
|
||||
}
|
||||
else {
|
||||
core.status.replay.replaying=false;
|
||||
core.drawTip("录像文件出错");
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
value = prompt("请输入你要加攻击力的数值:");
|
||||
}
|
||||
value = parseInt(value)||0;
|
||||
core.status.route.push("input:"+value);
|
||||
|
||||
if (value>0) { // 检查
|
||||
core.setStatus("atk", core.getStatus("atk")+value);
|
||||
// core.updateStatusBar(); // 和下面的 {"type": "update"} 等价,立即更新状态栏和地图显伤
|
||||
core.drawTip("操作成功,攻击+"+value); // 左上角气泡提示
|
||||
core.events.insertAction([ // 往当前事件列表前插入两条事件
|
||||
{"type": "update"}, // 更新状态栏和地图显伤
|
||||
"操作成功,攻击+"+value // 对话框提示
|
||||
]);
|
||||
}
|
||||
}},
|
||||
"\t[老人,womanMagician]具体可参见样板中本事件的写法。"
|
||||
|
||||
@ -14,23 +14,23 @@ icons.prototype.init = function () {
|
||||
'ground': 0,
|
||||
'grass': 1,
|
||||
'grass2': 2,
|
||||
'snowGround': 3,
|
||||
'ground2': 4,
|
||||
'ground3': 5,
|
||||
'ground4': 6,
|
||||
'sand': 7,
|
||||
'ground5': 8,
|
||||
'yellowWall2': 9,
|
||||
'whiteWall2': 10,
|
||||
'blueWall2': 11,
|
||||
'blockWall': 12,
|
||||
'grayWall': 13,
|
||||
'white': 14,
|
||||
'ground6': 15,
|
||||
'soil': 16,
|
||||
'yellowWall': 17,
|
||||
'whiteWall': 18,
|
||||
'blueWall': 19,
|
||||
'yellowWall': 3,
|
||||
'whiteWall': 4,
|
||||
'blueWall': 5,
|
||||
'snowGround': 6,
|
||||
'ground2': 7,
|
||||
'ground3': 8,
|
||||
'ground4': 9,
|
||||
'sand': 10,
|
||||
'ground5': 11,
|
||||
'yellowWall2': 12,
|
||||
'whiteWall2': 13,
|
||||
'blueWall2': 14,
|
||||
'blockWall': 15,
|
||||
'grayWall': 16,
|
||||
'white': 17,
|
||||
'ground6': 18,
|
||||
'soil': 19,
|
||||
'star': 20,
|
||||
'lava': 21,
|
||||
'ice': 22,
|
||||
@ -178,11 +178,13 @@ icons.prototype.init = function () {
|
||||
'bluePotion': 21,
|
||||
'greenPotion': 22,
|
||||
'yellowPotion': 23,
|
||||
'sword0': 60,
|
||||
'sword1': 50,
|
||||
'sword2': 51,
|
||||
'sword3': 52,
|
||||
'sword4': 53,
|
||||
'sword5': 54,
|
||||
'shield0': 61,
|
||||
'shield1': 55,
|
||||
'shield2': 56,
|
||||
'shield3': 57,
|
||||
|
||||
@ -33,6 +33,8 @@ items.prototype.init = function () {
|
||||
'moneyPocket': {'cls': 'items', 'name': '金钱袋'},
|
||||
|
||||
// 物品
|
||||
'sword0': {'cls': 'constants', 'name': '折断的剑', 'text': '没有任何作用的剑,相当于脱掉装备。'},
|
||||
'shield0': {'cls': 'constants', 'name': '残破的盾', 'text': '没有任何作用的盾,相当于脱掉装备。'},
|
||||
'book': {'cls': 'constants', 'name': '怪物手册', 'text': '可以查看当前楼层各怪物属性'},
|
||||
'fly': {'cls': 'constants', 'name': '楼层传送器', 'text': '可以自由往来去过的楼层'},
|
||||
'coin': {'cls': 'constants', 'name': '幸运金币', 'text': '持有时打败怪物可得双倍金币'},
|
||||
@ -70,6 +72,19 @@ items.prototype.getItems = function () {
|
||||
this.items.pickaxe.text = "可以破坏勇士四周的墙";
|
||||
if (core.flags.bombFourDirections)
|
||||
this.items.bomb.text = "可以炸掉勇士四周的怪物";
|
||||
if (core.flags.equipment) {
|
||||
this.items.sword1 = {'cls': 'constants', 'name': '铁剑', 'text': '一把很普通的铁剑,攻击+'+core.values.sword1};
|
||||
this.items.sword2 = {'cls': 'constants', 'name': '银剑', 'text': '一把很普通的银剑,攻击+'+core.values.sword2};
|
||||
this.items.sword3 = {'cls': 'constants', 'name': '骑士剑', 'text': '一把很普通的骑士剑,攻击+'+core.values.sword3};
|
||||
this.items.sword4 = {'cls': 'constants', 'name': '圣剑', 'text': '一把很普通的圣剑,攻击+'+core.values.sword4};
|
||||
this.items.sword5 = {'cls': 'constants', 'name': '神圣剑', 'text': '一把很普通的神圣剑,攻击+'+core.values.sword5};
|
||||
this.items.shield1 = {'cls': 'constants', 'name': '铁盾', 'text': '一个很普通的铁盾,防御+'+core.values.shield1};
|
||||
this.items.shield2 = {'cls': 'constants', 'name': '银盾', 'text': '一个很普通的银盾,防御+'+core.values.shield2};
|
||||
this.items.shield3 = {'cls': 'constants', 'name': '骑士盾', 'text': '一个很普通的骑士盾,防御+'+core.values.shield3};
|
||||
this.items.shield4 = {'cls': 'constants', 'name': '圣盾', 'text': '一个很普通的圣盾,防御+'+core.values.shield4};
|
||||
this.items.shield5 = {'cls': 'constants', 'name': '神圣盾', 'text': '一个很普通的神圣盾,防御+'+core.values.shield5};
|
||||
}
|
||||
|
||||
return this.items;
|
||||
}
|
||||
|
||||
@ -118,24 +133,24 @@ items.prototype.getItemEffect = function(itemId, itemNum) {
|
||||
|
||||
////// “即捡即用类”道具的文字提示 //////
|
||||
items.prototype.getItemEffectTip = function(itemId) {
|
||||
if (itemId === 'redJewel') return ",攻击+"+core.values.redJewel;
|
||||
if (itemId === 'blueJewel') return ",防御+"+core.values.blueJewel;
|
||||
if (itemId === 'greenJewel') return ",魔防+"+core.values.greenJewel;
|
||||
if (itemId == 'redJewel') return ",攻击+"+core.values.redJewel;
|
||||
if (itemId == 'blueJewel') return ",防御+"+core.values.blueJewel;
|
||||
if (itemId == 'greenJewel') return ",魔防+"+core.values.greenJewel;
|
||||
if (itemId == 'yellowJewel') return ",全属性提升";
|
||||
if (itemId === 'redPotion') return ",生命+"+core.values.redPotion;
|
||||
if (itemId === 'bluePotion') return ",生命+"+core.values.bluePotion;
|
||||
if (itemId === 'yellowPotion') return ",生命+"+core.values.yellowPotion;
|
||||
if (itemId === 'greenPotion') return ",生命+"+core.values.greenPotion;
|
||||
if (itemId === 'sword1') return ",攻击+"+core.values.sword1;
|
||||
if (itemId === 'sword2') return ",攻击+"+core.values.sword2;
|
||||
if (itemId === 'sword3') return ",攻击+"+core.values.sword3;
|
||||
if (itemId === 'sword4') return ",攻击+"+core.values.sword4;
|
||||
if (itemId === 'sword5') return ",攻击+"+core.values.sword5;
|
||||
if (itemId === 'shield1') return ",防御+"+core.values.shield1;
|
||||
if (itemId === 'shield2') return ",防御+"+core.values.shield2;
|
||||
if (itemId === 'shield3') return ",防御+"+core.values.shield3;
|
||||
if (itemId === 'shield4') return ",防御+"+core.values.shield4;
|
||||
if (itemId === 'shield5') return ",防御+"+core.values.shield5;
|
||||
if (itemId == 'redPotion') return ",生命+"+core.values.redPotion;
|
||||
if (itemId == 'bluePotion') return ",生命+"+core.values.bluePotion;
|
||||
if (itemId == 'yellowPotion') return ",生命+"+core.values.yellowPotion;
|
||||
if (itemId == 'greenPotion') return ",生命+"+core.values.greenPotion;
|
||||
if (!core.flags.equipment && itemId == 'sword1') return ",攻击+"+core.values.sword1;
|
||||
if (!core.flags.equipment && itemId == 'sword2') return ",攻击+"+core.values.sword2;
|
||||
if (!core.flags.equipment && itemId == 'sword3') return ",攻击+"+core.values.sword3;
|
||||
if (!core.flags.equipment && itemId == 'sword4') return ",攻击+"+core.values.sword4;
|
||||
if (!core.flags.equipment && itemId == 'sword5') return ",攻击+"+core.values.sword5;
|
||||
if (!core.flags.equipment && itemId == 'shield1') return ",防御+"+core.values.shield1;
|
||||
if (!core.flags.equipment && itemId == 'shield2') return ",防御+"+core.values.shield2;
|
||||
if (!core.flags.equipment && itemId == 'shield3') return ",防御+"+core.values.shield3;
|
||||
if (!core.flags.equipment && itemId == 'shield4') return ",防御+"+core.values.shield4;
|
||||
if (!core.flags.equipment && itemId == 'shield5') return ",防御+"+core.values.shield5;
|
||||
if (itemId === 'bigKey') return ",全钥匙+1";
|
||||
if (itemId === 'superPotion') return ",生命值翻倍";
|
||||
if (itemId == 'moneyPocket') return ",金币+"+core.values.moneyPocket;
|
||||
@ -143,8 +158,11 @@ items.prototype.getItemEffectTip = function(itemId) {
|
||||
}
|
||||
|
||||
////// 使用道具 //////
|
||||
items.prototype.useItem = function (itemId) {
|
||||
if (!this.canUseItem(itemId)) return;
|
||||
items.prototype.useItem = function (itemId, callback) {
|
||||
if (!this.canUseItem(itemId)) {
|
||||
if (core.isset(callback)) callback();
|
||||
return;
|
||||
}
|
||||
var itemCls = core.material.items[itemId].cls;
|
||||
|
||||
if (itemId=='book') core.ui.drawBook(0);
|
||||
@ -174,6 +192,7 @@ items.prototype.useItem = function (itemId) {
|
||||
// 上楼器/下楼器
|
||||
core.changeFloor(core.status.event.data.id, null, {'direction': core.status.hero.loc.direction, 'x': core.status.event.data.x, 'y': core.status.event.data.y}, null, function (){
|
||||
core.drawTip(core.material.items[itemId].name + "使用成功");
|
||||
core.replay();
|
||||
});
|
||||
}
|
||||
if (itemId == 'poisonWine') core.setFlag('poison', false);
|
||||
@ -192,12 +211,42 @@ items.prototype.useItem = function (itemId) {
|
||||
}
|
||||
core.setFlag('curse', false);
|
||||
}
|
||||
|
||||
// 剑
|
||||
if (itemId.indexOf("sword")==0) {
|
||||
var now=core.getFlag('sword', 'sword0'); // 当前装备剑的ID
|
||||
core.status.hero.atk -= core.values[now];
|
||||
core.setItem(now, 1);
|
||||
core.status.hero.atk += core.values[itemId];
|
||||
core.setItem(itemId, 0);
|
||||
core.setFlag('sword', itemId);
|
||||
core.drawTip("已装备"+core.material.items[itemId].name);
|
||||
}
|
||||
// 盾
|
||||
if (itemId.indexOf("shield")==0) {
|
||||
var now=core.getFlag('shield', 'shield0');
|
||||
core.status.hero.def -= core.values[now];
|
||||
core.setItem(now, 1);
|
||||
core.status.hero.def += core.values[itemId];
|
||||
core.setItem(itemId, 0);
|
||||
core.setFlag('shield', itemId);
|
||||
core.drawTip("已装备"+core.material.items[itemId].name);
|
||||
}
|
||||
|
||||
core.updateStatusBar();
|
||||
|
||||
// 记录路线
|
||||
if (itemId!='book' && itemId!='fly') {
|
||||
core.status.route.push("item:"+itemId);
|
||||
}
|
||||
|
||||
// 道具使用完毕:删除
|
||||
if (itemCls=='tools')
|
||||
core.status.hero.items[itemCls][itemId]--;
|
||||
if (core.status.hero.items[itemCls][itemId]==0)
|
||||
delete core.status.hero.items[itemCls][itemId];
|
||||
|
||||
if (core.isset(callback)) callback();
|
||||
}
|
||||
|
||||
////// 当前能否使用道具 //////
|
||||
@ -363,5 +412,9 @@ items.prototype.canUseItem = function (itemId) {
|
||||
if (itemId=='weakWine') return core.hasFlag('weak');
|
||||
if (itemId=='curseWine') return core.hasFlag('curse');
|
||||
if (itemId=='superWine') return core.hasFlag('poison') || core.hasFlag('weak') || core.hasFlag('curse');
|
||||
|
||||
// 剑盾
|
||||
if (itemId.indexOf("sword")==0 || itemId.indexOf("shield")==0) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
17
libs/maps.js
@ -68,10 +68,10 @@ maps.prototype.getBlock = function (x, y, id) {
|
||||
// 0-20 地形
|
||||
if (id == 1) tmp.event = {'cls': 'terrains', 'id': 'yellowWall'}; // 黄墙
|
||||
if (id == 2) tmp.event = {'cls': 'terrains', 'id': 'whiteWall'}; // 白墙
|
||||
if (id == 3) tmp.event = {'cls': 'terrains', 'id': 'blueWall'}; // 白墙
|
||||
if (id == 3) tmp.event = {'cls': 'terrains', 'id': 'blueWall'}; // 蓝墙
|
||||
if (id == 4) tmp.event = {'cls': 'animates', 'id': 'star', 'noPass': true}; // 星空
|
||||
if (id == 5) tmp.event = {'cls': 'animates', 'id': 'lava', 'noPass': true}; // 岩浆
|
||||
if (id == 6) tmp.event = {'cls': 'terrains', 'id': 'ice'}; // 岩浆
|
||||
if (id == 6) tmp.event = {'cls': 'terrains', 'id': 'ice'}; // 冰面
|
||||
if (id == 7) tmp.event = {'cls': 'terrains', 'id': 'blueShop-left'}; // 蓝色商店左
|
||||
if (id == 8) tmp.event = {'cls': 'terrains', 'id': 'blueShop-right'}; // 蓝色商店右
|
||||
if (id == 9) tmp.event = {'cls': 'terrains', 'id': 'pinkShop-left'}; // 粉色商店左
|
||||
@ -356,16 +356,7 @@ maps.prototype.load = function (data, floorId) {
|
||||
}
|
||||
|
||||
////// 将当前地图重新变成二维数组形式 //////
|
||||
maps.prototype.getMapArray = function (maps, floorId){
|
||||
if (!core.isset(floorId)) {
|
||||
var map = {};
|
||||
for (var id in maps) {
|
||||
map[id] = this.getMapArray(maps, id);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
var thisFloor = maps[floorId];
|
||||
maps.prototype.getMapArray = function (blockArray){
|
||||
|
||||
var blocks = [];
|
||||
for (var x=0;x<13;x++) {
|
||||
@ -374,7 +365,7 @@ maps.prototype.getMapArray = function (maps, floorId){
|
||||
blocks[x].push(0);
|
||||
}
|
||||
}
|
||||
thisFloor.blocks.forEach(function (block) {
|
||||
blockArray.forEach(function (block) {
|
||||
if (!(core.isset(block.enable) && !block.enable))
|
||||
blocks[block.y][block.x] = block.id;
|
||||
});
|
||||
|
||||
136
libs/ui.js
@ -257,6 +257,8 @@ ui.prototype.drawChoices = function(content, choices) {
|
||||
|
||||
if (choices.length>0) {
|
||||
if (!core.isset(core.status.event.selection)) core.status.event.selection=0;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1;
|
||||
var len = core.canvas.ui.measureText(core.replaceText(choices[core.status.event.selection].text || choices[core.status.event.selection])).width;
|
||||
core.strokeRect('ui', 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28, "#FFD700", 2);
|
||||
}
|
||||
@ -271,7 +273,8 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) {
|
||||
core.status.event.data = {'yes': yesCallback, 'no': noCallback};
|
||||
core.status.event.ui = text;
|
||||
|
||||
if (!core.isset(core.status.event.selection)) core.status.event.selection=1;
|
||||
if (!core.isset(core.status.event.selection) || core.status.event.selection>1) core.status.event.selection=1;
|
||||
if (core.status.event.selection<0) core.status.event.selection=0;
|
||||
|
||||
var background = core.canvas.ui.createPattern(core.material.ground, "repeat");
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
@ -319,29 +322,26 @@ ui.prototype.drawSwitchs = function() {
|
||||
var choices = [
|
||||
"背景音乐:"+(core.musicStatus.bgmStatus ? "[ON]" : "[OFF]"),
|
||||
"背景音效:"+(core.musicStatus.soundStatus ? "[ON]" : "[OFF]"),
|
||||
"战斗动画: " + (core.flags.battleAnimate ? "[ON]" : "[OFF]"),
|
||||
"怪物显伤: " + (core.flags.displayEnemyDamage ? "[ON]" : "[OFF]"),
|
||||
"领域显伤: " + (core.flags.displayExtraDamage ? "[ON]" : "[OFF]"),
|
||||
"战斗动画: "+(core.flags.battleAnimate ? "[ON]" : "[OFF]"),
|
||||
"怪物显伤: "+(core.flags.displayEnemyDamage ? "[ON]" : "[OFF]"),
|
||||
"领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"),
|
||||
"下载离线版本",
|
||||
"返回主菜单"
|
||||
];
|
||||
this.drawChoices(null, choices);
|
||||
|
||||
}
|
||||
|
||||
////// 绘制系统菜单栏 //////
|
||||
ui.prototype.drawSettings = function (need) {
|
||||
if (!core.checkStatus('settings', need))
|
||||
return;
|
||||
ui.prototype.drawSettings = function () {
|
||||
core.status.event.id = 'settings';
|
||||
|
||||
this.drawChoices(null, [
|
||||
"系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏"
|
||||
"系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏"
|
||||
]);
|
||||
}
|
||||
|
||||
////// 绘制快捷商店选择栏 //////
|
||||
ui.prototype.drawQuickShop = function (need) {
|
||||
if (core.isset(need) && !core.checkStatus('selectShop', need))
|
||||
return;
|
||||
ui.prototype.drawQuickShop = function () {
|
||||
|
||||
core.status.event.id = 'selectShop';
|
||||
|
||||
@ -654,12 +654,17 @@ ui.prototype.drawWaiting = function(text) {
|
||||
core.setAlpha('ui', 1);
|
||||
core.setFillStyle('ui', background);
|
||||
|
||||
var left = 97, top = 208 - 32 - 16, right = 416 - 2 * left, bottom = 416 - 2 * top;
|
||||
core.setFont('ui', 'bold 17px Verdana');
|
||||
var text_length = core.canvas.ui.measureText(text).width;
|
||||
|
||||
var right = Math.max(text_length+50, 220);
|
||||
var left = 208-right/2, top = 208 - 32 - 16, bottom = 416 - 2 * top;
|
||||
|
||||
core.fillRect('ui', left, top, right, bottom, background);
|
||||
core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2);
|
||||
|
||||
core.canvas.ui.textAlign = "center";
|
||||
core.fillText('ui', text, 208, top + 56, "#FFFFFF", "bold 17px Verdana");
|
||||
core.fillText('ui', text, 208, top + 56, '#FFFFFF');
|
||||
|
||||
}
|
||||
|
||||
@ -669,7 +674,7 @@ ui.prototype.drawSyncSave = function () {
|
||||
core.status.event.id = 'syncSave';
|
||||
|
||||
this.drawChoices(null, [
|
||||
"同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单"
|
||||
"同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单"
|
||||
]);
|
||||
|
||||
}
|
||||
@ -902,6 +907,38 @@ ui.prototype.drawFly = function(page) {
|
||||
this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 20, 100, 273);
|
||||
}
|
||||
|
||||
////// 绘制浏览地图界面 //////
|
||||
ui.prototype.drawMaps = function (index) {
|
||||
if (!core.isset(index)) index=core.floorIds.indexOf(core.status.floorId);
|
||||
|
||||
if (index<0) index=0;
|
||||
if (index>=core.floorIds.length) index=core.floorIds.length-1;
|
||||
|
||||
core.lockControl();
|
||||
core.status.event.id = 'viewMaps';
|
||||
core.status.event.data = index;
|
||||
|
||||
var floorId = core.floorIds[index];
|
||||
|
||||
clearTimeout(core.interval.tipAnimate);
|
||||
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
core.setAlpha('ui', 1);
|
||||
this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 0, 0, 416);
|
||||
|
||||
core.clearMap('data', 0, 0, 416, 416);
|
||||
core.setOpacity('data', 0.2);
|
||||
core.canvas.data.textAlign = 'left';
|
||||
core.setFont('data', '16px Arial');
|
||||
|
||||
var text = core.floors[floorId].title;
|
||||
var textX = 16, textY = 18, width = textX + core.canvas.data.measureText(text).width + 16, height = 42;
|
||||
core.fillRect('data', 5, 5, width, height, '#000');
|
||||
core.setOpacity('data', 0.5);
|
||||
core.fillText('data', text, textX + 5, textY + 15, '#fff');
|
||||
|
||||
}
|
||||
|
||||
////// 绘制道具栏 //////
|
||||
ui.prototype.drawToolbox = function(index) {
|
||||
|
||||
@ -1020,16 +1057,15 @@ ui.prototype.drawToolbox = function(index) {
|
||||
////// 绘制存档/读档界面 //////
|
||||
ui.prototype.drawSLPanel = function(index) {
|
||||
if (!core.isset(index)) index=1;
|
||||
if (index<=0) index=1;
|
||||
if (index>180) index=180;
|
||||
if (index<0) index=0;
|
||||
|
||||
var page = parseInt(index/10), offset=index%10;
|
||||
if (page>=30) page=29;
|
||||
if (offset>5) offset=5;
|
||||
index=10*page+offset;
|
||||
|
||||
core.status.event.data=index;
|
||||
|
||||
var page=parseInt((index-1)/6);
|
||||
|
||||
// core.status.event.data = page;
|
||||
// core.status.savePage = page;
|
||||
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
core.setAlpha('ui', 0.85);
|
||||
core.fillRect('ui', 0, 0, 416, 416, '#000000');
|
||||
@ -1040,12 +1076,11 @@ ui.prototype.drawSLPanel = function(index) {
|
||||
|
||||
var name=core.status.event.id=='save'?"存档":"读档";
|
||||
for (var i=0;i<6;i++) {
|
||||
var id=6*page+i+1;
|
||||
var data=core.getLocalStorage("save"+id,null);
|
||||
|
||||
var id=5*page+i;
|
||||
var data=core.getLocalStorage(i==0?"autoSave":"save"+id, null);
|
||||
if (i<3) {
|
||||
core.fillText('ui', name+id, (2*i+1)*u, 35, '#FFFFFF', "bold 17px Verdana");
|
||||
core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, id==index?'#FFD700':'#FFFFFF', id==index?6:2);
|
||||
core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 35, '#FFFFFF', "bold 17px Verdana");
|
||||
core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2);
|
||||
if (core.isset(data) && core.isset(data.floorId)) {
|
||||
this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 50, size, data.hero.loc);
|
||||
core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 65+size, '#FFFFFF', '10px Verdana');
|
||||
@ -1057,7 +1092,7 @@ ui.prototype.drawSLPanel = function(index) {
|
||||
}
|
||||
else {
|
||||
core.fillText('ui', name+id, (2*i-5)*u, 230, '#FFFFFF', "bold 17px Verdana");
|
||||
core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, id==index?'#FFD700':'#FFFFFF', id==index?6:2);
|
||||
core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2);
|
||||
if (core.isset(data) && core.isset(data.floorId)) {
|
||||
this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 245, size, data.hero.loc);
|
||||
core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 260+size, '#FFFFFF', '10px Verdana');
|
||||
@ -1091,7 +1126,7 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL
|
||||
}
|
||||
}
|
||||
|
||||
var mapArray = core.maps.getMapArray(core.status.maps, floorId);
|
||||
var mapArray = core.maps.getMapArray(blocks);
|
||||
for (var b in blocks) {
|
||||
var block = blocks[b];
|
||||
if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) {
|
||||
@ -1116,6 +1151,44 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL
|
||||
}
|
||||
}
|
||||
|
||||
ui.prototype.drawKeyBoard = function () {
|
||||
core.lockControl();
|
||||
core.status.event.id = 'keyBoard';
|
||||
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
|
||||
var left = 16, top = 48, right = 416 - 2 * left, bottom = 416 - 2 * top;
|
||||
var background = core.canvas.ui.createPattern(core.material.ground, "repeat");
|
||||
core.fillRect('ui', left, top, right, bottom, background);
|
||||
core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2);
|
||||
|
||||
core.canvas.ui.textAlign = "center";
|
||||
core.fillText('ui', "虚拟键盘", 208, top+35, "#FFD700", "bold 22px Verdana");
|
||||
|
||||
core.setFont('ui', '17px Verdana');
|
||||
core.setFillStyle('ui', '#FFFFFF');
|
||||
var offset = 128-9;
|
||||
|
||||
var lines = [
|
||||
["F1","F2","F3","F4","F5","F6","F7","F8","F9","10","11"],
|
||||
["1","2","3","4","5","6","7","8","9","0"],
|
||||
["Q","W","E","R","T","Y","U","I","O","P"],
|
||||
["A","S","D","F","G","H","J","K","L"],
|
||||
["Z","X","C","V","B","N","M"],
|
||||
["-","=","[","]","\\",";","'",",",".","/","`"],
|
||||
["ES","TA","CA","SH","CT","AL","SP","BS","EN","DE"]
|
||||
]
|
||||
|
||||
lines.forEach(function (line) {
|
||||
for (var i=0;i<line.length;i++) {
|
||||
core.fillText('ui', line[i], 48+32*i, offset);
|
||||
}
|
||||
offset+=32;
|
||||
});
|
||||
|
||||
core.fillText("ui", "返回游戏", 416-80, offset-3, '#FFFFFF', 'bold 15px Verdana');
|
||||
}
|
||||
|
||||
////// 绘制“关于”界面 //////
|
||||
ui.prototype.drawAbout = function() {
|
||||
|
||||
@ -1151,11 +1224,13 @@ ui.prototype.drawHelp = function () {
|
||||
"[CTRL] 跳过对话\n" +
|
||||
"[X] 打开/关闭怪物手册\n" +
|
||||
"[G] 打开/关闭楼层传送器\n" +
|
||||
"[A] 读取自动存档(回退)\n" +
|
||||
"[S/D] 打开/关闭存/读档页面\n" +
|
||||
"[K] 打开/关闭快捷商店选择列表\n" +
|
||||
"[T] 打开/关闭工具栏\n" +
|
||||
"[ESC] 打开/关闭系统菜单\n" +
|
||||
"[H] 打开帮助页面\n"+
|
||||
"[R] 回放\n"+
|
||||
"[SPACE] 轻按(仅在轻按开关打开时有效)\n" +
|
||||
"[1] 快捷使用破墙镐\n" +
|
||||
"[2] 快捷使用炸弹/圣锤\n" +
|
||||
@ -1165,6 +1240,7 @@ ui.prototype.drawHelp = function () {
|
||||
"点任意块: 寻路并移动\n"+
|
||||
"点任意块并拖动: 指定寻路路线\n"+
|
||||
"单击勇士: 转向\n"+
|
||||
"双击勇士: 轻按(仅在轻按开关打开时有效)"
|
||||
"双击勇士: 轻按(仅在轻按开关打开时有效)\n"+
|
||||
"长按任意位置:打开虚拟键盘"
|
||||
]);
|
||||
}
|
||||
42
main.js
@ -2,7 +2,7 @@ function main() {
|
||||
|
||||
//------------------------ 用户修改内容 ------------------------//
|
||||
|
||||
this.version = "0.1"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
|
||||
this.version = "1.3.2"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
|
||||
|
||||
this.useCompress = false; // 是否使用压缩文件
|
||||
// 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。
|
||||
@ -15,11 +15,11 @@ function main() {
|
||||
this.pngs = [ // 在此存放所有可能的背景图片;背景图片最好是416*416像素,其他分辨率会被强制缩放成416*416
|
||||
// 建议对于较大的图片,在网上使用在线的“图片压缩工具”来进行压缩,以节省流量
|
||||
// 有关使用自定义背景图,请参见文档的“自定义素材”说明
|
||||
"bg.png", "yewai.png", // 依次向后添加
|
||||
"bg.png", // 依次向后添加
|
||||
];
|
||||
this.bgms = [ // 在此存放所有的bgm,和文件名一致。第一项为默认播放项
|
||||
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
'058-Slow01.mid', 'bgm.mp3', 'qianjin.mid', 'star.mid',
|
||||
'bgm.mp3', 'qianjin.mid', 'star.mid',
|
||||
];
|
||||
this.sounds = [ // 在此存放所有的SE,和文件名一致
|
||||
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
@ -53,7 +53,7 @@ function main() {
|
||||
'startButtons': document.getElementById('startButtons'),
|
||||
'playGame': document.getElementById('playGame'),
|
||||
'loadGame': document.getElementById('loadGame'),
|
||||
'aboutGame': document.getElementById('aboutGame'),
|
||||
'replayGame': document.getElementById('replayGame'),
|
||||
'levelChooseButtons': document.getElementById('levelChooseButtons'),
|
||||
'easyLevel': document.getElementById('easyLevel'),
|
||||
'normalLevel': document.getElementById('normalLevel'),
|
||||
@ -338,7 +338,7 @@ main.statusBar.image.toolbox.onclick = function () {
|
||||
////// 点击状态栏中的快捷商店时 //////
|
||||
main.statusBar.image.shop.onclick = function () {
|
||||
if (main.core.isPlaying())
|
||||
main.core.ui.drawQuickShop(true);
|
||||
main.core.openQuickShop(true);
|
||||
}
|
||||
|
||||
////// 点击状态栏中的存档按钮时 //////
|
||||
@ -356,7 +356,7 @@ main.statusBar.image.load.onclick = function () {
|
||||
////// 点击状态栏中的系统菜单时 //////
|
||||
main.statusBar.image.settings.onclick = function () {
|
||||
if (main.core.isPlaying())
|
||||
main.core.ui.drawSettings(true);
|
||||
main.core.openSettings(true);
|
||||
}
|
||||
|
||||
////// 点击“开始游戏”时 //////
|
||||
@ -376,9 +376,33 @@ main.dom.loadGame.onclick = function() {
|
||||
main.core.load();
|
||||
}
|
||||
|
||||
////// 点击“关于本塔”时 //////
|
||||
main.dom.aboutGame.onclick = function () {
|
||||
main.core.ui.drawAbout();
|
||||
////// 点击“录像回放”时 //////
|
||||
main.dom.replayGame.onclick = function () {
|
||||
|
||||
core.readFile(function (obj) {
|
||||
if (obj.name!=core.firstData.name) {
|
||||
alert("存档和游戏不一致!");
|
||||
return;
|
||||
}
|
||||
if (obj.version!=core.firstData.version) {
|
||||
alert("游戏版本不一致!");
|
||||
return;
|
||||
}
|
||||
if (!core.isset(obj.route) || !core.isset(obj.hard)) {
|
||||
alert("无效的录像!");
|
||||
return;
|
||||
}
|
||||
|
||||
core.dom.startPanel.style.display = 'none';
|
||||
core.resetStatus(core.firstData.hero, obj.hard, core.firstData.floorId, null, core.initStatus.maps);
|
||||
core.events.setInitData(obj.hard);
|
||||
core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() {
|
||||
core.setHeroMoveTriggerInterval();
|
||||
core.replay(core.decodeRoute(obj.route));
|
||||
});
|
||||
}, function () {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
////// 点击“简单难度”时 //////
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
margin-top: 8%;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
font: bold 4rem 华文行楷;
|
||||
font: bold 4rem STXingkai;
|
||||
}
|
||||
|
||||
#startTitle {
|
||||
@ -147,7 +147,7 @@
|
||||
|
||||
#logoLabel {
|
||||
margin-top: 8%;
|
||||
font: bold 3rem 华文行楷;
|
||||
font: bold 3rem STXingkai;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
@ -169,7 +169,7 @@
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
background: url(images/ground.png) round;
|
||||
background: url(images/ground.png) repeat;
|
||||
z-index: 7;
|
||||
display: none;
|
||||
}
|
||||
@ -198,7 +198,7 @@
|
||||
}
|
||||
#toolBar {
|
||||
position: absolute;
|
||||
background: url(images/ground.png) round;
|
||||
background: url(images/ground.png) repeat;
|
||||
z-index: 6;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
|
||||
@ -3,14 +3,17 @@
|
||||
=== 全局 ===
|
||||
[↑][↓][←][→] 移动勇士
|
||||
[CTRL] 跳过对话
|
||||
[Z] 转向
|
||||
[X] 打开/关闭怪物手册
|
||||
[G] 打开/关闭楼层传送器
|
||||
[A] 读取自动存档
|
||||
[S] 打开/关闭存档页面
|
||||
[D] 打开/关闭读档页面
|
||||
[K] 打开/关闭快捷商店选择列表
|
||||
[T] 打开/关闭工具栏
|
||||
[ESC] 打开/关闭系统菜单
|
||||
[H] 打开帮助页面
|
||||
[R] 回放
|
||||
[SPACE] 轻按(仅在轻按开关打开时有效)
|
||||
[1] 快捷使用破墙镐
|
||||
[2] 快捷使用炸弹/圣锤(先检测有没有炸弹,没有再检测圣锤)
|
||||
|
||||
21
更新说明.txt
@ -1,4 +1,23 @@
|
||||
HTML5魔塔样板V1.3:
|
||||
HTML5魔塔样板V1.3.2
|
||||
|
||||
增加录像和回放功能。
|
||||
增加统计功能,现在能看到每部塔的游戏人数、通关人数和当前MAX了。
|
||||
增加浏览地图功能,玩家可以快速查看每层楼的地图。
|
||||
现在保存文件到本地,以及从本地文件读档了。
|
||||
可以在全局开关中设置剑盾是否作为装备存在。
|
||||
修复了部分已知Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.3.1:
|
||||
|
||||
增加虚拟键盘。
|
||||
增加自动存档(回退),A键可快速读档。
|
||||
修复几处较为严重的Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.3:
|
||||
|
||||
支持全键盘操作。
|
||||
支持将某个图片作为某层的背景素材。
|
||||
|
||||