Merge remote-tracking branch 'refs/remotes/ckcz123/master' into 2.0-for-merge
Conflicts: _server/vm.js drawMapGUI.html index.html libs/core.js libs/data.js libs/enemys.js libs/icons.js libs/items.js libs/maps.js main.js project/floors/sample1.js project/images/yewai.png project/images/常用素材:如需使用请直接替换目录中的对应文件/items1:圆形宝石.png styles.css
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.
|
||||
44
README.md
@ -16,6 +16,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
|
||||
``` bash
|
||||
├── /_server/ # 为可视化地图编辑器提供一些支持的目录
|
||||
├── /docs/ # 文档目录
|
||||
├── /animates/ # 动画目录
|
||||
├── /images/ # 所有图片素材目录
|
||||
│ ├─ /常用素材/ # 可以被直接替换的素材
|
||||
│ └─ *.png # 对应的某个具体的图片素材
|
||||
@ -32,6 +33,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
|
||||
│ └─ ui.js # UI绘制信息,主要负责绘制各个UI窗口。
|
||||
├── /sounds/ # 音效目录
|
||||
├── /常用工具/ # 一些常用工具,可以辅助造塔
|
||||
│ ├─ RM动画导出器.exe # 能从RMXP中导出动画,以供H5使用。 http://github.com/ckcz123/animate_export/
|
||||
│ ├─ JS代码压缩工具.exe # 能对Javascript代码进行压缩和整合,从而减少IO请求量。 http://github.com/ckcz123/JSCompressor/
|
||||
│ ├─ 便捷PS工具.exe # 能只用复制和粘贴来快速对素材进行PS操作。 http://github.com/ckcz123/ps/
|
||||
│ ├─ 地图生成器.exe # 能从一张截图识别出来具体的数字数组,方便复刻已有的塔。 http://github.com/ckcz123/map_generator/
|
||||
@ -45,6 +47,48 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
|
||||
|
||||
## 更新说明
|
||||
|
||||
### 2018.2.9 V1.4.1
|
||||
|
||||
* [x] 改变图块(setBlock事件)。
|
||||
* [x] 同一个点的多事件处理(做法详见文档)。
|
||||
* [x] 地图中每个块的可通行方向控制(悬崖效果)。
|
||||
* [x] 动画支持带旋转和翻转的帧。
|
||||
* [x] 现在可以允许用户丢弃道具了(例如不会再使用的装备)。
|
||||
* [x] 修复行走时按键会发生动画抖动问题。
|
||||
* [x] 修复无法打开战斗动画的Bug。
|
||||
|
||||
### 2018.2.6 V1.4
|
||||
|
||||
* [x] 支持动画。
|
||||
* [x] 瞬间移动。
|
||||
* [x] 支持天气系统,可以在剧本中设置默认天气。
|
||||
* [x] 新增自定义事件-图片显示。
|
||||
* [x] 同时可以在剧本中设定多个背景素材。
|
||||
* [x] 剧情文本特性控制,人物的对话框效果。
|
||||
* [x] 单存档同步到服务器,下载到文件和读取。
|
||||
* [x] 键盘支持自动寻路操作。
|
||||
* [x] 浏览地图模式下可以查看怪物数据。
|
||||
* [x] 未成功打怪和开门则不自动存档。
|
||||
* [x] 重新支持楼梯穿透。
|
||||
* [x] 支持多结局,成绩将分开统计。
|
||||
* [x] 重构全局动画、行走动画和行走检测,大幅提升性能。
|
||||
* [x] 修复所有已知Bug。
|
||||
|
||||
### 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,5 +1,5 @@
|
||||
function editor() {
|
||||
this.version = "1.2";
|
||||
this.version = "2.0";
|
||||
this.material = {};
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ editor.prototype.init = function(callback){
|
||||
|
||||
editor.reset(function(){
|
||||
editor.drawMapBg();
|
||||
var mapArray = core.maps.getMapArray(core.status.maps, core.status.floorId);
|
||||
var mapArray = core.maps.getMapArray(core.status.maps[core.status.floorId].blocks);
|
||||
editor.map = mapArray.map(function(v){return v.map(function(v){return editor.ids[[editor.indexs[v][0]]]})});
|
||||
editor.updateMap();
|
||||
editor.currentFloorId=core.status.floorId;
|
||||
@ -28,7 +28,7 @@ editor.prototype.init = function(callback){
|
||||
editor.material.images=core.material.images;
|
||||
editor.listen(); // 开始监听事件
|
||||
var hard = 'Hard';
|
||||
core.resetStatus(core.firstData.hero, hard, core.firstData.floorId, core.initStatus.maps);
|
||||
core.resetStatus(core.firstData.hero, hard, core.firstData.floorId, null, core.initStatus.maps);
|
||||
//core.status.maps = core.clone(core.maps.initMaps(floorIds));
|
||||
core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() {
|
||||
afterCoreReset();
|
||||
@ -298,7 +298,7 @@ editor.prototype.changeFloor = function(floorId,callback) {
|
||||
editor.currentFloorData.map = editor.map.map(function(v){return v.map(function(v){return v.idnum||v||0})});
|
||||
core.changeFloor(floorId, null, core.firstData.hero.loc, null, function(){
|
||||
editor.drawMapBg();
|
||||
var mapArray = core.maps.getMapArray(core.status.maps, core.status.floorId);
|
||||
var mapArray = core.maps.getMapArray(core.status.maps[core.status.floorId].blocks);
|
||||
editor.map = mapArray.map(function(v){return v.map(function(v){return editor.ids[[editor.indexs[v][0]]]})});
|
||||
editor.updateMap();
|
||||
editor.currentFloorId=core.status.floorId;
|
||||
@ -318,9 +318,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; }//返回可用的组件内坐标
|
||||
@ -453,9 +455,11 @@ editor.prototype.listen = function() {
|
||||
|
||||
edata.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;
|
||||
|
||||
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)});
|
||||
@ -10,15 +10,13 @@ iconLib.onmousedown = function(e){
|
||||
}
|
||||
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+='['
|
||||
@ -43,7 +41,9 @@ var exportM = new Vue({
|
||||
filestr += ']'+(yy==12?'':',\n');
|
||||
}
|
||||
pout.value = filestr;
|
||||
|
||||
editArea.mapArr = filestr;
|
||||
this.isExport = true;
|
||||
editArea.error = 0;
|
||||
tip.whichShow = 2;
|
||||
}
|
||||
}
|
||||
@ -65,10 +65,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);
|
||||
@ -108,7 +113,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('],[');
|
||||
|
||||
@ -129,7 +135,6 @@ var editArea = new Vue({
|
||||
}
|
||||
formatArrStr += ']'+(i==12?'':',\n');
|
||||
}
|
||||
|
||||
return formatArrStr;
|
||||
}
|
||||
}
|
||||
|
||||
24
docs/api.md
@ -1,6 +1,6 @@
|
||||
# 附录:API列表
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
所有系统支持的API都列在了这里。所有可能被用到的API都在前面用\*标记。
|
||||
|
||||
@ -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 // 让勇士开始移动
|
||||
@ -146,7 +148,6 @@ core.addGlobalAnimate // 添加一个全局动画
|
||||
core.removeGlobalAnimate // 删除一个或所有全局动画
|
||||
core.setGlobalAnimate // 设置全局动画的显示效果
|
||||
core.syncGlobalAnimate // 同步所有的全局动画效果
|
||||
core.setBoxAnimate // 显示UI层某个box的动画(如怪物手册中怪物的动画)
|
||||
core.drawBoxAnimate // 绘制UI层的box动画
|
||||
core.updateCheckBlock // 更新领域、夹击、阻击的伤害地图
|
||||
core.checkBlock // 检查并执行领域、夹击、阻击事件
|
||||
@ -176,18 +177,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 +206,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 +251,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 +272,7 @@ core.events.changeLight // 改变亮灯(感叹号)的事件
|
||||
* core.events.afterLoadData // 读档事件后,载入事件前,可以执行的操作
|
||||
|
||||
// ------ 点击事件和键盘事件的处理 ------
|
||||
core.events.longClick // 长按
|
||||
core.events.keyDownCtrl // 按下Ctrl键时(快捷跳过对话)
|
||||
core.events.clickConfirmBox // 确认框界面时的点击操作
|
||||
core.events.keyUpConfirmBox // 确认框界面时,放开某个键的操作
|
||||
@ -273,6 +286,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 +311,7 @@ core.events.keyUpSettings // 系统菜单栏界面时,放开某个键的操作
|
||||
core.events.clickSyncSave // 同步存档界面时的点击操作
|
||||
core.events.keyDownSyncSave // 同步存档界面时,按下某个键的操作
|
||||
core.events.keyUpSyncSave // 同步存档界面时,放开某个键的操作
|
||||
core.events.clickKeyBoard // 虚拟键盘界面时的点击操作
|
||||
core.events.clickAbout // “关于”界面时的点击操作
|
||||
```
|
||||
|
||||
@ -341,6 +358,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 // 绘制一个缩略图
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# 元件说明
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。
|
||||
|
||||
@ -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,9 +149,41 @@ floorId指定的是目标楼层的唯一标识符(ID)。
|
||||
|
||||
可以指定time,指定后切换动画时长为指定的数值。
|
||||
|
||||
楼梯和传送门默认可`"穿透"`。所谓穿透,就是当寻路穿过一个楼梯/传送门后,不会触发楼层传送事件,而是继续前进。通过系统Flag可以指定是否穿透,你也可以对每个传送点单独设置该项。
|
||||
## 动画和天气系统
|
||||
|
||||

