diff --git a/.idea/mota-js.xml b/.idea/mota-js.xml
new file mode 100644
index 00000000..24643cc3
--- /dev/null
+++ b/.idea/mota-js.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE.md b/LICENSE.md
new file mode 100644
index 00000000..e145e12f
--- /dev/null
+++ b/LICENSE.md
@@ -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.
diff --git a/README.md b/README.md
index db47a83d..66369b8a 100644
--- a/README.md
+++ b/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] 支持全键盘操作。
diff --git a/_server/css/editor.css b/_server/css/editor.css
index 1ffb46b9..13e74df7 100644
--- a/_server/css/editor.css
+++ b/_server/css/editor.css
@@ -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;
diff --git a/_server/editor.js b/_server/editor.js
index 8741332d..a6dc7b18 100644
--- a/_server/editor.js
+++ b/_server/editor.js
@@ -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;
diff --git a/_server/vendor/polyfill.min.js b/_server/vendor/polyfill.min.js
new file mode 100644
index 00000000..80fe8dc8
--- /dev/null
+++ b/_server/vendor/polyfill.min.js
@@ -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)});
diff --git a/_server/vm.js b/_server/vm.js
index 3ae26442..8b227a19 100644
--- a/_server/vm.js
+++ b/_server/vm.js
@@ -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;
}
}
diff --git a/docs/api.md b/docs/api.md
index ebd28f99..ec92f8a5 100644
--- a/docs/api.md
+++ b/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 // 绘制一个缩略图
diff --git a/docs/element.md b/docs/element.md
index ef764af5..d66b2c41 100644
--- a/docs/element.md
+++ b/docs/element.md
@@ -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]** 快捷使用炸弹/圣锤
diff --git a/docs/event.md b/docs/event.md
index 58d0917e..8bdf07cb 100644
--- a/docs/event.md
+++ b/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进行一段对话。
diff --git a/docs/img/blood.png b/docs/img/blood.png
index 7d369e74..53d52171 100644
Binary files a/docs/img/blood.png and b/docs/img/blood.png differ
diff --git a/docs/img/tuihua.png b/docs/img/tuihua.png
new file mode 100644
index 00000000..de7d1836
Binary files /dev/null and b/docs/img/tuihua.png differ
diff --git a/docs/index.md b/docs/index.md
index 9f0059ef..7a358d0d 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,6 +1,6 @@
# HTML5 魔塔样板说明文档
-?> 上次更新时间:* {docsify-updated} *
+?> 目前版本**v1.4.1**,上次更新时间:* {docsify-updated} *
众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。
diff --git a/docs/personalization.md b/docs/personalization.md
index 9b4eb0ca..1f4fbd0b 100644
--- a/docs/personalization.md
+++ b/docs/personalization.md
@@ -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函数中。
diff --git a/docs/start.md b/docs/start.md
index 8ddde2af..c9a838c0 100644
--- a/docs/start.md
+++ b/docs/start.md
@@ -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`,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!
+做完后保存所有文件,在本地服务器中“启动游戏”,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢!

diff --git a/editor.html b/editor.html
index 1d03c983..4e1f4ebd 100644
--- a/editor.html
+++ b/editor.html
@@ -179,7 +179,7 @@
开始游戏
载入游戏
- 关于本塔
+ 录像回放
简单
@@ -256,6 +256,8 @@
+
+
@@ -284,6 +286,7 @@
+
diff --git a/index.html b/index.html
index a8d12214..5c84fe0c 100644
--- a/index.html
+++ b/index.html
@@ -32,7 +32,7 @@
开始游戏
载入游戏
- 关于本塔
+ 录像回放
简单
@@ -109,11 +109,13 @@
+
+
-
+