diff --git a/.idea/mota-js.iml b/.idea/mota-js.xml similarity index 100% rename from .idea/mota-js.iml rename to .idea/mota-js.xml 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..66428b22 100644 --- a/README.md +++ b/README.md @@ -45,6 +45,12 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2018.1.12 V1.3.1 + +* [x] 增加虚拟键盘 +* [x] 增加自动存档(回退),A键可快速读档 +* [x] 修复几处较为严重的Bug + ### 2018.1.1 V1.3 * [x] 支持全键盘操作。 diff --git a/docs/api.md b/docs/api.md index ebd28f99..092ad862 100644 --- a/docs/api.md +++ b/docs/api.md @@ -93,6 +93,7 @@ core.setAutoHeroMove // 设置勇士的自动行走路线 core.autoHeroMove // 让勇士开始自动行走 core.setHeroMoveInterval // 设置行走的效果动画 core.setHeroMoveTriggerInterval // 设置勇士行走过程中对事件的触发检测 +core.moveAction // 实际每一步的行走过程 * core.turnHero(direction) // 设置勇士的方向(转向) core.canMoveHero // 勇士能否前往某方向 core.moveHero // 让勇士开始移动 @@ -178,16 +179,21 @@ core.clone // 深拷贝一个对象 core.formatDate // 格式化时间为字符串 core.setTwoDigits // 两位数显示 core.debug // 进入Debug模式,攻防血和钥匙都调成很高的数值 +core.replay // 开始回放 core.checkStatus // 判断当前能否进入某个事件 core.openBook // 点击怪物手册时的打开操作 core.useFly // 点击楼层传送器时的打开操作 core.openToolbox // 点击工具栏时的打开操作 +core.openQuickShop // 点击快捷商店时的打开操作 core.save // 点击保存按钮时的打开操作 core.load // 点击读取按钮时的打开操作 +core.openSettings // 点击设置按钮时的打开操作 core.doSL // 实际进行存读档事件 core.syncSave // 存档同步操作 core.saveData // 存档到本地 core.loadData // 从本地读档 +core.encodeRoute // 将路线压缩 +core.decodeRoute // 将路线解压缩 * core.setStatus // 设置勇士属性 * core.getStatus // 获得勇士属性 core.getLvName // 获得某个等级的名称 @@ -260,6 +266,7 @@ core.events.changeLight // 改变亮灯(感叹号)的事件 * core.events.afterLoadData // 读档事件后,载入事件前,可以执行的操作 // ------ 点击事件和键盘事件的处理 ------ +core.events.longClick // 长按 core.events.keyDownCtrl // 按下Ctrl键时(快捷跳过对话) core.events.clickConfirmBox // 确认框界面时的点击操作 core.events.keyUpConfirmBox // 确认框界面时,放开某个键的操作 @@ -295,6 +302,7 @@ core.events.keyUpSettings // 系统菜单栏界面时,放开某个键的操作 core.events.clickSyncSave // 同步存档界面时的点击操作 core.events.keyDownSyncSave // 同步存档界面时,按下某个键的操作 core.events.keyUpSyncSave // 同步存档界面时,放开某个键的操作 +core.events.clickKeyBoard // 虚拟键盘界面时的点击操作 core.events.clickAbout // “关于”界面时的点击操作 ``` diff --git a/docs/element.md b/docs/element.md index ef764af5..21df84a9 100644 --- a/docs/element.md +++ b/docs/element.md @@ -142,10 +142,6 @@ floorId指定的是目标楼层的唯一标识符(ID)。 可以指定time,指定后切换动画时长为指定的数值。 -楼梯和传送门默认可`"穿透"`。所谓穿透,就是当寻路穿过一个楼梯/传送门后,不会触发楼层传送事件,而是继续前进。通过系统Flag可以指定是否穿透,你也可以对每个传送点单独设置该项。 - -![楼层转换穿透](./img/floorset.png) - ## 背景音乐 本塔支持BGM和SE的播放。 @@ -190,12 +186,14 @@ this.sounds = [ // 在此存放所有的SE,和文件名一致 - **点任意块并拖动:** 指定寻路路线 - **单击勇士:** 转向 - **双击勇士:** 轻按(仅在轻按开关打开时有效) +- **长按任意位置:** 打开虚拟键盘 键盘操作快捷键如下: - **[CTRL]** 跳过对话 - **[X]** 打开/关闭怪物手册 - **[G]** 打开/关闭楼层传送器 +- **[A]** 读取自动存档 - **[S/D]** 打开/关闭存/读档页面 - **[K]** 打开/关闭快捷商店选择列表 - **[T]** 打开/关闭工具栏 diff --git a/docs/event.md b/docs/event.md index 58d0917e..a694f731 100644 --- a/docs/event.md +++ b/docs/event.md @@ -465,6 +465,8 @@ direction为可选的,指定的话将使勇士的朝向变成该方向 time为可选的,指定的话将作为楼层切换动画的时间。 +**time也可以置为0,如果为0则没有楼层切换动画。** + !> **changeFloor到达一个新的楼层,将不会执行firstArrive事件!如有需求请在到达点设置自定义事件,然后使用type: trigger立刻调用之。** ### changePos: 当前位置切换/勇士转向 @@ -844,8 +846,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 +873,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 +889,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 是一个表达式,计算商店所需要用到的数值。 diff --git a/images/terrains.png b/images/terrains.png index 31ff78cf..15d492c3 100644 Binary files a/images/terrains.png and b/images/terrains.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png b/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png new file mode 100644 index 00000000..c1c1cb1a Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/animates0:经典.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png b/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png new file mode 100644 index 00000000..3a6cdbb5 Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/animates1:旋转门.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/items1:圆形宝石.png b/images/常用素材:如需使用请直接替换目录中的对应文件/items1:圆形宝石.png deleted file mode 100644 index 7150fe9f..00000000 Binary files a/images/常用素材:如需使用请直接替换目录中的对应文件/items1:圆形宝石.png and /dev/null differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/items1:方块宝石.png b/images/常用素材:如需使用请直接替换目录中的对应文件/items1:方块宝石.png new file mode 100644 index 00000000..189b98eb Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/items1:方块宝石.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/宝石1.png b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石1.png new file mode 100644 index 00000000..d930ea4e Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石1.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/宝石2.png b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石2.png new file mode 100644 index 00000000..4749c79d Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石2.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/宝石3.png b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石3.png new file mode 100644 index 00000000..6a1d977a Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石3.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/宝石4.png b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石4.png new file mode 100644 index 00000000..612e1efa Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/宝石4.png differ diff --git a/images/常用素材:如需使用请直接替换目录中的对应文件/旋转机关门.png b/images/常用素材:如需使用请直接替换目录中的对应文件/旋转机关门.png new file mode 100644 index 00000000..ce9bc323 Binary files /dev/null and b/images/常用素材:如需使用请直接替换目录中的对应文件/旋转机关门.png differ diff --git a/index.html b/index.html index ae063d97..60b85214 100644 --- a/index.html +++ b/index.html @@ -32,7 +32,7 @@
开始游戏 载入游戏 - 关于本塔 + 录像回放
简单 diff --git a/libs/core.js b/libs/core.js index 145c6b9b..c53ecf52 100644 --- a/libs/core.js +++ b/libs/core.js @@ -45,6 +45,21 @@ function core() { 'playingBgm': null, // 正在播放的BGM 'isPlaying': false, } + this.platform = { + 'isOnline': true, // 是否http + 'isPC': true, // 是否是PC + 'isAndroid': false, // 是否是Android + 'isIOS': false, // 是否是iOS + 'isWeChat': false, // 是否是微信 + 'isQQ': false, // 是否是QQ + 'isChrome': false, // 是否是Chrome + 'supportCopy': false, // 是否支持复制到剪切板 + + 'fileInput': null, // FileInput + 'fileReader': null, // 是否支持FileReader + 'successCallback': null, // 读取成功 + 'errorCallback': null, // 读取失败 + } // 样式 this.domStyle = { styles: [], @@ -78,8 +93,17 @@ function core() { 'stepPostfix': [], 'mouseOutCheck': 1, 'moveStepBeforeStop': [], + 'downTime': null, - // 勇士状态;中心对称飞行器 + // 路线&回放 + 'route': [], + 'replay': { + 'replaying': false, + 'pausing': false, + 'animate': false, // 正在某段动画中 + 'toReplay': [], + 'totalList': [] + }, // event事件 'saveIndex': null, @@ -129,7 +153,12 @@ core.prototype.init = function (dom, statusBar, canvas, images, pngs, bgms, soun } core.values = core.clone(core.data.values); core.firstData = core.data.getFirstData(); - core.initStatus.shops = core.firstData.shops; + + // core.initStatus.shops = core.firstData.shops; + core.firstData.shops.forEach(function (t) { + core.initStatus.shops[t.id] = t; + }) + core.dom.versionLabel.innerHTML = core.firstData.version; core.dom.logoLabel.innerHTML = core.firstData.title; document.title = core.firstData.title + " - HTML5魔塔"; @@ -140,7 +169,8 @@ core.prototype.init = function (dom, statusBar, canvas, images, pngs, bgms, soun core.material.icons = core.icons.getIcons(); core.material.events = core.events.getEvents(); - if (location.protocol.indexOf("http")==0) { + core.platform.isOnline = location.protocol.indexOf("http")==0; + if (core.platform.isOnline) { window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; try { core.musicStatus.audioContext = new window.AudioContext(); @@ -150,12 +180,55 @@ core.prototype.init = function (dom, statusBar, canvas, images, pngs, bgms, soun } } - // 音效设置部分 - var isPC = true; ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"].forEach(function (t) { - if (navigator.userAgent.indexOf(t)>=0) isPC=false; + if (navigator.userAgent.indexOf(t)>=0) { + if (t=='iPhone' || t=='iPad' || t=='iPod') core.platform.isIOS = true; + if (t=='Android') core.platform.isAndroid=true; + core.platform.isPC=false; + } }); - if (isPC) { + + try { + core.platform.supportCopy = document.queryCommandSupported("copy"); + } + catch (e) { + core.platform.supportCopy = false; + } + + var chrome=/Chrome\/(\d+)\./.exec(navigator.userAgent); + if (core.isset(chrome) && parseInt(chrome[1])>=50) + core.platform.isChrome = true; + core.platform.isSafari = /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent); + core.platform.isQQ = /QQ/.test(navigator.userAgent); + core.platform.isWeChat = /MicroMessenger/.test(navigator.userAgent); + + if (window.FileReader) { + core.platform.fileReader = new FileReader(); + core.platform.fileReader.onload = function () { + var content=core.platform.fileReader.result; + var obj=null; + try { + obj=JSON.parse(content); + if (core.isset(obj)) { + if (core.isset(core.platform.successCallback)) + core.platform.successCallback(obj); + return; + } + } + catch (e) {} + alert("不是有效的JSON文件!"); + + if (core.isset(core.platform.errorCallback)) + core.platform.errorCallback(); + + }; + core.platform.fileReader.onerror = function () { + if (core.isset(core.platform.errorCallback)) + core.platform.errorCallback(); + } + } + + if (core.platform.isPC) { // 如果是PC端直接加载 core.musicStatus.startDirectly = true; } @@ -174,7 +247,6 @@ core.prototype.init = function (dom, statusBar, canvas, images, pngs, bgms, soun core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); core.setLocalStorage('soundStatus', core.musicStatus.soundStatus); - // switchs core.flags.battleAnimate = core.getLocalStorage('battleAnimate', core.flags.battleAnimate); core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); @@ -442,7 +514,7 @@ core.prototype.clearStatus = function() { } ////// 重置游戏状态和初始数据 ////// -core.prototype.resetStatus = function(hero, hard, floorId, maps) { +core.prototype.resetStatus = function(hero, hard, floorId, route, maps) { // 停止各个Timeout和Interval for (var i in core.interval) { @@ -460,8 +532,11 @@ core.prototype.resetStatus = function(hero, hard, floorId, maps) { // 初始化人物属性 core.status.hero = core.clone(hero); core.status.hard = hard; + // 初始化路线 + if (core.isset(route)) + core.status.route = route; // 保存的Index - core.status.saveIndex = core.getLocalStorage('saveIndex', 1); + core.status.saveIndex = core.getLocalStorage('saveIndex2', 1); core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); } @@ -470,12 +545,30 @@ core.prototype.resetStatus = function(hero, hard, floorId, maps) { core.prototype.startGame = function (hard, callback) { console.log('开始游戏'); - 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.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function() { core.setHeroMoveTriggerInterval(); if (core.isset(callback)) callback(); }); + + + setTimeout(function () { + // Upload + var formData = new FormData(); + formData.append('type', 'people'); + formData.append('name', core.firstData.name); + formData.append('version', core.firstData.version); + formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('hard', hard); + formData.append('hardCode', core.getFlag('hard', 0)); + + var xhr = new XMLHttpRequest(); + xhr.open("POST", "/games/upload.php"); + xhr.send(formData); + + }) + } ////// 重新开始游戏;此函数将回到标题页面 ////// @@ -492,6 +585,7 @@ core.prototype.restart = function() { ////// 按下某个键时 ////// core.prototype.onkeyDown = function(e) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; if (!core.isset(core.status.holdingKeys))core.status.holdingKeys=[]; var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] if(isArrow && !core.status.lockControl){ @@ -509,6 +603,7 @@ core.prototype.onkeyDown = function(e) { ////// 放开某个键时 ////// core.prototype.onkeyUp = function(e) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] if(isArrow && !core.status.lockControl){ for(var ii =0;ii0){ var stepPostfix = []; @@ -842,8 +972,16 @@ core.prototype.onup = function () { core.status.stepPostfix=[]; core.canvas.ui.clearRect(0, 0, 416,416); core.canvas.ui.restore(); - core.onclick(posx,posy,stepPostfix); - //posx,posy是寻路的目标点,stepPostfix是后续的移动 + + // 长按 + if (!core.status.lockControl && stepPostfix.length==0 && core.status.downTime!=null && new Date()-core.status.downTime>=1000) { + core.events.longClick(); + } + else { + //posx,posy是寻路的目标点,stepPostfix是后续的移动 + core.onclick(posx,posy,stepPostfix); + } + core.status.downTime=null; } } @@ -874,6 +1012,7 @@ core.prototype.getClickLoc = function (x, y) { ////// 具体点击屏幕上(x,y)点时,执行的操作 ////// core.prototype.onclick = function (x, y, stepPostfix) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; // console.log("Click: (" + x + "," + y + ")"); // 非游戏屏幕内 @@ -921,6 +1060,12 @@ core.prototype.onclick = function (x, y, stepPostfix) { return; } + // 查看地图 + if (core.status.event.id == 'viewMaps') { + core.events.clickViewMaps(x,y); + return; + } + // 开关 if (core.status.event.id == 'switchs') { core.events.clickSwitchs(x,y); @@ -963,6 +1108,11 @@ core.prototype.onclick = function (x, y, stepPostfix) { return; } + if (core.status.event.id == 'keyBoard') { + core.events.clickKeyBoard(x,y); + return; + } + // 关于 if (core.status.event.id == 'about') { core.events.clickAbout(x,y); @@ -990,6 +1140,7 @@ core.prototype.onclick = function (x, y, stepPostfix) { ////// 滑动鼠标滚轮时的操作 ////// core.prototype.onmousewheel = function (direct) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; // 向下滚动是 -1 ,向上是 1 // 楼层飞行器 @@ -1001,15 +1152,15 @@ core.prototype.onmousewheel = function (direct) { // 怪物手册 if (core.status.lockControl && core.status.event.id == 'book') { - if (direct==1) core.ui.drawBook(core.status.event.data - 1); - if (direct==-1) core.ui.drawBook(core.status.event.data + 1); + if (direct==1) core.ui.drawBook(core.status.event.data - 6); + if (direct==-1) core.ui.drawBook(core.status.event.data + 6); return; } // 存读档 if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) { - if (direct==1) core.ui.drawSLPanel(core.status.event.data - 6); - if (direct==-1) core.ui.drawSLPanel(core.status.event.data + 6); + if (direct==1) core.ui.drawSLPanel(core.status.event.data - 10); + if (direct==-1) core.ui.drawSLPanel(core.status.event.data + 10); return; } } @@ -1313,7 +1464,7 @@ core.prototype.stopAutoHeroMove = function () { } ////// 设置勇士的自动行走路线 ////// -core.prototype.setAutoHeroMove = function (steps, start) { +core.prototype.setAutoHeroMove = function (steps) { if (steps.length == 0) { return; } @@ -1366,6 +1517,8 @@ core.prototype.setHeroMoveInterval = function (direction, x, y, callback) { core.moveOneStep(); if (core.status.heroStop) core.drawHero(direction, core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + clearInterval(core.interval.heroMoveInterval); + core.status.heroMoving = false; if (core.isset(callback)) callback(); } }, 12.5); @@ -1373,73 +1526,80 @@ core.prototype.setHeroMoveInterval = function (direction, x, y, callback) { ////// 设置勇士行走过程中对事件的触发检测 ////// core.prototype.setHeroMoveTriggerInterval = function () { - var direction, x, y; + core.interval.heroMoveTriggerInterval = window.setInterval(function () { + if (!core.status.heroStop) { + core.moveAction(); + } + }, 50); +} + +////// 实际每一步的行走过程 ////// +core.prototype.moveAction = function (callback) { + if (core.interval.openDoorAnimate!=null) return; // 开门判断 var scan = { 'up': {'x': 0, 'y': -1}, 'left': {'x': -1, 'y': 0}, 'down': {'x': 0, 'y': 1}, 'right': {'x': 1, 'y': 0} }; - core.interval.heroMoveTriggerInterval = window.setInterval(function () { - if (!core.status.heroStop) { - direction = core.getHeroLoc('direction'); - x = core.getHeroLoc('x'); - y = core.getHeroLoc('y'); - var noPass = core.noPass(x + scan[direction].x, y + scan[direction].y), canMove = core.canMoveHero(); - if (noPass || !canMove) { - if (canMove) // 非箭头:触发 - core.trigger(x + scan[direction].x, y + scan[direction].y); - core.drawHero(direction, x, y, 'stop'); - if (core.status.autoHeroMove) { - core.status.movedStep++; - if (core.status.destStep == core.status.movedStep) { - core.status.autoHeroMove = false; - core.status.destStep = 0; - core.status.movedStep = 0; - core.status.moveStepBeforeStop=[]; - core.stopAutomaticRoute(); - } - } - else { - core.status.heroStop = true; - } - return; + var direction = core.getHeroLoc('direction'); + var x = core.getHeroLoc('x'); + var y = core.getHeroLoc('y'); + var noPass = core.noPass(x + scan[direction].x, y + scan[direction].y), canMove = core.canMoveHero(); + if (noPass || !canMove) { + core.status.route.push(direction); + if (canMove) // 非箭头:触发 + core.trigger(x + scan[direction].x, y + scan[direction].y); + core.drawHero(direction, x, y, 'stop'); + if (core.status.autoHeroMove) { + core.status.movedStep++; + if (core.status.destStep == core.status.movedStep) { + core.status.autoHeroMove = false; + core.status.destStep = 0; + core.status.movedStep = 0; + core.status.moveStepBeforeStop=[]; + core.stopAutomaticRoute(); } - core.setHeroMoveInterval(direction, x, y, function () { - if (core.status.autoHeroMove) { - core.status.movedStep++; - if (core.status.destStep == core.status.movedStep) { - core.status.autoHeroMove = false; - core.status.destStep = 0; - core.status.movedStep = 0; - core.stopHero(); - core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); - } - } - else if (core.status.heroStop) { + } + else { + core.status.heroStop = true; + } + if (core.isset(callback)) + callback(); + } + else { + core.setHeroMoveInterval(direction, x, y, function () { + if (core.status.autoHeroMove) { + core.status.movedStep++; + if (core.status.destStep == core.status.movedStep) { + core.status.autoHeroMove = false; + core.status.destStep = 0; + core.status.movedStep = 0; + core.stopHero(); core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); } - core.trigger(core.getHeroLoc('x'), core.getHeroLoc('y')); - clearInterval(core.interval.heroMoveInterval); - core.status.heroMoving = false; - core.checkBlock(); - }); - } - }, 50); + } + else if (core.status.heroStop) { + core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); + } + core.status.route.push(direction); + core.trigger(core.getHeroLoc('x'), core.getHeroLoc('y')); + core.checkBlock(); + if (core.isset(callback)) callback(); + }); + } } -////// 设置勇士的方向(转向) ////// -core.prototype.turnHero = function(direction) { - if (core.isset(direction)) { - core.status.hero.loc.direction = direction; - } - else if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; +////// 转向 ////// +core.prototype.turnHero = function() { + if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; core.drawHero(core.status.hero.loc.direction, core.status.hero.loc.x, core.status.hero.loc.y, 'stop', 0, 0); core.status.automaticRoutingTemp = {'destX': 0, 'destY': 0, 'moveStep': []}; core.canvas.ui.clearRect(0, 0, 416, 416); + core.status.route.push("turn"); } ////// 勇士能否前往某方向 ////// @@ -1452,8 +1612,6 @@ core.prototype.canMoveHero = function() { if(nowIsArrow){ var nowArrow = nowId.slice(5).toLowerCase(); if (direction != nowArrow) { - // core.status.heroStop = true; - // core.turnHero(direction); return false; } } @@ -1472,8 +1630,6 @@ core.prototype.canMoveHero = function() { if(isArrow){ var nextArrow = nextId.slice(5).toLowerCase(); if ( (scan[direction].x + scan[nextArrow].x) == 0 && (scan[direction].y + scan[nextArrow].y) == 0 ) { - // core.status.heroStop = true; - // core.turnHero(direction); return false; } } @@ -1482,9 +1638,17 @@ core.prototype.canMoveHero = function() { } ////// 让勇士开始移动 ////// -core.prototype.moveHero = function (direction) { - core.setHeroLoc('direction', direction); - core.status.heroStop = false; +core.prototype.moveHero = function (direction, callback) { + if (core.isset(direction)) + core.setHeroLoc('direction', direction); + if (!core.isset(callback)) { // 如果不存在回调函数,则使用heroMoveTrigger + core.status.heroStop = false; + } + else { // 否则,只向某个方向移动一步,然后调用callback + core.moveAction(function () { + callback(); + }) + } } /////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// @@ -1521,11 +1685,14 @@ core.prototype.eventMoveHero = function(steps, time, callback) { 'right': {'x': 1, 'y': 0} }; + core.status.replay.animate=true; + var animate=window.setInterval(function() { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); if (moveSteps.length==0) { clearInterval(animate); core.drawHero(core.getHeroLoc('direction'), x, y, 'stop'); + core.status.replay.animate=false; if (core.isset(callback)) callback(); } else { @@ -1550,6 +1717,7 @@ core.prototype.eventMoveHero = function(steps, time, callback) { ////// 每移动一格后执行的事件 ////// core.prototype.moveOneStep = function() { + core.status.hero.steps++; // 中毒状态 if (core.hasFlag('poison')) { core.status.hero.hp -= core.values.poisonDamage; @@ -1568,8 +1736,10 @@ core.prototype.waitHeroToStop = function(callback) { core.stopAutomaticRoute(); core.clearContinueAutomaticRoute(); if (core.isset(callback)) { + core.status.replay.animate=true; core.lockControl(); setTimeout(function(){ + core.status.replay.animate=false; core.drawHero(core.getHeroLoc('direction'), core.getHeroLoc('x'), core.getHeroLoc('y'), 'stop'); callback(); }, 30); @@ -1665,7 +1835,6 @@ core.prototype.openDoor = function (id, x, y, needKey, callback) { core.drawTip("你没有" + core.material.items[key].name); else core.drawTip("无法开启此门"); core.clearContinueAutomaticRoute(); - if (core.isset(callback)) callback(); return; } } @@ -1678,12 +1847,14 @@ core.prototype.openDoor = function (id, x, y, needKey, callback) { speed=100; } var door = core.material.icons.animates[doorId]; + core.status.replay.animate=true; core.interval.openDoorAnimate = window.setInterval(function () { state++; if (state == 4) { clearInterval(core.interval.openDoorAnimate); core.interval.openDoorAnimate=null; core.removeBlock(x, y); + core.status.replay.animate=false; core.events.afterOpenDoor(id,x,y,callback); return; } @@ -1708,7 +1879,7 @@ core.prototype.battle = function (id, x, y, force, callback) { core.clearContinueAutomaticRoute(); return; } - if (core.flags.battleAnimate) { + if (core.flags.battleAnimate&&!core.status.replay.replaying) { core.waitHeroToStop(function() { core.ui.drawBattleAnimate(id, function() { core.afterBattle(id, x, y, callback); @@ -1767,12 +1938,14 @@ core.prototype.trigger = function (x, y) { if (core.isset(mapBlocks[b].event) && core.isset(mapBlocks[b].event.trigger)) { var trigger = mapBlocks[b].event.trigger; // 转换楼层能否穿透 + /* if (trigger=='changeFloor' && (core.status.autoHeroMove || core.status.autoStep1) - core.status.checkBlock.damage[13*x+y] += parseInt((leftHp+1)/2); + core.status.checkBlock.damage[13*x+y] += parseInt((leftHp+(core.flags.betweenAttackCeil?0:1))/2); } } } @@ -2665,107 +2865,119 @@ core.prototype.checkBlock = function () { ////// 阻击事件(动画效果) ////// core.prototype.snipe = function (snipes) { - core.waitHeroToStop(function() { - core.lockControl(); - var scan = { - 'up': {'x': 0, 'y': -1}, - 'left': {'x': -1, 'y': 0}, - 'down': {'x': 0, 'y': 1}, - 'right': {'x': 1, 'y': 0} - }; + var scan = { + 'up': {'x': 0, 'y': -1}, + 'left': {'x': -1, 'y': 0}, + 'down': {'x': 0, 'y': 1}, + 'right': {'x': 1, 'y': 0} + }; - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; - snipe.nx = x+scan[snipe.direction].x; - snipe.ny = y+scan[snipe.direction].y; + snipes.forEach(function (snipe) { + var x=snipe.x, y=snipe.y, direction = snipe.direction; + snipe.nx = x+scan[snipe.direction].x; + snipe.ny = y+scan[snipe.direction].y; - core.removeGlobalAnimate(x, y); + core.removeGlobalAnimate(x, y); - var block = core.getBlock(x,y).block; + var block = core.getBlock(x,y).block; - snipe.blockIcon = core.material.icons[block.event.cls][block.event.id]; - snipe.blockImage = core.material.images[block.event.cls]; - var damage = core.enemys.getDamage(block.event.id); + snipe.blockIcon = core.material.icons[block.event.cls][block.event.id]; + snipe.blockImage = core.material.images[block.event.cls]; + var damage = core.enemys.getDamage(block.event.id); - var color = "#000000"; - if (damage <= 0) color = '#00FF00'; - else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; - else if (damage < core.status.hero.hp) color = '#FF7F00'; - else color = '#FF0000'; + var color = "#000000"; + if (damage <= 0) color = '#00FF00'; + else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; + else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; + else if (damage < core.status.hero.hp) color = '#FF7F00'; + else color = '#FF0000'; - if (damage >= 999999999) damage = "???"; - else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; + if (damage >= 999999999) damage = "???"; + else if (damage > 100000) damage = (damage / 10000).toFixed(1) + "w"; - snipe.damage = damage; - snipe.color = color; - snipe.block = core.clone(block); - }) + snipe.damage = damage; + snipe.color = color; + snipe.block = core.clone(block); + }) - var time = 500, step = 0; + var finishSnipe = function () { + snipes.forEach(function (t) { + core.removeBlock(t.x, t.y); + var nBlock = core.clone(t.block); + nBlock.x = t.nx; nBlock.y = t.ny; + core.status.thisMap.blocks.push(nBlock); + core.addGlobalAnimate(2, 32*t.nx, 32*t.ny, t.blockIcon, t.blockImage); + core.canvas.event.drawImage(t.blockImage, 0, t.blockIcon*32, 32, 32, 32*t.nx, 32*t.ny, 32, 32); + }); + core.syncGlobalAnimate(); + core.updateStatusBar(); + return; + } - var animateValue = 2; - var animateCurrent = 0; - var animateTime = 0; + if (core.status.replay.replaying) { + finishSnipe(); + } + else { + core.waitHeroToStop(function() { - core.canvas.fg.textAlign = 'left'; + core.lockControl(); - var animate=window.setInterval(function() { + var time = 500, step = 0; - step++; - animateTime += time / 16; - if (animateTime >= core.values.animateSpeed * 2 / animateValue) { - animateCurrent++; - animateTime = 0; - if (animateCurrent>=animateValue) animateCurrent=0; - } + var animateValue = 2; + var animateCurrent = 0; + var animateTime = 0; - snipes.forEach(function (snipe) { - var x=snipe.x, y=snipe.y, direction = snipe.direction; + core.canvas.fg.textAlign = 'left'; - var nowX=32*x+scan[direction].x*2*step, nowY=32*y+scan[direction].y*2*step; + var animate=window.setInterval(function() { - // 清空上一次 - core.clearMap('event', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - core.clearMap('fg', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); - - core.canvas.event.drawImage(snipe.blockImage, animateCurrent*32, snipe.blockIcon*32, 32, 32, nowX, nowY, 32, 32); - - if (core.hasItem('book')) { - // drawFG - core.setFillStyle('fg', '#000000'); - core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 30); - core.canvas.fg.fillText(snipe.damage, nowX, nowY + 30); - core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 32); - core.canvas.fg.fillText(snipe.damage, nowX, nowY + 32); - - core.setFillStyle('fg', snipe.color); - core.canvas.fg.fillText(snipe.damage, nowX + 1, nowY + 31); + step++; + animateTime += time / 16; + if (animateTime >= core.values.animateSpeed * 2 / animateValue) { + animateCurrent++; + animateTime = 0; + if (animateCurrent>=animateValue) animateCurrent=0; } - }) + snipes.forEach(function (snipe) { + var x=snipe.x, y=snipe.y, direction = snipe.direction; - if (step==16) { // 移动完毕 - clearInterval(animate); - snipes.forEach(function (t) { - core.removeBlock(t.x, t.y); - var nBlock = core.clone(t.block); - nBlock.x = t.nx; nBlock.y = t.ny; - core.status.thisMap.blocks.push(nBlock); - core.addGlobalAnimate(animateValue, 32*t.nx, 32*t.ny, t.blockIcon, t.blockImage); - }); - core.syncGlobalAnimate(); - core.updateStatusBar(); - // 不存在自定义事件 - if (core.status.event.id==null) - core.unLockControl(); - } - }, time/16); + var nowX=32*x+scan[direction].x*2*step, nowY=32*y+scan[direction].y*2*step; + + // 清空上一次 + core.clearMap('event', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); + core.clearMap('fg', nowX-2*scan[direction].x, nowY-2*scan[direction].y, 32, 32); + + core.canvas.event.drawImage(snipe.blockImage, animateCurrent*32, snipe.blockIcon*32, 32, 32, nowX, nowY, 32, 32); + + if (core.hasItem('book')) { + // drawFG + core.setFillStyle('fg', '#000000'); + core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 30); + core.canvas.fg.fillText(snipe.damage, nowX, nowY + 30); + core.canvas.fg.fillText(snipe.damage, nowX + 2, nowY + 32); + core.canvas.fg.fillText(snipe.damage, nowX, nowY + 32); + + core.setFillStyle('fg', snipe.color); + core.canvas.fg.fillText(snipe.damage, nowX + 1, nowY + 31); + } + + }) + + if (step==16) { // 移动完毕 + clearInterval(animate); + finishSnipe(); + // 不存在自定义事件 + if (core.status.event.id==null) + core.unLockControl(); + } + }, time/16); + }); + } - - }); } ////// 更改画面色调 ////// @@ -2799,6 +3011,7 @@ core.prototype.setFg = function(color, time, callback) { } var step=0; + core.status.replay.animate=true; var changeAnimate = setInterval(function() { step++; @@ -2817,6 +3030,7 @@ core.prototype.setFg = function(color, time, callback) { if (step>=25) { clearInterval(changeAnimate); core.status.curtainColor = color; + core.status.replay.animate=false; if (core.isset(callback)) callback(); } }, time/25); @@ -2936,8 +3150,8 @@ core.prototype.removeItem = function (itemId) { } ////// 使用某个物品 ////// -core.prototype.useItem = function (itemId) { - core.items.useItem(itemId); +core.prototype.useItem = function (itemId, callback) { + core.items.useItem(itemId, callback); return; } @@ -2969,6 +3183,7 @@ core.prototype.getNextItem = function() { if (block==null) return; if (block.block.event.trigger=='getItem') { core.getItem(block.block.event.id, 1, nextX, nextY); + core.status.route.push("getNext"); } } @@ -3053,6 +3268,13 @@ core.prototype.drawTip = function (text, itemIcon) { ////// 地图中间绘制一段文字 ////// core.prototype.drawText = function (contents, callback) { if (core.isset(contents)) { + + // 合并 + if (core.isset(core.status.event)&&core.status.event.id=='action') { + core.insertAction(contents,null,null,callback); + return; + } + if (typeof contents == 'string') { contents = [{'content': contents}]; } @@ -3232,6 +3454,13 @@ core.prototype.formatDate = function(date) { +core.setTwoDigits(date.getHours())+":"+core.setTwoDigits(date.getMinutes())+":"+core.setTwoDigits(date.getSeconds()); } +////// 格式化时间为最简字符串 ////// +core.prototype.formatDate2 = function (date) { + if (!core.isset(date)) return ""; + return date.getFullYear()+core.setTwoDigits(date.getMonth()+1)+core.setTwoDigits(date.getDate()) + +core.setTwoDigits(date.getHours())+core.setTwoDigits(date.getMinutes())+core.setTwoDigits(date.getSeconds()); +} + ////// 两位数显示 ////// core.prototype.setTwoDigits = function (x) { return parseInt(x)<10?"0"+x:x; @@ -3257,6 +3486,121 @@ core.prototype.debug = function() { core.drawTip("作弊成功"); } +////// 回放 ////// +core.prototype.replay = function (list) { + + if (core.isset(list) && (list instanceof Array)) { + core.status.replay.replaying=true; + core.status.replay.toReplay = core.clone(list); + this.replay(); + return; + } + + if (!core.status.replay.replaying) return; // 没有回放 + if (core.status.replay.pausing) return; // 暂停状态 + if (core.status.replay.animate) return; // 正在某段动画中 + + if (core.status.replay.toReplay.length==0) { // 回放完毕 + core.status.replay.replaying=false; + core.insertAction("录像回放完毕!"); + return; + } + + var action=core.status.replay.toReplay.shift(); + + if (action=='up' || action=='down' || action=='left' || action=='right') { + core.moveHero(action, function () { + core.replay(); + }); + return; + } + else if (action.indexOf("item:")==0) { + var itemId = action.substring(5); + if (core.canUseItem(itemId)) { + var tools = Object.keys(core.status.hero.items.tools).sort(); + var constants = Object.keys(core.status.hero.items.constants).sort(); + var index; + if ((index=tools.indexOf(itemId))>=0 || (index=constants.indexOf(itemId)+100)>=100) { + core.ui.drawToolbox(index); + setTimeout(function () { + core.ui.closePanel(); + core.useItem(itemId, function () { + core.replay(); + }); + }, 500); + } + return; + } + } + else if (action.indexOf("fly:")==0) { + var floorId=action.substring(4); + var toIndex=core.status.hero.flyRange.indexOf(floorId); + var nowIndex=core.status.hero.flyRange.indexOf(core.status.floorId); + if (core.hasItem('fly') && toIndex>=0 && nowIndex>=0) { + core.ui.drawFly(toIndex); + setTimeout(function () { + core.ui.closePanel(); + var stair=toIndex0) { + var shop=core.status.shops[shopId]; + if (core.isset(shop) && shop.visited) { // 商店可用 + var choices = shop.choices; + var topIndex = 6 - parseInt(choices.length / 2); + core.events.openShop(shopId, false); + var shopInterval = setInterval(function () { + if (selections.length==0) { + clearInterval(shopInterval); + core.events.clickShop(6, topIndex+choices.length); + core.replay(); + return; + } + var selection = parseInt(selections.shift()); + if (isNaN(selection) || selection<0 || selection>=choices.length || !core.events.clickShop(6, topIndex+selection)) { + clearInterval(shopInterval); + core.status.replay.replaying=false; + core.drawTip("录像文件出错"); + return; + } + }, 500); + return; + } + } + } + else if (action=='turn') { + core.turnHero(); + core.replay(); + return; + } + else if (action=='getNext') { + if (core.flags.enableGentleClick && core.getBlock(core.nextX(), core.nextY())!=null) { + var nextX = core.nextX(), nextY = core.nextY(); + var block = core.getBlock(nextX, nextY); + if (block!=null && block.block.event.trigger=='getItem') { + core.getItem(block.block.event.id, 1, nextX, nextY); + core.status.route.push("getNext"); + core.replay(); + return; + } + } + } + + core.status.replay.replaying=false; + core.insertAction("录像文件出错"); + +} + ////// 判断当前能否进入某个事件 ////// core.prototype.checkStatus = function (name, need, item) { if (need && core.status.event.id == name) { @@ -3282,6 +3626,7 @@ core.prototype.checkStatus = function (name, need, item) { ////// 点击怪物手册时的打开操作 ////// core.prototype.openBook = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; if (!core.checkStatus('book', need, true)) return; core.useItem('book'); @@ -3289,6 +3634,7 @@ core.prototype.openBook = function (need) { ////// 点击楼层传送器时的打开操作 ////// core.prototype.useFly = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; if (!core.checkStatus('fly', need, true)) return; if (core.flags.flyNearStair && !core.nearStair()) { @@ -3311,43 +3657,80 @@ core.prototype.useFly = function (need) { ////// 点击工具栏时的打开操作 ////// core.prototype.openToolbox = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; if (!core.checkStatus('toolbox', need)) return; core.ui.drawToolbox(); } +////// 点击快捷商店按钮时的打开操作 ////// +core.prototype.openQuickShop = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('selectShop', need)) + return; + core.ui.drawQuickShop(); +} + ////// 点击保存按钮时的打开操作 ////// core.prototype.save = function(need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; if (!core.checkStatus('save', need)) return; - core.ui.drawSLPanel(core.status.saveIndex); + + var saveIndex = core.status.saveIndex; + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; + + core.ui.drawSLPanel(10*page+offset); } ////// 点击读取按钮时的打开操作 ////// core.prototype.load = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + + var saveIndex = core.getLocalStorage('saveIndex2', 1); + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; // 游戏开始前读档 if (!core.isPlaying()) { core.status.event = {'id': 'load', 'data': null}; core.status.lockControl = true; core.dom.startPanel.style.display = 'none'; - core.ui.drawSLPanel(core.getLocalStorage('saveIndex', 1)); + core.ui.drawSLPanel(10*page+offset); return; } if (!core.checkStatus('load', need)) return; - core.ui.drawSLPanel(core.status.saveIndex); + core.ui.drawSLPanel(10*page+offset); +} + +////// 点击设置按钮时的操作 ////// +core.prototype.openSettings = function (need) { + if (core.isset(core.status.replay)&&core.status.replay.replaying) return; + if (!core.checkStatus('settings', need)) + return; + core.ui.drawSettings(); +} + +////// 自动存档 ////// +core.prototype.autosave = function () { + core.saveData("autoSave"); } ////// 实际进行存读档事件 ////// core.prototype.doSL = function (id, type) { - core.status.saveIndex=id; if (type=='save') { + if (id=='autoSave') { + core.drawTip('不能覆盖自动存档!'); + return; + } if (core.saveData("save"+id)) { core.ui.closePanel(); core.drawTip('存档成功!'); - core.setLocalStorage('saveIndex', core.status.saveIndex); + if (id!="autoSave") { + core.status.saveIndex=id; + core.setLocalStorage('saveIndex2', core.status.saveIndex); + } } else { core.drawTip('存储空间不足,请覆盖已有的存档或在菜单栏中进行清理'); @@ -3355,7 +3738,7 @@ core.prototype.doSL = function (id, type) { return; } else if (type=='load') { - var data = core.getLocalStorage("save"+id, null); + var data = core.getLocalStorage(id=='autoSave'?id:"save"+id, null); if (!core.isset(data)) { core.drawTip("无效的存档"); return; @@ -3366,9 +3749,11 @@ core.prototype.doSL = function (id, type) { } core.ui.closePanel(); core.loadData(data, function() { - core.status.saveIndex=id; - core.setLocalStorage('saveIndex', core.status.saveIndex); core.drawTip("读档成功"); + if (id!="autoSave") { + core.status.saveIndex=id; + core.setLocalStorage('saveIndex2', core.status.saveIndex); + } }); return; } @@ -3386,7 +3771,7 @@ core.prototype.syncSave = function(type) { formData.append('type', 'save'); formData.append('name', core.firstData.name); var saves = []; - for (var i=1;i<=180;i++) { + for (var i=1;i<=150;i++) { var data = core.getLocalStorage("save"+i, null); if (core.isset(data)) { saves.push(data); @@ -3413,13 +3798,11 @@ core.prototype.syncSave = function(type) { core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:HTTP "+xhr.status); } }; - xhr.ontimeout = function(e) { - console.log(e); - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); + xhr.ontimeout = function() { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:Timeout"); } - xhr.onerror = function(e) { - console.log(e); - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); + xhr.onerror = function() { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:XHR Error"); } xhr.send(formData); }, function() { @@ -3458,7 +3841,7 @@ core.prototype.syncSave = function(type) { // 成功 var data=JSON.parse(response.msg); // console.log(data); - for (var i=1;i<=180;i++) { + for (var i=1;i<=150;i++) { if (i<=data.length) { core.setLocalStorage("save"+i, data[i-1]); } @@ -3483,11 +3866,11 @@ core.prototype.syncSave = function(type) { core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:HTTP "+xhr.status); } }; - xhr.ontimeout = function(e) { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e); + xhr.ontimeout = function() { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:Timeout"); } - xhr.onerror = function(e) { - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e); + xhr.onerror = function() { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:XHR Error"); } xhr.send(formData); }, function() { @@ -3505,6 +3888,7 @@ core.prototype.saveData = function(dataId) { 'hero': core.clone(core.status.hero), 'hard': core.status.hard, 'maps': core.maps.save(core.status.maps), + 'route': core.encodeRoute(core.status.route), 'shops': {}, 'version': core.firstData.version, "time": new Date().getTime() @@ -3524,7 +3908,7 @@ core.prototype.saveData = function(dataId) { ////// 从本地读档 ////// core.prototype.loadData = function (data, callback) { - core.resetStatus(data.hero, data.hard, data.floorId, core.maps.load(data.maps)); + core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.load(data.maps)); // load shop times for (var shop in core.status.shops) { @@ -3534,12 +3918,96 @@ core.prototype.loadData = function (data, callback) { core.events.afterLoadData(data); - core.changeFloor(data.floorId, null, data.hero.loc, null, function() { + core.changeFloor(data.floorId, null, data.hero.loc, 0, function() { core.setHeroMoveTriggerInterval(); if (core.isset(callback)) callback(); }); } +////// 加密路线 ////// +core.prototype.encodeRoute = function (route) { + var ans=""; + var lastMove = "", cnt=0; + + var items=Object.keys(core.material.items).sort(); + var shops=Object.keys(core.initStatus.shops).sort(); + route.forEach(function (t) { + if (t=='up' || t=='down' || t=='left' || t=='right') { + if (t!=lastMove && cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + cnt=0; + } + lastMove=t; + cnt++; + } + else { + if (cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + cnt=0; + } + if (t.indexOf('item:')==0) + ans+="I"+items.indexOf(t.substring(5)); + else if (t.indexOf('fly:')==0) + ans+="F"+core.floorIds.indexOf(t.substring(4)); + else if (t.indexOf('choices:')==0) + ans+="C"+t.substring(8); + else if (t.indexOf('shop:')==0) { + var sp=t.substring(5).split(":"); + ans+="S"+shops.indexOf(sp[0])+":"+sp[1]; + } + else if (t=='turn') + ans+='T'; + else if (t=='getNext') + ans+='G'; + } + }); + if (cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + } + return ans; +} + +////// 解密路线 ////// +core.prototype.decodeRoute = function (route) { + + if (!core.isset(route)) return route; + + var ans=[], index=0; + + var getNumber = function (noparse) { + var num=""; + while (index=0) && index= 5 && x <= 7) { var topIndex = 6 - parseInt((choices.length - 1) / 2); if (y>=topIndex && y0) { if (keycode==38) { core.status.event.selection--; - if (core.status.event.selection<0) core.status.event.selection=0; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } if (keycode==40) { core.status.event.selection++; - if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -794,6 +948,7 @@ events.prototype.keyUpAction = function (keycode) { var choices = data.choices; if (choices.length>0) { if (keycode==13 || keycode==32 || keycode==67) { + core.status.route.push("choices:"+core.status.event.selection); this.insertAction(choices[core.status.event.selection].action); this.doAction(); } @@ -870,6 +1025,7 @@ events.prototype.clickFly = function(x,y) { var index=core.status.hero.flyRange.indexOf(core.status.floorId); var stair=core.status.event.data=8) { + core.ui.drawMaps(core.status.event.data-1); + } + else { + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.ui.closePanel(); + } +} + +////// 查看地图界面时,按下某个键的操作 ////// +events.prototype.keyDownViewMaps = function (keycode) { + if (keycode==37 || keycode==38) core.ui.drawMaps(core.status.event.data+1); + else if (keycode==39 || keycode==40) core.ui.drawMaps(core.status.event.data-1); + return; +} + +////// 查看地图界面时,放开某个键的操作 ////// +events.prototype.keyUpViewMaps = function (keycode) { + if (keycode==27 || keycode==88 || keycode==13 || keycode==32 || keycode==67) { + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 1); + core.ui.closePanel(); + } + return; +} + ////// 商店界面时的点击操作 ////// events.prototype.clickShop = function(x,y) { var shop = core.status.event.data.shop; @@ -899,6 +1087,9 @@ events.prototype.clickShop = function(x,y) { if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(choices.length / 2); if (y>=topIndex && y eval(use)) { core.drawTip("你的"+use_text+"不足"); - return; + return false; } - eval(use+'-='+need); + core.status.event.data.actions.push(y-topIndex); + eval(use+'-='+need); core.setStatus('money', money); core.setStatus('experience', experience); @@ -930,27 +1122,29 @@ events.prototype.clickShop = function(x,y) { } // 离开 else if (y==topIndex+choices.length) { + if (core.status.event.data.actions.length>0) { + core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); + } + core.status.boxAnimateObjs = []; core.setBoxAnimate(); if (core.status.event.data.fromList) core.ui.drawQuickShop(); else core.ui.closePanel(); } + else return false; } + return true; } ////// 商店界面时,按下某个键的操作 ////// events.prototype.keyDownShop = function (keycode) { - var shop = core.status.event.data.shop; - var choices = shop.choices; if (keycode==38) { core.status.event.selection--; - if (core.status.event.selection<0) core.status.event.selection=0; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } if (keycode==40) { core.status.event.selection++; - if (core.status.event.selection>choices.length) core.status.event.selection=choices.length; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -982,7 +1176,7 @@ events.prototype.clickQuickShop = function(x, y) { if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(keys.length / 2); if (y>=topIndex && ykeys.length) core.status.event.selection=keys.length; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -1141,13 +1332,17 @@ events.prototype.keyUpToolbox = function (keycode) { ////// 存读档界面时的点击操作 ////// events.prototype.clickSL = function(x,y) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + // 上一页 if ((x == 3 || x == 4) && y == 12) { - core.ui.drawSLPanel(core.status.event.data - 6); + core.ui.drawSLPanel(10*(page-1)+offset); } // 下一页 if ((x == 8 || x == 9) && y == 12) { - core.ui.drawSLPanel(core.status.event.data + 6); + core.ui.drawSLPanel(10*(page+1)+offset); } // 返回 if (x>=10 && x<=12 && y==12) { @@ -1158,50 +1353,77 @@ events.prototype.clickSL = function(x,y) { return; } - var page=parseInt((core.status.event.data-1)/6); var index=6*page+1; if (y>=1 && y<=4) { - if (x>=1 && x<=3) core.doSL(index, core.status.event.id); - if (x>=5 && x<=7) core.doSL(index+1, core.status.event.id); - if (x>=9 && x<=11) core.doSL(index+2, core.status.event.id); + if (x>=1 && x<=3) core.doSL("autoSave", core.status.event.id); + if (x>=5 && x<=7) core.doSL(5*page+1, core.status.event.id); + if (x>=9 && x<=11) core.doSL(5*page+2, core.status.event.id); } if (y>=7 && y<=10) { - if (x>=1 && x<=3) core.doSL(index+3, core.status.event.id); - if (x>=5 && x<=7) core.doSL(index+4, core.status.event.id); - if (x>=9 && x<=11) core.doSL(index+5, core.status.event.id); + if (x>=1 && x<=3) core.doSL(5*page+3, core.status.event.id); + if (x>=5 && x<=7) core.doSL(5*page+4, core.status.event.id); + if (x>=9 && x<=11) core.doSL(5*page+5, core.status.event.id); } } ////// 存读档界面时,按下某个键的操作 ////// events.prototype.keyDownSL = function(keycode) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + if (keycode==37) { // left - core.ui.drawSLPanel(core.status.event.data - 1); + if (offset==0) { + core.ui.drawSLPanel(10*(page-1) + 5); + } + else { + core.ui.drawSLPanel(index - 1); + } return; } if (keycode==38) { // up - core.ui.drawSLPanel(core.status.event.data - 3); + if (offset<3) { + core.ui.drawSLPanel(10*(page-1) + offset + 3); + } + else { + core.ui.drawSLPanel(index - 3); + } return; } if (keycode==39) { // right - core.ui.drawSLPanel(core.status.event.data + 1); + if (offset==5) { + core.ui.drawSLPanel(10*(page+1)+1); + } + else { + core.ui.drawSLPanel(index + 1); + } return; } if (keycode==40) { // down - core.ui.drawSLPanel(core.status.event.data + 3); + if (offset>=3) { + core.ui.drawSLPanel(10*(page+1) + offset - 3); + } + else { + core.ui.drawSLPanel(index + 3); + } return; } if (keycode==33) { // PAGEUP - core.ui.drawSLPanel(core.status.event.data - 6); + core.ui.drawSLPanel(10*(page-1) + offset); return; } if (keycode==34) { // PAGEDOWN - core.ui.drawSLPanel(core.status.event.data + 6); + core.ui.drawSLPanel(10*(page+1) + offset); return; } } ////// 存读档界面时,放开某个键的操作 ////// events.prototype.keyUpSL = function (keycode) { + + var index=core.status.event.data; + var page = parseInt(index/10), offset=index%10; + if (keycode==27 || keycode==88 || (core.status.event.id == 'save' && keycode==83) || (core.status.event.id == 'load' && keycode==68)) { core.ui.closePanel(); if (!core.isPlaying()) { @@ -1210,7 +1432,12 @@ events.prototype.keyUpSL = function (keycode) { return; } if (keycode==13 || keycode==32 || keycode==67) { - core.doSL(core.status.event.data, core.status.event.id); + if (offset==0) { + core.doSL("autoSave", core.status.event.id); + } + else { + core.doSL(5*page+offset, core.status.event.id); + } return; } } @@ -1219,7 +1446,7 @@ events.prototype.keyUpSL = function (keycode) { events.prototype.clickSwitchs = function (x,y) { if (x<5 || x>7) return; var choices = [ - "背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "返回主菜单" + "背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "下载离线版本", "返回主菜单" ]; var topIndex = 6 - parseInt((choices.length - 1) / 2); if (y>=topIndex && y=choices.length) core.status.event.selection=choices.length-1; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -1290,11 +1515,11 @@ events.prototype.keyDownSwitchs = function (keycode) { events.prototype.keyUpSwitchs = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=0; - core.ui.drawSettings(false); + core.ui.drawSettings(); return; } var choices = [ - "背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "返回主菜单" + "背景音乐", "背景音效", "战斗动画", "怪物显伤", "领域显伤", "下载离线版本", "返回主菜单" ]; if (keycode==13 || keycode==32 || keycode==67) { var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -1307,7 +1532,7 @@ events.prototype.keyUpSwitchs = function (keycode) { events.prototype.clickSettings = function (x,y) { if (x<5 || x>7) return; var choices = [ - "系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏" + "系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏" ]; var topIndex = 6 - parseInt((choices.length - 1) / 2); if (y>=topIndex && y0) { + text+="\n当前MAX为"+t.max+",最早由 "+(t.username||"匿名")+" 于"+core.formatDate(new Date(1000*t.timestamp))+"打出。"; + } + }) + core.drawText(text); + } + } + else { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:HTTP "+xhr.status); + } + }; + xhr.ontimeout = function() { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:Timeout"); + } + xhr.onerror = function() { + core.drawText("出错啦!\n无法拉取统计信息。\n错误原因:XHR Error"); + } + xhr.send(formData); break; case 6: + core.ui.drawHelp(); + break; + case 7: + core.ui.drawAbout(); + break; + case 8: core.ui.closePanel(); break; } @@ -1352,17 +1631,12 @@ events.prototype.clickSettings = function (x,y) { ////// 系统菜单栏界面时,按下某个键的操作 ////// events.prototype.keyDownSettings = function (keycode) { - var choices = [ - "系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏" - ]; if (keycode==38) { core.status.event.selection--; - if (core.status.event.selection<0) core.status.event.selection=0; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } if (keycode==40) { core.status.event.selection++; - if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -1374,7 +1648,7 @@ events.prototype.keyUpSettings = function (keycode) { return; } var choices = [ - "系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏" + "系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏" ]; if (keycode==13 || keycode==32 || keycode==67) { var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -1386,7 +1660,7 @@ events.prototype.keyUpSettings = function (keycode) { events.prototype.clickSyncSave = function (x,y) { if (x<5 || x>7) return; var choices = [ - "同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单" + "同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单" ]; var topIndex = 6 - parseInt((choices.length - 1) / 2); if (y>=topIndex && y=choices.length) core.status.event.selection=choices.length-1; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } @@ -1439,11 +1751,11 @@ events.prototype.keyDownSyncSave = function (keycode) { events.prototype.keyUpSyncSave = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=2; - core.ui.drawSettings(false); + core.ui.drawSettings(); return; } var choices = [ - "同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单" + "同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单" ]; if (keycode==13 || keycode==32 || keycode==67) { var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -1451,6 +1763,65 @@ events.prototype.keyUpSyncSave = function (keycode) { } } +////// “虚拟键盘”界面时的点击操作 ////// +events.prototype.clickKeyBoard = function (x, y) { + if (y==3 && x>=1 && x<=11) { + core.ui.closePanel(); + core.keyUp(112+x-1); // F1-F12: 112-122 + } + if (y==4 && x>=1 && x<=10) { + core.ui.closePanel(); + core.keyUp(x==10?48:48+x); // 1-9: 49-57; 0: 48 + } + // 字母 + var lines = [ + ["Q","W","E","R","T","Y","U","I","O","P"], + ["A","S","D","F","G","H","J","K","L"], + ["Z","X","C","V","B","N","M"], + ]; + if (y==5 && x>=1 && x<=10) { + core.ui.closePanel(); + core.keyUp(lines[0][x-1].charCodeAt(0)); + } + if (y==6 && x>=1 && x<=9) { + core.ui.closePanel(); + core.keyUp(lines[1][x-1].charCodeAt(0)); + } + if (y==7 && x>=1 && x<=7) { + core.ui.closePanel(); + core.keyUp(lines[2][x-1].charCodeAt(0)); + } + if (y==8 && x>=1 && x<=11) { + core.ui.closePanel(); + if (x==1) core.keyUp(189); // - + if (x==2) core.keyUp(187); // = + if (x==3) core.keyUp(219); // [ + if (x==4) core.keyUp(221); // ] + if (x==5) core.keyUp(220); // \ + if (x==6) core.keyUp(186); // ; + if (x==7) core.keyUp(222); // ' + if (x==8) core.keyUp(188); // , + if (x==9) core.keyUp(190); // . + if (x==10) core.keyUp(191); // / + if (x==11) core.keyUp(192); // ` + } + if (y==9 && x>=1 && x<=10) { + core.ui.closePanel(); + if (x==1) core.keyUp(27); // ESC + if (x==2) core.keyUp(9); // TAB + if (x==3) core.keyUp(20); // CAPS + if (x==4) core.keyUp(16); // SHIFT + if (x==5) core.keyUp(17); // CTRL + if (x==6) core.keyUp(18); // ALT + if (x==7) core.keyUp(32); // SPACE + if (x==8) core.keyUp(8); // BACKSPACE + if (x==9) core.keyUp(13); // ENTER + if (x==10) core.keyUp(46); // DEL + } + if (y==10 && x>=9 && x<=11) + core.ui.closePanel(); +} + ////// “关于”界面时的点击操作 ////// events.prototype.clickAbout = function () { if (core.isPlaying()) diff --git a/libs/floors/sample0.js b/libs/floors/sample0.js index bbc54cd8..e4b65511 100644 --- a/libs/floors/sample0.js +++ b/libs/floors/sample0.js @@ -50,7 +50,6 @@ main.floors.sample0 = { "\t[老人,womanMagician]这些是路障、楼梯、传送门。", "\t[老人,womanMagician]血网的伤害数值、中毒后每步伤害数值、衰弱时攻防下降的数值,都在 data.js 内定义。\n\n路障同样会尽量被自动寻路绕过。", "\t[老人,womanMagician]楼梯和传送门需要在changeFloor中定义目标楼层和位置,可参见样板里已有的的写法。", - "\t[老人,womanMagician]楼梯和传送门是否可“穿透”,由data.js中的全局变量所决定,你也可以单独设置。\n穿透的意思是,自动寻路得到的路径中间经过了楼梯,行走时是否触发楼层转换事件。\n例如,下面的“下箭头”就是不能穿透的。", {"type": "hide", "time": 500} ], "2,8": [ // 守着第一批怪物的老人 @@ -75,7 +74,6 @@ main.floors.sample0 = { {"type": "hide", "time": 500} ] }, - }, "changeFloor": { // 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖 "6,0": {"floorId": "sample1", "stair": "downFloor"}, // 目标点:sample1层的下楼梯位置 @@ -85,8 +83,8 @@ main.floors.sample0 = { "2,12": {"floorId": "sample0", "loc": [2,12]}, "3,12": {"floorId": "sample0", "loc": [6,1], "direction": "up"}, // 切换楼层后勇士面对上方 "4,12": {"floorId": "sample0", "loc": [0,9], "direction": "left", "time": 1000}, // 切换楼层后勇士面对左边,切换动画1000ms - "5,12": {"floorId": "sample0", "loc": [6,10], "portalWithoutTrigger": false}, // 不能穿透 - "6,12": {"floorId": "sample0", "loc": [10,10], "direction": "left", "time": 1000, "portalWithoutTrigger": false}, + "5,12": {"floorId": "sample0", "loc": [6,10], "time": 0}, // time=0表示无切换时间 + "6,12": {"floorId": "sample0", "loc": [10,10], "direction": "left", "time": 1000}, }, "afterBattle": { // 战斗后可能触发的事件列表 "2,6": ["\t[ghostSkeleton]不可能,你怎么可能打败我!\n(一个打败怪物触发的事件)"] diff --git a/libs/icons.js b/libs/icons.js index 4aced479..b8f9d206 100644 --- a/libs/icons.js +++ b/libs/icons.js @@ -14,23 +14,23 @@ icons.prototype.init = function () { 'ground': 0, 'grass': 1, 'grass2': 2, - 'snowGround': 3, - 'ground2': 4, - 'ground3': 5, - 'ground4': 6, - 'sand': 7, - 'ground5': 8, - 'yellowWall2': 9, - 'whiteWall2': 10, - 'blueWall2': 11, - 'blockWall': 12, - 'grayWall': 13, - 'white': 14, - 'ground6': 15, - 'soil': 16, - 'yellowWall': 17, - 'whiteWall': 18, - 'blueWall': 19, + 'yellowWall': 3, + 'whiteWall': 4, + 'blueWall': 5, + 'snowGround': 6, + 'ground2': 7, + 'ground3': 8, + 'ground4': 9, + 'sand': 10, + 'ground5': 11, + 'yellowWall2': 12, + 'whiteWall2': 13, + 'blueWall2': 14, + 'blockWall': 15, + 'grayWall': 16, + 'white': 17, + 'ground6': 18, + 'soil': 19, 'star': 20, 'lava': 21, 'ice': 22, diff --git a/libs/items.js b/libs/items.js index 149fb395..d503e599 100644 --- a/libs/items.js +++ b/libs/items.js @@ -143,8 +143,11 @@ items.prototype.getItemEffectTip = function(itemId) { } ////// 使用道具 ////// -items.prototype.useItem = function (itemId) { - if (!this.canUseItem(itemId)) return; +items.prototype.useItem = function (itemId, callback) { + if (!this.canUseItem(itemId)) { + if (core.isset(callback)) callback(); + return; + } var itemCls = core.material.items[itemId].cls; if (itemId=='book') core.ui.drawBook(0); @@ -174,6 +177,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); @@ -193,11 +197,19 @@ items.prototype.useItem = function (itemId) { core.setFlag('curse', false); } 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(); } ////// 当前能否使用道具 ////// diff --git a/libs/maps.js b/libs/maps.js index 1e9c72dc..36fb5a27 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -356,16 +356,7 @@ maps.prototype.load = function (data, floorId) { } ////// 将当前地图重新变成二维数组形式 ////// -maps.prototype.getMapArray = function (maps, floorId){ - if (!core.isset(floorId)) { - var map = {}; - for (var id in maps) { - map[id] = this.getMapArray(maps, id); - } - return map; - } - - var thisFloor = maps[floorId]; +maps.prototype.getMapArray = function (blockArray){ var blocks = []; for (var x=0;x<13;x++) { @@ -374,7 +365,7 @@ maps.prototype.getMapArray = function (maps, floorId){ blocks[x].push(0); } } - thisFloor.blocks.forEach(function (block) { + blockArray.forEach(function (block) { if (!(core.isset(block.enable) && !block.enable)) blocks[block.y][block.x] = block.id; }); diff --git a/libs/ui.js b/libs/ui.js index f3635f61..1b8217af 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -257,6 +257,8 @@ ui.prototype.drawChoices = function(content, choices) { if (choices.length>0) { if (!core.isset(core.status.event.selection)) core.status.event.selection=0; + if (core.status.event.selection<0) core.status.event.selection=0; + if (core.status.event.selection>=choices.length) core.status.event.selection=choices.length-1; var len = core.canvas.ui.measureText(core.replaceText(choices[core.status.event.selection].text || choices[core.status.event.selection])).width; core.strokeRect('ui', 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28, "#FFD700", 2); } @@ -271,7 +273,8 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { core.status.event.data = {'yes': yesCallback, 'no': noCallback}; core.status.event.ui = text; - if (!core.isset(core.status.event.selection)) core.status.event.selection=1; + if (!core.isset(core.status.event.selection) || core.status.event.selection>1) core.status.event.selection=1; + if (core.status.event.selection<0) core.status.event.selection=0; var background = core.canvas.ui.createPattern(core.material.ground, "repeat"); core.clearMap('ui', 0, 0, 416, 416); @@ -319,29 +322,26 @@ ui.prototype.drawSwitchs = function() { var choices = [ "背景音乐:"+(core.musicStatus.bgmStatus ? "[ON]" : "[OFF]"), "背景音效:"+(core.musicStatus.soundStatus ? "[ON]" : "[OFF]"), - "战斗动画: " + (core.flags.battleAnimate ? "[ON]" : "[OFF]"), - "怪物显伤: " + (core.flags.displayEnemyDamage ? "[ON]" : "[OFF]"), - "领域显伤: " + (core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), + "战斗动画: "+(core.flags.battleAnimate ? "[ON]" : "[OFF]"), + "怪物显伤: "+(core.flags.displayEnemyDamage ? "[ON]" : "[OFF]"), + "领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), + "下载离线版本", "返回主菜单" ]; this.drawChoices(null, choices); - } ////// 绘制系统菜单栏 ////// -ui.prototype.drawSettings = function (need) { - if (!core.checkStatus('settings', need)) - return; +ui.prototype.drawSettings = function () { + core.status.event.id = 'settings'; this.drawChoices(null, [ - "系统设置", "快捷商店", "同步存档", "重新开始", "操作帮助", "关于本塔", "返回游戏" + "系统设置", "快捷商店", "浏览地图", "同步存档", "重新开始", "数据统计", "操作帮助", "关于本塔", "返回游戏" ]); } ////// 绘制快捷商店选择栏 ////// -ui.prototype.drawQuickShop = function (need) { - if (core.isset(need) && !core.checkStatus('selectShop', need)) - return; +ui.prototype.drawQuickShop = function () { core.status.event.id = 'selectShop'; @@ -654,12 +654,17 @@ ui.prototype.drawWaiting = function(text) { core.setAlpha('ui', 1); core.setFillStyle('ui', background); - var left = 97, top = 208 - 32 - 16, right = 416 - 2 * left, bottom = 416 - 2 * top; + core.setFont('ui', 'bold 17px Verdana'); + var text_length = core.canvas.ui.measureText(text).width; + + var right = Math.max(text_length+50, 220); + var left = 208-right/2, top = 208 - 32 - 16, bottom = 416 - 2 * top; + core.fillRect('ui', left, top, right, bottom, background); core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); core.canvas.ui.textAlign = "center"; - core.fillText('ui', text, 208, top + 56, "#FFFFFF", "bold 17px Verdana"); + core.fillText('ui', text, 208, top + 56, '#FFFFFF'); } @@ -669,7 +674,7 @@ ui.prototype.drawSyncSave = function () { core.status.event.id = 'syncSave'; this.drawChoices(null, [ - "同步存档到服务器", "从服务器加载存档", "清空本地存档", "返回主菜单" + "同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "清空所有存档", "返回主菜单" ]); } @@ -902,6 +907,38 @@ ui.prototype.drawFly = function(page) { this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 20, 100, 273); } +////// 绘制浏览地图界面 ////// +ui.prototype.drawMaps = function (index) { + if (!core.isset(index)) index=core.floorIds.indexOf(core.status.floorId); + + if (index<0) index=0; + if (index>=core.floorIds.length) index=core.floorIds.length-1; + + core.lockControl(); + core.status.event.id = 'viewMaps'; + core.status.event.data = index; + + var floorId = core.floorIds[index]; + + clearTimeout(core.interval.tipAnimate); + + core.clearMap('ui', 0, 0, 416, 416); + core.setAlpha('ui', 1); + this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 0, 0, 416); + + core.clearMap('data', 0, 0, 416, 416); + core.setOpacity('data', 0.2); + core.canvas.data.textAlign = 'left'; + core.setFont('data', '16px Arial'); + + var text = core.floors[floorId].title; + var textX = 16, textY = 18, width = textX + core.canvas.data.measureText(text).width + 16, height = 42; + core.fillRect('data', 5, 5, width, height, '#000'); + core.setOpacity('data', 0.5); + core.fillText('data', text, textX + 5, textY + 15, '#fff'); + +} + ////// 绘制道具栏 ////// ui.prototype.drawToolbox = function(index) { @@ -1020,16 +1057,15 @@ ui.prototype.drawToolbox = function(index) { ////// 绘制存档/读档界面 ////// ui.prototype.drawSLPanel = function(index) { if (!core.isset(index)) index=1; - if (index<=0) index=1; - if (index>180) index=180; + if (index<0) index=0; + + var page = parseInt(index/10), offset=index%10; + if (page>=30) page=29; + if (offset>5) offset=5; + index=10*page+offset; core.status.event.data=index; - var page=parseInt((index-1)/6); - - // core.status.event.data = page; - // core.status.savePage = page; - core.clearMap('ui', 0, 0, 416, 416); core.setAlpha('ui', 0.85); core.fillRect('ui', 0, 0, 416, 416, '#000000'); @@ -1040,12 +1076,11 @@ ui.prototype.drawSLPanel = function(index) { var name=core.status.event.id=='save'?"存档":"读档"; for (var i=0;i<6;i++) { - var id=6*page+i+1; - var data=core.getLocalStorage("save"+id,null); - + var id=5*page+i; + var data=core.getLocalStorage(i==0?"autoSave":"save"+id, null); if (i<3) { - core.fillText('ui', name+id, (2*i+1)*u, 35, '#FFFFFF', "bold 17px Verdana"); - core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, id==index?'#FFD700':'#FFFFFF', id==index?6:2); + core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 35, '#FFFFFF', "bold 17px Verdana"); + core.strokeRect('ui', (2*i+1)*u-size/2, 50, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 50, size, data.hero.loc); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 65+size, '#FFFFFF', '10px Verdana'); @@ -1057,7 +1092,7 @@ ui.prototype.drawSLPanel = function(index) { } else { core.fillText('ui', name+id, (2*i-5)*u, 230, '#FFFFFF', "bold 17px Verdana"); - core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, id==index?'#FFD700':'#FFFFFF', id==index?6:2); + core.strokeRect('ui', (2*i-5)*u-size/2, 245, size, size, i==offset?'#FFD700':'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { this.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 245, size, data.hero.loc); core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 260+size, '#FFFFFF', '10px Verdana'); @@ -1091,7 +1126,7 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL } } - var mapArray = core.maps.getMapArray(core.status.maps, floorId); + var mapArray = core.maps.getMapArray(blocks); for (var b in blocks) { var block = blocks[b]; if (core.isset(block.event) && !(core.isset(block.enable) && !block.enable)) { @@ -1116,6 +1151,44 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, heroL } } +ui.prototype.drawKeyBoard = function () { + core.lockControl(); + core.status.event.id = 'keyBoard'; + + core.clearMap('ui', 0, 0, 416, 416); + + var left = 16, top = 48, right = 416 - 2 * left, bottom = 416 - 2 * top; + var background = core.canvas.ui.createPattern(core.material.ground, "repeat"); + core.fillRect('ui', left, top, right, bottom, background); + core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); + + core.canvas.ui.textAlign = "center"; + core.fillText('ui', "虚拟键盘", 208, top+35, "#FFD700", "bold 22px Verdana"); + + core.setFont('ui', '17px Verdana'); + core.setFillStyle('ui', '#FFFFFF'); + var offset = 128-9; + + var lines = [ + ["F1","F2","F3","F4","F5","F6","F7","F8","F9","10","11"], + ["1","2","3","4","5","6","7","8","9","0"], + ["Q","W","E","R","T","Y","U","I","O","P"], + ["A","S","D","F","G","H","J","K","L"], + ["Z","X","C","V","B","N","M"], + ["-","=","[","]","\\",";","'",",",".","/","`"], + ["ES","TA","CA","SH","CT","AL","SP","BS","EN","DE"] + ] + + lines.forEach(function (line) { + for (var i=0;i