|
||||
现在我们的H5魔塔支持播放动画,也支持天气系统了。
|
||||
|
||||
要播放动画,你需要先使用“RM动画导出器”将动画导出,放在animates目录下,然后在main.js中定义。
|
||||
|
||||
``` js
|
||||
this.animates = [// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名
|
||||
// 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符
|
||||
"hand", "sword", "zone", "yongchang", "thunder" // 根据需求自行添加
|
||||
]
|
||||
```
|
||||
|
||||
!> 动画必须是animate格式,名称不能使用中文,不能带空格或特殊字符。
|
||||
|
||||
目前暂时不支持带旋转和翻转的帧。
|
||||
|
||||
导出动画时可能会进行一些压缩以节省流量,因此清晰度可能不如原版。
|
||||
|
||||
动画播放时,是按照每秒20帧的速度(即50ms/帧)。
|
||||
|
||||
定义完毕后,我们可以调用`animate`事件来播放该动画,有关事件的详细介绍请参见[事件](event)。
|
||||
|
||||
!> 播放录像时,将默认忽略所有动画。
|
||||
|
||||
目前天气系统只支持雨和雪两种天气。
|
||||
|
||||
在每层楼的剧本文件里存在一个weather选项,表示该层楼的默认天气。
|
||||
|
||||
``` js
|
||||
// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。
|
||||
"weather": ["snow",5]
|
||||
```
|
||||
|
||||
我们也可以使用`setWeather`事件来设置当前天气,有关事件的详细介绍请参见[事件](event)。
|
||||
|
||||
## 背景音乐
|
||||
|
||||
@ -169,6 +208,8 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
|
||||
|
||||
!> mid格式是通过数学方法模拟出来的音乐效果,质量可能会和实际效果差距较大。
|
||||
|
||||
!> **警告!** mid格式在手机端播放可能会特别卡,仍推荐直接使用mp3/ogg来播放。
|
||||
|
||||
定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。
|
||||
|
||||
**另外,考虑到用户的流量问题,将遵循如下规则:**
|
||||
@ -190,17 +231,21 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
|
||||
- **点任意块并拖动:** 指定寻路路线
|
||||
- **单击勇士:** 转向
|
||||
- **双击勇士:** 轻按(仅在轻按开关打开时有效)
|
||||
- **长按任意位置:** 打开虚拟键盘
|
||||
|
||||
键盘操作快捷键如下:
|
||||
|
||||
- **[CTRL]** 跳过对话
|
||||
- **[X]** 打开/关闭怪物手册
|
||||
- **[G]** 打开/关闭楼层传送器
|
||||
- **[A]** 读取自动存档
|
||||
- **[S/D]** 打开/关闭存/读档页面
|
||||
- **[K]** 打开/关闭快捷商店选择列表
|
||||
- **[T]** 打开/关闭工具栏
|
||||
- **[ESC]** 打开/关闭系统菜单
|
||||
- **[H]** 打开帮助页面
|
||||
- **[Z]** 转向
|
||||
- **[R]** 回退
|
||||
- **[SPACE]** 轻按(仅在轻按开关打开时有效)
|
||||
- **[1]** 快捷使用破墙镐
|
||||
- **[2]** 快捷使用炸弹/圣锤
|
||||
|
||||
249
docs/event.md
@ -1,6 +1,6 @@
|
||||
# 事件
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
本章内将对样板所支持的事件进行介绍。
|
||||
|
||||
@ -16,7 +16,8 @@
|
||||
- 启用状态下,该事件才处于可见状态,可被触发、交互与处理。
|
||||
- 禁用状态下该事件相当于不存在,不可见、不可被触发、不可交互。
|
||||
|
||||
所有事件默认情况下都是启用的,除非指定了`enable: false`。
|
||||
所有事件默认情况下都是启用的,除非指定了`enable: false`。
|
||||
|
||||
在事件列表中使用`type: show`和`type: hide`可以将一个禁用事件启用,或将一个启用事件给禁用。
|
||||
|
||||
|
||||
@ -213,6 +214,25 @@
|
||||
]
|
||||
```
|
||||
|
||||
除此以外,我们还能实现“对话框效果”,只要有`\b[...]`就可以。
|
||||
|
||||
- `\b[up]` 直接显示在当前点上方。同样把这里的up换成down则为下方。
|
||||
- 如果不存在当前点(如在firstArrive中调用),则显示在屏幕最上方(最下方)
|
||||
- `\b[up,hero]` 显示在勇士上方。同样把这里的up换成down则为下方。
|
||||
- `\b[up,x,y]` 显示在(x,y)点的上方(下方);x和y都为整数且在0到12之间。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
"\b[up]这段文字显示在当前点上方",
|
||||
"\b[down]这段文字显示在当前点上方",
|
||||
"\t[hero]\b[up,hero]这是一段勇士说的话,会显示在勇士上方",
|
||||
"\t[小妖精,fairy]\b[down,2,2]这是一段小妖精说的话,会显示在(2,2)点下方",
|
||||
]
|
||||
```
|
||||
|
||||
!> `\t[...]`必须在`\b[...]`前面!不然两者都无法正常显示。
|
||||
|
||||
|
||||
另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。
|
||||
|
||||
``` js
|
||||
@ -241,6 +261,25 @@
|
||||
|
||||

|
||||
|
||||
### setText:设置剧情文本的属性
|
||||
|
||||
使用`{"type": "setText"}`可以设置剧情文本的各项属性。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "setText", "position": "up", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3]},
|
||||
"这段话将显示在上方,标题为红色,正文为黄色,背景为透明度0.3的蓝色"
|
||||
]
|
||||
```
|
||||
|
||||
position为可选项,表示设置文字显示位置。只能为up(上),center(中)和down(下)三者。
|
||||
|
||||
title为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示标题(名字)颜色。
|
||||
|
||||
text为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示正文颜色。
|
||||
|
||||
background为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示背景色。
|
||||
|
||||
### tip:显示一段提示文字
|
||||
|
||||
`{"type": "tip"}`可以在左上角显示一段提示文字。
|
||||
@ -380,13 +419,40 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不
|
||||
]
|
||||
```
|
||||
|
||||
### setBlock:设置某个图块
|
||||
|
||||
我们可以采用 `{"type": "setBlock"}` 来改变某个地图块。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "setBlock", "floorId": "MT1", "loc": [3,3], "number": 233}, // 将MT1层的(3,3)点变成数字233
|
||||
{"type": "setBlock", "loc": [2,1], "number": 121}, // 省略floorId则默认为本层
|
||||
{"type": "setBlock", "number": 57}, // loc也可省略,默认为当前点
|
||||
]
|
||||
```
|
||||
|
||||
floorId为可选的,表示要更改的目标楼层。如果忽略此项,则默认为当前楼层。
|
||||
|
||||
loc为可选的,表示要更改地图块的坐标。如果忽略此项,则默认为当前事件点。
|
||||
|
||||
number为**要更改到的数字**,有关“数字”的定义详见参见[素材的机制](personalization#素材的机制)。
|
||||
|
||||
图块更改后:
|
||||
|
||||
- 其启用/禁用状态不会发生任何改变。原来是启用还是启用,原来是禁用还是禁用。
|
||||
- 可通行状态遵循覆盖原则,即**首先取该图块的默认noPass属性,如果剧本的events中定义该点的noPass则覆盖**。
|
||||
- 触发器(trigger)亦采用覆盖原则,即**首先取该图块的默认触发器(例如怪物是battle,道具是getItem,门是openDoor),如果剧本的events中定义了该点的trigger则覆盖**。
|
||||
|
||||
图块更改往往与[同一个点的多事件处理](#同一个点的多事件处理)相关。
|
||||
|
||||
### update: 立刻更新状态栏和地图显伤
|
||||
|
||||
当我们在上面调用show事件,显示一个怪物后,该怪物将不会有显伤显示。如果你需要刷新状态栏和地图显伤,只需要简单地调用 `{"type": "update"}` 即可。
|
||||
如果你需要刷新状态栏和地图显伤,只需要简单地调用 `{"type": "update"}` 即可。
|
||||
|
||||
### sleep: 等待多少毫秒
|
||||
|
||||
等价于RMXP中的"等待x帧",不过是以毫秒来计算。
|
||||
|
||||
基本写法:`{"type": "sleep", "time": xxx}` ,其中xxx为指定的毫秒数。
|
||||
|
||||
``` js
|
||||
@ -465,6 +531,8 @@ direction为可选的,指定的话将使勇士的朝向变成该方向
|
||||
|
||||
time为可选的,指定的话将作为楼层切换动画的时间。
|
||||
|
||||
**time也可以置为0,如果为0则没有楼层切换动画。**
|
||||
|
||||
!> **changeFloor到达一个新的楼层,将不会执行firstArrive事件!如有需求请在到达点设置自定义事件,然后使用type: trigger立刻调用之。**
|
||||
|
||||
### changePos: 当前位置切换/勇士转向
|
||||
@ -489,6 +557,48 @@ time为可选的,指定的话将作为楼层切换动画的时间。
|
||||
|
||||
使用disableShop可以永久禁用全局商店直到再次被openShop打开为止。有关全局商店的说明可参见[全局商店](#全局商店)。
|
||||
|
||||
### animate:显示动画
|
||||
|
||||
我们可以使用 `{"type": "animate"}` 来显示一段动画。
|
||||
|
||||
有关动画的详细介绍可参见[动画和天气系统](element#动画和天气系统)。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "animate", "name": "yongchang", "loc": [1,3]}, // 在(1,3)显示“咏唱魔法”动画
|
||||
{"type": "animate", "name": "zone", "loc": "hero"}, // 在勇士位置显示“领域”动画
|
||||
{"type": "animate", "name": "hand"} // 可以不指定loc,则默认为当前事件点
|
||||
]
|
||||
```
|
||||
|
||||
name为动画名,**请确保动画在main.js中的this.animates中被定义过。**
|
||||
|
||||
loc为动画的位置,可以是`[x,y]`表示在(x,y)点显示,也可以是字符串`"hero"`表示在勇士点显示。
|
||||
|
||||
loc可忽略,如果忽略则显示为事件当前点。
|
||||
|
||||
在动画播放结束后才会继续执行下一个事件。
|
||||
|
||||
### showImage:显示图片
|
||||
|
||||
我们可以使用 `{"type": "showImage"}` 来显示一张图片。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "showImage", "name": "bg", "loc": [231,297]}, // 在(231,297)显示bg.png
|
||||
{"type": "showImage", "name": "1", "loc": [109,167]}, // 在(109,167)显示1.png
|
||||
{"type": "showImage"} // 如果不指定name则清除所有图片。
|
||||
]
|
||||
```
|
||||
|
||||
name为图片名。**请确保图片在main.js中的this.pngs中被定义过。**
|
||||
|
||||
loc为图片左上角坐标,以像素为单位进行计算。
|
||||
|
||||
如果不指定name则清除所有显示的图片。
|
||||
|
||||
调用show/hide/move/animate等几个事件同样会清除所有显示的图片。
|
||||
|
||||
### setFg: 更改画面色调
|
||||
|
||||
我们可以使用 `{"type": "setFg"}` 来更改画面色调。
|
||||
@ -509,6 +619,26 @@ color为需要更改画面色调的颜色。它是一个数组,分别指定目
|
||||
|
||||
time为可选的,如果指定,则会作为更改画面色调的时间。
|
||||
|
||||
### setWeather:更改天气
|
||||
|
||||
我们可以使用 `{"type": "setWeather"}` 来更改天气。
|
||||
|
||||
``` js
|
||||
"x,y": [ // 实际执行的事件列表
|
||||
{"type": "setWeather", "name": "rain", "level": 6}, // 更改为雨天,强度为6级
|
||||
{"type": "setWeather", "name": "snow", "level": 3}, // 更改为雪天,强度为3级
|
||||
{"type": "setWeather"} // 更改回晴天
|
||||
]
|
||||
```
|
||||
|
||||
name为天气选项。目前只支持`rain`和`snow`,即雨天和雪天。
|
||||
|
||||
level为天气的强度等级,在1-10之间。1级为最弱,10级为最强。
|
||||
|
||||
如果想改回晴天则直接不加任何参数。
|
||||
|
||||
!> 使用setWeather更改的天气在切换地图后会被目标地图的默认天气覆盖。
|
||||
|
||||
### move: 让某个NPC/怪物移动
|
||||
|
||||
如果我们需要移动某个NPC或怪物,可以使用`{"type": "move"}`。
|
||||
@ -798,6 +928,81 @@ core.insertAction(list) //往当前事件列表中插入一系列事件。使用
|
||||
// ……
|
||||
```
|
||||
|
||||
## 同一个点的多事件处理
|
||||
|
||||
我们可以发现,就目前而且,每个点的事件是和该点进行绑定,并以该点坐标作为唯一索引来查询。
|
||||
|
||||
而有时候,我们往往需要在同一个点存在多个不同的事件。这涉及到同一个点的多事件处理。
|
||||
|
||||
我们可以依靠两来实现。**`setBlock`事件**和**if+flag的条件判断**。
|
||||
|
||||
下面以几个具体例子来进行详细说明。
|
||||
|
||||
### 打怪掉宝(怪物->道具)
|
||||
|
||||
我们注意到怪物和道具都是系统默认事件,因此无需写events,而是直接在afterBattle中setBlock即可。
|
||||
|
||||
``` js
|
||||
"afterBattle": {
|
||||
"x,y": [
|
||||
{"type": "setBlock", "number": 21} // 变成黄钥匙。注意是当前点因此可省略floorId和loc
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 打怪变成可对话的NPC(怪物->NPC)
|
||||
|
||||
由于NPC是自定义事件,因此我们需要写events。注意到events中不覆盖trigger,则还是怪物时,存在系统trigger因此会战斗;变成NPC后没有系统trigger因此会触发自定义事件。
|
||||
|
||||
``` js
|
||||
"events": {
|
||||
"x,y": [
|
||||
"可对话的NPC"
|
||||
]
|
||||
},
|
||||
"afterBattle": {
|
||||
"x,y": [
|
||||
{"type": "setBlock", "number": 121} // 变成老人
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 获得圣水后变成墙
|
||||
|
||||
这个例子要求获得圣水时不前进(也就是不能走到圣水地方),然后把圣水位置变成墙。
|
||||
|
||||
因此需要我们需要覆盖系统trigger(getItem),并覆盖noPass。
|
||||
|
||||
通过if来判断有没有获得圣水,没有则触发圣水(生命x2)然后变成墙,否则不执行。
|
||||
|
||||
``` js
|
||||
"events": {
|
||||
"x,y": {
|
||||
"trigger": "action", // 覆盖系统trigger,默认的getItem不会执行
|
||||
"noPass": true, // 覆盖可通行状态,不允许走到该点
|
||||
"data": [
|
||||
{"type": "if", "condition": "flag:hasSuperPotion", // 条件判断:是否喝过圣水
|
||||
"true": [], // 喝过了,不执行
|
||||
"false": [
|
||||
{"type":"setValue", "name":"status:hp", "value":"status:hp*2"}, // 生命翻倍
|
||||
{"type":"setBlock", "number": 1}, // 将该点变成墙
|
||||
{"type":"setValue", "name":"flag:hasSuperPotion", "value": "true"} // 标记已经喝过了
|
||||
]
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
总之,记住如下两点:
|
||||
|
||||
- 可以使用setBlock来更改一个图块。
|
||||
- 可通行状态遵循覆盖原则,即**首先取该图块的默认noPass属性,如果剧本的events中定义该点的noPass则覆盖**。
|
||||
- 触发器(trigger)亦采用覆盖原则,即**首先取该图块的默认触发器(例如怪物是battle,道具是getItem,门是openDoor),如果剧本的events中定义了该点的trigger则覆盖**。
|
||||
- 可以通过if语句和flag来控制自定义事件具体走向哪个分支。
|
||||
- 如果弄不清楚系统trigger和自定义事件等的区别,也可以全部覆盖为自定义事件,然后通过type:battle,type:openDoor等来具体进行控制。
|
||||
|
||||
## 加点事件
|
||||
|
||||
打败怪物后可以进行加点。
|
||||
@ -844,8 +1049,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 +1076,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 +1092,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 +1174,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 |
@ -1,6 +1,6 @@
|
||||
# HTML5 魔塔样板说明文档
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。
|
||||
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# 个性化
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。
|
||||
|
||||
@ -27,27 +27,35 @@
|
||||
|
||||
由于HTML5功能(素材)有限,导致了对很多比较复杂的素材(比如房子内)等无法有着较好的绘图方式。
|
||||
|
||||
为了解决这个问题,我们允许用户自己放置一张图片作为某一层的背景素材。
|
||||
为了解决这个问题,我们允许用户自己放置一张或多张图片作为某一层的背景素材。
|
||||
|
||||
要启用这个功能,我们首先需要在`main.js`中将可能的图片进行加载。
|
||||
|
||||
``` js
|
||||
this.pngs = [ // 在此存放所有可能的背景图片;背景图片最好是416*416像素,其他分辨率会被强制缩放成416*416
|
||||
// 建议对于较大的图片,在网上使用在线的“图片压缩工具”来进行压缩,以节省流量
|
||||
"bg.png", // "yewai.png",
|
||||
this.pngs = [ // 在此存放所有可能使用的图片,只能是png格式,可以不写后缀名
|
||||
// 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。
|
||||
// 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
// 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量
|
||||
"bg", // 依次向后添加
|
||||
];
|
||||
```
|
||||
|
||||
!> 背景素材只支持png格式,且会被强制缩放到416*416。
|
||||
!> 背景素材只支持png格式。
|
||||
|
||||
!> 请使用网上的一些[在线图片压缩工具](http://www.asqql.com/gifzip/)对png图片进行压缩,以节省流量。一张500KB的png图片可以被压缩到20-30KB,显示效果不会有太大差异。
|
||||
!> 请使用网上的一些[在线图片压缩工具](http://compresspng.com/zh/)对png图片进行压缩,以节省流量。一张500KB的png图片可以被压缩到20-30KB,显示效果不会有太大差异。
|
||||
|
||||
之后,我们可以在每层剧本的`"png": "xxx"`里来定义该层的默认背景图片素材。
|
||||
之后,我们可以在每层剧本的`"png"`里来定义该层的默认背景图片素材。
|
||||
|
||||
``` js
|
||||
"png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。
|
||||
"png": [[x,y,"bg"]], // 背景图;你可以选择一张或多张png图片来作为背景素材。
|
||||
"png": [], // 无任何背景图
|
||||
"png": [[1,1,"house"], [6,7,"house2"]] // 在(1,1)放一个house.png,且(6,7)放house2.png
|
||||
```
|
||||
|
||||
png为一个数组,代表当前层所有作为背景素材的图片信息。
|
||||
|
||||
每一项为一个三元组,分别为该背景素材的x,y和图片名。其中x和y分别为横纵坐标,在0-12之间;图片名则必须在上面的this.pngs中定义过。
|
||||
|
||||
你的图片背景素材将会覆盖原来本身的背景层。
|
||||
|
||||
**如果你需要让某些点不可通行(比如你建了个房子,墙壁和家具等位置不让通行),则需在`events`中指定`{"noPass": false}`,参见[自定义事件](event#自定义事件)的写法。
|
||||
@ -213,15 +221,23 @@ if (itemId === 'shield5') {
|
||||
core.setFlag("shield5", true); // 增加一个自定义Flag:已经拿到神圣盾
|
||||
}
|
||||
```
|
||||
2. 免疫吸血效果:在`enemys.js`的getExtraDamage函数中,编辑成如果存在神圣盾标记,额外伤害为0。
|
||||
2. 免疫吸血效果:在`enemys.js`的伤害计算中,编辑成如果存在神圣盾标记,吸血伤害为0。
|
||||
``` js
|
||||
enemys.prototype.getExtraDamage = function (monster) {
|
||||
var extra_damage = 0;
|
||||
if (this.hasSpecial(monster.special, 11)) { // 吸血
|
||||
// 吸血的比例
|
||||
extra_damage = core.status.hero.hp * monster.value;
|
||||
if (core.hasFlag("shield5")) extra_damage = 0; // 如果存在神圣盾,则免疫吸血
|
||||
extra_damage = parseInt(extra_damage);
|
||||
enemys.prototype.calDamage = function (monster, hero_hp, hero_atk, hero_def, hero_mdef) {
|
||||
// ... 上略
|
||||
// 吸血
|
||||
if (this.hasSpecial(mon_special, 11)) {
|
||||
var vampireDamage = hero_hp * monster.value;
|
||||
|
||||
// 如果有神圣盾免疫吸血等可以在这里写
|
||||
if (core.hasFlag("shield5")) vampireDamage = 0; // 存在神圣盾,吸血伤害为0
|
||||
|
||||
vampireDamage = parseInt(vampireDamage);
|
||||
// 加到自身
|
||||
if (monster.add) // 如果加到自身
|
||||
mon_hp += vampireDamage;
|
||||
|
||||
initDamage += vampireDamage;
|
||||
}
|
||||
// ... 下略
|
||||
```
|
||||
@ -255,8 +271,6 @@ core.prototype.checkBlock = function () {
|
||||
|
||||
如果要修改伤害计算公式,请修改下面的calDamage函数。请注意,如果无法战斗,该函数必须返回`999999999`。
|
||||
|
||||
对于吸血怪的额外伤害计算在getExtraDamage中。
|
||||
|
||||
对于毒衰弱怪物的战斗后结算在`events.js`中的afterBattle函数中。
|
||||
|
||||
对于领域、夹击、阻击怪物的检查在`events.js`中的checkBlock函数中。
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
# 快速上手
|
||||
|
||||
?> 上次更新时间:* {docsify-updated} *
|
||||
?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
|
||||
|
||||
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
|
||||
|
||||
@ -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`,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!
|
||||
做完后保存所有文件,在本地服务器中“启动游戏”,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!
|
||||
|
||||

|
||||
|
||||
|
||||
@ -179,7 +179,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>
|
||||
@ -256,6 +256,8 @@
|
||||
<!-- <canvas class='gameCanvas' id='event' width='416' height='416'></canvas> -->
|
||||
<canvas class='gameCanvas' id='fg' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='hero' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='animate' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='weather' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='ui' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
|
||||
</div>
|
||||
@ -284,6 +286,7 @@
|
||||
|
||||
<script src='_server/vendor/vue.min.js'></script>
|
||||
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
|
||||
<script src='_server/vendor/polyfill.min.js'></script>
|
||||
<script src='_server/fs.js'></script>
|
||||
<script src='_server/editor_file.js'></script>
|
||||
<script src='_server/editor_mode.js'></script>
|
||||
|
||||
@ -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>
|
||||
@ -109,11 +109,13 @@
|
||||
<canvas class='gameCanvas' id='event' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='fg' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='hero' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='animate' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='weather' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='ui' width='416' height='416'></canvas>
|
||||
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
|
||||
</div>
|
||||
<script id='mainScript' src='main.js'></script>
|
||||
<script>main.init();main.listen();</script>
|
||||
<script src='libs/thirdparty/mid.js'></script>
|
||||
<script src='libs/thirdparty/mid.min.js'></script>
|
||||
</body>
|
||||
</html>
|
||||
2262
libs/core.js
105
libs/enemys.js
@ -19,7 +19,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;
|
||||
}
|
||||
|
||||
////// 获得所有特殊属性的名称 //////
|
||||
@ -48,6 +57,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;
|
||||
}
|
||||
|
||||
@ -76,16 +86,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 ""
|
||||
@ -94,21 +105,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);
|
||||
}
|
||||
@ -118,14 +122,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;
|
||||
@ -139,31 +144,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;
|
||||
@ -177,42 +196,51 @@ 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;
|
||||
}
|
||||
|
||||
////// 获得当前楼层的怪物列表 //////
|
||||
enemys.prototype.getCurrentEnemys = function () {
|
||||
enemys.prototype.getCurrentEnemys = function (floorId) {
|
||||
floorId=floorId||core.status.floorId;
|
||||
var enemys = [];
|
||||
var used = {};
|
||||
var mapBlocks = core.status.thisMap.blocks;
|
||||
var mapBlocks = core.status.maps[floorId].blocks;
|
||||
for (var b = 0; b < mapBlocks.length; b++) {
|
||||
if (core.isset(mapBlocks[b].event) && !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable) && mapBlocks[b].event.cls == 'enemys') {
|
||||
var monsterId = mapBlocks[b].event.id;
|
||||
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;
|
||||
@ -228,11 +256,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),
|
||||
|
||||
935
libs/events.js
@ -20,6 +20,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;
|
||||
}
|
||||
|
||||
@ -39,13 +52,18 @@ items.prototype.getItemEffect = function(itemId, itemNum) {
|
||||
|
||||
////// “即捡即用类”道具的文字提示 //////
|
||||
items.prototype.getItemEffectTip = function(itemId) {
|
||||
if (itemId in this.itemEffectTip)return eval(this.itemEffectTip[itemId]);
|
||||
if (itemId in this.itemEffectTip && (!this.items[itemId].isEquipment || !core.flags.equipment)) {
|
||||
return eval(this.itemEffectTip[itemId]);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
////// 使用道具 //////
|
||||
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);
|
||||
@ -75,6 +93,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);
|
||||
@ -93,12 +112,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();
|
||||
}
|
||||
|
||||
////// 当前能否使用道具 //////
|
||||
@ -264,5 +313,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;
|
||||
}
|
||||
|
||||
62
libs/maps.js
@ -18,28 +18,8 @@ maps.prototype.loadFloor = function (floorId, map) {
|
||||
for (var i = 0; i < 13; i++) {
|
||||
for (var j = 0; j < 13; j++) {
|
||||
var block = maps.getBlock(j, i, map[i][j]);
|
||||
if (core.isset(block.event)) {
|
||||
if (block.event.cls == 'enemys' && block.event.trigger==undefined) {
|
||||
block.event.trigger = 'battle';
|
||||
}
|
||||
if (block.event.cls == 'items' && block.event.trigger==undefined) {
|
||||
block.event.trigger = 'getItem';
|
||||
}
|
||||
if (block.event.noPass == undefined) {
|
||||
if (block.event.cls=='enemys' || block.event.cls=='terrains' || block.event.cls=='npcs') {
|
||||
block.event.noPass = true;
|
||||
}
|
||||
}
|
||||
if (block.event.animate == undefined) {
|
||||
if (block.event.cls=='enemys' || block.event.cls=='npcs') {
|
||||
block.event.animate = 2;
|
||||
}
|
||||
if (block.event.cls == 'animates') {
|
||||
block.event.animate = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
maps.addEvent(block,j,i,floor.events[j+","+i]);
|
||||
maps.addInfo(block);
|
||||
maps.addEvent(block,j,i,floor.events[j+","+i])
|
||||
maps.addChangeFloor(block,j,i,floor.changeFloor[j+","+i]);
|
||||
if (core.isset(block.event)) blocks.push(block);
|
||||
}
|
||||
@ -79,6 +59,31 @@ maps.prototype.getBlock = function (x, y, id) {
|
||||
return tmp;
|
||||
}
|
||||
|
||||
////// 添加一些信息到block上 //////
|
||||
maps.prototype.addInfo = function (block) {
|
||||
if (core.isset(block.event)) {
|
||||
if (block.event.cls == 'enemys' && block.event.trigger==undefined) {
|
||||
block.event.trigger = 'battle';
|
||||
}
|
||||
if (block.event.cls == 'items' && block.event.trigger==undefined) {
|
||||
block.event.trigger = 'getItem';
|
||||
}
|
||||
if (block.event.noPass == undefined) {
|
||||
if (block.event.cls=='enemys' || block.event.cls=='terrains' || block.event.cls=='npcs') {
|
||||
block.event.noPass = true;
|
||||
}
|
||||
}
|
||||
if (block.event.animate == undefined) {
|
||||
if (block.event.cls=='enemys' || block.event.cls=='npcs') {
|
||||
block.event.animate = 2;
|
||||
}
|
||||
if (block.event.cls == 'animates') {
|
||||
block.event.animate = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////// 向该楼层添加剧本的自定义事件 //////
|
||||
maps.prototype.addEvent = function (block, x, y, event) {
|
||||
if (!core.isset(event)) return;
|
||||
@ -178,16 +183,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++) {
|
||||
@ -196,7 +192,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;
|
||||
});
|
||||
|
||||
1
libs/thirdparty/mid.min.js
vendored
Normal file
387
libs/ui.js
@ -15,7 +15,6 @@ main.instance.ui = new ui();
|
||||
////// 结束一切事件和绘制,关闭UI窗口,返回游戏进程 //////
|
||||
ui.prototype.closePanel = function () {
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.setBoxAnimate();
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
core.setAlpha('ui', 1.0);
|
||||
core.unLockControl();
|
||||
@ -30,10 +29,11 @@ ui.prototype.drawTextBox = function(content) {
|
||||
|
||||
// 获得name, image, icon
|
||||
var id=null, name=null, image=null, icon=null;
|
||||
if (content.indexOf("\t[")==0) {
|
||||
if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) {
|
||||
var index = content.indexOf("]");
|
||||
if (index>=0) {
|
||||
var str=content.substring(2, index);
|
||||
if (content.indexOf("\\t[")==0) str=content.substring(3, index);
|
||||
content=content.substring(index+1);
|
||||
var ss=str.split(",");
|
||||
if (ss.length==1) {
|
||||
@ -64,10 +64,55 @@ ui.prototype.drawTextBox = function(content) {
|
||||
}
|
||||
}
|
||||
|
||||
// 获得位置信息
|
||||
|
||||
var textAttribute = core.status.textAttribute || core.initStatus.textAttribute;
|
||||
|
||||
var position = textAttribute.position, px=null, py=null, ydelta=0;
|
||||
if (content.indexOf("\b[")==0 || content.indexOf("\\b[")==0) {
|
||||
var index = content.indexOf("]");
|
||||
if (index>=0) {
|
||||
var str = content.substring(2, index);
|
||||
if (content.indexOf("\\b[")==0) str = content.substring(3, index);
|
||||
content = content.substring(index + 1);
|
||||
|
||||
var ss=str.split(",");
|
||||
|
||||
if (ss[0]=='up' || ss[0]=='center' || ss[0]=='down') {
|
||||
position=ss[0];
|
||||
if (core.status.event.id=='action') {
|
||||
px = core.status.event.data.x;
|
||||
py = core.status.event.data.y;
|
||||
}
|
||||
|
||||
if (ss.length>=2) {
|
||||
if (ss[1]=='hero') {
|
||||
px=core.getHeroLoc('x');
|
||||
py=core.getHeroLoc('y');
|
||||
ydelta = core.material.icons.hero.height-32;
|
||||
}
|
||||
else if (ss.length>=3) {
|
||||
px=parseInt(ss[1]);
|
||||
py=parseInt(ss[2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (ss.length==3) {
|
||||
px=parseInt(ss[1]);
|
||||
py=parseInt(ss[2]);
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
content = core.replaceText(content);
|
||||
|
||||
var background = core.canvas.ui.createPattern(core.material.ground, "repeat");
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
|
||||
// var contents = content.split('\n');
|
||||
// var contents = core.splitLines('ui', content, );
|
||||
var left=10, right=416-2*left;
|
||||
@ -77,16 +122,74 @@ ui.prototype.drawTextBox = function(content) {
|
||||
var validWidth = right-(content_left-left)-13;
|
||||
var contents = core.splitLines("ui", content, validWidth, '16px Verdana');
|
||||
|
||||
var height = 416 - 10 - Math.min(416-24*(contents.length+1)-65, 250);
|
||||
var top = (416-height)/2, bottom = height;
|
||||
var height = 20 + 21*(contents.length+1) + (id=='hero'?core.material.icons.hero.height-10:core.isset(name)?32-10:0);
|
||||
|
||||
|
||||
var xoffset = 6, yoffset = 22;
|
||||
|
||||
var top;
|
||||
if (position=='center') {
|
||||
top = (416 - height) / 2;
|
||||
}
|
||||
else if (position=='up') {
|
||||
if (px==null || py==null) {
|
||||
top = 5;
|
||||
}
|
||||
else {
|
||||
top = 32 * py - height - ydelta - yoffset;
|
||||
}
|
||||
}
|
||||
else if (position=='down') {
|
||||
if (px==null || py==null) {
|
||||
top = 416 - height - 5;
|
||||
}
|
||||
else {
|
||||
top = 32 * py + 32 + yoffset;
|
||||
}
|
||||
}
|
||||
|
||||
// var left = 97, top = 64, right = 416 - 2 * left, bottom = 416 - 2 * top;
|
||||
core.setAlpha('ui', 0.85);
|
||||
core.fillRect('ui', left, top, right, bottom, '#000000');
|
||||
core.setAlpha('ui', 1);
|
||||
core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2);
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.setBoxAnimate();
|
||||
//core.setAlpha('ui', 0.85);
|
||||
core.setAlpha('ui', textAttribute.background[3]);
|
||||
core.setFillStyle('ui', core.arrayToRGB(textAttribute.background));
|
||||
core.setStrokeStyle('ui', '#FFFFFF');
|
||||
|
||||
|
||||
core.fillRect('ui', left, top, right, height);
|
||||
core.strokeRect('ui', left - 1, top - 1, right + 1, height + 1, '#FFFFFF', 2);
|
||||
|
||||
var xoffset = 6;
|
||||
|
||||
// draw triangle
|
||||
if (position=='up' && core.isset(px) && core.isset(py)) {
|
||||
core.canvas.ui.clearRect(32*px+xoffset, top+height-1, 32-2*xoffset, 2);
|
||||
core.canvas.ui.beginPath();
|
||||
core.canvas.ui.moveTo(32*px+xoffset-1, top+height-1);
|
||||
core.canvas.ui.lineTo(32*px+16, top+height+yoffset-2);
|
||||
core.canvas.ui.lineTo(32*px+32-xoffset+1, top+height-1);
|
||||
core.canvas.ui.moveTo(32*px+xoffset-1, top+height-1);
|
||||
core.canvas.ui.closePath();
|
||||
core.canvas.ui.fill();
|
||||
// core.canvas.ui.stroke();
|
||||
// core.drawLine('ui', 32*px+4+1, top+height+1, 32*px + 28-1, top+height+1, core.arrayToRGB(textAttribute.background), 3);
|
||||
core.drawLine('ui', 32*px+xoffset, top+height, 32*px+16, top+height+yoffset-2);
|
||||
core.drawLine('ui', 32*px+32-xoffset, top+height, 32*px+16, top+height+yoffset-2);
|
||||
}
|
||||
if (position=='down' && core.isset(px) && core.isset(py)) {
|
||||
core.canvas.ui.clearRect(32*px+xoffset, top-2, 32-2*xoffset, 3);
|
||||
core.canvas.ui.beginPath();
|
||||
core.canvas.ui.moveTo(32*px+xoffset-1, top+1);
|
||||
core.canvas.ui.lineTo(32*px+16-1, top-yoffset+2);
|
||||
core.canvas.ui.lineTo(32*px+32-xoffset-1, top+1);
|
||||
core.canvas.ui.moveTo(32*px+xoffset-1, top+1);
|
||||
core.canvas.ui.closePath();
|
||||
core.canvas.ui.fill();
|
||||
// core.canvas.ui.stroke();
|
||||
// core.drawLine('ui', 32*px+4+1, top+height+1, 32*px + 28-1, top+height+1, core.arrayToRGB(textAttribute.background), 3);
|
||||
core.drawLine('ui', 32*px+xoffset, top, 32*px+16, top-yoffset+2);
|
||||
core.drawLine('ui', 32*px+32-xoffset, top, 32*px+16, top-yoffset+2);
|
||||
}
|
||||
|
||||
|
||||
// 名称
|
||||
core.canvas.ui.textAlign = "left";
|
||||
@ -95,36 +198,42 @@ ui.prototype.drawTextBox = function(content) {
|
||||
if (core.isset(id)) {
|
||||
|
||||
content_top = top+57;
|
||||
core.setAlpha('ui', textAttribute.title[3]);
|
||||
core.setFillStyle('ui', core.arrayToRGB(textAttribute.title));
|
||||
core.setStrokeStyle('ui', core.arrayToRGB(textAttribute.title));
|
||||
|
||||
if (id == 'hero') {
|
||||
var heroHeight=core.material.icons.hero.height;
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, '#FFD700', 2);
|
||||
core.fillText('ui', core.status.hero.name, content_left, top + 30, '#FFD700', 'bold 22px Verdana');
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, null, 2);
|
||||
core.fillText('ui', core.status.hero.name, content_left, top + 30, null, 'bold 22px Verdana');
|
||||
core.clearMap('ui', left + 15, top + 40, 32, heroHeight);
|
||||
core.fillRect('ui', left + 15, top + 40, 32, heroHeight, background);
|
||||
var heroIcon = core.material.icons.hero['down'];
|
||||
core.canvas.ui.drawImage(core.material.images.hero, heroIcon.stop * 32, heroIcon.loc * heroHeight, 32, heroHeight, left+15, top+40, 32, heroHeight);
|
||||
}
|
||||
else {
|
||||
core.fillText('ui', name, content_left, top + 30, '#FFD700', 'bold 22px Verdana');
|
||||
core.fillText('ui', name, content_left, top + 30, null, 'bold 22px Verdana');
|
||||
if (core.isset(icon)) {
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, 34, '#FFD700', 2);
|
||||
core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, 34, null, 2);
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.status.boxAnimateObjs.push({
|
||||
'bgx': left + 15, 'bgy': top + 40, 'bgsize': 32,
|
||||
'image': image, 'x': left + 15, 'y': top + 40, 'icon': icon
|
||||
});
|
||||
core.setBoxAnimate();
|
||||
core.drawBoxAnimate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
core.setAlpha('ui', textAttribute.text[3]);
|
||||
core.setFillStyle('ui', core.arrayToRGB(textAttribute.text));
|
||||
|
||||
for (var i=0;i<contents.length;i++) {
|
||||
core.fillText('ui', contents[i], content_left, content_top, '#FFFFFF', '16px Verdana');
|
||||
content_top+=24;
|
||||
core.fillText('ui', contents[i], content_left, content_top, null, '16px Verdana');
|
||||
content_top+=21;
|
||||
}
|
||||
|
||||
core.fillText('ui', '<点击任意位置继续>', 270, top+height-13, '#CCCCCC', '13px Verdana');
|
||||
// core.fillText('ui', '<点击任意位置继续>', 270, top+height-13, '#CCCCCC', '13px Verdana');
|
||||
}
|
||||
|
||||
////// 绘制一个选项界面 //////
|
||||
@ -237,7 +346,7 @@ ui.prototype.drawChoices = function(content, choices) {
|
||||
'bgx': left + 15, 'bgy': top + 30, 'bgsize': 32,
|
||||
'image': image, 'x': left + 15, 'y': top + 30, 'icon': icon
|
||||
});
|
||||
core.setBoxAnimate();
|
||||
core.drawBoxAnimate();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -257,6 +366,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 +382,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 +431,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';
|
||||
|
||||
@ -369,6 +478,22 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
|
||||
var monster = core.material.enemys[monsterId];
|
||||
var mon_hp = monster.hp, mon_atk = monster.atk, mon_def = monster.def, mon_money=monster.money, mon_exp = monster.experience, mon_special=monster.special;
|
||||
|
||||
var initDamage = 0; // 战前伤害
|
||||
|
||||
// 吸血
|
||||
if (core.enemys.hasSpecial(mon_special, 11)) {
|
||||
var vampireDamage = hero_hp * monster.value;
|
||||
|
||||
// 如果有神圣盾免疫吸血等可以在这里写
|
||||
|
||||
vampireDamage = parseInt(vampireDamage);
|
||||
// 加到自身
|
||||
if (monster.add) // 如果加到自身
|
||||
mon_hp += vampireDamage;
|
||||
|
||||
initDamage += vampireDamage;
|
||||
}
|
||||
|
||||
hero_hp -= core.enemys.getExtraDamage(monster);
|
||||
|
||||
if (core.enemys.hasSpecial(mon_special, 10)) { // 模仿
|
||||
@ -388,16 +513,9 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
|
||||
if (core.enemys.hasSpecial(mon_special, 5)) turns=4;
|
||||
if (core.enemys.hasSpecial(mon_special, 6)) turns=1+(monster.n||4);
|
||||
|
||||
|
||||
// 初始伤害
|
||||
var initDamage = 0;
|
||||
if (core.enemys.hasSpecial(mon_special, 7)) initDamage+=parseInt(core.values.breakArmor * hero_def);
|
||||
if (core.enemys.hasSpecial(mon_special, 9)) initDamage+=parseInt(core.values.purify * hero_mdef);
|
||||
if (core.enemys.hasSpecial(mon_special, 11)) { // 吸血
|
||||
var extraDamage = monster.value * hero_hp;
|
||||
initDamage+=parseInt(extraDamage);
|
||||
}
|
||||
if (core.enemys.hasSpecial(mon_special, 17)) initDamage+=core.getFlag('hatred', 0);
|
||||
hero_mdef-=initDamage;
|
||||
if (hero_mdef<0) {
|
||||
hero_hp+=hero_mdef;
|
||||
@ -433,7 +551,6 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
|
||||
core.setAlpha('data', 1);
|
||||
core.setOpacity('data', 1);
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.setBoxAnimate();
|
||||
|
||||
var margin = 35;
|
||||
var boxWidth = 40;
|
||||
@ -464,7 +581,7 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
|
||||
'bgx': left + right - margin - 40, 'bgy': top+margin, 'bgsize': boxWidth,
|
||||
'image': core.material.images.enemys, 'x': left + right - margin - 40 + (boxWidth-32)/2, 'y': top + margin + (boxWidth-32)/2, 'icon': core.material.icons.enemys[monsterId]
|
||||
});
|
||||
core.setBoxAnimate();
|
||||
core.drawBoxAnimate();
|
||||
|
||||
var lineWidth = 80;
|
||||
|
||||
@ -627,7 +744,6 @@ ui.prototype.drawBattleAnimate = function(monsterId, callback) {
|
||||
// 战斗结束
|
||||
clearInterval(battleInterval);
|
||||
core.status.boxAnimateObjs = [];
|
||||
core.setBoxAnimate();
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
core.setAlpha('ui', 1.0);
|
||||
core.clearMap('data', 0, 0, 416, 416);
|
||||
@ -654,12 +770,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,11 +790,27 @@ ui.prototype.drawSyncSave = function () {
|
||||
core.status.event.id = 'syncSave';
|
||||
|
||||
this.drawChoices(null, [
|
||||
"同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单"
|
||||
"同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "下载当前录像", "清空本地存档", "返回主菜单"
|
||||
]);
|
||||
|
||||
}
|
||||
|
||||
////// 绘制存档同步选择页面 //////
|
||||
ui.prototype.drawSyncSelect = function () {
|
||||
core.status.event.id = 'syncSelect';
|
||||
this.drawChoices(null, [
|
||||
"同步本地所有存档", "只同步最新单存档", "返回上级菜单"
|
||||
]);
|
||||
}
|
||||
|
||||
////// 绘制单存档界面 //////
|
||||
ui.prototype.drawLocalSaveSelect = function () {
|
||||
core.status.event.id = 'localSaveSelect';
|
||||
this.drawChoices(null, [
|
||||
"下载所有存档", "只下载最新单存档", "返回上级菜单"
|
||||
]);
|
||||
}
|
||||
|
||||
////// 绘制分页 //////
|
||||
ui.prototype.drawPagination = function (page, totalPage) {
|
||||
|
||||
@ -696,10 +833,34 @@ ui.prototype.drawPagination = function (page, totalPage) {
|
||||
|
||||
}
|
||||
|
||||
////// 绘制键盘光标 //////
|
||||
ui.prototype.drawCursor = function () {
|
||||
|
||||
if (!core.isset(core.status.automaticRoute.cursorX))
|
||||
core.status.automaticRoute.cursorX=core.getHeroLoc('x');
|
||||
if (core.status.automaticRoute.cursorX<0) core.status.automaticRoute.cursorX=0;
|
||||
if (core.status.automaticRoute.cursorX>12) core.status.automaticRoute.cursorX=12;
|
||||
if (!core.isset(core.status.automaticRoute.cursorY))
|
||||
core.status.automaticRoute.cursorY=core.getHeroLoc('y');
|
||||
if (core.status.automaticRoute.cursorY<0) core.status.automaticRoute.cursorY=0;
|
||||
if (core.status.automaticRoute.cursorY>12) core.status.automaticRoute.cursorY=12;
|
||||
|
||||
core.status.event.id = 'cursor';
|
||||
core.lockControl();
|
||||
|
||||
core.clearMap('ui', 0, 0, 416, 416);
|
||||
core.setAlpha('ui', 1);
|
||||
|
||||
var width = 4;
|
||||
core.strokeRect('ui', 32*core.status.automaticRoute.cursorX+width/2, 32*core.status.automaticRoute.cursorY+width/2,
|
||||
32-width, 32-width, '#FFD700', width);
|
||||
|
||||
}
|
||||
|
||||
////// 绘制怪物手册 //////
|
||||
ui.prototype.drawBook = function (index) {
|
||||
|
||||
var enemys = core.enemys.getCurrentEnemys();
|
||||
var enemys = core.enemys.getCurrentEnemys(core.floorIds[core.status.event.selection]);
|
||||
var background = core.canvas.ui.createPattern(core.material.ground, "repeat");
|
||||
|
||||
clearInterval(core.interval.tipAnimate);
|
||||
@ -809,13 +970,13 @@ ui.prototype.drawBook = function (index) {
|
||||
}
|
||||
|
||||
}
|
||||
core.setBoxAnimate();
|
||||
core.drawBoxAnimate();
|
||||
this.drawPagination(page, totalPage);
|
||||
}
|
||||
|
||||
////// 绘制怪物属性的详细信息 //////
|
||||
ui.prototype.drawBookDetail = function (index) {
|
||||
var enemys = core.enemys.getCurrentEnemys();
|
||||
var enemys = core.enemys.getCurrentEnemys(core.floorIds[core.status.event.selection]);
|
||||
if (enemys.length==0) return;
|
||||
if (index<0) index=0;
|
||||
if (index>=enemys.length) index=enemys.length-1;
|
||||
@ -902,6 +1063,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) {
|
||||
|
||||
@ -1014,22 +1207,22 @@ ui.prototype.drawToolbox = function(index) {
|
||||
|
||||
// 退出
|
||||
core.canvas.ui.textAlign = 'center';
|
||||
core.fillText('ui', '删除道具', 370, 32,'#DDDDDD', 'bold 15px Verdana');
|
||||
core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px Verdana');
|
||||
}
|
||||
|
||||
////// 绘制存档/读档界面 //////
|
||||
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 +1233,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 +1249,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');
|
||||
@ -1086,12 +1278,34 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL
|
||||
|
||||
if (core.isset(core.floors[floorId].png)) {
|
||||
var png = core.floors[floorId].png;
|
||||
/*
|
||||
if (core.isset(core.material.images.pngs[png])) {
|
||||
core.canvas.ui.drawImage(core.material.images.pngs[png], x, y, size, size);
|
||||
}
|
||||
*/
|
||||
|
||||
var ratio = size/416;
|
||||
|
||||
if (typeof png == 'string') {
|
||||
if (core.isset(core.material.images.pngs[png])) {
|
||||
core.canvas.ui.drawImage(core.material.images.pngs[png], x, y, size, size);
|
||||
}
|
||||
}
|
||||
else if (png instanceof Array) {
|
||||
png.forEach(function (t) {
|
||||
if (t.length!=3) return;
|
||||
var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2];
|
||||
if (core.isset(dx) && core.isset(dy) && core.isset(core.material.images.pngs[p])) {
|
||||
dx*=32; dy*=32;
|
||||
var image = core.material.images.pngs[p];
|
||||
core.canvas.ui.drawImage(image, x+dx*ratio, y+dy*ratio, Math.min(size-dx*ratio, ratio*image.width), Math.min(size-dy*ratio, ratio*image.height));
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 +1330,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() {
|
||||
|
||||
@ -1139,9 +1391,10 @@ ui.prototype.drawAbout = function() {
|
||||
// 名称
|
||||
core.canvas.ui.textAlign = "left";
|
||||
core.fillText('ui', "HTML5 魔塔样板", text_start, top+35, "#FFD700", "bold 22px Verdana");
|
||||
core.fillText('ui', "作者: 艾之葵", text_start, top + 80, "#FFFFFF", "bold 17px Verdana");
|
||||
core.fillText('ui', 'HTML5魔塔交流群:539113091', text_start, top+112);
|
||||
// TODO: 写自己的“关于”页面
|
||||
core.fillText('ui', "版本: "+core.firstData.version, text_start, top + 80, "#FFFFFF", "bold 17px Verdana");
|
||||
core.fillText('ui', "作者: 艾之葵", text_start, top + 112);
|
||||
core.fillText('ui', 'HTML5魔塔交流群:539113091', text_start, top+112+32);
|
||||
// TODO: 写自己的“关于”页面,每次增加32像素即可
|
||||
}
|
||||
|
||||
////// 绘制帮助页面 //////
|
||||
@ -1151,11 +1404,14 @@ ui.prototype.drawHelp = function () {
|
||||
"[CTRL] 跳过对话\n" +
|
||||
"[X] 打开/关闭怪物手册\n" +
|
||||
"[G] 打开/关闭楼层传送器\n" +
|
||||
"[A] 读取自动存档(回退)\n" +
|
||||
"[S/D] 打开/关闭存/读档页面\n" +
|
||||
"[K] 打开/关闭快捷商店选择列表\n" +
|
||||
"[T] 打开/关闭工具栏\n" +
|
||||
"[ESC] 打开/关闭系统菜单\n" +
|
||||
"[E] 显示光标\n" +
|
||||
"[H] 打开帮助页面\n"+
|
||||
"[R] 回放\n"+
|
||||
"[SPACE] 轻按(仅在轻按开关打开时有效)\n" +
|
||||
"[1] 快捷使用破墙镐\n" +
|
||||
"[2] 快捷使用炸弹/圣锤\n" +
|
||||
@ -1165,6 +1421,7 @@ ui.prototype.drawHelp = function () {
|
||||
"点任意块: 寻路并移动\n"+
|
||||
"点任意块并拖动: 指定寻路路线\n"+
|
||||
"单击勇士: 转向\n"+
|
||||
"双击勇士: 轻按(仅在轻按开关打开时有效)"
|
||||
"双击勇士: 轻按(仅在轻按开关打开时有效)\n"+
|
||||
"长按任意位置:打开虚拟键盘"
|
||||
]);
|
||||
}
|
||||
85
main.js
@ -2,7 +2,7 @@ function main() {
|
||||
|
||||
//------------------------ 用户修改内容 ------------------------//
|
||||
|
||||
this.version = "0.1"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
|
||||
this.version = "1.4.1"; // 游戏版本号;如果更改了游戏内容建议修改此version以免造成缓存问题。
|
||||
|
||||
//------------------------ 用户修改内容 END ------------------------//
|
||||
|
||||
@ -31,7 +31,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'),
|
||||
@ -77,6 +77,19 @@ function main() {
|
||||
'load': document.getElementById("img-load"),
|
||||
'settings': document.getElementById("img-settings")
|
||||
},
|
||||
'icons': {
|
||||
'book': null,
|
||||
'fly': null,
|
||||
'toolbox': null,
|
||||
'save': null,
|
||||
'load': null,
|
||||
'settings': null,
|
||||
'rewind': null, // 减速
|
||||
'forward': null, // 加速
|
||||
'play': null, // 播放
|
||||
'pause': null, // 暂停
|
||||
'stop': null, // 停止
|
||||
},
|
||||
'floor': document.getElementById('floor'),
|
||||
'lv': document.getElementById('lv'),
|
||||
'hp': document.getElementById('hp'),
|
||||
@ -107,6 +120,11 @@ main.prototype.init = function (mode) {
|
||||
main.mode = mode;
|
||||
if (mode === 'editor')main.editor = {'disableGlobalAnimate':true};
|
||||
}
|
||||
Object.keys(this.statusBar.icons).forEach(function (t) {
|
||||
var image=new Image();
|
||||
image.src="project/images/"+t+".png";
|
||||
main.statusBar.icons[t] = image;
|
||||
})
|
||||
main.loadPureData(function(){
|
||||
var mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main;
|
||||
for(var ii in mainData)main[ii]=mainData[ii];
|
||||
@ -119,7 +137,11 @@ main.prototype.init = function (mode) {
|
||||
coreData[name] = main[name];
|
||||
}
|
||||
main.loaderFloors(function() {
|
||||
main.core.init(main.dom, main.statusBar, main.canvas, main.images, main.pngs, main.bgms, main.sounds, main.floorIds, main.floors, coreData);
|
||||
["dom", "statusBar", "canvas", "images", "pngs",
|
||||
"animates", "bgms", "sounds", "floorIds", "floors"].forEach(function (t) {
|
||||
coreData[t] = main[t];
|
||||
})
|
||||
main.core.init(coreData);
|
||||
main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight);
|
||||
});
|
||||
});
|
||||
@ -323,12 +345,23 @@ main.dom.data.ontouchend = function () {
|
||||
|
||||
////// 点击状态栏中的怪物手册时 //////
|
||||
main.statusBar.image.book.onclick = function () {
|
||||
if (core.isset(core.status.replay) && core.status.replay.replaying) {
|
||||
core.triggerReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying())
|
||||
main.core.openBook(true);
|
||||
}
|
||||
|
||||
////// 点击状态栏中的楼层传送器时 //////
|
||||
main.statusBar.image.fly.onclick = function () {
|
||||
|
||||
if (core.isset(core.status.replay) && core.status.replay.replaying) {
|
||||
core.stopReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying())
|
||||
main.core.useFly(true);
|
||||
}
|
||||
@ -342,17 +375,29 @@ 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);
|
||||
}
|
||||
|
||||
////// 点击状态栏中的存档按钮时 //////
|
||||
main.statusBar.image.save.onclick = function () {
|
||||
|
||||
if (core.isset(core.status.replay) && core.status.replay.replaying) {
|
||||
core.rewindReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying())
|
||||
main.core.save(true);
|
||||
}
|
||||
|
||||
////// 点击状态栏中的读档按钮时 //////
|
||||
main.statusBar.image.load.onclick = function () {
|
||||
|
||||
if (core.isset(core.status.replay) && core.status.replay.replaying) {
|
||||
core.forwardReplay();
|
||||
return;
|
||||
}
|
||||
|
||||
if (main.core.isPlaying())
|
||||
main.core.load(true);
|
||||
}
|
||||
@ -360,7 +405,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);
|
||||
}
|
||||
|
||||
////// 点击“开始游戏”时 //////
|
||||
@ -380,9 +425,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 (core.isset(obj.version) && 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.startReplay(core.decodeRoute(obj.route));
|
||||
});
|
||||
}, function () {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
////// 点击“简单难度”时 //////
|
||||
|
||||
1
project/animates/hand.animate
Normal file
1
project/animates/jianji.animate
Normal file
1
project/animates/sword.animate
Normal file
@ -0,0 +1 @@
|
||||
{"ratio":2,"bitmaps":["data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAD6SURBVHhe7dQ9SsVAFAXg+MNTeAhaWCrWLsHGUlCwsHMXgo2NjZ31a1yBVtaCrSvQ1i24hSSegbuEBAS/Dw7M3JnqZEgHAAAAAAAAAAAAAP/NOI5rySI5GobhNDlJ9uuYqaXo9RR83Pf9U/KevGV/kxwkW+2D1FWmkmKXKfYuZf8k38lrZpeZHSaLusaU2ktOyRcp+zP5Sl6yv858t53VNaaWcrdT9mPSXvpHskrxO3XMnNpvJYW3F/+Q9XmNmVv7raT055R+n/VejZlbyt5M6VfJbdYbNWZureyUvkzOagQAAAAAAAAAAAAAAAAAAAAAAAAAAADwd3XdL135q9NaPZ6+AAAAAElFTkSuQmCC","data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABgCAYAAADimHc4AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAJ4SURBVHhe7de7alRRFMbx3DSIgqiNIBJsBUUESyutBAsLO9/CWtL4BtorlgFBRGIEEQwxMSBiMWouGo2TCyaTC0lmJjM5ey+/HVfeYPZB8P+DNefsS/WdxZ5zugAAAAAAAAAAAAAAAAAAAID/lZkdVnX7ELmkkA+C1rU3xngthHBf1xsa9+1vQmcdhK7qUdAXFPh4URSjur+r6vdt6DQP/ZDqkkL/ZlZs6jqh8WnfghzU1UcOQlclmop3fBk5KPA+hXxRYb9LiWtsujR0Oe5b0Gke+hUF/TaFLtHrh29BDgr9jEJOoReqeur2RPfTvgWdpnzTG8yAQm6oYgq8uWfWLvaD1y+vkNko3G6FPJ9CT7ZbZpVVs9m1/Ydw3bchB3X9+dTxqVLwk4tmH1T1VnjlW5CDGj11/XDq+HTgfFwye/rVbKpmNjzDx1N2Cn8jhb+qF8mRObOX381m1sPww4od8y3IQZn3KPzdogjNyorZ8xmzaXX9cjOe8y3IxcNvNtq2OV41ezFrttYMv30ZOSn8dOavqBrjC3+PnfVGvOfLyE0P4HH6qhr9Zfbmp7p/Lg74EnJT+LdbeyGk4F/PhfhgMp7yJeSm9/yTavza2HyIYwuhPTRkvb6E3NT5fQr/2cRS2HhfDfVB/Qn7EnJLf7rq/pvTq6H9uRa2fBplSOGrTixvhdrUWqj7NMqi8HsV/shsLez5FMq004qXq+th14cok879/upO+FKp2GGfQll09PSsNOLVxXq85VMoUzr7F7fDIx+iTOnNR8fP2UGOnvKl8NPx8+RTPOpTKFt6CH4LAAAAAAAAAAAAAAAAAAAAAAAAAACAf1RX1x9x4x3SPdhnTAAAAABJRU5ErkJggg==","","","","","","","","","","","","","","","","","",""],"frame_max":5,"frames":[[[0,8,32,30,100]],[[0,-16,32,50,130]],[[0,-24,40,80,150]],[[0,-48,24,90,180],[1,-8,40,100,255]],[[0,-56,24,100,200],[1,-8,24,100,255]]]}
|
||||
1
project/animates/thunder.animate
Normal file
1
project/animates/yongchang.animate
Normal file
1
project/animates/zone.animate
Normal file
@ -4,7 +4,8 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
|
||||
'items':{
|
||||
'cls': "只能取keys(钥匙) items(宝石、血瓶) constants(物品) tools(道具)\n$select({\"values\":[\"keys\",\"items\",\"constants\",\"tools\"]})$end",
|
||||
'name': '名称',
|
||||
'text': '道具在道具栏中显示的描述'
|
||||
'text': '道具在道具栏中显示的描述',
|
||||
'isEquipment': '物品是否属于装备(仅在core.flags.equipment时有效)\n$select({\"values\":[true,false]})$end'
|
||||
},
|
||||
'itemEffect':'cls为items的即捡即用类物品的效果,执行时会对这里的字符串执行eval()',
|
||||
'itemEffectTip':'cls为items的即捡即用类物品,在获得时左上角额外显示的文字,执行时会对这里的字符串执行eval()得到字符串'
|
||||
|
||||
@ -3,7 +3,8 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"main": {
|
||||
"useCompress": " 是否使用压缩文件 \n 当你即将发布你的塔时,请使用“JS代码压缩工具”将所有js代码进行压缩,然后将这里的useCompress改为true。 \n 请注意,只有useCompress是false时才会读取floors目录下的文件,为true时会直接读取libs目录下的floors.min.js文件。 \n 如果要进行剧本的修改请务必将其改成false。 \n$select({\"values\":[false]})$end",
|
||||
"floorIds": " 在这里按顺序放所有的楼层;其顺序直接影响到楼层传送器的顺序和上楼器/下楼器的顺序 \n$leaf(true)$end",
|
||||
"pngs": " 在此存放所有可能的背景图片;背景图片最好是416*416像素,其他分辨率会被强制缩放成416*416 \n 建议对于较大的图片,在网上使用在线的“图片压缩工具”来进行压缩,以节省流量 \n 有关使用自定义背景图,请参见文档的“自定义素材”说明 \n\n 依次向后添加 \n$leaf(true)$end",
|
||||
"pngs": " 在此存放所有可能使用的图片,只能是png格式,可以不写后缀名 \n 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。 \n 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量 \n 依次向后添加 \n$leaf(true)$end",
|
||||
"animates": " 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 \n 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 \n \"jianji\", \"thunder\" \n 根据需求自行添加 \n$leaf(true)$end",
|
||||
"bgms": " 在此存放所有的bgm,和文件名一致。第一项为默认播放项 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end",
|
||||
"sounds": " 在此存放所有的SE,和文件名一致 \n 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 \n$leaf(true)$end"
|
||||
},
|
||||
@ -40,10 +41,11 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"poison": " 游戏过程中的变量或flags \n 毒 ",
|
||||
"weak": " 衰 ",
|
||||
"curse": " 咒 "
|
||||
}
|
||||
},
|
||||
"steps": " 行走步数统计 ",
|
||||
},
|
||||
"startText": " 游戏开始前剧情。如果无剧情直接留一个空数组即可。 \n$leaf(true)$end",
|
||||
"shops": {
|
||||
"shops": "全局商店\n$leaf(true)$end",/*{
|
||||
"moneyShop1": {
|
||||
"name": " 定义全局商店(即快捷商店) \n 商店唯一ID \n 商店名称(标题) ",
|
||||
"icon": " 商店图标,blueShop为蓝色商店,pinkShop为粉色商店 ",
|
||||
@ -95,7 +97,7 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
},*/
|
||||
"levelUp": [
|
||||
" 经验升级所需要的数值,是一个数组 \n 第一项为初始等级,可以简单留空,也可以写name \n 每一个里面可以含有三个参数 need, name, effect \n need为所需要的经验数值,是一个正整数。请确保need所需的依次递增 \n name为该等级的名称,也可以省略代表使用系统默认值;本项将显示在状态栏中 \n effect为本次升级所执行的操作,可由若干项组成,由分号分开 \n 其中每一项写法和上面的商店完全相同,同样必须是X+=Y的形式,Y是一个表达式,同样可以使用status:xxx或item:xxx代表勇士的某项数值/道具个数 \n$leaf(true)$end",
|
||||
{
|
||||
@ -121,6 +123,8 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"bluePotion": " 蓝血瓶加血数值 ",
|
||||
"yellowPotion": " 黄血瓶加血数值 ",
|
||||
"greenPotion": " 绿血瓶加血数值 ",
|
||||
"sword0": " 默认装备折断的剑的攻击力 ",
|
||||
"shield0": " 默认装备残破的盾的防御力 ",
|
||||
"sword1": " 铁剑加攻数值 ",
|
||||
"shield1": " 铁盾加防数值 ",
|
||||
"sword2": " 银剑加攻数值 ",
|
||||
@ -150,8 +154,11 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"pickaxeFourDirections": " 使用破墙镐是否四个方向都破坏;如果false则只破坏面前的墙壁 \n$select({\"values\":[true,false]})$end",
|
||||
"bombFourDirections": " 使用炸弹是否四个方向都会炸;如果false则只炸面前的怪物(即和圣锤等价) \n$select({\"values\":[true,false]})$end",
|
||||
"bigKeyIsBox": " 如果此项为true,则视为钥匙盒,红黄蓝钥匙+1;若为false,则视为大黄门钥匙 \n$select({\"values\":[true,false]})$end",
|
||||
"equipment": " 剑和盾是否直接作为装备。如果此项为true,则作为装备,需要在道具栏使用,否则将直接加属性。 \n$select({\"values\":[true,false]})$end",
|
||||
"enableDeleteItem": " 是否允许删除(丢弃)道具 \n$select({\"values\":[true,false]})$end",
|
||||
"enableNegativeDamage": " /****** 怪物相关 ******/ \n 是否支持负伤害(回血) \n$select({\"values\":[true,false]})$end",
|
||||
"zoneSquare": " 领域类型。如果此项为true则为九宫格伤害,为false则为十字伤害 \n$select({\"values\":[true,false]})$end",
|
||||
"hatredDecrease": " 是否在和仇恨怪战斗后减一半的仇恨值,此项为false则和仇恨怪不会扣减仇恨值。 \n$select({\"values\":[true,false]})$end",
|
||||
"betweenAttackCeil": " 夹击方式是向上取整还是向下取整。如果此项为true则为向上取整,为false则为向下取整 \n$select({\"values\":[true,false]})$end",
|
||||
"startDirectly": " /****** 系统相关 ******/ \n 点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面 \n$select({\"values\":[true,false]})$end",
|
||||
"canOpenBattleAnimate": " 是否允许用户开启战斗过程;如果此项为false,则下面两项均强制视为false \n$select({\"values\":[true,false]})$end",
|
||||
"showBattleAnimateConfirm": " 是否在游戏开始时提供“是否开启战斗动画”的选项 \n$select({\"values\":[true,false]})$end",
|
||||
@ -159,7 +166,9 @@ data_comment_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"displayEnemyDamage": " 是否地图怪物显伤;用户可以手动在菜单栏中开关 \n$select({\"values\":[true,false]})$end",
|
||||
"displayExtraDamage": " 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关 \n$select({\"values\":[true,false]})$end",
|
||||
"enableGentleClick": " 是否允许轻触(获得面前物品) \n$select({\"values\":[true,false]})$end",
|
||||
"potionWhileRouting": " 寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶 \n$select({\"values\":[true,false]})$end",
|
||||
"enableViewMaps": " 是否支持在菜单栏中查看所有楼层的地图 \n$select({\"values\":[true,false]})$end",
|
||||
"portalWithoutTrigger": " 经过楼梯、传送门时是否能“穿透”。穿透的意思是,自动寻路得到的的路径中间经过了楼梯,行走时是否触发楼层转换事件 \n$select({\"values\":[true,false]})$end",
|
||||
"potionWhileRouting": " 寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶 \n$select({\"values\":[true,false]})$end"
|
||||
"enableMoveDirectly": " 是否允许瞬间移动 \n$select({\"values\":[true,false]})$end"
|
||||
}
|
||||
}
|
||||
@ -10,18 +10,25 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"sample0", "sample1", "sample2"
|
||||
],// 在这里按顺序放所有的楼层;其顺序直接影响到楼层传送器的顺序和上楼器/下楼器的顺序
|
||||
"pngs" : [
|
||||
"bg.png", "yewai.png", // 在此存放所有可能的背景图片;背景图片最好是416*416像素,其他分辨率会被强制缩放成416*416
|
||||
// 建议对于较大的图片,在网上使用在线的“图片压缩工具”来进行压缩,以节省流量
|
||||
// 有关使用自定义背景图,请参见文档的“自定义素材”说明
|
||||
"bg", // 在此存放所有可能使用的图片,只能是png格式,可以不写后缀名
|
||||
// 图片可以被作为背景图(的一部分),也可以直接用自定义事件进行显示。
|
||||
// 图片名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
// 建议对于较大的图片,在网上使用在线的“图片压缩工具(http://compresspng.com/zh/)”来进行压缩,以节省流量
|
||||
// 依次向后添加
|
||||
],
|
||||
"animates" : [
|
||||
"hand", "sword", "zone", "yongchang", // "jianji", "thunder"
|
||||
// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名
|
||||
// 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符
|
||||
// 根据需求自行添加
|
||||
],
|
||||
"bgms" : [
|
||||
'058-Slow01.mid', 'bgm.mp3', 'qianjin.mid', 'star.mid',
|
||||
'bgm.mp3', 'qianjin.mid', 'star.mid',
|
||||
// 在此存放所有的bgm,和文件名一致。第一项为默认播放项
|
||||
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
],
|
||||
"sounds" : [
|
||||
'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg',
|
||||
'floor.mp3', 'attack.ogg', 'door.ogg', 'item.ogg', 'zone.ogg'
|
||||
// 在此存放所有的SE,和文件名一致
|
||||
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
|
||||
],
|
||||
@ -29,7 +36,7 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"firstData" : {
|
||||
"title": "魔塔样板", // 游戏名,将显示在标题页面以及切换楼层的界面中
|
||||
"name": "template", // 游戏的唯一英文标识符。由英文、数字、下划线组成,不能超过20个字符。
|
||||
"version": "Ver 1.0.0 (Beta)", // 当前游戏版本;版本不一致的存档不能通用。
|
||||
"version": "Ver 1.4.1", // 当前游戏版本;版本不一致的存档不能通用。
|
||||
"floorId": "sample0", // 初始楼层ID
|
||||
"hero": {
|
||||
"name": "阳光", // 勇士初始数据
|
||||
@ -57,19 +64,19 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
// 毒
|
||||
"weak": false, // 衰
|
||||
"curse": false, // 咒
|
||||
}
|
||||
},
|
||||
"steps": 0, // 行走步数统计
|
||||
},
|
||||
"startText": [
|
||||
"Hi,欢迎来到 HTML5 魔塔样板!\n\n本样板由艾之葵制作,可以让你在不会写任何代码\n的情况下也能做出属于自己的H5魔塔!",
|
||||
"这里游戏开始时的剧情。\n定义在data.js的startText处。\n\n你可以在这里写上自己的内容。",
|
||||
"赶快来试一试吧!"
|
||||
], // 游戏开始前剧情。如果无剧情直接留一个空数组即可。
|
||||
"shops": {
|
||||
"moneyShop1": {
|
||||
"name": "贪婪之神", // 定义全局商店(即快捷商店)
|
||||
// 商店唯一ID
|
||||
// 商店名称(标题)
|
||||
"icon": "blueShop", // 商店图标,blueShop为蓝色商店,pinkShop为粉色商店
|
||||
"shops": [ // 定义全局商店(即快捷商店)
|
||||
{
|
||||
"id": "moneyShop1", // 商店唯一ID
|
||||
"name": "贪婪之神", // 商店名称(标题)
|
||||
"icon": "blueShop", // 商店图标,在icons.js中的npc一项定义
|
||||
"textInList": "1F金币商店", // 在快捷商店栏中显示的名称
|
||||
"use": "money", // 商店所要使用的。只能是"money"或"experience"。
|
||||
"need": "20+10*times*(times+1)", // 商店需要的金币/经验数值;可以是一个表达式,以times作为参数计算。
|
||||
@ -78,8 +85,8 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
// 例如: "need": "25" 就是恒定需要25金币的商店; "need": "20+2*times" 就是第一次访问要20金币,以后每次递增2金币的商店。
|
||||
// 如果是对于每个选项有不同的计算公式,写 "need": "-1" 即可。可参见下面的经验商店。
|
||||
"text": "勇敢的武士啊,给我${need}金币就可以:", // 显示的文字,需手动加换行符。可以使用${need}表示上面的need值。
|
||||
"choices": [
|
||||
{"text": "生命+800", "effect": "status:hp+=800"}, // 商店的选项
|
||||
"choices": [ // 商店的选项
|
||||
{"text": "生命+800", "effect": "status:hp+=800"},
|
||||
// 如果有多个effect以分号分开,参见下面的经验商店
|
||||
{"text": "攻击+4", "effect": "status:atk+=4"},
|
||||
{"text": "防御+4", "effect": "status:def+=4"},
|
||||
@ -92,24 +99,24 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
// "status:hp+=2*(status:atk+status:def)" 将生命提升攻防和的数值的两倍
|
||||
]
|
||||
},
|
||||
"expShop1": {
|
||||
"name": "经验之神", // 商店唯一ID
|
||||
{
|
||||
"id": "expShop1", // 商店唯一ID
|
||||
"name": "经验之神",
|
||||
"icon": "pinkShop",
|
||||
"textInList": "1F经验商店",
|
||||
"use": "experience", // 该商店使用的是经验进行计算
|
||||
"need": "-1", // 如果是对于每个选项所需要的数值不同,这里直接写-1,然后下面选项里给定具体数值
|
||||
"text": "勇敢的武士啊,给我若干经验就可以:",
|
||||
"choices": [
|
||||
{"text": "等级+1", "need": "100", "effect": "status:lv+=1;status:hp+=1000;status:atk+=7;status:def+=7"},
|
||||
// 在choices中写need,可以针对每个选项都有不同的需求。
|
||||
// 这里的need同样可以以times作为参数,比如 "need": "100+20*times"
|
||||
|
||||
{"text": "等级+1", "need": "100", "effect": "status:lv+=1;status:hp+=1000;status:atk+=7;status:def+=7"},
|
||||
// 多个effect直接以分号分开即可。如上面的意思是生命+1000,攻击+7,防御+7。
|
||||
{"text": "攻击+5", "need": "30", "effect": "status:atk+=5"},
|
||||
{"text": "防御+5", "need": "30", "effect": "status:def+=5"},
|
||||
]
|
||||
},
|
||||
},
|
||||
}
|
||||
],
|
||||
"levelUp": [
|
||||
{}, // 经验升级所需要的数值,是一个数组
|
||||
// 第一项为初始等级,可以简单留空,也可以写name
|
||||
@ -150,6 +157,8 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"bluePotion": 250, // 蓝血瓶加血数值
|
||||
"yellowPotion": 500, // 黄血瓶加血数值
|
||||
"greenPotion": 800, // 绿血瓶加血数值
|
||||
"sword0": 0, // 默认装备折断的剑的攻击力
|
||||
"shield0": 0, // 默认装备残破的盾的防御力
|
||||
"sword1": 10, // 铁剑加攻数值
|
||||
"shield1": 10, // 铁盾加防数值
|
||||
"sword2": 20, // 银剑加攻数值
|
||||
@ -190,10 +199,13 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"pickaxeFourDirections": true, // 使用破墙镐是否四个方向都破坏;如果false则只破坏面前的墙壁
|
||||
"bombFourDirections": true, // 使用炸弹是否四个方向都会炸;如果false则只炸面前的怪物(即和圣锤等价)
|
||||
"bigKeyIsBox": false, // 如果此项为true,则视为钥匙盒,红黄蓝钥匙+1;若为false,则视为大黄门钥匙
|
||||
"equipment": false, // 剑和盾是否直接作为装备。如果此项为true,则作为装备,需要在道具栏使用,否则将直接加属性。
|
||||
"enableDeleteItem": true, // 是否允许删除(丢弃)道具
|
||||
|
||||
"enableNegativeDamage": true, /****** 怪物相关 ******/
|
||||
// 是否支持负伤害(回血)
|
||||
"zoneSquare": false, // 领域类型。如果此项为true则为九宫格伤害,为false则为十字伤害
|
||||
"hatredDecrease": true, // 是否在和仇恨怪战斗后减一半的仇恨值,此项为false则和仇恨怪不会扣减仇恨值。
|
||||
"betweenAttackCeil": false, // 夹击方式是向上取整还是向下取整。如果此项为true则为向上取整,为false则为向下取整
|
||||
|
||||
"startDirectly": false, /****** 系统相关 ******/
|
||||
// 点击“开始游戏”后是否立刻开始游戏而不显示难度选择界面
|
||||
@ -203,7 +215,9 @@ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
|
||||
"displayEnemyDamage": true, // 是否地图怪物显伤;用户可以手动在菜单栏中开关
|
||||
"displayExtraDamage": false, // 是否地图高级显伤(领域、夹击等);用户可以手动在菜单栏中开关
|
||||
"enableGentleClick": true, // 是否允许轻触(获得面前物品)
|
||||
"portalWithoutTrigger": true, // 经过楼梯、传送门时是否能“穿透”。穿透的意思是,自动寻路得到的的路径中间经过了楼梯,行走时是否触发楼层转换事件
|
||||
"potionWhileRouting": false, // 寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶
|
||||
"enableViewMaps": true, // 是否支持在菜单栏中查看所有楼层的地图
|
||||
"portalWithoutTrigger": true, // 经过楼梯、传送门时是否能“穿透”。穿透的意思是,自动寻路得到的的路径中间经过了楼梯,行走时是否触发楼层转换事件
|
||||
"enableMoveDirectly": true, // 是否允许瞬间移动
|
||||
}
|
||||
}
|
||||
@ -15,11 +15,11 @@ enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
||||
'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},
|
||||
@ -46,7 +46,7 @@ enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 =
|
||||
'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},
|
||||
|
||||
@ -9,8 +9,9 @@ main.floors.MT0 =
|
||||
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
|
||||
"canUseQuickShop": true, // 该层是否允许使用快捷商店
|
||||
"defaultGround": "ground", // 默认地面的图块ID(terrains中)
|
||||
// "png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。详细用法请参见文档“自定义素材”中的说明。
|
||||
"png": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。
|
||||
// "color": [0,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。
|
||||
// "weather": ["snow",5], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。
|
||||
// "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。
|
||||
"map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成
|
||||
|
||||
@ -32,6 +33,11 @@ main.floors.MT0 =
|
||||
},
|
||||
"afterOpenDoor": { // 开完门后可能触发的事件列表
|
||||
|
||||
}
|
||||
},
|
||||
"cannotMove": { // 每个图块不可通行的方向
|
||||
// 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去
|
||||
// "x,y": ["up", "left"], // (x,y)点不能往上和左走
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,9 @@ main.floors.sample0 =
|
||||
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
|
||||
"canUseQuickShop": true, // 该层是否允许使用快捷商店
|
||||
"defaultGround": "ground", // 默认地面的图块ID(terrains中)
|
||||
// "png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。详细用法请参见文档“自定义素材”中的说明。
|
||||
"png": [], // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。
|
||||
// "color": [0,0,0,0.3] // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。
|
||||
// "weather": ["snow",5], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。
|
||||
"bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。
|
||||
"map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成
|
||||
[0, 0, 220, 0, 0, 20, 87, 3, 65, 64, 44, 43, 42],
|
||||
@ -29,7 +30,7 @@ main.floors.sample0 =
|
||||
],
|
||||
"firstArrive": [ // 第一次到该楼层触发的事件
|
||||
"\t[样板提示]首次到达某层可以触发 firstArrive 事件,该事件可类似于RMXP中的“自动执行脚本”。\n\n本事件支持一切的事件类型,常常用来触发对话,例如:",
|
||||
"\t[hero]我是谁?我从哪来?我又要到哪去?",
|
||||
"\t[hero]\b[up,hero]我是谁?我从哪来?我又要到哪去?",
|
||||
"\t[仙子,fairy]你问我...?我也不知道啊...",
|
||||
"本层主要对道具、门、怪物等进行介绍,有关事件的各种信息在下一层会有更为详细的说明。",
|
||||
],
|
||||
@ -37,9 +38,9 @@ main.floors.sample0 =
|
||||
|
||||
"10,9": [ // 守着道具的老人
|
||||
"\t[老人,man]这些是本样板支持的所有的道具。\n\n道具分为三类:items, constants, tools。\nitems 为即捡即用类道具,例如宝石、血瓶、剑盾等。\nconstants 为永久道具,例如怪物手册、楼层传送器、幸运金币等。\ntools 为消耗类道具,例如破墙镐、炸弹、中心对称飞行器等。\n\n后两类道具在工具栏中可以看到并使用。",
|
||||
"\t[老人,man]有关道具效果,定义在items.js中。\n目前大多数道具已有默认行为,如有自定义的需求则需在items.js中修改代码。",
|
||||
"\t[老人,man]\b[up]有关道具效果,定义在items.js中。\n目前大多数道具已有默认行为,如有自定义的需求则需在items.js中修改代码。",
|
||||
"\t[老人,man]constants 和 tools 各最多只允许12种,多了会导致图标溢出。",
|
||||
"\t[老人,man]拾取道具结束后可触发 afterGetItem 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。",
|
||||
"\t[老人,man]\b[up]拾取道具结束后可触发 afterGetItem 事件。\n\n有关事件的各种信息在下一层会有更为详细的说明。",
|
||||
{"type": "hide", "time": 500} // 消失
|
||||
],
|
||||
"10,11": [ // 守着门的老人
|
||||
@ -51,7 +52,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": [ // 守着第一批怪物的老人
|
||||
@ -76,7 +76,6 @@ main.floors.sample0 =
|
||||
{"type": "hide", "time": 500}
|
||||
]
|
||||
},
|
||||
|
||||
},
|
||||
"changeFloor": { // 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖
|
||||
"6,0": {"floorId": "sample1", "stair": "downFloor"}, // 目标点:sample1层的下楼梯位置
|
||||
@ -86,11 +85,11 @@ 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, "portalWithoutTrigger": false}, // time=0表示无切换时间
|
||||
"6,12": {"floorId": "sample0", "loc": [10,10], "direction": "left", "time": 1000},
|
||||
},
|
||||
"afterBattle": { // 战斗后可能触发的事件列表
|
||||
"2,6": ["\t[ghostSkeleton]不可能,你怎么可能打败我!\n(一个打败怪物触发的事件)"]
|
||||
"2,6": ["\t[ghostSkeleton]不可能,你怎么可能打败我!\n(一个打败怪物触发的事件)"],
|
||||
},
|
||||
"afterGetItem": { // 获得道具后可能触发的事件列表
|
||||
"11,8": ["由于状态栏放不下,绿钥匙和铁门钥匙均视为tools,放入工具栏中。\n碰到绿门和铁门仍然会自动使用开门。"],
|
||||
@ -111,7 +110,12 @@ main.floors.sample0 =
|
||||
},
|
||||
"afterOpenDoor": { // 开完门后可能触发的事件列表
|
||||
"11,12": ["你开了一个绿门,触发了一个afterOpenDoor事件"]
|
||||
}
|
||||
},
|
||||
"cannotMove": { // 每个图块不可通行的方向
|
||||
// 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去
|
||||
// "x,y": ["up", "left"], // (x,y)点不能往上和左走
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,9 @@ main.floors.sample1 =
|
||||
"canFlyTo": true, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
|
||||
"canUseQuickShop": true, // 该层是否允许使用快捷商店
|
||||
"defaultGround": "grass", // 默认地面的图块ID(terrains中)
|
||||
"png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。详细用法请参见文档“自定义素材”中的说明。
|
||||
"png": [[0,0,"bg"]], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。
|
||||
// "color": [0,0,0,0.3] // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。
|
||||
"weather": ["snow",6], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。
|
||||
// "bgm": "bgm.mp3", // 到达该层后默认播放的BGM。本项可忽略。
|
||||
"map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成
|
||||
[7, 131, 8, 152, 9, 130, 10, 152, 166, 165, 132, 165, 166],
|
||||
@ -35,8 +36,8 @@ main.floors.sample1 =
|
||||
"4,10": [ // 走到中间时的提示
|
||||
"\t[样板提示]本层楼将会对各类事件进行介绍。",
|
||||
"左边是一个仿50层的陷阱做法,上方是商店、快捷商店的使用方法,右上是一个典型的杀怪开门的例子,右下是各类可能的NPC事件。",
|
||||
"本样板目前支持的事件列表大致有:\ntext: 显示一段文字(比如你现在正在看到的)\ntip: 左上角显示提示\nshow: 使一个事件有效(可见、可被交互)\nhide: 使一个事件失效(不可见、不可被交互)\ntrigger: 触发另一个地点的事件\nbattle: 强制和某怪物战斗\nopenDoor: 无需钥匙开门(例如机关门、暗墙)",
|
||||
"openShop: 打开一个全局商店\ndisableShop: 禁用一个全局商店\nchangeFloor: 传送勇士到某层某位置\nchangePos: 传送勇士到当层某位置;转向\nsetFg: 更改画面色调\nmove: 移动事件效果\nmoveHero: 移动勇士效果\nplayBgm: 播放某个背景音乐\npauseBgm: 暂停背景音乐\nresumeBgm: 恢复背景音乐的播放\nplaySound: 播放某个音频",
|
||||
"本样板目前支持的事件列表大致有:\ntext: 显示一段文字(比如你现在正在看到的)\ntip: 左上角显示提示\nshow: 使一个事件有效(可见、可被交互)\nhide: 使一个事件失效(不可见、不可被交互)\ntrigger: 触发另一个地点的事件\nanimate: 显示动画\nbattle: 强制和某怪物战斗\nopenDoor: 无需钥匙开门(例如机关门、暗墙)",
|
||||
"openShop: 打开一个全局商店\ndisableShop: 禁用一个全局商店\nchangeFloor: 传送勇士到某层某位置\nchangePos: 传送勇士到当层某位置;转向\nshowImage: 显示图片\nsetFg: 更改画面色调\nsetWeather: 更改天气\nmove: 移动事件效果\nmoveHero: 移动勇士效果\nplayBgm: 播放某个背景音乐\npauseBgm: 暂停背景音乐\nresumeBgm: 恢复背景音乐的播放\nplaySound: 播放某个音频",
|
||||
"if: 条件判断\nchoices: 提供选项\nsetValue: 设置勇士属性道具,或某个变量/flag\nupdate: 更新状态栏和地图显伤\nwin: 获得胜利(游戏通关)\nlose: 游戏失败\nsleep: 等待多少毫秒\nexit: 立刻结束当前事件\nrevisit: 立刻结束事件并重新触发\nfunction: 自定义JS脚本\n\n更多支持的事件还在编写中,欢迎您宝贵的意见。",
|
||||
"有关各事件的样例,可参见本层一些NPC的写法。\n所有事件样例本层都有介绍。\n\n一个自定义事件处理完后,需要调用{\"type\": \"hide\"}该事件才不会再次出现。",
|
||||
{"type": "hide"}
|
||||
@ -259,18 +260,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.stopReplay();
|
||||
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]具体可参见样板中本事件的写法。"
|
||||
@ -305,6 +322,11 @@ main.floors.sample1 =
|
||||
},
|
||||
"afterOpenDoor": { // 开完门后可能触发的事件列表
|
||||
|
||||
}
|
||||
},
|
||||
"cannotMove": { // 每个图块不可通行的方向
|
||||
// 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去
|
||||
// "x,y": ["up", "left"], // (x,y)点不能往上和左走
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@ -9,8 +9,9 @@ main.floors.sample2 =
|
||||
"canFlyTo": false, // 该楼能否被楼传器飞到(不能的话在该楼也不允许使用楼传器)
|
||||
"canUseQuickShop": true, // 该层是否允许使用快捷商店
|
||||
"defaultGround": "snowGround", // 默认地面的图块ID(terrains中)
|
||||
// "png": "bg.png", // 背景图;你可以选择一张png图片来作为背景素材。详细用法请参见文档“自定义素材”中的说明。
|
||||
"png": [], // // 该层默认显示的所有图片;详细用法请查看文档“自定义素材”中的说明。
|
||||
"color": [255,0,0,0.3], // 该层的默认画面色调。本项可不写(代表无色调),如果写需要是一个RGBA数组。
|
||||
"weather": ["rain",10], // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain"或"snow"代表雨雪,第二项为1-10之间的数代表强度。
|
||||
"bgm": "qianjin.mid", // 到达该层后默认播放的BGM。本项可忽略。
|
||||
"map": [ // 地图数据,需要是13x13,建议使用地图生成器来生成
|
||||
[5, 5, 5, 5, 5, 5, 87, 5, 5, 5, 5, 5, 5],
|
||||
@ -28,8 +29,7 @@ main.floors.sample2 =
|
||||
[5, 5, 5, 5, 5, 5, 88, 5, 5, 5, 5, 5, 5],
|
||||
],
|
||||
"firstArrive": [ // 第一次到该楼层触发的事件
|
||||
"\t[实战!]本楼将尝试复刻《宿命的旋律》40F剧情。",
|
||||
"由于暂不支持一些动画效果,例如雷电、振动、天气渲染等等,因此做出来的效果远远比不上原版。\n\n不过作为抛砖引玉,还是能展示一下H5的能力。\n(开音效食用更加)"
|
||||
"\t[实战!]本楼将尝试复刻《宿命的旋律》40F剧情。"
|
||||
],
|
||||
"events": { // 该楼的所有可能事件列表
|
||||
|
||||
@ -182,6 +182,7 @@ main.floors.sample2 =
|
||||
{"type": "show", "loc": [8,3], "time": 500}, // 依次显示四个角的法师
|
||||
{"type": "sleep", "time": 500},
|
||||
"\t[blackMagician]感受绝望吧!冥顽不化的蠢货!",
|
||||
/*
|
||||
{"type": "hide", "loc": [4,3], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
{"type": "show", "loc": [4,3], "time": 150},
|
||||
{"type": "hide", "loc": [4,6], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
@ -190,8 +191,14 @@ main.floors.sample2 =
|
||||
{"type": "show", "loc": [8,6], "time": 150},
|
||||
{"type": "hide", "loc": [8,3], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
{"type": "show", "loc": [8,3], "time": 150},
|
||||
*/
|
||||
{"type": "animate", "name": "yongchang", "loc": [4,3]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [4,6]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [8,6]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [8,3]},
|
||||
{"type": "sleep", "time": 200},
|
||||
{"type": "playSound", "name": "attack.ogg"}, // 播放攻击音效
|
||||
{"type": "animate", "name": "thunder", "loc": "hero"},
|
||||
{"type": "sleep", "time": 200},
|
||||
"\t[hero]唔……!!(吐血)",
|
||||
{"type": "playSound", "name": "item.ogg"},
|
||||
@ -267,6 +274,7 @@ main.floors.sample2 =
|
||||
"\t[小妖精,fairy]别小瞧咱!咱好歹也是妖精族里实力数一数二的存在!",
|
||||
{"type": "playSound", "name": "item.ogg"},
|
||||
"\t[blackMagician]只会耍嘴皮子的恼人苍蝇!我倒要看看一块焦炭会不会说话!\n——招雷弹!!",
|
||||
/*
|
||||
{"type": "hide", "loc": [4,3], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
{"type": "show", "loc": [4,3], "time": 150},
|
||||
{"type": "hide", "loc": [4,6], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
@ -275,9 +283,17 @@ main.floors.sample2 =
|
||||
{"type": "show", "loc": [8,6], "time": 150},
|
||||
{"type": "hide", "loc": [8,3], "time": 150}, // 由于没有动画效果,暂时使用“闪一下”表示
|
||||
{"type": "show", "loc": [8,3], "time": 150},
|
||||
*/
|
||||
{"type": "animate", "name": "yongchang", "loc": [4,3]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [4,6]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [8,6]},
|
||||
{"type": "animate", "name": "yongchang", "loc": [8,3]},
|
||||
{"type": "playSound", "name": "attack.ogg"}, // 播放攻击音效
|
||||
/*
|
||||
{"type": "hide", "loc": [6,6], "time": 150}, // 妖精也闪一下表示收到了伤害
|
||||
{"type": "show", "loc": [6,6], "time": 150}, // 妖精也闪一下表示收到了伤害
|
||||
*/
|
||||
{"type": "animate", "name": "thunder", "loc": [6,6]},
|
||||
{"type": "sleep", "time": 500}, // 等待500毫秒
|
||||
"\t[小妖精,fairy]切,这点伤痛跟他刚才经历的身心地狱相比根本就不算什么。",
|
||||
{"type": "playSound", "name": "item.ogg"},
|
||||
@ -386,6 +402,11 @@ main.floors.sample2 =
|
||||
},
|
||||
"afterOpenDoor": { // 开完门后可能触发的事件列表
|
||||
|
||||
}
|
||||
},
|
||||
"cannotMove": { // 每个图块不可通行的方向
|
||||
// 可以在这里定义每个点不能前往哪个方向,例如悬崖边不能跳下去
|
||||
// "x,y": ["up", "left"], // (x,y)点不能往上和左走
|
||||
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
412
project/icons.js
@ -1,215 +1,217 @@
|
||||
icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 =
|
||||
{
|
||||
"hero": {
|
||||
"down": {"loc": 0, "stop": 0, "leftFoot": 1, "rightFoot": 3},
|
||||
"left": {"loc": 1, "stop": 0, "leftFoot": 1, "rightFoot": 3},
|
||||
"right": {"loc": 2, "stop": 0, "leftFoot": 1, "rightFoot": 3},
|
||||
"up": {"loc": 3, "stop": 0, "leftFoot": 1, "rightFoot": 3}
|
||||
'hero': {
|
||||
'down': {'loc': 0, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3},
|
||||
'left': {'loc': 1, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3},
|
||||
'right': {'loc': 2, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3},
|
||||
'up': {'loc': 3, 'stop': 0, 'leftFoot': 1, 'rightFoot': 3}
|
||||
},
|
||||
"terrains": {
|
||||
"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,
|
||||
"star": 20,
|
||||
"lava": 21,
|
||||
"ice": 22,
|
||||
"downFloor": 23,
|
||||
"upFloor": 24,
|
||||
"yellowDoor": 25,
|
||||
"blueDoor": 26,
|
||||
"redDoor": 27,
|
||||
"greenDoor": 28,
|
||||
"specialDoor": 29,
|
||||
"steelDoor": 30,
|
||||
"blueShop-left": 31,
|
||||
"blueShop-right": 32,
|
||||
"pinkShop-left": 33,
|
||||
"pinkShop-right": 34,
|
||||
"arrowUp": 35,
|
||||
"arrowDown": 36,
|
||||
"arrowLeft": 37,
|
||||
"arrowRight": 38,
|
||||
"light": 39,
|
||||
"darkLight": 40
|
||||
'terrains': {
|
||||
'ground': 0,
|
||||
'grass': 1,
|
||||
'grass2': 2,
|
||||
'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,
|
||||
'downFloor': 23,
|
||||
'upFloor': 24,
|
||||
'yellowDoor': 25,
|
||||
'blueDoor': 26,
|
||||
'redDoor': 27,
|
||||
'greenDoor': 28,
|
||||
'specialDoor': 29,
|
||||
'steelDoor': 30,
|
||||
'blueShop-left': 31,
|
||||
'blueShop-right': 32,
|
||||
'pinkShop-left': 33,
|
||||
'pinkShop-right': 34,
|
||||
'arrowUp': 35,
|
||||
'arrowDown': 36,
|
||||
'arrowLeft': 37,
|
||||
'arrowRight': 38,
|
||||
'light': 39,
|
||||
'darkLight': 40
|
||||
},
|
||||
"animates": {
|
||||
"star": 0,
|
||||
"lava": 1,
|
||||
"waterWall": 2,
|
||||
"yellowDoor": 3,
|
||||
"blueDoor": 4,
|
||||
"redDoor": 5,
|
||||
"greenDoor": 6,
|
||||
"specialDoor": 7,
|
||||
"blueWallDoor": 8,
|
||||
"yellowWallDoor": 9,
|
||||
"whiteWallDoor": 10,
|
||||
"steelDoor": 11,
|
||||
"lavaDoor": 12,
|
||||
"grayLavaDoor": 13,
|
||||
"starDoor": 14,
|
||||
"mockBlueWallDoor": 15,
|
||||
"mockYellowWallDoor": 16,
|
||||
"mockWhiteWallDoor": 17,
|
||||
"iceYellowWallDoor": 18,
|
||||
"starPortal": 19,
|
||||
"exclamation": 20,
|
||||
"portal": 21,
|
||||
"switch": 22,
|
||||
"lavaNet": 23,
|
||||
"poisonNet": 24,
|
||||
"weakNet": 25,
|
||||
"curseNet": 26,
|
||||
"downPortal": 27,
|
||||
"leftPortal": 28,
|
||||
"rightPortal": 29,
|
||||
"upPortal": 30,
|
||||
"water": 31,
|
||||
'animates': {
|
||||
'star': 0,
|
||||
'lava': 1,
|
||||
'waterWall': 2,
|
||||
'yellowDoor': 3,
|
||||
'blueDoor': 4,
|
||||
'redDoor': 5,
|
||||
'greenDoor': 6,
|
||||
'specialDoor': 7,
|
||||
'blueWallDoor': 8,
|
||||
'yellowWallDoor': 9,
|
||||
'whiteWallDoor': 10,
|
||||
'steelDoor': 11,
|
||||
'lavaDoor': 12,
|
||||
'grayLavaDoor': 13,
|
||||
'starDoor': 14,
|
||||
'mockBlueWallDoor': 15,
|
||||
'mockYellowWallDoor': 16,
|
||||
'mockWhiteWallDoor': 17,
|
||||
'iceYellowWallDoor': 18,
|
||||
'starPortal': 19,
|
||||
'exclamation': 20,
|
||||
'portal': 21,
|
||||
'switch': 22,
|
||||
'lavaNet': 23,
|
||||
'poisonNet': 24,
|
||||
'weakNet': 25,
|
||||
'curseNet': 26,
|
||||
'downPortal': 27,
|
||||
'leftPortal': 28,
|
||||
'rightPortal': 29,
|
||||
'upPortal': 30,
|
||||
'water': 31,
|
||||
},
|
||||
"npcs": {
|
||||
"man": 0,
|
||||
"woman": 1,
|
||||
"thief": 2,
|
||||
"fairy": 3,
|
||||
"magician": 4,
|
||||
"womanMagician": 5,
|
||||
"oldMan": 6,
|
||||
"child": 7,
|
||||
"wood": 8,
|
||||
"pinkShop": 9,
|
||||
"blueShop": 10,
|
||||
"princess": 11
|
||||
'npcs': {
|
||||
'man': 0,
|
||||
'woman': 1,
|
||||
'thief': 2,
|
||||
'fairy': 3,
|
||||
'magician': 4,
|
||||
'womanMagician': 5,
|
||||
'oldMan': 6,
|
||||
'child': 7,
|
||||
'wood': 8,
|
||||
'pinkShop': 9,
|
||||
'blueShop': 10,
|
||||
'princess': 11
|
||||
},
|
||||
"enemys": {
|
||||
"greenSlime": 0,
|
||||
"redSlime": 1,
|
||||
"blackSlime": 2,
|
||||
"slimelord": 3,
|
||||
"bat": 4,
|
||||
"bigBat": 5,
|
||||
"redBat": 6,
|
||||
"vampire": 7,
|
||||
"skeleton": 8,
|
||||
"skeletonSoilder": 9,
|
||||
"skeletonCaptain": 10,
|
||||
"ghostSkeleton": 11,
|
||||
"zombie": 12,
|
||||
"zombieKnight": 13,
|
||||
"rock": 14,
|
||||
"slimeMan": 15,
|
||||
"bluePriest": 16,
|
||||
"redPriest": 17,
|
||||
"brownWizard": 18,
|
||||
"redWizard": 19,
|
||||
"yellowGuard": 20,
|
||||
"blueGuard": 21,
|
||||
"redGuard": 22,
|
||||
"swordsman": 23,
|
||||
"soldier": 24,
|
||||
"yellowKnight": 25,
|
||||
"redKnight": 26,
|
||||
"darkKnight": 27,
|
||||
"blackKing": 28,
|
||||
"yellowKing": 29,
|
||||
"greenKing": 30,
|
||||
"blueKnight": 31,
|
||||
"goldSlime": 32,
|
||||
"poisonSkeleton": 33,
|
||||
"poisonBat": 34,
|
||||
"steelRock": 35,
|
||||
"skeletonPriest": 36,
|
||||
"skeletonKing": 37,
|
||||
"skeletonWizard": 38,
|
||||
"redSkeletonCaption": 39,
|
||||
"badHero": 40,
|
||||
"demon": 41,
|
||||
"demonPriest": 42,
|
||||
"goldHornSlime": 43,
|
||||
"redKing": 44,
|
||||
"whiteKing": 45,
|
||||
"blackMagician": 46,
|
||||
"silverSlime": 47,
|
||||
"swordEmperor": 48,
|
||||
"whiteHornSlime": 49,
|
||||
"badPrincess": 50,
|
||||
"badFairy": 51,
|
||||
"grayPriest": 52,
|
||||
"redSwordsman": 53,
|
||||
"whiteGhost": 54,
|
||||
"poisonZombie": 55,
|
||||
"magicDragon": 56,
|
||||
"octopus": 57,
|
||||
"darkFairy": 58,
|
||||
"greenKnight": 59,
|
||||
'enemys': {
|
||||
'greenSlime': 0,
|
||||
'redSlime': 1,
|
||||
'blackSlime': 2,
|
||||
'slimelord': 3,
|
||||
'bat': 4,
|
||||
'bigBat': 5,
|
||||
'redBat': 6,
|
||||
'vampire': 7,
|
||||
'skeleton': 8,
|
||||
'skeletonSoilder': 9,
|
||||
'skeletonCaptain': 10,
|
||||
'ghostSkeleton': 11,
|
||||
'zombie': 12,
|
||||
'zombieKnight': 13,
|
||||
'rock': 14,
|
||||
'slimeMan': 15,
|
||||
'bluePriest': 16,
|
||||
'redPriest': 17,
|
||||
'brownWizard': 18,
|
||||
'redWizard': 19,
|
||||
'yellowGuard': 20,
|
||||
'blueGuard': 21,
|
||||
'redGuard': 22,
|
||||
'swordsman': 23,
|
||||
'soldier': 24,
|
||||
'yellowKnight': 25,
|
||||
'redKnight': 26,
|
||||
'darkKnight': 27,
|
||||
'blackKing': 28,
|
||||
'yellowKing': 29,
|
||||
'greenKing': 30,
|
||||
'blueKnight': 31,
|
||||
'goldSlime': 32,
|
||||
'poisonSkeleton': 33,
|
||||
'poisonBat': 34,
|
||||
'steelRock': 35,
|
||||
'skeletonPriest': 36,
|
||||
'skeletonKing': 37,
|
||||
'skeletonWizard': 38,
|
||||
'redSkeletonCaption': 39,
|
||||
'badHero': 40,
|
||||
'demon': 41,
|
||||
'demonPriest': 42,
|
||||
'goldHornSlime': 43,
|
||||
'redKing': 44,
|
||||
'whiteKing': 45,
|
||||
'blackMagician': 46,
|
||||
'silverSlime': 47,
|
||||
'swordEmperor': 48,
|
||||
'whiteHornSlime': 49,
|
||||
'badPrincess': 50,
|
||||
'badFairy': 51,
|
||||
'grayPriest': 52,
|
||||
'redSwordsman': 53,
|
||||
'whiteGhost': 54,
|
||||
'poisonZombie': 55,
|
||||
'magicDragon': 56,
|
||||
'octopus': 57,
|
||||
'darkFairy': 58,
|
||||
'greenKnight': 59,
|
||||
},
|
||||
"items": {
|
||||
"yellowKey": 0,
|
||||
"blueKey": 1,
|
||||
"redKey": 2,
|
||||
"greenKey": 3,
|
||||
"steelKey": 4,
|
||||
"bigKey": 6,
|
||||
"redJewel": 16,
|
||||
"blueJewel": 17,
|
||||
"greenJewel": 18,
|
||||
"yellowJewel": 19,
|
||||
"redPotion": 20,
|
||||
"bluePotion": 21,
|
||||
"greenPotion": 22,
|
||||
"yellowPotion": 23,
|
||||
"sword1": 50,
|
||||
"sword2": 51,
|
||||
"sword3": 52,
|
||||
"sword4": 53,
|
||||
"sword5": 54,
|
||||
"shield1": 55,
|
||||
"shield2": 56,
|
||||
"shield3": 57,
|
||||
"shield4": 58,
|
||||
"shield5": 59,
|
||||
"book": 9,
|
||||
"fly": 12,
|
||||
"pickaxe": 45,
|
||||
"icePickaxe": 44,
|
||||
"bomb": 43,
|
||||
"centerFly": 13,
|
||||
"upFly": 15,
|
||||
"downFly": 14,
|
||||
"coin": 11,
|
||||
"snow": 41,
|
||||
"cross": 40,
|
||||
"superPotion": 29,
|
||||
"earthquake": 8,
|
||||
"poisonWine": 24,
|
||||
"weakWine": 25,
|
||||
"curseWine": 27,
|
||||
"superWine": 28,
|
||||
"knife": 42,
|
||||
"moneyPocket": 46,
|
||||
"shoes": 47,
|
||||
"hammer": 48
|
||||
'items': {
|
||||
'yellowKey': 0,
|
||||
'blueKey': 1,
|
||||
'redKey': 2,
|
||||
'greenKey': 3,
|
||||
'steelKey': 4,
|
||||
'bigKey': 6,
|
||||
'redJewel': 16,
|
||||
'blueJewel': 17,
|
||||
'greenJewel': 18,
|
||||
'yellowJewel': 19,
|
||||
'redPotion': 20,
|
||||
'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,
|
||||
'shield4': 58,
|
||||
'shield5': 59,
|
||||
'book': 9,
|
||||
'fly': 12,
|
||||
'pickaxe': 45,
|
||||
'icePickaxe': 44,
|
||||
'bomb': 43,
|
||||
'centerFly': 13,
|
||||
'upFly': 15,
|
||||
'downFly': 14,
|
||||
'coin': 11,
|
||||
'snow': 41,
|
||||
'cross': 40,
|
||||
'superPotion': 29,
|
||||
'earthquake': 8,
|
||||
'poisonWine': 24,
|
||||
'weakWine': 25,
|
||||
'curseWine': 27,
|
||||
'superWine': 28,
|
||||
'knife': 42,
|
||||
'moneyPocket': 46,
|
||||
'shoes': 47,
|
||||
'hammer': 48
|
||||
},
|
||||
"autotile": { // 所有的Autotile列表;后面的index简单取0即可
|
||||
"autotile": 0,
|
||||
"autotile1": 0,
|
||||
"autotile2": 0,
|
||||
"autotile3": 0,
|
||||
'autotile': { // 所有的Autotile列表;后面的index简单取0即可
|
||||
'autotile': 0,
|
||||
'autotile1': 0,
|
||||
'autotile2': 0,
|
||||
'autotile3': 0,
|
||||
}
|
||||
}
|
||||
BIN
project/images/forward.png
Normal file
|
After Width: | Height: | Size: 662 B |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
BIN
project/images/pause.png
Normal file
|
After Width: | Height: | Size: 269 B |
BIN
project/images/play.png
Normal file
|
After Width: | Height: | Size: 340 B |
BIN
project/images/rewind.png
Normal file
|
After Width: | Height: | Size: 689 B |
BIN
project/images/stop.png
Normal file
|
After Width: | Height: | Size: 239 B |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png
Normal file
|
After Width: | Height: | Size: 55 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/animates2:四方门.png
Normal file
|
After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/items1:方块宝石.png
Normal file
|
After Width: | Height: | Size: 35 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/四方机关门.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/宝石1.png
Normal file
|
After Width: | Height: | Size: 3.7 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/宝石2.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/宝石3.png
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/宝石4.png
Normal file
|
After Width: | Height: | Size: 33 KiB |
BIN
project/images/常用素材:如需使用请直接替换目录中的对应文件/旋转机关门.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
@ -2,12 +2,12 @@ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
||||
{
|
||||
|
||||
"items" : {
|
||||
|
||||
// 钥匙
|
||||
'yellowKey': {'cls': 'keys', 'name': '黄钥匙'},
|
||||
'blueKey': {'cls': 'keys', 'name': '蓝钥匙'},
|
||||
'redKey': {'cls': 'keys', 'name': '红钥匙'},
|
||||
|
||||
|
||||
// 宝石、血瓶
|
||||
'redJewel': {'cls': 'items', 'name': '红宝石'},
|
||||
'blueJewel': {'cls': 'items', 'name': '蓝宝石'},
|
||||
'greenJewel': {'cls': 'items', 'name': '绿宝石'},
|
||||
@ -16,20 +16,22 @@ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
||||
'bluePotion': {'cls': 'items', 'name': '蓝血瓶'},
|
||||
'yellowPotion': {'cls': 'items', 'name': '黄血瓶'},
|
||||
'greenPotion': {'cls': 'items', 'name': '绿血瓶'},
|
||||
'sword1': {'cls': 'items', 'name': '铁剑'},
|
||||
'sword2': {'cls': 'items', 'name': '银剑'},
|
||||
'sword3': {'cls': 'items', 'name': '骑士剑'},
|
||||
'sword4': {'cls': 'items', 'name': '圣剑'},
|
||||
'sword5': {'cls': 'items', 'name': '神圣剑'},
|
||||
'shield1': {'cls': 'items', 'name': '铁盾'},
|
||||
'shield2': {'cls': 'items', 'name': '银盾'},
|
||||
'shield3': {'cls': 'items', 'name': '骑士盾'},
|
||||
'shield4': {'cls': 'items', 'name': '圣盾'},
|
||||
'shield5': {'cls': 'items', 'name': '神圣盾'},
|
||||
'sword1': {'cls': 'items', 'name': '铁剑', 'isEquipment': true},
|
||||
'sword2': {'cls': 'items', 'name': '银剑', 'isEquipment': true},
|
||||
'sword3': {'cls': 'items', 'name': '骑士剑', 'isEquipment': true},
|
||||
'sword4': {'cls': 'items', 'name': '圣剑', 'isEquipment': true},
|
||||
'sword5': {'cls': 'items', 'name': '神圣剑', 'isEquipment': true},
|
||||
'shield1': {'cls': 'items', 'name': '铁盾', 'isEquipment': true},
|
||||
'shield2': {'cls': 'items', 'name': '银盾', 'isEquipment': true},
|
||||
'shield3': {'cls': 'items', 'name': '骑士盾', 'isEquipment': true},
|
||||
'shield4': {'cls': 'items', 'name': '圣盾', 'isEquipment': true},
|
||||
'shield5': {'cls': 'items', 'name': '神圣盾', 'isEquipment': true},
|
||||
'superPotion': {'cls': 'items', 'name': '圣水'},
|
||||
'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': '持有时打败怪物可得双倍金币'},
|
||||
@ -38,7 +40,7 @@ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
|
||||
'knife': {'cls': 'constants', 'name': '屠龙匕首', 'text': '该道具尚未被定义'},
|
||||
'shoes': {'cls': 'constants', 'name': '绿鞋', 'text': '持有时无视负面地形'},
|
||||
|
||||
|
||||
// 道具
|
||||
'bigKey': {'cls': 'tools', 'name': '大黄门钥匙', 'text': '可以开启当前层所有黄门'},
|
||||
'greenKey': {'cls': 'tools', 'name': '绿钥匙', 'text': '可以打开一扇绿门'},
|
||||
'steelKey': {'cls': 'tools', 'name': '铁门钥匙', 'text': '可以打开一扇铁门'},
|
||||
|
||||
@ -8,7 +8,7 @@ maps_comment_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
||||
'3':' 蓝墙',
|
||||
'4':' 星空',
|
||||
'5':' 岩浆',
|
||||
'6':' 岩浆',
|
||||
'6':' 冰面',
|
||||
'7':' 蓝色商店左',
|
||||
'8':' 蓝色商店右',
|
||||
'9':' 粉色商店左',
|
||||
|
||||
@ -5,10 +5,10 @@ maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
|
||||
// 0-20 地形
|
||||
'1':{'cls': 'terrains', 'id': 'yellowWall'}, // 黄墙
|
||||
'2':{'cls': 'terrains', 'id': 'whiteWall'}, // 白墙
|
||||
'3':{'cls': 'terrains', 'id': 'blueWall'}, // 白墙
|
||||
'3':{'cls': 'terrains', 'id': 'blueWall'}, // 蓝墙
|
||||
'4':{'cls': 'animates', 'id': 'star', 'noPass': true}, // 星空
|
||||
'5':{'cls': 'animates', 'id': 'lava', 'noPass': true}, // 岩浆
|
||||
'6':{'cls': 'terrains', 'id': 'ice'}, // 岩浆
|
||||
'6':{'cls': 'terrains', 'id': 'ice'}, // 冰面
|
||||
'7':{'cls': 'terrains', 'id': 'blueShop-left'}, // 蓝色商店左
|
||||
'8':{'cls': 'terrains', 'id': 'blueShop-right'}, // 蓝色商店右
|
||||
'9':{'cls': 'terrains', 'id': 'pinkShop-left'}, // 粉色商店左
|
||||
|
||||
BIN
project/sounds/zone.ogg
Normal file
46
styles.css
@ -21,7 +21,7 @@
|
||||
position: fixed;
|
||||
top: 10px;
|
||||
left: 10px;
|
||||
z-index: 13;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#startPanel {
|
||||
@ -32,7 +32,7 @@
|
||||
left: 0;
|
||||
background-color: #fff;
|
||||
overflow: hidden;
|
||||
z-index: 9;
|
||||
z-index: 11;
|
||||
}
|
||||
|
||||
#startTop {
|
||||
@ -42,7 +42,7 @@
|
||||
top: 0;
|
||||
left: 0;
|
||||
background-color: #000;
|
||||
z-index: 12;
|
||||
z-index: 14;
|
||||
}
|
||||
|
||||
#startTopProgressBar {
|
||||
@ -52,7 +52,7 @@
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
background-color: #fff;
|
||||
z-index: 13;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#startTopProgress {
|
||||
@ -67,7 +67,7 @@
|
||||
position: absolute;
|
||||
top: 8%;
|
||||
left: 5%;
|
||||
z-index: 13;
|
||||
z-index: 15;
|
||||
}
|
||||
|
||||
#startBackground {
|
||||
@ -77,12 +77,12 @@
|
||||
height: 100%;
|
||||
width: auto;
|
||||
transform:translate(-50%,-50%);
|
||||
z-index: 10;
|
||||
z-index: 12;
|
||||
}
|
||||
|
||||
#startLogo {
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
z-index: 12;
|
||||
left: 0;
|
||||
right: 0;
|
||||
margin-left: auto;
|
||||
@ -90,12 +90,12 @@
|
||||
margin-top: 8%;
|
||||
max-width: 100%;
|
||||
text-align: center;
|
||||
font: bold 4rem 华文行楷;
|
||||
font: bold 4rem STXingkai;
|
||||
}
|
||||
|
||||
#startTitle {
|
||||
position: absolute;
|
||||
z-index: 11;
|
||||
z-index: 13;
|
||||
}
|
||||
|
||||
#startButtonGroup {
|
||||
@ -106,7 +106,7 @@
|
||||
background-color: #000;
|
||||
opacity: 0.85;
|
||||
display: none;
|
||||
z-index: 10;
|
||||
z-index: 12;
|
||||
bottom: 0;
|
||||
margin-bottom: 7%;
|
||||
}
|
||||
@ -142,12 +142,12 @@
|
||||
display: none;
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
z-index: 8;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
#logoLabel {
|
||||
margin-top: 8%;
|
||||
font: bold 3rem 华文行楷;
|
||||
font: bold 3rem STXingkai;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
}
|
||||
@ -169,8 +169,8 @@
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
background: url(project/images/ground.png) round;
|
||||
z-index: 7;
|
||||
background: url(project/images/ground.png) repeat;
|
||||
z-index: 9;
|
||||
display: none;
|
||||
}
|
||||
#statusBar .status{
|
||||
@ -198,8 +198,8 @@
|
||||
}
|
||||
#toolBar {
|
||||
position: absolute;
|
||||
background: url(project/images/ground.png) round;
|
||||
z-index: 6;
|
||||
background: url(project/images/ground.png) repeat;
|
||||
z-index: 8;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
@ -234,7 +234,7 @@ span#poison, span#weak, span#curse {
|
||||
}
|
||||
|
||||
#curtain {
|
||||
z-index: 5;
|
||||
z-index: 7;
|
||||
position: absolute;
|
||||
opacity: 0;
|
||||
background: #000000;
|
||||
@ -256,12 +256,20 @@ span#poison, span#weak, span#curse {
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
#ui {
|
||||
#animate {
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
#weather {
|
||||
z-index: 6;
|
||||
}
|
||||
|
||||
#ui {
|
||||
z-index: 8;
|
||||
}
|
||||
|
||||
#data {
|
||||
z-index: 7;
|
||||
z-index: 9;
|
||||
}
|
||||
|
||||
.clearfix:before,
|
||||
|
||||
BIN
常用工具/Newtonsoft.Json.dll
Normal file
BIN
常用工具/RM动画导出器.exe
Normal file
BIN
常用工具/rgss.dll
Normal file
BIN
常用工具/便捷PS工具.exe
@ -3,14 +3,18 @@
|
||||
=== 全局 ===
|
||||
[↑][↓][←][→] 移动勇士
|
||||
[CTRL] 跳过对话
|
||||
[Z] 转向
|
||||
[X] 打开/关闭怪物手册
|
||||
[G] 打开/关闭楼层传送器
|
||||
[A] 读取自动存档
|
||||
[S] 打开/关闭存档页面
|
||||
[D] 打开/关闭读档页面
|
||||
[K] 打开/关闭快捷商店选择列表
|
||||
[T] 打开/关闭工具栏
|
||||
[ESC] 打开/关闭系统菜单
|
||||
[E] 显示光标
|
||||
[H] 打开帮助页面
|
||||
[R] 回放
|
||||
[SPACE] 轻按(仅在轻按开关打开时有效)
|
||||
[1] 快捷使用破墙镐
|
||||
[2] 快捷使用炸弹/圣锤(先检测有没有炸弹,没有再检测圣锤)
|
||||
|
||||
52
更新说明.txt
@ -1,4 +1,54 @@
|
||||
HTML5魔塔样板V1.3:
|
||||
HTML5魔塔样板V1.4.1
|
||||
|
||||
改变图块(setBlock事件)。
|
||||
同一个点的多事件处理(做法详见文档)。
|
||||
地图中每个块的可通行方向控制(悬崖效果)。
|
||||
动画支持带旋转和翻转的帧。
|
||||
现在可以允许用户丢弃道具了(例如不会再使用的装备)。
|
||||
修复行走时按键会发生动画抖动问题。
|
||||
修复无法打开战斗动画的Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.4
|
||||
|
||||
动画!动画!!动画!!!
|
||||
瞬间移动。
|
||||
支持天气系统,可以在剧本中设置默认天气。
|
||||
新增自定义事件-图片显示。
|
||||
同时可以在剧本中设定多个背景素材。
|
||||
剧情文本特性控制,人物的对话框效果。
|
||||
单存档同步到服务器,下载到文件和读取。
|
||||
键盘支持自动寻路操作。
|
||||
浏览地图模式下可以查看怪物数据。
|
||||
未成功打怪和开门则不自动存档。
|
||||
重新支持楼梯穿透。
|
||||
支持多结局,成绩将分开统计。
|
||||
重构全局动画、行走动画和行走检测,大幅提升性能。
|
||||
修复所有已知Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.3.2
|
||||
|
||||
增加录像和回放功能。
|
||||
增加统计功能,现在能看到每部塔的游戏人数、通关人数和当前MAX了。
|
||||
增加浏览地图功能,玩家可以快速查看每层楼的地图。
|
||||
现在保存文件到本地,以及从本地文件读档了。
|
||||
可以在全局开关中设置剑盾是否作为装备存在。
|
||||
修复了部分已知Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.3.1:
|
||||
|
||||
增加虚拟键盘。
|
||||
增加自动存档(回退),A键可快速读档。
|
||||
修复几处较为严重的Bug。
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
HTML5魔塔样板V1.3:
|
||||
|
||||
支持全键盘操作。
|
||||
支持将某个图片作为某层的背景素材。
|
||||
|
||||