diff --git a/README.md b/README.md index 314b01b8..066ff6c4 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! * [Docs / 使用文档说明](https://ckcz123.github.io/mota-js/) * [Video / 视频教程](https://www.bilibili.com/video/av32781473/) -![样板](./docs/img/sample0.png) +![样板](./_docs/img/sample0.png) ## 目录结构 diff --git a/_docs/_api.md b/_docs/_api.md deleted file mode 100644 index db441be3..00000000 --- a/_docs/_api.md +++ /dev/null @@ -1,367 +0,0 @@ -# 附录:API列表 - -?> 目前版本**v2.3.3**,上次更新时间:* {docsify-updated} * - -所有系统支持的API都列在了这里。所有可能被用到的API都在前面用\*标记。 - -可以在chrome浏览器的控制台中(`ctrl+shift+I`,找到Console)中直接进行调用,以查看效果。 - -!> **`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.keyboard.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.replayGame.onclick // 点击“录像回放”时 -main.dom.easyLevel.onclick // 点击“简单难度”时 -main.dom.normalLevel.onclick // 点击“普通难度”时 -main.dom.hardLevel.onclick // 点击“困难难度”时 -``` - -!> **`core.js`:系统核心文件。所有核心逻辑处理都在此文件完成。** - -``` js -* core.status.floorId // 获得当前层floorId -* core.status.thisMap // 获得当前层的地图信息 -* core.status.maps // 获得所有楼层的地图信息 -* core.floors // 获得所有楼层的剧本 - -// ------ 初始化部分 ------ -core.init // 初始化 -core.showStartAnimate // 显示游戏开始界面 -core.hideStartAnimate // 隐藏游戏开始界面 -core.setStartProgressVal // 设置加载进度条进度 -core.setStartLoadTipText // 设置加载进度条提示文字 -core.loader // 加载图片和音频 -core.loadAutotile // 加载Autotile -core.loadImage // 加载图片 -core.loadMusic // 加载音频 -core.isPlaying // 游戏是否已经开始 -core.clearStatus // 清除游戏状态和数据 -core.resetStatus // 重置游戏状态和初始数据 -core.startGame // 开始游戏 -* core.restart // 重新开始游戏;此函数将回到标题页面 - -// ------ 键盘、鼠标事件 ------ -core.onKeyDown // 按下某个键时 -core.onKeyUp // 放开某个键时 -core.pressKey // 按住某个键时 -core.keyDown // 根据按下键的code来执行一系列操作 -core.keyUp // 根据放开键的code来执行一系列操作 -core.ondown // 点击(触摸)事件按下时 -core.onmove // 当在触摸屏上滑动时 -core.onup // 当点击(触摸)事件放开时 -core.getClickLoc // 获得点击事件相对左上角的坐标(0到12之间) -core.onclick // 具体点击屏幕上(x,y)点时,执行的操作 -core.onmousewheel // 滑动鼠标滚轮时的操作 - -// ------ 自动寻路代码相关 ------ -core.clearAutomaticRouteNode // 清除自动寻路路线 -core.stopAutomaticRoute // 停止自动寻路操作 -core.continueAutomaticRoute // 继续剩下的自动寻路操作 -core.clearContinueAutomaticRoute // 清空剩下的自动寻路列表 -core.setAutomaticRoute // 设置自动寻路路线 -core.automaticRoute // 自动寻路算法,找寻最优路径 -core.fillPosWithPoint // 显示离散的寻路点 -core.clearStepPostfix // 清除已经寻路过的部分 - -// ------ 自动行走,行走控制 ------ -core.stopAutoHeroMove // 停止勇士的自动行走 -core.setAutoHeroMove // 设置勇士的自动行走路线 -core.autoHeroMove // 让勇士开始自动行走 -core.setHeroMoveInterval // 设置行走的效果动画 -core.setHeroMoveTriggerInterval // 设置勇士行走过程中对事件的触发检测 -core.moveAction // 实际每一步的行走过程 -* core.turnHero(direction) // 设置勇士的方向(转向) -core.canMoveHero // 勇士能否前往某方向 -core.moveHero // 让勇士开始移动 -core.eventMoveHero // 使用事件让勇士移动。这个函数将不会触发任何事件。 -core.moveOneStep // 每移动一格后执行的事件。中毒时在这里进行扣血判断。 -core.waitHeroToStop(callback) // 停止勇士的一切行动,等待勇士行动结束后,再执行callback回调函数。 -core.stopHero // 停止勇士的移动状态。 -core.drawHero // 绘制勇士。 -* core.setHeroLoc(name, value) // 设置勇士的位置。name为”direction”,”x”,”y” -* core.getHeroLoc(name) // 获得勇士的位置。 -* core.nextX // 获得勇士面对位置的x坐标 -* core.nextY // 获得勇士面对位置的y坐标 - -// ------ 地图和事件处理 ------ -* core.openDoor(id, x, y, needKey, callback) // 打开一扇位于 (x,y) 的门 -* core.battle(id, x, y, force, callback) // 进行战斗;force表示是否强制战斗 -core.afterBattle // 战斗完毕 -core.trigger(x,y) // 触发x,y点的事件 -* core.changeFloor(floorId, stair, heroLoc, time, callback) // 楼层切换。floorId为目标楼层Id,stair可指定为上/下楼梯,time动画时间 -core.mapChangeAnimate // 地图切换动画效果 -core.clearMap // 清除地图 -core.fillText // 在某个canvas上绘制一段文字 -core.fillRect // 在某个canvas上绘制一个矩形 -core.strokeRect // 在某个canvas上绘制一个矩形的边框 -core.drawLine // 在某个canvas上绘制一条线 -core.setFont // 设置某个canvas的文字字体 -core.setLineWidth // 设置某个canvas的线宽度 -core.saveCanvas // 保存某个canvas状态 -core.loadCanvas // 加载某个canvas状态 -core.setStrokeStyle // 设置某个canvas边框属性 -core.setAlpha // 设置某个canvas的alpha值 -core.setOpacity // 设置某个canvas的透明度 -core.setFillStyle // 设置某个canvas的绘制属性(如颜色等) -* core.drawMap(mapId, callback) // 绘制某张地图。mapId为地图Id,绘制完毕将执行callback回调函数。 -core.drawAutotile // 绘制Autotile -* core.noPassExists(x,y) // 某个点是否不可通行 -core.noPass // 某个点是否在区域内且不可通行 -* core.npcExists(x,y) // 某个点是否存在NPC -* core.terrainExists(x,y) // 某个点是否存在(指定的)地形 -* core.stairExists(x,y) // 某个点是否存在楼梯 -* core.nearStair // 当前位置是否在楼梯边 -* core.enemyExists(x,y) // 某个点是否存在(指定的)怪物 -* core.getBlock(x, y, floorId, needEnable) // 获得某个点的block。floorId指定目标楼层,needEnable如果为false则即使该点的事件处于禁用状态也将被返回(否则只有事件启用的点才被返回) -core.moveBlock // 显示移动某块的动画,达到{“type”:”move”}的效果 -core.animateBlock // 显示/隐藏某个块时的动画效果 -core.showBlock // 将某个块从禁用变成启用状态 -core.removeBlock // 将某个块从启用变成禁用状态 -core.removeBlockById // 根据block的索引删除该块 -core.removeBlockByIds // 一次性删除多个block -core.addGlobalAnimate // 添加一个全局动画 -core.removeGlobalAnimate // 删除一个或所有全局动画 -core.setGlobalAnimate // 设置全局动画的显示效果 -core.syncGlobalAnimate // 同步所有的全局动画效果 -core.drawBoxAnimate // 绘制UI层的box动画 -core.updateCheckBlock // 更新领域、夹击、阻击的伤害地图 -core.checkBlock // 检查并执行领域、夹击、阻击事件 -core.snipe // 阻击事件(动画效果) -core.setFg // 更改画面色调 -* core.updateFg // 更新全地图显伤 -* core.itemCount // 获得某个物品的个数 -* core.hasItem // 是否存在某个物品 -* core.setItem // 设置某个物品的个数 -* core.removeItem // 删除某个物品 -* core.useItem // 使用某个物品;直接调用items.js中的useItem函数。 -* core.canUseItem // 能否使用某个物品。直接调用items.js中的canUseItem函数。 -* core.addItem // 增加某个物品的个数 -core.getNextItem // 获得面前的物品(轻按) -* core.getItem // 获得某个物品 -* core.drawTip // 左上角绘制一段提示 -* core.drawText // 地图中间绘制一段文字 - -// ------ 系统机制 ------ -core.replaceText // 将文字中的${和}(表达式)进行替换 -core.calValue // 计算表达式的值 -core.doEffect // 执行一个表达式的effect操作 -core.splitLines // 字符串自动换行的分割 -core.unshift // 向某个数组前插入另一个数组或元素 -core.setLocalStorage // 设置本地存储 -core.getLocalStorage // 获得本地存储 -core.removeLocalStorage // 移除本地存储 -core.clone // 深拷贝一个对象 -core.formatDate // 格式化时间为字符串 -core.formatDate2 // 格式化时间为最简字符串 -core.setTwoDigits // 两位数显示 -core.debug // 进入Debug模式,攻防血和钥匙都调成很高的数值 -core.replay // 开始回放 -core.checkStatus // 判断当前能否进入某个事件 -core.openBook // 点击怪物手册时的打开操作 -core.useFly // 点击楼层传送器时的打开操作 -core.openToolbox // 点击工具栏时的打开操作 -core.openQuickShop // 点击快捷商店时的打开操作 -core.save // 点击保存按钮时的打开操作 -core.load // 点击读取按钮时的打开操作 -core.openSettings // 点击设置按钮时的打开操作 -core.autosave // 自动存档 -core.doSL // 实际进行存读档事件 -core.syncSave // 存档同步操作 -core.saveData // 存档到本地 -core.loadData // 从本地读档 -core.encodeRoute // 将路线压缩 -core.decodeRoute // 将路线解压缩 -* core.setStatus // 设置勇士属性 -* core.getStatus // 获得勇士属性 -core.getLvName // 获得某个等级的名称 -* core.setFlag // 设置某个自定义变量或flag -* core.getFlag // 获得某个自定义变量或flag -* core.hasFlag // 是否存在某个自定义变量或flag,且值为true -core.insertAction // 往当前事件列表之前插入一系列事件 -* core.lockControl // 锁定状态栏,常常用于事件处理 -* core.unlockControl // 解锁状态栏 -* core.isset // 判断某对象是否不为undefined也不会null -core.readFile // 读取一个本地文件内容 -core.download // 下载文件到本地 -core.copy // 复制一段文字到剪切板 -* core.playBgm // 播放背景音乐 -* core.pauseBgm // 暂停背景音乐的播放 -* core.resumeBgm // 恢复背景音乐的播放 -* core.playSound // 播放音频 -core.show // 动画显示某对象 -core.hide // 动画使某对象消失 -core.clearStatusBar // 清空状态栏 -core.updateStatusBar // 更新状态栏 -core.resize // 屏幕分辨率改变后重新自适应 -core.domRenderer // 渲染DOM - -// ------ core.js 结束 ------ -``` - -!> **`data.js` 定义了一些初始化的数据信息。** - -!> **`enemys.js` 定义了怪物信息。** - -``` js -core.enemys.init // 初始化 -* core.enemys.getEnemys // 获得一个或所有怪物数据 -* core.enemys.hasSpecial // 判断是否含有某特殊属性 -* core.enemys.getSpecialText // 获得所有特殊属性的名称 -* core.enemys.getSpecialHint // 获得每个特殊属性的说明 -* core.enemys.getDamage // 获得某个怪物的伤害 -* core.enemys.getExtraDamage // 获得某个怪物的额外伤害 -* core.enemys.getCritical // 临界值计算 -* core.enemys.getCriticalDamage // 临界减伤计算 -* core.enemys.getDefDamage // 1防减伤计算 -* core.enemys.calDamage // 具体的伤害计算公式 -core.enemys.getCurrentEnemys // 获得当前楼层的怪物列表 -``` - -!> **`events.js` 定义了各个事件的处理流程。** - -``` js -core.events.init // 初始化 -core.events.getEvents // 获得一个或所有系统事件类型 -core.events.startGame // 游戏开始事件 -* core.events.setInitData // 不同难度分别设置初始属性 -* core.events.win // 游戏获胜事件 -* core.events.lose // 游戏失败事件 -core.evens.gameOver // 游戏结束 -core.events.afterChangeFloor // 转换楼层结束的事件 -core.events.doEvents // 开始执行一系列自定义事件 -core.events.doAction // 执行当前自定义事件列表中的下一个事件 -core.events.insertAction // 往当前事件列表之前添加一个或多个事件 -core.events.openShop // 打开一个全局商店 -core.events.disableQuickShop // 禁用一个全局商店 -* core.events.canUseQuickShop // 当前能否使用快捷商店 -* core.events.checkLvUp // 检查升级事件 -* core.events.useItem // 尝试使用道具 -core.events.addPoint // 加点事件 -core.events.afterBattle // 战斗结束后触发的事件 -core.events.afterOpenDoor // 开一个门后触发的事件 -core.events.passNet // 经过一个路障 -core.events.changeLight // 改变亮灯(感叹号)的事件 -* core.events.afterChangeLight // 改变亮灯之后,可以触发的事件 -* core.events.afterUseBomb // 使用炸弹/圣锤后的事件 -* core.events.beforeSaveData // 即将存档前可以执行的操作 -* core.events.afterLoadData // 读档事件后,载入事件前,可以执行的操作 - -// ------ 点击事件和键盘事件的处理 ------ -core.events.longClick // 长按 -core.events.keyDownCtrl // 按下Ctrl键时(快捷跳过对话) -core.events.clickConfirmBox // 确认框界面时的点击操作 -core.events.keyUpConfirmBox // 确认框界面时,放开某个键的操作 -core.events.clickAction // 自定义事件时的点击操作 -core.events.keyDownAction // 自定义事件时,按下某个键的操作 -core.events.keyUpAction // 自定义事件时,放开某个键的操作 -core.events.clickBook // 怪物手册界面的点击操作 -core.events.keyDownBook // 怪物手册界面时,按下某个键的操作 -core.events.keyUpBook // 怪物手册界面时,放开某个键的操作 -core.events.clickBookDetail // 怪物手册属性显示界面时的点击操作 -core.events.clickFly // 楼层传送器界面时的点击操作 -core.events.keyDownFly // 楼层传送器界面时,按下某个键的操作 -core.events.keyUpFly // 楼层传送器界面时,放开某个键的操作 -core.events.clickViewMaps // 浏览地图界面时的点击操作 -core.events.keyDownViewMaps // 浏览地图界面时,按下某个键的操作 -core.events.keyUpViewMaps // 浏览地图界面时,放开某个键的操作 -core.events.clickShop // 商店界面时的点击操作 -core.events.keyDownShop // 商店界面时,按下某个键的操作 -core.events.keyUpShop // 商店界面时,放开某个键的操作 -core.events.clickQuickShop // 快捷商店界面时的点击操作 -core.events.keyDownQuickShop // 快捷商店界面时,按下某个键的操作 -core.events.keyUpQuickShop // 快捷商店界面时,放开某个键的操作 -core.events.clickToolbox // 工具栏界面时的点击操作 -core.events.clickToolboxIndex // 选择工具栏界面中某个Index后的操作 -core.events.keyDownToolbox // 工具栏界面时,按下某个键的操作 -core.events.keyUpToolbox // 工具栏界面时,放开某个键的操作 -core.events.clickSL // 存读档界面时的点击操作 -core.events.keyDownSL // 存读档界面时,按下某个键的操作 -core.events.keyUpSL // 存读档界面时,放开某个键的操作 -core.events.clickSwitchs // 系统设置界面时的点击操作 -core.events.keyDownSwitchs // 系统设置界面时,按下某个键的操作 -core.events.keyUpSwitchs // 系统设置界面时,放开某个键的操作 -core.events.clickSettings // 系统菜单栏界面时的点击事件 -core.events.keyDownSettings // 系统菜单栏界面时,按下某个键的操作 -core.events.keyUpSettings // 系统菜单栏界面时,放开某个键的操作 -core.events.clickSyncSave // 同步存档界面时的点击操作 -core.events.keyDownSyncSave // 同步存档界面时,按下某个键的操作 -core.events.keyUpSyncSave // 同步存档界面时,放开某个键的操作 -core.events.clickKeyBoard // 虚拟键盘界面时的点击操作 -core.events.clickAbout // “关于”界面时的点击操作 -``` - -!> `icons.js` 定义了素材ID和它在图片上的索引的对应关系。 - -!> `items.js` 定义了每个道具的名称,以及使用效果。 - -``` js -core.items.init // 初始化 -core.items.getItems // 获得所有道具 -core.items.getItemEffect // “即捡即用类”道具的使用效果 -core.items.getItemEffectTip // “即捡即用类”道具的文字提示 -* core.items.useItem // 使用道具 -* core.items.cauUseItem // 当前能否使用道具 -``` - -!> `maps.js` 定义了数字-ID的对应关系。 - -``` js -core.maps.loadFloor // 加载某个楼层(从剧本或存档中) -core.maps.getBlock // 数字和ID的对应关系 -core.maps.addEvent // 向该楼层添加剧本的自定义事件 -core.maps.addChangeFloor // 向该楼层添加剧本的楼层转换事件 -core.maps.initMaps // 初始化所有地图 -core.maps.save // 将当前地图重新变成数字,以便于存档 -core.maps.load // 将存档中的地图信息重新读取出来 -core.maps.getMapArray // 将当前地图重新变成二维数组形式 -``` - -!> `ui.js` 定义了各种界面的绘制。 - -``` js -core.ui.closePanel // 结束一切事件和绘制,关闭UI窗口,返回游戏进程 -core.ui.drawTextBox // 绘制一个对话框 -core.ui.drawChoices // 绘制一个选项界面 -core.ui.drawConfirmBox // 绘制一个确认/取消的警告页面 -core.ui.drawSwitchs // 绘制系统设置界面 -core.ui.drawSettings // 绘制系统菜单栏 -core.ui.drawQuickShop // 绘制快捷商店选择栏 -core.ui.drawBattleAnimate // 绘制战斗动画 -core.ui.drawWaiting // 绘制等待界面 -core.ui.drawSyncSave // 绘制存档同步界面 -core.ui.drawPagination // 绘制分页 -core.ui.drawEnemyBook // 绘制怪物手册 -core.ui.drawBookDetail // 绘制怪物属性的详细信息 -core.ui.drawFly // 绘制楼层传送器 -core.ui.drawMaps // 绘制浏览地图界面 -core.ui.drawToolbox // 绘制道具栏 -core.ui.drawSLPanel // 绘制存档/读档界面 -core.ui.drawThumbnail // 绘制一个缩略图 -core.ui.drawAbout // 绘制“关于”界面 -core.ui.drawHelp // 绘制帮助界面 -``` diff --git a/_docs/_start.md b/_docs/_start.md deleted file mode 100644 index 5b3d91dc..00000000 --- a/_docs/_start.md +++ /dev/null @@ -1,222 +0,0 @@ -# 快速上手 - -?> 目前版本**v2.3.3**,上次更新时间:* {docsify-updated} * - -在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! - -## 前置需求 - -你需要有满足如下条件才能进行制作: - -- Windows 8以上操作系统;Windows 7需要安装.Net Framework 4.0。(能打开同目录下的“启动服务.exe”即可) -- Chrome浏览器。其他浏览器可能会导致本地服务器产生闪退等现象。 -- 一个很好的文本编辑器。推荐带有高亮染色、错误提示等效果。例如:WebStorm,VSCode,或者至少也要Sublime Text。 - - ([VSCode下载地址](https://code.visualstudio.com/),群里的群文件中也有,强烈推荐之。) - - **2.0版本可以不需要,但是仍然强烈推荐有一个,从而能对H5造塔有更深的了解。** - -只要满足了上述条件,你就可以开始做自己的塔啦! - -## V2.0的使用 - -目前版本已经更新到V2.0,在2.0版本中,我们可以进行全GUI造塔。 - -下面的文档主要是讲如何通过代码编辑的方式来造,仍然强烈建议进行阅读从而有着一定的了解。 - -如果想直接知道如何在V2.0造塔,可以直接参见[V2.0版本介绍](V2.0)的说明,或者看[B站视频教程](http://www.bilibili.com/video/av17608025/)。 - -## 启动HTTP服务 - -在根目录下有一个“启动服务.exe”,运行之。 - -![启动服务](img/server.png) - -* “启动游戏”按钮将打开一个网页,你能在里面看到现在游戏的效果。 -* “地图编辑器”允许你以可视化的方式进行编辑地图。 -* “便捷PS工具”能让你很方便的对自定义素材进行添加。参见[自定义素材](personalization#自定义素材)。 -* “地图生成器”能让你从已有的截图(如RMXP项目)中立刻生成可被本样板识别的地图数据。 -* “RM动画导出器”能让你从RMXP中导出动画而被H5魔塔使用。 -* “JS代码压缩工具”能对JS代码进行压缩,从而减少IO请求数和文件大小。 -* “伤害和临界值计算器”是一个很便捷的小工具,能对怪物的伤害和临界值进行计算。 - -!> **警告:** 非Chrome浏览器(如Edge/IE等)下本地服务器可能表现不正常,会出现闪退等现象。请务必下载安装Chrome浏览器。 - -## 新建剧本 - -类似于RMXP,本塔每层楼都是一个“剧本”,剧本内主要定义了本层的地图和各种事件。主函数将读取每个剧本,并生成实际的地图供游戏使用。 - -我们打开 `project/floors/` 目录,这个目录是所有剧本的目录。我们需要指定一个楼层名,例如MT1;然后,我们可以将`MT0.js`(模板)复制重命名为为`MT1.js`,并使用文本编辑器打开。 - -![新建剧本](./img/script.png) - -然后将楼层名改为MT1,floorId改名为MT1;title可以改成任意内容,将在切换楼层时进行显示(比如可以改成“1层小塔”)。 - -具体样板文件的每个要素如下: -- **`floorId`** 楼层唯一标识符;必须和文件名,以及 `main.floors.xxx` 完全一致 -- **`title`** 楼层中文名,将在切换楼层时进行显示 -- **`name`** 楼层再状态栏显示的名称 -- **`canFlyTo`** 当前楼层可否被楼传器飞到。如果该层不能飞到,则也在该层也不允许使用楼传器。 -- **`canUseQuickShop`** 当前楼层可否使用快捷商店。 -- **`defaultGround`** 该层的背景(地面)素材。 -- **`images`** 该层默认显示的前景/背景图片 -- **`color`** 该层的画面色调。 -- **`bgm`** 到达该层后默认播放的BGM。本项可忽略。 -- **`item_ratio`** 该层的宝石/血瓶倍率 -- **`map`** 本层地图,需要是13x13数组,建议使用地图生成器或者可视化地图编辑器制作。 -- **`firstArrive`** 第一次到该楼层触发的事件 -- **`events`** 该楼的所有可能事件列表 -- **`changeFloor`** 楼层转换事件;该事件不能和上面的events有冲突(同位置点),否则会被覆盖 -- **`afterBattle`** 战斗后可能触发的事件列表 -- **`afterGetItem`** 获得道具后可能触发的事件列表 -- **`afterOpenDoor`** 开完门后可能触发的事件列表 -- **`cannotMove`** 每个图块不可通行的方向,也就是悬崖效果 - -我们最终的任务其实是,将每个楼层的剧本(地图&事件)给写完即可。 - -换句话说,只需要简单的复制操作,我们就可以新建一个剧本了。 - -## 绘制地图 - -有两种绘制地图的方式:从头绘制地图;从RMXP中导入已有的地图。 - -### 从头绘制地图 - -我们直接打开“地图编辑器”,可以看到一个可视化的UI界面。 - -![地图编辑器](img/mapgui.png) - -然后可以在上面任意进行绘制地图。 - -!> **如果地图的数字和ID未被定义,则会进行提示:数字和ID未被定义!此时要对素材的ID和数字进行定义,请参见[自定义素材](personalization#自定义素材)。** - -绘制地图完毕后,点击"导出地图",即可在左边看到对应的JSON数组,并且已经复制到了剪切板。将其粘贴到剧本中的map位置即可。 - -![地图数组](./img/maparray.png) - -!> V2.0版本可以直接将当前地图进行保存或另存为,不需要这样手动打开进行编辑。 - -### 从RMXP导入已有的地图 - -如果我们想复刻一个现有的,已经被RMXP所制作的塔,也有很便捷的方式,那就是用到我们的“地图生成器”。 - -首先,我们打开RMXP和对应的项目,可以看到它的地图。 - -![绘制地图](./img/rmxp2.png) - -我们打开Windows自带的“截图工具”,并将整个地图有效区域截图下来,并将其复制到剪切板。 - -![绘制地图](./img/rmxp3.png) - -截图时请注意:**只截取有效游戏空间内数据,并且有效空间内的范围必须是13x13。(如果地图小于13*13,请用星空或墙壁填充到13x13)。** - -确认地图的图片文件已经复制到剪切板后,我们打开“地图生成器”,并点“加载图片”。大约1-2秒后,可以得到地图的数据。 - -![生成地图](./img/map1.png) - -然后点击“复制地图”,即可将地图数据复制到剪切板。 - -!> **如果有识别不一致的存在,即生成的地图和实际的地图不符,我们可以在地图编辑器中粘贴,再可视化进行编辑。** - -!> **地图生成器默认只支持经典素材。如果有自定义素材需求(例如原版的1层小塔那种素材),请参见[自定义素材](personalization#自定义素材)。** - -!> **请确保截图范围刚好为13x13,并且保证每个位置的像素都是32x32。** - - -## 录入数据 - -有了地图后,我们下一步需要做的就是录入数据。数据主要包括如下几种: - -- 勇士初始的属性 -- 全局变量(宝石效果、全局Flag等) -- 怪物数据(每个怪物的攻防血金币经验等等) - -下面依次进行说明。 - -我们打开`data.js`文件,这里面定义了各种全局属性和勇士初始值。 - -!> V2.0版本可以直接在地图编辑器的`全塔属性`中进行修改! - -我们可以将本塔标题改名为“1层小塔”, - -游戏的唯一标识符叫onefloor,然后可以直接修改勇士的各项初始数据. - -!> **注:name作为游戏的唯一标识符必须进行修改,否则可能会导致存档等出现问题。** - -![初始数据](./img/init.png) - -!> **请注意,勇士的初始位置一栏,x为横坐标,y为纵坐标;即,x为从左到右第几列,y为从上到下第几行,均从0开始计算。** - -修改完初始化信息后,接下来我们需要修改道具的信息(比如宝石加攻防的数值,血瓶加生命的数值等)。还是在这个`data.js`文件,往下拉,找到values一项,并进行相应的设置 - -![修改数据](./img/moddata.png) - -然后,再设置一些系统Flag,以进行游戏。继续将`data.js`往下拉,我们注意到本塔是存在魔防的,不存在经验,因此我们可以简单地将enableMDef改为true,enableExperience改成false,enableDebuff改成false。 - -同理,本塔的破墙镐只能破面前的墙壁,因此`pickaxeFourDirections`需要改成`false`。 - -![系统标志](./img/flag.png) - -其他的几项暂时不会被涉及到,因此不用考虑。 - -全局变量修改完毕后,我们需要告诉主函数加载该楼层。打开`data.js`,找到`floorIds`项,将其值改为楼层ID即MT1。 - -最后一步就是录入怪物数据。打开`enemys.js`文件,依次输入你在本塔内使用到的所有怪物的攻防血的数据。其中怪物的特殊属性(special项)与该文件下面的getSpecialText对应。 - -!> V2.0版本可以直接在“图块属性”一栏进行修改怪物属性! - -![怪物数据](./img/enemyarray.png) - -只需要修改自己用到的怪物属性即可,其他没有用到的怪物完全无所谓。 - -做完后保存所有文件,在本地服务器中“启动游戏”,就能立刻看到自己的塔并开始游戏啦!是不是很简单呢! - -![保存](./img/save.png) - -## 压缩与发布 - -当你将上述步骤完成后,你实际上已经做出来了一个魔塔,并且可以发布给大家进行游戏了。 -目前而言发布有如下几种方式: - -- 离线版本:直接将游戏文件夹打包,放到百度网盘等地方供用户下载;用户下载到本地后直接使用浏览器打开`index.html`进行游戏。 - - 手机端的部分浏览器如chrome也支持本地网页,可以下载到手机然后直接打开进行游戏。 -- 在线版本:将游戏放到某个服务器上,大家在线联网游戏。 - -**离线版本的好处是:先全部下载后再游戏,无需考虑流量的问题,也可以支持高清音乐的播放。坏处是:没办法在多平台之间迁移,无法及时获得游戏更新(需要重新下载),而浏览器打开本地文件有丢失存档的风险。 -在线版本的好处是:随时随地可以玩,可以多平台接档,还可以在后台看到一些统计信息,可以随时对游戏进行更新;坏处是需要一个服务器,且还要考虑到用户流量的问题。** - -在此我们只讨论在线版本。当你决定发布游戏时,强烈建议先将JS代码进行压缩以节省可能的IO请求以及网络流量。直接打开同目录下的“JS代码压缩工具”进行压缩即可。 - -压缩完毕后,你还需要将`main.js`中的useCompress从false改为true,这样方才只会加载压缩后的文件。 - -如果你需要发布到服务器上且你没有服务器,可以直接将本塔发给我(`艾之葵`),我会给负责你部署上去的。我的服务器至少能保证两年内有效。 - -然后就是发布帖子、链接二维码,能让任何人在任何时候任何平台上都能进行游戏啦!是不是很简单呢! - -## 注意事项和常见FAQ - -1. 截图请务必刚好截取13x13的图片,并需要保证每个位置必须为32x32像素。一般无放缩的RMXP符合条件。 -2. 游戏的唯一标识符name请务必修改。如果不修改可能会导致存档出现异常。 -3. 别忘了data.js中要修改floorIds指明所用到的所有楼层哦~ - -下面是几个常见的FAQ: - -**Q: 为什么截图识别不出来?** - -**A:** 请保证刚好为13x13,且每个位置必须32x32像素。如果不确定,可以保存你的截图,右键属性查看详细信息,看像素的宽高是不是在416左右。多少几十像素都是没关系的。 - -![图片大小](./img/imginfo.png) - -**Q: 打开游戏时卡死在了xxx.js加载完毕!无法进入游戏。** - -**A:** 最大的可能是因为少了逗号,或者反括号等等。一般而言VSCode都会有错误提示,你哪里少了东西。 - -如果没有,可以采用如下方式debug: - -Ctrl+Shift+I 打开Chrome的控制台,找到Console。 - -如果出现了语法错误,会有红色提示 **Unexpected xxx** ,找到后面文件名和行号,打开,使用VSCode检查该处是否存在问题,即可。 - -![检查错误](./img/chrome.png) - -========================================================================================== - -[继续阅读下一章:元件说明](element) \ No newline at end of file diff --git a/_docs/element.md b/_docs/element.md index c5fcc4be..8d352fef 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -187,13 +187,6 @@ function() { 多属性可采用数组的写法,比如`'special': [1,3]`视为同时拥有先攻和坚固属性;`'special': [5,10,14,18]`视为拥有3连击、魔防、诅咒、阻击四个属性。 -本塔支持战斗动画,在`data.js`中存在三个全局选项:`canOpenBattleAnimate`, `showBattleAnimateConfirm`, `battleAnimate`。 - -- `canOpenBattleAnimate`代表是否允许用户开启战斗动画。如果你添加了一些自定义属性,且不想修改战斗界面的UI,则可以将其关闭。 -- `showBattleAnimateConfirm`代表是否在游戏开始时给用户提供开启动画的选项。对于一些偏向于萌新的塔,可以开启此项。 -- `battleAnimate`代表是否默认开启战斗动画。此项会被用户存储的设置给覆盖。 -- 如果`canOpenBattleAnimate`为false,则后面两个也强制为false。 - 怪物可以负伤,在`data.js`的全局变量`enableNegativeDamage`中指定。 下面的`getSpecialHint`函数则给定了每个特殊属性的详细描述。这个描述将在怪物手册中看到。 diff --git a/_docs/event.md b/_docs/event.md index a84cc3d8..86f93c9e 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1316,13 +1316,11 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 ### pauseBgm:暂停背景音乐 使用`{"type": "pauseBgm"}`可以暂停背景音乐的播放。 - ### loadBgm:预加载一个背景音乐 使用loadBgm可以预加载一个背景音乐。 diff --git a/_docs/personalization.md b/_docs/personalization.md index 0b54e789..51ca82d2 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -966,7 +966,7 @@ this.getAchievements = function () { - **`flag:heroIcon`**: 当前的勇士行走图名称。 - **`flag:saveEquips`**: 快速换装时保存的套装。 - **`flag:__visited__`**: 当前访问过的楼层。 -- **`flag:equip_atk_buff`**, **`flag:equip_def_buff`**, **`flag:equip_mdef_buff`**: 当前攻防魔防的实际计算比例加成。 +- **`flag:__atk_buff__`**, **`flag:__def_buff__`**, **`flag:__mdef_buff__`**: 当前攻防魔防的实际计算比例加成。 - **`flag:__color__`**, **`flag:__weather__`**, **`flag:__volume__`**: 当前的画面色调、天气和音量。 - **`flag:__events__`**: 当前保存的事件列表,读档时会恢复(适用于在事件中存档) - **`flag:textAttribute`**, **`flag:globalAttribute`**, **`flag:globalFlags`**: 当前的剧情文本属性,当前的全局属性,当前的全局开关。 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index fafa1bb7..df4cf03e 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -5,7 +5,7 @@ grammar MotaAction; //事件 事件编辑器入口之一 event_m - : '事件' BGNL? Newline '覆盖触发器' Bool '启用' Bool '通行状态' B_0_List '动画' Bool '显伤' Bool BGNL? Newline action+ BEND + : '事件' BGNL? Newline '覆盖触发器' Bool '启用' Bool '通行状态' B_0_List '显伤' Bool BGNL? Newline action+ BEND /* event_m @@ -17,11 +17,10 @@ var code = { 'trigger': Bool_0?'action':null, 'enable': Bool_1, 'noPass': B_0_List_0, - 'animate': Bool_2, - 'displayDamage': Bool_3, + 'displayDamage': Bool_2, 'data': 'data_asdfefw' } -if (!Bool_0 && Bool_1 && (B_0_List_0===null) && Bool_2 && Bool_3) code = 'data_asdfefw'; +if (!Bool_0 && Bool_1 && (B_0_List_0===null) && Bool_2) code = 'data_asdfefw'; code=JSON.stringify(code,null,2).split('"data_asdfefw"').join('[\n'+action_0+']\n'); return code; */; @@ -1994,7 +1993,7 @@ ActionParser.prototype.parse = function (obj,type) { if(typeof(obj)===typeof('')) obj={'data':[obj]}; if(obj instanceof Array) obj={'data':obj}; return MotaActionBlocks['event_m'].xmlText([ - obj.trigger==='action',obj.enable,obj.noPass,obj.animate,obj.displayDamage,this.parseList(obj.data) + obj.trigger==='action',obj.enable,obj.noPass,obj.displayDamage,this.parseList(obj.data) ]); case 'changeFloor': diff --git a/_server/comment.js b/_server/comment.js index 72474062..cdf576e4 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -263,6 +263,12 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_range": "thiseval==null||(thiseval instanceof Array)", "_data": "该图块的不可入方向\n可以在这里定义不能朝哪个方向进入该图块,可以达到悬崖之类的效果\n例如 [\"down\"] 代表不能从该图块的上方点朝向下进入此图块\n此值对背景层、事件层、前景层上的图块均有效" }, + "animate": { + "_leaf": true, + "_type": "textarea", + "_range": "thiseval==~~thiseval||thiseval==null", + "_data": "该图块的全局动画帧数。\n如果此项为null,则对于除了npc48外,使用素材默认帧数;npc48默认是1帧(即静止)。" + }, "faceIds": { "_leaf": true, "_type": "textarea", diff --git a/_server/data.comment.js b/_server/data.comment.js index 76c87a1f..4b6d6156 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -606,24 +606,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_range": "thiseval==null || (thiseval>0 && thiseval<=4)", "_data": "竖屏模式下,顶端状态栏canvas化后的行数。\n此项将决定竖屏的状态栏高度,如果设置则不小于1且不大于4。\n仅在statusCanvas开启时才有效" }, - "canOpenBattleAnimate": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "是否允许用户开启战斗过程;如果此项为false,则下面两项均强制视为false" - }, - "showBattleAnimateConfirm": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "是否在游戏开始时提供“是否开启战斗动画”的选项" - }, - "battleAnimate": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "是否默认显示战斗动画;用户可以手动在菜单栏中开关" - }, "displayEnemyDamage": { "_leaf": true, "_type": "checkbox", diff --git a/_server/editor.js b/_server/editor.js index 5a9f3539..f77895f1 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -49,7 +49,6 @@ editor.prototype.init = function (callback) { editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 editor.drawInitData(core.icons.icons); // 初始化绘图 - editor.drawMapBg(); editor.fetchMapFromCore(); editor.updateMap(); editor.buildMark(); @@ -195,7 +194,7 @@ editor.prototype.mapInit = function () { } editor.prototype.fetchMapFromCore = function(){ - var mapArray = core.maps.save(core.status.maps, core.status.floorId); + var mapArray = core.maps.saveMap(core.status.floorId); editor.map = mapArray.map(function (v) { return v.map(function (v) { var x = parseInt(v), y = editor.indexs[x]; @@ -242,7 +241,6 @@ editor.prototype.changeFloor = function (floorId, callback) { core.bigmap.offsetY=0; editor.moveViewport(0,0); - editor.drawMapBg(); editor.fetchMapFromCore(); editor.updateMap(); editor_mode.floor(); @@ -253,12 +251,6 @@ editor.prototype.changeFloor = function (floorId, callback) { /////////// 游戏绘图相关 /////////// -editor.prototype.drawMapBg = function (img) { - return; - //legacy - editor.main.editor.drawMapBg(); -} - editor.prototype.drawEventBlock = function () { var fg=document.getElementById('efg').getContext('2d'); @@ -296,20 +288,30 @@ editor.prototype.drawPosSelection = function () { } editor.prototype.updateMap = function () { - var evs = {}; - if (editor.currentFloorData && editor.currentFloorData.events) { - for (var loc in editor.currentFloorData.events) { - if ((editor.currentFloorData.events[loc]||{}).animate == false) - evs[loc] = {"animate": false}; - } - } - var blocks = main.editor.mapIntoBlocks(editor.map.map(function (v) { + var blocks = core.maps._mapIntoBlocks(editor.map.map(function (v) { return v.map(function (v) { - return v.idnum || v || 0 - }) - }), {'events': evs, 'changeFloor': {}}, editor.currentFloorId); + try { + return v.idnum || v || 0 + } + catch (e) { + console.log("Unable to read idnum from "+v); + return 0; + } + }); + }), {'events': editor.currentFloorData.events}, editor.currentFloorId); core.status.thisMap.blocks = blocks; - main.editor.updateMap(); + + var updateMap = function () { + core.removeGlobalAnimate(null, null, true); + core.clearMap('bg'); + core.clearMap('event'); + core.clearMap('event2'); + core.clearMap('fg'); + core.maps._drawMap_drawBgFg(); + core.maps._drawMap_drawEvent(); + core.setGlobalAnimate(core.values.animateSpeed); + } + updateMap(); var drawTile = function (ctx, x, y, tileInfo) { // 绘制一个普通块 @@ -498,7 +500,6 @@ editor.prototype.drawInitData = function (icons) { dc.drawImage(tilesets[img], nowx, 0) nowx += tilesets[img].width; } - //editor.drawMapBg(); //editor.mapInit(); } @@ -990,7 +991,6 @@ editor.prototype.listen = function () { return widthNoScroll - widthWithScroll; } var scrollBarHeight = getScrollBarHeight(); - console.log(scrollBarHeight); var dataSelection = document.getElementById('dataSelection'); var iconLib=document.getElementById('iconLib'); diff --git a/libs/actions.js b/libs/actions.js index a899d99e..87bedddf 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -6,11 +6,96 @@ actions.js:用户交互的事件的处理 "use strict"; function actions() { - this.init(); + this._init(); } -actions.prototype.init = function () { +actions.prototype._init = function () { this.actionsdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.actions; + this.actions = {}; + // --- onkeyDown注册 + this.registerAction('onkeyDown', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('onkeyDown', '_sys_onkeyDown', this._sys_onkeyDown, 0); + // --- onkeyUp注册 + this.registerAction('onkeyUp', '_sys_onkeyUp_replay', this._sys_onkeyUp_replay, 100); + this.registerAction('onkeyUp', '_sys_onkeyUp', this._sys_onkeyUp, 0); + // --- pressKey注册 + this.registerAction('pressKey', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('pressKey', '_sys_pressKey', this._sys_pressKey, 0); + // --- keyDown注册 + this.registerAction('keyDown', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('keyDown', '_sys_keyDown_lockControl', this._sys_keyDown_lockControl, 50); + this.registerAction('keyDown', '_sys_keyDown', this._sys_keyDown, 0); + // --- keyUp注册 + this.registerAction('keyUp', '_sys_keyUp_replay', this._sys_keyUp_replay, 100); + this.registerAction('keyUp', '_sys_keyUp_lockControl', this._sys_keyUp_lockControl, 50); + this.registerAction('keyUp', '_sys_keyUp', this._sys_keyUp, 0); + // --- ondown注册 + this.registerAction('ondown', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('ondown', '_sys_ondown_paint', this._sys_ondown_paint, 60); + this.registerAction('ondown', '_sys_ondown_lockControl', this._sys_ondown_lockControl, 30); + this.registerAction('ondown', '_sys_ondown', this._sys_ondown, 0); + // --- onmove注册 + this.registerAction('onmove', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('onmove', '_sys_onmove_paint', this._sys_onmove_paint, 50); + this.registerAction('onmove', '_sys_onmove', this._sys_onmove, 0); + // --- onup注册 + this.registerAction('onup', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('onup', '_sys_onup_paint', this._sys_onup_paint, 50); + this.registerAction('onup', '_sys_onup', this._sys_onup, 0); + // --- onclick注册 + this.registerAction('onclick', '_sys_checkReplay', this._sys_checkReplay, 100); + this.registerAction('onclick', '_sys_onclick_lockControl', this._sys_onclick_lockControl, 50); + this.registerAction('onclick', '_sys_onclick', this._sys_onclick, 0); + // --- onmousewheel注册 + this.registerAction('onmousewheel', '_sys_onmousewheel', this._sys_onmousewheel, 0); + // --- keyDownCtrl注册 + this.registerAction('keyDownCtrl', '_sys_keyDownCtrl', this._sys_keyDownCtrl, 0); + // --- longClick注册 + this.registerAction('longClick', '_sys_longClick_lockControl', this._sys_longClick_lockControl, 50); + this.registerAction('longClick', '_sys_longClick', this._sys_longClick, 0); + +} + +////// 注册一个用户交互行为 ////// +/* + * 此函数将注册一个用户交互行为。 + * action:要注册的交互类型,如 ondown, onclick, keyDown 等等。 + * name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。 + * func:执行函数。 + * priority:优先级;优先级高的将会被执行。此项可不填,默认为0。 + * 返回:如果func返回true,则不会再继续执行其他的交互函数;否则会继续执行其他的交互函数。 + */ +actions.prototype.registerAction = function (action, name, func, priority) { + if (!name || !func || !(func instanceof Function)) + return; + priority = priority || 0; + if (!this.actions[action]) { + this.actions[action] = []; + } + this.unregisterAction(action, name); + this.actions[action].push( + {"action": action, "name": name, "func": func, "priority": priority} + ); + this.actions[action] = this.actions[action].sort(function (a, b) { + return b.priority - a.priority; + }); +} + +////// 注销一个用户交互行为 ////// +actions.prototype.unregisterAction = function (action, name) { + if (!this.actions[action]) return; + this.actions[action] = this.actions[action].filter(function (x) { return x.name != name; }); +} + +////// 执行一个用户交互行为 ////// +actions.prototype.doRegisteredAction = function (action) { + var actions = this.actions[action]; + if (!core.isset(actions)) return false; + for (var i = 0; i < actions.length; ++i) { + if (actions[i].func.apply(this, Array.prototype.slice.call(arguments, 1))) + return true; + } + return false; } actions.prototype.checkReplaying = function () { @@ -20,9 +105,17 @@ actions.prototype.checkReplaying = function () { return false; } +////// 检查是否在录像播放中,如果是,则停止交互 +actions.prototype._sys_checkReplay = function () { + if (this.checkReplaying()) return true; +} + ////// 按下某个键时 ////// actions.prototype.onkeyDown = function (e) { - if (this.checkReplaying()) return; + this.doRegisteredAction('onkeyDown', e); +} + +actions.prototype._sys_onkeyDown = function (e) { 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){ @@ -41,6 +134,10 @@ actions.prototype.onkeyDown = function (e) { ////// 放开某个键时 ////// actions.prototype.onkeyUp = function(e) { + this.doRegisteredAction('onkeyUp', e); +} + +actions.prototype._sys_onkeyUp_replay = function (e) { if (this.checkReplaying()) { if (e.keyCode==27) // ESCAPE core.stopReplay(); @@ -66,9 +163,11 @@ actions.prototype.onkeyUp = function(e) { core.setReplaySpeed(12); else if (e.keyCode==54) core.setReplaySpeed(24); - return; + return true; } +} +actions.prototype._sys_onkeyUp = function (e) { var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] if(isArrow && !core.status.lockControl){ for(var ii =0;ii0) { var pos={'x':x,'y':y}; var pos0=core.status.stepPostfix[core.status.stepPostfix.length-1]; @@ -406,49 +477,54 @@ actions.prototype.onmove = function (loc) { core.fillPosWithPoint(pos); } } + return true; } ////// 当点击(触摸)事件放开时 ////// actions.prototype.onup = function () { - if (this.checkReplaying()) return; + this.doRegisteredAction('onup'); +} +actions.prototype._sys_onup_paint = function () { // 画板 - if (core.status.played && (core.status.event||{}).id=='paint') { - this.onupPaint() - return; + if (core.status.played && (core.status.event || {}).id == 'paint') { + this.onupPaint(); + return true; } +} +actions.prototype._sys_onup = function () { clearTimeout(core.timeout.onDownTimeout); core.timeout.onDownTimeout = null; clearInterval(core.interval.onDownInterval); core.interval.onDownInterval = null; - // core.status.holdingPath=0; - if ((core.status.stepPostfix||[]).length>0) { - var stepPostfix = []; - var direction={'0':{'1':'down','-1':'up'},'-1':{'0':'left'},'1':{'0':'right'}}; - for(var ii=1;ii=1000) { - this.longClick(posx, posy); - } - else { - //posx,posy是寻路的目标点,stepPostfix是后续的移动 - this.onclick(posx,posy,stepPostfix); - } - core.status.downTime=null; + var stepPostfix = []; + var direction={'0':{'1':'down','-1':'up'},'-1':{'0':'left'},'1':{'0':'right'}}; + for(var ii=1;ii=1000) { + this.longClick(posx, posy); + } + else { + //posx,posy是寻路的目标点,stepPostfix是后续的移动 + this.onclick(posx,posy,stepPostfix); + } + core.status.downTime=null; + return true; } ////// 获得点击事件相对左上角的坐标(0到12之间) ////// @@ -475,163 +551,104 @@ actions.prototype.getClickLoc = function (x, y) { ////// 具体点击屏幕上(x,y)点时,执行的操作 ////// actions.prototype.onclick = function (x, y, stepPostfix) { - if (this.checkReplaying()) return; // console.log("Click: (" + x + "," + y + ")"); + this.doRegisteredAction('onclick', x, y, stepPostfix || []); +} - stepPostfix=stepPostfix||[]; - - // 非游戏屏幕内 - if (x<0 || y<0 || x>12 || y>12) return; +actions.prototype._sys_onclick_lockControl = function (x, y) { + if (!core.status.lockControl) return false; + switch (core.status.event.id) { + case 'centerFly': + this._clickCenterFly(x, y); + break; + case 'book': + this._clickBook(x,y); + break; + case 'book-detail': + this._clickBookDetail(x,y); + break; + case 'fly': + this._clickFly(x,y); + break; + case 'viewMaps': + this._clickViewMaps(x,y); + break; + case 'switchs': + this._clickSwitchs(x,y); + break; + case 'settings': + this._clickSettings(x,y); + break; + case 'shop': + this._clickShop(x,y); + break; + case 'selectShop': + this._clickQuickShop(x,y); + break; + case 'equipbox': + this._clickEquipbox(x,y); + break; + case 'toolbox': + this._clickToolbox(x,y); + break; + case 'save': + case 'load': + case 'replayLoad': + this._clickSL(x,y); + break; + case 'confirmBox': + this._clickConfirmBox(x,y); + break; + case 'keyBoard': + this._clickKeyBoard(x,y); + break; + case 'action': + this._clickAction(x,y); + break; + case 'text': + core.drawText(); + break; + case 'syncSave': + this._clickSyncSave(x,y); + break; + case 'syncSelect': + this._clickSyncSelect(x,y); + break; + case 'localSaveSelect': + this._clickLocalSaveSelect(x,y); + break; + case 'storageRemove': + this._clickStorageRemove(x,y); + break; + case 'cursor': + this._clickCursor(x,y); + break; + case 'replay': + this._clickReplay(x,y); + break; + case 'gameInfo': + this._clickGameInfo(x,y); + break; + case 'about': + case 'help': + core.ui.closePanel(); + break; + } + return true; +} +actions.prototype._sys_onclick = function (x, y, stepPostfix) { // 寻路 - if (!core.status.lockControl) { - core.setAutomaticRoute(x+parseInt(core.bigmap.offsetX/32), y+parseInt(core.bigmap.offsetY/32), stepPostfix); - return; - } - - // 中心对称飞行器 - if (core.status.event.id == 'centerFly') { - this.clickCenterFly(x, y); - return; - } - - // 怪物手册 - if (core.status.event.id == 'book') { - this.clickBook(x,y); - return; - } - - // 怪物详细信息 - if (core.status.event.id == 'book-detail') { - this.clickBookDetail(x,y); - return; - } - - // 楼层飞行器 - if (core.status.event.id == 'fly') { - this.clickFly(x,y); - return; - } - - // 查看地图 - if (core.status.event.id == 'viewMaps') { - this.clickViewMaps(x,y); - return; - } - - // 开关 - if (core.status.event.id == 'switchs') { - this.clickSwitchs(x,y); - return; - } - - // 设置 - if (core.status.event.id == 'settings') { - this.clickSettings(x,y); - return; - } - - // 商店 - if (core.status.event.id == 'shop') { - this.clickShop(x,y); - return; - } - - // 快捷商店 - if (core.status.event.id == 'selectShop') { - this.clickQuickShop(x,y); - return; - } - - // 装备栏 - if (core.status.event.id == 'equipbox') { - this.clickEquipbox(x,y); - return; - } - - // 工具栏 - if (core.status.event.id == 'toolbox') { - this.clickToolbox(x,y); - return; - } - - // 存读档 - if (core.status.event.id == 'save' || core.status.event.id == 'load' || core.status.event.id=='replayLoad') { - this.clickSL(x,y); - return; - } - - // 选项 - if (core.status.event.id == 'confirmBox') { - this.clickConfirmBox(x,y); - return; - } - - if (core.status.event.id == 'keyBoard') { - this.clickKeyBoard(x,y); - return; - } - - // 关于 - if (core.status.event.id == 'about') { - this.clickAbout(x,y); - return; - } - - if (core.status.event.id == 'help') { - this.clickHelp(x,y); - return; - } - - if (core.status.event.id == 'action') { - this.clickAction(x,y); - return; - } - - // 纯文本 - if (core.status.event.id == 'text') { - core.drawText(); - return; - } - - // 同步存档 - if (core.status.event.id == 'syncSave') { - this.clickSyncSave(x,y); - return; - } - - if (core.status.event.id == 'syncSelect') { - this.clickSyncSelect(x,y); - return; - } - - if (core.status.event.id == 'localSaveSelect') { - this.clickLocalSaveSelect(x,y); - return; - } - if (core.status.event.id=='storageRemove') { - this.clickStorageRemove(x,y); - return; - } - - if (core.status.event.id == 'cursor') { - this.clickCursor(x,y); - return; - } - - if (core.status.event.id == 'replay') { - this.clickReplay(x,y); - return; - } - - if (core.status.event.id=='gameInfo') { - this.clickGameInfo(x,y); - } - + core.setAutomaticRoute(x+parseInt(core.bigmap.offsetX/32), y+parseInt(core.bigmap.offsetY/32), stepPostfix); + return true; } ////// 滑动鼠标滚轮时的操作 ////// actions.prototype.onmousewheel = function (direct) { + this.doRegisteredAction('onmousewheel', direct); +} + +actions.prototype._sys_onmousewheel = function (direct) { // 向下滚动是 -1 ,向上是 1 if (this.checkReplaying()) { @@ -664,76 +681,115 @@ actions.prototype.onmousewheel = function (direct) { // 浏览地图 if (core.status.lockControl && core.status.event.id == 'viewMaps') { - if (direct==1) this.clickViewMaps(6,3); - if (direct==-1) this.clickViewMaps(6,9); + if (direct==1) this._clickViewMaps(6,3); + if (direct==-1) this._clickViewMaps(6,9); return; } + } -/////////////////// 在某个界面时的按键点击效果 /////////////////// - -////// 长按 ////// -actions.prototype.longClick = function (x, y, fromEvent) { - if (!core.isPlaying()) return false; - if (core.status.lockControl) { - if (core.status.event.id=='text') { - core.drawText(); - return true; - } - if (core.status.event.id=='action' && core.status.event.data.type=='text') { - core.doAction(); - return true; - } - // 长按楼传器的箭头可以快速翻页 - if (core.status.event.id=='fly') { - if ((x==10 || x==11) && (y==5 || y==9)) { - this.clickFly(x, y); - return true; - } - } - // 长按可以跳过等待事件 - if (core.status.event.id=='action' && core.status.event.data.type=='sleep' - && !core.status.event.data.current.noSkip) { - if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length==0) { - clearTimeout(core.timeout.sleepTimeout); - core.timeout.sleepTimeout = null; - core.events.doAction(); - return true; - } - } - } - else if (!fromEvent) { - core.waitHeroToStop(function () { - // 绘制快捷键 - core.ui.drawKeyBoard(); - }); - } - return false; -} - -////// 按下Ctrl键时(快捷跳过对话) ////// +////// 长按Ctrl键时 ////// actions.prototype.keyDownCtrl = function () { + this.doRegisteredAction('keyDownCtrl'); +} + +actions.prototype._sys_keyDownCtrl = function () { if (core.status.event.id=='text') { core.drawText(); - return; + return true; } if (core.status.event.id=='action' && core.status.event.data.type=='text') { core.doAction(); - return; + return true; } if (core.status.event.id=='action' && core.status.event.data.type=='sleep' - && !core.status.event.data.current.noSkip) { + && !core.status.event.data.current.noSkip) { if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length==0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.events.doAction(); } - return; + return true; } } -////// -actions.prototype.clickCenterFly = function(x, y) { +////// 长按 ////// +actions.prototype.longClick = function (x, y, fromEvent) { + if (!core.isPlaying()) return false; + return this.doRegisteredAction('longClick', x, y, fromEvent); +} + +actions.prototype._sys_longClick_lockControl = function (x, y) { + if (!core.status.lockControl) return false; + if (core.status.event.id == 'text') { + core.drawText(); + return true; + } + if (core.status.event.id == 'action' && core.status.event.data.type == 'text') { + core.doAction(); + return true; + } + // 长按楼传器的箭头可以快速翻页 + if (core.status.event.id == 'fly') { + if ((x == 10 || x == 11) && (y == 5 || y == 9)) { + this._clickFly(x, y); + return true; + } + } + // 长按可以跳过等待事件 + if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' + && !core.status.event.data.current.noSkip) { + if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length == 0) { + clearTimeout(core.timeout.sleepTimeout); + core.timeout.sleepTimeout = null; + core.events.doAction(); + return true; + } + } + return false; +} + +actions.prototype._sys_longClick = function (x, y, fromEvent) { + if (!core.status.lockControl && !fromEvent) { + // 虚拟键盘 + core.waitHeroToStop(function () { + core.ui.drawKeyBoard(); + }); + return true; + } + return false; +} + +/////////////////// 在某个界面时的按键点击效果 /////////////////// + +// 数字键快速选择选项 +actions.prototype._selectChoices = function (length, keycode, callback) { + var topIndex = 6 - parseInt((length - 1) / 2); + if (keycode==13 || keycode==32 || keycode==67) { + callback(6, topIndex+core.status.event.selection); + } + if (keycode>=49 && keycode<=57) { + var index = keycode-49; + if (index < length) { + callback(6, topIndex+index); + } + } +} + +// 上下键调整选项 +actions.prototype._keyDownChoices = function (keycode) { + if (keycode==38) { + core.status.event.selection--; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } + if (keycode==40) { + core.status.event.selection++; + core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); + } +} + +////// 点击中心对称飞行器时 +actions.prototype._clickCenterFly = function(x, y) { var posX = core.status.event.data.posX, posY = core.status.event.data.posY; core.ui.closePanel(); if (x==posX&& y==posY) { @@ -746,7 +802,7 @@ actions.prototype.clickCenterFly = function(x, y) { } } -actions.prototype.keyUpCenterFly = function (keycode) { +actions.prototype._keyUpCenterFly = function (keycode) { core.ui.closePanel(); if (keycode==51 || keycode==13 || keycode==32 || keycode==67) { if (core.canUseItem('centerFly')) { @@ -758,9 +814,8 @@ actions.prototype.keyUpCenterFly = function (keycode) { } } - ////// 点击确认框时 ////// -actions.prototype.clickConfirmBox = function (x,y) { +actions.prototype._clickConfirmBox = function (x,y) { if ((x == 4 || x == 5) && y == 7 && core.isset(core.status.event.data.yes)) core.status.event.data.yes(); if ((x == 7 || x == 8) && y == 7 && core.isset(core.status.event.data.no)) @@ -768,32 +823,35 @@ actions.prototype.clickConfirmBox = function (x,y) { } ////// 键盘操作确认框时 ////// -actions.prototype.keyUpConfirmBox = function (keycode) { +actions.prototype._keyUpConfirmBox = function (keycode) { if (keycode==37) { core.status.event.selection=0; core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); + return; } if (keycode==39) { core.status.event.selection=1; core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); + return; } if (keycode==13 || keycode==32 || keycode==67) { if (core.status.event.selection==0 && core.isset(core.status.event.data.yes)) { core.status.event.selection=null; core.status.event.data.yes(); + return; } if (core.status.event.selection==1 && core.isset(core.status.event.data.no)) { core.status.event.selection=null; core.status.event.data.no(); + return; } } } ////// 自定义事件时的点击操作 ////// -actions.prototype.clickAction = function (x,y) { - +actions.prototype._clickAction = function (x,y) { if (core.status.event.data.type=='text') { // 打字机效果显示全部文字 @@ -805,16 +863,6 @@ actions.prototype.clickAction = function (x,y) { core.doAction(); return; } - /* - if (core.status.event.data.type=='wait') { - core.setFlag('type', 1); - core.setFlag('x', x); - core.setFlag('y', y); - core.status.route.push("input:"+(10000+100*x+y)); - core.doAction(); - return; - } - */ if (core.status.event.data.type=='choices') { // 选项 @@ -834,25 +882,14 @@ actions.prototype.clickAction = function (x,y) { } ////// 自定义事件时,按下某个键的操作 ////// -actions.prototype.keyDownAction = function (keycode) { +actions.prototype._keyDownAction = function (keycode) { if (core.status.event.data.type=='choices') { - var data = core.status.event.data.current; - var choices = data.choices; - if (choices.length>0) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - } + this._keyDownChoices(keycode); } } ////// 自定义事件时,放开某个键的操作 ////// -actions.prototype.keyUpAction = function (keycode) { +actions.prototype._keyUpAction = function (keycode) { if (core.status.event.data.type=='text' && (keycode==13 || keycode==32 || keycode==67)) { // 打字机效果显示全部文字 if (core.status.event.interval!=null) { @@ -872,26 +909,13 @@ actions.prototype.keyUpAction = function (keycode) { var data = core.status.event.data.current; var choices = data.choices; if (choices.length>0) { - if (keycode==13 || keycode==32 || keycode==67) { - core.status.route.push("choices:"+core.status.event.selection); - core.insertAction(choices[core.status.event.selection].action); - core.doAction(); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index13) this.clickViewMaps(6,0); - if (keycode==65) this.clickViewMaps(0,6); - if (keycode==83 && mh>13) this.clickViewMaps(6,12); - if (keycode==68) this.clickViewMaps(12,6); + if (keycode==38||keycode==33) this._clickViewMaps(6, 3); + if (keycode==40||keycode==34) this._clickViewMaps(6, 9); + if (keycode==87 && mh>13) this._clickViewMaps(6,0); + if (keycode==65) this._clickViewMaps(0,6); + if (keycode==83 && mh>13) this._clickViewMaps(6,12); + if (keycode==68) this._clickViewMaps(12,6); return; } ////// 查看地图界面时,放开某个键的操作 ////// -actions.prototype.keyUpViewMaps = function (keycode) { +actions.prototype._keyUpViewMaps = function (keycode) { if (!core.isset(core.status.event.data)) { core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId)); return; @@ -1113,122 +1137,35 @@ actions.prototype.keyUpViewMaps = function (keycode) { } ////// 商店界面时的点击操作 ////// -actions.prototype.clickShop = function(x,y) { +actions.prototype._clickShop = function(x,y) { var shop = core.status.event.data.shop; var choices = shop.choices; if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(choices.length / 2); if (y>=topIndex && y eval(use)) { - core.drawTip("你的"+use_text+"不足"); - return false; - } - - core.status.event.data.actions.push(y-topIndex); - - eval(use+'-='+need); - core.setStatus('money', money); - core.setStatus('experience', experience); - - // 更新属性 - choice.effect.split(";").forEach(function (t) { - core.doEffect(t, need, times); - }); - core.updateStatusBar(); - shop.times++; - if (shop.commonTimes) - core.setFlag('commonTimes', shop.times); - core.events.openShop(core.status.event.data.id); + return core.events._useShop(shop, y-topIndex); } // 离开 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.event.data.actions = []; - core.status.boxAnimateObjs = []; - if (core.status.event.data.fromList) - core.ui.drawQuickShop(); - else core.ui.closePanel(); + core.events._exitShop(); } else return false; } return true; } -////// 商店界面时,按下某个键的操作 ////// -actions.prototype.keyDownShop = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 商店界面时,放开某个键的操作 ////// -actions.prototype.keyUpShop = function (keycode) { +actions.prototype._keyUpShop = function (keycode) { if (keycode==27 || keycode==88) { - 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.event.data.actions = []; - - core.status.boxAnimateObjs = []; - - if (core.status.event.data.fromList) - core.ui.drawQuickShop(); - else - core.ui.closePanel(); + core.events._exitShop(); return; } - var shop = core.status.event.data.shop; - var choices = shop.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt(choices.length / 2); - this.clickShop(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index<=choices.length) { - var topIndex = 6 - parseInt(choices.length / 2); - this.clickShop(6, topIndex+index); - } - } + this._selectChoices(core.status.event.data.shop.choices.length+1, keycode, this._clickShop); return; } ////// 快捷商店界面时的点击操作 ////// -actions.prototype.clickQuickShop = function(x, y) { +actions.prototype._clickQuickShop = function(x, y) { var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(keys.length / 2); @@ -1248,41 +1185,19 @@ actions.prototype.clickQuickShop = function(x, y) { } } -////// 快捷商店界面时,按下某个键的操作 ////// -actions.prototype.keyDownQuickShop = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 快捷商店界面时,放开某个键的操作 ////// -actions.prototype.keyUpQuickShop = function (keycode) { +actions.prototype._keyUpQuickShop = function (keycode) { if (keycode==27 || keycode==75 || keycode==88 || keycode==86) { core.ui.closePanel(); return; } var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt(keys.length / 2); - this.clickQuickShop(6, topIndex+core.status.event.selection); - } - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index<=keys.length) { - var topIndex = 6 - parseInt(keys.length / 2); - this.clickQuickShop(6, topIndex+index); - } - } + this._selectChoices(keys.length+1, keycode, this._clickQuickShop); return; } ////// 工具栏界面时的点击操作 ////// -actions.prototype.clickToolbox = function(x,y) { +actions.prototype._clickToolbox = function(x,y) { // 装备栏 if (x>=10 && x<=12 && y==0) { core.ui.closePanel(); @@ -1294,19 +1209,6 @@ actions.prototype.clickToolbox = function(x,y) { core.ui.closePanel(); return; } - /* - if (x>=10 && x<=12 && y<=1) { - if (!core.isset(core.status.event.data)) return; - if (!core.flags.enableDeleteItem) { - core.drawTip("不支持删除道具!"); - return; - } - core.removeItem(core.status.event.data); - core.status.event.data = null; - core.ui.drawToolbox(); - return; - } - */ var toolsPage = core.status.event.data.toolsPage; var constantsPage = core.status.event.data.constantsPage; // 上一页 @@ -1340,11 +1242,11 @@ actions.prototype.clickToolbox = function(x,y) { else index =-1; if (index>=0) - this.clickToolboxIndex(index); + this._clickToolboxIndex(index); } ////// 选择工具栏界面中某个Index后的操作 ////// -actions.prototype.clickToolboxIndex = function(index) { +actions.prototype._clickToolboxIndex = function(index) { var items = null; var select; if (index<12) { @@ -1359,7 +1261,7 @@ actions.prototype.clickToolboxIndex = function(index) { if (select>=items.length) return; var itemId=items[select]; if (itemId==core.status.event.data.selectId) { - core.events.useItem(itemId); + core.events.tryUseItem(itemId); } else { core.ui.drawToolbox(index); @@ -1367,7 +1269,7 @@ actions.prototype.clickToolboxIndex = function(index) { } ////// 工具栏界面时,按下某个键的操作 ////// -actions.prototype.keyDownToolbox = function (keycode) { +actions.prototype._keyDownToolbox = function (keycode) { if (!core.isset(core.status.event.data)) return; var tools = Object.keys(core.status.hero.items.tools).sort(); @@ -1400,7 +1302,7 @@ actions.prototype.keyDownToolbox = function (keycode) { } } else index -= 1 ; - this.clickToolboxIndex(index); + this._clickToolboxIndex(index); return; } if (keycode==38) { // up @@ -1411,7 +1313,7 @@ actions.prototype.keyDownToolbox = function (keycode) { } else if (index<6) return; // 第一行没有向上 else index -= 6; - this.clickToolboxIndex(index); + this._clickToolboxIndex(index); return; } if (keycode==39) { // right @@ -1431,7 +1333,7 @@ actions.prototype.keyDownToolbox = function (keycode) { else if(index==constantsLastIndex) // 一个物品无操作 return; else index++; - this.clickToolboxIndex(index); + this._clickToolboxIndex(index); return; } if (keycode==40) { // down @@ -1448,14 +1350,14 @@ actions.prototype.keyDownToolbox = function (keycode) { if (constantsLastIndex > 17) nextIndex = Math.min(constantsLastIndex, index+6); } if (nextIndex!=null) { - this.clickToolboxIndex(nextIndex); + this._clickToolboxIndex(nextIndex); } return; } } ////// 工具栏界面时,放开某个键的操作 ////// -actions.prototype.keyUpToolbox = function (keycode) { +actions.prototype._keyUpToolbox = function (keycode) { if (keycode==81){ core.ui.closePanel(); core.openEquipbox(); @@ -1468,29 +1370,13 @@ actions.prototype.keyUpToolbox = function (keycode) { if (!core.isset(core.status.event.data)) return; if (keycode==13 || keycode==32 || keycode==67) { - this.clickToolboxIndex(core.status.event.selection); + this._clickToolboxIndex(core.status.event.selection); return; } - - /* - if (keycode==46) { // delete - if (!core.isset(core.status.event.data)) return; - if (!core.flags.enableDeleteItem) { - core.drawTip("不支持删除道具!"); - return; - } - core.removeItem(core.status.event.data); - core.status.event.data = null; - core.ui.drawToolbox(); - return; - } - */ - } - ////// 装备栏界面时的点击操作 ////// -actions.prototype.clickEquipbox = function(x,y) { +actions.prototype._clickEquipbox = function(x,y) { // 道具栏 if (x>=10 && x<=12 && y==0) { core.ui.closePanel(); @@ -1533,12 +1419,12 @@ actions.prototype.clickEquipbox = function(x,y) { if (index>=0) { if (index<12) index = parseInt(index/2); - this.clickEquipboxIndex(index); + this._clickEquipboxIndex(index); } } ////// 选择装备栏界面中某个Index后的操作 ////// -actions.prototype.clickEquipboxIndex = function(index) { +actions.prototype._clickEquipboxIndex = function(index) { if (index<6) { if (index>=core.status.globalAttribute.equipName.length) return; if (index==core.status.event.selection && core.isset(core.status.hero.equipment[index])) { @@ -1558,7 +1444,7 @@ actions.prototype.clickEquipboxIndex = function(index) { } ////// 装备栏界面时,按下某个键的操作 ////// -actions.prototype.keyDownEquipbox = function (keycode) { +actions.prototype._keyDownEquipbox = function (keycode) { if (!core.isset(core.status.event.data)) return; var equipCapacity = core.status.globalAttribute.equipName.length; @@ -1580,7 +1466,7 @@ actions.prototype.keyDownEquipbox = function (keycode) { else return; } else index -= 1; - this.clickEquipboxIndex(index); + this._clickEquipboxIndex(index); return; } if (keycode==38) { // up @@ -1592,7 +1478,7 @@ actions.prototype.keyDownEquipbox = function (keycode) { else index = Math.min(equipCapacity-1, index); } else index -= 6; - this.clickEquipboxIndex(index); + this._clickEquipboxIndex(index); return; } if (keycode==39) { // right @@ -1607,7 +1493,7 @@ actions.prototype.keyDownEquipbox = function (keycode) { else if (index==totalLastIndex) return; else index++; - this.clickEquipboxIndex(index); + this._clickEquipboxIndex(index); return; } if (keycode==40) { // down @@ -1625,13 +1511,13 @@ actions.prototype.keyDownEquipbox = function (keycode) { else if (index < 18) index = Math.min(index+6, totalLastIndex); else return; - this.clickEquipboxIndex(index); + this._clickEquipboxIndex(index); return; } } ////// 装备栏界面时,放开某个键的操作 ////// -actions.prototype.keyUpEquipbox = function (keycode, altKey) { +actions.prototype._keyUpEquipbox = function (keycode, altKey) { if (altKey && keycode>=48 && keycode<=57) { core.items.quickSaveEquip(keycode-48); return; @@ -1648,13 +1534,13 @@ actions.prototype.keyUpEquipbox = function (keycode, altKey) { if (!core.isset(core.status.event.data.selectId)) return; if (keycode==13 || keycode==32 || keycode==67) { - this.clickEquipboxIndex(core.status.event.selection); + this._clickEquipboxIndex(core.status.event.selection); return; } } ////// 存读档界面时的点击操作 ////// -actions.prototype.clickSL = function(x,y) { +actions.prototype._clickSL = function(x,y) { var index=core.status.event.data; var page = parseInt(index/10), offset=index%10; @@ -1728,7 +1614,7 @@ actions.prototype.clickSL = function(x,y) { } ////// 存读档界面时,按下某个键的操作 ////// -actions.prototype.keyDownSL = function(keycode) { +actions.prototype._keyDownSL = function(keycode) { var index=core.status.event.data; var page = parseInt(index/10), offset=index%10; @@ -1780,7 +1666,7 @@ actions.prototype.keyDownSL = function(keycode) { } ////// 存读档界面时,放开某个键的操作 ////// -actions.prototype.keyUpSL = function (keycode) { +actions.prototype._keyUpSL = function (keycode) { var index=core.status.event.data; var page = parseInt(index/10), offset=index%10; @@ -1828,7 +1714,7 @@ actions.prototype.keyUpSL = function (keycode) { } ////// 系统设置界面时的点击操作 ////// -actions.prototype.clickSwitchs = function (x,y) { +actions.prototype._clickSwitchs = function (x,y) { if (x<5 || x>7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -1845,34 +1731,24 @@ actions.prototype.clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 2: - if (!core.flags.canOpenBattleAnimate) { - core.drawTip("本塔不能开启战斗动画!"); - } - else { - core.flags.battleAnimate=!core.flags.battleAnimate; - core.setLocalStorage('battleAnimate', core.flags.battleAnimate); - core.ui.drawSwitchs(); - } - break; - case 3: core.flags.displayEnemyDamage=!core.flags.displayEnemyDamage; core.updateDamage(); core.setLocalStorage('enemyDamage', core.flags.displayEnemyDamage); core.ui.drawSwitchs(); break; - case 4: + case 3: core.flags.displayCritical=!core.flags.displayCritical; core.updateDamage(); core.setLocalStorage('critical', core.flags.displayCritical); core.ui.drawSwitchs(); break; - case 5: + case 4: core.flags.displayExtraDamage=!core.flags.displayExtraDamage; core.updateDamage(); core.setLocalStorage('extraDamage', core.flags.displayExtraDamage); core.ui.drawSwitchs(); break; - case 6: + case 5: core.platform.useLocalForage=!core.platform.useLocalForage; core.setLocalStorage('useLocalForage', core.platform.useLocalForage); core.control.getSaveIndexes(function (indexes) { @@ -1880,17 +1756,17 @@ actions.prototype.clickSwitchs = function (x,y) { }); core.ui.drawSwitchs(); break; - case 7: + case 6: core.setFlag('clickMove', !core.getFlag('clickMove', true)); core.ui.drawSwitchs(); break; - case 8: + case 7: core.platform.extendKeyboard = !core.platform.extendKeyboard; core.setLocalStorage('extendKeyboard', core.platform.extendKeyboard); core.updateStatusBar(); core.ui.drawSwitchs(); break; - case 9: + case 8: core.status.event.selection=0; core.ui.drawSettings(); break; @@ -1898,43 +1774,18 @@ actions.prototype.clickSwitchs = function (x,y) { } } -////// 系统设置界面时,按下某个键的操作 ////// -actions.prototype.keyDownSwitchs = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 系统设置界面时,放开某个键的操作 ////// -actions.prototype.keyUpSwitchs = function (keycode) { +actions.prototype._keyUpSwitchs = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=0; core.ui.drawSettings(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSwitchs(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -1983,41 +1834,17 @@ actions.prototype.clickSettings = function (x,y) { return; } -////// 系统菜单栏界面时,按下某个键的操作 ////// -actions.prototype.keyDownSettings = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 系统菜单栏界面时,放开某个键的操作 ////// -actions.prototype.keyUpSettings = function (keycode) { +actions.prototype._keyUpSettings = function (keycode) { if (keycode==27 || keycode==88) { core.ui.closePanel(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSettings(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); @@ -2110,42 +1937,18 @@ actions.prototype.clickSyncSave = function (x,y) { return; } -////// 同步存档界面时,按下某个键的操作 ////// -actions.prototype.keyDownSyncSave = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 同步存档界面时,放开某个键的操作 ////// -actions.prototype.keyUpSyncSave = function (keycode) { +actions.prototype._keyUpSyncSave = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=2; core.ui.drawSettings(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSyncSave(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; @@ -2167,42 +1970,18 @@ actions.prototype.clickSyncSelect = function (x, y) { } } -////// 同步存档选择界面时,按下某个键的操作 ////// -actions.prototype.keyDownSyncSelect = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 同步存档选择界面时,放开某个键的操作 ////// -actions.prototype.keyUpSyncSelect = function (keycode) { +actions.prototype._keyUpSyncSelect = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=0; core.ui.drawSettings(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickSyncSelect(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; @@ -2228,42 +2007,18 @@ actions.prototype.clickLocalSaveSelect = function (x,y) { core.ui.drawSyncSave(); } -////// 存档下载界面时,按下某个键的操作 ////// -actions.prototype.keyDownLocalSaveSelect = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 存档下载界面时,放开某个键的操作 ////// -actions.prototype.keyUpLocalSaveSelect = function (keycode) { +actions.prototype._keyUpLocalSaveSelect = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=0; core.ui.drawSettings(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickLocalSaveSelect(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; @@ -2326,42 +2081,18 @@ actions.prototype.clickStorageRemove = function (x, y) { } } -////// 存档删除界面时,按下某个键的操作 ////// -actions.prototype.keyDownStorageRemove = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 存档删除界面时,放开某个键的操作 ////// -actions.prototype.keyUpStorageRemove = function (keycode) { +actions.prototype._keyUpStorageRemove = function (keycode) { if (keycode==27 || keycode==88) { core.status.event.selection=5; core.ui.drawSyncSave(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickStorageRemove(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; @@ -2373,14 +2104,14 @@ actions.prototype.clickReplay = function (x, y) { case 0: { core.ui.closePanel(); - var hard=core.status.hard, seed = core.getFlag('__seed__'); - core.startGame(hard, seed, core.clone(core.status.route)); + core.startGame(core.status.hard, core.getFlag('__seed__'), core.clone(core.status.route)); break; } case 1: { core.status.event.id = 'replayLoad'; core.status.event.selection = null; + core.ui.clearLastEvent(); var saveIndex = core.saves.saveIndex; var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; core.ui.drawSLPanel(10*page+offset); @@ -2409,42 +2140,17 @@ actions.prototype.clickReplay = function (x, y) { } } -////// 回放选择界面时,按下某个键的操作 ////// -actions.prototype.keyDownReplay = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 回放选择界面时,放开某个键的操作 ////// -actions.prototype.keyUpReplay = function (keycode) { +actions.prototype._keyUpReplay = function (keycode) { if (keycode==27 || keycode==88) { core.ui.closePanel(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickReplay(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index7) return; var choices = core.status.event.ui.choices; @@ -2493,41 +2199,17 @@ actions.prototype.clickGameInfo = function (x, y) { } } -////// 游戏信息界面时,按下某个键的操作 ////// -actions.prototype.keyDownGameInfo = function (keycode) { - if (keycode==38) { - core.status.event.selection--; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } - if (keycode==40) { - core.status.event.selection++; - core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); - } -} - ////// 游戏信息界面时,放开某个键的操作 ////// -actions.prototype.keyUpGameInfo = function (keycode) { +actions.prototype._keyUpGameInfo = function (keycode) { if (keycode==27 || keycode==88) { core.ui.closePanel(); return; } - var choices = core.status.event.ui.choices; - if (keycode==13 || keycode==32 || keycode==67) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); - this.clickGameInfo(6, topIndex+core.status.event.selection); - } - // 数字键快速选择 - if (keycode>=49 && keycode<=57) { - var index = keycode-49; - if (index=1 && x<=11) { core.ui.closePanel(); core.keyUp(112+x-1); // F1-F12: 112-122 @@ -2595,8 +2277,7 @@ actions.prototype.clickKeyBoard = function (x, y) { } ////// 光标界面时的点击操作 ////// -actions.prototype.clickCursor = function (x,y) { - +actions.prototype._clickCursor = function (x,y) { if (x==core.status.automaticRoute.cursorX && y==core.status.automaticRoute.cursorY) { core.ui.closePanel(); core.onclick(x,y,[]); @@ -2608,7 +2289,7 @@ actions.prototype.clickCursor = function (x,y) { } ////// 光标界面时,按下某个键的操作 ////// -actions.prototype.keyDownCursor = function (keycode) { +actions.prototype._keyDownCursor = function (keycode) { if (keycode==37) { // left core.status.automaticRoute.cursorX--; core.ui.drawCursor(); @@ -2632,7 +2313,7 @@ actions.prototype.keyDownCursor = function (keycode) { } ////// 光标界面时,放开某个键的操作 ////// -actions.prototype.keyUpCursor = function (keycode) { +actions.prototype._keyUpCursor = function (keycode) { if (keycode==27 || keycode==88) { core.ui.closePanel(); return; @@ -2644,19 +2325,6 @@ actions.prototype.keyUpCursor = function (keycode) { } } -////// “关于”界面时的点击操作 ////// -actions.prototype.clickAbout = function () { - if (core.isPlaying()) - core.ui.closePanel(); - else - core.restart(true); -} - -////// “帮助”界面时的点击操作 ////// -actions.prototype.clickHelp = function () { - core.ui.closePanel(); -} - ////// 绘图相关 ////// actions.prototype.ondownPaint = function (x, y) { @@ -2689,7 +2357,7 @@ actions.prototype.onupPaint = function () { core.status.event.data.x = null; core.status.event.data.y = null; // 保存 - core.paint[core.status.floorId] = LZString.compress(core.utils.encodeCanvas(core.dymCanvas.paint).join(",")); + core.paint[core.status.floorId] = lzw_encode(core.utils.encodeCanvas(core.dymCanvas.paint).join(",")); } actions.prototype.setPaintMode = function (mode) { @@ -2710,7 +2378,7 @@ actions.prototype.savePaint = function () { var data = {}; for (var floorId in core.paint) { if (core.isset(core.paint[floorId])) - data[floorId] = LZString.decompress(core.paint[floorId]); + data[floorId] = lzw_decode(core.paint[floorId]); } core.download(core.firstData.name+".h5paint", JSON.stringify({ 'name': core.firstData.name, @@ -2731,12 +2399,12 @@ actions.prototype.loadPaint = function () { core.paint = {}; for (var floorId in obj.paint) { if (core.isset(obj.paint[floorId])) - core.paint[floorId] = LZString.compress(obj.paint[floorId]); + core.paint[floorId] = lzw_encode(obj.paint[floorId]); } core.clearMap('paint'); var value = core.paint[core.status.floorId]; - if (core.isset(value)) value = LZString.decompress(value).split(","); + if (core.isset(value)) value = lzw_decode(value).split(","); core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); @@ -2753,7 +2421,7 @@ actions.prototype.exitPaint = function () { core.drawTip("退出绘图模式"); } -actions.prototype.keyUpPaint = function (keycode) { +actions.prototype._keyUpPaint = function (keycode) { if (keycode==27 || keycode==88 || keycode==77 || keycode==13 || keycode==32 || keycode==67) { this.exitPaint(); return; diff --git a/libs/control.js b/libs/control.js index f3f96378..a9296e4a 100644 --- a/libs/control.js +++ b/libs/control.js @@ -7,10 +7,10 @@ control.js:游戏主要逻辑控制 "use strict"; function control() { - this.init(); + this._init(); } -control.prototype.init = function () { +control.prototype._init = function () { this.controldata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.control; } @@ -71,7 +71,8 @@ control.prototype.setRequestAnimationFrame = function () { }); // Global floor images - core.maps.drawFloorImages(core.status.floorId, core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); + core.maps.drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); + core.maps.drawFloorImages(core.status.floorId, core.canvas.fg, 'fg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); // Global Autotile Animate core.status.autotileAnimateObjs.blocks.forEach(function (block) { @@ -406,8 +407,8 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value core.status.floorId = floorId; core.status.maps = core.clone(maps); // 初始化怪物 - core.material.enemys = core.clone(core.enemys.getEnemys()); - core.material.items = core.clone(core.items.getItems()); + core.material.enemys = core.enemys.getEnemys(); + core.material.items = core.items.getItems(); // 初始化人物属性 core.status.hero = core.clone(hero); // 初始化人物图标 @@ -527,9 +528,10 @@ control.prototype.moveDirectly = function (destX, destY) { control.prototype.tryMoveDirectly = function (destX, destY) { if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1) return false; + var canMoveArray = core.maps._canMoveHero_generateArray(); var testMove = function (dx, dy, dir) { if (dx<0 || dx>=core.bigmap.width|| dy<0 || dy>=core.bigmap.height) return false; - if (core.isset(dir) && !core.canMoveHero(dx,dy,dir)) return false; + if (core.isset(dir) && !core.inArray(canMoveArray[dx][dy],dir)) return false; if (core.control.moveDirectly(dx, dy)) { if (core.isset(dir)) core.moveHero(dir, function() {}); return true; @@ -651,6 +653,8 @@ control.prototype.automaticRoute = function (destX, destY) { }}); var ans = []; + var canMoveArray = core.maps._canMoveHero_generateArray(); + route[startX + fw * startY] = ''; queue.queue({depth: 0, x: startX, y: startY}); while (queue.length!=0) { @@ -658,7 +662,7 @@ control.prototype.automaticRoute = function (destX, destY) { var deep = curr.depth, nowX = curr.x, nowY = curr.y; for (var direction in core.utils.scan) { - if (!core.canMoveHero(nowX, nowY, direction)) + if (!core.inArray(canMoveArray[nowX][nowY], direction)) continue; var nx = nowX + core.utils.scan[direction].x; @@ -683,6 +687,9 @@ control.prototype.automaticRoute = function (destX, destY) { if (nextBlock.block.event.trigger == 'changeFloor') deepAdd+=10; } deepAdd+=core.status.checkBlock.damage[nid]*10; + // 绕过捕捉 + if ((core.status.checkBlock.ambush||[])[nid]) + deepAdd += 10000; if (nx == destX && ny == destY) { route[nid] = direction; @@ -1284,6 +1291,21 @@ control.prototype.checkBlock = function () { if (snipe.length>0) core.snipe(snipe); } + // 检查捕捉 + var ambush = (core.status.checkBlock.ambush||[])[x+core.bigmap.width*y]; + if (core.isset(ambush)) { + // 捕捉效果 + var actions = []; + ambush.forEach(function (t) { + actions.push({"type": "move", "loc": [t[0],t[1]], "steps": [t[3]], "time": 500, "keep": false, "async":true}); + }); + actions.push({"type": "waitAsync"}); + // 强制战斗 + ambush.forEach(function (t) { + actions.push({"type": "battle", "id": t[2]}); + }) + core.insertAction(actions); + } } ////// 阻击事件(动画效果) ////// @@ -1485,26 +1507,31 @@ control.prototype.updateDamage = function (floorId, canvas) { if (floorId != core.status.floorId) { tempCheckBlock = core.clone(core.status.checkBlock); core.status.thisMap = core.status.maps[floorId]; - core.bigmap.width = core.floors[floorId].width || 13; - core.bigmap.height = core.floors[floorId].height || 13; + core.bigmap.width = core.floors[floorId].width; + core.bigmap.height = core.floors[floorId].height; core.updateCheckBlock(); } for (var x=0;x0) { + if (damage>0) { // 该点伤害 damage = core.formatBigNumber(damage, true); core.fillBoldText(canvas, damage, 32*x+16, 32*(y+1)-14, '#FF7F00'); } + else { // 检查捕捉 + if ((core.status.checkBlock.ambush||[])[x+core.bigmap.width*y]) { + core.fillBoldText(canvas, '!', 32*x+16, 32*(y+1)-14, '#FF7F00'); + } + } } } if (floorId!=core.status.floorId) { core.status.thisMap = core.status.maps[core.status.floorId]; core.status.checkBlock = tempCheckBlock; - core.bigmap.width = core.floors[core.status.floorId].width || 13; - core.bigmap.height = core.floors[core.status.floorId].height || 13; + core.bigmap.width = core.floors[core.status.floorId].width; + core.bigmap.height = core.floors[core.status.floorId].height; } } } @@ -1798,6 +1825,11 @@ control.prototype.replay = function () { var action=core.status.replay.toReplay.shift(); + if (action == 'input2:===') { + core.replay(); + return; + } + if (action=='up' || action=='down' || action=='left' || action=='right') { core.moveHero(action, function () { setTimeout(function() { @@ -1902,7 +1934,7 @@ control.prototype.replay = function () { core.events.openShop(shopId, false); var shopInterval = setInterval(function () { - if (!core.actions.clickShop(6, topIndex+core.status.event.selection)) { + if (!core.actions._clickShop(6, topIndex+core.status.event.selection)) { clearInterval(shopInterval); core.stopReplay(); core.drawTip("录像文件出错"); @@ -1910,7 +1942,7 @@ control.prototype.replay = function () { } if (selections.length==0) { clearInterval(shopInterval); - core.actions.clickShop(6, topIndex+choices.length); + core.actions._clickShop(6, topIndex+choices.length); core.replay(); return; } @@ -2407,7 +2439,7 @@ control.prototype.saveData = function() { 'floorId': core.status.floorId, 'hero': hero, 'hard': core.status.hard, - 'maps': core.maps.save(core.status.maps), + 'maps': core.maps.saveMap(), 'route': core.encodeRoute(core.status.route), 'values': core.clone(core.values), 'shops': {}, @@ -2430,7 +2462,7 @@ control.prototype.saveData = function() { ////// 从本地读档 ////// control.prototype.loadData = function (data, callback) { - core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.load(data.maps), + core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.loadMap(data.maps), data.values); // load shop times @@ -2543,13 +2575,27 @@ control.prototype.setStatus = function (statusName, statusVal) { } ////// 获得勇士属性 ////// -control.prototype.getStatus = function (statusName) { +control.prototype.getStatus = function (name) { if (!core.isset(core.status.hero)) return null; // support status:x - if (core.isset(core.status.hero.loc[statusName])) - return core.status.hero.loc[statusName]; - if (statusName == 'exp') statusName = 'experience'; - return core.status.hero[statusName]; + if (core.isset(core.status.hero.loc[name])) + return core.status.hero.loc[name]; + if (name == 'exp') name = 'experience'; + return core.status.hero[name]; +} + +control.prototype.getStatusOrDefault = function (status, name) { + if (core.isset(status) && name in status) + return status[name]; + return this.getStatus(name); +} + +control.prototype.getRealStatus = function (name) { + return this.getRealStatusOrDefault(null, name); +} + +control.prototype.getRealStatusOrDefault = function (status, name) { + return this.getStatusOrDefault(status, name) * core.getFlag('__'+name+'_buff__', 1); } ////// 获得某个等级的名称 ////// @@ -2585,6 +2631,12 @@ control.prototype.removeFlag = function(flag) { delete core.status.hero.flags[flag]; } +////// 增加某个flag数值 ////// +control.prototype.addFlag = function(flag, delta) { + if (!core.isset(core.status.hero)) return; + core.setFlag(flag, core.getFlag(flag, 0) + delta); +} + ////// 锁定状态栏,常常用于事件处理 ////// control.prototype.lockControl = function () { core.status.lockControl = true; @@ -2596,7 +2648,7 @@ control.prototype.unLockControl = function () { } ////// 播放背景音乐 ////// -control.prototype.playBgm = function (bgm) { +control.prototype.playBgm = function (bgm, startTime) { if (main.mode!='play')return; // 音频不存在 if (!core.isset(core.material.bgms[bgm])) return; @@ -2614,14 +2666,6 @@ control.prototype.playBgm = function (bgm) { } this.setMusicBtn(); - /* - // 延迟播放 - if (core.material.bgms[bgm] == 'loading') { - core.material.bgms[bgm] = 'starting'; - return; - } - */ - try { // 缓存BGM core.loader.loadBgm(bgm); @@ -2635,7 +2679,7 @@ control.prototype.playBgm = function (bgm) { } // 播放当前BGM core.material.bgms[bgm].volume = core.musicStatus.volume; - core.material.bgms[bgm].currentTime = 0; + core.material.bgms[bgm].currentTime = startTime || 0; core.material.bgms[bgm].play(); core.musicStatus.playingBgm = bgm; core.musicStatus.lastBgm = bgm; diff --git a/libs/core.js b/libs/core.js index 0092ac83..c35abc7f 100644 --- a/libs/core.js +++ b/libs/core.js @@ -212,6 +212,8 @@ function core() { ////// 初始化 ////// core.prototype.init = function (coreData, callback) { + this._forwardFuncs(); + for (var key in coreData) { core[key] = coreData[key]; } @@ -223,11 +225,6 @@ core.prototype.init = function (coreData, callback) { core.flags.enableLevelUp = false; if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false; - if (!core.flags.canOpenBattleAnimate) { - core.flags.showBattleAnimateConfirm = false; - core.flags.battleAnimate = false; - core.setLocalStorage('battleAnimate', false); - } if (core.isset(core.firstData.shops)) { core.firstData.shops.forEach(function (t) { @@ -235,12 +232,14 @@ core.prototype.init = function (coreData, callback) { }) } + core.maps._setFloorSize(); + core.dom.versionLabel.innerHTML = core.firstData.version; core.dom.logoLabel.innerHTML = core.firstData.title; document.title = core.firstData.title + " - HTML5魔塔"; document.getElementById("startLogo").innerHTML = core.firstData.title; - core.material.items = core.clone(core.items.getItems()); - core.material.enemys = core.clone(core.enemys.getEnemys()); + core.material.items = core.items.getItems(); + core.material.enemys = core.enemys.getEnemys(); core.material.icons = core.icons.getIcons(); core.material.events = core.events.getEvents(); @@ -281,11 +280,11 @@ core.prototype.init = function (coreData, callback) { core.platform.useLocalForage = core.getLocalStorage('useLocalForage', !core.platform.isIOS); if (core.platform.useLocalForage) { try { - core.setLocalForage("__test__", LZString.compress("__test__"), function() { + core.setLocalForage("__test__", lzw_encode("__test__"), function() { try { core.getLocalForage("__test__", null, function(data) { try { - if (LZString.decompress(data)!="__test__") { + if (lzw_decode(data)!="__test__") { console.log("localForage unsupported!"); core.platform.useLocalForage=false; } @@ -323,7 +322,6 @@ core.prototype.init = function (coreData, callback) { core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); // switchs - core.flags.battleAnimate = core.getLocalStorage('battleAnimate', core.flags.battleAnimate); core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); core.flags.displayCritical = core.getLocalStorage('critical', core.flags.displayCritical); core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', core.flags.displayExtraDamage); @@ -352,7 +350,7 @@ core.prototype.init = function (coreData, callback) { core.saves.ids = indexes; }); - core.loader.load(function () { + core.loader._load(function () { console.log(core.material); // 设置勇士高度 core.material.icons.hero.height = core.material.images.hero.height/4; @@ -380,1172 +378,36 @@ core.prototype.init = function (coreData, callback) { }); } -////// 设置requestAnimationFrame ////// -core.prototype.setRequestAnimationFrame = function () { - core.control.setRequestAnimationFrame(); -} - -////// 显示游戏开始界面 ////// -core.prototype.showStartAnimate = function (noAnimate, callback) { - core.control.showStartAnimate(noAnimate, callback); -} - -////// 隐藏游戏开始界面 ////// -core.prototype.hideStartAnimate = function (callback) { - core.control.hideStartAnimate(callback); -} - -////// 游戏是否已经开始 ////// -core.prototype.isPlaying = function() { - return core.control.isPlaying(); -} - -////// 清除游戏状态和数据 ////// -core.prototype.clearStatus = function() { - core.control.clearStatus(); -} - -////// 重置游戏状态和初始数据 ////// -core.prototype.resetStatus = function(hero, hard, floorId, route, maps, values) { - core.control.resetStatus(hero, hard, floorId, route, maps, values); -} - -////// 开始游戏 ////// -core.prototype.startGame = function (hard, seed, route, callback) { - core.events.startGame(hard, seed, route, callback); -} - -////// 重新开始游戏;此函数将回到标题页面 ////// -core.prototype.restart = function(noAnimate) { - core.control.restart(noAnimate); -} - -/////////// 系统事件相关 END /////////// - - -/////////// 键盘、鼠标事件相关 /////////// - -////// 按下某个键时 ////// -core.prototype.onkeyDown = function(e) { - return core.actions.onkeyDown(e); -} - -////// 放开某个键时 ////// -core.prototype.onkeyUp = function(e) { - return core.actions.onkeyUp(e); -} - -////// 按住某个键时 ////// -core.prototype.pressKey = function (keyCode) { - return core.actions.pressKey(keyCode); -} - -////// 根据按下键的code来执行一系列操作 ////// -core.prototype.keyDown = function(keyCode) { - return core.actions.keyDown(keyCode); -} - -////// 根据放开键的code来执行一系列操作 ////// -core.prototype.keyUp = function(keyCode, altKey, fromReplay) { - return core.actions.keyUp(keyCode, altKey, fromReplay); -} - -////// 点击(触摸)事件按下时 ////// -core.prototype.ondown = function (loc) { - return core.actions.ondown(loc); -} - -////// 当在触摸屏上滑动时 ////// -core.prototype.onmove = function (loc) { - return core.actions.onmove(loc); -} - -////// 当点击(触摸)事件放开时 ////// -core.prototype.onup = function () { - return core.actions.onup(); -} - -////// 获得点击事件相对左上角的坐标(0到12之间) ////// -core.prototype.getClickLoc = function (x, y) { - return core.actions.getClickLoc(x,y); -} - -////// 具体点击屏幕上(x,y)点时,执行的操作 ////// -core.prototype.onclick = function (x, y, stepPostfix) { - return core.actions.onclick(x,y,stepPostfix); -} - -////// 滑动鼠标滚轮时的操作 ////// -core.prototype.onmousewheel = function (direct) { - return core.actions.onmousewheel(direct); -} - -/////////// 键盘、鼠标事件相关 END /////////// - -/////////// 寻路代码相关 /////////// - -////// 清除自动寻路路线 ////// -core.prototype.clearAutomaticRouteNode = function (x, y) { - core.control.clearAutomaticRouteNode(x,y); -} - -////// 停止自动寻路操作 ////// -core.prototype.stopAutomaticRoute = function () { - core.control.stopAutomaticRoute(); -} - -////// 继续剩下的自动寻路操作 ////// -core.prototype.continueAutomaticRoute = function () { - core.control.continueAutomaticRoute(); -} - -////// 清空剩下的自动寻路列表 ////// -core.prototype.clearContinueAutomaticRoute = function () { - core.control.clearContinueAutomaticRoute(); -} - -////// 设置自动寻路路线 ////// -core.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { - core.control.setAutomaticRoute(destX,destY,stepPostfix); -} - -////// 自动寻路算法,找寻最优路径 ////// -core.prototype.automaticRoute = function (destX, destY) { - return core.control.automaticRoute(destX, destY); -} - -////// 显示离散的寻路点 ////// -core.prototype.fillPosWithPoint = function (pos) { - core.control.fillPosWithPoint(pos); -} - -/////////// 寻路代码相关 END /////////// - - - -/////////// 自动行走 & 行走控制 /////////// - -////// 设置勇士的自动行走路线 ////// -core.prototype.setAutoHeroMove = function (steps) { - core.control.setAutoHeroMove(steps); -} - -////// 设置行走的效果动画 ////// -core.prototype.setHeroMoveInterval = function (direction, x, y, callback) { - core.control.setHeroMoveInterval(direction, x, y, callback); -} - -////// 实际每一步的行走过程 ////// -core.prototype.moveAction = function (callback) { - core.control.moveAction(callback); -} - -////// 转向 ////// -core.prototype.turnHero = function(direction) { - core.control.turnHero(direction); -} - -////// 勇士能否前往某方向 ////// -core.prototype.canMoveHero = function(x,y,direction,floorId) { - return core.maps.canMoveHero(x,y,direction,floorId); -} - -////// 能否瞬间移动 ////// -core.prototype.canMoveDirectly = function (destX,destY) { - return core.maps.canMoveDirectly(destX, destY); -} - -////// 让勇士开始移动 ////// -core.prototype.moveHero = function (direction, callback) { - core.control.moveHero(direction, callback); -} - -/////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// -core.prototype.eventMoveHero = function(steps, time, callback) { - core.control.eventMoveHero(steps, time, callback); -} - -////// 使用事件让勇士跳跃。这个函数将不会触发任何事件 ////// -core.prototype.jumpHero = function (ex,ey,time,callback) { - core.control.jumpHero(ex,ey,time,callback); -} - -////// 每移动一格后执行的事件 ////// -core.prototype.moveOneStep = function() { - core.control.moveOneStep(); -} - -////// 停止勇士的一切行动,等待勇士行动结束后,再执行callback ////// -core.prototype.waitHeroToStop = function(callback) { - core.control.waitHeroToStop(callback); -} - -////// 停止勇士的移动状态 ////// -core.prototype.stopHero = function () { - core.control.stopHero(); -} - -////// 绘制勇士 ////// -core.prototype.drawHero = function (direction, x, y, status, offset) { - core.control.drawHero(direction, x, y, status, offset); -} - -////// 设置勇士的位置 ////// -core.prototype.setHeroLoc = function (itemName, itemVal, noGather) { - core.control.setHeroLoc(itemName, itemVal, noGather); -} - -////// 获得勇士的位置 ////// -core.prototype.getHeroLoc = function (itemName) { - return core.control.getHeroLoc(itemName); -} - -////// 获得勇士面对位置的x坐标 ////// -core.prototype.nextX = function(n) { - return core.control.nextX(n); -} - -////// 获得勇士面对位置的y坐标 ////// -core.prototype.nextY = function (n) { - return core.control.nextY(n); -} - -////// 某个点是否在勇士旁边 ////// -core.prototype.nearHero = function (x, y) { - return core.control.nearHero(x, y); -} - -/////////// 自动行走 & 行走控制 END /////////// - - - -/////////// 地图处理 /////////// - -////// 开门 ////// -core.prototype.openDoor = function (id, x, y, needKey, callback) { - return core.events.openDoor(id, x, y, needKey, callback); -} - -////// 战斗 ////// -core.prototype.battle = function (id, x, y, force, callback) { - core.events.battle(id,x,y,force,callback); -} - -////// 战斗完毕 ////// -core.prototype.afterBattle = function(id, x, y, callback) { - core.events.afterBattle(id, x, y, callback); -} - -////// 触发(x,y)点的事件 ////// -core.prototype.trigger = function (x, y) { - core.events.trigger(x,y); -} - -////// 楼层切换 ////// -core.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, fromLoad) { - core.events.changeFloor(floorId, stair, heroLoc, time, callback, fromLoad); -} - -////// 从名字获得画布 ////// -core.prototype.getContextByName = function (canvas) { - return core.ui.getContextByName(canvas); -} - -////// 清除地图 ////// -core.prototype.clearMap = function (name, x, y, width, height) { - core.ui.clearMap(name, x, y, width, height); -} - -////// 在某个canvas上绘制一段文字 ////// -core.prototype.fillText = function (name, text, x, y, style, font) { - core.ui.fillText(name, text, x, y, style, font); -} - -////// 在某个canvas上绘制一段描边文字 ////// -core.prototype.fillBoldText = function (name, text, x, y, style, font) { - core.ui.fillBoldText(name, text, x, y, style, font); -} - -////// 在某个canvas上绘制一个矩形 ////// -core.prototype.fillRect = function (name, x, y, width, height, style) { - core.ui.fillRect(name, x, y, width, height, style) -} - -////// 在某个canvas上绘制一个矩形的边框 ////// -core.prototype.strokeRect = function (name, x, y, width, height, style, lineWidth) { - core.ui.strokeRect(name, x, y, width, height, style, lineWidth) -} - -////// 在某个canvas上绘制一条线 ////// -core.prototype.drawLine = function (name, x1, y1, x2, y2, style, lineWidth) { - core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth); -} - -////// 在某个canvas上绘制一个箭头 ////// -core.prototype.drawArrow = function (name, x1, y1, x2, y2, style, lineWidth) { - core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth); -} - -////// 设置某个canvas的文字字体 ////// -core.prototype.setFont = function (name, font) { - core.ui.setFont(name, font); -} - -////// 设置某个canvas的线宽度 ////// -core.prototype.setLineWidth = function (name, lineWidth) { - core.ui.setLineWidth(name, lineWidth); -} - -////// 保存某个canvas状态 ////// -core.prototype.saveCanvas = function (name) { - core.ui.saveCanvas(name); -} - -////// 加载某个canvas状态 ////// -core.prototype.loadCanvas = function (name) { - core.ui.loadCanvas(name); -} -////// 设置某个canvas的alpha值 ////// -core.prototype.setAlpha = function (name, alpha) { - core.ui.setAlpha(name, alpha); -} - -////// 设置某个canvas的透明度 ////// -core.prototype.setOpacity = function (name, opacity) { - core.ui.setOpacity(name, opacity); -} - -////// 设置某个canvas的绘制属性(如颜色等) ////// -core.prototype.setFillStyle = function (name, style) { - core.ui.setFillStyle(name, style); -} - -////// 设置某个canvas的边框属性 ////// -core.prototype.setStrokeStyle = function (name, style) { - core.ui.setStrokeStyle(name, style); -} - -////// 设置某个canvas的对齐 ////// -core.prototype.setTextAlign = function (name, align) { - core.ui.setTextAlign(name, align); -} - -////// 计算某段文字的宽度 ////// -core.prototype.calWidth = function (name, text, font) { - return core.ui.calWidth(name, text, font); -} - -////// 绘制一张图片 ////// -core.prototype.drawImage = function (name, image, x, y, w, h, x1, y1, w1, h1) { - core.ui.drawImage(name, image, x, y, w, h, x1, y1, w1, h1); -} - -////// canvas创建 ////// -core.prototype.createCanvas = function (name, x, y, width, height, z) { - return core.ui.createCanvas(name, x, y, width, height, z); -} - -////// canvas重定位 ////// -core.prototype.relocateCanvas = function (name, x, y) { - return core.ui.relocateCanvas(name, x, y); -} - -////// canvas重置 ////// -core.prototype.resizeCanvas = function (name, width, height) { - return core.ui.resizeCanvas(name, width, height); -} - -////// canvas删除 ////// -core.prototype.deleteCanvas = function (name) { - core.ui.deleteCanvas(name); -} -////// 删除所有canvas ////// -core.prototype.deleteAllCanvas = function () { - core.ui.deleteAllCanvas(); -} - -core.prototype.drawBlock = function (block, animate, dx, dy) { - core.maps.drawBlock(block, animate, dx, dy); -} - -////// 绘制某张地图 ////// -core.prototype.drawMap = function (floorId, callback) { - core.maps.drawMap(floorId, callback); -} - -////// 绘制Autotile ////// -core.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, status){ - core.maps.drawAutotile(ctx, mapArr, block, size, left, top, status); -} - -////// 某个点是否不可通行 ////// -core.prototype.noPassExists = function (x, y, floorId) { - return core.maps.noPassExists(x,y,floorId); -} - -////// 某个点是否在区域内且不可通行 ////// -core.prototype.noPass = function (x, y) { - return core.maps.noPass(x,y); -} - -////// 某个点是否存在NPC ////// -core.prototype.npcExists = function (x, y, floorId) { - return core.maps.npcExists(x, y, floorId); -} - -////// 某个点是否存在(指定的)地形 ////// -core.prototype.terrainExists = function (x, y, id, floorId) { - return core.maps.terrainExists(x, y, id, floorId); -} - -////// 某个点是否存在楼梯 ////// -core.prototype.stairExists = function (x, y, floorId) { - return core.maps.stairExists(x, y, floorId); -} - -////// 当前位置是否在楼梯边 ////// -core.prototype.nearStair = function() { - return core.maps.nearStair(); -} - -////// 某个点是否存在(指定的)怪物 ////// -core.prototype.enemyExists = function (x, y, id,floorId) { - return core.maps.enemyExists(x, y, id, floorId); -} - -////// 获得某个点的block ////// -core.prototype.getBlock = function (x, y, floorId, showDisable) { - return core.maps.getBlock(x,y,floorId,showDisable); -} - -////// 获得某个点的blockId ////// -core.prototype.getBlockId = function (x, y, floorId, showDisable) { - return core.maps.getBlockId(x, y, floorId, showDisable); -} - -////// 获得某个点的blockCls ////// -core.prototype.getBlockCls = function (x, y, floorId, showDisable) { - return core.maps.getBlockCls(x, y, floorId, showDisable); -} - -////// 显示移动某块的动画,达到{“type”:”move”}的效果 ////// -core.prototype.moveBlock = function(x,y,steps,time,keep,callback) { - core.maps.moveBlock(x,y,steps,time,keep,callback) -} - -////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 ////// -core.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { - core.maps.jumpBlock(sx,sy,ex,ey,time,keep,callback); -} - -////// 显示/隐藏某个块时的动画效果 ////// -core.prototype.animateBlock = function (loc,type,time,callback) { - core.maps.animateBlock(loc,type,time,callback) -} - -////// 将某个块从禁用变成启用状态 ////// -core.prototype.showBlock = function(x, y, floorId) { - core.maps.showBlock(x,y,floorId); -} - -////// 将某个块从启用变成禁用状态,但是并不删除它 ////// -core.prototype.hideBlock = function(x, y, floorId) { - core.maps.hideBlock(x,y,floorId); -} - -////// 将某个块从启用变成禁用状态,并删除该块 ////// -core.prototype.removeBlock = function (x, y, floorId) { - core.maps.removeBlock(x,y,floorId); -} - -////// 根据block的索引删除该块 ////// -core.prototype.removeBlockById = function (index, floorId) { - core.maps.removeBlockById(index, floorId); -} - -////// 一次性删除多个block ////// -core.prototype.removeBlockByIds = function (floorId, ids) { - core.maps.removeBlockByIds(floorId, ids); -} - -////// 改变图块 ////// -core.prototype.setBlock = function (number, x, y, floorId) { - core.maps.setBlock(number, x, y, floorId); -} - -////// 改变图层块 ////// -core.prototype.setBgFgBlock = function (name, number, x, y, floorId) { - core.maps.setBgFgBlock(name, number, x, y, floorId); -} - -////// 添加一个全局动画 ////// -core.prototype.addGlobalAnimate = function (block) { - core.maps.addGlobalAnimate(block); -} - -core.prototype.addAutotileGlobalAnimate = function (block) { - core.maps.addAutotileGlobalAnimate(block); -} - -////// 删除一个或所有全局动画 ////// -core.prototype.removeGlobalAnimate = function (x, y, all) { - core.maps.removeGlobalAnimate(x, y, all); -} - -////// 设置全局动画的显示效果 ////// -core.prototype.setGlobalAnimate = function (speed) { - core.maps.setGlobalAnimate(speed); -} - -////// 绘制UI层的box动画 ////// -core.prototype.drawBoxAnimate = function () { - core.maps.drawBoxAnimate(); -} - -////// 绘制动画 ////// -core.prototype.drawAnimate = function (name, x, y, callback) { - return core.maps.drawAnimate(name, x, y, callback); -} - -////// 停止动画 ////// -core.prototype.stopAnimate = function (id, doCallback) { - return core.maps.stopAnimate(id, doCallback); -} - -////// 更新领域、夹击、阻击的伤害地图 ////// -core.prototype.updateCheckBlock = function() { - core.control.updateCheckBlock(); -} - -////// 检查并执行领域、夹击、阻击事件 ////// -core.prototype.checkBlock = function () { - core.control.checkBlock(); -} - -////// 阻击事件(动画效果) ////// -core.prototype.snipe = function (snipes) { - core.control.snipe(snipes); -} - -////// 更改天气效果 ////// -core.prototype.setWeather = function (type, level) { - core.control.setWeather(type, level); -} - -////// 更改画面色调 ////// -core.prototype.setFg = function(color, time, callback) { - core.control.setFg(color, time, callback); -} - -////// 画面闪烁 ////// -core.prototype.screenFlash = function (color, time, times, callback) { - core.control.screenFlash(color, time, times, callback); -} - -////// 更新全地图显伤 ////// -core.prototype.updateDamage = function () { - core.control.updateDamage(); -} - -////// 测试是否拥有某个特殊属性 ////// -core.prototype.hasSpecial = function (special, test) { - return core.enemys.hasSpecial(special, test); -} - -////// 判断能否战斗 ////// -core.prototype.canBattle = function(enemyId, x, y, floorId) { - return core.enemys.canBattle(enemyId, x, y, floorId); -} - -////// 获得伤害数值 ////// -core.prototype.getDamage = function(enemy, x, y, floorId) { - return core.enemys.getDamage(enemy, x, y, floorId); -} - -////// 获得某个物品的个数 ////// -core.prototype.itemCount = function (itemId) { - return core.items.itemCount(itemId); -} - -////// 是否存在某个物品 ////// -core.prototype.hasItem = function (itemId) { - return core.items.hasItem(itemId); -} - -////// 是否装备某件装备 ////// -core.prototype.hasEquip = function (itemId) { - return core.items.hasEquip(itemId); -} - -////// 获得某个装备类型的当前装备 ///// -core.prototype.getEquip = function (equipType) { - return core.items.getEquip(equipType); -} - -////// 设置某个物品的个数 ////// -core.prototype.setItem = function (itemId, itemNum) { - core.items.setItem(itemId, itemNum); -} - -////// 删除某个物品 ////// -core.prototype.removeItem = function (itemId, itemNum) { - return core.items.removeItem(itemId, itemNum); -} - -////// 使用某个物品 ////// -core.prototype.useItem = function (itemId, noRoute, callback) { - core.items.useItem(itemId, noRoute, callback); -} - -////// 能否使用某个物品 ////// -core.prototype.canUseItem = function (itemId) { - return core.items.canUseItem(itemId); -} - -////// 换上某件装备 ////// -core.prototype.loadEquip = function (equipId, callback) { - core.items.loadEquip(equipId,callback); -} - -////// 卸下某件装备 ////// -core.prototype.unloadEquip = function (equipType, callback) { - core.items.unloadEquip(equipType,callback); -} - -////// 比较某件装备与当前装备 ////// -core.prototype.compareEquipment = function (equipId, beComparedEquipId) { - return core.items.compareEquipment(equipId, beComparedEquipId); -} - -////// 增加某个物品的个数 ////// -core.prototype.addItem = function (itemId, itemNum) { - core.items.addItem(itemId, itemNum); -} - -////// 获得面前的物品(轻按) ////// -core.prototype.getNextItem = function() { - return core.events.getNextItem(); -} - -////// 获得某个物品 ////// -core.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { - core.events.getItem(itemId, itemNum, itemX, itemY, callback); -} - -////// 左上角绘制一段提示 ////// -core.prototype.drawTip = function (text, itemIcon) { - core.ui.drawTip(text, itemIcon); -} - -////// 地图中间绘制一段文字 ////// -core.prototype.drawText = function (contents, callback) { - core.ui.drawText(contents, callback); -} - -/////////// 地图相关 END /////////// - - - - -/////////// 系统机制 /////////// - -////// 将文字中的${和}(表达式)进行替换 ////// -core.prototype.replaceText = function (text, need, times) { - return core.utils.replaceText(text, need, times); -} - -////// 计算表达式的值 ////// -core.prototype.calValue = function (value, prefix, need, times) { - return core.utils.calValue(value, prefix, need, times); -} - -////// 执行一个表达式的effect操作 ////// -core.prototype.doEffect = function (expression, need, times) { - core.control.doEffect(expression, need, times); -} - -////// 字符串自动换行的分割 ////// -core.prototype.splitLines = function(canvas, text, maxLength, font) { - return core.utils.splitLines(canvas, text, maxLength, font); -} - -////// 向某个数组前插入另一个数组或元素 ////// -core.prototype.unshift = function (a,b) { - return core.utils.unshift(a,b); -} - -////// 向某个数组后插入另一个数组或元素 ////// -core.prototype.push = function (a,b) { - return core.utils.push(a,b); -} - -////// 设置本地存储 ////// -core.prototype.setLocalStorage = function(key, value) { - return core.utils.setLocalStorage(key, value); -} - -////// 获得本地存储 ////// -core.prototype.getLocalStorage = function(key, defaultValue) { - return core.utils.getLocalStorage(key, defaultValue); -} - -////// 移除本地存储 ////// -core.prototype.removeLocalStorage = function (key) { - core.utils.removeLocalStorage(key); -} - -core.prototype.setLocalForage = function (key, value, successCallback, errorCallback) { - core.utils.setLocalForage(key, value, successCallback, errorCallback); -} - -core.prototype.getLocalForage = function (key, defaultValue, successCallback, errorCallback) { - core.utils.getLocalForage(key, defaultValue, successCallback, errorCallback); -} - -core.prototype.removeLocalForage = function (key, successCallback, errorCallback) { - core.utils.removeLocalForage(key, successCallback, errorCallback); -} - -////// 深拷贝一个对象 ////// -core.prototype.clone = function (data) { - return core.utils.clone(data); -} - -////// 裁剪图片 ////// -core.prototype.cropImage = function (image, size) { - return core.utils.cropImage(image, size); -} - -////// 格式化时间为字符串 ////// -core.prototype.formatDate = function(date) { - return core.utils.formatDate(date); -} - -////// 格式化时间为最简字符串 ////// -core.prototype.formatDate2 = function (date) { - return core.utils.formatDate2(date); -} - -////// 格式化大数 ////// -core.prototype.formatBigNumber = function (x, onMap) { - return core.utils.formatBigNumber(x, onMap); -} - -////// 两位数显示 ////// -core.prototype.setTwoDigits = function (x) { - return core.utils.setTwoDigits(x); -} - -////// 数组转RGB ////// -core.prototype.arrayToRGB = function (color) { - return core.utils.arrayToRGB(color); -} - -////// 数组转RGBA ////// -core.prototype.arrayToRGBA = function (color) { - return core.utils.arrayToRGBA(color); -} - - -////// 作弊 ////// -core.prototype.debug = function() { - core.control.debug(); -} - -////// 存档前 ////// -core.prototype.beforeSaveData = function (data) { - return core.events.beforeSaveData(data); -} - -////// 读档后 ////// -core.prototype.afterLoadData = function (data) { - return core.events.afterLoadData(data); -} - -////// 重置当前地图 ////// -core.prototype.resetMap = function(floorId) { - core.maps.resetMap(floorId); -} - -////// 选择录像文件 ////// -core.prototype.chooseReplayFile = function () { - core.control.chooseReplayFile(); -} - -////// 开始播放 ////// -core.prototype.startReplay = function (list) { - core.control.startReplay(list); -} - -////// 关闭UI窗口 ////// -core.prototype.closePanel = function () { - core.ui.closePanel(); -} - -////// 一般清除事件 ////// -core.prototype.clearLastEvent = function () { - core.ui.clearLastEvent(); -} - -////// 更改播放状态 ////// -core.prototype.triggerReplay = function () { - core.control.triggerReplay(); -} - -////// 暂停播放 ////// -core.prototype.pauseReplay = function () { - core.control.pauseReplay(); -} - -////// 恢复播放 ////// -core.prototype.resumeReplay = function () { - core.control.resumeReplay(); -} - -////// 加速播放 ////// -core.prototype.speedUpReplay = function () { - core.control.speedUpReplay(); -} - -////// 减速播放 ////// -core.prototype.speedDownReplay = function () { - core.control.speedDownReplay(); -} - -////// 设置播放速度 ////// -core.prototype.setReplaySpeed = function (speed) { - core.control.setReplaySpeed(speed); -} - -////// 回退播放 ////// -core.prototype.rewindReplay = function () { - core.control.rewindReplay(); -} - -////// 停止播放 ////// -core.prototype.stopReplay = function () { - core.control.stopReplay(); -} - -////// 回放时存档 ////// -core.prototype.saveReplay = function () { - core.control.saveReplay(); -} - -////// 回放时查看怪物手册 ////// -core.prototype.bookReplay = function () { - core.control.bookReplay(); -} - -////// 回放录像时浏览地图 ////// -core.prototype.viewMapReplay = function () { - core.control.viewMapReplay(); -} - -////// 回放 ////// -core.prototype.replay = function () { - core.control.replay(); -} - -////// 是否正在回放录像 ////// -core.prototype.isReplaying = function () { - return core.control.isReplaying(); -} - -////// 判断当前能否进入某个事件 ////// -core.prototype.checkStatus = function (name, need, item) { - return core.control.checkStatus(name, need, item); -} - -////// 点击怪物手册时的打开操作 ////// -core.prototype.openBook = function (need) { - core.control.openBook(need); -} - -////// 点击楼层传送器时的打开操作 ////// -core.prototype.useFly = function (need) { - core.control.useFly(need); -} - -////// 点击装备栏时的打开操作 ////// -core.prototype.openEquipbox = function (need) { - core.control.openEquipbox(need); -} - -////// 点击工具栏时的打开操作 ////// -core.prototype.openToolbox = function (need) { - core.control.openToolbox(need); -} - -////// 点击快捷商店按钮时的打开操作 ////// -core.prototype.openQuickShop = function (need) { - core.control.openQuickShop(need); -} - -core.prototype.openKeyBoard = function (need) { - core.control.openKeyBoard(need); -} - -////// 点击保存按钮时的打开操作 ////// -core.prototype.save = function(need) { - core.control.save(need); -} - -////// 点击读取按钮时的打开操作 ////// -core.prototype.load = function (need) { - core.control.load(need); -} - -////// 点击设置按钮时的操作 ////// -core.prototype.openSettings = function (need) { - core.control.openSettings(need); -} - -////// 自动存档 ////// -core.prototype.autosave = function (removeLast) { - core.control.autosave(removeLast); -} - -////// 实际进行存读档事件 ////// -core.prototype.doSL = function (id, type) { - core.control.doSL(id, type); -} - -////// 同步存档到服务器 ////// -core.prototype.syncSave = function (type) { - core.control.syncSave(type); -} - -////// 从服务器加载存档 ////// -core.prototype.syncLoad = function () { - core.control.syncLoad(); -} - -////// 存档到本地 ////// -core.prototype.saveData = function() { - return core.control.saveData(); -} - -////// 从本地读档 ////// -core.prototype.loadData = function (data, callback) { - core.control.loadData(data, callback); -} - -////// 加密路线 ////// -core.prototype.encodeRoute = function (route) { - return core.utils.encodeRoute(route); -} - -////// 解密路线 ////// -core.prototype.decodeRoute = function (route) { - return core.utils.decodeRoute(route); -} - -////// 发送HTTP ////// -core.prototype.http = function (type, url, formData, success, error, mimeType, responseType) { - core.utils.http(type, url, formData, success, error, mimeType, responseType) -} - -////// 判断某个存档位是否存在存档 ////// -core.prototype.hasSave = function (index) { - return core.control.hasSave(index); -} - -////// 设置勇士属性 ////// -core.prototype.setStatus = function (statusName, statusVal) { - core.control.setStatus(statusName, statusVal); -} - -////// 获得勇士属性 ////// -core.prototype.getStatus = function (statusName) { - return core.control.getStatus(statusName); -} - -////// 获得某个等级的名称 ////// -core.prototype.getLvName = function () { - return core.control.getLvName(); -} - -////// 设置某个自定义变量或flag ////// -core.prototype.setFlag = function(flag, value) { - core.control.setFlag(flag, value); -} - -////// 获得某个自定义变量或flag ////// -core.prototype.getFlag = function(flag, defaultValue) { - return core.control.getFlag(flag, defaultValue); -} - -////// 是否存在某个自定义变量或flag,且值为true ////// -core.prototype.hasFlag = function(flag) { - return core.control.hasFlag(flag); -} - -////// 删除某个自定义变量或flag ////// -core.prototype.removeFlag = function(flag) { - core.control.removeFlag(flag); -} - -////// 执行下一个自定义事件 ////// -core.prototype.doAction = function() { - core.events.doAction(); -} - -////// 往当前事件列表之前插入一系列事件 ////// -core.prototype.insertAction = function (list, x, y, callback) { - core.events.insertAction(list, x, y, callback); -} - -////// 获得一个公共事件内容 ////// -core.prototype.getCommonEvent = function (name) { - return core.events.getCommonEvent(name); -} - -////// 锁定状态栏,常常用于事件处理 ////// -core.prototype.lockControl = function () { - core.control.lockControl(); -} - -////// 解锁状态栏 ////// -core.prototype.unLockControl = function () { - core.control.unLockControl(); -} - -////// 判断某对象是否不为undefined也不会null ////// -core.prototype.isset = function (val) { - return core.utils.isset(val); -} - -////// 获得子数组 ////// -core.prototype.subarray = function (a, b) { - return core.utils.subarray(a, b); -} - -core.prototype.same = function (a, b) { - return core.utils.same(a, b); -} - -core.prototype.clamp = function (x, a, b) { - return core.utils.clamp(x, a, b); -} - -core.prototype.getCookie = function (name) { - return core.utils.getCookie(name); -} - -////// Base64加密 ////// -core.prototype.encodeBase64 = function (str) { - return core.utils.encodeBase64(str); -} - -////// Base64解密 ////// -core.prototype.decodeBase64 = function (str) { - return core.utils.decodeBase64(str); -} - -////// 生成随机数(seed方法) ////// -core.prototype.rand = function (num) { - return core.utils.rand(num); -} - -////// 生成随机数(录像方法) ////// -core.prototype.rand2 = function (num) { - return core.utils.rand2(num); -} - -////// 读取一个本地文件内容 ////// -core.prototype.readFile = function (success, error, readType) { - core.utils.readFile(success, error, readType); -} - -////// 读取本地文件完毕 ////// -core.prototype.readFileContent = function (content) { - core.utils.readFileContent(content); -} - -////// 下载文件到本地 ////// -core.prototype.download = function (filename, content) { - core.utils.download(filename, content); -} - -////// 复制一段内容到剪切板 ////// -core.prototype.copy = function (data) { - return core.utils.copy(data); -} - -////// 播放背景音乐 ////// -core.prototype.playBgm = function (bgm) { - core.control.playBgm(bgm); -} - -////// 暂停背景音乐的播放 ////// -core.prototype.pauseBgm = function () { - core.control.pauseBgm(); -} - -////// 恢复背景音乐的播放 ////// -core.prototype.resumeBgm = function () { - core.control.resumeBgm(); -} - -////// 更改背景音乐的状态 ////// -core.prototype.triggerBgm = function () { - core.control.triggerBgm(); -} - -////// 预加载一个背景音乐 ////// -core.prototype.loadBgm = function (bgm) { - core.loader.loadBgm(bgm); -} - -////// 手动释放一个背景音乐的缓存 ////// -core.prototype.freeBgm = function (bgm) { - core.loader.freeBgm(bgm); -} - -////// 播放音频 ////// -core.prototype.playSound = function (sound) { - core.control.playSound(sound); -} - -////// 停止所有音效 ////// -core.prototype.stopSound = function () { - core.control.stopSound(); -} - -////// 动画显示某对象 ////// -core.prototype.show = function (obj, speed, callback) { - core.utils.show(obj, speed, callback); -} - -////// 动画使某对象消失 ////// -core.prototype.hide = function (obj, speed, callback) { - core.utils.hide(obj, speed, callback); -} - -////// 清空状态栏 ////// -core.prototype.clearStatusBar = function() { - core.control.clearStatusBar(); -} - -////// 更新状态栏 ////// -core.prototype.updateStatusBar = function () { - core.control.updateStatusBar(); -} - -////// 绘制状态栏 ////// -core.prototype.drawStatusBar = function () { - core.ui.drawStatusBar(); -} - -////// 屏幕分辨率改变后重新自适应 ////// -core.prototype.resize = function(clientWidth, clientHeight) { - core.control.resize(clientWidth, clientHeight); -} - -////// 渲染DOM ////// -core.prototype.domRenderer = function(){ - core.control.domRenderer(); +core.prototype._forwardFuncs = function () { + var list = {}; + for (var i = 0; i < main.loadList.length; ++i) { + var name = main.loadList[i]; + if (name == 'core') continue; + for (var funcname in core[name]) { + if (funcname.charAt(0) != "_" && core[name][funcname] instanceof Function) { + if (list[funcname]) { + main.log("Error forward: "+name+"."+funcname); + } + else { + list[funcname] = name; + } + } + } + } + for (var funcname in list) { + this._forwardFunc(list[funcname], funcname); + } +} + +core.prototype._forwardFunc = function (name, funcname) { + if (core[funcname]) { + main.log("Error in forwarding "+funcname+" from "+name+"!"); + return; + } + var parameterInfo = /^\s*function\s*[\w_$]*\(([\w_,$\s]*)\)\s*\{/.exec(core[name][funcname].toString()); + var parameters = (parameterInfo==null?"":parameterInfo[1]).replace(/\s*/g, '').replace(/,/g, ', '); + // core[funcname] = new Function(parameters, "return core."+name+"."+funcname+"("+parameters+");"); + eval("core."+funcname+" = function ("+parameters+") {\n\treturn core."+name+"."+funcname+"("+parameters+");\n}"); } /** diff --git a/libs/data.js b/libs/data.js index 64c3864c..b11f91cf 100644 --- a/libs/data.js +++ b/libs/data.js @@ -1,10 +1,10 @@ "use strict"; function data() { - this.init(); + this._init(); } -data.prototype.init = function() { +data.prototype._init = function() { this.firstData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData; this.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values; this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags; diff --git a/libs/enemys.js b/libs/enemys.js index 6049ce82..f0fc4c7a 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -1,11 +1,11 @@ "use strict"; function enemys() { - this.init(); + this._init(); } ////// 初始化 ////// -enemys.prototype.init = function () { +enemys.prototype._init = function () { this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80; this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys; if (main.mode=='play') { @@ -16,17 +16,12 @@ enemys.prototype.init = function () { } } -////// 获得一个或所有怪物数据 ////// -enemys.prototype.getEnemys = function (enemyId) { - if (!core.isset(enemyId)) { - return this.enemys; - } - return this.enemys[enemyId]; +enemys.prototype.getEnemys = function () { + return core.clone(this.enemys); } ////// 判断是否含有某特殊属性 ////// enemys.prototype.hasSpecial = function (special, test) { - if (!core.isset(special)) return false; if (special instanceof Array) { @@ -52,9 +47,9 @@ enemys.prototype.getSpecials = function () { return this.enemydata.getSpecials(); } -enemys.prototype.calContent = function (enemy, content) { - if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; +enemys.prototype._calSpecialContent = function (enemy, content) { if (typeof content == 'string') return content; + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (content instanceof Function) { return content(enemy); } @@ -63,8 +58,6 @@ enemys.prototype.calContent = function (enemy, content) { ////// 获得所有特殊属性的名称 ////// enemys.prototype.getSpecialText = function (enemy) { - // 移动到了脚本编辑 - getSpecials中 - if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (!core.isset(enemy)) return []; var special = enemy.special; @@ -74,7 +67,7 @@ enemys.prototype.getSpecialText = function (enemy) { if (core.isset(specials)) { for (var i=0;i=1;t--) { - var nextAtk = Math.ceil(mon_hp/t) + mon_def; - // 装备提升比例的计算临界 - nextAtk = Math.ceil(nextAtk / core.getFlag('equip_atk_buff', 1)); - if (nextAtk<=hero_atk) break; - if (nextAtk!=pre) { - var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); - if (nextInfo==null || (typeof nextInfo == 'number')) break; - list.push([nextAtk-hero_atk,Math.floor(info.damage-nextInfo.damage)]); - if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; - pre = nextAtk; - } - if (list.length>=number) - break; - } - } - else { // 暴力for循环法 - - // V2.5.3以后,大数据改为二分法进行计算 - var LOOP_MAX_VALUE = 1; - pre = info.damage; - if (hero_atk <= LOOP_MAX_VALUE) { // 循环法 - for (var atk=hero_atk+1;atk<=mon_hp+mon_def;atk++) { - var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, atk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); - if (nextInfo==null || (typeof nextInfo == 'number')) break; - if (pre>nextInfo.damage) { - pre = nextInfo.damage; - list.push([atk-hero_atk, info.damage-nextInfo.damage]); - if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; - if (list.length>=number) break; - } - } - } - else { // 二分法算临界 - var calNext = function (currAtk, maxAtk) { - var start = Math.floor(currAtk), end = Math.floor(maxAtk); - if (start>end) return null; - - while (startnextInfo.damage) end = mid; - else start = mid+1; - } - var nextInfo = core.enemys.getDamageInfo(enemy, core.status.hero.hp, start, core.status.hero.def, core.status.hero.mdef, x, y, floorId); - return nextInfo==null||(typeof nextInfo == 'number')||nextInfo.damage>=pre?null:[start,nextInfo.damage]; - } - var currAtk = hero_atk; - while (true) { - var next = calNext(currAtk+1, mon_hp+mon_def, pre); - if (next == null) break; - currAtk = next[0]; - pre = next[1]; - list.push([currAtk-hero_atk, info.damage-pre]); - if (pre<=0 && !core.flags.enableNegativeDamage) break; - if (list.length>=number) break; - } +enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, floorId) { + var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage; + var list = []; + for (var atk=hero_atk+1;atk<=mon_hp+mon_def;atk++) { + var nextInfo = this.getDamageInfo(enemy, {"atk": atk}, x, y, floorId); + if (nextInfo==null || (typeof nextInfo == 'number')) break; + if (pre>nextInfo.damage) { + pre = nextInfo.damage; + list.push([atk-hero_atk, info.damage-nextInfo.damage]); + if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; + if (list.length>=number) break; } } if (list.length==0) list.push([0,0]); return list; } +enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, x, y, floorId) { + var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage; + var list = []; + var calNext = function (currAtk, maxAtk) { + var start = Math.floor(currAtk), end = Math.floor(maxAtk); + if (start>end) return null; + + while (startnextInfo.damage) end = mid; + else start = mid+1; + } + var nextInfo = core.enemys.getDamageInfo(enemy, {"atk": start}, x, y, floorId); + return nextInfo==null||(typeof nextInfo == 'number')||nextInfo.damage>=pre?null:[start,nextInfo.damage]; + } + var currAtk = hero_atk; + while (true) { + var next = calNext(currAtk+1, mon_hp+mon_def, pre); + if (next == null) break; + currAtk = next[0]; + pre = next[1]; + list.push([currAtk-hero_atk, info.damage-pre]); + if (pre<=0 && !core.flags.enableNegativeDamage) break; + if (list.length>=number) break; + } + if (list.length==0) list.push([0,0]); + return list; +} + +enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, floorId) { + var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, turn = info.turn; + var list = [], pre = null; + for (var t = turn-1;t>=1;t--) { + var nextAtk = Math.ceil(mon_hp/t) + mon_def; + // 装备提升比例的计算临界 + nextAtk = Math.ceil(nextAtk / core.getFlag('__atk_buff__', 1)); + if (nextAtk<=hero_atk) break; + if (nextAtk!=pre) { + var nextInfo = this.getDamageInfo(enemy, {"atk": nextAtk}, x, y, floorId); + if (nextInfo==null || (typeof nextInfo == 'number')) break; + list.push([nextAtk-hero_atk,Math.floor(info.damage-nextInfo.damage)]); + if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; + pre = nextAtk; + } + if (list.length>=number) + break; + } + if (list.length==0) list.push([0,0]); + return list; +} + +////// 接下来N个临界值和临界减伤计算 ////// +enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; + number = number||1; + + if (this.hasSpecial(enemy.special, 10)) return []; // 模仿怪物临界 + var info = this.getDamageInfo(enemy, null, x, y, floorId); + if (info == null || this.hasSpecial(enemy.special, 3)) { // 未破防,或是坚固怪 + info = this.getEnemyInfo(enemy, null, x, y, floorId); + if (core.status.hero.atk<=info.def) { + return [[info.def+1-core.status.hero.atk,'?']]; + } + return []; + } + + // getDamageInfo直接返回数字;0伤且无负伤 + if (typeof info == 'number' || (info.damage<=0 && !core.flags.enableNegativeDamage)) { + return [[0,0]]; + } + + if (core.flags.useLoop) { + var LOOP_MAX_VALUE = 1; + if (core.status.hero.atk <= LOOP_MAX_VALUE) { + return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId); + } + else { + return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId); + } + } + else { + return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId); + } +} + ////// N防减伤计算 ////// enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; k = k || 1; - var nowDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); - var nextDamage = this.calDamage(enemy, core.status.hero.hp, core.status.hero.atk, core.status.hero.def + k, core.status.hero.mdef, x, y, floorId); + var nowDamage = this.calDamage(enemy, null, x, y, floorId); + var nextDamage = this.calDamage(enemy, {"def": core.status.hero.def + k}, x, y, floorId); if (nowDamage == null || nextDamage ==null) return "???"; return nowDamage - nextDamage; } -enemys.prototype.getEnemyInfo = function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { +enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - return this.enemydata.getEnemyInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) + return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId) } ////// 获得战斗伤害信息(实际伤害计算函数) ////// -enemys.prototype.getDamageInfo = function(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { +enemys.prototype.getDamageInfo = function(enemy, hero, x, y, floorId) { // 移动到了脚本编辑 - getDamageInfo中 if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - return this.enemydata.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId); + return this.enemydata.getDamageInfo(enemy, hero, x, y, floorId); } ////// 获得在某个勇士属性下怪物伤害 ////// -enemys.prototype.calDamage = function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { +enemys.prototype.calDamage = function (enemy, hero, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - var info = this.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId); + var info = this.getDamageInfo(enemy, hero, x, y, floorId); if (info == null) return null; if (typeof info == 'number') return info; return info.damage; @@ -308,57 +299,56 @@ enemys.prototype.updateEnemys = function () { ////// 获得当前楼层的怪物列表 ////// enemys.prototype.getCurrentEnemys = function (floorId) { floorId=floorId||core.status.floorId; - var enemys = []; - var used = {}; + var enemys = [], used = {}; var mapBlocks = core.status.maps[floorId].blocks; for (var b = 0; b < mapBlocks.length; b++) { if (core.isset(mapBlocks[b].event) && !mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy')==0) { - var enemyId = mapBlocks[b].event.id; - - var enemy = core.material.enemys[enemyId]; - if (!core.isset(enemy)) continue; - - // 检查displayIdInBook - var tmpId = enemy.displayIdInBook; - if (core.isset(core.material.enemys[tmpId])) { - enemyId = tmpId; - enemy = core.material.enemys[tmpId]; - } - if (core.isset(used[enemyId])) continue; - - var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def; - var hero_atk = core.status.hero.atk, hero_def = core.status.hero.def, hero_mdef = core.status.hero.mdef; - - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - - var enemyInfo = this.getEnemyInfo(enemy, core.status.hero.hp, hero_atk, hero_def, hero_mdef, null, null, floorId); - - var specialText = core.enemys.getSpecialText(enemyId); - if (specialText.length>=3) specialText = "多属性..."; - else specialText = specialText.join(" "); - - var critical = this.nextCriticals(enemyId, 1, null, null, floorId); - if (critical.length>0) critical=critical[0]; - - var e = core.clone(enemy); - for (var x in enemyInfo) { - e[x] = enemyInfo[x]; - } - e.id = enemyId; - e.specialText = specialText; - e.damage = this.getDamage(enemyId, null, null, floorId); - e.critical = critical[0]; - e.criticalDamage = critical[1]; - e.defDamage = this.getDefDamage(enemyId,1,null,null,floorId); - enemys.push(e); - used[enemyId] = true; + this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId); } } + return this._getCurrentEnemys_sort(enemys); +} - enemys.sort(function (a, b) { +enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) { + var enemy = core.material.enemys[enemyId]; + if (!core.isset(enemy)) return null; + + // 检查displayIdInBook + var tmpId = enemy.displayIdInBook; + if (core.isset(core.material.enemys[tmpId])) { + enemy = core.material.enemys[tmpId]; + } + return enemy; +} + +enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, floorId) { + var enemy = this._getCurrentEnemys_getEnemy(enemyId); + if (enemy==null || used[enemy.id]) return; + + var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId); + var specialText = core.enemys.getSpecialText(enemy); + if (specialText.length>=3) specialText = "多属性..."; + else specialText = specialText.join(" "); + + var critical = this.nextCriticals(enemy, 1, null, null, floorId); + if (critical.length>0) critical=critical[0]; + + var e = core.clone(enemy); + for (var x in enemyInfo) { + e[x] = enemyInfo[x]; + } + e.specialText = specialText; + e.damage = this.getDamage(enemy, null, null, floorId); + e.critical = critical[0]; + e.criticalDamage = critical[1]; + e.defDamage = this.getDefDamage(enemy,1,null,null,floorId); + enemys.push(e); + used[enemy.id] = true; +} + +enemys.prototype._getCurrentEnemys_sort = function (enemys) { + return enemys.sort(function (a, b) { if (a.damage == b.damage) { return a.money - b.money; } @@ -370,5 +360,4 @@ enemys.prototype.getCurrentEnemys = function (floorId) { } return a.damage - b.damage; }); - return enemys; } \ No newline at end of file diff --git a/libs/events.js b/libs/events.js index d9be042a..5ed17252 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1,11 +1,11 @@ "use strict"; function events() { - this.init(); + this._init(); } ////// 初始化 ////// -events.prototype.init = function () { +events.prototype._init = function () { this.eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events; this.commonEvent = events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent; this.events = { @@ -135,21 +135,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { var real_start = function () { core.insertAction(core.clone(core.firstData.startText), null, null, function() { - if (!core.flags.startUsingCanvas && !core.isReplaying() && core.flags.showBattleAnimateConfirm) { // 是否提供“开启战斗动画”的选择项 - core.status.event.selection = core.flags.battleAnimate ? 0 : 1; - core.ui.drawConfirmBox("你想开启战斗动画吗?\n之后可以在菜单栏中开启或关闭。\n(强烈建议新手开启此项)", function () { - core.flags.battleAnimate = true; - core.setLocalStorage('battleAnimate', true); - post_start(); - }, function () { - core.flags.battleAnimate = false; - core.setLocalStorage('battleAnimate', false); - post_start(); - }); - } - else { - post_start(); - } + post_start(); }); } @@ -976,8 +962,7 @@ events.prototype.doAction = function() { this.doAction(); break case "loadBgm": - if (core.platform.isPC) - core.loadBgm(data.name); + core.loadBgm(data.name); this.doAction(); break; case "freeBgm": @@ -1505,16 +1490,27 @@ events.prototype.battle = function (id, x, y, force, callback) { if (!core.isset(core.status.event.id)) // 自动存档 core.autosave(true); - if (core.flags.battleAnimate&&!core.isReplaying()) { - core.waitHeroToStop(function() { - core.ui.drawBattleAnimate(id, function() { - core.events.afterBattle(id, x, y, callback); - }); - }); - } - else { - core.events.afterBattle(id, x, y, callback); + // ------ 支援技能 ------// + if (core.isset(x) && core.isset(y)) { + var index = x + "," + y, cache = (core.status.checkBlock.cache || {})[index] || {}, + guards = cache.guards || []; + if (guards.length>0) { + core.setFlag("__guards__"+x+"_"+y, guards); + var actions = []; + guards.forEach(function (g) { + core.push(actions, {"type": "jump", "from": [g[0],g[1]], "to": [x, y], + "time": 300, "keep": false, "async": true}); + }) + core.push(actions, [ + {"type": "waitAsync"}, + {"type": "trigger", "loc": [x,y]} + ]); + core.insertAction(actions); + return; + } } + + core.events.afterBattle(id, x, y, callback); } ////// 触发(x,y)点的事件 ////// @@ -1983,6 +1979,64 @@ events.prototype.openShop = function(shopId, needVisited) { core.ui.drawChoices(content, choices); } +events.prototype._useShop = function (shop, index) { + // 检查能否使用快捷商店 + var reason = core.events.canUseQuickShop(shop.id); + if (core.isset(reason)) { + core.drawText(reason); + return false; + } + if (!shop.visited) { + if (shop.times==0) core.drawTip("该商店尚未开启"); + else core.drawTip("该商店已失效"); + return false; + } + + var money = core.getStatus('money'), experience = core.getStatus('experience'); + var times = shop.times, need = core.calValue(shop.need, null, null, times); + var use = shop.use; + var use_text = use=='money'?"金币":"经验"; + + var choice = shop.choices[index]; + if (core.isset(choice.need)) + need = core.calValue(choice.need, null, null, times); + + if (need > eval(use)) { + core.drawTip("你的"+use_text+"不足"); + return false; + } + + core.status.event.selection = index; + core.status.event.data.actions.push(index); + + eval(use+'-='+need); + core.setStatus('money', money); + core.setStatus('experience', experience); + + // 更新属性 + choice.effect.split(";").forEach(function (t) { + core.doEffect(t, need, times); + }); + core.updateStatusBar(); + shop.times++; + if (shop.commonTimes) + core.setFlag('commonTimes', shop.times); + core.events.openShop(shop.id); + return true; +} + +events.prototype._exitShop = function () { + 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.event.data.actions = []; + core.status.boxAnimateObjs = []; + if (core.status.event.data.fromList) + core.ui.drawQuickShop(); + else + core.ui.closePanel(); +} + ////// 禁用一个全局商店 ////// events.prototype.disableQuickShop = function (shopId) { core.status.shops[shopId].visited = false; @@ -2033,7 +2087,7 @@ events.prototype.checkLvUp = function () { } ////// 尝试使用道具 ////// -events.prototype.useItem = function(itemId) { +events.prototype.tryUseItem = function(itemId) { core.ui.closePanel(); if (itemId=='book') { diff --git a/libs/icons.js b/libs/icons.js index 41855dcd..db33f828 100644 --- a/libs/icons.js +++ b/libs/icons.js @@ -1,10 +1,10 @@ "use strict"; function icons() { - this.init(); + this._init(); } -icons.prototype.init = function () { +icons.prototype._init = function () { this.icons = icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1; //delete(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1); @@ -13,7 +13,29 @@ icons.prototype.init = function () { } icons.prototype.getIcons = function () { - return this.icons; + return core.clone(this.icons); +} + +////// 根据道具ID获得其cls ////// +icons.prototype.getClsFromId = function (id) { + for (var cls in core.material.icons) { + if (cls != 'hero' && id in core.material.icons[cls]) + return cls; + } + return null; +} + +icons.prototype._getAnimateFrames = function (cls, useOriginValue) { + if (cls=='enemys' || cls=='npcs') { + return 2; + } + if (cls == 'animates' || cls == 'enemy48') { + return 4; + } + if (cls == 'npc48') { + return useOriginValue? 4 : 1; + } + return 1; } ////// 根据图块数字或ID获得所在的tileset和坐标信息 ////// diff --git a/libs/items.js b/libs/items.js index efd04889..1834cdb3 100644 --- a/libs/items.js +++ b/libs/items.js @@ -1,26 +1,24 @@ "use strict"; function items() { - this.init(); + this._init(); } ////// 初始化 ////// -items.prototype.init = function () { +items.prototype._init = function () { this.items = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.items; this.itemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.itemEffect; this.itemEffectTip = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.itemEffectTip; this.useItemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.useItemEffect; this.canUseItemEffect = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canUseItemEffect; - if (!core.isset(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip)) + if (!items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip) items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip = {}; - this.canEquip = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip; - - //delete(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a); + this.equipCondition = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a.canEquip; } ////// 获得所有道具 ////// items.prototype.getItems = function () { - return this.items; + return core.clone(this.items); } ////// “即捡即用类”道具的使用效果 ////// @@ -63,39 +61,42 @@ items.prototype.getItemEffectTip = function(itemId) { return ""; } -////// 使用道具 ////// -items.prototype.useItem = function (itemId, noRoute, callback) { - if (!this.canUseItem(itemId)) { - if (core.isset(callback)) callback(); - return; - } - var itemCls = core.material.items[itemId].cls; - +items.prototype._useItemEffect = function (itemId) { if (itemId in this.useItemEffect) { try { + var ratio = parseInt(core.status.thisMap.item_ratio) || 1; eval(this.useItemEffect[itemId]); } catch (e) { main.log(e); } } - // 记录路线 - if (!noRoute) { - core.status.route.push("item:"+itemId); - } +} +items.prototype._afterUseItem = function (itemId) { // 道具使用完毕:删除 + var itemCls = core.material.items[itemId].cls; if (itemCls=='tools') core.status.hero.items[itemCls][itemId]--; if (core.status.hero.items[itemCls][itemId]<=0) delete core.status.hero.items[itemCls][itemId]; + core.status.event.ui = null; core.updateStatusBar(); - if (!core.isset(core.status.event.id)) { - core.status.event.data = null; - core.status.event.ui = null; - } +} +////// 使用道具 ////// +items.prototype.useItem = function (itemId, noRoute, callback) { + if (!this.canUseItem(itemId)) { + if (core.isset(callback)) callback(); + return; + } + // 执行道具效果 + this._useItemEffect(itemId); + // 执行完毕 + this._afterUseItem(itemId); + // 记录路线 + if (!noRoute) core.status.route.push("item:"+itemId); if (core.isset(callback)) callback(); } @@ -113,7 +114,7 @@ items.prototype.canUseItem = function (itemId) { main.log(e); } } - if (!able) core.status.event.data = null; + if (!able) core.status.event.ui = null; return able; } @@ -171,7 +172,7 @@ items.prototype.setItem = function (itemId, itemNum) { ////// 删除某个物品 ////// items.prototype.removeItem = function (itemId, itemNum) { if (!core.isset(core.status.hero)) return null; - itemNum = itemNum || 1; + if (!core.isset(itemNum)) itemNum = 1; if (!core.hasItem(itemId)) return false; var itemCls = core.material.items[itemId].cls; core.status.hero.items[itemCls][itemId]-=itemNum; @@ -186,7 +187,7 @@ items.prototype.removeItem = function (itemId, itemNum) { ////// 增加某个物品的个数 ////// items.prototype.addItem = function (itemId, itemNum) { if (!core.isset(core.status.hero)) return null; - itemNum = itemNum || 1; + if (!core.isset(itemNum)) itemNum = 1; var itemData = core.material.items[itemId]; var itemCls = itemData.cls; if (itemCls == 'items') return; @@ -208,6 +209,15 @@ items.prototype.addItem = function (itemId, itemNum) { core.updateStatusBar(); } +// ---------- 装备相关 ------------ // + +items.prototype.getEquipTypeById = function (equipId) { + var type = core.material.items[equipId].equip.type; + if (typeof type == 'string') + type = this.getEquipTypeByName(type); + return type; +} + items.prototype.getEquipTypeByName = function (name) { var names = core.status.globalAttribute.equipName; for (var i = 0; i < names.length; ++i) { @@ -218,125 +228,116 @@ items.prototype.getEquipTypeByName = function (name) { return -1; } -////// 换上 ////// -items.prototype.loadEquip = function (equipId, callback) { - if (!core.isset(core.status.hero)) return null; - - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - - var loadEquip = core.material.items[equipId]||{}; - if (!core.isset(loadEquip.equip)) { - if (core.isset(callback)) callback(); - return; +// 当前能否撞上某装备 +items.prototype.canEquip = function (equipId, hint) { + // 装备是否合法 + var equip = core.material.items[equipId]||{}; + if (!core.isset(equip.equip)) { + if (hint) core.drawTip("不合法的装备!"); + return false; } - var can = this.canEquip[equipId]; - if (core.isset(can)) { + // 是否拥有该装备 + if (!core.hasItem(equipId) && !core.hasEquip(equipId)) { + if (hint) core.drawTip("你当前没有"+equip.name+",无法换装"); + return false; + } + + // 可装备条件 + var condition = this.equipCondition[equipId]; + if (core.isset(condition) && condition.length>0) { try { - if (!eval(can)) { - core.drawTip("当前不可换上"+loadEquip.name); - if (core.isset(callback)) callback(); - return; + if (!eval(condition)) { + if (hint) core.drawTip("当前不可换上"+equip.name); + return false; } } catch (e) { - main.log(e); + console.log(e); + return false; } } + return true; +} - core.playSound('equip.mp3'); +////// 实际换装的效果 ////// +items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentage) { + // 比较能力值 + var result = core.compareEquipment(equipId, unloadEquipId); - var loadEquipType = loadEquip.equip.type; - - // ------ 判定多重装备 ------ - if (typeof loadEquipType === 'string') { - loadEquipType = this.getEquipTypeByName(loadEquipType); - if (loadEquipType < 0) { - core.drawTip("当前没有"+loadEquip.equip.type+"的空位!"); - return; - } + if (isPercentage) { + for (var v in result) + core.addFlag('__'+v+'_buff__', result[v]/100); } + else { + for (var v in result) + core.status.hero[v] += result[v]; + } +} - var unloadEquipId = core.status.hero.equipment[loadEquipType]; - var unloadEquip = core.material.items[unloadEquipId] || {}; +items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { + var loadEquip = core.material.items[loadId] || {}, unloadEquip = core.material.items[unloadId] || {}; + if (!core.isset(loadEquip.equip)) loadEquip.equip = {}; + if (!core.isset(unloadEquip.equip)) unloadEquip.equip = {}; - // ------ 如果当前装备和目标装备的模式不同(一个百分比一个数值),则需要先脱再穿 ------ // - if (core.isset(unloadEquip.equip) && (unloadEquip.equip.percentage||false) != (loadEquip.equip.percentage||false)) { - this.unloadEquip(loadEquipType); - this.loadEquip(equipId); + var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage; + + if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) { + this.unloadEquip(type); + this.loadEquip(loadId); if (core.isset(callback)) callback(); return; } - // 下面保证了两者的模式是相同的 - // 比较能力值 - var result = core.compareEquipment(equipId,unloadEquipId); + // --- 音效 + core.playSound('equip.mp3'); - if (loadEquip.equip.percentage) { - core.setFlag('equip_atk_buff', core.getFlag('equip_atk_buff',1)+result.atk/100); - core.setFlag('equip_def_buff', core.getFlag('equip_def_buff',1)+result.def/100); - core.setFlag('equip_mdef_buff', core.getFlag('equip_mdef_buff',1)+result.mdef/100); - } - else { - core.status.hero.atk += result.atk; - core.status.hero.def += result.def; - core.status.hero.mdef += result.mdef; - } + // --- 实际换装 + this._loadEquipEffect(loadId, unloadId, loadPercentage==null?unloadPercentage:loadPercentage); - // 更新装备状态 - core.status.hero.equipment[loadEquipType] = equipId; - core.updateStatusBar(); + // --- 加减 + if (loadId) core.removeItem(loadId); + if (unloadId) core.addItem(unloadId); + core.status.hero.equipment[type] = loadId||null; - // 装备更换完毕:删除换上的装备 - core.removeItem(equipId); - - // 装备更换完毕:增加卸下的装备 - if (core.isset(unloadEquipId)) - core.addItem(unloadEquipId, 1); - - core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[equipId]); + // --- 提示 + if (loadId) core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[loadId]); + else if (unloadId) core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadId]); if (core.isset(callback)) callback(); } +////// 换上 ////// +items.prototype.loadEquip = function (equipId, callback) { + if (!core.isset(core.status.hero)) return null; + if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; + if (!this.canEquip(equipId, true)) { + if (core.isset(callback)) callback(); + return; + } + + var loadEquip = core.material.items[equipId] || {}; + var type = this.getEquipTypeById(equipId); + if (type < 0) { + core.drawTip("当前没有"+loadEquip.equip.type+"的空位!"); + return; + } + + this._realLoadEquip(type, equipId, core.status.hero.equipment[type], callback); +} + ////// 卸下 ////// items.prototype.unloadEquip = function (equipType, callback) { if (!core.isset(core.status.hero)) return null; - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - core.playSound('equip.mp3'); - var unloadEquipId = core.status.hero.equipment[equipType]; if (!core.isset(unloadEquipId)) { if (core.isset(callback)) callback(); return; } - var unloadEquip = core.material.items[unloadEquipId] || {}; - // 处理能力值改变 - if (unloadEquip.equip.percentage) { - core.setFlag('equip_atk_buff', core.getFlag('equip_atk_buff',1)-(unloadEquip.equip.atk||0)/100); - core.setFlag('equip_def_buff', core.getFlag('equip_def_buff',1)-(unloadEquip.equip.def||0)/100); - core.setFlag('equip_mdef_buff', core.getFlag('equip_mdef_buff',1)-(unloadEquip.equip.mdef||0)/100); - } - else { - core.status.hero.atk -= unloadEquip.equip.atk || 0; - core.status.hero.def -= unloadEquip.equip.def || 0; - core.status.hero.mdef -= unloadEquip.equip.mdef || 0; - } - - // 更新装备状态 - core.status.hero.equipment[equipType] = null; - - core.updateStatusBar(); - - // 装备更换完毕:增加卸下的装备 - core.addItem(unloadEquipId, 1); - - core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadEquipId]); - - if (core.isset(callback)) callback(); + this._realLoadEquip(equipType, null, unloadEquipId, callback); } items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) { @@ -376,20 +377,8 @@ items.prototype.quickLoadEquip = function (index) { var equipSize = core.status.globalAttribute.equipName.length; for (var i=0;i 32*32*3000) { - console.warn("警告!"+imgName+"上的图块素材个数大于3000!"); - } - } - - core.loader.loadAnimates(); - core.loader.loadMusic(); - if (core.isset(callback)) - callback(); - }) + core.loader._loadMaterialImages(function () { + core.loader._loadExtraImages(function () { + core.loader._loadAutotiles(function () { + core.loader._loadTilesets(callback); }) }) - }) + }); } -loader.prototype.loadIcons = function () { - +loader.prototype._loadIcons = function () { this.loadImage("icons.png", function (id, image) { var images = core.cropImage(image); for (var key in core.statusBar.icons) { @@ -91,6 +49,55 @@ loader.prototype.loadIcons = function () { }); } +loader.prototype._loadMaterialImages = function (callback) { + this.loadImages(core.materials, core.material.images, callback); +} + +loader.prototype._loadExtraImages = function (callback) { + core.material.images.images = {}; + + var images = core.clone(core.images); + if (images.indexOf("hero.png")<0) + images.push("hero.png"); + + this.loadImages(images, core.material.images.images, callback); +} + +loader.prototype._loadAutotiles = function (callback) { + core.material.images.autotile = {}; + var keys = Object.keys(core.material.icons.autotile); + var autotiles = {}; + this.loadImages(keys, autotiles, function () { + keys.forEach(function (v) { + core.material.images.autotile[v] = autotiles[v]; + }); + + setTimeout(function () { + core.maps.makeAutotileEdges(); + }); + + callback(); + }); +} + +loader.prototype._loadTilesets = function (callback) { + core.material.images.tilesets = {}; + if (!core.isset(core.tilesets)) core.tilesets = []; + core.loader.loadImages(core.clone(core.tilesets), core.material.images.tilesets, function () { + // 检查宽高是32倍数,如果出错在控制台报错 + for (var imgName in core.material.images.tilesets) { + var img = core.material.images.tilesets[imgName]; + if (img.width%32!=0 || img.height%32!=0) { + console.warn("警告!"+imgName+"的宽或高不是32的倍数!"); + } + if (img.width * img.height > 32*32*3000) { + console.warn("警告!"+imgName+"上的图块素材个数大于3000!"); + } + } + callback(); + }); +} + loader.prototype.loadImages = function (names, toSave, callback) { if (!core.isset(names) || names.length==0) { if (core.isset(callback)) callback(); @@ -126,7 +133,7 @@ loader.prototype.loadImage = function (imgName, callback) { } } -loader.prototype.loadAnimates = function () { +loader.prototype._loadAnimates = function () { core.animates.forEach(function (t) { core.http('GET', 'project/animates/' + t + ".animate", null, function (content) { try { @@ -182,79 +189,14 @@ loader.prototype.loadAnimates = function () { } ////// 加载音频 ////// -loader.prototype.loadMusic = function () { - +loader.prototype._loadMusic = function () { core.bgms.forEach(function (t) { core.loader.loadOneMusic(t); - /* - // 判断是不是mid - if (/^.*\.mid$/i.test(t)) { - - if (core.musicStatus.audioContext!=null) { - core.material.bgms[t] = 'loading'; - - core.http('GET', 'project/sounds/'+t, null, function (data) { - try { - var ff = []; - var mx = data.length; - for (var z = 0; z < mx; z++) - ff[z] = String.fromCharCode(data.charCodeAt(z) & 255); - var shouldStart = core.material.bgms[t] == 'starting'; - core.material.bgms[t] = AudioPlayer(core.musicStatus.audioContext, Replayer(MidiFile(ff.join("")), Synth(44100)), true); - - if (shouldStart) - core.playBgm(t); - } - catch (e) { - main.log(e); - core.material.bgms[t] = null; - } - }, function (e) { - main.log(e); - core.material.bgms[t] = null; - }, "text/plain; charset=x-user-defined") - - } - else { - core.material.bgms[t] = null; - } - } - else { - core.loader.loadOneMusic(t); - } - */ }); core.sounds.forEach(function (t) { - - if (core.musicStatus.audioContext != null) { - - core.http('GET', 'project/sounds/'+t, null, function (data) { - try { - core.musicStatus.audioContext.decodeAudioData(data, function (buffer) { - core.material.sounds[t] = buffer; - }, function (e) { - main.log(e); - core.material.sounds[t] = null; - }) - } - catch (ee) { - main.log(ee); - core.material.sounds[t] = null; - } - }, function (e) { - main.log(e); - core.material.sounds[t] = null; - }, null, 'arraybuffer'); - } - else { - var music = new Audio(); - music.src = 'project/sounds/'+t; - core.material.sounds[t] = music; - } - + core.loader.loadOneSound(t); }); - // 直接开始播放 core.playBgm(main.startBgm); } @@ -268,6 +210,33 @@ loader.prototype.loadOneMusic = function (name) { core.material.bgms[name] = music; } +loader.prototype.loadOneSound = function (name) { + if (core.musicStatus.audioContext != null) { + core.http('GET', 'project/sounds/'+name, null, function (data) { + try { + core.musicStatus.audioContext.decodeAudioData(data, function (buffer) { + core.material.sounds[name] = buffer; + }, function (e) { + main.log(e); + core.material.sounds[name] = null; + }) + } + catch (e) { + main.log(e); + core.material.sounds[name] = null; + } + }, function (e) { + main.log(e); + core.material.sounds[name] = null; + }, null, 'arraybuffer'); + } + else { + var music = new Audio(); + music.src = 'project/sounds/'+name; + core.material.sounds[name] = music; + } +} + loader.prototype.freeBgm = function (name) { if (!core.isset(core.material.bgms[name])) return; // 从cachedBgms中删除 @@ -285,6 +254,11 @@ loader.prototype.freeBgm = function (name) { }, 3000); } +loader.prototype._preloadBgm = function (bgm) { + bgm.volume = 0; + bgm.play(); +} + loader.prototype.loadBgm = function (name) { if (!core.isset(core.material.bgms[name])) return; // 如果没开启音乐,则不预加载 @@ -296,7 +270,8 @@ loader.prototype.loadBgm = function (name) { } else { // 预加载BGM - core.material.bgms[name].load(); + this._preloadBgm(core.material.bgms[name]); + // core.material.bgms[name].load(); // 清理尾巴 if (core.musicStatus.cachedBgms.length == core.musicStatus.cachedBgmCount) { this.freeBgm(core.musicStatus.cachedBgms.pop()); diff --git a/libs/maps.js b/libs/maps.js index 6b7d28c9..c1fdd3b8 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1,18 +1,34 @@ "use strict"; function maps() { - this.init(); + this._init(); + this.DEFAULT_WIDTH = 13; + this.DEFAULT_HEIGHT = 13; + this.DEFAULT_PIXEL_WIDTH = this.DEFAULT_WIDTH * 32; + this.DEFAULT_PIXEL_HEIGHT = this.DEFAULT_HEIGHT * 32; } -maps.prototype.init = function() { +maps.prototype._init = function() { this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; //delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e); } +maps.prototype._setFloorSize = function (floorId) { + if (!core.isset(floorId)) { + core.floorIds.forEach(function (floorId) { + core.maps._setFloorSize(floorId); + }); + return; + } + core.floors[floorId].width = core.floors[floorId].width || this.DEFAULT_WIDTH; + core.floors[floorId].height = core.floors[floorId].height || this.DEFAULT_HEIGHT; +} + +// ------ 加载与存档读档 ------ // + ////// 加载某个楼层(从剧本或存档中) ////// maps.prototype.loadFloor = function (floorId, map) { var floor = core.floors[floorId]; - if (!core.isset(map)) map = floor.map; if (map instanceof Array) { map = {"map": map}; @@ -24,31 +40,24 @@ maps.prototype.loadFloor = function (floorId, map) { else content[e] = core.clone(floor[e]); }); map=this.decompressMap(map.map, floorId); - var mapIntoBlocks = function(map,maps,floor,floorId){ - var blocks = []; - var mw = core.floors[floorId].width || 13; - var mh = core.floors[floorId].height || 13; - for (var i = 0; i < mh; i++) { - for (var j = 0; j < mw; j++) { - var block = maps.initBlock(j, i, (map[i]||[])[j]||0); - maps.addInfo(block); - maps.addEvent(block,j,i,floor.events[j+","+i]) - maps.addChangeFloor(block,j,i,floor.changeFloor[j+","+i]); - if (core.isset(block.event)) blocks.push(block); - } - } - return blocks; - } - if (main.mode=='editor'){ - main.editor.mapIntoBlocks = function(map,floor,floorId){ - return mapIntoBlocks(map,core.maps,floor,floorId); - } - } // 事件处理 - content['blocks'] = mapIntoBlocks(map,this,floor,floorId); + content['blocks'] = this._mapIntoBlocks(map,floor,floorId); return content; } +maps.prototype._mapIntoBlocks = function (map,floor,floorId){ + var blocks = []; + var mw = core.floors[floorId].width; + var mh = core.floors[floorId].height; + for (var i = 0; i < mh; i++) { + for (var j = 0; j < mw; j++) { + var block = this.initBlock(j, i, (map[i]||[])[j], true, floor); + if (core.isset(block.event)) blocks.push(block); + } + } + return blocks; +} + ////// 从ID获得数字 ////// maps.prototype.getNumberById = function (id) { for (var number in this.blocksInfo) { @@ -57,8 +66,7 @@ maps.prototype.getNumberById = function (id) { } // tilesets if (/^X\d+$/.test(id)) { - var info = core.icons.getTilesetOffset(id); - if (info!=null) return parseInt(id.substring(1)); + if (core.icons.getTilesetOffset(id)) return parseInt(id.substring(1)); } // 特殊ID if (id == 'none') return 0; @@ -67,39 +75,31 @@ maps.prototype.getNumberById = function (id) { } ////// 数字和ID的对应关系 ////// -maps.prototype.initBlock = function (x, y, id) { +maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { var disable=null; - id = ""+id; - if (id.length>2) { - if (id.indexOf(":f")==id.length-2) { - id = id.substring(0, id.length - 2); - disable = true; - } - else if (id.indexOf(":t")==id.length-2) { - id = id.substring(0, id.length - 2); - disable = false; - } - } + id = ""+(id||0); + if (id.endsWith(":f")) disable = true; + if (id.endsWith(":t")) disable = false; id=parseInt(id); - var tmp = {'x': x, 'y': y, 'id': id}; - if (disable!=null) tmp.disable = disable; + var block = {'x': x, 'y': y, 'id': id}; + if (disable!=null) block.disable = disable; - if (id==17) { - tmp.event = {"cls": "terrains", "id": "airwall", "noPass": true}; - } - else if (id in this.blocksInfo) tmp.event = JSON.parse(JSON.stringify(this.blocksInfo[id])); - else { - var tilesetOffset = core.icons.getTilesetOffset(id); - if (tilesetOffset != null) { - tmp.event = {"cls": "tileset", "id": "X"+id, "noPass": true}; - } - } + if (id==17) block.event = {"cls": "terrains", "id": "airwall", "noPass": true}; + else if (id in this.blocksInfo) block.event = JSON.parse(JSON.stringify(this.blocksInfo[id])); + else if (core.icons.getTilesetOffset(id)) block.event = {"cls": "tileset", "id": "X"+id, "noPass": true}; - return tmp; + if (addInfo) this._addInfo(block); + if (eventFloor) { + this._addEvent(block, x, y, (eventFloor.events||{})[x+","+y]); + var changeFloor = (eventFloor.changeFloor||{})[x+","+y]; + if (changeFloor) this._addEvent(block, x, y, {"trigger": "changeFloor", "data": changeFloor}); + } + if (main.mode == 'editor') delete block.disable; + return block; } ////// 添加一些信息到block上 ////// -maps.prototype.addInfo = function (block) { +maps.prototype._addInfo = function (block) { if (core.isset(block.event)) { if (block.event.cls.indexOf("enemy")==0 && !core.isset(block.event.trigger)) { block.event.trigger = 'battle'; @@ -113,12 +113,7 @@ maps.prototype.addInfo = function (block) { } } if (!core.isset(block.event.animate)) { - if (block.event.cls=='enemys' || block.event.cls=='npcs') { - block.event.animate = 2; - } - if (block.event.cls == 'animates' || block.event.cls == 'enemy48' || block.event.cls == 'npc48') { - block.event.animate = 4; - } + block.event.animate = core.icons._getAnimateFrames(block.event.cls, false); } block.event.height = 32; if (block.event.cls == 'enemy48' || block.event.cls == 'npc48') @@ -127,7 +122,7 @@ maps.prototype.addInfo = function (block) { } ////// 向该楼层添加剧本的自定义事件 ////// -maps.prototype.addEvent = function (block, x, y, event) { +maps.prototype._addEvent = function (block, x, y, event) { if (!core.isset(event)) return; if (!core.isset(block.event)) { // 本身是空地? block.event = {'cls': 'terrains', 'id': 'none', 'noPass': false}; @@ -162,12 +157,6 @@ maps.prototype.addEvent = function (block, x, y, event) { } } -////// 向该楼层添加剧本的楼层转换事件 ////// -maps.prototype.addChangeFloor = function (block, x, y, event, ground) { - if (!core.isset(event)) return; - this.addEvent(block, x, y, {"trigger": "changeFloor", "data": event}, ground); -} - ////// 初始化所有地图 ////// maps.prototype.initMaps = function (floorIds) { var maps = {}; @@ -178,11 +167,11 @@ maps.prototype.initMaps = function (floorIds) { return maps; } -maps.prototype.__initFloorMap = function (floorId) { +maps.prototype._initFloorMap = function (floorId) { var map = core.clone(core.floors[floorId].map); - var mw = core.floors[floorId].width || 13; - var mh = core.floors[floorId].height || 13; + var mw = core.floors[floorId].width; + var mh = core.floors[floorId].height; for (var x=0;x=0) - return false; - } - - var check = function (block, name) { - if (!core.isset(block)) return true; - if (block instanceof Array) return check((block[y]||[])[x], name); - if (typeof block == 'number') return check(core.maps.initBlock(0,0,block), name); - if (core.isset(block.block)) return check(block.block, name); - return ((block.event||{})[name]||[]).indexOf(direction)<0; - } - var getNumber = function (floorId, name, x, y) { - return (core.maps.getBgFgMapArray(floorId, name)[y]||[])[x]; - } - - // 检查该点的cannotOut - if (!check(core.getBlock(x,y,floorId),"cannotOut") || !check(getNumber(floorId,"bg",x,y),"cannotOut") || !check(getNumber(floorId,"fg",x,y),"cannotOut")) - return false; - - var nx = x+core.utils.scan[direction].x, ny = y+core.utils.scan[direction].y; - // 检查目标点的cannotIn - if (!check(core.getBlock(nx,ny,floorId),"cannotIn") || !check(getNumber(floorId,"bg",nx,ny),"cannotIn") || !check(getNumber(floorId,"fg",nx,ny),"cannotIn")) - return false; - - // 检查将死的领域 - if (floorId==core.status.floorId && core.status.hero.hp <= core.status.checkBlock.damage[nx+core.bigmap.width*ny] - && !core.flags.canGoDeadZone && core.getBlock(nx, ny)==null) - return false; - - return true; -} - -////// 能否瞬间移动 ////// -maps.prototype.canMoveDirectly = function (destX,destY) { - - // 不可瞬间移动请返回-1 - if (!core.flags.enableMoveDirectly) return -1; - - // 检查该楼层是否不可瞬间移动 - if (core.status.thisMap.cannotMoveDirectly) return -1; - - // flag:cannotMoveDirectly为true:不能 - if (core.hasFlag('cannotMoveDirectly')) return -1; - - // 中毒状态:不能 - if (core.hasFlag('poison')) return -1; - - var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y'); - if (fromX==destX&&fromY==destY) return 0; - - // 无视起点事件 - var nowBlockId = core.getBlockId(fromX, fromY); - if ((nowBlockId!=null&&nowBlockId!='upFloor'&&nowBlockId!='downFloor'&&nowBlockId!='portal' - &&nowBlockId!='upPortal'&&nowBlockId!='leftPortal'&&nowBlockId!='downPortal'&&nowBlockId!='rightPortal') - ||core.status.checkBlock.damage[fromX+core.bigmap.width*fromY]>0) - return -1; - - // BFS - var visited=[], queue=[]; - visited[fromX+core.bigmap.width*fromY]=0; - queue.push(fromX+core.bigmap.width*fromY); - - var directions = { - "left": [-1,0], - "up": [0,-1], - "right": [1,0], - "down": [0,1] - } - while (queue.length>0) { - var now=queue.shift(), nowX=parseInt(now%core.bigmap.width), nowY=parseInt(now/core.bigmap.width); - - for (var dir in directions) { - if (!core.canMoveHero(nowX, nowY, dir)) continue; - var nx=nowX+directions[dir][0], ny=nowY+directions[dir][1]; - if (nx<0||nx>=core.bigmap.width||ny<0||ny>=core.bigmap.height||visited[nx+core.bigmap.width*ny]||core.getBlock(nx,ny)!=null||core.status.checkBlock.damage[nx+core.bigmap.width*ny]>0) continue; - visited[nx+core.bigmap.width*ny]=visited[nowX+core.bigmap.width*nowY]+1; - if (nx==destX&&ny==destY) return visited[nx+core.bigmap.width*ny]; - queue.push(nx+core.bigmap.width*ny); - } - } - return -1; -} - -maps.prototype.drawBlock = function (block, animate, dx, dy) { - // none:空地 - if (block.event.id=='none') return; - - dx = dx || 0; - dy = dy || 0; - - // --- 在界面外的动画不绘制 - if ((animate||0)>1 && (block.event.animate||0)>1 && - (block.x * 32 + dx < core.bigmap.offsetX - 64 || block.x * 32 + dx > core.bigmap.offsetX + 416 + 32 - || block.y * 32 + dy < core.bigmap.offsetY - 64 || block.y * 32 + dy > core.bigmap.offsetY + 416 + 32 + 16)) { - return; - } - - var blockInfo = this.__getBlockInfo(block); - if (blockInfo == null) return; - var image = blockInfo.image, x = blockInfo.bx, y = blockInfo.by, height = blockInfo.height; - if (!blockInfo.isTileset) x = (animate||0)%(block.event.animate||1); - - if (core.isset(block.name)) { - core.clearMap(block.name, block.x * 32, block.y * 32 + 32 - height, 32, height); - if (block.name == 'bg') { - if (height>32) { - core.clearMap(block.name, block.x * 32, block.y * 32 - 32, 32, 32); - core.drawImage('bg', core.material.groundCanvas.canvas, block.x * 32, block.y * 32 - 32); - } - core.drawImage('bg', core.material.groundCanvas.canvas, block.x * 32, block.y * 32); - } - core.drawImage(block.name, image, x * 32, y * height, 32, height, - block.x * 32, block.y * 32 + 32 - height, 32, height); - return; - } - - core.clearMap('event', block.x * 32 + dx, block.y * 32 + dy, 32, 32); - core.drawImage('event', image, x * 32, y * height + height-32, 32, 32, block.x * 32 + dx, block.y * 32 + dy, 32, 32); - if (height>32) { - core.clearMap('event2', block.x * 32 + dx, block.y * 32 + 32 - height + dy, 32, height-32) - core.drawImage('event2', image, x * 32, y * height, 32, height-32, block.x * 32 + dx, block.y*32 + 32 - height + dy, 32, height-32); - } + var obj = {}; + core.status.maps[floorId].blocks.forEach(function (block) { + if (!block.disable || showDisable) + obj[block.x+","+block.y] = block; + }); + return obj; } maps.prototype.getBgFgMapArray = function (floorId, name) { floorId = floorId||core.status.floorId; if (!core.isset(floorId)) return []; - var width = core.floors[floorId].width || 13; - var height = core.floors[floorId].height || 13; + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; if (main.mode!='editor' && core.isset(core.status[name+"maps"][floorId])) return core.status[name+"maps"][floorId]; @@ -499,12 +360,251 @@ maps.prototype.getBgFgMapArray = function (floorId, name) { return arr; } +// ------ 地图处理 ------ // + +// ------ canMoveHero & canMoveDirectly ------ // + +////// 勇士能否前往某方向 ////// +maps.prototype.canMoveHero = function(x,y,direction,floorId) { + if (!core.isset(x)) x = core.getHeroLoc('x'); + if (!core.isset(y)) y = core.getHeroLoc('y'); + if (!core.isset(direction)) direction = core.getHeroLoc('direction'); + return core.inArray(this._canMoveHero_generateArray(floorId, x, y), direction); +} + +////// 生成全图的当前可移动信息 ////// +maps.prototype._canMoveHero_generateArray = function (floorId, x, y) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return null; + var width = core.floors[floorId].width, height = core.floors[floorId].height; + var bgArray = this.getBgFgMapArray(floorId, "bg"), + fgArray = this.getBgFgMapArray(floorId, "fg"), + eventArray = this.getMapArray(floorId); + + var generate = function (x, y) { + return ["left", "down", "up", "right"].filter(function (direction) { + return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, { + bgArray: bgArray, fgArray: fgArray, eventArray: eventArray + }); + }); + } + + if (core.isset(x) && core.isset(y)) return generate(x, y); + var array = []; + for (var x = 0; x < width; x++) { + array[x] = []; + for (var y = 0; y < height; y++) { + array[x][y] = generate(x, y); + } + } + return array; +} + +maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, extraData) { + // 1. 检查该点 cannotMove + if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction)) + return false; + + var nx = x + core.utils.scan[direction].x, ny = y + core.utils.scan[direction].y; + if (nx < 0 || ny < 0 || nx >= core.floors[floorId].width || ny >= core.floors[floorId].width) + return false; + + // 2. 检查该点素材的 cannotOut 和下一个点的 cannotIn + if (this._canMoveHero_checkCannotInOut([ + extraData.bgArray[y][x], extraData.fgArray[y][x], extraData.eventArray[y][x] + ], "cannotOut", direction)) + return false; + if (this._canMoveHero_checkCannotInOut([ + extraData.bgArray[ny][nx], extraData.fgArray[ny][nx], extraData.eventArray[ny][nx] + ], "cannotIn", direction)) + return false; + + // 3. 检查是否能进将死的领域 + if (floorId == core.status.floorId + && core.status.hero.hp <= core.status.checkBlock.damage[nx + core.bigmap.width * ny] + && !core.flags.canGoDeadZone && extraData.eventArray[ny][nx] == 0) + return false; + + return true; +} + +maps.prototype._canMoveHero_checkCannotInOut = function (number, name, direction) { + if (number instanceof Array) { + for (var x in number) { + if (this._canMoveHero_checkCannotInOut(number[x], name, direction)) + return true; + } + return false; + } + return core.inArray((this.initBlock(0, 0, number).event||{})[name], direction); +} + +////// 能否瞬间移动 ////// +maps.prototype.canMoveDirectly = function (destX,destY) { + if (!this._canMoveDirectly_checkGlobal()) return -1; + + var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y'); + if (fromX==destX&&fromY==destY) return 0; + // 检查起点事件 + if (!this._canMoveDirectly_checkStartPoint(fromX, fromY)) return -1; + + return this._canMoveDirectly_bfs(fromX, fromY, destX, destY); +} + +maps.prototype._canMoveDirectly_checkGlobal = function () { + // 检查全塔是否禁止瞬间移动 + if (!core.flags.enableMoveDirectly) return false; + // 检查该楼层是否不可瞬间移动 + if (core.status.thisMap.cannotMoveDirectly) return false; + // flag:cannotMoveDirectly为true:不能 + if (core.hasFlag('cannotMoveDirectly')) return false; + // 中毒状态:不能 + if (core.hasFlag('poison')) return false; + + return true; +} + +maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) { + if (core.status.checkBlock.damage[sx+core.bigmap.width*sy]>0) return false; + var id = core.getBlockId(sx, sy); + if (id != null) { + // 楼梯或者传送点才能无视 + if (["upFloor","downFloor","portal","upPortal","downPortal","leftPortal","rightPortal"].indexOf(id)>=0) + return true; + return false; + } + return true; +} + +maps.prototype._canMoveDirectly_bfs = function (sx, sy, ex, ey) { + var canMoveArray = this._canMoveHero_generateArray(); + var blocksObj = this.getMapBlocksObj(core.status.floorId); + + var visited=[], queue=[]; + visited[sx+","+sy]=0; + queue.push(sx+","+sy); + + while (queue.length>0) { + var now=queue.shift().split(","), x=parseInt(now[0]), y=parseInt(now[1]); + for (var direction in core.utils.scan) { + if (!core.inArray(canMoveArray[x][y], direction)) continue; + var nx=x+core.utils.scan[direction].x, ny=y+core.utils.scan[direction].y, nindex = nx+","+ny; + if (visited[nindex]) continue; + if (!this._canMoveDirectly_checkNextPoint(blocksObj, nx, ny)) continue; + visited[nindex] = visited[now]+1; + if (nx == ex && ny == ey) return visited[nindex]; + queue.push(nindex); + } + } + + return -1; +} + +maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { + var index = x + "," + y; + // 该点是否有事件 + if (blocksObj[index]) return false; + // 是否存在阻激夹域伤害 + if (core.status.checkBlock.damage[x+core.bigmap.width*y]>0) return false; + // 是否存在捕捉 + if (core.status.checkBlock.ambush[x+core.bigmap.width*y]) return false; + + return true; +} + +// -------- Draw block, map, autotile, ... -------- // + +// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 +maps.prototype.getBlockInfo = function (block) { + if (!core.isset(block)) return null; + if (typeof block == 'string') { // 参数是ID + block = this.getNumberById(block); + } + if (typeof block == 'number') { // 参数是数字 + if (block == 0) return null; + block = this.initBlock(0, 0, block, true); + } + if (!core.isset(block.event)) return null; + var id = block.event.id, cls = block.event.cls, image = null, posX = 0, posY = 0, + height = block.event.height || 32, faceIds = {}; + + if (id == 'none') return null; + else if (id == 'airwall') { + if (!core.isset(core.material.images.airwall)) return null; + image = core.material.images.airwall; + } + else if (cls == 'tileset') { + var offset = core.icons.getTilesetOffset(id); + if (offset == null) return null; + posX = offset.x; + posY = offset.y; + image = core.material.images.tilesets[offset.image]; + } + else if (cls == 'autotile') { + image = core.material.images.autotile[id]; + } + else { + image = core.material.images[cls]; + posY = core.material.icons[cls][id]; + faceIds = block.event.faceIds||{}; + } + + return {id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; +} + +maps.prototype.drawBlock = function (block, animate, dx, dy) { + if (block.event.id == 'none') return; + animate = animate || 0; + dx = dx || 0; + dy = dy || 0; + var x = block.x, y = block.y; + // --- 在界面外的动画不绘制 + if (animate > 1 && block.event.animate > 1 && + (32*x + dx < core.bigmap.offsetX - 64 || 32*x + dx > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 + || 32*y + dy < core.bigmap.offsetY - 64 || 32*y + dy > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { + return; + } + + var blockInfo = this.getBlockInfo(block); + if (blockInfo == null) return; + if (blockInfo.cls != 'tileset') blockInfo.posX = animate % block.event.animate; + if (!core.isset(block.name)) + this._drawBlockInfo(blockInfo, block.x, block.y, dx, dy); + else + this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y); +} + +maps.prototype._drawBlockInfo = function (blockInfo, x, y, dx, dy) { + var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height; + + core.clearMap('event', x * 32 + dx, y * 32 + dy, 32, 32); + core.drawImage('event', image, posX * 32, posY * height + height - 32, 32, 32, x * 32 + dx, y * 32 + dy, 32, 32); + if (height>32) { + core.clearMap('event2', x * 32 + dx, y * 32 + 32 - height + dy, 32, height - 32) + core.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, x * 32 + dx, y * 32 + 32 - height + dy, 32, height-32); + } +} + +maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y) { + var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height; + + core.clearMap(name, x * 32, y * 32 + 32 - height, 32, height); + if (name == 'bg') { + if (height>32) { + core.clearMap('bg', x * 32, y * 32 - 32, 32, 32); + core.drawImage('bg', core.material.groundCanvas.canvas, x * 32, y * 32 - 32); + } + core.drawImage('bg', core.material.groundCanvas.canvas, x * 32, y * 32); + } + core.drawImage(name, image, posX * 32, posY * height, 32, height, x * 32, y * 32 + 32 - height, 32, height); +} + ////// 背景/前景图块的绘制 ////// -maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { +maps.prototype.drawBgFgMap = function (floorId, ctx, name, onMap) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - var width = core.floors[floorId].width || 13; - var height = core.floors[floorId].height || 13; + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; if (!core.isset(core.status[name+"maps"])) core.status[name+"maps"] = {}; @@ -512,42 +612,31 @@ maps.prototype.drawBgFgMap = function (floorId, canvas, name, animate) { var arr = this.getBgFgMapArray(floorId, name); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { - if (arr[y][x]>0) { - var block = core.maps.initBlock(x, y, arr[y][x]); - this.addInfo(block); - block.name = name; - if (core.isset(block.event)) { - var id = block.event.id, cls = block.event.cls; - if (cls == 'autotile') { - core.drawAutotile(canvas, arr, block, 32, 0, 0); - if (animate) - core.addAutotileGlobalAnimate(block); - } - else if (cls == 'tileset') { - var offset = core.icons.getTilesetOffset(id); - if (offset!=null) { - canvas.drawImage(core.material.images.tilesets[offset.image], 32*offset.x, 32*offset.y, 32, 32, 32*x, 32*y, 32, 32); - } - } - else if (arr[y][x]==17) { - if (core.isset(core.material.images.airwall)) { - canvas.drawImage(core.material.images.airwall, 32*x, 32*y); - } - } - else { - if (animate) { - this.drawBlock(block); - this.addGlobalAnimate(block); - } - else { - canvas.drawImage(core.material.images[cls], 0, core.material.icons[cls][id] * 32, 32, 32, x * 32, y * 32, 32, 32); - } - } - } - } + var block = this.initBlock(x, y, arr[y][x], true); + if (!core.isset(block.event)) continue; + block.name = name; + var blockInfo = this.getBlockInfo(block); + if (!core.isset(blockInfo)) continue; + this._drawBgFgMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); } } - if (animate) core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); + if (onMap) + core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); +} + +maps.prototype._drawBgFgMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { + if (blockInfo.cls == 'autotile') { // Autotile单独处理 + this.drawAutotile(ctx, arr, block, 32, 0, 0); + if (onMap) core.addAutotileGlobalAnimate(block); + return; + } + if (!onMap) { + var height = blockInfo.height; + core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); + return; + } + this.drawBlock(block); + this.addGlobalAnimate(block); } ////// 生成groundPattern ////// @@ -561,164 +650,171 @@ maps.prototype.generateGroundPattern = function (floorId) { // core.material.groundPattern = '#000000'; } -maps.prototype.drawFloorImages = function (floorId, images, animate) { - var redraw = core.isset(animate); - if (!redraw) { - core.status.floorAnimateObjs = core.clone(images); +maps.prototype._getFloorImages = function (floorId) { + floorId = floorId || core.status.floorId; + var images = []; + if (core.isset(core.status.maps[floorId].images)) { + images = core.status.maps[floorId].images; + if (typeof images == 'string') { + images = [[0, 0, images]]; + } } + return images; +} - animate = animate || 0; +maps.prototype.drawFloorImages = function (floorId, ctx, name, images, animate) { + floorId = floorId || core.status.floorId; + if (!core.isset(images)) images = this._getFloorImages(floorId); + var redraw = core.isset(animate); + if (!redraw) core.status.floorAnimateObjs = core.clone(images); images.forEach(function (t) { if (typeof t == 'string') t = [0,0,t]; - var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); + var dx=parseInt(t[0]), dy=parseInt(t[1]), imageName=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); + var image = core.material.images.images[imageName]; if (redraw && frame == 1) return; // 不重绘 - if (core.isset(dx) && core.isset(dy) && - !core.hasFlag("floorimg_"+floorId+"_"+dx+"_"+dy) && - core.isset(core.material.images.images[p])) { - var image = core.material.images.images[p]; - var width = parseInt(image.width / frame), height = image.height; - var offsetX = animate%frame*width; - - if (!t[3]) { - if (/.*\.gif/i.test(p) && main.mode=='play') { - - if (redraw) return; // 忽略gif - - core.dom.gif.innerHTML = ""; - var gif = new Image(); - gif.src = image.src; - gif.style.position = 'absolute'; - gif.style.left = (dx*core.domStyle.scale)+"px"; - gif.style.top = (dy*core.domStyle.scale)+"px"; - gif.style.width = image.width*core.domStyle.scale+"px"; - gif.style.height = image.height*core.domStyle.scale+"px"; - core.dom.gif.appendChild(gif); - } - else { - if (redraw) core.clearMap('bg', dx, dy, width, height); - core.drawImage('bg', image, offsetX, 0, width, height, dx, dy, width, height); - } - } - else if (t[3]==1) { - if (redraw) core.clearMap('fg', dx, dy, width, height); - core.drawImage('fg', image, offsetX, 0, width, height, dx, dy, width, height); - } - else if (t[3]==2) { - if (redraw) { - core.clearMap('bg', dx, dy + height - 32, width, 32); - core.clearMap('fg', dx, dy, width, height-32); - } - core.drawImage('bg', image, offsetX, height-32, width, 32, dx, dy + height - 32, width, 32); - core.drawImage('fg', image, offsetX, 0, width, height-32, dx, dy, width, height-32); + if (core.isset(dx) && core.isset(dy) && core.isset(image) && + !core.hasFlag("floorimg_"+floorId+"@"+dx+"@"+dy)) { + var width = parseInt(image.width / frame), offsetX = (animate||0)%frame*width; + if (/.*\.gif/i.test(imageName) && main.mode=='play') { + if (redraw) return; // 忽略gif + this._drawFloorImages_gif(image, dx, dy); + return; } + core.maps._drawFloorImage(ctx, name, t[3], image, offsetX, width, dx, dy, redraw); } }); } +maps.prototype._drawFloorImages_gif = function (image, dx, dy) { + core.dom.gif.innerHTML = ""; + var gif = new Image(); + gif.src = image.src; + gif.style.position = 'absolute'; + gif.style.left = (dx*core.domStyle.scale)+"px"; + gif.style.top = (dy*core.domStyle.scale)+"px"; + gif.style.width = image.width*core.domStyle.scale+"px"; + gif.style.height = image.height*core.domStyle.scale+"px"; + core.dom.gif.appendChild(gif); + return; +} + +maps.prototype._drawFloorImage = function (ctx, name, type, image, offsetX, width, dx, dy, redraw) { + var height = image.height; + var _draw = function () { + if (redraw) core.clearMap(ctx, dx, dy, width, height); + core.drawImage(ctx, image, offsetX, 0, width, height, dx, dy, width, height); + } + if (!type) { + if (name != 'bg') return; + return _draw(); + } + if (type==1) { + if (name != 'fg') return; + return _draw(); + } + if (type==2) { + if (name == 'bg') { + if (redraw) core.clearMap(ctx, dx, dy + height - 32, width, 32); + core.drawImage('bg', image, offsetX, height-32, width, 32, dx, dy + height - 32, width, 32); + } + else if (name == 'fg') { + if (redraw) core.clearMap(ctx, dx, dy, width, height-32); + core.drawImage('fg', image, offsetX, 0, width, height-32, dx, dy, width, height-32); + } + return; + } +} + ////// 绘制某张地图 ////// maps.prototype.drawMap = function (floorId, callback) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) { - if (core.isset(callback)) - callback(); + if (core.isset(callback)) callback(); return; } core.clearMap('all'); - this.generateGroundPattern(floorId); - - var drawBg = function(){ - var width = core.floors[floorId].width || 13; - var height = core.floors[floorId].height || 13; - - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - core.drawImage('bg', core.material.groundCanvas.canvas, 32*x, 32*y); - } - } - - // 获得image - var images = []; - if (core.isset(core.status.maps[floorId].images)) { - images = core.status.maps[floorId].images; - if (typeof images == 'string') { - images = [[0, 0, images]]; - } - } - - // ----- 可以调整这三行的顺序来修改覆盖关系;同层画布上,后绘制的覆盖先绘制的 - // ----- ui.js的drawThumbnail函数也需要对应进行修改。 - - // 绘制楼层贴图 - core.maps.drawFloorImages(floorId, images); - // 绘制背景层图块 - core.maps.drawBgFgMap(floorId, core.canvas.bg, "bg", true); - // 绘制前景层图块 - core.maps.drawBgFgMap(floorId, core.canvas.fg, "fg", true); - - } - if (main.mode=='editor'){ - // just do not run drawBg - - // //---move to main.editor.updateMap - // main.editor.drawMapBg = function(){ - // core.clearMap('bg'); - // core.clearMap('fg'); - // drawBg(); - // } - } else { - drawBg(); - } - core.status.floorId = floorId; core.status.thisMap = core.status.maps[floorId]; - var drawEvent = function(){ - var mapData = core.status.maps[core.status.floorId]; - var mapBlocks = mapData.blocks; - - var mapArray = core.maps.getMapArray(mapBlocks,core.bigmap.width,core.bigmap.height); - for (var b = 0; b < mapBlocks.length; b++) { - // 事件启用 - var block = mapBlocks[b]; - if (core.isset(block.event) && !block.disable) { - if (block.event.cls == 'autotile') { - core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); - core.addAutotileGlobalAnimate(block); - } - else { - core.drawBlock(block); - core.addGlobalAnimate(block); - } - } - } - core.status.autotileAnimateObjs.map = core.clone(mapArray); - } - - if (main.mode=='editor'){ - main.editor.updateMap = function(){ - core.removeGlobalAnimate(null, null, true); - core.clearMap('bg'); - core.clearMap('event'); - core.clearMap('event2'); - core.clearMap('fg'); - drawBg(); - drawEvent(); - core.setGlobalAnimate(core.values.animateSpeed); - } - } else { - drawEvent(); - if (core.isset(core.status.curtainColor)) - core.fillRect('curtain',0,0,416,416,core.arrayToRGBA(core.status.curtainColor)); - core.setGlobalAnimate(core.values.animateSpeed); - core.drawHero(); - core.updateStatusBar(); + this._drawMap_drawBgFg(); + this._drawMap_drawEvent(); + if (core.isset(core.status.curtainColor)) { + core.fillRect('curtain', 0, 0, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, + core.arrayToRGBA(core.status.curtainColor)); } + core.setGlobalAnimate(core.values.animateSpeed); + core.drawHero(); + core.updateStatusBar(); if (core.isset(callback)) callback(); } +maps.prototype._drawMap_drawEvent = function (floorId) { + floorId = floorId || core.status.floorId; + var mapBlocks = core.status.maps[floorId].blocks; + + var mapArray = this.getMapArray(mapBlocks, core.bigmap.width, core.bigmap.height); + for (var b = 0; b < mapBlocks.length; b++) { + // 事件启用 + var block = mapBlocks[b]; + if (core.isset(block.event) && !block.disable) { + if (block.event.cls == 'autotile') { + core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); + core.addAutotileGlobalAnimate(block); + } + else { + core.drawBlock(block); + core.addGlobalAnimate(block); + } + } + } + core.status.autotileAnimateObjs.map = core.clone(mapArray); +} + +maps.prototype._drawMap_drawBgFg = function (floorId) { + floorId = floorId || core.status.floorId; + this.drawBg(floorId); + this.drawFg(floorId); +} + +maps.prototype.drawBg = function (floorId, ctx) { + var onMap = !core.isset(ctx); + if (onMap) { + ctx = core.canvas.bg; + core.clearMap(ctx); + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + core.drawImage(ctx, core.material.groundCanvas.canvas, 32*x, 32*y); + } + } + } + this._drawBg_drawContent(floorId, ctx, onMap); +} + +maps.prototype.drawFg = function (floorId, ctx) { + var onMap = !core.isset(ctx); + if (onMap) ctx = core.canvas.fg; + this._drawFg_drawContent(floorId, ctx, onMap); +} + +// --- 实际绘制背景层;可以调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块 +// 先绘制的会被后绘制的覆盖 +maps.prototype._drawBg_drawContent = function (floorId, ctx, onMap) { + this.drawFloorImages(floorId, ctx, 'bg'); + this.drawBgFgMap(floorId, ctx, 'bg', onMap); +} + +// --- 实际绘制前景层;可以调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块 +// 先绘制的会被后绘制的覆盖 +maps.prototype._drawFg_drawContent = function (floorId, ctx, onMap) { + this.drawFloorImages(floorId, ctx, 'fg'); + this.drawBgFgMap(floorId, ctx, 'fg', onMap); +} + ////// 绘制Autotile ////// maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, status){ var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 @@ -912,45 +1008,6 @@ maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { return null; } -maps.prototype.__getBlockInfo = function (block) { - var image, bx, by, height = block.event.height || 32; - var faceIds = {}, isTileset = false; - if (block.event.cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset==null) { - return null; - } - bx = offset.x; - by = offset.y; - image = core.material.images.tilesets[offset.image]; - isTileset = true; - } - // 不支持autotile - else if (block.event.cls == 'autotile') { - return null; - } - // 空气墙;忽略事件 - else if (block.id==17) { - if (!core.isset(core.material.images.airwall)) return null; - image = core.material.images.airwall; - bx = by = 0; - } - else { - image = core.material.images[block.event.cls]; - bx = 0; - by = core.material.icons[block.event.cls][block.event.id]; - faceIds = block.event.faceIds||{}; - } - return { - "image": image, - "bx": bx, - "by": by, - "height": height, - "isTileset": isTileset, - "faceIds": faceIds - }; -} - maps.prototype.__moveBlockCanvas = function (image, bx, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas) { // 重绘block & 重定位 if (headCanvas != null) { @@ -1023,7 +1080,7 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { core.removeBlock(x,y); block=block.block; - var blockInfo = this.__getBlockInfo(block); + var blockInfo = this.getBlockInfo(block); if (blockInfo == null) { if (core.isset(callback)) callback(); return; @@ -1056,7 +1113,7 @@ maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { destY += core.utils.scan[t].y; }); - var animateValue = block.event.animate || 1, animateCurrent = isTileset?bx:0, animateTime = 0; + var animateValue = core.icons._getAnimateFrames(block.event.cls, true), animateCurrent = isTileset?bx:0, animateTime = 0; var blockCanvas = this.__initBlockCanvas(block, height, x, y); var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; var opacity = 1; @@ -1139,7 +1196,7 @@ maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { core.removeBlock(sx,sy); block=block.block; - var blockInfo = this.__getBlockInfo(block); + var blockInfo = this.getBlockInfo(block); if (blockInfo == null) { if (core.isset(callback)) callback(); return; @@ -1223,7 +1280,7 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { if (block==null) return; block=block.block; - var blockInfo = core.maps.__getBlockInfo(block); + var blockInfo = core.maps.getBlockInfo(block); if (blockInfo == null) return; var blockCanvas = core.maps.__initBlockCanvas(block, blockInfo.height, t[0], t[1]); var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; @@ -1390,13 +1447,10 @@ maps.prototype.setBlock = function (number, x, y, floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=(core.floors[floorId].width||13) || y<0 || y>=(core.floors[floorId].height||13)) return; + if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; var originBlock=core.getBlock(x,y,floorId,true); - var block = core.maps.initBlock(x,y,number); - core.maps.addInfo(block); - core.maps.addEvent(block,x,y,core.floors[floorId].events[x+","+y]); - core.maps.addChangeFloor(block,x,y,core.floors[floorId].changeFloor[x+","+y]); + var block = core.maps.initBlock(x,y,number,true,core.floors[floorId]); if (core.isset(block.event)) { if (floorId == core.status.floorId) { core.removeGlobalAnimate(x, y); @@ -1428,7 +1482,7 @@ maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=(core.floors[floorId].width||13) || y<0 || y>=(core.floors[floorId].height||13)) return; + if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; if (name!='bg' && name!='fg') return; core.setFlag(name+"v_"+floorId+"_"+x+"_"+y, number); @@ -1590,7 +1644,7 @@ maps.prototype.setFloorImage = function (type, loc, floorId, callback) { if (loc.length==0) return; loc.forEach(function (t) { var x=t[0], y=t[1]; - var flag = "floorimg_"+floorId+"_"+x+"_"+y; + var flag = "floorimg_"+floorId+"@"+x+"@"+y; core.setFlag(flag, type=='show'?false:true); }) diff --git a/libs/ui.js b/libs/ui.js index 41290945..db2f135c 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -7,11 +7,11 @@ "use strict"; function ui() { - this.init(); + this._init(); } // 初始化UI -ui.prototype.init = function () { +ui.prototype._init = function () { this.uidata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.ui; } @@ -349,20 +349,17 @@ ui.prototype.getTitleAndIcon = function (content) { var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; var getInfo = function (v) { - ["enemy48", "enemys", "npc48", "npcs"].forEach(function (x) { - if (core.isset(core.material.icons[x][v])) { - image = core.material.images[x]; - icon = core.material.icons[x][v]; - if (x.indexOf("48")>=0) { - iconHeight = 48; - animate = 4; - } - else { - iconHeight = 32; - animate = 2; - } + var number = core.maps.getNumberById(v); + if (number>0) { + var block = core.maps.initBlock(0,0,number,true); + if (core.isset(block.event)) { + var cls = block.event.cls; + image = core.material.images[cls]; + icon = core.material.icons[cls][v]; + iconHeight = block.event.height; + animate = block.event.animate; } - }); + } }; if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) { @@ -1120,7 +1117,6 @@ 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.displayCritical ? "[ON]" : "[OFF]"), "领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), @@ -1155,311 +1151,6 @@ ui.prototype.drawQuickShop = function () { this.drawChoices(null, choices); } -////// 绘制战斗动画 ////// -ui.prototype.drawBattleAnimate = function(monsterId, callback) { - - // UI层 - core.lockControl(); - if (!core.isset(core.status.event.id)) { - core.status.event = {'id': 'battle'}; - } - - var hero_hp = core.getStatus('hp'), hero_atk = core.getStatus('atk'), hero_def = core.getStatus('def'), - hero_mdef = core.getStatus('mdef'); - - hero_hp=Math.max(0, hero_hp); - hero_atk=Math.max(0, hero_atk); - hero_def=Math.max(0, hero_def); - hero_mdef=Math.max(0, hero_mdef); - - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - - var enemy = core.material.enemys[monsterId]; - var enemyInfo = core.enemys.getEnemyInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef); - var mon_hp = enemyInfo.hp, mon_atk = enemyInfo.atk, mon_def = enemyInfo.def, mon_money=enemyInfo.money, - mon_exp = enemyInfo.experience, mon_special=enemyInfo.special; - - var initDamage = 0; // 战前伤害 - - // 吸血 - if (core.enemys.hasSpecial(mon_special, 11)) { - var vampireDamage = hero_hp * enemy.value; - - // 如果有神圣盾免疫吸血等可以在这里写 - - vampireDamage = Math.floor(vampireDamage) || 0; - // 加到自身 - if (enemy.add) // 如果加到自身 - mon_hp += vampireDamage; - - initDamage += vampireDamage; - } - - hero_hp -= core.enemys.getExtraDamage(enemy); - - if (core.enemys.hasSpecial(mon_special, 2)) hero_def=0; // 魔攻 - - // 实际操作 - var turn = 0; // 0为勇士攻击 - if (core.enemys.hasSpecial(mon_special, 1)) turn=1; - - // 回合 - var turns = 2; - if (core.enemys.hasSpecial(mon_special, 4)) turns=3; - if (core.enemys.hasSpecial(mon_special, 5)) turns=4; - if (core.enemys.hasSpecial(mon_special, 6)) turns=1+(enemy.n||4); - - // 初始伤害 - if (core.enemys.hasSpecial(mon_special, 7)) initDamage+=Math.floor(core.values.breakArmor * hero_def); - if (core.enemys.hasSpecial(mon_special, 9)) initDamage+=Math.floor(core.values.purify * hero_mdef); - hero_mdef-=initDamage; - if (hero_mdef<0) { - hero_hp+=hero_mdef; - hero_mdef=0; - } - - var specialTexts = core.enemys.getSpecialText(monsterId); - - core.clearMap('ui'); - var left=10, right=416-2*left; - - var lines = 3; - if (core.flags.enableMDef || core.flags.enableMoney || core.flags.enableExperience) lines=4; - if (core.flags.enableMoney && core.flags.enableExperience) lines=5; - - var lineHeight = 60; - var height = lineHeight * lines + 50; - - var top = (416-height)/2, bottom = height; - - core.fillRect('ui', left, top, right, bottom, 'rgba(0,0,0,0.85)'); - core.setAlpha('ui', 1); - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, '#FFFFFF', 2); - core.clearMap('data'); - - clearInterval(core.interval.tipAnimate); - core.setAlpha('data', 1); - core.status.boxAnimateObjs = []; - var globalFont = core.status.globalAttribute.font; - - var margin = 35; - var boxWidth = 40; - var monsterHeight = 32, animate=2; - - var image = core.material.images.enemys, icon = core.material.icons.enemys; - if (core.isset(core.material.icons.enemy48[monsterId])) { - image = core.material.images.enemy48; - icon = core.material.icons.enemy48; - monsterHeight = 48; - animate=4; - } - - // 方块 - var heroHeight = core.material.icons.hero.height; - core.strokeRect('ui', left + margin - 1, top + margin - 1, boxWidth+2, heroHeight+boxWidth-32+2, '#FFD700', 2); - core.strokeRect('ui', left + right - margin - boxWidth - 1 , top+margin-1, boxWidth+2, monsterHeight+boxWidth-32+2); - - // 名称 - core.setTextAlign('ui', 'center'); - core.fillText('ui', core.status.hero.name, left+margin+boxWidth/2, top+margin+heroHeight+40, '#FFD700', 'bold 22px '+globalFont); - core.fillText('ui', "怪物", left+right-margin-boxWidth/2, top+margin+monsterHeight+40); - for (var i=0, j=0; i0) - mon_hp-=hero_atk-mon_def; - if (mon_hp<0) mon_hp=0; - - // 更新怪物伤害 - core.clearMap('data', right_start, top+margin+10, lineWidth, 40); - core.setTextAlign('data', 'left'); - core.fillText('data', mon_hp, right_start, top+margin+10+26, '#DDDDDD', 'bold 16px '+globalFont); - - // 反击 - if (core.enemys.hasSpecial(mon_special, 8)) { - hero_mdef -= Math.floor(core.values.counterAttack * hero_atk); - - if (hero_mdef<0) { - hero_hp+=hero_mdef; - hero_mdef=0; - } - // 更新勇士数据 - core.clearMap('data', left_start, top+margin+10, lineWidth, 40); - core.setTextAlign('data', 'right'); - core.fillText('data', hero_hp, left_end, top+margin+10+26, '#DDDDDD', 'bold 16px '+globalFont); - - if (core.flags.enableMDef) { - core.clearMap('data', left_start, top+margin+10+3*lineHeight, lineWidth, 40); - core.fillText('data', hero_mdef, left_end, top+margin+10+26+3*lineHeight); - } - - } - - } - else { - // 怪物攻击 - core.drawLine('data', left + margin + 6, top+margin+heroHeight+(boxWidth-32)-6, - left+margin+boxWidth-6, top+margin+6, '#FF0000', 4); - setTimeout(function() { - core.clearMap('data', left + margin, top+margin, boxWidth, heroHeight+boxWidth-32); - }, 250); - - var per_damage = mon_atk-hero_def; - if (per_damage < 0) per_damage = 0; - - hero_mdef-=per_damage; - if (hero_mdef<0) { - hero_hp+=hero_mdef; - hero_mdef=0; - } - // 更新勇士数据 - core.clearMap('data', left_start, top+margin+10, lineWidth, 40); - core.setTextAlign('data', 'right'); - core.fillText('data', hero_hp, left_end, top+margin+10+26, '#DDDDDD', 'bold 16px '+globalFont); - - if (core.flags.enableMDef) { - core.clearMap('data', left_start, top+margin+10+3*lineHeight, lineWidth, 40); - core.fillText('data', hero_mdef, left_end, top+margin+10+26+3*lineHeight); - } - - } - turn++; - if (turn>=turns) turn=0; - - if (hero_hp<=0 || mon_hp<=0) { - // 战斗结束 - clearInterval(battleInterval); - core.status.boxAnimateObjs = []; - core.clearMap('ui'); - core.setAlpha('ui', 1.0); - core.clearMap('data'); - if (core.status.event.id=='battle') { - core.unLockControl(); - core.status.event.id=null; - } - if (core.isset(callback)) - callback(); - return; - } - - }, 400); -} - ////// 绘制等待界面 ////// ui.prototype.drawWaiting = function(text) { @@ -1977,7 +1668,7 @@ ui.prototype.drawMaps = function (index, x, y) { if (index<0) index=0; if (index>=core.floorIds.length) index=core.floorIds.length-1; - var floorId = core.floorIds[index], mw = core.floors[floorId].width||13, mh = core.floors[floorId].height||13; + var floorId = core.floorIds[index], mw = core.floors[floorId].width, mh = core.floors[floorId].height; if (!core.isset(x)) x = parseInt(mw/2); if (!core.isset(y)) y = parseInt(mh/2); if (x<6) x=6; @@ -1989,14 +1680,14 @@ ui.prototype.drawMaps = function (index, x, y) { clearTimeout(core.interval.tipAnimate); core.clearLastEvent(); - core.status.checkBlock.buff = {}; + core.status.checkBlock.cache = {}; this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 0, 0, 416, x, y); // 绘图 if (core.status.event.data.paint) { var offsetX = core.clamp(x-6, 0, mw-13), offsetY = core.clamp(y-6, 0, mh-13); var value = core.paint[floorId]; - if (core.isset(value)) value = LZString.decompress(value).split(","); + if (core.isset(value)) value = lzw_decode(value).split(","); core.utils.decodeCanvas(value, 32*mw, 32*mh); core.drawImage('ui', core.bigmap.tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, 0, 0, 416, 416); } @@ -2291,7 +1982,7 @@ ui.prototype.drawEquipbox = function(index) { if (compare[name]<0) color = '#FF0000'; var nowValue = core.getStatus(name), newValue = nowValue + compare[name]; if (equip.equip.percentage) { - var nowBuff = core.getFlag('equip_'+name+"_buff",1), newBuff = nowBuff+compare[name]/100; + var nowBuff = core.getFlag('__'+name+"_buff__", 1), newBuff = nowBuff+compare[name]/100; nowValue = Math.floor(nowBuff*core.getStatus(name)); newValue = Math.floor(newBuff*core.getStatus(name)); } @@ -2397,7 +2088,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 30, '#FFFFFF', "bold 17px "+globalFont); core.strokeRect('ui', (2*i+1)*u-size/2, 45, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { - core.ui.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 45, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); + core.ui.drawThumbnail(data.floorId, 'ui', core.maps.loadMap(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 45, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; @@ -2413,7 +2104,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.fillText('ui', name+id, (2*i-5)*u, 218, '#FFFFFF', "bold 17px "+globalFont); core.strokeRect('ui', (2*i-5)*u-size/2, 233, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { - core.ui.drawThumbnail(data.floorId, 'ui', core.maps.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 233, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); + core.ui.drawThumbnail(data.floorId, 'ui', core.maps.loadMap(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 233, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; @@ -2469,8 +2160,8 @@ ui.prototype.drawSLPanel = function(index, refresh) { ////// 绘制一个缩略图 ////// ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, centerX, centerY, heroLoc, heroIcon) { - var mw = core.floors[floorId].width || 13; - var mh = core.floors[floorId].height || 13; + var mw = core.floors[floorId].width; + var mh = core.floors[floorId].height; // 绘制到tempCanvas上面 var tempCanvas = core.bigmap.tempCanvas; var tempWidth = mw*32, tempHeight = mh*32; @@ -2500,7 +2191,7 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente if (typeof t == 'string') t = [0,0,t]; var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); if (core.isset(dx) && core.isset(dy) && - !core.hasFlag("floorimg_"+floorId+"_"+dx+"_"+dy) && + !core.hasFlag("floorimg_"+floorId+"@"+dx+"@"+dy) && core.isset(core.material.images.images[p])) { var image = core.material.images.images[p]; var width = image.width / frame, height = image.height; @@ -2554,7 +2245,7 @@ ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, cente images.forEach(function (t) { var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); if (core.isset(dx) && core.isset(dy) && - !core.hasFlag("floorimg_"+floorId+"_"+dx+"_"+dy) && + !core.hasFlag("floorimg_"+floorId+"@"+dx+"@"+dy) && core.isset(core.material.images.images[p])) { var image = core.material.images.images[p]; var width = image.width / frame, height = image.height; @@ -2888,7 +2579,7 @@ ui.prototype.drawPaint = function () { // 将已有的内容绘制到route上 var value = core.paint[core.status.floorId]; - if (core.isset(value)) value = LZString.decompress(value).split(","); + if (core.isset(value)) value = lzw_decode(value).split(","); core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); diff --git a/libs/utils.js b/libs/utils.js index f51ca99b..f8a9323b 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -6,7 +6,7 @@ utils.js 工具类 "use strict"; function utils() { - this.init(); + this._init(); this.scan = { 'up': {'x': 0, 'y': -1}, 'left': {'x': -1, 'y': 0}, @@ -15,7 +15,7 @@ function utils() { }; } -utils.prototype.init = function () { +utils.prototype._init = function () { // 定义Object.assign if (typeof Object.assign != "function") { Object.assign = function(target, varArgs) { // .length of function is 2 @@ -136,12 +136,14 @@ utils.prototype.setLocalStorage = function(key, value) { return; } - var str = JSON.stringify(value); - var compressed = LZString.compress(str); + var str = JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function(chr) { + return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) + }); + var compressed = lzw_encode(str); // test if we can save to localStorage localStorage.setItem("__tmp__", compressed); - if (LZString.decompress(localStorage.getItem("__tmp__"))==str) { + if (lzw_decode(localStorage.getItem("__tmp__"))==str) { localStorage.setItem(core.firstData.name + "_" + key, compressed); } else { @@ -161,28 +163,30 @@ utils.prototype.setLocalStorage = function(key, value) { } } +utils.prototype.decompress = function (value) { + try { + var output = lzw_decode(value); + if (core.isset(output) && output.length > 0) + return JSON.parse(output); + } + catch (e) {} + try { + var output = LZString.decompress(value); + if (core.isset(output) && output.length > 0) + return JSON.parse(output); + } + catch (e) {} + try { + return JSON.parse(value); + } + catch (e) {main.log(e);} + return null; +} + ////// 获得本地存储 ////// utils.prototype.getLocalStorage = function(key, defaultValue) { - try { - var value = localStorage.getItem(core.firstData.name+"_"+key); - if (core.isset(value)) { - var output = LZString.decompress(value); - if (core.isset(output) && output.length>0) { - try { - return JSON.parse(output); - } - catch (ee) { - // Ignore, use default value - } - } - return JSON.parse(value); - } - return defaultValue; - } - catch (e) { - main.log(e); - return defaultValue; - } + var res = this.decompress(localStorage.getItem(core.firstData.name+"_"+key)); + return res==null?defaultValue:res; } ////// 移除本地存储 ////// @@ -210,7 +214,9 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal } // Save to localforage - var compressed = LZString.compress(JSON.stringify(value)); + var compressed = lzw_encode(JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function(chr) { + return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) + })); localforage.setItem(core.firstData.name+"_"+key, compressed, function (err) { if (core.isset(err)) { if (core.isset(errorCallback)) errorCallback(err); @@ -240,18 +246,9 @@ utils.prototype.getLocalForage = function (key, defaultValue, successCallback, e else { if (!core.isset(successCallback)) return; if (core.isset(value)) { - try { - var output = LZString.decompress(value); - if (core.isset(output) && output.length>0) { - try { - successCallback(JSON.parse(output)); - return; - } catch (ee) {main.log(ee);} - } - successCallback(JSON.parse(value)); - return; - } - catch (e) {main.log(e);} + var res = core.utils.decompress(value); + successCallback(res==null?defaultValue:res); + return; } successCallback(defaultValue); } @@ -400,15 +397,48 @@ utils.prototype.arrayToRGBA = function (color) { return "rgba("+nowR+","+nowG+","+nowB+","+nowA+")"; } +utils.prototype._encodeRoute_id2number = function (id) { + var number = core.maps.getNumberById(id); + return number==0?id:number; +} + +utils.prototype._encodeRoute_encodeOne = function (t) { + if (t.indexOf('item:')==0) + return "I"+this._encodeRoute_id2number(t.substring(5))+":"; + else if (t.indexOf('unEquip:')==0) + return "u"+t.substring(8); + else if (t.indexOf('equip:')==0) + return "e"+this._encodeRoute_id2number(t.substring(6))+":"; + else if (t.indexOf('fly:')==0) + return "F"+t.substring(4)+":"; + else if (t.indexOf('choices:')==0) + return "C"+t.substring(8); + else if (t.indexOf('shop:')==0) + return "S"+t.substring(5); + else if (t=='turn') + return 'T'; + else if (t.indexOf('turn:')==0) + return "t"+t.substring(5).substring(0,1).toUpperCase()+":"; + else if (t=='getNext') + return 'G'; + else if (t.indexOf('input:')==0) + return "P"+t.substring(6); + else if (t.indexOf('input2:')==0) + return "Q"+t.substring(7)+":"; + else if (t=='no') + return 'N'; + else if (t.indexOf('move:')==0) + return "M"+t.substring(5); + else if (t.indexOf('key:')==0) + return 'K'+t.substring(4); + else if (t.indexOf('random:')==0) + return 'X'+t.substring(7); + return ''; +} + ////// 加密路线 ////// utils.prototype.encodeRoute = function (route) { - var ans=""; - var lastMove = "", cnt=0; - - var id2number = function (id) { - var number = core.maps.getNumberById(id); - return number==0?id:number; - } + var ans="", lastMove = "", cnt=0; route.forEach(function (t) { if (t=='up' || t=='down' || t=='left' || t=='right') { @@ -426,117 +456,85 @@ utils.prototype.encodeRoute = function (route) { if (cnt>1) ans+=cnt; cnt=0; } - if (t.indexOf('item:')==0) - ans+="I"+id2number(t.substring(5))+":"; - else if (t.indexOf('unEquip:')==0) - ans+="u"+t.substring(8); - else if (t.indexOf('equip:')==0) - ans+="e"+id2number(t.substring(6))+":"; - else if (t.indexOf('fly:')==0) - ans+="F"+t.substring(4)+":"; - else if (t.indexOf('choices:')==0) - ans+="C"+t.substring(8); - else if (t.indexOf('shop:')==0) - ans+="S"+t.substring(5); - else if (t=='turn') - ans+='T'; - else if (t.indexOf('turn:')==0) - ans+="t"+t.substring(5).substring(0,1).toUpperCase()+":"; - else if (t=='getNext') - ans+='G'; - else if (t.indexOf('input:')==0) - ans+="P"+t.substring(6); - else if (t.indexOf('input2:')==0) - ans+="Q"+t.substring(7)+":"; - else if (t=='no') - ans+='N'; - else if (t.indexOf('move:')==0) - ans+="M"+t.substring(5); - else if (t.indexOf('key:')==0) - ans+='K'+t.substring(4); - else if (t.indexOf('random:')==0) - ans+='X'+t.substring(7); + ans += core.utils._encodeRoute_encodeOne(t); } }); if (cnt>0) { ans+=lastMove.substring(0,1).toUpperCase(); if (cnt>1) ans+=cnt; } - // return ans; - // 压缩 return LZString.compressToBase64(ans); } +utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) { + var num=""; + while (decodeObj.index=0; +} + utils.prototype.clamp = function (x, a, b) { var min=Math.min(a, b), max=Math.max(a, b); return Math.min(Math.max(x||0, min), max); @@ -1043,3 +1045,57 @@ utils.prototype.http = function (type, url, formData, success, error, mimeType, xhr.send(formData); else xhr.send(); } + +// LZW-compress +// https://gist.github.com/revolunet/843889 +function lzw_encode(s) { + var dict = {}; + var data = (s + "").split(""); + var out = []; + var currChar; + var phrase = data[0]; + var code = 256; + for (var i=1; i 1 ? dict[phrase] : phrase.charCodeAt(0)); + dict[phrase + currChar] = code; + code++; + phrase=currChar; + } + } + out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0)); + for (var i=0; i=1:直接扣数值" }, { - "type": "setValue", + "type": "setValue2", "name": "status:atk", - "value": "status:atk-core.values.weakValue" + "value": "-core.values.weakValue" }, { - "type": "setValue", + "type": "setValue2", "name": "status:def", - "value": "status:def-core.values.weakValue" + "value": "-core.values.weakValue" } ], "false": [ @@ -118,14 +118,14 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = "text": "<1:扣比例" }, { - "type": "setValue", - "name": "flag:equip_atk_buff", - "value": "core.getFlag('equip_atk_buff',1)-core.values.weakValue" + "type": "setValue2", + "name": "flag:__atk_buff__", + "value": "-core.values.weakValue" }, { - "type": "setValue", - "name": "flag:equip_def_buff", - "value": "core.getFlag('equip_def_buff',1)-core.values.weakValue" + "type": "setValue2", + "name": "flag:__def_buff__", + "value": "-core.values.weakValue" } ] } diff --git a/project/functions.js b/project/functions.js index e55d3f73..f0561da5 100644 --- a/project/functions.js +++ b/project/functions.js @@ -34,22 +34,28 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = }, "setInitData": function (hard) { // 不同难度分别设置初始属性 - if (hard=='Easy') { // 简单难度 + if (hard == 'Easy') { // 简单难度 core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 // 可以在此设置一些初始福利,比如设置初始生命值可以调用: // core.setStatus("hp", 10000); // 赠送一把黄钥匙可以调用 // core.setItem("yellowKey", 1); } - if (hard=='Normal') { // 普通难度 + if (hard == 'Normal') { // 普通难度 core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度 } - if (hard=='Hard') { // 困难难度 + if (hard == 'Hard') { // 困难难度 core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度 } - if (hard=='Hell') { // 噩梦难度 + if (hard == 'Hell') { // 噩梦难度 core.setFlag('hard', 4); // 可以用flag:hard来获得当前难度 } + + // 设置三围的初始增幅属性(均为1) + ["atk", "def", "mdef"].forEach(function (name) { + core.setFlag("__" + name + "_buff__", 1); + }); + core.events.afterLoadData(); }, "win": function(reason, norank) { @@ -172,22 +178,23 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.setFlag('point', point); // 设置flag:point return core.getCommonEvent('加点事件'); }, - "afterBattle": function(enemyId,x,y,callback) { + "afterBattle": function (enemyId, x, y, callback) { // 战斗结束后触发的事件 var enemy = core.material.enemys[enemyId]; // 播放战斗音效和动画 - var equipAnimate = 'hand', equipId = (core.status.hero.equipment||[])[0]; - if (core.isset(equipId) && core.isset((core.material.items[equipId].equip||{}).animate)) + var equipAnimate = 'hand', + equipId = (core.status.hero.equipment || [])[0]; + if (core.isset(equipId) && core.isset((core.material.items[equipId].equip || {}).animate)) equipAnimate = core.material.items[equipId].equip.animate; // 检查equipAnimate是否存在SE,如果不存在则使用默认音效 - if (!core.isset((core.material.animates[equipAnimate]||{}).se)) + if (!core.isset((core.material.animates[equipAnimate] || {}).se)) core.playSound('attack.mp3'); core.drawAnimate(equipAnimate, x, y); var damage = core.enemys.getDamage(enemyId, x, y); - if (damage == null) damage = core.status.hero.hp+1; + if (damage == null) damage = core.status.hero.hp + 1; // 扣减体力值 core.status.hero.hp -= damage; @@ -196,20 +203,35 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.hero.statistics.battleDamage += damage; core.status.hero.statistics.battle++; - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; + if (core.status.hero.hp <= 0) { + core.status.hero.hp = 0; core.updateStatusBar(); core.events.lose('战斗失败'); return; } + + // 删除该块 + var guards = []; // 支援 + if (core.isset(x) && core.isset(y)) { + core.removeBlock(x, y); + guards = core.getFlag("__guards__" + x + "_" + y, []); + core.removeFlag("__guards__" + x + "_" + y); + } + // 获得金币和经验 var money = enemy.money; + guards.forEach(function (g) { + money += core.material.enemys[g[2]].money; + }); if (core.hasItem('coin')) money *= 2; - if (core.hasFlag('curse')) money=0; + if (core.hasFlag('curse')) money = 0; core.status.hero.money += money; core.status.hero.statistics.money += money; - var experience =enemy.experience; - if (core.hasFlag('curse')) experience=0; + var experience = enemy.experience; + guards.forEach(function (g) { + experience += core.material.enemys[g[2]].experience; + }) + if (core.hasFlag('curse')) experience = 0; core.status.hero.experience += experience; core.status.hero.statistics.experience += experience; var hint = "打败 " + enemy.name; @@ -219,33 +241,28 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = hint += ",经验+" + experience; core.drawTip(hint); - // 删除该块 - if (core.isset(x) && core.isset(y)) { - core.removeBlock(x, y); - } - // 事件的处理 var todo = []; var special = enemy.special; // 中毒 if (core.enemys.hasSpecial(special, 12)) { - core.push(todo, [{"type": "setValue", "name": "flag:debuff", "value": "'poison'"}]); - core.push(todo, [{"type": "insert", "name": "毒衰咒处理"}]); + core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'poison'" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); } // 衰弱 if (core.enemys.hasSpecial(special, 13)) { - core.push(todo, [{"type": "setValue", "name": "flag:debuff", "value": "'weak'"}]); - core.push(todo, [{"type": "insert", "name": "毒衰咒处理"}]); + core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'weak'" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); } // 诅咒 if (core.enemys.hasSpecial(special, 14)) { - core.push(todo, [{"type": "setValue", "name": "flag:debuff", "value": "'curse'"}]); - core.push(todo, [{"type": "insert", "name": "毒衰咒处理"}]); + core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'curse'" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); } // 仇恨属性:减半 if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) { - core.setFlag('hatred', parseInt(core.getFlag('hatred', 0)/2)); + core.setFlag('hatred', parseInt(core.getFlag('hatred', 0) / 2)); } // 自爆 if (core.enemys.hasSpecial(special, 19)) { @@ -253,20 +270,20 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 退化 if (core.enemys.hasSpecial(special, 21)) { - core.status.hero.atk -= (enemy.atkValue||0); - core.status.hero.def -= (enemy.defValue||0); - if (core.status.hero.atk<0) core.status.hero.atk=0; - if (core.status.hero.def<0) core.status.hero.def=0; + core.status.hero.atk -= (enemy.atkValue || 0); + core.status.hero.def -= (enemy.defValue || 0); + if (core.status.hero.atk < 0) core.status.hero.atk = 0; + if (core.status.hero.def < 0) core.status.hero.def = 0; } // 增加仇恨值 - core.setFlag('hatred', core.getFlag('hatred',0)+core.values.hatred); - + core.setFlag('hatred', core.getFlag('hatred', 0) + core.values.hatred); + // 战后的技能处理,比如扣除魔力值 if (core.flags.enableSkill) { // 检测当前开启的技能类型 var skill = core.getFlag('skill', 0); - if (skill==1) { // 技能1:二倍斩 - core.status.hero.mana-=5; // 扣除5点魔力值 + if (skill == 1) { // 技能1:二倍斩 + core.status.hero.mana -= 5; // 扣除5点魔力值 } // 关闭技能 core.setFlag('skill', 0); @@ -276,14 +293,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果有加点 var point = core.material.enemys[enemyId].point; - if (core.flags.enableAddPoint && core.isset(point) && point>0) { - core.push(todo, [{"type": "setValue", "name": "flag:point", "value": point}]); - core.push(todo, [{"type": "insert", "name": "加点事件"}]); + if (core.flags.enableAddPoint && core.isset(point) && point > 0) { + core.push(todo, [{ "type": "setValue", "name": "flag:point", "value": point }]); + core.push(todo, [{ "type": "insert", "name": "加点事件" }]); } // 如果该点存在,且有事件 -- V2.5.4 以后阻击怪也可以有战后事件了 if (core.isset(x) && core.isset(y)) { - core.push(todo, core.floors[core.status.floorId].afterBattle[x+","+y]); + core.push(todo, core.floors[core.status.floorId].afterBattle[x + "," + y]); } // 在这里增加其他的自定义事件需求 @@ -296,15 +313,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = */ // 如果事件不为空,将其插入 - if (todo.length>0) { - core.events.insertAction(todo,x,y); + if (todo.length > 0) { + core.events.insertAction(todo, x, y); } // 如果已有事件正在处理中 if (core.status.event.id == null) { core.continueAutomaticRoute(); - } - else { + } else { core.clearContinueAutomaticRoute(); } if (core.isset(callback)) callback(); @@ -417,7 +433,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } }, "enemys": { - "getSpecials": function() { + "getSpecials": function () { // 获得怪物的特殊属性,每一行定义一个特殊属性。 // 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述 // 可以直接写字符串,也可以写个function将怪物传进去 @@ -427,29 +443,31 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = [3, "坚固", "勇士每回合最多只能对怪物造成1点伤害"], [4, "2连击", "怪物每回合攻击2次"], [5, "3连击", "怪物每回合攻击3次"], - [6, function(enemy) {return (enemy.n||4)+"连击";}, function(enemy) {return "怪物每回合攻击"+(enemy.n||4)+"次";}], - [7, "破甲", "战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害"], - [8, "反击", "战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御"], - [9, "净化", "战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害"], + [6, function (enemy) { return (enemy.n || 4) + "连击"; }, function (enemy) { return "怪物每回合攻击" + (enemy.n || 4) + "次"; }], + [7, "破甲", "战斗前,怪物附加角色防御的" + Math.floor(100 * core.values.breakArmor || 0) + "%作为伤害"], + [8, "反击", "战斗时,怪物每回合附加角色攻击的" + Math.floor(100 * core.values.counterAttack || 0) + "%作为伤害,无视角色防御"], + [9, "净化", "战斗前,怪物附加勇士魔防的" + core.values.purify + "倍作为伤害"], [10, "模仿", "怪物的攻防和勇士攻防相等"], - [11, "吸血", function (enemy) {return "战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命(约" + Math.floor((enemy.value||0)*core.getStatus('hp')) + "点)作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");}], - [12, "中毒", "战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点"], - [13, "衰弱", "战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%")], + [11, "吸血", function (enemy) { return "战斗前,怪物首先吸取角色的" + Math.floor(100 * enemy.value || 0) + "%生命(约" + Math.floor((enemy.value || 0) * core.getStatus('hp')) + "点)作为伤害" + (enemy.add ? ",并把伤害数值加到自身生命上" : ""); }], + [12, "中毒", "战斗后,勇士陷入中毒状态,每一步损失生命" + core.values.poisonDamage + "点"], + [13, "衰弱", "战斗后,勇士陷入衰弱状态,攻防暂时下降" + (core.values.weakValue >= 1 ? core.values.weakValue + "点" : parseInt(core.values.weakValue * 100) + "%")], [14, "诅咒", "战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验"], - [15, "领域", function (enemy) {return "经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";}], + [15, "领域", function (enemy) { return "经过怪物周围" + (enemy.range || 1) + "格时自动减生命" + (enemy.value || 0) + "点"; }], [16, "夹击", "经过两只相同的怪物中间,勇士生命值变成一半"], - [17, "仇恨", "战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)"], - [18, "阻击", function (enemy) {return "经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";}], + [17, "仇恨", "战斗前,怪物附加之前积累的仇恨值作为伤害" + (core.flags.hatredDecrease ? ";战斗后,释放一半的仇恨值" : "") + "。(每杀死一个怪物获得" + (core.values.hatred || 0) + "点仇恨值)"], + [18, "阻击", function (enemy) { return "经过怪物的十字领域时自动减生命" + (enemy.value || 0) + "点,同时怪物后退一格"; }], [19, "自爆", "战斗后勇士的生命值变成1"], [20, "无敌", "勇士无法打败怪物,除非拥有十字架"], - [21, "退化", function (enemy) {return "战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";}], - [22, "固伤", function (enemy) {return "战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";}], + [21, "退化", function (enemy) { return "战斗后勇士永久下降" + (enemy.atkValue || 0) + "点攻击和" + (enemy.defValue || 0) + "点防御"; }], + [22, "固伤", function (enemy) { return "战斗前,怪物对勇士造成" + (enemy.damage || 0) + "点固定伤害,无视勇士魔防。"; }], [23, "重生", "怪物被击败后,角色转换楼层则怪物将再次出现"], - [24, "激光", function (enemy) {return "经过怪物同行或同列时自动减生命"+(enemy.value||0)+"点";}], - [25, "光环", function (enemy) {return "同楼层所有怪物生命提升"+(enemy.value||0)+"%,攻击提升"+(enemy.atkValue||0)+"%,防御提升"+(enemy.defValue||0)+"%,"+(enemy.add?"可叠加":"不可叠加");}] + [24, "激光", function (enemy) { return "经过怪物同行或同列时自动减生命" + (enemy.value || 0) + "点"; }], + [25, "光环", function (enemy) { return "同楼层所有怪物生命提升" + (enemy.value || 0) + "%,攻击提升" + (enemy.atkValue || 0) + "%,防御提升" + (enemy.defValue || 0) + "%," + (enemy.add ? "可叠加" : "不可叠加"); }], + [26, "支援", "当周围一圈的怪物受到攻击时将上前支援,并组成小队战斗。"], + [27, "捕捉", "当走到怪物周围十字时会强制进行战斗。"] ]; }, - "getEnemyInfo": function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { + "getEnemyInfo": function (enemy, hero, x, y, floorId) { // 获得某个怪物变化后的数据;该函数将被伤害计算和怪物手册使用 // 例如:坚固、模仿、仿攻等等 // @@ -460,8 +478,18 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // floorId:该怪物所在的楼层 // 后面三个参数主要是可以在光环等效果上可以适用(也可以按需制作部分范围光环效果) floorId = floorId || core.status.floorId; - var mon_hp = enemy.hp, mon_atk = enemy.atk, mon_def = enemy.def, mon_special = enemy.special; - var mon_money = enemy.money, mon_experience = enemy.experience, mon_point = enemy.point; + var hero_hp = core.getRealStatusOrDefault(hero, 'hp'), + hero_atk = core.getRealStatusOrDefault(hero, 'atk'), + hero_def = core.getRealStatusOrDefault(hero, 'def'), + hero_mdef = core.getRealStatusOrDefault(hero, 'mdef'); + + var mon_hp = enemy.hp, + mon_atk = enemy.atk, + mon_def = enemy.def, + mon_special = enemy.special; + var mon_money = enemy.money, + mon_experience = enemy.experience, + mon_point = enemy.point; // 模仿 if (core.hasSpecial(mon_special, 10)) { mon_atk = hero_atk; @@ -471,21 +499,27 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.hasSpecial(mon_special, 3) && mon_def < hero_atk - 1) { mon_def = hero_atk - 1; } - + // 光环检查 // 从V2.5.4开始,对光环效果增加缓存,以解决多次重复计算的问题,从而大幅提升运行效率。 // 检查当前楼层所有光环怪物(数字25) - var hp_buff = 0, atk_buff = 0, def_buff = 0, cnt = 0; + var hp_buff = 0, + atk_buff = 0, + def_buff = 0, + cnt = 0; + // ------ 支援 ------ + var guards = []; // 检查光环缓存 - if (!core.isset(core.status.checkBlock.buff)) core.status.checkBlock.buff = {}; - var index = core.isset(x) && core.isset(y) ? (x+","+y) : "floor"; - var cache = core.status.checkBlock.buff[index]; + if (!core.isset(core.status.checkBlock.cache)) core.status.checkBlock.cache = {}; + var index = core.isset(x) && core.isset(y) ? (x + "," + y) : "floor"; + var cache = core.status.checkBlock.cache[index]; if (!core.isset(cache)) { // 没有该点的缓存,则遍历每个图块 core.status.maps[floorId].blocks.forEach(function (block) { if (core.isset(block.event) && !block.disable) { // 获得该图块的ID - var id = block.event.id, enemy = core.material.enemys[id]; + var id = block.event.id, + enemy = core.material.enemys[id]; // 检查是不是怪物,且是否拥有该特殊属性 if (core.isset(enemy) && core.hasSpecial(enemy.special, 25)) { // 检查是否可叠加 @@ -496,34 +530,42 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = cnt++; } } + // 检查【支援】技能 + if (core.isset(enemy) && core.hasSpecial(enemy.special, 26) && + // 检查支援条件,坐标存在,距离为1,且不能是自己 + // 其他类型的支援怪,比如十字之类的话.... 看着做是一样的 + core.isset(x) && core.isset(y) && Math.abs(block.x - x) <= 1 && Math.abs(block.y - y) <= 1 && !(x == block.x && y == block.y)) { + // 记录怪物的x,y,ID + guards.push([block.x, block.y, id]); + } + + // TODO:如果有其他类型光环怪物在这里仿照添加检查 } }); - - // TODO:如果有其他类型光环怪物在这里仿照添加检查,hp_buff, atk_buff和def_buff即可。 - + // 放入缓存中 - core.status.checkBlock.buff[index] = {"hp_buff": hp_buff, "atk_buff": atk_buff, "def_buff": def_buff}; - } - else { + core.status.checkBlock.cache[index] = { "hp_buff": hp_buff, "atk_buff": atk_buff, "def_buff": def_buff, "guards": guards }; + } else { // 直接使用缓存数据 hp_buff = cache.hp_buff; atk_buff = cache.atk_buff; def_buff = cache.def_buff; + guards = cache.guards; } - + // 增加比例;如果要增加数值可以直接在这里修改 - mon_hp *= (1+hp_buff/100); - mon_atk *= (1+atk_buff/100); - mon_def *= (1+def_buff/100); - - + mon_hp *= (1 + hp_buff / 100); + mon_atk *= (1 + atk_buff / 100); + mon_def *= (1 + def_buff / 100); + + // TODO:可以在这里新增其他的怪物数据变化 // 比如仿攻(怪物攻击不低于勇士攻击): // if (core.hasSpecial(mon_special, 27) && mon_atk < hero_atk) { // mon_atk = hero_atk; // } // 也可以按需增加各种自定义内容(比如幻塔的魔杖效果等) - + return { "hp": Math.floor(mon_hp), "atk": Math.floor(mon_atk), @@ -531,45 +573,52 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = "money": Math.floor(mon_money), "experience": Math.floor(mon_experience), "point": Math.floor(mon_point), - "special": mon_special + "special": mon_special, + "guards": guards, // 返回支援情况 }; }, - "getDamageInfo": function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { + "getDamageInfo": function (enemy, hero, x, y, floorId) { // 获得战斗伤害信息(实际伤害计算函数) // // 参数说明: // enemy:该怪物信息 - // hero_hp,hero_atk,hero_def,hero_mdef:勇士的生命攻防魔防数据 + // hero:勇士的当前数据;如果对应项不存在则会从core.status.hero中取。 // x,y:该怪物的坐标(查看手册和强制战斗时为undefined) // floorId:该怪物所在的楼层 // 后面三个参数主要是可以在光环等效果上可以适用 - floorId = floorId || core.status.floorId; + floorId = floorId || core.status.floorId; + + var hero_hp = core.getRealStatusOrDefault(hero, 'hp'), + hero_atk = core.getRealStatusOrDefault(hero, 'atk'), + hero_def = core.getRealStatusOrDefault(hero, 'def'), + hero_mdef = core.getRealStatusOrDefault(hero, 'mdef'), + origin_hero_hp = hero_hp, + origin_hero_atk = hero_atk, + origin_hero_def = hero_def; // 勇士的负属性都按0计算 - hero_hp=Math.max(0, hero_hp); - hero_atk=Math.max(0, hero_atk); - hero_def=Math.max(0, hero_def); - hero_mdef=Math.max(0, hero_mdef); + hero_hp = Math.max(0, hero_hp); + hero_atk = Math.max(0, hero_atk); + hero_def = Math.max(0, hero_def); + hero_mdef = Math.max(0, hero_mdef); - // 计算装备按比例增加属性后的数值 - hero_atk = Math.floor(core.getFlag('equip_atk_buff',1)*hero_atk); - hero_def = Math.floor(core.getFlag('equip_def_buff',1)*hero_def); - hero_mdef = Math.floor(core.getFlag('equip_mdef_buff',1)*hero_mdef); - // 怪物的各项数据 // 对坚固模仿等处理扔到了脚本编辑-getEnemyInfo之中 - var enemyInfo = core.enemys.getEnemyInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId); - var mon_hp = enemyInfo.hp, mon_atk = enemyInfo.atk, mon_def = enemyInfo.def, mon_special = enemyInfo.special; - + var enemyInfo = core.enemys.getEnemyInfo(enemy, hero, x, y, floorId); + var mon_hp = enemyInfo.hp, + mon_atk = enemyInfo.atk, + mon_def = enemyInfo.def, + mon_special = enemyInfo.special; + // 技能的处理 - if (core.getFlag('skill', 0)==1) { // 开启了技能1:二倍斩 + if (core.getFlag('skill', 0) == 1) { // 开启了技能1:二倍斩 hero_atk *= 2; // 计算时攻击力翻倍 } // 如果是无敌属性,且勇士未持有十字架 if (core.hasSpecial(mon_special, 20) && !core.hasItem("cross")) return null; // 不可战斗 - + // 战前造成的额外伤害(可被魔防抵消) var init_damage = 0; @@ -599,7 +648,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 2连击 & 3连击 & N连击 if (core.hasSpecial(mon_special, 4)) per_damage *= 2; if (core.hasSpecial(mon_special, 5)) per_damage *= 3; - if (core.hasSpecial(mon_special, 6)) per_damage *= (enemy.n||4); + if (core.hasSpecial(mon_special, 6)) per_damage *= (enemy.n || 4); // 每回合的反击伤害;反击是按照勇士的攻击次数来计算回合 var counterDamage = 0; @@ -624,6 +673,38 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 勇士的攻击回合数;为怪物生命除以每回合伤害向上取整 var turn = Math.ceil(mon_hp / hero_per_damage); + + // ------ 支援 ----- // + // 这个递归最好想明白为什么,flag:extra_turn是怎么用的 + var guards = core.getFlag("__guards__" + x + "_" + y, enemyInfo.guards); + var guard_before_current_enemy = false; // ------ 支援怪是先打(true)还是后打(false)? + turn += core.getFlag("__extraTurn__", 0); + if (guards.length > 0) { + if (!guard_before_current_enemy) { // --- 先打当前怪物,记录当前回合数 + core.setFlag("__extraTurn__", turn); + } + // 获得那些怪物组成小队战斗 + for (var i = 0; i < guards.length; i++) { + var gx = guards[i][0], + gy = guards[i][1], + gid = guards[i][2]; + // 递归计算支援怪伤害信息,这里不传x,y保证不会重复调用 + // 这里的mdef传0,因为护盾应该只会被计算一次 + var info = core.enemys.getDamageInfo(core.material.enemys[gid], origin_hero_hp, origin_hero_atk, origin_hero_def, 0); + if (info == null) { // 小队中任何一个怪物不可战斗,直接返回null + return null; + } + // 已经进行的回合数 + core.setFlag("__extraTurn__", info.turn); + init_damage += info.damage; + } + if (guard_before_current_enemy) { // --- 先打支援怪物,增加当前回合数 + turn += core.getFlag("__extraTurn__", 0); + } + } + core.removeFlag("__extraTurn__"); + // ------ 支援END ------ // + // 最终伤害:初始伤害 + 怪物对勇士造成的伤害 + 反击伤害 var damage = init_damage + (turn - 1) * per_damage + turn * counterDamage; // 再扣去魔防 @@ -631,7 +712,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 检查是否允许负伤 if (!core.flags.enableNegativeDamage) - damage=Math.max(0, damage); + damage = Math.max(0, damage); return { "mon_hp": Math.floor(mon_hp), @@ -777,7 +858,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = break; case 51: // 快捷键3: 飞 if (core.hasItem('centerFly')) { - core.events.useItem('centerFly'); + core.events.tryUseItem('centerFly'); } break; case 52: // 快捷键4:破冰/冰冻/地震/上下楼器/... 其他道具依次判断 @@ -878,12 +959,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 向下取整 if (core.isset(core.status.hero[item])) core.status.hero[item] = Math.floor(core.status.hero[item]); - // 装备按比例增加属性 - var value = Math.floor(core.getStatus(item)*core.getFlag('equip_'+item+'_buff',1)); // 大数据格式化; - core.statusBar[item].innerHTML = core.formatBigNumber(value); + core.statusBar[item].innerHTML = core.formatBigNumber(core.getRealStatus(item)); }); - + // 设置魔力值 if (core.flags.enableMana) { // 也可以使用flag:manaMax来表示最大魔力值;详见文档-个性化-技能塔的支持 @@ -902,14 +981,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果是自定义添加的状态栏,也需要在这里进行设置显示的数值 // 进阶 - if (core.flags.enableLevelUp && core.status.hero.lv=core.bigmap.width || ny<0 || ny>=core.bigmap.height) continue; + for (var dx = -range; dx <= range; dx++) { + for (var dy = -range; dy <= range; dy++) { + if (dx == 0 && dy == 0) continue; + var nx = x + dx, + ny = y + dy; + if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) continue; // 如果是十字领域,则还需要满足 |dx|+|dy|<=range - if (!zoneSquare && Math.abs(dx)+Math.abs(dy)>range) continue; - core.status.checkBlock.damage[nx+ny*core.bigmap.width]+=enemy.value||0; + if (!zoneSquare && Math.abs(dx) + Math.abs(dy) > range) continue; + core.status.checkBlock.damage[nx + ny * core.bigmap.width] += enemy.value || 0; } } } @@ -1003,25 +1084,38 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果要防止激光伤害,可以直接简单的将 flag:no_laser 设为true if (core.enemys.hasSpecial(enemy.special, 24) && !core.hasFlag("no_laser")) { // 检查同行和同列,增加激光伤害值 - for (var nx=0;nx=core.bigmap.width || ny<0 || ny>=core.bigmap.height || Math.abs(dx)+Math.abs(dy)>1) continue; - core.status.checkBlock.damage[nx+ny*core.bigmap.width]+=enemy.value||0; + for (var dx = -1; dx <= 1; dx++) { + for (var dy = -1; dy <= 1; dy++) { + if (dx == 0 && dy == 0) continue; + var nx = x + dx, + ny = y + dy; + if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height || Math.abs(dx) + Math.abs(dy) > 1) continue; + core.status.checkBlock.damage[nx + ny * core.bigmap.width] += enemy.value || 0; } } } + // 存在捕捉 + if (core.enemys.hasSpecial(enemy.special, 27)) { + // 给周围格子加上【捕捉】记号 + for (var dir in core.utils.scan) { + var nx = x + core.utils.scan[dir].x, + ny = y + core.utils.scan[dir].y; + if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) continue; + if (!core.isset(core.status.checkBlock.ambush[nx + ny * core.bigmap.width])) + core.status.checkBlock.ambush[nx + ny * core.bigmap.width] = []; + core.status.checkBlock.ambush[nx + ny * core.bigmap.width].push([x, y, id, dir]); + } + } } } } @@ -1030,15 +1124,15 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.checkBlock.betweenAttack = []; // 记录(x,y)点是否有夹击 // 如果要防止夹击伤害,可以简单的将 flag:no_betweenAttack 设为true if (!core.hasFlag('no_betweenAttack')) { - for (var x=0;x0 && x 0 && x < core.bigmap.width - 1) { + var id1 = core.status.checkBlock.map[x - 1 + core.bigmap.width * y], + id2 = core.status.checkBlock.map[x + 1 + core.bigmap.width * y]; + if (core.isset(id1) && core.isset(id2) && id1 == id2) { var enemy = core.material.enemys[id1]; if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { has = true; @@ -1046,10 +1140,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } // 检测上下是否存在相同的怪物,且拥有夹击属性 - if (y>0 && y 0 && y < core.bigmap.height - 1) { + var id1 = core.status.checkBlock.map[x + core.bigmap.width * (y - 1)], + id2 = core.status.checkBlock.map[x + core.bigmap.width * (y + 1)]; + if (core.isset(id1) && core.isset(id2) && id1 == id2) { var enemy = core.material.enemys[id1]; if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { has = true; @@ -1058,12 +1152,12 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 计算夹击伤害 if (has) { - core.status.checkBlock.betweenAttack[x+core.bigmap.width*y]=true; + core.status.checkBlock.betweenAttack[x + core.bigmap.width * y] = true; // 先扣除该点领域/阻击/激光造成的伤害,再算夹击 - var leftHp = core.status.hero.hp - core.status.checkBlock.damage[x+core.bigmap.width*y]; + var leftHp = core.status.hero.hp - core.status.checkBlock.damage[x + core.bigmap.width * y]; // 1血不夹;core.flags.betweenAttackCeil控制向上还是向下 - if (leftHp>1) - core.status.checkBlock.damage[x+core.bigmap.width*y] += Math.floor((leftHp+(core.flags.betweenAttackCeil?0:1))/2); + if (leftHp > 1) + core.status.checkBlock.damage[x + core.bigmap.width * y] += Math.floor((leftHp + (core.flags.betweenAttackCeil ? 0 : 1)) / 2); } } } @@ -1171,6 +1265,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = "drawAbout": function() { // 绘制“关于”界面 core.ui.closePanel(); + core.lockControl(); core.status.event.id = 'about'; var left = 48, top = 36, right = 416 - 2 * left, bottom = 416 - 2 * top; diff --git a/project/items.js b/project/items.js index 468f5e17..793296cb 100644 --- a/project/items.js +++ b/project/items.js @@ -368,13 +368,13 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "bigKey": "core.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});", "bomb": "core.playSound('bomb.mp3');\ncore.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.events.afterUseBomb();\n});", "hammer": "core.playSound('bomb.mp3');\ncore.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\tcore.events.afterUseBomb();\n});", - "centerFly": "core.playSound('centerFly.mp3');\ncore.clearMap('hero');\ncore.setHeroLoc('x', (core.bigmap.width||13)-1-core.getHeroLoc('x'));\ncore.setHeroLoc('y', (core.bigmap.height||13)-1-core.getHeroLoc('y'));\ncore.drawHero();\ncore.drawTip(core.material.items[itemId].name + '使用成功');", + "centerFly": "core.playSound('centerFly.mp3');\ncore.clearMap('hero');\ncore.setHeroLoc('x', core.bigmap.width-1-core.getHeroLoc('x'));\ncore.setHeroLoc('y', core.bigmap.height-1-core.getHeroLoc('y'));\ncore.drawHero();\ncore.drawTip(core.material.items[itemId].name + '使用成功');", "upFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.ui.x, 'y': core.status.event.ui.y};\nif (core.status.event.id == 'action') {\n\tcore.insertAction([\n\t\t{\"type\": \"changeFloor\", \"loc\": [loc.x, loc.y], \"direction\": loc.direction, \"floorId\": core.status.event.ui.id},\n\t\t{\"type\": \"tip\", \"text\": core.material.items[itemId].name + '使用成功'}\n\t]);\n}\nelse {\n\tcore.changeFloor(core.status.event.ui.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t\tcore.replay();\n\t});\n}", "downFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.ui.x, 'y': core.status.event.ui.y};\nif (core.status.event.id == 'action') {\n\tcore.insertAction([\n\t\t{\"type\": \"changeFloor\", \"loc\": [loc.x, loc.y], \"direction\": loc.direction, \"floorId\": core.status.event.ui.id},\n\t\t{\"type\": \"tip\", \"text\": core.material.items[itemId].name + '使用成功'}\n\t]);\n}\nelse {\n\tcore.changeFloor(core.status.event.ui.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t\tcore.replay();\n\t});\n}\n", "poisonWine": "core.removeFlag('poison');", - "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) + core.values.weakValue);\n\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) + core.values.weakValue);\n}", + "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.addFlag(\"__atk_buff__\", core.values.weakValue);\n\tcore.addFlag(\"__def_buff__\", core.values.weakValue);\n}", "curseWine": "core.removeFlag('curse');", - "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.setFlag(\"equip_atk_buff\", core.getFlag(\"equip_atk_buff\", 1) + core.values.weakValue);\n\t\tcore.setFlag(\"equip_def_buff\", core.getFlag(\"equip_def_buff\", 1) + core.values.weakValue);\n\t}\n}\ncore.removeFlag('curse');", + "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.addFlag(\"__atk_buff__\", core.values.weakValue);\n\t\tcore.addFlag(\"__def_buff__\", core.values.weakValue);\n\t}\n}\ncore.removeFlag('curse');", "lifeWand": "core.insertAction([\n\t{\"type\": \"input\", \"text\": \"请输入生命魔杖使用次数:(0-${item:lifeWand})\"},\n\t{\"type\": \"if\", \"condition\": \"flag:input<=item:lifeWand\",\n\t\t\"true\": [\n\t\t\t{\"type\": \"setValue\", \"name\": \"item:lifeWand\", \"value\": \"item:lifeWand-flag:input\"},\n\t\t\t{\"type\": \"setValue\", \"name\": \"status:hp\", \"value\": \"status:hp+flag:input*100\"},\n\t\t\t\"成功使用${flag:input}次生命魔杖,恢复${flag:input*100}点生命。\"\n\t\t],\n\t\t\"false\": [\"输入不合法!\"]\n\t},\n]);\ncore.addItem('lifeWand', 1);", "jumpShoes": "core.insertAction({\"type\":\"jumpHero\",\"loc\":[core.nextX(2),core.nextY(2)]});", "redPotion": "core.status.hero.hp += core.values.redPotion", @@ -395,9 +395,9 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "bomb": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", "hammer": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", "earthquake": "(function () {\n\tvar able=false;\n\tvar ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable &&\n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", - "centerFly": "(function () {\n\tvar toX = (core.bigmap.width||13)-1-core.getHeroLoc('x'), toY = (core.bigmap.height||13)-1-core.getHeroLoc('y');\n\tvar id = core.getBlockId(toX, toY);\n\treturn id == null;\n})();", - "upFly": "(function() {\n\tvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\n\tif (index=0 && toX=0 && toY0) {\n\t\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\t\tvar mw = core.floors[toId].width||13, mh = core.floors[toId].height||13;\n\t\tif (toX>=0 && toX=0 && toY=0 && toX=0 && toY0) {\n\t\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\t\tvar mw = core.floors[toId].width, mh = core.floors[toId].height;\n\t\tif (toX>=0 && toX=0 && toY0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", "bigKey": "(function() {\n\tvar able=false, ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", "poisonWine": "core.hasFlag('poison');",