diff --git a/docs/api.md b/docs/api.md
index d1b609f4..ebd28f99 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -1,13 +1,44 @@
# 附录:API列表
+?> 上次更新时间:* {docsify-updated} *
+
所有系统支持的API都列在了这里。所有可能被用到的API都在前面用\*标记。
可以在chrome浏览器的控制台中(`ctrl+shift+I`,找到Console)中直接进行调用,以查看效果。
-!> **`main.js`:游戏入口。所有其他JS文件都是被此文件加载。**
+!> **`main.js`:游戏入口,所有其他JS文件都是被此文件加载。**
``` js
-
+main.init // 初始化
+main.loaderJs // 动态加载所有核心JS文件
+main,loaderFloors // 动态加载所有楼层(剧本)
+main.loadMod // 加载某一个JS文件
+main.loadFloor // 加载某一个楼层
+main.setMainTipsText // 加载过程提示
+window.onresize // 窗口大小变化时
+main.dom.body.onkeydown // 在界面上按下某按键时
+main.dom.body.onkeydown // 在界面上放开某按键时
+main.dom.body.onselectstart // 开始选择时
+main.dom.data.onmousedown // 鼠标按下时
+main.dom.data.onmousemove // 鼠标移动时
+main.dom.data.onmouseup // 鼠标放开时
+main.dom.data.onmousewheel // 鼠标滑轮滚动时
+main.dom.data.ontouchstart // 手指在触摸屏开始触摸时
+main.dom.data.ontouchmove // 手指在触摸屏上移动时
+main.dom.data.ontouchend // 手指离开触摸屏时
+main.statusBar.image.book.onclick // 点击状态栏中的怪物手册时
+main.statusBar.image.fly.onclick // 点击状态栏中的楼层传送器时
+main.statusBar.image.toolbox.onclick // 点击状态栏中的工具箱时
+main.statusBar.image.shop.onclick // 点击状态栏中的快捷商店时
+main.statusBar.image.save.onclick // 点击状态栏中的存档按钮时
+main.statusBar.image.load.onclick // 点击状态栏中的读档按钮时
+main.statusBar.image.settings.onclick // 点击状态栏中的系统菜单时
+main.dom.playGame.onclick // 点击“开始游戏”时
+main.dom.loadGame.onclick // 点击“载入游戏”时
+main.dom.aboutGame.onclick // 点击“关于本塔”时
+main.dom.easyLevel.onclick // 点击“简单难度”时
+main.dom.normalLevel.onclick // 点击“普通难度”时
+main.dom.hardLevel.onclick // 点击“困难难度”时
```
!> **`core.js`:系统核心文件。所有核心逻辑处理都在此文件完成。**
@@ -97,7 +128,6 @@ core.setOpacity // 设置某个canvas的透明度
core.setFillStyle // 设置某个canvas的绘制属性(如颜色等)
* core.drawMap(mapId, callback) // 绘制某张地图。mapId为地图Id,绘制完毕将执行callback回调函数。
core.drawAutotile // 绘制Autotile
-core.drawAutotileBlock // 绘制Autotile的某一块
* core.noPassExists(x,y) // 某个点是否不可通行
core.noPass // 某个点是否在区域内且不可通行
* core.npcExists(x,y) // 某个点是否存在NPC
@@ -291,6 +321,7 @@ core.maps.addChangeFloor // 向该楼层添加剧本的楼层转换事件
core.maps.initMaps // 初始化所有地图
core.maps.save // 将当前地图重新变成数字,以便于存档
core.maps.load // 将存档中的地图信息重新读取出来
+core.maps.getMapArray // 将当前地图重新变成二维数组形式
```
!> `ui.js` 定义了各种界面的绘制。
diff --git a/docs/element.md b/docs/element.md
index 50459e42..ef764af5 100644
--- a/docs/element.md
+++ b/docs/element.md
@@ -1,5 +1,7 @@
# 元件说明
+?> 上次更新时间:* {docsify-updated} *
+
在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。
请打开样板0层 `sample0.js` 进行参照对比。
@@ -30,7 +32,7 @@
## 怪物
-本塔支持的怪物列表参见`enemys.js`。其与images目录下的`enemys.png`素材按顺序一一对应。如不知道怪物素材长啥样的请打开`enemys.png`对比查看。
+本塔支持的怪物列表参见`enemys.js`。其与images目录下的`enemys.png`素材按顺序一一对应。如不知道怪物素材长啥样的请打开`enemys.png`对比查看。
如有自己的怪物素材需求请参见[自定义素材](personalization#自定义素材)的内容。
怪物可以有特殊属性,每个怪物可以有多个自定义属性。
@@ -70,6 +72,7 @@ enemys.prototype.getSpecialText = function (enemyId) {
多属性可采用数组的写法,比如`'special': [1,3]`视为同时拥有先攻和坚固属性;`'special': [5,10,14,18]`视为拥有3连击、魔防、诅咒、阻击四个属性。
本塔支持战斗动画,在`data.js`中存在三个全局选项:`canOpenBattleAnimate`, `showBattleAnimateConfirm`, `battleAnimate`。
+
- `canOpenBattleAnimate`代表是否允许用户开启战斗动画。如果你添加了一些自定义属性,且不想修改战斗界面的UI,则可以将其关闭。
- `showBattleAnimateConfirm`代表是否在游戏开始时给用户提供开启动画的选项。对于一些偏向于萌新的塔,可以开启此项。
- `battleAnimate`代表是否默认开启战斗动画。此项会被用户存储的设置给覆盖。
@@ -117,7 +120,7 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数
如有额外需求,可参见[自定义怪物属性](personalization#自定义自定义怪物属性),里面讲了如何设置一个新的怪物属性。
-### 路障,楼梯,传送门
+## 路障,楼梯,传送门
血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在 `data.js` 的values内定义。
@@ -143,7 +146,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。

-### 背景音乐
+## 背景音乐
本塔支持BGM和SE的播放。
@@ -169,17 +172,19 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。
**另外,考虑到用户的流量问题,将遵循如下规则:**
+
- **如果用户当前使用的电脑,则默认开启音乐效果,并播放默认BGM**
- **如果用户当前使用的手机,且处于Wifi状态,则默认开启音乐效果,并播放默认BGM**
- **其他情况,将默认关闭音乐效果,只有在用户在菜单栏中点击“音乐开关”后才会播放音乐**
!> iOS平台以及部分浏览器不支持获得当前网络状态,此时即使在使用Wifi也必须要用户点击“音乐开关”才能播放音乐。
-### 操作说明
+## 操作说明
本塔主要支持鼠标(触摸屏)操作和键盘操作。
鼠标(触摸屏)操作说明如下:
+
- **点状态栏中图标:** 进行对应的操作
- **点任意块:** 寻路并移动
- **点任意块并拖动:** 指定寻路路线
@@ -187,6 +192,7 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
- **双击勇士:** 轻按(仅在轻按开关打开时有效)
键盘操作快捷键如下:
+
- **[CTRL]** 跳过对话
- **[X]** 打开/关闭怪物手册
- **[G]** 打开/关闭楼层传送器
@@ -213,4 +219,3 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致
==========================================================================================
[继续阅读下一章:事件](event)
-
diff --git a/docs/event.md b/docs/event.md
index 2f283b69..58d0917e 100644
--- a/docs/event.md
+++ b/docs/event.md
@@ -1,5 +1,7 @@
# 事件
+?> 上次更新时间:* {docsify-updated} *
+
本章内将对样板所支持的事件进行介绍。
## 事件的机制
@@ -965,6 +967,26 @@ events.prototype.addPoint = function (enemy) {
当且仅当勇士第一次到达某层时,将会触发此事件。可以利用此事件来显示一些剧情,或再让它调用 `{"type": "trigger"}` 来继续调用其他的事件。
+## 战前剧情
+
+有时候光战后事件`afterBattle`是不够的,我们可能还需要战前剧情,例如Boss战之前和Boss进行一段对话。
+
+要使用战前剧情,首先你需要覆盖该店的系统默认事件,改成你自己的自定义事件,然后在战前剧情后调用`{"type": "battle"}`强制战斗。
+
+值得注意的是,使用这种自定义事件来覆盖系统的默认战斗事件时,可以增加`displayDamage`代表该点是否需要显伤。此项可省略,默认为有显伤。
+
+``` js
+"x,y": { // (x,y)为该怪物坐标
+ "trigger": "action", // 覆盖该点本身默认事件,变成自定义事件
+ "displayDamage": true, // 覆盖后,该点是否有显伤;此项可忽略,默认为有。
+ "data": [ // 该点的自定义事件列表
+ // ... 战前剧情
+ {"type": "battle", "id": "xxx"}, // 强制战斗
+ // ... 战后剧情;请注意上面的强制战斗不会使怪物消失,如有需要请调动{"type": "hide"}
+ ]
+}
+```
+
## 经验升级(进阶/境界塔)
本塔也支持经验升级,即用户杀怪获得经验后,可以到达某些数值自动进阶,全面提升属性。
@@ -1039,9 +1061,8 @@ events.prototype.setInitData = function (hard) {
当获胜`{"type": "win"}`事件发生时,将调用`events.js`中的win事件。其显示一段恭喜文字,并重新开始游戏。
``` js
-////// 游戏结束事件 //////
+////// 游戏获胜事件 //////
events.prototype.win = function(reason) {
- // 获胜
core.waitHeroToStop(function() {
core.removeGlobalAnimate(0,0,true);
core.clearMap('all'); // 清空全地图
@@ -1059,8 +1080,8 @@ events.prototype.win = function(reason) {
当失败(`{"type": "lose"}`,或者被怪强制战斗打死、被领域怪扣血死、中毒导致扣血死,路障导致扣血死等等)事件发生时,将调用`events.js`中的`lose`事件。其直接显示一段文字,并重新开始游戏。
``` js
+////// 游戏失败事件 //////
events.prototype.lose = function(reason) {
- // 失败
core.waitHeroToStop(function() {
core.drawText([
"\t[结局1]你死了。\n如题。"
diff --git a/docs/index.html b/docs/index.html
index 8065a5e4..4c8311fa 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -19,7 +19,7 @@
repo: 'https://github.com/ckcz123/mota-js',
// basepath: '../docs/',
- // Search Support
+ // Search Support
// search: {
// maxAge: 43200000, // 过期时间,单位毫秒,默认一天
// paths: 'auto',
@@ -37,10 +37,9 @@
loadSidebar: '_sidebar.md',
subMaxLevel: 2,
autoHeader: true,
- }
- //离线模式
- if (typeof navigator.serviceWorker !== 'undefined') {
- navigator.serviceWorker.register('serviceWorker.js')
+ auto2top: true,
+ mergeNavbar: true,
+ formatUpdated: '{YYYY}-{MM}-{DD} {HH}:{mm}:{ss}',
}
diff --git a/docs/index.md b/docs/index.md
index ad17349c..9f0059ef 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -1,5 +1,7 @@
# HTML5 魔塔样板说明文档
+?> 上次更新时间:* {docsify-updated} *
+
众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。
但是,现在我们有了HTML5。 HTML5的画布(canvas)以及它被Android/iOS内置浏览器所支持的特性,可以让我们做出真正意义上的全平台覆盖的魔塔。
@@ -11,7 +13,7 @@
继续查看文档的详细介绍,让你学会如何使用这一个样板来制作属于自己的HTML5魔塔。
-视频教程地址:http://www.bilibili.com/video/av17608025/ ,配合本教程观看效果更佳~
+视频教程地址:[http://www.bilibili.com/video/av17608025/](http://www.bilibili.com/video/av17608025/) ,配合本教程观看效果更佳~
==========================================================================================
diff --git a/docs/personalization.md b/docs/personalization.md
index 8e5eca3f..9b4eb0ca 100644
--- a/docs/personalization.md
+++ b/docs/personalization.md
@@ -1,5 +1,7 @@
# 个性化
+?> 上次更新时间:* {docsify-updated} *
+
有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。
## 自定义素材
diff --git a/docs/serviceWorker.js b/docs/serviceWorker.js
deleted file mode 100644
index ab031ac1..00000000
--- a/docs/serviceWorker.js
+++ /dev/null
@@ -1,75 +0,0 @@
-const RUNTIME = 'docsify'
-const HOSTNAME_WHITELIST = [
- self.location.hostname,
- 'fonts.gstatic.com',
- 'fonts.googleapis.com',
- 'unpkg.com'
-]
-
-// The Util Function to hack URLs of intercepted requests
-const getFixedUrl = (req) => {
- var now = Date.now()
- var url = new URL(req.url)
-
- // 1. fixed http URL
- // Just keep syncing with location.protocol
- // fetch(httpURL) belongs to active mixed content.
- // And fetch(httpRequest) is not supported yet.
- url.protocol = self.location.protocol
-
- // 2. add query for caching-busting.
- // Github Pages served with Cache-Control: max-age=600
- // max-age on mutable content is error-prone, with SW life of bugs can even extend.
- // Until cache mode of Fetch API landed, we have to workaround cache-busting with query string.
- // Cache-Control-Bug: https://bugs.chromium.org/p/chromium/issues/detail?id=453190
- if (url.hostname === self.location.hostname) {
- url.search += (url.search ? '&' : '?') + 'cache-bust=' + now
- }
- return url.href
-}
-
-/**
- * @Lifecycle Activate
- * New one activated when old isnt being used.
- *
- * waitUntil(): activating ====> activated
- */
-self.addEventListener('activate', event => {
- event.waitUntil(self.clients.claim())
-})
-
-/**
- * @Functional Fetch
- * All network requests are being intercepted here.
- *
- * void respondWith(Promise r)
- */
-self.addEventListener('fetch', event => {
- // Skip some of cross-origin requests, like those for Google Analytics.
- if (HOSTNAME_WHITELIST.indexOf(new URL(event.request.url).hostname) > -1) {
- // Stale-while-revalidate
- // similar to HTTP's stale-while-revalidate: https://www.mnot.net/blog/2007/12/12/stale
- // Upgrade from Jake's to Surma's: https://gist.github.com/surma/eb441223daaedf880801ad80006389f1
- const cached = caches.match(event.request)
- const fixedUrl = getFixedUrl(event.request)
- const fetched = fetch(fixedUrl, { cache: 'no-store' })
- const fetchedCopy = fetched.then(resp => resp.clone())
-
- // Call respondWith() with whatever we get first.
- // If the fetch fails (e.g disconnected), wait for the cache.
- // If there’s nothing in cache, wait for the fetch.
- // If neither yields a response, return offline pages.
- event.respondWith(
- Promise.race([fetched.catch(_ => cached), cached])
- .then(resp => resp || fetched)
- .catch(_ => { /* eat any errors */ })
- )
-
- // Update the cache with the version we fetched (only for ok status)
- event.waitUntil(
- Promise.all([fetchedCopy, caches.open(RUNTIME)])
- .then(([response, cache]) => response.ok && cache.put(event.request, response))
- .catch(_ => { /* eat any errors */ })
- )
- }
-})
diff --git a/docs/start.md b/docs/start.md
index 10300b46..8ddde2af 100644
--- a/docs/start.md
+++ b/docs/start.md
@@ -1,5 +1,7 @@
# 快速上手
+?> 上次更新时间:* {docsify-updated} *
+
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
## 前置需求
@@ -8,8 +10,8 @@
- Windows 8以上操作系统;Windows 7需要安装.Net Framework 4.0。(能打开同目录下的“启动服务.exe”即可)
- 任一款现代浏览器。强烈推荐Chrome。
-- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。
-([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。)
+- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。
+ - ([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。)
只要满足了上述条件,你就可以开始做自己的塔啦!
diff --git a/libs/core.js b/libs/core.js
index a8419715..1e8dd4db 100644
--- a/libs/core.js
+++ b/libs/core.js
@@ -296,7 +296,7 @@ core.prototype.loadImage = function (imgName, callback) {
if (name.indexOf(".png")<0) // 不包含"png"
name=name+".png";
var image = new Image();
- image.src = 'images/' + name;
+ image.src = 'images/' + name + "?v=" + main.version;
if (image.complete) {
callback(imgName, image);
return;
@@ -2013,6 +2013,7 @@ core.prototype.drawMap = function (mapName, callback) {
core.canvas.bg.drawImage(blockImage, 0, blockIcon * 32, 32, 32, x * 32, y * 32, 32, 32);
}
}
+
// 如果存在png
if (core.isset(core.floors[mapName].png)) {
var png = core.floors[mapName].png;
@@ -2021,15 +2022,13 @@ core.prototype.drawMap = function (mapName, callback) {
}
}
- var autotileMaps = [];
+ var mapArray = core.maps.getMapArray(core.status.maps, mapName);
for (var b = 0; b < mapBlocks.length; b++) {
// 事件启用
var block = mapBlocks[b];
if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) {
if (block.event.cls == 'autotile') {
- // core.drawAutotile();
- autotileMaps[13*block.x + block.y] = block.event.id;
- continue;
+ core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0);
}
else {
if (block.event.id!='none') {
@@ -2041,140 +2040,90 @@ core.prototype.drawMap = function (mapName, callback) {
}
}
}
- core.drawAutotile(mapName, 'event', autotileMaps, 0, 0, 32);
core.setGlobalAnimate(core.values.animateSpeed);
-
if (core.isset(callback))
callback();
}
////// 绘制Autotile //////
-core.prototype.drawAutotile = function (floorId, canvas, autotileMaps, left, top, size, autotileId) {
-
- if (!core.isset(autotileId)) {
- var autotileIds = {};
- autotileMaps.forEach(function (t) {
- if (core.isset(t)) autotileIds[t]=true;
- });
- Object.keys(autotileIds).forEach(function (t) {
- core.drawAutotile(floorId, canvas, autotileMaps, left, top, size, t);
- })
- return;
+core.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top){
+ var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块
+ // +----+----+----+----+----+----+
+ [10, 9, 4, 3 ], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 |
+ [10, 9, 4, 13], //1 bin:0001 +----+----+----+----+----+----+
+ [10, 9, 18, 3 ], //2 bin:0010 | 7 | 8 | 9 | 10 | 11 | 12 |
+ [10, 9, 16, 15], //3 bin:0011 +----+----+----+----+----+----+
+ [10, 43, 4, 3 ], //4 bin:0100 | 13 | 14 | 15 | 16 | 17 | 18 |
+ [10, 31, 4, 25], //5 bin:0101 +----+----+----+----+----+----+
+ [10, 7, 2, 3 ], //6 bin:0110 | 19 | 20 | 21 | 22 | 23 | 24 |
+ [10, 31, 16, 5 ], //7 bin:0111 +----+----+----+----+----+----+
+ [48, 9, 4, 3 ], //8 bin:1000 | 25 | 26 | 27 | 28 | 29 | 30 |
+ [ 8, 9, 4, 1 ], //9 bin:1001 +----+----+----+----+----+----+
+ [36, 9, 30, 3 ], //10 bin:1010 | 31 | 32 | 33 | 34 | 35 | 36 |
+ [36, 9, 6, 15], //11 bin:1011 +----+----+----+----+----+----+
+ [46, 45, 4, 3 ], //12 bin:1100 | 37 | 38 | 39 | 40 | 41 | 42 |
+ [46, 11, 4, 25], //13 bin:1101 +----+----+----+----+----+----+
+ [12, 45, 30, 3 ], //14 bin:1110 | 43 | 44 | 45 | 46 | 47 | 48 |
+ [34, 33, 28, 27] //15 bin:1111 +----+----+----+----+----+----+
+ ];
+
+ var drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size){ //index为autotile的图块索引1-48
+ var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6));
+ ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, size/2, size/2);
}
-
- var isAutotile = function(x, y) {
- if (x<0 || x>12 || y<0 || y>12) return 1;
- return autotileMaps[13*x+y]==autotileId?1:0;
+ var getAutotileAroundId = function(currId, x, y){
+ if(x<0 || y<0 || x>12 || y>12) return 1;
+ else return mapArr[y][x]==currId ? 1:0;
}
- for (var xx=0;xx<13;xx++) {
- for (var yy=0;yy<13;yy++) {
- if (isAutotile(xx, yy)) {
- // 绘制autotile
- var id=isAutotile(xx, yy - 1) + 2 * isAutotile(xx - 1, yy) + 4 * isAutotile(xx, yy + 1) + 8 * isAutotile(xx + 1, yy);
- core.drawAutotileBlock(floorId, canvas, left + xx * size, top + yy * size, size, core.material.images.autotile[autotileId], id);
+ var checkAround = function(x, y){ // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引
+ var currId = mapArr[y][x];
+ var pointBlock = [];
+ for(var i=0; i<4; i++){
+ var bsum = 0;
+ var offsetx = i%2, offsety = ~~(i/2);
+ for(var j=0; j<4; j++){
+ var mx = j%2, my = ~~(j/2);
+ var b = getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1);
+ bsum += b*(Math.pow(2, 3-j));
}
+ pointBlock.push(bsum);
}
+ return pointBlock;
}
- for (var xx=0;xx<13;xx++) {
- for (var yy=0;yy<13;yy++) {
- if (isAutotile(xx, yy) + isAutotile(xx + 1, yy) + isAutotile(xx + 1, yy + 1) + isAutotile(xx, yy + 1) != 3) continue;
- if (!isAutotile(xx, yy)) {
- core.drawAutotileBlock(floorId, canvas, left + xx * size + size, top + yy * size + size, size, core.material.images.autotile[autotileId], 16);
- }
- if (!isAutotile(xx + 1, yy)) {
- core.drawAutotileBlock(floorId, canvas, left + xx * size + size / 2, top + yy * size + size, size, core.material.images.autotile[autotileId], 17);
- }
- if (!isAutotile(xx + 1, yy + 1)) {
- core.drawAutotileBlock(floorId, canvas, left + xx * size + size / 2, top + yy * size + size / 2, size, core.material.images.autotile[autotileId], 18);
- }
- if (!isAutotile(xx, yy + 1)) {
- core.drawAutotileBlock(floorId, canvas, left + xx * size + size, top + yy * size + size / 2, size, core.material.images.autotile[autotileId], 19);
- }
+ var getAutotileIndexs = function(x, y){
+ var indexArr = [];
+ var pointBlocks = checkAround(x, y);
+ for(var i=0; i<4; i++){
+ var arr = indexArrs[pointBlocks[i]]
+ indexArr.push(arr[3-i]);
}
+ return indexArr;
}
-}
+ // 开始绘制autotile
+ var x = block.x, y = block.y;
+ var pieceIndexs = getAutotileIndexs(x, y);
-////// 绘制Autotile的某一块 //////
-core.prototype.drawAutotileBlock = function (floorId, map, x, y, size, autotile, index) {
- var canvas = core.canvas[map];
- var groundId = core.floors[floorId].defaultGround || "ground";
- var blockIcon = core.material.icons.terrains[groundId];
- var blockImage = core.material.images.terrains;
- switch (index) {
- case 0:
- canvas.drawImage(autotile, 0, 0, 32, 32, x, y, size, size);
- break;
- case 1:
- canvas.drawImage(autotile, 0, 3 * 32, 16, 32, x, y, size / 2, size);
- canvas.drawImage(autotile, 2 * 32 + 16, 3 * 32, 16, 32, x + size / 2, y, size / 2, size);
- break;
- case 2:
- canvas.drawImage(autotile, 2 * 32, 32, 32, 16, x, y, size, size / 2);
- canvas.drawImage(autotile, 2 * 32, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2);
- break;
- case 3:
- canvas.drawImage(autotile, 2 * 32, 3 * 32, 32, 32, x, y, size, size);
- break;
- case 4:
- canvas.drawImage(autotile, 0, 1 * 32, 16, 32, x, y, size / 2, size);
- canvas.drawImage(autotile, 2 * 32 + 16, 1 * 32, 16, 32, x + size / 2, y, size / 2, size);
- break;
- case 5:
- canvas.drawImage(autotile, 0, 2 * 32, 16, 32, x, y, size / 2, size);
- canvas.drawImage(autotile, 2 * 32 + 16, 2 * 32, 16, 32, x + size / 2, y, size / 2, size);
- break;
- case 6:
- canvas.drawImage(autotile, 2 * 32, 1 * 32, 32, 32, x, y, size, size);
- break;
- case 7:
- canvas.drawImage(autotile, 2 * 32, 2 * 32, 32, 32, x, y, size, size);
- break;
- case 8:
- canvas.drawImage(autotile, 0, 32, 32, 16, x, y, size, size / 2);
- canvas.drawImage(autotile, 0, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2);
- break;
- case 9:
- canvas.drawImage(autotile, 0, 3 * 32, 32, 32, x, y, size, size);
- break;
- case 10:
- canvas.drawImage(autotile, 32, 32, 32, 16, x, y, size, size / 2);
- canvas.drawImage(autotile, 32, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2);
- break;
- case 11:
- canvas.drawImage(autotile, 32, 3 * 32, 32, 32, x, y, size, size);
- break;
- case 12:
- canvas.drawImage(autotile, 0, 32, 32, 32, x, y, size, size);
- break;
- case 13:
- canvas.drawImage(autotile, 0, 2 * 32, 32, 32, x, y, size, size);
- break;
- case 14:
- canvas.drawImage(autotile, 32, 32, 32, 32, x, y, size, size);
- break;
- case 15:
- canvas.drawImage(autotile, 32, 2 * 32, 32, 32, x, y, size, size);
- break;
- case 16:
- canvas.clearRect(x, y, size / 2, size / 2);
- canvas.drawImage(blockImage, 0, blockIcon * 32, 16, 16, x, y, size / 2, size / 2);
- canvas.drawImage(autotile, 2 * 32, 0, 16, 16, x, y, size / 2, size / 2);
- break;
- case 17:
- canvas.clearRect(x, y, size / 2, size / 2);
- canvas.drawImage(blockImage, 0, blockIcon * 32, 16, 16, x, y, size / 2, size / 2);
- canvas.drawImage(autotile, 2 * 32 + 16, 0, 16, 16, x, y, size / 2, size / 2);
- break;
- case 18:
- canvas.clearRect(x, y, size / 2, size / 2);
- canvas.drawImage(blockImage, 0, blockIcon * 32, 16, 16, x, y, size / 2, size / 2);
- canvas.drawImage(autotile, 2 * 32 + 16, 16, 16, 16, x, y, size / 2, size / 2);
- break;
- case 19:
- canvas.clearRect(x, y, size / 2, size / 2);
- canvas.drawImage(blockImage, 0, blockIcon * 32, 16, 16, x, y, size / 2, size / 2);
- canvas.drawImage(autotile, 2 * 32, 16, 16, 16, x, y, size / 2, size / 2);
- break;
+ //修正四个边角的固定搭配
+ if(pieceIndexs[0] == 13){
+ if(pieceIndexs[1] == 16) pieceIndexs[1] = 14;
+ if(pieceIndexs[2] == 31) pieceIndexs[2] = 19;
+ }
+ if(pieceIndexs[1] == 18){
+ if(pieceIndexs[0] == 15) pieceIndexs[0] = 17;
+ if(pieceIndexs[3] == 36) pieceIndexs[3] = 24;
+ }
+ if(pieceIndexs[2] == 43){
+ if(pieceIndexs[0] == 25) pieceIndexs[0] = 37;
+ if(pieceIndexs[3] == 46) pieceIndexs[3] = 44;
+ }
+ if(pieceIndexs[3] == 48){
+ if(pieceIndexs[1] == 30) pieceIndexs[1] = 42;
+ if(pieceIndexs[2] == 45) pieceIndexs[2] = 47;
+ }
+ for(var i=0; i<4; i++){
+ var index = pieceIndexs[i];
+ var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2));
+ drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size);
}
}
@@ -2876,8 +2825,19 @@ core.prototype.updateFg = function () {
core.canvas.fg.textAlign = 'left';
for (var b = 0; b < mapBlocks.length; b++) {
var x = mapBlocks[b].x, y = mapBlocks[b].y;
- if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls == 'enemys' && mapBlocks[b].event.trigger == 'battle'
+ if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls == 'enemys'
&& !(core.isset(mapBlocks[b].enable) && !mapBlocks[b].enable)) {
+
+ // 非系统默认的战斗事件(被覆盖)
+ if (mapBlocks[b].event.trigger != 'battle') {
+ // 判断显伤
+ var event = core.floors[core.status.floorId].events[x+","+y];
+ if (core.isset(event) && !(event instanceof Array)) {
+ if (core.isset(event.displayDamage) && !event.displayDamage)
+ continue;
+ }
+ }
+
var id = mapBlocks[b].event.id;
var damage = core.enemys.getDamage(id);
@@ -3061,7 +3021,7 @@ core.prototype.drawTip = function (text, itemIcon) {
return;
}
else {
- if (!core.timeout.getItemTipTimeout) {
+ if (!core.isset(core.timeout.getItemTipTimeout)) {
core.timeout.getItemTipTimeout = window.setTimeout(function () {
hide = true;
core.timeout.getItemTipTimeout = null;
@@ -3421,30 +3381,29 @@ core.prototype.syncSave = function(type) {
// send
var xhr = new XMLHttpRequest();
- xhr.open("POST", "../sync.php");
- xhr.timeout = 1000;
+ xhr.open("POST", "/games/sync.php");
xhr.onload = function(e) {
if (xhr.status==200) {
// console.log("同步成功。");
var response = JSON.parse(xhr.response);
if (response.code<0) {
- core.drawText("出错啦!\n无法同步存档到服务器。");
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg);
}
else {
core.drawText("同步成功!\n\n您的存档编号: "+response.code+"\n您的存档密码: "+response.msg+"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。")
}
}
else {
- core.drawText("出错啦!\n无法同步存档到服务器。");
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:HTTP "+xhr.status);
}
};
xhr.ontimeout = function(e) {
console.log(e);
- core.drawText("出错啦!\n无法同步存档到服务器。");
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e);
}
xhr.onerror = function(e) {
console.log(e);
- core.drawText("出错啦!\n无法同步存档到服务器。");
+ core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e);
}
xhr.send(formData);
}, function() {
@@ -3473,8 +3432,7 @@ core.prototype.syncSave = function(type) {
// send
var xhr = new XMLHttpRequest();
- xhr.open("POST", "../sync.php");
- xhr.timeout = 1000;
+ xhr.open("POST", "/games/sync.php");
xhr.onload = function(e) {
if (xhr.status==200) {
// console.log("同步成功。");
@@ -3501,22 +3459,19 @@ core.prototype.syncSave = function(type) {
core.drawText("出错啦!\n存档密码错误!");
break;
default:
- core.drawText("出错啦!\n无法从服务器同步存档。");
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg);
break;
}
-
}
else {
- core.drawText("出错啦!\n无法从服务器同步存档。");
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:HTTP "+xhr.status);
}
};
xhr.ontimeout = function(e) {
- console.log(e);
- core.drawText("出错啦!\n无法从服务器同步存档。");
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e);
}
xhr.onerror = function(e) {
- console.log(e);
- core.drawText("出错啦!\n无法从服务器同步存档。");
+ core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e);
}
xhr.send(formData);
}, function() {
diff --git a/libs/floors/sample2.js b/libs/floors/sample2.js
index acb6b881..5e440aa4 100644
--- a/libs/floors/sample2.js
+++ b/libs/floors/sample2.js
@@ -202,10 +202,26 @@ main.floors.sample2 = {
{"type": "trigger", "loc": [6,6]} // 立刻触发妖精事件
]
},
- "4,3": {"trigger":"action","enable":false}, // 四个角的大法师,添加trigger:action可避免该点出现显伤
- "8,3": {"trigger":"action","enable":false}, // 四个角的大法师
- "4,6": {"trigger":"action","enable":false}, // 四个角的大法师
- "8,6": {"trigger":"action","enable":false}, // 四个角的大法师
+ "4,3": { // 四个角的大法师,
+ "trigger": "action",
+ "displayDamage": false,
+ "enable":false
+ },
+ "8,3": { // 四个角的大法师,
+ "trigger": "action",
+ "displayDamage": false,
+ "enable":false
+ },
+ "4,6": { // 四个角的大法师,
+ "trigger": "action",
+ "displayDamage": false,
+ "enable":false
+ },
+ "8,6": { // 四个角的大法师,
+ "trigger": "action",
+ "displayDamage": false,
+ "enable":false
+ },
"6,6": { // 妖精
"enable":false, // 初始时禁用状态
diff --git a/libs/maps.js b/libs/maps.js
index 7078ea61..1e9c72dc 100644
--- a/libs/maps.js
+++ b/libs/maps.js
@@ -355,4 +355,30 @@ maps.prototype.load = function (data, floorId) {
return this.loadFloor(floorId, 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];
+
+ var blocks = [];
+ for (var x=0;x<13;x++) {
+ blocks[x]=[];
+ for (var y=0;y<13;y++) {
+ blocks[x].push(0);
+ }
+ }
+ thisFloor.blocks.forEach(function (block) {
+ if (!(core.isset(block.enable) && !block.enable))
+ blocks[block.y][block.x] = block.id;
+ });
+ return blocks;
+}
+
main.instance.maps = new maps();
\ No newline at end of file
diff --git a/libs/ui.js b/libs/ui.js
index 5904d68b..f3635f61 100644
--- a/libs/ui.js
+++ b/libs/ui.js
@@ -1084,22 +1084,19 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL
}
}
- // 如果存在png
if (core.isset(core.floors[floorId].png)) {
var png = core.floors[floorId].png;
if (core.isset(core.material.images.pngs[png])) {
- core.canvas[canvas].drawImage(core.material.images.pngs[png], x, y, size, size);
+ core.canvas.ui.drawImage(core.material.images.pngs[png], x, y, size, size);
}
}
- var autotileMaps = [];
+ var mapArray = core.maps.getMapArray(core.status.maps, floorId);
for (var b in blocks) {
var block = blocks[b];
if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) {
if (block.event.cls == 'autotile') {
- // core.drawAutotile();
- autotileMaps[13*block.x + block.y] = block.event.id;
- continue;
+ core.drawAutotile(core.canvas.ui, mapArray, block, persize, x, y);
}
else {
if (block.event.id!='none') {
@@ -1110,7 +1107,6 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL
}
}
}
- core.drawAutotile(floorId, 'ui', autotileMaps, x, y, persize);
if (core.isset(heroLoc)) {
var heroIcon = core.material.icons.hero[heroLoc.direction];
diff --git a/main.js b/main.js
index a34c18c4..fd19a8a0 100644
--- a/main.js
+++ b/main.js
@@ -117,6 +117,7 @@ function main() {
this.canvas = {};
}
+////// 初始化 //////
main.prototype.init = function () {
for (var i = 0; i < main.dom.gameCanvas.length; i++) {
main.canvas[main.dom.gameCanvas[i].id] = main.dom.gameCanvas[i].getContext('2d');
@@ -136,6 +137,7 @@ main.prototype.init = function () {
});
}
+////// 动态加载所有核心JS文件 //////
main.prototype.loaderJs = function (callback) {
var instanceNum = 0;
// 加载js
@@ -156,13 +158,14 @@ main.prototype.loaderJs = function (callback) {
}
}
+////// 动态加载所有楼层(剧本) //////
main.prototype.loaderFloors = function (callback) {
// 加载js
main.setMainTipsText('正在加载楼层文件...')
if (this.useCompress) { // 读取压缩文件
var script = document.createElement('script');
- script.src = 'libs/floors.min.js?' + this.version;
+ script.src = 'libs/floors.min.js?v=' + this.version;
main.dom.body.appendChild(script);
script.onload = function () {
main.dom.mainTips.style.display = 'none';
@@ -182,10 +185,11 @@ main.prototype.loaderFloors = function (callback) {
}
}
+////// 加载某一个JS文件 //////
main.prototype.loadMod = function (modName, callback) {
var script = document.createElement('script');
var name = modName;
- script.src = 'libs/' + modName + (this.useCompress?".min":"") + '.js?' + this.version;
+ script.src = 'libs/' + modName + (this.useCompress?".min":"") + '.js?v=' + this.version;
main.dom.body.appendChild(script);
script.onload = function () {
main[name] = main.instance[name];
@@ -193,15 +197,17 @@ main.prototype.loadMod = function (modName, callback) {
}
}
+////// 加载某一个楼层 //////
main.prototype.loadFloor = function(floorId, callback) {
var script = document.createElement('script');
- script.src = 'libs/floors/' + floorId +'.js?' + this.version;
+ script.src = 'libs/floors/' + floorId +'.js?v=' + this.version;
main.dom.body.appendChild(script);
script.onload = function () {
callback(floorId);
}
}
+////// 加载过程提示 //////
main.prototype.setMainTipsText = function (text) {
main.dom.mainTips.innerHTML = text;
}
@@ -209,12 +215,14 @@ main.prototype.setMainTipsText = function (text) {
var main = new main();
main.init();
+////// 窗口大小变化时 //////
window.onresize = function () {
try {
main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight);
}catch (e) {}
}
+////// 在界面上按下某按键时 //////
main.dom.body.onkeydown = function(e) {
try {
if (main.core.isPlaying() || main.core.status.lockControl)
@@ -222,6 +230,7 @@ main.dom.body.onkeydown = function(e) {
} catch (ee) {}
}
+////// 在界面上放开某按键时 //////
main.dom.body.onkeyup = function(e) {
try {
if (main.core.isPlaying() || main.core.status.lockControl)
@@ -229,10 +238,12 @@ main.dom.body.onkeyup = function(e) {
} catch (ee) {}
}
+////// 开始选择时 //////
main.dom.body.onselectstart = function () {
return false;
}
+////// 鼠标按下时 //////
main.dom.data.onmousedown = function (e) {
try {
e.stopPropagation();
@@ -247,6 +258,7 @@ main.dom.data.onmousedown = function (e) {
} catch (ee) {}
}
+////// 鼠标移动时 //////
main.dom.data.onmousemove = function (e) {
try {
e.stopPropagation();
@@ -257,12 +269,14 @@ main.dom.data.onmousemove = function (e) {
}catch (ee) {}
}
+////// 鼠标放开时 //////
main.dom.data.onmouseup = function () {
try {
main.core.onup();
}catch (e) {}
}
+////// 鼠标滑轮滚动时 //////
main.dom.data.onmousewheel = function(e) {
try {
if (e.wheelDelta)
@@ -272,6 +286,7 @@ main.dom.data.onmousewheel = function(e) {
} catch (ee) {}
}
+////// 手指在触摸屏开始触摸时 //////
main.dom.data.ontouchstart = function (e) {
try {
e.preventDefault();
@@ -283,6 +298,7 @@ main.dom.data.ontouchstart = function (e) {
}catch (ee) {}
}
+////// 手指在触摸屏上移动时 //////
main.dom.data.ontouchmove = function (e) {
try {
e.preventDefault();
@@ -293,6 +309,7 @@ main.dom.data.ontouchmove = function (e) {
}catch (ee) {}
}
+////// 手指离开触摸屏时 //////
main.dom.data.ontouchend = function () {
try {
main.core.onup();
@@ -300,41 +317,49 @@ main.dom.data.ontouchend = function () {
}
}
+////// 点击状态栏中的怪物手册时 //////
main.statusBar.image.book.onclick = function () {
if (main.core.isPlaying())
main.core.openBook(true);
}
+////// 点击状态栏中的楼层传送器时 //////
main.statusBar.image.fly.onclick = function () {
if (main.core.isPlaying())
main.core.useFly(true);
}
+////// 点击状态栏中的工具箱时 //////
main.statusBar.image.toolbox.onclick = function () {
if (main.core.isPlaying())
main.core.openToolbox(true);
}
+////// 点击状态栏中的快捷商店时 //////
main.statusBar.image.shop.onclick = function () {
if (main.core.isPlaying())
main.core.ui.drawQuickShop(true);
}
+////// 点击状态栏中的存档按钮时 //////
main.statusBar.image.save.onclick = function () {
if (main.core.isPlaying())
main.core.save(true);
}
+////// 点击状态栏中的读档按钮时 //////
main.statusBar.image.load.onclick = function () {
if (main.core.isPlaying())
main.core.load(true);
}
+////// 点击状态栏中的系统菜单时 //////
main.statusBar.image.settings.onclick = function () {
if (main.core.isPlaying())
main.core.ui.drawSettings(true);
}
+////// 点击“开始游戏”时 //////
main.dom.playGame.onclick = function () {
main.dom.startButtons.style.display='none';
@@ -346,22 +371,27 @@ main.dom.playGame.onclick = function () {
}
}
+////// 点击“载入游戏”时 //////
main.dom.loadGame.onclick = function() {
main.core.load();
}
+////// 点击“关于本塔”时 //////
main.dom.aboutGame.onclick = function () {
main.core.ui.drawAbout();
}
+////// 点击“简单难度”时 //////
main.dom.easyLevel.onclick = function() {
core.events.startGame('Easy');
}
+////// 点击“普通难度”时 //////
main.dom.normalLevel.onclick = function () {
core.events.startGame('Normal');
}
+////// 点击“困难难度”时 //////
main.dom.hardLevel.onclick = function () {
core.events.startGame('Hard');
}