Merge pull request #340 from ckcz123/v2.0

V2.6
This commit is contained in:
Zhang Chen 2019-04-04 23:15:52 +08:00 committed by GitHub
commit 051d313f96
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
60 changed files with 15498 additions and 13038 deletions

View File

@ -38,10 +38,12 @@ HTML5 canvas制作的魔塔样板支持全平台游戏
│ ├─ /sounds/ # 音效目录
│ ├─ data.js # 全局变量信息
│ ├─ enemys.js # 怪物属性数据
│ ├─ events.js # 公共事件
│ ├─ functions.js # 可能会被修改的脚本代码
│ ├─ icons.js # 素材和ID的对应关系定义
│ ├─ items.js # 道具的定义,获得道具的效果
│ └─ maps.js # 地图和数字的对应关系
│ ├─ maps.js # 地图和数字的对应关系
│ └─ plugins.js # 自定义插件
├── /常用工具/ # 一些常用工具,可以辅助造塔;具体可参见下面的【相关工具】
├── editor.html # 可视化地图编辑工具
├── editor-mobile.html # 可视化地图编辑工具(手机版)

689
_docs/_api.md Normal file
View File

@ -0,0 +1,689 @@
# 附录: API列表
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
**这里只列出所有可能会被造塔者用到的常用API更多的有关内容请在代码内进行查询。**
如有任何疑问,请联系小艾寻求帮助。
可以在chrome浏览器的控制台中`ctrl+shift+I`找到Console中直接进行调用以查看效果。
**以下所有异步API都会加上[异步]的说明,存在此说明的请勿在事件处理的自定义脚本中使用。**
!> 最常用的新手向命令,强烈建议每个人了解
``` text
core.status.floorId
获得当前层的floorId。
core.status.maps
获得所有楼层的地图信息。
core.status.thisMap
获得当前楼层信息其等价于core.status.maps[core.status.floorId]。
core.floors
获得所有楼层的信息。例如core.floors[core.status.floorId].events可获得本楼层的所有自定义事件。
core.status.hero
获得当前勇士状态信息。例如core.status.hero.atk就是当前勇士的攻击力数值。
core.material.enemys
获得所有怪物信息。例如core.material.enemys.greenSlime就是获得绿色史莱姆的属性数据。
core.material.items
获得所有道具的信息。
core.debug()
开启调试模式。此模式下可以按Ctrl键进行穿墙并忽略一切事件。
此模式下不可回放录像和上传成绩。
core.updateStatusBar()
立刻刷新状态栏和地图显伤。
core.setStatus('atk', 1000)
将攻击力设置为1000这里把atk可以改成hp, def, mdef, money, experience等等。
本句等价于 core.status.hero.atk = 1000
core.getStatus('atk')
返回当前攻击力数值。本句等价于 core.status.hero.atk。
core.setHeroLoc('x', 5)
设置勇士位置。这句话的意思是将勇士当前位置的横坐标设置为5。
同理可以设置勇士纵坐标 core.setHeroLoc('y', 3)。
值得注意的是,这句话虽然会使勇士改变位置,但并不会使界面重新绘制;如需立刻重新绘制地图还需调用:
core.clearMap('hero'); core.drawHero();
来对界面进行更新。
core.setItem('pickaxe', 10)
将破墙镐个数设置为10个。这里可以写任何道具的ID。
core.addItem('pickaxe', 2)
将破墙镐的个数增加2个无任何特效。这里可以写任何道具的ID。
core.getItem('pickaxe', 4)
令勇士获得4个破墙镐。这里可以写任何道具的ID。
和addItem相比使用getItem会播放获得道具的音效也会在左上角绘制获得提示。
core.removeItem('pickaxe', 3)
删除3个破墙镐。第二项可忽略默认值为1。
core.itemCount('pickaxe')
返回当前破墙镐的个数。这里可以写任何道具的ID。
core.hasItem('pickaxe')
返回当前是否存在某个道具。等价于 core.itemCount('pickaxe')>0 。
core.getEquip(0)
获得0号装备类型武器的当前装备的itemId。如果不存在则返回null。
这里可以写任意装备类型从0开始和全塔属性中的equipName一一对应。
core.hasEquip('sword1')
获得当前某个具体的装备是否处于正在被装备状态。
core.setFlag('xyz', 2)
设置某个flag/变量的值为2。这里可以写任何的flag变量名。
core.getFlag('xyz', 7)
获得某个flag/变量的值;如果该变量不存在,则返回第二个参数。
比如 core.getFlag('point', 2) 则获得变量point的值如果该变量从未定义过则返回2。
core.hasFlag('xyz')
返回是否存在某个变量且不为0。等价于 core.getFlag('xyz', 0)!=0 。
core.removeFlag('xyz')
删除某个flag/变量。
core.insertAction(list, x, y, callback)
插入并执行一段自定义事件。在这里你可以写任意的自定义事件列表,有关详细写法请参见文档-事件。
x和y如果设置则覆盖"当前事件点"的坐标callback如果设置则覆盖事件执行完毕后的回调函数。
例如: core.insertAction(["楼层切换", {"type":"changeFloor", "floorId": "MT3"}])
将依次显示剧情文本,并执行一个楼层切换的自定义事件。
--------
从V2.5.4开始提出了“公共事件”的说法,这里也可以插入一个公共事件名。
例如core.insertAction("毒衰咒处理") 将插入公共事件“毒衰咒处理”。
core.changeFloor(floorId, stair, heroLoc, time, callback) [异步]
立刻切换到指定楼层。
floorId为目标楼层IDstair为到达的目标楼梯heroLoc为到达的指定点time为动画时间callback为切换完毕后的回调。
例如:
core.changeFloor('MT2', 'upFloor', null, 600) 切换到MT2层的上楼点动画事件600ms
core.changeFloor('MT5', null, {'x': 3, 'y': 6}, 0) 无动画切换到MT5层的(3,6)位置。
core.resetMap()
重置当前楼层地图和楼层属性。
此函数参数有三种形式:
- 不加任何参数表示重置当前层core.resetMap()
- 加上一个floorId表示重置某一层core.resetMap("MT1")
- 使用一个数组表示重置若干层core.resetMap(["MT1", "MT2", "MT3"])
---------------------------
** 说明从V2.5.5开始存档方式发生了改变,在编辑器修改了地图后现在将直接生效,无需再重置地图。
R
录像回放的快捷键;这不是一个控制台命令,但是也把它放在这里供使用。
录像回放在修改地图或新增数据后会很有用。
```
!> 一些相对高级的命令,针对有一定脚本经验的人
``` text
========== 可直接从core中调用的最常被使用的函数 ==========
core.js实际上是所有API的入口路由核心API的实现在其他几个文件中core.js主要进行转发操作。
core.nextX(n)
获得勇士面向的第n个位置的x坐标n可以省略默认为1即正前方
core.nextY(n)
获得勇士面向的第n个位置的y坐标n可以省略默认为1即正前方
core.nearHero(x, y)
判断某个点是否和勇士的距离不超过1。
core.openDoor(id, x, y, needKey, callback) [异步]
尝试开门操作。id为目标点的IDx和y为坐标needKey表示是否需要使用钥匙callback为开门完毕后的回调函数。
id可为null代表使用地图上的值。
例如core.openDoor('yellowDoor', 10, 3, false, function() {console.log("1")})
此函数返回true代表成功开门并将执行callback回调返回false代表无法开门且不会执行回调函数。
core.battle(id, x, y, force, callback) [异步]
执行战斗事件。id为怪物的idx和y为坐标force为bool值表示是否是强制战斗callback为战斗完毕后的回调函数。
id可为null代表使用地图上的值。
例如core.battle('greenSlime', null, null, true)
core.trigger(x, y) [异步]
触发某个地点的事件。
core.isReplaying()
当前是否正在录像播放中
core.drawBlock(block)
重绘某个图块。block应为core.status.thisMap.blocks中的一项。
core.drawMap(floorId, callback)
重绘某一层的地图。floorId为要绘制楼层的floorIdcallback为绘制完毕后的回调函数。
core.terrainExists(x, y, id, floorId)
检测某个点是否存在(指定的)地形。
x和y为坐标id为地形ID可为null表示任意地形floorId为楼层ID可忽略表示当前楼层。
core.enemyExists(x, y, id, floorId)
检测某个点是否存在(指定的)怪物。
x和y为坐标id为怪物ID可为null表示任意怪物floorId为楼层ID可忽略表示当前楼层。
core.getBlock(x, y, floorId, showDisable)
获得某个点的当前图块信息。
x和y为坐标floorId为楼层ID可忽略或null表示当前楼层。
showDisable如果为true则对于禁用的点和事件也会进行返回。
如果该点不存在图块则返回null。
否则,返回值如下: {"index": xxx, "block": xxx}
其中index为该点在该楼层blocks数组中的索引block为该图块实际内容。
core.getBlockId(x, y, floorId, showDisable)
获得某个点的图块ID。
x和y为坐标floorId为楼层ID可忽略或null表示当前楼层。
showDisable如果为true则对于禁用的点和事件也会进行返回。
如果该点不存在图块则返回null否则返回该点的图块ID。
core.getBlockCls(x, y, floorId, showDisable)
获得某个点的图块cls。
x和y为坐标floorId为楼层ID可忽略或null表示当前楼层。
showDisable如果为true则对于禁用的点和事件也会进行返回。
如果该点不存在图块则返回null否则返回该点的图块cls。
core.showBlock(x, y, floorId)
将某个点从禁用变成启用状态。
core.hideBlock(x, y, floorId)
将某个点从启用变成禁用状态,但不会对其进行删除。
此函数不会实际将该块从地图中进行删除,而是将该点设置为禁用,以供以后可能的启用事件。
core.removeBlock(x, y, floorId)
将从启用变成禁用状态,并尽可能将其从地图上删除。
和hideBlock相比如果该点不存在自定义事件比如门或普通的怪物则将直接从地图中删除。
如果存在自定义事件,则简单的禁用它,以供以后可能的启用事件。
core.setBlock(number, x, y, floorId)
改变图块。number为要改变到的图块数字x和y为坐标floorId为楼层ID可忽略表示当前楼层。
core.useItem(itemId, noRoute, callback)
尝试使用某个道具。itemId为道具IDnoRoute如果为真则该道具的使用不计入录像。
callback为成功或失败后的回调。
core.canUseItem(itemId)
返回当前能否使用某个道具。
core.loadEquip(itemId, callback)
装备上某个装备。itemId为装备的IDcallback为成功或失败后的回调。
core.unloadEquip(equipType, callback)
卸下某个部位的装备。equipType为装备类型从0开始callback为成功或失败后的回调。
core.getNextItem()
轻按。
core.drawTip(text, itemIcon)
在左上角绘制一段提示信息2秒后消失。itemIcon为道具图标的索引。
core.drawText(contents, callback) [异步]
绘制一段文字。
不推荐使用此函数尽量使用core.insertAction(contents)来显示剧情文本。
core.closePanel()
结束一切事件和绘制关闭UI窗口返回游戏进程。
core.replaceText(text)
将一段文字中的${}进行计算并替换。
core.calValue(value, prefix, need, times)
计算表达式的实际值。这个函数可以传入status:atk等这样的参数。
core.getLocalStorage(key, defaultValue)
从localStorage中获得某个数据已被parse如果对应的key不存在则返回defaultValue。
core.getLocalForage(key, defaultValue, successCallback, errorCallback)
从localForage中获得某个数据已被parse如果对应的key不存在则返回defaultValue。
如果成功则通过successCallback回调失败则通过errorCallback回调。
core.hasSave(index)
判定当前某个存档位是否存在存档返回true/false。
index为存档编号0代表自动存档大于0则为正常的存档位。
core.clone(data)
深拷贝某个对象。
core.isset(x)
测试x是否不为null不为undefined也不为NaN。
core.rand(num)
使用伪种子生成伪随机数。该随机函数能被录像支持。
num如果设置大于0则生成一个[0, num-1]之间的数否则生成一个0到1之间的浮点数。
此函数为伪随机算法SL大法无效。即多次SL后调用的该函数返回的值都是相同的。
core.rand2(num)
使用系统的随机数算法得到的随机数。该随机函数能被录像支持。
num如果设置大于0则生成一个[0, num-1]之间的数否则生成一个0到2147483647之间的整数。
此函数使用了系统的Math.random()函数支持SL大法。
但是,此函数会将生成的随机数值存入录像,因此如果调用次数太多则会导致录像文件过大。
core.restart() [异步]
返回标题界面。
========== core.actions.XXX 和游戏控制相关的函数 ==========
actions.js主要用来进行用户交互行为的处理。
所有用户行为,比如按键、点击、滑动等等,都会被此文件接收并进行操作。
========== core.control.XXX 和游戏控制相关的函数 ==========
control.js主要用来进行游戏控制比如行走控制、自动寻路、存读档等等游戏核心内容。
core.control.setGameCanvasTranslate(canvasId, x, y)
设置大地图的偏移量
core.control.updateViewport()
更新大地图的可见区域
core.control.gatherFollowers()
立刻聚集所有的跟随者
core.control.replay()
回放下一个操作
========== core.enemys.XXX 和怪物相关的函数 ==========
enemys.js主要用来进行怪物相关的内容比如怪物的特殊属性伤害和临界计算等。
core.enemys.hasSpecial(special, test)
测试怪物是否含有某个特殊属性。
常见用法: core.enemys.hasSpecial(monster.special, 3) ## 测试是否拥有坚固
core.enemys.getSpecialText(enemyId)
返回一个列表包含该怪物ID对应的所有特殊属性。
core.enemys.getSpecialHint(enemy, special)
获得怪物某个(或全部)特殊属性的文字说明。
core.enemys.canBattle(enemyId, x, y, floorId)
返回当前能否战胜某个怪物。
后面三个参数是怪物坐标和楼层。
core.enemys.getDamage(enemyId, x, y, floorId)
返回当前对某个怪物的战斗伤害。如果无法战斗返回null。
后面三个参数是怪物坐标和楼层。
core.enemys.getExtraDamage(enemyId)
返回某个怪物会对勇士造成的额外伤害(不可被魔防抵消),例如仇恨、固伤等等。
core.enemys.nextCriticals(enemyId, number, x, y, floorId)
返回一个列表为接下来number可忽略默认为1个该怪物的临界值和临界减伤。
列表每一项类似 [x,y] 表示临界值为x且临界减伤为y。
如果无临界值,则返回空列表。
core.enemys.getDefDamage(enemyId, k, x, y, floorId)
获得k可忽略默认为1防减伤值。
core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId)
获得实际战斗信息,比如伤害,回合数,每回合伤害等等。
此函数是实际战斗过程的计算。
core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId)
获得在某个勇士属性下怪物伤害实际返回的是上面getDamageInfo中伤害的数值。
core.enemys.getCurrentEnemys(floorId)
获得某一层楼剩余所有怪物的信息(供怪物手册使用)
========== core.events.XXX 和事件相关的函数 ==========
events.js主要用来进行事件处理比如自定义事件以及某些条件下可能会被触发的事件。
大多数事件API都在脚本编辑中存在这里只列出部分比较重要的脚本编辑中不存在的API。
core.events.gameOver(ending, fromReplay)
游戏结束并上传的事件。
该函数将提问是否上传和是否下载录像,并返回标题界面。
core.events.doEvents(list, x, y, callback) [异步]
开始执行某个事件。
请不要执行此函数,尽量使用 core.insertAction(list, x, y, callback) 来开始执行一段事件。
core.events.doAction()
执行下一个事件。此函数中将对所有自定义事件类型分别处理。
core.events.getCommonEvent(name)
根据名称获得一个公共事件如果不存在对应的公共事件则返回null。
core.events.openShop(shopId, needVisited) [异步]
打开一个全局商店。needVisited表示是否需要该商店已被打开过。
core.events.disableQuickShop(shopId)
禁用一个全局商店
core.events.canUseQuickShop(shopId)
当前能否使用某个快捷商店
core.events.setHeroIcon(name)
设置勇士行走图
========== core.items.XXX 和道具相关的函数 ==========
items.js将处理和道具相关的内容比如道具的使用获取和删除等等。
core.items.compareEquipment(equipId1, equipId2)
比较两个装备的属性变化值
========== core.loader.XXX 和游戏加载相关的函数 ==========
loader.js将主要用来进行资源的加载比如加载音乐、图片、动画等等。
========== core.maps.XXX 和地图处理相关的函数 ==========
maps.js主要用来进行地图相关的的操作。包括绘制地图获取地图上的点等等。
core.maps.getNumberById(id)
根据ID来获得对应的数字。如果该ID不存在对应的数字则返回0。
core.maps.canMoveHero(x,y,direction,floorId)
判断能否前往某个方向。x,y为坐标可忽略为当前点direction为方向可忽略为当前方向。
floorId为楼层ID可忽略为当前楼层。
core.maps.canMoveDirectly(destX, destY)
判断当前能否瞬间移动到某个点。
该函数如果返回0则不可瞬间移动大于0则可以瞬间移动且返回值是跨度即少走的步数
core.maps.removeBlockById(index, floorId)
根据索引删除或禁用某块。
core.maps.removeBlockByIds(floorId, ids)
根据索引删除或禁用若干块。
core.maps.drawAnimate(name, x, y, callback)
播放一段动画name为动画名需在全塔属性注册x和y为坐标0-12之间callback可选为播放完毕的回调函数。
播放过程是异步的如需等待播放完毕请使用insertAction插入一条type:waitAsync事件。
此函数将随机返回一个数字id为此异步动画的唯一标识符。
core.maps.stopAnimate(id, doCallback)
立刻停止一个异步动画。
id为该动画的唯一标识符由drawAnimate函数返回doCallback可选若为true则会执行该动画所绑定的回调函数。
========== core.ui.XXX 和对话框绘制相关的函数 ==========
ui.js主要用来进行UI窗口的绘制比如对话框、怪物手册、楼传器、存读档界面等等。
core.ui.getContextByName(canvas)
根据画布名找到一个画布的context支持系统画布和自定义画布。如果不存在画布返回null。
也可以传画布的context自身则返回自己。
core.clearMap(name)
清空某个画布图层。
name为画布名可以是系统画布之一也可以是任意自定义动态创建的画布名还可以直接传画布的context本身。下同
如果name也可以是'all'若为all则为清空所有系统画布。
core.ui.fillText(name, text, x, y, style, font)
在某个画布上绘制一段文字。
text为要绘制的文本x,y为要绘制的坐标style可选为绘制的样式font可选为绘制的字体。下同
core.ui.fillBoldText(name, text, x, y, style, font)
在某个画布上绘制一个描黑边的文字。
core.ui.fillRect(name, x, y, width, height, style)
绘制一个矩形。style可选为绘制样式。
core.ui.strokeRect(name, x, y, width, height, style)
绘制一个矩形的边框。
core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth)
绘制一条线。lineWidth可选为线宽。
core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth)
绘制一个箭头。
core.ui.setFont(name, font) / core.ui.setLineWidth(name, lineWidth)
设置一个画布的字体/线宽。
core.ui.setAlpha(name, font) / core.ui.setOpacity(name, font)
设置一个画布的绘制不透明度和画布本身的不透明度。
两者区别如下:
- setAlpha是设置"接下来绘制的内容的不透明度"不会对已经绘制的内容产生影响。比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。
- setOpacity是设置"画布本身的不透明度"已经绘制的内容也会产生影响。比如我已经在UI层绘制了一段文字再setOpacity则也会看起来变得透明。
尽量不要对系统画布使用setOpacity因为会对已经绘制的内容产生影响自定义创建的画布则不受此限制。
core.ui.setFillStyle(name, style) / core.ui.setStrokeStyle(name, style)
设置一个画布的填充样式/描边样式。
core.ui.setTextAlign(name, align)
设置一个画布的文字对齐模式。
core.ui.calWidth(name, text, font)
计算一段文字在画布上的绘制宽度
font可选如果存在则会先设置该画布上的字体。
core.ui.drawImage(name, image, x, y, w, h, x1, y1, w1, h1)
在一个画布上绘制图片。
name为画布名可以是系统画布之一也可以是任意自定义动态创建的画布名还可以直接传画布的context本身。
image为要绘制的图片可以是一个全塔属性中定义的图片名会从images中去获取图片本身或者一个画布。
后面的8个坐标参数与canvas的drawImage的八个参数完全相同。
请查看 http://www.w3school.com.cn/html5/canvas_drawimage.asp 了解更多。
core.ui.createCanvas(name, x, y, width, height, zIndex)
动态创建一个画布。name为要创建的画布名如果已存在则会直接取用当前存在的。
x,y为创建的画布相对窗口左上角的像素坐标width,height为创建的长宽。
zIndex为创建的纵向高度关系到画布之间的覆盖z值高的将覆盖z值低的系统画布的z值可在个性化中查看。
返回创建的画布的context也可以通过core.dymCanvas[name]调用。
core.ui.relocateCanvas(name, x, y)
重新定位一个自定义画布。
core.ui.resizeCanvas(name, x, y)
重新设置一个自定义画布的大小。
core.ui.deleteCanvas(name)
删除一个自定义画布。
core.ui.deleteAllCanvas()
清空所有的自定义画布。
core.ui.drawThumbnail(floorId, canvas, blocks, x, y, size, heroLoc, heroIcon)
绘制一个缩略图,比如楼传器界面,存读档界面等情况。
floorId为目标楼层IDcanvas为要绘制到的图层blocks为要绘制的所有图块。
x,y为该图层开始绘制的起始点坐标size为每一格的像素heroLoc为勇士坐标heroIcon为勇士图标。
========== core.utils.XXX 工具类的辅助函数 ==========
utils.js主要用来进行一些辅助函数的计算。
core.utils.splitLines(canvas, text, maxLength, font)
自动切分长文本的换行。
canvas为图层text为要自动换行的内容maxLength为每行最长像素font为文本的字体。
core.utils.cropImage(image, size)
纵向对图片进行切分(裁剪)。
core.utils.push(a,b)
向某个数组后插入另一个数组或元素
core.utils.unshift(a, b)
向某个数组前插入另一个数组或元素
core.utils.encodeBase64(str)
Base64加密字符串
core.utils.decodeBase64(str)
Base64解密字符串
core.utils.formatBigNumber(x, onMap)
大数据的格式化
core.utils.subarray(a, b)
检查b是否是a的从头开始子串。
如果是则返回a删去b的一段否则返回null。
core.utils.same(a, b)
比较a和b两个对象是否相同
core.utils.clamp(x, a, b)
将x限制在[a,b]之间的范围内
core.utils.arrayToRGB(color)
将形如[255,0,0]之类的数组转成#FF0000这样的RGB形式。
core.utils.arrayToRGBA(color)
将形如[255,0,0,1]之类的数组转成rgba(255,0,0,1)这样的RGBA形式。
core.utils.encodeRoute(list)
压缩加密路线。可以使用core.encodeRoute(core.status.route)来压缩当前路线。
core.utils.decodeRoute(route)
解压缩(解密)路线。
core.utils.readFile(success, error, readType) [异步]
尝试请求读取一个本地文件内容。
success和error为成功/失败后的回调readType不设置则以文本读取否则以DataUrl形式读取。
core.utils.readFileContent(content) [异步]
文件读取完毕后的内容处理。
core.utils.download(filename, content)
尝试生成并下载一个文件。
core.utils.copy(data)
尝试复制一段文本到剪切板。
core.utils.http(type, url, formData, success, error) [异步]
发送一个异步HTTP请求。
type为'GET'或者'POST'url为目标地址formData如果是POST请求则为表单数据。
success为成功后的回调error为失败后的回调。
```

View File

@ -3,5 +3,5 @@
- [元件说明](element)
- [事件](event)
- [个性化](personalization)
- [V2.0版本介绍](V2.0)
- [脚本](script)
- [附录API列表](api)

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
# 元件说明
?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} *
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。
@ -56,6 +56,8 @@ type为该装备的类型必填和上面装备栏一一对应。例如0
atk/def/mdef为该装备分别增加的攻防魔防数值支持负数如果不加也可省略不写。
从V2.6开始可以拓展到任何勇士的属性如hpmax, atk, def, mdef, experience等等自行添加的属性包括攻速speed也能使用。
animate为该装备的攻击动画仅对type为0时有效。具体可参见[动画和天气系统](#动画和天气系统)。
percentage为该装备是否按比例增加属性。
@ -151,49 +153,13 @@ yellowWall, blueWall, whiteWall
怪物的特殊属性所对应的数字special在脚本编辑中的`getSpecials`中定义,请勿对已有的属性进行修改。
``` js
function() {
// 获得怪物的特殊属性,每一行定义一个特殊属性。
// 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述
// 可以直接写字符串也可以写个function将怪物传进去
return [
[1, "先攻", "怪物首先攻击"],
[2, "魔攻", "怪物无视勇士的防御"],
[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+"倍作为伤害"],
[10, "模仿", "怪物的攻防和勇士攻防相等"],
[11, "吸血", function (enemy) {return "战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(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)+"点";}],
[16, "夹击", "经过两只相同的怪物中间,勇士生命值变成一半"],
[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)+"点固定伤害,无视勇士魔防。";}],
[23, "重生", "怪物被击败后,角色转换楼层则怪物将再次出现"],
[24, "激光", function (enemy) {return "经过怪物同行或同列时自动减生命"+(enemy.value||0)+"点";}]
];
}
```
多属性可采用数组的写法,比如`'special': [1,3]`视为同时拥有先攻和坚固属性;`'special': [5,10,14,18]`视为拥有3连击、魔防、诅咒、阻击四个属性。
怪物可以负伤,在`data.js`的全局变量`enableNegativeDamage`中指定。
下面的`getSpecialHint`函数则给定了每个特殊属性的详细描述。这个描述将在怪物手册中看到。
怪物可以负伤,在全塔属性的全局变量`enableNegativeDamage`中指定。
打败怪物后可以进行加点操作。有关加点塔的制作可参见[加点事件](event#加点事件)。
如果`data.js`中的enableExperience为false即不启用经验的话怪物手册里将不显示怪物的经验值打败怪物也不获得任何经验。
如果全塔属性中的enableExperience为false即不启用经验的话怪物手册里将不显示怪物的经验值打败怪物也不获得任何经验。
拿到幸运金币后,打怪获得的金币将翻倍。
@ -286,16 +252,12 @@ N连击怪物的special是6且我们可以为它定义n代表实际连击数
## 路障,楼梯,传送门
血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在 `data.js` 的values内定义。
血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在全塔属性的values内定义。
路障同样会尽量被自动寻路绕过。
有关楼梯和传送门必须在该层样板的changeFloor里指定传送点的目标。
![楼层转换](./img/changefloor.png)
!> **请注意这里的`"x,y"`代表该点的横坐标为x纵坐标为y即从左到右第x列从上到下的第y行从0开始计算。如(6,0)代表最上面一行的正中间一列。**
floorId指定的是目标楼层的唯一标识符ID
也可以写`"floorId": ":before"`和`"floorId": ":next"`表示上一楼和下一楼。
@ -347,7 +309,7 @@ floorId指定的是目标楼层的唯一标识符ID
从V2.4开始H5魔塔开始支持大地图。
大地图在创建时可以指定宽高,要求**宽和高都不得小于13且宽高之积不超过1000**。
大地图在创建时可以指定宽高,要求**宽和高都不得小于1315x15版本则是不小于15且宽高之积不超过1000**。
大地图一旦创建成功则不得修改宽高数值。
@ -355,13 +317,12 @@ floorId指定的是目标楼层的唯一标识符ID
现在我们的H5魔塔支持播放动画也支持天气系统了。
要播放动画你需要先使用“RM动画导出器”将动画导出放在animates目录下然后再data.js中定义。
要播放动画你需要先使用“RM动画导出器”将动画导出放在animates目录下然后在全塔属性的animates中定义。
``` js
"animates": [// 在此存放所有可能使用的动画必须是animate格式在这里不写后缀名
// 在此存放所有可能使用的动画必须是animate格式在这里不写后缀名
// 动画必须放在animates目录下文件名不能使用中文不能带空格或特殊字符
"hand", "sword", "zone", "yongchang", "thunder" // 根据需求自行添加
]
"animates": ["hand", "sword", "zone", "yongchang", "thunder"]
```
!> 动画必须是animate格式名称不能使用中文不能带空格或特殊字符。
@ -376,9 +337,9 @@ floorId指定的是目标楼层的唯一标识符ID
!> 播放录像时,将默认忽略所有动画。
目前天气系统支持雨和雪两种天气。
目前天气系统支持雨和雪和雾两种天气。
在每层楼的剧本文件里存在一个weather选项表示该层楼的默认天气。
在每层楼的楼层属性中存在一个weather选项表示该层楼的默认天气。
``` js
// 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain""snow"或"fog"代表雨雪雾第二项为1-10之间的数代表强度。
@ -394,24 +355,18 @@ floorId指定的是目标楼层的唯一标识符ID
要播放音乐和音效你需要将对应的文件放在sounds目录下然后在全塔属性中进行定义
``` js
"bgms": [ // 在此存放所有的bgm和文件名一致。
// 在此存放所有的bgm和文件名一致。
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
'bgm.mp3'
];
"sounds": [ // 在此存放所有的SE和文件名一致
// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好
'floor.mp3', 'attack.mp3', 'door.mp3', 'item.mp3', 'zone.mp3'
]
"bgms": ["bgm.mp3"]
// 在此存放所有的SE和文件名一致
"sounds": ["floor.mp3", "attack.mp3", "door.mp3", "item.mp3", "zone.mp3"]
```
!> 音频名不能使用中文,不能带空格或特殊字符。
目前BGM支持主流的音乐格式如mp3, ogg,格式等。不支持mid格式的播放。
<!--
!> mid格式是通过数学方法模拟出来的音乐效果质量可能会和实际效果差距较大。
目前BGM支持主流的音乐格式如mp3, ogg等。不支持mid格式的播放。
!> **警告!** mid格式在手机端播放可能会特别卡仍推荐直接使用mp3/ogg来播放。
-->
定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。
**另外,考虑到用户的流量问题,将遵循如下规则:**
@ -443,7 +398,7 @@ HTML5魔塔一大亮点就是存在录像系统可以很方便进行录像回
录像的回放主要有两种方式:
1. 保存成的录像文件(.h5route文件):在标题界面点录像回放,再选择文件即可。
2. 游戏过程中时的当前录像随时按R可以进行回放手机端则长按任何位置3秒以上调出虚拟键盘再按R。
2. 游戏过程中时的当前录像随时按R可以进行回放手机端则调出虚拟键盘再按R。
录像播放过程中,可以进行如下操作:
@ -474,6 +429,9 @@ HTML5魔塔一大亮点就是存在录像系统可以很方便进行录像回
## 操作说明
![](img/keyboard.png)
<!--
本塔主要支持鼠标(触摸屏)操作和键盘操作。
鼠标(触摸屏)操作说明如下:
@ -511,6 +469,7 @@ HTML5魔塔一大亮点就是存在录像系统可以很方便进行录像回
- **[Alt+0~9]** 快捷换装
以上快捷键也能在游戏菜单中的操作说明中看到。
-->
&nbsp;

File diff suppressed because it is too large Load Diff

BIN
_docs/img/console.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
_docs/img/console1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

BIN
_docs/img/elements.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
_docs/img/keyboard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

BIN
_docs/img/plugin.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
_docs/img/sources.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

View File

@ -1,11 +1,10 @@
# HTML5 魔塔样板说明文档
?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} *
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
众所周知魔塔的趋势是向移动端发展贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中NekoRPG有着比较大的局限性游戏感较差更是完全没法在iOS上运行。而一些APP的魔塔虽然可用但是必须要下载安装对于Android和iOS还必须开发不同的版本非常麻烦。
但是现在我们有了HTML5。 HTML5的画布canvas以及它被Android/iOS内置浏览器所支持的特性可以让我们做出真正意义上的全平台覆盖的魔塔。
事实上在贴吧的试水发布也证明了H5魔塔确实是可以成功的。两部即使是复刻的魔塔也受到了不少人的追捧其流畅的手感和全平台支持的特性也让很多没办法打开电脑的人爱不释手。
然而一般而言使用非RMXP制作魔塔往往需要一定的编程技术HTML5魔塔自然也不例外。但是为了能让大家更加注重于“做塔”本身而不用考虑做塔以外的各种脚本问题我特意制作了这样一部HTML5的魔塔样板。

View File

@ -1,6 +1,6 @@
# 个性化
?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} *
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。
@ -21,10 +21,14 @@ HTML5魔塔是使用画布canvas来绘制存在若干个图层它们
- route**[D]**:路线层;主要用来绘制勇士的行走路线图。 (z-index: 95)
- paint**[D]**绘图层主要用来进行绘图模式。z-index: 95)
- curtain色调层用来控制当前楼层的画面色调 (z-index: 125)
- image1\~50**[D]**图片层用来绘制图片等操作。z-index: 100+code, 101~150也就是图片编号在1~25的在色调层之下26~50的在色调层之上
- uiUI层用来绘制一切UI窗口如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 160)
- image1\~50**[D]**图片层用来绘制图片等操作。z-index: 100+code, 101~150
- uiUI层用来绘制一切UI窗口如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 140)
- data数据层用来绘制一些顶层的或更新比较快的数据如左上角的提示战斗界面中数据的变化等等。 (z-index: 170)
请注意显示图片事件将自动创建一个图片层z-index是100+图片编号。
色调层的z-index是25ui层的z-index是140因此图片编号在1~24的将被色调层遮挡25~40的将被ui层遮挡41~50的将遮挡UI层。
### 动态创建canvas
从V2.5.3开始可以在H5样板中任意动态创建canvas并进行使用。
@ -104,11 +108,11 @@ core.fillText('test', '这是一段文字', 10, 30, '#FF0000', '16px Verdana');
从V2.5.4开始,贴图也允许进行帧动画,只要设置第五项的数值。
``` js
"images": [[96,120,"bg.jpg",0]], // 背景图;你可以选择一张或多张图片来作为背景/前景素材。
"images": [], // 无任何背景图
"images": [[32,32,"house.png",0], [160,170,"bed.png",1]] // 在(32,32)放一个house.png在背景层且(160,170)放bed.png在前景层
"images": [[96,120,"tree.png",2]] // 如果写2则会自动调节遮挡效果
"images": [[64,0,"x.png",1,4]] // 这是一个前景层的4帧动画贴图
[[96,120,"bg.jpg",0]] // 背景图;你可以选择一张或多张图片来作为背景/前景素材。
[] // 无任何背景图
[[32,32,"house.png",0], [160,170,"bed.png",1]] // 在(32,32)放一个house.png在背景层且(160,170)放bed.png在前景层
[[96,120,"tree.png",2]] // 如果写2则会自动调节遮挡效果
[[64,0,"x.png",1,4]] // 这是一个前景层的4帧动画贴图
```
images为一个数组代表当前层所有作为背景素材的图片信息。每一项为一个五元组分别为该背景素材的xy图片名遮挡方式和帧数。
@ -129,18 +133,21 @@ images为一个数组代表当前层所有作为背景素材的图片信息
关于楼层贴图和前景、背景层的层叠覆盖关系,默认是:**地板 - 背景贴图 - 背景图块 - 事件 - 勇士 - 前景贴图 - 前景图块**。
可以通过修改`libs/maps.js`的`drawMap`函数中下面三行的顺序来改变其覆盖关系。
可以通过修改`libs/maps.js`的`drawBg`和`drawFg`函数来改变其覆盖关系。
``` js
// ----- 可以调整这三行的顺序来修改覆盖关系;同层画布上,后绘制的覆盖先绘制的
// ----- 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);
////// 绘制背景层 //////
maps.prototype.drawBg = function (floorId, ctx) {
var onMap = ctx == null;
if (onMap) {
ctx = core.canvas.bg;
core.clearMap(ctx);
}
this._drawBg_drawBackground(floorId, ctx);
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。
this._drawFloorImages(floorId, ctx, 'bg');
this._drawBgFgMap(floorId, ctx, 'bg', onMap);
}
```
楼层贴图可以被事件隐藏和显示,详见[隐藏贴图](event#hideFloorImg隐藏贴图)的写法。
@ -192,7 +199,7 @@ ID必须由数字字母下划线组成数字在1000以内且均不能和
之后刷新编辑器即可。
对于怪物和道具,我们也可以进行自动注册只需要点击“自动注册”按钮将对该栏下所有未注册的素材进行自动注册自动分配ID和数字
我们也可以进行自动注册只需要点击“自动注册”按钮将对该栏下所有未注册的素材进行自动注册自动分配ID和数字
素材注册完毕后,即可在游戏中正常使用,也可以被地图生成器所识别(需要重开地图生成器)。
@ -206,85 +213,6 @@ ID必须由数字字母下划线组成数字在1000以内且均不能和
2. 下拉框选择autotile然后点“追加”
3. 看到成功的提示后刷新编辑器即可。
<!--
1. 将新的Autotile图片复制到images目录下。文件名必须是字母数字和下划线组成。
2. 进入icons.js在autotile分类下进行添加该文件的名称索引简单的写0。
3. 指定一个数字在maps.js中类似进行添加。
!> Autotile的ID和文件名应确保完全相同
-->
<!--
#### 新添加自定义地形(路面、墙壁等)
如果你在terrains.png中新增了一行
1. 指定一个唯一的英文ID不能和现有的重复。
2. 进入icons.js在terrains分类下进行添加索引对应图标在图片上的位置即index
**如果你无须在游戏内使用本地形,而仅仅是将其作为“背景图”使用,则操作如下:**
3. 修改对应楼层的剧本文件的`defaultGround`项改成新的ID。
**如果你要在游戏内使用本地形,则操作如下:**
3. 指定一个数字在maps.js中类似进行添加。
#### 新添加Autotile
如果你需要新增一个Autotile
1. 将新的Autotile图片复制到images目录下。
2. 进入icons.js在autotile分类下进行添加该文件的名称索引简单的写0。
3. 指定一个数字在maps.js中类似进行添加。
!> Autotile的ID和文件名完全相同且其ID/文件名不能含有中文、空格或特殊字符。
!> V2.0版本不能在地图编辑器中添加Autotile请按上面的操作来执行。
#### 新添加道具
如果你需要新增一个未被定义的道具:
1. 指定一个唯一的英文ID不能和现有的重复。
2. 进入icons.js在items分类下进行添加索引对应图标在图片上的位置即index
3. 指定一个数字在maps.js中类似进行添加。
4. 在items.js中仿照其他道具来添加道具的信息。
有关如何自行实现一个道具的效果,参见[自定义道具效果](#自定义道具效果)。
#### 新添加怪物
如果我们需要新添加怪物请在enemys.png中新增一行。
你可以通过便捷PS工具的“更改色相”来将红头怪变成橙头怪等。
然后执行如下操作:
1. 指定一个唯一的英文ID不能和enemys中现有的重复。
2. 进入icons.js在enemys分类下进行添加索引对应图标在图片上的位置即index
3. 在maps.js中继续进行添加。
4. 在enemys.js中仿照其他怪物来添加怪物的信息。
!> 如果是48x32的怪物素材请放在enemy48.png中然后在icons.js的enemy48下添加索引。
有关如何自行实现一个怪物的特殊属性或伤害计算公式,参见[怪物的特殊属性](#怪物的特殊属性)。
#### 新添加NPC
1. 指定一个唯一的英文ID不能和现有的重复。
2. 进入icons.js在npcs分类下进行添加索引对应图标在图片上的位置即index
3. 指定一个数字在maps.js的getBlock下类似进行添加。
!> 如果是48x32的怪物素材请放在npc48.png中然后在icons.js的npc48下添加索引。
-->
### 地图生成器使用自定义素材
地图生成器是直接从js文件中读取数字-图标对应关系的。
因此在你修改了icons.js和maps.js两个文件也就是将素材添加到游戏后地图生成器的对应关系也将同步更新。
### 额外素材
从V2.4.2开始HTML5魔塔样板开始支持额外素材。
@ -300,6 +228,7 @@ ID必须由数字字母下划线组成数字在1000以内且均不能和
**该素材的宽高必须都是32的倍数且图片上的总图块数不超过1000即最多有1000个32*32的图块在该图片上。**
```js
// 在全塔属性中的tilesets导入素材
"tilesets": ["1.png", "2.png"] // 导入两个额外素材文件名分别是1.png和2.png
```
@ -350,19 +279,6 @@ core.status.hero.atk += core.values.redJewel + 2*ratio
具体过程比较复杂需要一定的JS能力在这里就不多说了有需求可以找`艾之葵`进行了解。
但值得一提的是,我们可以使用`core.hasItem(name)` 来判断是否某个道具是否存在。例如下面是passNet通过路障处理的一部分
``` js
/****** 经过路障 ******/
events.prototype.passNet = function (data) {
// 有鞋子
if (core.hasItem('shoes')) return;
if (data.event.id=='lavaNet') { // 血网
// ... 下略
```
我们进行了一个简单的判断,如果拥有绿鞋,则不进行任何路障的处理。
### 实战!拿到神圣盾后免疫吸血、领域、夹击效果
1. 在itemEffect中修改拿到神圣盾时的效果标记一个自定义Flag。
@ -421,107 +337,20 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) {
对于特殊的塔,我们可以考虑修改楼传事件来完成一些特殊的要求,比如镜子可以按楼传来切换表里。
要修改楼传事件,需要进行如下步:
要修改楼传事件,需要进行如下步:
1. 截获楼传的点击事件。在control.js中找到useFly函数并将其替换成如下内容
``` js
////// 点击楼层传送器时的打开操作 //////
control.prototype.useFly = function (need) {
if (!core.status.heroStop) {
core.drawTip("请先停止勇士行动");
return;
}
if (core.canUseItem('fly')) core.useItem('fly');
else core.drawTip("当前无法使用"+core.material.items.fly.name);
}
```
1. 重写楼传的点击事件。在插件中对`core.control.useFly进行重写`。详细代码参见[重写点击楼传事件](script#重写点击楼传事件)。
2. 修改楼传的使用事件。和其他永久道具一样在地图编辑器的图块属性中修改楼传的useItemEffect和canUseItemEffect两个内容。例如
``` js
"useItemEffect": "core.insertAction([...])" // 执行某段自定义事件,或者其他脚本
"canUseItemEffect": "true" // 任何时候可用
```
修改时,请先把`null`改成空字符串`""`,然后再双击进行编辑。
<!--
## 自定义装备
由于HTML5魔塔并不像RM那样存在一个装备界面可供我们对装备进行调整但是我们也可以使用一个替代的方式实现这个目标。
### 装备的实现原理
在HTML5中装备将全部看成是永久道具constants同时对于每个装备位置勇士都定义一个flag域表示正在装备的内容。
例如:当勇士获得银剑时,将获得一个永久道具“银剑”;当使用这个银剑,首先检查勇士当前是否装备了武器(比如铁剑),如果
装备了则先脱掉装备(减去已装备的铁剑所加的属性,并获得永久道具铁剑),然后再穿上新的银剑。
同时由于脱剑术和脱盾术的存在我们还需要一个“脱掉装备”的永久道具比如sword0使用它可以脱掉对应位置的装备。
### 装备加值的修改
要启用装备首先需要在data.js全塔属性中设置`'equipment': true`。此时,游戏内将自动将剑盾变成装备的存在,其
所加的数值就是全塔属性中对应的数值比如铁剑sword1就加的全塔属性中sword1的值
有时候,我们还会有一个装备加多种属性的需求,此时需要将对应的项从数值改变成一个对象。
``` js
"sword1": {"atk": 10, "def": 0, "mdef": 5}, // 铁剑加10攻和5魔防
"shield1": {"atk": 0, "def": 10, "mdef": 10}, // 铁盾加10防和10魔防
```
通过这种方式,当穿上装备时,将会给你的三围分别加上对应项的数值(支持负数,比如装剑减防御)。
### 新增剑盾
样板默认提供了铁剑(盾),银剑(盾),骑士剑(盾),圣剑(盾)和神圣剑(盾)这五类装备。但有时候,五类是不够的,
我们可能还需要更多的剑盾。
要增加更多的剑盾,我们需要进行如下步骤:(以新增剑为例)
1. 新注册一个素材到游戏;**其ID必须是sword+数字的形式比如sword6等。**同理如果是盾就必须是shield+数字的形式比如shield6。
2. 将其cls设置为`constants``useItemEffect`和`canUseItem`直接复制其他几个剑盾的内容。
(即:`useItemEffect`必须为`"core.plugin.useEquipment(itemId)"``canUseItemEffect`必须为`"true"`)。
3. 使用VSCode或其他文本编辑器直接打开`data.js`文件,并在`"values"`中仿照已有的内容添加剑盾的属性。
(例如:`"sword6": 100`,或者`"sword6": `{"atk": 100, "def": 0, "mdef": 50}`
!> 请注意新的剑的ID必须是sword+数字新的盾的ID必须是shield+数字的形式,不然装备将无效!
### 新增其他部位的装备
如果我们还需要新增更多部位的装备,比如戒指、首饰等等,也是可以的,只需要依次进行如下步骤:(以新建戒指为例)
1. 选择一个装备的部位的ID比如假设我们的装备部位为戒指那么我们可以选择"ring"作为装备的部位。
2. 定义一个空戒指,相当于脱掉戒指。注册一个素材到游戏,**其ID必须是ring0**即部位ID+数字0
3. 同上述新建剑盾的方式来设置ring0这个空戒指的属性。请注意打开data.js后设置的其值必须为0。
(即:必须是`"ring0": 0`)
3. 创建更多的戒指每加一个新的戒指到游戏其ID必须是**ring+数字**的形式,比如`ring1`, `ring2`,等等。
4. 对于每一个创建的戒指按照上述新建剑盾的方式设置属性图块属性打开data.js直接编辑
(例如:`"ring2": {"atk": 3, "def": 5, "mdef": 8}`
5. **切换到脚本编辑 - 自定义插件编写,在`this.useEquipment`中仿照着新增一行代表戒指的使用。**
``` js
this.useEquipment = function (itemId) { // 使用装备
_useEquipment(itemId, "sword", "atk"); // 剑
_useEquipment(itemId, "shield", "def"); // 盾
_useEquipment(itemId, "ring", "mdef"); // 新增的戒指
}
```
我们仿照着新增一行`_useEquipment(itemId, "ring", "mdef")`。
其中第二项为装备部位的ID比如我们上述定义的是ring第三项表示“如果values中该值为数字则加到什么属性上”。
比如如果我们这里写mdef那么我们假设在data.js的values中设置`"ring1": 20`则使用该戒指会增加20点魔防。
如果你定义的是对象`{"atk": xxx, "def": xxx, "mdef": xxx}`的形式,则不会受到第三项的影响。
!> 必须对于每一个装备部位定义唯一一个不同的ID脱掉装备空装备必须是该ID加数字0的形式其他有效装备必须是
该ID+正整数的形式,不然会出错!
-->
除了覆盖楼传事件外,对于快捷商店、虚拟键盘等等也可以进行覆盖,只不过是仿照上述代码重写对应的函数(`openQuickShop`,`openKeyBoard`)即可。
## 自定义怪物属性
如果你对现有的怪物不满意,想自行添加怪物属性也是可以的。具体参见脚本编辑-getSpecials。
如果你对现有的怪物不满意想自行添加怪物属性也是可以的。具体参见脚本编辑的getSpecials。
你需自己指定一个special数字修改属性名和属性提示文字。后两者可以直接写字符串或写个函数传入怪物。
@ -550,7 +379,8 @@ case 89: // 使用该按键的keyCode比如Y键就是89
// ... 在这里写你要执行脚本
// **强烈建议所有新增的自定义快捷键均能给个对应的道具可点击,以方便手机端的行为**
if (core.hasItem('...')) {
core.useItem('...');
core.status.route.push("key:0"); // 记录按键到录像中
core.useItem('...', true); // 第二个参数true代表该次使用道具是被按键触发的使用过程不计入录像
}
break;
@ -558,6 +388,10 @@ case 89: // 使用该按键的keyCode比如Y键就是89
强烈建议所有新增的自定义快捷键均给个对应的永久道具可点击,以方便手机端的行为。
使用`core.status.route.push("key:"+keyCode)`可以将这次按键记录在录像中。
!> 如果记录了按键且使用道具的话需要将useItem的第二个参数设为true避免重复记录
可以使用altKey来判断Alt键是否被同时按下。
## 公共事件
@ -572,13 +406,9 @@ case 89: // 使用该按键的keyCode比如Y键就是89
## 插件系统
在H5中提供了“插件”系统。具体参见“脚本编辑 - 插件编写”
在H5中提供了“插件”系统。在V2.6中提供了一个插件下拉框,用户可以自行创建和写插件
![插件编写](./img/plugin.png)
当我们在这上面定义了自己需要的函数(插件后),就可以通过任何方式进行调用。
在这个插件编写的过程中,我们可以使用任何[常见API](api)里面的代码调用;也可以通过`core.insertAction`来插入自定义事件执行。
在插件编写的过程中,我们可以使用任何[常见API](api)里面的代码调用;也可以通过`core.insertAction`来插入自定义事件执行。
下面是一个很简单的例子我编写一个插件函数其效果是让勇士生命值变成原来的x倍并令面前的图块消失。
@ -597,11 +427,13 @@ this.myfunc = function(x) {
网站上也提供了一个[插件库](https://h5mota.com/plugins/),欢迎大家把自己写的插件进行共享。
从V2.6开始,在插件中用`this.xxx`定义的函数将会被转发到core中。例如上述的`myfunc`除了`core.plugin.myfunc`外也可以直接`core.myfunc`调用。
详见[函数的转发](script#函数的转发)。
## 标题界面事件化
从V2.5.3开始,我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、
全塔属性flags中的startUsingCanvas可以决定是否开启标题界面事件化。
从V2.5.3开始我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、全塔属性flags中的startUsingCanvas可以决定是否开启标题界面事件化。
然后就可以使用“事件流”的形式来绘制标题界面、提供选项等等。
@ -617,36 +449,70 @@ this.myfunc = function(x) {
从V2.5.3以后,我们可以给手机端增加按键了,这样将非常有利于技能的释放。
用户在竖屏模式下点击工具栏,就会在工具栏按钮和快捷键模式之间进行切换。
用户在菜单栏打开“拓展键盘”后,在竖屏模式下点击工具栏,就会在工具栏按钮和快捷键模式之间进行切换。
切换到快捷键模式后可以点1-7分别等价于在电脑端按键1-7
切换到快捷键模式后可以点1-8分别等价于在电脑端按键1-8
可以在脚本编辑的onKeyUp中定义每个快捷键的使用效果比如使用道具或释放技能等。
默认值下1使用破2使用炸3使用飞4使用其他存在的道具5-7未定义。可以相应修改成自己的效果。
默认值下1使用破2使用炸3使用飞4使用其他存在的道具5-8未定义。可以相应修改成自己的效果。
也可以替换icons.png中的对应图标以及修改main.js中`main.statusBar.image.btn1~7`中的onclick事件来自定义按钮和对应按键。
也可以替换icons.png中的对应图标以及修改main.js中`main.statusBar.image.btn1~8`中的onclick事件来自定义按钮和对应按键。
非竖屏模式下、回放录像中、隐藏状态栏中,将不允许进行切换。
## 自定义状态栏(新增显示项)
## 自绘状态栏
从V2.5.3开始允许自绘状态栏。要自绘状态栏,则应该打开全塔属性中的`statusCanvas`开关。
自绘模式下,全塔属性中的`statusCanvasRowsOnMobile`将控制竖屏模式下的状态栏行数。
开启自绘模式后,可以在脚本编辑的`drawStatusBar`中自行进行绘制。
横屏模式下的状态栏为`129x416`15x15则是`149x480`);竖屏模式下的状态栏为`416*(32*rows+9)`15x15是480
具体可详见脚本编辑的`drawStatusBar`函数。
## 自定义状态栏的显示项
在V2.2以后,我们可以自定义状态栏背景图(全塔属性 - statusLeftBackground等等。
但是,如果我们还想新增其他项目的显示,比如攻速或者暴击,该怎么办?
需要进行如下几个操作:
我们可以[自绘状态栏](#自绘状态栏),或者采用下面两个方式之一来新增。
### 利用已有项目
一个最为简单的方式是,直接利用已有项目。
例如,如果本塔中没有技能栏,则可以使用技能栏所对应的显示项。
1. 覆盖project/icons.png中技能的图标
2. 打开全塔属性的enableSkill开关
3. 在脚本编辑-updateStatusBar中可以直接替换技能栏的显示内容
```
// 设置技能栏
if (core.flags.enableSkill) {
// 替换成你想显示的内容比如你定义的一个flag:abc。
core.setStatusBarInnerHTML('skill', core.getFlag("abc", 0));
}
```
### 额外新增新项目
如果是在需要给状态栏新定义项目,则需要进行如下几个操作:
1. 定义ID比如攻速我就定义speed暴击可以简单的定义baoji你也可以定义其他的ID但是不能和已有的重复。这里以speed为例。
2. 在index.html的statusBar中44行起进行该状态栏项的定义。仿照其他几项插在其应当显示的位置注意替换掉相应的ID。
2. 在index.html的statusBar中46行起进行该状态栏项的定义。仿照其他几项插在其应当显示的位置注意替换掉相应的ID。
``` html
<div class="status" id="speedCol">
<img id="img-speed">
<p class='statusLabel' id='speed'></p>
</div>
```
3. 在editor.html中的statusBar323行起仿照第二点同样添加这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。
4. 使用便捷PS工具打开icons.png新增一行并将魔力的图标P上去记下其索引比如37从0开始数
3. 在editor.html中的statusBar383行起仿照第二点同样添加这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。
4. 使用便捷PS工具打开project/icons.png新增一行并将魔力的图标P上去记下其索引比如37从0开始数
5. 在main.js的this.statusBar中增加图片、图标和内容的定义。
``` js
this.statusBar = {
@ -672,17 +538,15 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0);
## 技能塔的支持
其实在HTML5上制作技能塔是完全可行的。
要支持技能塔,可能需要如下几个方面:
从V2.5开始,内置了"二倍斩"技能,可以仿照其制作自己的技能。
- 魔力(和上限)的添加;技能的定义
- 状态栏的显示
- 技能的触发(按键与录像问题)
- 技能的效果
从V2.5开始,内置了"二倍斩"技能,可以仿照其制作自己的技能。
### 魔力的定义添加;技能的定义
从V2.5开始提供了status:mana选项可以直接代表当前魔力值。
@ -695,6 +559,8 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0);
如果flag:skill不为0则代表当前处于某个技能开启状态且状态栏显示flag:skillName值。伤害计算函数中只需要对flag:skill进行处理即可。
!> 关于魔力上限样板中默认没有提供status:manamax
### 状态栏的显示
从V2.5开始,魔力值和技能名的状态栏项目已经被添加,可以直接使用。
@ -704,9 +570,14 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0);
``` js
// 设置魔力值
if (core.flags.enableMana) {
// 也可以使用flag:manaMax来表示最大魔力值
// core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10));
// core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10);
// status:manamax 只有在非负时才生效。
if (core.status.hero.manamax != null && core.status.hero.manamax >= 0) {
core.status.hero.mana = Math.min(core.status.hero.mana, core.status.hero.manamax);
core.setStatusBarInnerHTML('mana', core.status.hero.mana + "/" + core.status.hero.manamax);
}
else {
core.setStatusBarInnerHTML("mana", core.status.hero.mana);
}
}
// 设置技能栏
if (core.flags.enableSkill) {
@ -759,14 +630,15 @@ else { // 关闭技能
case 87: // W开启技能“二倍斩”
// 检测技能栏是否开启,是否拥有“二倍斩”这个技能道具
if (core.flags.enableSkill && core.hasItem('skill1')) {
core.useItem('skill1');
core.status.route.push("key:87");
core.useItem('skill1', true);
}
break;
```
在勇士处于停止的条件下按下W键时判断技能的道具是否存在如果存在再使用它。
!> 123这三个键被默认绑定到了破炸飞如果想用的话也是一样只不过是把已有的实现进行替换
!> 由于现在手机端存在拓展键盘也强烈建议直接覆盖1-8的使用效果这样手机端使用也非常方便
### 技能的效果
@ -814,141 +686,6 @@ if (core.flags.enableSkill) {
通过上述这几种方式我们就能成功的让H5支持技能啦
## 成就系统
我们还可以给HTML5魔塔增加成就系统。注意到成就是和游戏相关因此需要使用getLocalStorage而不是getFlag判定。
可将下面的代码粘贴到脚本编辑 - 插件编写中。
``` js
// 所有成就项的定义
this.achievements = [
// 每行一个分别定义flag、名称、描述、是否存在提示、成就点数
{"flag": "a1", "name": "成就1", "text": "成就1的达成描述", "hint": false, "point": 1},
// 可以继续往后新增其他的。
];
// 达成成就;如 core.plugin.achieve("a1") 即达成a1对应的成就
this.achieve = function (flag) {
// 获得已达成的成就如果跟存档而不是跟游戏则改成getFlag
var achieved = core.getLocalStorage("achievements", []);
var point = core.getLocalStorage("achievePoint", 0);
// 已经获得该成就
if (achieved.indexOf(flag)>=0) return;
// 尝试达成成就;找到对应的成就项
this.achievements.forEach(function (one) {
if (one.flag == flag) {
// 执行达成成就的操作;也可以自行在上面加上达成成就后的事件
core.insertAction("\t[达成成就:"+one.name+"]"+one.text);
point += one.point || 0;
}
});
achieved.push(flag);
// 存入localStorage中如果跟存档走则使用setFlag
core.setLocalStorage("achievements", achieved);
core.setLocalStorage("achievePoint", point);
}
// 获得所有成就说明这里简单使用两个insertAction你也可以修改成自己的实现
// 简单一点的可以使用insertAction+剧情文本稍微复杂一点的可以使用图片化文本等更复杂的可以自绘UI。
this.getAchievements = function () {
var achieved = core.getLocalStorage("achievements", []);
var yes = [], no = [];
// 对所有成就进行遍历
this.achievements.forEach(function (one) {
// 检测是否达成
if (achieved.indexOf(one.flag)>=0) {
yes.push(one.name+""+one.text);
}
else {
no.push(one.name+""+(one.hint?one.text:"达成条件请自行探索"));
}
});
core.insertAction([
"\t[已达成的成就]"+(yes.length==0?"暂无":yes.join("\n")),
"\t[尚未达成的成就]"+(no.length==0?"暂无":no.join("\n"))
]);
}
```
## 多角色的支持
其实,我们的样板还能支持多角色的制作。比如《黑·白·间》之类的塔也是完全可以刻的。
你只需要如下几步来达到多角色的效果。
1. 每个角色弄一张行走图。相关信息参见[自定义事件setHeroIcon](event#setHeroIcon更改角色行走图)。
2. [覆盖楼传事件](#覆盖楼传事件),这样可以通过点工具栏的楼层传送按钮来切换角色。当然你也完全可以自己写一个道具,或[自定义快捷键](#自定义快捷键)来进行绑定。
3. 将下述代码直接贴入脚本编辑 - 插件编写中。
``` js
// 所有需要保存的内容;这些保存的内容不会多角色共用,在切换时会进行恢复。
// 你也可以自行新增或删除,比如不共用金币则可以加上"money"的初始化,不共用道具则可以加上"items"的初始化,
// 多角色共用hp的话则删除hp等等。总之不共用的属性都在这里进行定义就好。
var hero1 = { // 1号勇士默认的是0号
"floorId": "MT0", // 该角色楼层ID
"icon": "hero1.png", // 角色的行走图名称
"name": "1号角色",
"lv": 1,
"hp": 1000,
"atk": 10,
"def": 10,
"mdef": 0,
"loc": {"x": 0, "y": 0, "direction": "up"},
// 如果道具不共用就将下面这句话取消注释
// "items": {"keys":{"yellowKey":0,"blueKey":0,"redKey":0},"tools":{},"constants":{}}
}
// 也可以类似新增其他勇士
// var hero2 = { ...
var heroCount = 2; // 包含默认的在内总共多少个勇士,该值需手动修改。
// 初始化该勇士
this.initHeros = function () {
core.status.hero.icon = "hero.png";
core.setFlag("hero1", core.clone(hero1)); // 将属性值存到变量中
// core.setFlag("hero2", core.clone(hero2)); // 更多的勇士...
}
// 切换勇士
this.changeHero = function (toHeroId) {
var currHeroId = core.getFlag("heroId", 0); // 获得当前角色ID
if (!core.isset(toHeroId)) {
toHeroId = (currHeroId+1)%heroCount;
}
if (currHeroId == toHeroId) return;
var saveList = Object.keys(hero1);
// 保存当前内容
var toSave = {};
saveList.forEach(function(name) {
if (name=='floorId') toSave[name] = core.status.floorId; // 楼层单独设置
else toSave[name] = core.clone(core.status.hero[name]); // 使用core.clone()来创建新对象
})
core.setFlag("hero"+currHeroId, toSave); // 将当前角色信息进行保存
var data = core.getFlag("hero"+toHeroId); // 获得要切换的角色保存内容
// 设置角色的属性值
saveList.forEach(function(name) {
if (name != 'floorId')
core.status.hero[name] = core.clone(data[name]);
})
// 插入事件:改变角色行走图并进行楼层切换
core.insertAction([
{"type": "setHeroIcon", "name": data.icon||"hero.png"}, // 改变行走图
{"type": "changeFloor", "floorId": data.floorId, "loc": [data.loc.x, data.loc.y],
"direction": data.loc.direction, "time": 0} // 楼层切换事件
])
core.setFlag("heroId", toHeroId); // 保存切换到的角色ID
}
```
3. 在脚本编辑 - setInitData中加上`core.plugin.initHeros()`来初始化新勇士。(写在`core.events.afterLoadData()`后,反大括号之前。)
4. 如果需要切换角色包括事件、道具或者快捷键等可以直接调用自定义JS脚本`core.plugin.changeHero();`进行切换。也可以指定参数调用`core.plugin.changeHero(1)`来切换到某个具体的勇士上。
## 系统使用的flag变量
众所周知自定义flag变量都可以任意定义并取用未定义直接取用的flag默认值为0
@ -970,11 +707,11 @@ this.getAchievements = function () {
- **`flag:__color__`**, **`flag:__weather__`**, **`flag:__volume__`**: 当前的画面色调、天气和音量。
- **`flag:__events__`**: 当前保存的事件列表,读档时会恢复(适用于在事件中存档)
- **`flag:textAttribute`**, **`flag:globalAttribute`**, **`flag:globalFlags`**: 当前的剧情文本属性,当前的全局属性,当前的全局开关。
- **`flag:cannotMoveDirectly`**, **`flag:clickMove`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。
- **`flag:cannotMoveDirectly`**, **`flag:__noClickMove__`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。
- **`flag:hideStatusBar`**, **`flag:showToolbox`**: 是否隐藏状态栏,是否显示工具栏。
- **`flag:debug`**, **`flag:consoleOpened`**: 当前是否开启了调试模式,是否开启了控制台。
- **`flag:debug`**, **`flag:__consoleOpened__`**: 当前是否开启了调试模式,是否开启了控制台。
- **`flag:__seed__`**, **`flag:__rand__`**: 伪随机数生成种子和当前的状态
==========================================================================================
[继续阅读附录所有API列表](api)
[继续阅读脚本](script)

313
_docs/script.md Normal file
View File

@ -0,0 +1,313 @@
# 脚本
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。
## 控制台的使用
在Chrome浏览器中Ctrl+Shift+I可打开控制台。
![](img/console.jpg)
控制台中有很多的标签,最常用的是`Console`, `Sources`和`Elements`。
有关更详尽的控制台使用可自行搜索[Chrome开发者工具](https://www.baidu.com/s?wd=chrome%20%E5%BC%80%E5%8F%91%E8%80%85%E5%B7%A5%E5%85%B7)了解更多。
### Console命令行
Console页为命令行。可以在这里输入一些命令进行调试。
比如,进入游戏后,输入`core.status.hero.atk`即可获得勇士的当前攻击力数值。`core.status.hero.atk=100`可以设置攻击力为100。
更多的API可参见[附录API列表](#附录API列表)。
除此以外游戏中的报错等信息也是可以在Console中进行查看的。
![](img/console1.jpg)
### Sources断点调试
Sources页可以查看JS源代码并进行断点调试等。
例如,如果相对脚本编辑中的伤害计算函数进行断点调试:
1. 在左边找到`project/functions.js`,单击打开文件
2. 并找到对应的行可以Ctrl+F搜索比如搜索`getDamageInfo`
3. 在行号上点一下打断点,会出现一个蓝色标签
之后,当代码运行到你的断点处时,将自动停止运行。
![](img/sources.jpg)
可以将鼠标移动到变量上,将弹窗形式显示这个变量的各项数值,从而查看变量值是否符合预期。
图中红色框内有几个按钮,从左到右分别是:**继续执行****执行到下一行****进入当前函数****跳出当前函数****单步执行**。
通过这几个按钮,可以一行一行的对代码进行执行,执行过程中能不断查看各个变量的数值变化,从而定位问题所在。
红圈下方是Call Stack即当前的函数调用链从哪些地方调用过来的
Sources还有更多有趣的功能在此不做介绍有兴趣的可自行网上搜索了解。
### Elements网页元素查看
Elements页可以查看网页的源代码调整css布局等。
![](img/elements.jpg)
不过对魔塔样板来说,最重要的是红圈中的按钮。点击此按钮可以进入**手机模式**。
手机模式下,左边可以对屏幕分辨率进行调整和模拟。
这可以很有效的帮我们进行测试样板在手机端的表现。
## 整体项目架构
``` text
├── /_server/ # 为可视化地图编辑器提供一些支持的目录
├── /libs/ # ---- 系统库目录 ----
│ ├─ /thirdparty/ # 游戏所用到的第三方库文件
│ ├─ actions.js # 用户交互处理
│ ├─ core.js # 系统核心文件(游戏入口,接口&转发)
│ ├─ control.js # 游戏逻辑控制
│ ├─ data.js # 全塔属性等
│ ├─ enemys.js # 怪物相关处理
│ ├─ events.js # 各个事件的执行
│ ├─ icons.js # 图标和素材
│ ├─ items.js # 道具效果
│ ├─ loader.js # 各个资源加载
│ ├─ maps.js # 地图数据和绘制
│ ├─ ui.js # UI窗口绘制
│ └─ utils.js # 工具类函数
├── /project/ # ---- 项目目录 ----
│ ├─ /animates/ # 动画目录
│ ├─ /floors/ # 楼层文件
│ ├─ /images/ # 图片素材
│ ├─ /sounds/ # bgm和音效
│ ├─ data.js # 全塔属性
│ ├─ enemys.js # 怪物属性
│ ├─ events.js # 公共事件
│ ├─ functions.js # 脚本编辑
│ ├─ icons.js # 素材和ID的对应关系定义
│ ├─ items.js # 道具的定义和效果
│ ├─ maps.js # 地图和数字的对应关系
│ └─ plugins.js # 自定义插件
├── /常用工具/ # 辅助造塔的小工具
├── editor.html # 地图编辑器
├── editor-mobile.html # 手机版的地图编辑器
├── index.html # 主程序,游戏的入口
├── main.js # JS程序的入口将动态对所需JS进行加载
├── style.css # 游戏所需要用到的样式表
└── 启动服务.exe # 一个本地的HTTP服务器通过它来运行游戏
```
`_server`为**地图编辑器目录**,里面存放了地图编辑器相关的各项内容。
`libs`为**系统库目录**,里面存放了各个系统核心函数。
从V2.6开始请勿直接修改libs下的代码如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数)。
`project`为**项目目录**你所造的塔的数据全部存放在project下。在不同样板之间接档也是直接迁移project目录即可。
## 函数的转发
在本样板中,`core.js`里面基本是没有定义什么函数的,所有的游戏内函数都在其他几个文件中实现。
例如,常见的获得某个变量值`getFlag`是定义在`control.js`中的:
```js
////// 获得某个自定义变量或flag //////
control.prototype.getFlag = function(name, defaultValue) {
if (!core.status.hero) return defaultValue;
var value = core.status.hero.flags[name];
return value != null ? value : defaultValue;
}
```
也就是,我们可以通过`core.control.getFlag(name, value)`来调用此函数。
但是这样会十分不便,我们希望能直接调用`core.getFlag(name, value)`而不需要中间的control。
为了达到这个目的,样板设置了**函数转发**,即**将其他文件中定义的函数转发到core中执行**。
上述`getFlag`代码的转发实际上是增加了如下函数:
```js
////// getFlag函数的转发 //////
core.getFlag = function (name, defaultValue) {
return core.control.getFlag(name, defaultValue);
}
// 转发后,即可通过 core.getFlag() 来实际调用 core.control.getFlag()
```
转发是自动完成的,其满足如下两条规则:
- **在libs中其他文件定义的函数如果不以下划线`_`开头,就会进行转发。**
- **如果core中已经存在同名函数则会在控制台中打出一条报错信息并不转发该函数。**
具体函数的转发实现代码可参见`core.js`的`_forwardFunc`函数。
!> 除此以外,插件中以`this.xxx`来定义的函数也会被转发!
例如,你可以直接调用`core.drawLight()`来实际调用插件中的`core.plugin.drawLight`。
## 插件编写
插件编写是H5魔塔的一个重大特点从V2.0.1引入,并逐渐发扬光大。
对于有一定脚本经验的人来说,可以编写插件来实现各种各样的功能,包括且不仅限于拓展功能的实现,系统代码的复写等等。
在V2.5.5以前插件位置都在脚本编辑中从V2.6开始则迁移到了新的下拉框中,并进行了切分。
你也可以创建自己的插件。
![](img/plugin.jpg)
新的插件切分和原来的单插件使用方法完全一致,单纯进行了切分而已。可参见已有的`init`和`drawLight`的样例。
拆分的意义主要是将各个可能的功能独立出来,避免单个框内内容太长,过大和混杂等。
在V2.6中,应当每个独立的额外功能实现都新建一个自己的插件,这样也方便进行拓展,例如打包迁移到别的塔上,或发布在网页插件库中。
另外一点需要注意的是,所有插件的初始化都会在系统资源加载之前,此时图片等资源尚未进行加载。
在所有资源加载完毕时将会执行init插件中的_afterLoadResources函数可以在这里对资源进行一些操作比如切分图片等。
```js
function () {
console.log("插件编写测试");
// 可以写一些直接执行的代码
// 在这里写的代码将会在【资源加载前】被执行,此时图片等资源尚未被加载。
// 请勿在这里对包括bgm图片等资源进行操作。
this._afterLoadResources = function () {
// 本函数将在所有资源加载完毕后,游戏开启前被执行
// 可以在这个函数里面对资源进行一些操作,比如切分图片等。
// 这是一个将assets.png拆分成若干个32x32像素的小图片并保存的样例。
// var arr = core.splitImage("assets.png", 32, 32);
// for (var i = 0; i < arr.length; i++) {
// core.material.images.images["asset"+i+".png"] = arr[i];
// }
}
// 可以在任何地方如afterXXX或自定义脚本事件调用函数方法为 core.plugin.xxx();
// 从V2.6开始插件中用this.XXX方式定义的函数也会被转发到core中详见文档-脚本-函数的转发。
}
```
网站上提供了一个插件库,[https://h5mota.com/plugins/](https://h5mota.com/plugins/),上面有一些大家分享的插件,可供使用。
可以查看附录中的[API列表](api)来查看所有的系统API内容。
## 复写函数
样板的功能毕竟是写死的,有时候我们也需要修改样板的一些行为。
在V2.6以前需要直接打开libs目录下的对应文件并进行修改。但是开libs下的文件就会出现各种问题
- 不容易随着新样板接档进行迁移
- 也不好找到自己改过什么,从而能整理成新的插件在别的塔使用
- ……
好消息的是从V2.6开始,我们再也不需要开文件了,而是可以直接在插件中对原始函数进行复写。
如果我想对xxx文件中的yyy函数进行重写其模式一般是`core.xxx.yyy = function (参数列表) { ... }`
下面是几个例子,从简单到复杂。
### 重写怪物手册的背景图绘制使用winskin而不是默认的黑色
直接重写怪物手册的背景图绘制,使用`core.drawBackground`来用winskin绘制一个背景图。
```js
// 重写ui.js中的_drawBook_drawBackground函数
core.ui._drawBook_drawBackground = function () {
// core.__PIXEL__为定义的一个宏对于13x13的值是416对于15x15的值是480
core.drawBackground(0, 0, core.__PIXEL__, core.__PIXEL__);
}
```
### 重写点击楼传事件
重写点击楼传事件使得点击楼传按钮时能使用一个道具比如item:fly
```js
// 重写events.js的useFly函数即点击楼传按钮时的事件
core.events.useFly = function (fromUserAction) {
if (core.isMoving()) {
core.drawTip("请先停止勇士行动");
return;
}
if (core.status.lockControl || core.status.event.id != null) return;
if (core.canUseItem('fly')) core.useItem('fly');
else core.drawTip("当前无法使用"+core.material.items.fly.name);
}
```
其他的几个按钮,如快捷商店`openQuickShop`,虚拟键盘`openKeyBoard`的重写也几乎完全一样。
### 楼层切换时根据flag来播放不同的音效
整体复制并重写整个楼传切换前的函数,将`core.playSound('floor.mp3')`替换成根据flag来判定。
```js
// 复制重写events.js中的_changeFloor_beforeChange修改音效
core.events._changeFloor_beforeChange = function (info, callback) {
// 直接替换原始函数中的 core.playSound('floor.mp3');
if (core.getFlag("floorSound") == 0) core.playSound('floor0.mp3');
if (core.getFlag("floorSound") == 1) core.playSound('floor1.mp3');
if (core.getFlag("floorSound") == 2) core.playSound('floor2.mp3');
// ...
// 下面是原始函数中的剩余代码,保持不变
window.setTimeout(function () {
if (info.time == 0)
core.events._changeFloor_changing(info, callback);
else
core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () {
core.events._changeFloor_changing(info, callback);
});
}, 25)
}
```
### 每次打开全局商店时播放一个音效
打开全局商店是在`events.js`中的`openShop`函数,因此需要对其进行重写。
然而,我们只需要在这个函数执行之前插一句音效播放,所以并不需要重写整个函数,而是直接插入一行就行。
```js
var openShop = core.events.openShop; // 先把原始函数用一个变量记录下来
core.events.openShop = function (shopId, needVisited) {
core.playSound("shop.mp3"); // 播放一个音效
return openShop(shopId, needVisited); // 直接调用原始函数
}
```
### 每次绘制地图前在控制台打出一条信息
绘制地图在`maps.js`的`drawMap`函数,因此需要对其进行重写。
由于只需要额外在函数执行前增加一句控制台输出,所以直接插入一行即可。
但是需要注意的是,`drawMap`中使用了`this._drawMap_drawAll()`,因此使用函数时需要用`call`或者`apply`来告知this是什么。
```js
var drawMap = core.maps.drawMap; // 先把原始函数用一个变量记录下来
core.maps.drawMap = function (floorId, callback) {
console.log("drawMap..."); // 控制台打出一条信息
drawMap.call(core.maps, floorId, callback); // 需要使用`call`来告知this是core.maps
}
```
详见[call和apply的用法](https://www.jianshu.com/p/80ea0d1c04f8)。
==========================================================================================
[继续阅读下一章API列表](api)

View File

@ -1,6 +1,6 @@
# 快速上手
?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} *
?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
@ -28,6 +28,7 @@
* “地图编辑器”允许你以可视化的方式进行编辑地图。
* “便捷PS工具”能让你很方便的对自定义素材进行添加。参见[自定义素材](personalization#自定义素材)。
* “地图生成器”能让你从已有的截图如RMXP项目中立刻生成可被本样板识别的地图数据。
* “怪物数据导出”能让你从RMXP中导出怪物数据而被H5魔塔使用。
* “RM动画导出器”能让你从RMXP中导出动画而被H5魔塔使用。
* “JS代码压缩工具”能对JS代码进行压缩从而减少IO请求数和文件大小。
* “伤害和临界值计算器”是一个很便捷的小工具,能对怪物的伤害和临界值进行计算。
@ -54,6 +55,8 @@
### 从RMXP导入已有的地图
!> 注现在已经不推荐此方法如需从RM刻塔请使用 [RM转H5刻塔器使用教程](https://www.bilibili.com/video/av43125840) 进行操作。
如果我们想复刻一个现有的已经被RMXP所制作的塔也有很便捷的方式那就是用到我们的“地图生成器”。
首先我们打开RMXP和对应的项目可以看到它的地图。
@ -176,7 +179,7 @@
之后刷新编辑器即可。
对于怪物和道具,我们也可以进行自动注册只需要点击“自动注册”按钮将对该栏下所有未注册的素材进行自动注册自动分配ID和数字
也可以进行自动注册只需要点击“自动注册”按钮将对该栏下所有未注册的素材进行自动注册自动分配ID和数字
素材注册完毕后,即可在游戏中正常使用,也可以被地图生成器所识别(需要重开地图生成器)。
@ -230,6 +233,18 @@ HTML5的塔都是可以进行控制台调试的。
更多API和详细参数介绍可参见[API列表](api)。
## 编辑器的基本操作
- **Alt+0~9, Ctrl+0~9** 保存和读取当前选中图块
- **W/A/S/D** 移动大地图
- **Ctrl+Z** 撤销上次绘图
- **Ctrl+Y** 重做上次绘图
- **PgUp/PgDn** 切换楼层
- **Ctrl+S** 保存事件编辑器/脚本编辑器
- **地图上单击** 选中该点
- **地图上双击** 选中该点图块
- **地图上右键** 弹出菜单栏,包括选中、复制、清除等操作
- **事件编辑器中Ctrl+C, Ctrl+X, 右键等** 执行相应操作
## 报错处理

View File

@ -65,6 +65,7 @@ return code;
shoplist
: shopsub
| shopcommonevent
| emptyshop
;
@ -77,6 +78,36 @@ var code = ' \n';
return code;
*/;
shopcommonevent
: '商店 id' IdString '快捷商店栏中名称' EvalString BGNL? '未开启状态则不显示在列表中' Bool BGNL? '执行的公共事件 id' EvalString '参数列表' EvalString?
/* shopcommonevent
tooltip : 全局商店, 执行一个公共事件
helpUrl : https://h5mota.com/games/template/docs/#/
default : ["shop1","回收钥匙商店",false,"回收钥匙商店",""]
if (EvalString_2) {
if (EvalString_2.indexOf('"')>=0)
throw new Error('请勿在此处使用双引号!尝试使用单引号吧~');
// 检查是不是数组
try {
EvalString_2 = JSON.parse(EvalString_2.replace(/'/g, '"'));
if (!(EvalString_2 instanceof Array)) throw new Error();
}
catch (e) {
throw new Error('参数列表必须是个有效的数组!');
}
}
var code = {
'id': IdString_0,
'textInList': EvalString_0,
'mustEnable': Bool_0,
'commonEvent': EvalString_1
}
if (EvalString_2) code.args = EvalString_2;
code=JSON.stringify(code,null,2)+',\n';
return code;
*/;
shopsub
: '商店 id' IdString '标题' EvalString '图标' IdString BGNL? Newline '快捷商店栏中名称' EvalString '共用times' Bool BGNL? Newline '未开启状态则不显示在列表中' Bool BGNL? NewLine '使用' ShopUse_List '消耗' EvalString BGNL? Newline '显示文字' EvalString BGNL? Newline shopChoices+ BEND
@ -200,7 +231,7 @@ var loc = ', "loc": ['+Number_0+', '+Number_1+']';
if (Stair_List_0!=='loc')loc = ', "stair": "'+Stair_List_0+'"';
DirectionEx_List_0 = DirectionEx_List_0 && (', "direction": "'+DirectionEx_List_0+'"');
Int_0 = (Int_0!=='') ?(', "time": '+Int_0):'';
Bool_0 = Bool_0 ?'':(', "portalWithoutTrigger": false');
Bool_0 = Bool_0 ?'':(', "ignoreChangeFloor": false');
var code = '{"floorId": "'+toFloorId+'"'+loc+DirectionEx_List_0+Int_0+Bool_0+' }\n';
return code;
*/;
@ -228,7 +259,7 @@ action
| setText_s
| tip_s
| setValue_s
| setValue2_s
| addValue_s
| setFloor_s
| setGlobalAttribute_s
| setGlobalValue_s
@ -256,6 +287,7 @@ action
| waitAsync_s
| battle_s
| openDoor_s
| closeDoor_s
| changeFloor_s
| changePos_0_s
| changePos_1_s
@ -267,13 +299,14 @@ action
| animate_s
| vibrate_s
| showImage_s
| showImage_1_s
| hideImage_s
| showTextImage_s
| moveImage_s
| showGif_0_s
| showGif_1_s
| setFg_0_s
| setFg_1_s
| setCurtain_0_s
| setCurtain_1_s
| screenFlash_s
| setWeather_s
| move_s
@ -298,9 +331,11 @@ action
| input_s
| input2_s
| choices_s
| confirm_s
| callBook_s
| callSave_s
| callLoad_s
| unknown_s
| function_s
| pass_s
;
@ -379,27 +414,28 @@ return code;
*/;
scrollText_s
: '滚动剧情文本:' '时间' Int '不等待执行完毕' Bool? BGNL? EvalString Newline
: '滚动剧情文本:' '时间' Int '行距' Number '不等待执行完毕' Bool? BGNL? EvalString Newline
/* scrollText_s
tooltip : scrollText滚动剧情文本将从下到上进行滚动显示。
helpUrl : https://h5mota.com/games/template/docs/#/event?id=scrollText%ef%bc%9a%e6%bb%9a%e5%8a%a8%e5%89%a7%e6%83%85%e6%96%87%e6%9c%ac
default : [5000,false,"时间是总时间可以使用setText事件来控制字体、颜色、大小、偏移量等"]
default : [5000,1.4,false,"时间是总时间可以使用setText事件来控制字体、颜色、大小、偏移量等"]
Bool_0 = Bool_0?', "async": true':'';
var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+'},\n';
var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+', "lineHeight": '+Number_0+'},\n';
return code;
*/;
setText_s
: '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline
: '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? '对齐' SetTextAlign_List? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline
/* setText_s
tooltip : setText设置剧情文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填
helpUrl : https://h5mota.com/games/template/docs/#/event?id=settext%EF%BC%9A%E8%AE%BE%E7%BD%AE%E5%89%A7%E6%83%85%E6%96%87%E6%9C%AC%E7%9A%84%E5%B1%9E%E6%80%A7
default : [null,"","",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',null,"","",""]
default : [null,"",null,"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',null,"","",""]
SetTextPosition_List_0 =SetTextPosition_List_0==='null'?'': ', "position": "'+SetTextPosition_List_0+'"';
SetTextAlign_List_0 =SetTextAlign_List_0==='null'?'': ', "align": "'+SetTextAlign_List_0+'"';
var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/;
if (EvalString_0) {
if (!/^\d+$/.test(EvalString_0))throw new Error('像素偏移量必须是整数或不填');
@ -437,7 +473,7 @@ if (EvalString_6) {
EvalString_6 = ', "time": '+EvalString_6;
}
B_1_List_0 = B_1_List_0==='null'?'':', "bold": '+B_1_List_0;
var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+EvalString_6+'},\n';
var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+SetTextAlign_List_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+EvalString_6+'},\n';
return code;
*/;
@ -465,15 +501,15 @@ var code = '{"type": "setValue", "name": "'+idString_e_0+'", "value": "'+express
return code;
*/;
setValue2_s
addValue_s
: '数值增减' ':' '名称' idString_e '+=' expression Newline
/* setValue2_s
tooltip : setValue2:增减勇士的某个属性、道具个数, 或某个变量/Flag的值
helpUrl : https://h5mota.com/games/template/docs/#/event?id=setValue2%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc
/* addValue_s
tooltip : addValue:增减勇士的某个属性、道具个数, 或某个变量/Flag的值
helpUrl : https://h5mota.com/games/template/docs/#/event?id=addValue%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc
colour : this.dataColor
var code = '{"type": "setValue2", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n';
var code = '{"type": "addValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n';
return code;
*/;
@ -614,29 +650,55 @@ return code;
*/;
insert_1_s
: '插入公共事件' EvalString Newline
: '插入公共事件' EvalString '参数列表' EvalString? Newline
/* insert_1_s
tooltip : insert: 插入公共事件并执行
helpUrl : https://h5mota.com/games/template/docs/#/event?id=insert%ef%bc%9a%e6%8f%92%e5%85%a5%e5%85%ac%e5%85%b1%e4%ba%8b%e4%bb%b6%e6%88%96%e5%8f%a6%e4%b8%80%e4%b8%aa%e5%9c%b0%e7%82%b9%e7%9a%84%e4%ba%8b%e4%bb%b6%e5%b9%b6%e6%89%a7%e8%a1%8c
default : ["加点事件"]
default : ["加点事件", ""]
colour : this.eventColor
var code = '{"type": "insert", "name": "'+EvalString_0+'"},\n';
if (EvalString_1) {
if (EvalString_1.indexOf('"')>=0)
throw new Error('请勿在此处使用双引号!尝试使用单引号吧~');
// 检查是不是数组
try {
if (!(JSON.parse(EvalString_1.replace(/'/g, '"')) instanceof Array)) throw new Error();
}
catch (e) {
throw new Error('参数列表必须是个有效的数组!');
}
EvalString_1 = ', "args": ' +EvalString_1;
}
var code = '{"type": "insert", "name": "'+EvalString_0+'"'+EvalString_1+'},\n';
return code;
*/;
insert_2_s
: '插入事件' 'x' PosString ',' 'y' PosString '楼层' IdString? Newline
: '插入事件' 'x' PosString ',' 'y' PosString Event_List? '楼层' IdString? '参数列表' EvalString? ENewline
/* insert_2_s
tooltip : insert: 立即插入另一个地点的事件执行,当前事件不会中断,事件坐标不会改变
helpUrl : https://h5mota.com/games/template/docs/#/event?id=insert%ef%bc%9a%e6%8f%92%e5%85%a5%e5%85%ac%e5%85%b1%e4%ba%8b%e4%bb%b6%e6%88%96%e5%8f%a6%e4%b8%80%e4%b8%aa%e5%9c%b0%e7%82%b9%e7%9a%84%e4%ba%8b%e4%bb%b6%e5%b9%b6%e6%89%a7%e8%a1%8c
default : ["0","0",""]
default : ["0","0",null,"",""]
colour : this.eventColor
IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"');
var code = '{"type": "insert", "loc": ['+PosString_0+','+PosString_1+']'+IdString_0+'},\n';
if (EvalString_0) {
if (EvalString_0.indexOf('"')>=0)
throw new Error('请勿在此处使用双引号!尝试使用单引号吧~');
try {
if (!(JSON.parse(EvalString_0.replace(/'/g, '"')) instanceof Array)) throw new Error();
}
catch (e) {
throw new Error('参数列表必须是个有效的数组!');
}
EvalString_0 = ', "args": ' +EvalString_0;
}
if (Event_List_0 && Event_List_0 !=='null')
Event_List_0 = ', "which": "'+Event_List_0+'"';
else Event_List_0 = '';
var code = '{"type": "insert", "loc": ['+PosString_0+','+PosString_1+']'+Event_List_0+IdString_0+EvalString_0+'},\n';
return code;
*/;
@ -935,6 +997,23 @@ var code = '{"type": "openDoor"'+floorstr+IdString_0+Bool_0+'},\n';
return code;
*/;
closeDoor_s
: '关门' 'x' PosString? ',' 'y' PosString? 'ID' IdString Newline
/* closeDoor_s
tooltip : closeDoor: 关门事件,需要该点本身无事件
helpUrl : https://h5mota.com/games/template/docs/#/event?id=opendoor%EF%BC%9A%E5%BC%80%E9%97%A8
default : ["","","yellowDoor"]
colour : this.dataColor
var floorstr = '';
if (PosString_0 && PosString_1) {
floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
}
var code = '{"type": "closeDoor", "id": "'+IdString_0+'"'+floorstr+'},\n';
return code;
*/;
changeFloor_s
: '楼层切换' IdString? 'x' PosString? ',' 'y' PosString? '朝向' DirectionEx_List '动画时间' Int? Newline
@ -1088,34 +1167,54 @@ return code;
*/;
showImage_s
: '显示图片' '图片编号' Int '图片' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL?
'放大率 : x' Int '% y' Int '% 不透明度' Number '时间' Int '不等待执行完毕' Bool Newline
: '显示图片' '图片编号' Int '图片' EvalString BGNL?
'绘制的起点像素' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline
/* showImage_s
tooltip : showImage显示图片
helpUrl : https://h5mota.com/games/template/docs/#/event?id=showImage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87
default : [1,"bg.jpg","0","0",100,100,1,0,false]
default : [1,"bg.jpg","0","0",1,0,false]
colour : this.printColor
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
var async = Bool_0?', "async": true':'';
var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "dw": '+Int_1+', "dh": '+Int_2+', "opacity": '+Number_0+', "time": '+Int_3+async+'},\n';
var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Number_0+', "time": '+Int_1+async+'},\n';
return code;
*/;
showImage_1_s
: '显示图片' '图片编号' Int '图片' EvalString BGNL?
'裁剪的起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '不透明度' Number BGNL?
'绘制的起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '时间' Int '不等待执行完毕' Bool Newline
/* showImage_1_s
tooltip : showImage_1显示图片
helpUrl : https://h5mota.com/games/template/docs/#/event?id=showImage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87
default : [1,"bg.jpg","0","0","","",1,"0","0","","",0,false]
colour : this.printColor
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
var async = Bool_0?', "async": true':'';
var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", '+
'"sloc": ['+PosString_0+','+PosString_1+','+PosString_2+','+PosString_3+'], '+
'"loc": ['+PosString_4+','+PosString_5+','+PosString_6+','+PosString_7+'], '+
'"opacity": '+Number_0+', "time": '+Int_1+async+'},\n';
return code;
*/;
showTextImage_s
: '显示图片化文本' '文本内容' EvalString BGNL?
'图片编号' Int '起点像素位置' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline
'图片编号' Int '起点像素' 'x' PosString 'y' PosString '行距' Number '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline
/* showTextImage_s
tooltip : showTextImage显示图片化文本
helpUrl : https://h5mota.com/games/template/docs/#/event?id=showTextImage%ef%bc%9a%e6%98%be%e7%a4%ba%e6%96%87%e6%9c%ac%e5%8c%96%e5%9b%be%e7%89%87
colour : this.printColor
default : ["可以使用setText事件来控制字体、颜色、大小、偏移量等",1,"0","0",1,0,false]
default : ["可以使用setText事件来控制字体、颜色、大小、偏移量等",1,"0","0",1.4,1,0,false]
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
var async = Bool_0?', "async": true':'';
var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Number_0+', "time": '+Int_1+async+'},\n';
var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "lineHeight": '+Number_0+', "opacity": '+Number_1+', "time": '+Int_1+async+'},\n';
return code;
*/;
@ -1179,35 +1278,35 @@ var code = '{"type": "moveImage", "code": '+Int_0+toloc+EvalString_0+',"time": '
return code;
*/;
setFg_0_s
setCurtain_0_s
: '更改画面色调' EvalString Colour '动画时间' Int? '不等待执行完毕' Bool Newline
/* setFg_0_s
tooltip : setFg: 更改画面色调,动画时间可不填
helpUrl : https://h5mota.com/games/template/docs/#/event?id=setfg%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83
/* setCurtain_0_s
tooltip : setCurtain: 更改画面色调,动画时间可不填
helpUrl : https://h5mota.com/games/template/docs/#/event?id=setcurtain%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83
default : ["255,255,255,1",'rgba(255,255,255,1)',500,false]
colour : this.soundColor
var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/;
if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
Int_0 = Int_0!=='' ?(', "time": '+Int_0):'';
var async = Bool_0?', "async": true':'';
var code = '{"type": "setFg", "color": ['+EvalString_0+']'+Int_0 +async+'},\n';
var code = '{"type": "setCurtain", "color": ['+EvalString_0+']'+Int_0 +async+'},\n';
return code;
*/;
setFg_1_s
setCurtain_1_s
: '恢复画面色调' '动画时间' Int? '不等待执行完毕' Bool Newline
/* setFg_1_s
tooltip : setFg: 恢复画面色调,动画时间可不填
helpUrl : https://h5mota.com/games/template/docs/#/event?id=setfg%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83
/* setCurtain_1_s
tooltip : setCurtain: 恢复画面色调,动画时间可不填
helpUrl : https://h5mota.com/games/template/docs/#/event?id=setcurtain%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83
default : [500,false]
colour : this.soundColor
Int_0 = Int_0!=='' ?(', "time": '+Int_0):'';
var async = Bool_0?', "async": true':'';
var code = '{"type": "setFg"'+Int_0 +async+'},\n';
var code = '{"type": "setCurtain"'+Int_0 +async+'},\n';
return code;
*/;
@ -1383,15 +1482,16 @@ return code;
*/;
playSound_s
: '播放音效' EvalString Newline
: '播放音效' EvalString '停止之前音效' Bool? Newline
/* playSound_s
tooltip : playSound: 播放音效
helpUrl : https://h5mota.com/games/template/docs/#/event?id=playsound%EF%BC%9A%E6%92%AD%E6%94%BE%E9%9F%B3%E6%95%88
default : ["item.mp3"]
default : ["item.mp3",false]
colour : this.soundColor
var code = '{"type": "playSound", "name": "'+EvalString_0+'"},\n';
Bool_0 = Bool_0 ? ', "stop": true' : '';
var code = '{"type": "playSound", "name": "'+EvalString_0+'"'+Bool_0+'},\n';
return code;
*/;
@ -1504,14 +1604,16 @@ return code;
*/;
switchCase
: '如果是' expression '的场合' BGNL? Newline action+
: '如果是' expression '的场合' '不跳出' Bool BGNL? Newline action+
/* switchCase
tooltip : 选项的选择
helpUrl : https://h5mota.com/games/template/docs/#/event?id=switch%EF%BC%9A%E5%A4%9A%E9%87%8D%E6%9D%A1%E4%BB%B6%E5%88%86%E6%AD%A7
default : ["", false]
colour : this.subColor
var code = '{"case": "'+expression_0+'", "action": [\n'+action_0+']},\n';
Bool_0 = Bool_0?', "nobreak": true':'';
var code = '{"case": "'+expression_0+'"'+Bool_0+', "action": [\n'+action_0+']},\n';
return code;
*/;
@ -1560,6 +1662,21 @@ var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\
return code;
*/;
confirm_s
: '显示确认框' ':' EvalString BGNL? '确定的场合' ':' '(默认选中' Bool '' BGNL? Newline action+ '取消的场合' ':' BGNL? Newline action+ BEND Newline
/* confirm_s
tooltip : 弹出确认框
helpUrl : https://h5mota.com/games/template/docs/#/
default : ["确认要xxx吗?",false]
Bool_0 = Bool_0?', "default": true':''
var code = ['{"type": "confirm"'+Bool_0+', "text": "',EvalString_0,'",\n',
'"yes": [\n',action_0,'],\n',
'"no": [\n',action_1,']\n',
'},\n'].join('');
return code;
*/;
while_s
: '循环处理' '' '当' expression '时' BGNL? Newline action+ BEND Newline
@ -1660,6 +1777,21 @@ var code = '{"type": "callLoad"},\n';
return code;
*/;
unknown_s
: '自定义事件' BGNL? RawEvalString
/* unknown_s
tooltip : 通过脚本自定义的事件类型, 以及编辑器不识别的事件类型
helpUrl : https://h5mota.com/games/template/docs/#/
default : ['{"type":"test", "data": "这是自定义的参数"}']
colour : this.dataColor
try {
var tempobj = JSON.parse(RawEvalString_0);
} catch (e) {throw new Error("不合法的JSON格式");}
if (!tempobj.type) throw new Error("自定义事件需要一个type:xxx");
var code = JSON.stringify(tempobj) +',\n';
return code;
*/;
function_s
: '自定义JS脚本' '不自动执行下一个事件' Bool BGNL? Newline RawEvalString Newline BEND Newline
@ -1828,6 +1960,10 @@ SetTextPosition_List
: '不改变'|'距离顶部'|'居中'|'距离底部'
/*SetTextPosition_List ['null','up','center','down']*/;
SetTextAlign_List
: '不改变'|'左对齐'|'左右居中'|'右对齐'
/*SetTextAlign_List ['null','left','center','right']*/;
ShopUse_List
: '金币' | '经验'
/*ShopUse_List ['money','experience']*/;
@ -1852,6 +1988,10 @@ Bg_Fg_List
: '背景层'|'前景层'
/*Bg_Fg_List ['bg','fg']*/;
Event_List
: '事件'|'战后事件'|'道具后事件'|'开门后事件'
/*Event_List ['null','afterBattle','afterGetItem','afterOpenDoor']*/;
Floor_Meta_List
: '楼层中文名'|'状态栏名称'|'能否使用楼传'|'能否打开快捷商店'|'是否不可浏览地图'|'是否不可瞬间移动'|'默认地面ID'|'楼层贴图'|'宝石血瓶效果'|'上楼点坐标'|'下楼点坐标'|'背景音乐'|'画面色调'|'天气和强度'|'是否地下层'
/*Floor_Meta_List ['title','name','canFlyTo', 'canUseQuickShop', 'cannotViewMap', 'cannotMoveDirectly', 'defaultGround', 'images', 'item_ratio', 'upFloor', 'downFloor', 'bgm', 'color', 'weather', 'underGround']*/;
@ -2006,7 +2146,7 @@ ActionParser.prototype.parse = function (obj,type) {
if (!this.isset(obj.time)) obj.time=500;
return MotaActionBlocks['changeFloor_m'].xmlText([
obj.floorType||'floorId',obj.floorId,obj.stair||'loc',obj.loc[0],obj.loc[1],obj.direction,
obj.time,!this.isset(obj.portalWithoutTrigger)
obj.time,!this.isset(obj.ignoreChangeFloor)
]);
case 'level':
@ -2040,10 +2180,26 @@ ActionParser.prototype.parse = function (obj,type) {
obj.id,obj.name,obj.icon,obj.textInList,obj.commonTimes,obj.mustEnable,obj.use,obj.need,parser.EvalString(obj.text),text_choices,next
]);
}
var buildcommentevent = function(obj,parser,next){
if (obj.args instanceof Array) {
try { obj.args = JSON.stringify(obj.args).replace(/"/g, "'"); }
catch (e) {obj.args = '';}
}
else obj.args = null;
return MotaActionBlocks['shopcommonevent'].xmlText([
obj.id,parser.EvalString(obj.textInList),obj.mustEnable,parser.EvalString(obj.commonEvent),obj.args,next
]);
}
var next=null;
if(!obj)obj=[];
while(obj.length){
next=buildsub(obj.pop(),this,next);
var shopobj=obj.pop()
if(shopobj.choices)
next=buildsub(shopobj,this,next);
else if(shopobj.commonEvent)
next=buildcommentevent(shopobj,this,next);
else
throw new Error("[警告]出错啦!\n"+shopobj.id+" 无效的商店");
}
return MotaActionBlocks['shop_m'].xmlText([next]);
@ -2103,7 +2259,7 @@ ActionParser.prototype.parseAction = function() {
break;
case "scrollText":
this.next = MotaActionBlocks['scrollText_s'].xmlText([
data.time, data.async||false, this.EvalString(data.text), this.next]);
data.time, data.lineHeight||1.4, data.async||false, this.EvalString(data.text), this.next]);
break;
case "comment": // 注释
this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString(data.text),this.next],null,data.text);
@ -2115,7 +2271,7 @@ ActionParser.prototype.parseAction = function() {
if (!/^\w+\.png$/.test(data.background))
data.background=setTextfunc(data.background);
this.next = MotaActionBlocks['setText_s'].xmlText([
data.position,data.offset,data.title,'rgba('+data.title+')',
data.position,data.offset,data.align,data.title,'rgba('+data.title+')',
data.text,'rgba('+data.text+')',data.background,'rgba('+data.background+')',
data.bold,data.titlefont,data.textfont,data.time,this.next]);
break;
@ -2260,8 +2416,16 @@ ActionParser.prototype.parseAction = function() {
break;
case "showImage": // 显示图片
data.loc=data.loc||['','']
if (data.sloc) {
this.next = MotaActionBlocks['showImage_1_s'].xmlText([
data.code,data.image||data.name,data.sloc[0],data.sloc[1],data.sloc[2],data.sloc[3],data.opacity,
data.loc[0],data.loc[1],data.loc[2],data.loc[3],data.time||0,data.async||false,this.next
]);
}
else {
this.next = MotaActionBlocks['showImage_s'].xmlText([
data.code,data.image||data.name,data.loc[0],data.loc[1],data.dw,data.dh,data.opacity,data.time||0,data.async||false,this.next]);
data.code,data.image||data.name,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]);
}
break;
case "hideImage": // 清除图片
this.next = MotaActionBlocks['hideImage_s'].xmlText([
@ -2270,7 +2434,7 @@ ActionParser.prototype.parseAction = function() {
case "showTextImage": // 显示图片化文本
data.loc=data.loc||['','']
this.next = MotaActionBlocks['showTextImage_s'].xmlText([
this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]);
this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.lineHeight||1.4,data.opacity,data.time||0,data.async||false,this.next]);
break;
case "moveImage": // 移动图片
data.to=data.to||['','']
@ -2287,11 +2451,12 @@ ActionParser.prototype.parseAction = function() {
}
break;
case "setFg": // 颜色渐变
case "setCurtain":
if(this.isset(data.color)){
this.next = MotaActionBlocks['setFg_0_s'].xmlText([
this.next = MotaActionBlocks['setCurtain_0_s'].xmlText([
data.color,'rgba('+data.color+')',data.time||0,data.async||false,this.next]);
} else {
this.next = MotaActionBlocks['setFg_1_s'].xmlText([
this.next = MotaActionBlocks['setCurtain_1_s'].xmlText([
data.time||0,data.async||false,this.next]);
}
break;
@ -2308,6 +2473,11 @@ ActionParser.prototype.parseAction = function() {
this.next = MotaActionBlocks['openDoor_s'].xmlText([
data.loc[0],data.loc[1],data.floorId||'',data.needKey||false,this.next]);
break;
case "closeDoor": // 关一个门,需要该点无事件
data.loc=data.loc||['','']
this.next = MotaActionBlocks['closeDoor_s'].xmlText([
data.loc[0],data.loc[1],data.id,this.next]);
break;
case "useItem": // 使用道具
this.next = MotaActionBlocks['useItem_s'].xmlText([
data.id,this.next]);
@ -2329,18 +2499,23 @@ ActionParser.prototype.parseAction = function() {
data.loc[0],data.loc[1],this.next]);
break;
case "insert": // 强制插入另一个点的事件在当前事件列表执行,当前坐标和楼层不会改变
if (data.args instanceof Array) {
try { data.args = JSON.stringify(data.args).replace(/"/g, "'"); }
catch (e) {data.args = '';}
}
else data.args = null;
if (this.isset(data.name)) {
this.next = MotaActionBlocks['insert_1_s'].xmlText([
data.name, this.next]);
data.name, data.args||"", this.next]);
}
else {
this.next = MotaActionBlocks['insert_2_s'].xmlText([
data.loc[0],data.loc[1],data.floorId||'',this.next]);
data.loc[0],data.loc[1],data.which,data.floorId||'',data.args||"",this.next]);
}
break;
case "playSound":
this.next = MotaActionBlocks['playSound_s'].xmlText([
data.name,this.next]);
data.name,data.stop,this.next]);
break;
case "playBgm":
this.next = MotaActionBlocks['playBgm_s'].xmlText([
@ -2372,14 +2547,13 @@ ActionParser.prototype.parseAction = function() {
break
case "setValue":
this.next = MotaActionBlocks['setValue_s'].xmlText([
// MotaActionBlocks['idString_e'].xmlText([data.name]),
this.tryToUseEvFlag_e('idString_e', [data.name]),
MotaActionBlocks['evalString_e'].xmlText([data.value]),
this.next]);
break;
case "setValue2":
this.next = MotaActionBlocks['setValue2_s'].xmlText([
// MotaActionBlocks['idString_e'].xmlText([data.name]),
case "addValue":
this.next = MotaActionBlocks['addValue_s'].xmlText([
this.tryToUseEvFlag_e('idString_e', [data.name]),
MotaActionBlocks['evalString_e'].xmlText([data.value]),
this.next]);
@ -2416,11 +2590,18 @@ ActionParser.prototype.parseAction = function() {
this.insertActionList(data["false"]),
this.next]);
break;
case "confirm": // 显示确认框
this.next = MotaActionBlocks['confirm_s'].xmlText([
this.EvalString(data.text), data["default"],
this.insertActionList(data["yes"]),
this.insertActionList(data["no"]),
this.next]);
break;
case "switch": // 多重条件分歧
var case_caseList = null;
for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) {
case_caseList=MotaActionBlocks['switchCase'].xmlText([
this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",this.insertActionList(caseNow.action),case_caseList]);
this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",caseNow.nobreak,this.insertActionList(caseNow.action),case_caseList]);
}
this.next = MotaActionBlocks['switch_s'].xmlText([
// MotaActionBlocks['evalString_e'].xmlText([data.condition]),
@ -2516,7 +2697,8 @@ ActionParser.prototype.parseAction = function() {
case "animateImage": // 兼容 animateImage
break;
default:
throw new Error("[警告]出错啦!\n"+data.type+" 事件不被支持...");
this.next = MotaActionBlocks['unknown_s'].xmlText([
JSON.stringify(data),this.next]);
}
this.parseAction();
return;

View File

@ -1,5 +1,7 @@
# editor
[重构](refactoring.md)
>! 以下均是v2.0时的说明, 未及时改动
本目录下所有文件,以及`../editor.html`和`../启动服务.exe`([源码](http://github.com/ckcz123/mota-js-server/))是地图编辑器的所有组件.
@ -31,7 +33,7 @@
``` js
editor.mapInit();//清空地图
editor.changeFloor('MT2')//切换地图
editor.guid()//产生一个可以作为id的长随机字符串
editor.util.guid()//产生一个可以作为id的长随机字符串
```
`editor.updateMap`中画未定义快的报错

View File

@ -227,8 +227,8 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"openDoor",
"passNet",
"changeLight",
"ski",
"pushBox"
"pushBox",
"custom"
]
},
"_data": "该图块的默认触发器"

View File

@ -54,7 +54,7 @@ body {
height: 630px;
}
#editArea {
#mapEditArea {
position: absolute;
width: 100%;
height: 400px;
@ -107,7 +107,7 @@ body {
top: 530px;
}
#editArea p {
#mapEditArea p {
margin: 10px;
display: block;
width: 70%;
@ -148,7 +148,6 @@ body {
height: 180px;
left: 0;
bottom: 0;
border-top: 1px solid #ccc;
padding: 10px 5px;
margin-left: 8px;;
box-sizing: border-box;

View File

@ -37,7 +37,7 @@ body {
position: absolute;
}
#editArea {
#mapEditArea {
position: absolute;
width: 100%;
height: 70%;
@ -64,7 +64,7 @@ body {
overflow: auto;
}
#editArea p {
#mapEditArea p {
margin: 10px;
display: block;
width: 70%;

View File

@ -187,6 +187,11 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_type": "textarea",
"_data": "初始生命值"
},
"manamax": {
"_leaf": true,
"_type": "textarea",
"_data": "魔力上限此项非负才会生效null或小于0都不会生效"
},
"mana": {
"_leaf": true,
"_type": "textarea",
@ -253,12 +258,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
}
}
},
"flyRange": {
"_leaf": true,
"_type": "textarea",
"_range": "thiseval instanceof Array",
"_data": "初始可飞的楼层;一般留空数组即可"
},
"loc": {
"_type": "object",
@ -636,7 +635,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_bool": "bool",
"_data": "寻路算法是否经过血瓶如果该项为false则寻路算法会自动尽量绕过血瓶"
},
"portalWithoutTrigger": {
"ignoreChangeFloor": {
"_leaf": true,
"_type": "checkbox",
"_bool": "bool",

View File

@ -41,15 +41,34 @@ editor.info
/////////// 数据相关 ///////////
editor.prototype.init = function (callback) {
editor_util_wrapper(editor);
editor_game_wrapper(editor, main, core);
editor_table_wrapper(editor);
var afterMainInit = function () {
editor.game.fixFunctionInGameData();
editor.main = main;
editor.core = core;
editor.fs = fs;
editor_file = editor_file(editor, function () {
editor.file = editor_file;
editor_mode = editor_mode(editor);
editor.mode = editor_mode;
core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.initStatus.maps);
core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function () {
afterCoreReset();
}, true);
core.events.setInitData(null);
});
}
var afterCoreReset = function () {
main.editor.disableGlobalAnimate = false;//允许GlobalAnimate
// core.setHeroMoveTriggerInterval();
editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息
editor.game.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息
editor.drawInitData(core.icons.icons); // 初始化绘图
editor.fetchMapFromCore();
editor.game.fetchMapFromCore();
editor.updateMap();
editor.buildMark();
editor.drawEventBlock();
@ -70,102 +89,9 @@ editor.prototype.init = function (callback) {
}
var afterMainInit = function () {
core.floors = JSON.parse(JSON.stringify(core.floors, function (k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
core.data = JSON.parse(JSON.stringify(core.data, function (k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = JSON.parse(JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, function (k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
editor.main = main;
editor.core = core;
editor.fs = fs;
editor_file = editor_file(editor, function () {
editor.file = editor_file;
editor_mode = editor_mode(editor);
editor.mode = editor_mode;
core.resetStatus(core.firstData.hero, null, core.firstData.floorId, null, core.initStatus.maps);
core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function () {
afterCoreReset();
}, true);
core.events.setInitData(null);
});
}
afterMainInit();
}
editor.prototype.idsInit = function (maps, icons) {
editor.ids = [0];
editor.indexs = [];
var MAX_NUM = 0;
var keys=Object.keys(maps_90f36752_8815_4be8_b32b_d7fad1d0542e);
for(var ii=0;ii<keys.length;ii++){
var v=~~keys[ii];
if(v>MAX_NUM && v<core.icons.tilesetStartOffset)MAX_NUM=v;
}
editor.MAX_NUM=MAX_NUM;
var getInfoById = function (id) {
var block = maps.initBlock(0, 0, id);
if (hasOwnProp(block, 'event')) {
return block;
}
}
var point = 0;
for (var i = 0; i <= MAX_NUM; i++) {
var indexBlock = getInfoById(i);
editor.indexs[i] = [];
if (indexBlock) {
var id = indexBlock.event.id;
var indexId = indexBlock.id;
var allCls = Object.keys(icons);
if(i==17){
editor.ids.push({'idnum': 17, 'id': id, 'images': 'terrains'});
point++;
editor.indexs[i].push(point);
continue;
}
for (var j = 0; j < allCls.length; j++) {
if (id in icons[allCls[j]]) {
editor.ids.push({'idnum': indexId, 'id': id, 'images': allCls[j], 'y': icons[allCls[j]][id]});
point++;
editor.indexs[i].push(point);
}
}
}
}
editor.indexs[0] = [0];
var startOffset = core.icons.tilesetStartOffset;
for (var i in core.tilesets) {
var imgName = core.tilesets[i];
var img = core.material.images.tilesets[imgName];
var width = Math.floor(img.width/32), height = Math.floor(img.height/32);
if(img.width%32 || img.height%32){
alert(imgName+'的长或宽不是32的整数倍, 请修改后刷新页面');
}
if(img.width*img.height > 32*32*3000){
alert(imgName+'上的图块数量超过了3000请修改后刷新页面');
}
for (var id=startOffset; id<startOffset+width*height;id++) {
var x = (id-startOffset)%width, y = parseInt((id-startOffset)/width);
var indexBlock = getInfoById(id);
editor.ids.push({'idnum': id, 'id': indexBlock.event.id, 'images': imgName, "x": x, "y": y, isTile: true});
point++;
editor.indexs[id]=[point];
}
startOffset += core.icons.tilesetStartOffset;
}
}
editor.prototype.mapInit = function () {
var ec = document.getElementById('event').getContext('2d');
ec.clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32);
@ -193,39 +119,6 @@ editor.prototype.mapInit = function () {
editor.currentFloorData.cannotMove = {};
}
editor.prototype.fetchMapFromCore = function(){
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];
if (!core.isset(y)) {
printe("素材数字"+x+"未定义。是不是忘了注册或者接档时没有覆盖icons.js和maps.js");
y = [0];
}
return editor.ids[y[0]]
})
});
editor.currentFloorId = core.status.floorId;
editor.currentFloorData = core.floors[core.status.floorId];
for(var ii=0,name;name=['bgmap','fgmap'][ii];ii++){
var mapArray = editor.currentFloorData[name];
if(!mapArray || JSON.stringify(mapArray)==JSON.stringify([])){//未设置或空数组
//与editor.map同形的全0
mapArray=eval('['+Array(editor.map.length+1).join('['+Array(editor.map[0].length+1).join('0,')+'],')+']');
}
editor[name]=mapArray.map(function (v) {
return v.map(function (v) {
var x = parseInt(v), y = editor.indexs[x];
if (!core.isset(y)) {
printe("素材数字"+x+"未定义。是不是忘了注册或者接档时没有覆盖icons.js和maps.js");
y = [0];
}
return editor.ids[y[0]]
})
});
}
}
editor.prototype.changeFloor = function (floorId, callback) {
for(var ii=0,name;name=['map','bgmap','fgmap'][ii];ii++){
var mapArray=editor[name].map(function (v) {
@ -241,11 +134,11 @@ editor.prototype.changeFloor = function (floorId, callback) {
core.bigmap.offsetY=0;
editor.moveViewport(0,0);
editor.fetchMapFromCore();
editor.game.fetchMapFromCore();
editor.updateMap();
editor_mode.floor();
editor.drawEventBlock();
if (core.isset(callback)) callback();
if (callback) callback();
});
}
@ -254,22 +147,22 @@ editor.prototype.changeFloor = function (floorId, callback) {
editor.prototype.drawEventBlock = function () {
var fg=document.getElementById('efg').getContext('2d');
fg.clearRect(0, 0, 416, 416);
for (var i=0;i<13;i++) {
for (var j=0;j<13;j++) {
fg.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
for (var i=0;i<core.__SIZE__;i++) {
for (var j=0;j<core.__SIZE__;j++) {
var color=[];
var loc=(i+core.bigmap.offsetX/32)+","+(j+core.bigmap.offsetY/32);
if (core.isset(editor.currentFloorData.events[loc]))
if (editor.currentFloorData.events[loc])
color.push('#FF0000');
if (core.isset(editor.currentFloorData.changeFloor[loc]))
if (editor.currentFloorData.changeFloor[loc])
color.push('#00FF00');
if (core.isset(editor.currentFloorData.afterBattle[loc]))
if (editor.currentFloorData.afterBattle[loc])
color.push('#FFFF00');
if (core.isset(editor.currentFloorData.afterGetItem[loc]))
if (editor.currentFloorData.afterGetItem[loc])
color.push('#00FFFF');
if (core.isset(editor.currentFloorData.afterOpenDoor[loc]))
if (editor.currentFloorData.afterOpenDoor[loc])
color.push('#FF00FF');
if (core.isset(editor.currentFloorData.cannotMove[loc]))
if (editor.currentFloorData.cannotMove[loc])
color.push('#0000FF');
for(var kk=0,cc;cc=color[kk];kk++){
fg.fillStyle = cc;
@ -302,14 +195,12 @@ editor.prototype.updateMap = function () {
core.status.thisMap.blocks = blocks;
var updateMap = function () {
core.removeGlobalAnimate(null, null, true);
core.removeGlobalAnimate();
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);
core.maps._drawMap_drawAll();
}
updateMap();
@ -352,28 +243,13 @@ editor.prototype.updateMap = function () {
}
editor.prototype.moveViewport=function(x,y){
core.bigmap.offsetX = core.clamp(core.bigmap.offsetX+32*x, 0, 32*core.bigmap.width-416);
core.bigmap.offsetY = core.clamp(core.bigmap.offsetY+32*y, 0, 32*core.bigmap.height-416);
core.bigmap.offsetX = core.clamp(core.bigmap.offsetX+32*x, 0, 32*core.bigmap.width-core.__PIXELS__);
core.bigmap.offsetY = core.clamp(core.bigmap.offsetY+32*y, 0, 32*core.bigmap.height-core.__PIXELS__);
core.control.updateViewport();
editor.buildMark();
editor.drawPosSelection();
}
/////////// 通用 ///////////
editor.prototype.guid = function () {
return 'id_' + 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
editor.prototype.HTMLescape = function (str_) {
return String(str_).split('').map(function (v) {
return '&#' + v.charCodeAt(0) + ';'
}).join('');
}
/////////// 界面交互相关 ///////////
editor.prototype.drawInitData = function (icons) {
@ -511,14 +387,14 @@ editor.prototype.buildMark = function(){
var mapRowMark=document.getElementById('mapRowMark');
var buildMark = function (offsetX,offsetY) {
var colNum = ' ';
for (var i = 0; i < 13; i++) {
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<td>' + (i+offsetX) + '<div class="colBlock" style="left:' + (i * 32 + 1) + 'px;"></div></td>';
colNum += tpl;
}
arrColMark.innerHTML = '<tr>' + colNum + '</tr>';
mapColMark.innerHTML = '<tr>' + colNum + '</tr>';
var rowNum = ' ';
for (var i = 0; i < 13; i++) {
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<tr><td>' + (i+offsetY) + '<div class="rowBlock" style="top:' + (i * 32 + 1) + 'px;"></div></td></tr>';
rowNum += tpl;
}
@ -527,29 +403,29 @@ editor.prototype.buildMark = function(){
}
var buildMark_mobile = function (offsetX,offsetY) {
var colNum = ' ';
for (var i = 0; i < 13; i++) {
var tpl = '<td>' + (' '+i).slice(-2).replace(' ','&nbsp;') + '<div class="colBlock" style="left:' + (i * 96/13 ) + 'vw;"></div></td>';
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<td>' + (' '+i).slice(-2).replace(' ','&nbsp;') + '<div class="colBlock" style="left:' + (i * 96/core.__SIZE__) + 'vw;"></div></td>';
colNum += tpl;
}
arrColMark.innerHTML = '<tr>' + colNum + '</tr>';
//mapColMark.innerHTML = '<tr>' + colNum + '</tr>';
var rowNum = ' ';
for (var i = 0; i < 13; i++) {
var tpl = '<tr><td>' + (' '+i).slice(-2).replace(' ','&nbsp;') + '<div class="rowBlock" style="top:' + (i * 96/13 ) + 'vw;"></div></td></tr>';
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<tr><td>' + (' '+i).slice(-2).replace(' ','&nbsp;') + '<div class="rowBlock" style="top:' + (i * 96/core.__SIZE__) + 'vw;"></div></td></tr>';
rowNum += tpl;
}
arrRowMark.innerHTML = rowNum;
//mapRowMark.innerHTML = rowNum;
//=====
var colNum = ' ';
for (var i = 0; i < 13; i++) {
var tpl = '<div class="coltd" style="left:' + (i * 96/13 ) + 'vw;"><div class="coltext">' + (' '+(i+offsetX)).slice(-2).replace(' ','&nbsp;') + '</div><div class="colBlock"></div></div>';
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<div class="coltd" style="left:' + (i * 96/core.__SIZE__) + 'vw;"><div class="coltext">' + (' '+(i+offsetX)).slice(-2).replace(' ','&nbsp;') + '</div><div class="colBlock"></div></div>';
colNum += tpl;
}
mapColMark.innerHTML = '<div class="coltr">' + colNum + '</div>';
var rowNum = ' ';
for (var i = 0; i < 13; i++) {
var tpl = '<div class="rowtr"><div class="rowtd" style="top:' + (i * 96/13 ) + 'vw;"><div class="rowtext">' + (' '+(i+offsetY)).slice(-2).replace(' ','&nbsp;') + '</div><div class="rowBlock"></div></div></div>';
for (var i = 0; i < core.__SIZE__; i++) {
var tpl = '<div class="rowtr"><div class="rowtd" style="top:' + (i * 96/core.__SIZE__) + 'vw;"><div class="rowtext">' + (' '+(i+offsetY)).slice(-2).replace(' ','&nbsp;') + '</div><div class="rowBlock"></div></div></div>';
rowNum += tpl;
}
mapRowMark.innerHTML = rowNum;
@ -578,9 +454,9 @@ editor.prototype.setSelectBoxFromInfo=function(thisevent){
dataSelection.style.left = pos.x * 32 + 'px';
dataSelection.style.top = pos.y * ysize + 'px';
dataSelection.style.height = ysize - 6 + 'px';
setTimeout(function(){selectBox.isSelected = true;});
setTimeout(function(){selectBox.isSelected(true);});
editor.info = JSON.parse(JSON.stringify(thisevent));
tip.infos = JSON.parse(JSON.stringify(thisevent));
tip.infos(JSON.parse(JSON.stringify(thisevent)));
editor.pos=pos;
editor_mode.onmode('nextChange');
editor_mode.onmode('enemyitem');
@ -622,7 +498,7 @@ editor.prototype.listen = function () {
}
if (unselect) {
if (clickpath.indexOf('eui') === -1) {
if (selectBox.isSelected) {
if (selectBox.isSelected()) {
editor_mode.onmode('');
editor.file.saveFloorFile(function (err) {
if (err) {
@ -632,7 +508,7 @@ editor.prototype.listen = function () {
;printf('地图保存成功');
});
}
selectBox.isSelected = false;
selectBox.isSelected(false);
editor.info = {};
}
}
@ -662,7 +538,7 @@ editor.prototype.listen = function () {
editor.loc = {
'x': scrollLeft + xx - mid.offsetLeft - mapEdit.offsetLeft,
'y': scrollTop + yy - mid.offsetTop - mapEdit.offsetTop,
'size': editor.isMobile?(32*innerWidth*0.96/416):32
'size': editor.isMobile?(32*innerWidth*0.96/core.__PIXELS__):32
};
return editor.loc;
}//返回可用的组件内坐标
@ -690,7 +566,7 @@ editor.prototype.listen = function () {
}
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
}//用于鼠标移出canvas时的自动清除状态
eui.oncontextmenu=function(e){e.preventDefault()}
@ -710,13 +586,13 @@ editor.prototype.listen = function () {
editor.showMidMenu(e.clientX,e.clientY);
return;
}
if (!selectBox.isSelected) {
if (!selectBox.isSelected()) {
var loc = eToLoc(e);
var pos = locToPos(loc,true);
editor_mode.onmode('nextChange');
editor_mode.onmode('loc');
//editor_mode.loc();
//tip.whichShow = 1;
//tip.whichShow(1);
if(editor.isMobile)editor.showMidMenu(e.clientX,e.clientY);
return;
}
@ -726,7 +602,7 @@ editor.prototype.listen = function () {
mouseOutCheck = 2;
setTimeout(clear1);
e.stopPropagation();
uc.clearRect(0, 0, 416, 416);
uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
var loc = eToLoc(e);
var pos = locToPos(loc,true);
stepPostfix = [];
@ -735,8 +611,8 @@ editor.prototype.listen = function () {
}
eui.onmousemove = function (e) {
if (!selectBox.isSelected) {
//tip.whichShow = 1;
if (!selectBox.isSelected()) {
//tip.whichShow(1);
return;
}
@ -766,8 +642,8 @@ editor.prototype.listen = function () {
}
eui.onmouseup = function (e) {
if (!selectBox.isSelected) {
//tip.whichShow = 1;
if (!selectBox.isSelected()) {
//tip.whichShow(1);
return;
}
holdingPath = 0;
@ -812,7 +688,7 @@ editor.prototype.listen = function () {
editor.updateMap();
holdingPath = 0;
stepPostfix = [];
uc.clearRect(0, 0, 416, 416);
uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
}
}
@ -897,7 +773,7 @@ editor.prototype.listen = function () {
if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1)
e.preventDefault();
//Ctrl+z 撤销上一步undo
if (e.keyCode == 90 && e.ctrlKey && editor.preMapData && currDrawData.pos.length && selectBox.isSelected) {
if (e.keyCode == 90 && e.ctrlKey && editor.preMapData && currDrawData.pos.length && selectBox.isSelected()) {
editor.map = JSON.parse(JSON.stringify(editor.preMapData.map));
editor.fgmap = JSON.parse(JSON.stringify(editor.preMapData.fgmap));
editor.bgmap = JSON.parse(JSON.stringify(editor.preMapData.bgmap));
@ -907,7 +783,7 @@ editor.prototype.listen = function () {
editor.preMapData = null;
}
//Ctrl+y 重做一步redo
if (e.keyCode == 89 && e.ctrlKey && reDo && reDo.pos.length && selectBox.isSelected) {
if (e.keyCode == 89 && e.ctrlKey && reDo && reDo.pos.length && selectBox.isSelected()) {
editor.preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap}));
for (var j = 0; j < reDo.pos.length; j++)
editor.map[reDo.pos[j].y][reDo.pos[j].x] = JSON.parse(JSON.stringify(reDo.info));
@ -1029,7 +905,7 @@ editor.prototype.listen = function () {
} else if ((pos.y + 1) * ysize > editor.widthsX[spriter][3])
pos.y = ~~(editor.widthsX[spriter][3] / ysize) - 1;
selectBox.isSelected = true;
selectBox.isSelected(true);
// console.log(pos,core.material.images[pos.images].height)
dataSelection.style.left = pos.x * 32 + 'px';
dataSelection.style.top = pos.y * ysize + 'px';
@ -1060,7 +936,7 @@ editor.prototype.listen = function () {
}
}
}
tip.infos = JSON.parse(JSON.stringify(editor.info));
tip.infos(JSON.parse(JSON.stringify(editor.info)));
editor_mode.onmode('nextChange');
editor_mode.onmode('enemyitem');
//editor_mode.enemyitem();
@ -1132,12 +1008,12 @@ editor.prototype.listen = function () {
chooseThis.onmousedown = function(e){
editor.hideMidMenu();
e.stopPropagation();
selectBox.isSelected = false;
selectBox.isSelected(false);
editor_mode.onmode('nextChange');
editor_mode.onmode('loc');
//editor_mode.loc();
//tip.whichShow = 1;
//tip.whichShow(1);
if(editor.isMobile)editor.showdataarea(false);
}

View File

@ -37,6 +37,11 @@ editor_blockly = function () {
{"text": "防御+4", "effect": "status:def+=4"},
{"text": "魔防+10", "effect": "status:mdef+=10"}
]
},{
"id": "keyShop1",
"textInList": "回收钥匙商店",
"commonEvent": "回收钥匙商店",
"args": ""
}],'shop'),
MotaActionBlocks['afterBattle_m'].xmlText(),
MotaActionBlocks['afterGetItem_m'].xmlText(),
@ -54,6 +59,7 @@ editor_blockly = function () {
MotaActionBlocks['scrollText_s'].xmlText(),
MotaActionBlocks['setText_s'].xmlText(),
MotaActionBlocks['showImage_s'].xmlText(),
MotaActionBlocks['showImage_1_s'].xmlText(),
MotaActionBlocks['hideImage_s'].xmlText(),
MotaActionBlocks['showTextImage_s'].xmlText(),
MotaActionBlocks['moveImage_s'].xmlText(),
@ -70,12 +76,13 @@ editor_blockly = function () {
])
])
]),
MotaActionBlocks['confirm_s'].xmlText(),
],
'数据相关':[
MotaActionBlocks['setValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
MotaActionBlocks['setValue2_s'].xmlText([
MotaActionBlocks['addValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
MotaActionBlocks['setFloor_s'].xmlText(),
@ -93,6 +100,7 @@ editor_blockly = function () {
MotaActionBlocks['changePos_1_s'].xmlText(),
MotaActionBlocks['battle_s'].xmlText(),
MotaActionBlocks['openDoor_s'].xmlText(),
MotaActionBlocks['closeDoor_s'].xmlText(),
MotaActionBlocks['useItem_s'].xmlText(),
MotaActionBlocks['openShop_s'].xmlText(),
MotaActionBlocks['setBlock_s'].xmlText(),
@ -105,7 +113,7 @@ editor_blockly = function () {
MotaActionBlocks['if_s'].xmlText(),
MotaActionFunctions.actionParser.parseList({"type": "switch", "condition": "判别值", "caseList": [
{"action": [{"type": "comment", "text": "当判别值是值的场合执行此事件"}]},
{"action": []},
{"action": [], "nobreak": true},
{"case": "default", "action": [{"type": "comment", "text": "当没有符合的值的场合执行default事件"}]},
]}),
MotaActionBlocks['while_s'].xmlText(),
@ -134,8 +142,8 @@ editor_blockly = function () {
MotaActionBlocks['animate_s'].xmlText(),
MotaActionBlocks['showStatusBar_s'].xmlText(),
MotaActionBlocks['hideStatusBar_s'].xmlText(),
MotaActionBlocks['setFg_0_s'].xmlText(),
MotaActionBlocks['setFg_1_s'].xmlText(),
MotaActionBlocks['setCurtain_0_s'].xmlText(),
MotaActionBlocks['setCurtain_1_s'].xmlText(),
MotaActionBlocks['screenFlash_s'].xmlText(),
MotaActionBlocks['setWeather_s'].xmlText(),
MotaActionBlocks['playBgm_s'].xmlText(),
@ -152,12 +160,13 @@ editor_blockly = function () {
],
'原生脚本':[
MotaActionBlocks['function_s'].xmlText(),
MotaActionBlocks['unknown_s'].xmlText(),
],
'值块':[
MotaActionBlocks['setValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
MotaActionBlocks['setValue2_s'].xmlText([
MotaActionBlocks['addValue_s'].xmlText([
MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
]),
MotaActionBlocks['expression_arithmetic_0'].xmlText(),
@ -184,8 +193,8 @@ editor_blockly = function () {
{"text": "黄钥匙(\${9+flag:shop_times}金币)", "color": [255,255,0,1], "action": [
{"type": "if", "condition": "status:money>=9+flag:shop_times",
"true": [
{"type": "setValue2", "name": "status:money", "value": "-(9+flag:shop_times)"},
{"type": "setValue2", "name": "item:yellowKey", "value": "1"},
{"type": "addValue", "name": "status:money", "value": "-(9+flag:shop_times)"},
{"type": "addValue", "name": "item:yellowKey", "value": "1"},
],
"false": [
"\t[老人,man]你的金钱不足!",
@ -200,7 +209,7 @@ editor_blockly = function () {
]}
]
},
{"type": "setValue2", "name": "flag:shop_times", "value": "1"},
{"type": "addValue", "name": "flag:shop_times", "value": "1"},
{"type": "revisit"}
], 'event'),
'<label text="战前剧情"></label>',
@ -223,7 +232,7 @@ editor_blockly = function () {
],'afterBattle'),
'<label text="打怪开门"></label>',
MotaActionFunctions.actionParser.parse([
{"type": "setValue2", "name": "flag:__door__", "value": "1"},
{"type": "addValue", "name": "flag:__door__", "value": "1"},
{"type": "if", "condition": "flag:__door__==2",
"true": [
{"type": "openDoor", "loc": [10,5]}
@ -312,7 +321,8 @@ document.getElementById('blocklyDiv').onmousewheel = function(e){
//console.log(e);
e.preventDefault();
var hvScroll = e.shiftKey?'hScroll':'vScroll';
workspace.scrollbar[hvScroll].handlePosition_+=( ((e.deltaY||0)+(e.detail||0)) >0?20:-20);
var mousewheelOffsetValue=20/380*workspace.scrollbar[hvScroll].handleLength_*3;
workspace.scrollbar[hvScroll].handlePosition_+=( ((e.deltaY||0)+(e.detail||0)) >0?mousewheelOffsetValue:-mousewheelOffsetValue);
workspace.scrollbar[hvScroll].onScroll_();
workspace.setScale(workspace.scale);
}
@ -442,13 +452,13 @@ function omitedcheckUpdateFunction(event) {
xhr.onreadystatechange = function () {
if (xhr.readyState != 4) return;
if (xhr.status != 200) {
alert("无法在file://下加载");
alert("图块描述文件加载失败, 请在'启动服务.exe'中打开编辑器");
return;
}
input_ = xhr.responseText;
editor_blockly.runOne();
}
xhr.open('GET', '_server/blockly/MotaAction.g4', true);
xhr.open('GET', '_server/MotaAction.g4', true);
xhr.send(null);
codeAreaHL = CodeMirror.fromTextArea(document.getElementById("codeArea"), {
@ -512,7 +522,7 @@ function omitedcheckUpdateFunction(event) {
var blocklyWidgetDiv = document.getElementsByClassName('blocklyWidgetDiv');
editor_blockly.show = function () {
if (typeof(selectBox) !== typeof(undefined)) selectBox.isSelected = false;
if (typeof(selectBox) !== typeof(undefined)) selectBox.isSelected(false);
document.getElementById('left6').style = '';
for (var ii = 0, node; node = blocklyWidgetDiv[ii]; ii++) {
node.style.zIndex = 201;
@ -580,6 +590,7 @@ function omitedcheckUpdateFunction(event) {
'showTextImage_s': 'EvalString_0',
'function_s': 'RawEvalString_0',
'shopsub': 'EvalString_3',
'confirm_s': 'EvalString_0',
}
var f = b ? textStringDict[b.type] : null;
if (f) {

View File

@ -8,6 +8,7 @@ editor_file = function (editor, callback) {
'data.comment': 'dataComment',
'functions.comment': 'functionsComment',
'events.comment': 'eventsComment',
'plugins.comment': 'pluginsComment',
}
for (var key in commentjs) {
(function (key) {
@ -93,7 +94,7 @@ editor_file = function (editor, callback) {
}
// format 更改实现方式以支持undefined删除
var tempJsonObj=Object.assign({},editor.currentFloorData);
var tempMap=[['map',editor.guid()],['bgmap',editor.guid()],['fgmap',editor.guid()]];
var tempMap=[['map',editor.util.guid()],['bgmap',editor.util.guid()],['fgmap',editor.util.guid()]];
tempMap.forEach(function(v){
v[2]=tempJsonObj[v[0]];
tempJsonObj[v[0]]=v[1];
@ -154,7 +155,7 @@ editor_file = function (editor, callback) {
cannotMove: {}
};
Object.keys(editor.currentFloorData).forEach(function (t) {
if (!core.isset(editor.currentFloorData[t]))
if (editor.currentFloorData[t] == null)
delete editor.currentFloorData[t];
})
editor.currentFloorData.map = "new";
@ -216,7 +217,7 @@ editor_file = function (editor, callback) {
cannotMove: {}
};
Object.keys(data).forEach(function (t) {
if (!core.isset(data[t]))
if (data[t] == null)
delete data[t];
else {
if (t=='map') {
@ -278,7 +279,7 @@ editor_file = function (editor, callback) {
// get id num
var id = c+idnum;
if (image=='terrains' && core.isset(terrainsId[y])) {
if (image=='terrains' && terrainsId[y] != null) {
id=terrainsId[y];
}
else {
@ -763,7 +764,7 @@ editor_file = function (editor, callback) {
var fmap = {};
var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a, function (k, v) {
if (v instanceof Function) {
var id_ = editor.guid();
var id_ = editor.util.guid();
fmap[id_] = v.toString();
return id_;
} else return v
@ -849,6 +850,65 @@ editor_file = function (editor, callback) {
////////////////////////////////////////////////////////////////////
var plmap = {};
var pljson = JSON.stringify(plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1, function (k, v) {
if (v instanceof Function) {
var id_ = editor.util.guid();
plmap[id_] = v.toString();
return id_;
} else if(v===null){
var id_ = editor.util.guid();
plmap[id_] = 'null';
return id_;
} return v
}, 4);
var plobj = JSON.parse(pljson);
editor_file.pluginsMap = plmap;
editor_file.pluginsObj = plobj;
var buildpllocobj = function (locObj) {
for (var key in locObj) {
if (typeof(locObj[key]) !== typeof('')) buildpllocobj(locObj[key]);
else locObj[key] = plmap[locObj[key]];
}
};
editor_file.editPlugins = function (actionList, callback) {
/*actionList:[
["change","['test']","function(x,y){console.log(x,y)}"],
]
[]时只查询不修改
*/
if (!isset(callback)) {
printe('未设置callback');
throw('未设置callback')
}
;
if (isset(actionList) && actionList.length > 0) {
saveSetting('plugins', actionList, function (err) {
callback([
(function () {
var locObj = JSON.parse(JSON.stringify(plobj));
buildpllocobj(locObj);
return locObj;
})(),
editor_file.pluginsComment,
err]);
});
} else {
callback([
(function () {
var locObj = JSON.parse(JSON.stringify(plobj));
buildpllocobj(locObj);
return locObj;
})(),
editor_file.pluginsComment,
null]);
}
}
//callback([obj,commentObj,err:String])
////////////////////////////////////////////////////////////////////
var isset = function (val) {
if (val == undefined || val == null) {
return false;
@ -920,7 +980,7 @@ editor_file = function (editor, callback) {
var emap = {};
var estr = JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e, function (k, v) {
if (v.id != null) {
var id_ = editor.guid();
var id_ = editor.util.guid();
emap[id_] = JSON.stringify(v);
return id_;
} else return v
@ -954,7 +1014,7 @@ editor_file = function (editor, callback) {
var emap = {};
var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80, function (k, v) {
if (v.hp != null) {
var id_ = editor.guid();
var id_ = editor.util.guid();
emap[id_] = JSON.stringify(v);
return id_;
} else return v
@ -999,7 +1059,9 @@ editor_file = function (editor, callback) {
if (file == 'floorloc') {
actionList.forEach(function (value) {
// 检测null/undefined
if (!core.isset(value[2]))value[2]=undefined;
if (value[2]==null)
eval("delete editor.currentFloorData" + value[1]);
else
eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2]));
});
editor_file.saveFloorFile(callback);
@ -1023,6 +1085,25 @@ editor_file = function (editor, callback) {
});
return;
}
if (file == 'plugins') {
actionList.forEach(function (value) {
if(value[0]==='add'){
eval("plobj" + value[1] + '=' + JSON.stringify(value[2]));
} else {
eval("plmap[plobj" + value[1] + ']=' + JSON.stringify(value[2]));
}
});
var plraw = JSON.stringify(plobj,null,4);
for (var id_ in plmap) {
plraw = plraw.replace('"' + id_ + '"', plmap[id_])
}
var datastr = 'var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = \n';
datastr += plraw;
fs.writeFile('project/plugins.js', encode(datastr), 'base64', function (err, data) {
callback(err);
});
return;
}
callback('出错了,要设置的文件名不识别');
}

124
_server/editor_game.js Normal file
View File

@ -0,0 +1,124 @@
editor_game_wrapper = function (editor, main, core) {
editor_game = function () {
}
editor_game.prototype.fixFunctionInGameData = function () {
core.floors = JSON.parse(JSON.stringify(core.floors, function (_k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
core.data = JSON.parse(JSON.stringify(core.data, function (_k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = JSON.parse(JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, function (_k, v) {
if (v instanceof Function) {
return v.toString()
} else return v
}));
}
editor_game.prototype.idsInit = function (maps, icons) {
editor.ids = [0];
editor.indexs = [];
var MAX_NUM = 0;
var keys=Object.keys(maps_90f36752_8815_4be8_b32b_d7fad1d0542e);
for(var ii=0;ii<keys.length;ii++){
var v=~~keys[ii];
if(v>MAX_NUM && v<core.icons.tilesetStartOffset)MAX_NUM=v;
}
editor.MAX_NUM=MAX_NUM;
var getInfoById = function (id) {
var block = maps.initBlock(0, 0, id);
if (hasOwnProp(block, 'event')) {
return block;
}
}
var point = 0;
for (var i = 0; i <= MAX_NUM; i++) {
var indexBlock = getInfoById(i);
editor.indexs[i] = [];
if (indexBlock) {
var id = indexBlock.event.id;
var indexId = indexBlock.id;
var allCls = Object.keys(icons);
if(i==17){
editor.ids.push({'idnum': 17, 'id': id, 'images': 'terrains'});
point++;
editor.indexs[i].push(point);
continue;
}
for (var j = 0; j < allCls.length; j++) {
if (id in icons[allCls[j]]) {
editor.ids.push({'idnum': indexId, 'id': id, 'images': allCls[j], 'y': icons[allCls[j]][id]});
point++;
editor.indexs[i].push(point);
}
}
}
}
editor.indexs[0] = [0];
var startOffset = core.icons.tilesetStartOffset;
for (var i in core.tilesets) {
var imgName = core.tilesets[i];
var img = core.material.images.tilesets[imgName];
var width = Math.floor(img.width/32), height = Math.floor(img.height/32);
if(img.width%32 || img.height%32){
alert(imgName+'的长或宽不是32的整数倍, 请修改后刷新页面');
}
if(img.width*img.height > 32*32*3000){
alert(imgName+'上的图块数量超过了3000请修改后刷新页面');
}
for (var id=startOffset; id<startOffset+width*height;id++) {
var x = (id-startOffset)%width, y = parseInt((id-startOffset)/width);
var indexBlock = getInfoById(id);
editor.ids.push({'idnum': id, 'id': indexBlock.event.id, 'images': imgName, "x": x, "y": y, isTile: true});
point++;
editor.indexs[id]=[point];
}
startOffset += core.icons.tilesetStartOffset;
}
}
editor_game.prototype.fetchMapFromCore = function(){
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];
if (y == null) {
printe("素材数字"+x+"未定义。是不是忘了注册或者接档时没有覆盖icons.js和maps.js");
y = [0];
}
return editor.ids[y[0]]
})
});
editor.currentFloorId = core.status.floorId;
editor.currentFloorData = core.floors[core.status.floorId];
for(var ii=0,name;name=['bgmap','fgmap'][ii];ii++){
var mapArray = editor.currentFloorData[name];
if(!mapArray || JSON.stringify(mapArray)==JSON.stringify([])){//未设置或空数组
//与editor.map同形的全0
mapArray=eval('['+Array(editor.map.length+1).join('['+Array(editor.map[0].length+1).join('0,')+'],')+']');
}
editor[name]=mapArray.map(function (v) {
return v.map(function (v) {
var x = parseInt(v), y = editor.indexs[x];
if (y == null) {
printe("素材数字"+x+"未定义。是不是忘了注册或者接档时没有覆盖icons.js和maps.js");
y = [0];
}
return editor.ids[y[0]]
})
});
}
}
editor.constructor.prototype.game = new editor_game();
}
//editor_game_wrapper(editor);

View File

@ -13,6 +13,7 @@ editor_mode = function (editor) {
'appendpic': 'left1',
'commonevent': 'left9',
'plugins': 'left10',
}
this._ids = {}
this.dom = {}
@ -37,309 +38,9 @@ editor_mode = function (editor) {
if (Boolean(callback)) callback();
}
/////////////////////////////////////////////////////////////////////////////
/**
* 把来自数据文件的obj和来自*comment.js的commentObj组装成表格
* commentObj在无视['_data']的意义下与obj同形
* : commentObj['_data']['a']['_data']['b'] obj['a']['b'] 是对应的
* 在此意义下, 两者的结构是一致的
* 在commentObj没有被定义的obj的分支, 会取defaultcobj作为默认值
* 因此在深度优先遍历时,维护
* field="['a']['b']"
* cfield="['_data']['a']['_data']['b']"
* vobj=obj['a']['b']
* cobj=commentObj['_data']['a']['_data']['b']
* cobj
* cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii])
* 每一项若未定义,就从defaultcobj中取
* 当其是函数不是具体值时,把args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}代入算出该值
* 得到的叶节点的<tr>结构如下
* tr>td[title=field]
* >td[title=comment,cobj=cobj:json]
* >td>div>input[value=thiseval]
* 返回结果
* 返回一个对象, 假设被命名为tableinfo
* 在把一个 table innerHTML 赋值为 tableinfo.HTML
* 再调 tableinfo.listen(tableinfo.guids) 进行绑定事件
* @param {Object} obj
* @param {Object} commentObj
* @returns {{"HTML":String,"guids":String[],"listen":Function}}
*/
editor_mode.prototype.objToTable_ = function (obj, commentObj) {
// 表格抬头
var outstr = ["\n<tr><td>条目</td><td>注释</td><td>值</td></tr>\n"];
var guids = [];
var defaultcobj = {
// 默认是文本域
_type: 'textarea',
_data: '',
_string: function (args) {//object~[field,cfield,vobj,cobj]
var thiseval = args.vobj;
return (typeof(thiseval) === typeof('')) && thiseval[0] === '"';
},
// 默认情况下 非对象和数组的视为叶节点
_leaf: function (args) {//object~[field,cfield,vobj,cobj]
var thiseval = args.vobj;
if (thiseval == null || thiseval == undefined) return true;//null,undefined
if (typeof(thiseval) === typeof('')) return true;//字符串
if (Object.keys(thiseval).length === 0) return true;//数字,true,false,空数组,空对象
return false;
},
}
/**
* 深度优先遍历, p*即为父节点的四个属性
* @param {String} pfield
* @param {String} pcfield
* @param {Object} pvobj
* @param {Object} pcobj
*/
var recursionParse = function (pfield, pcfield, pvobj, pcobj) {
var keysForTableOrder={};
var voidMark={};
// 1. 按照pcobj排序生成
if (pcobj && pcobj['_data']){
for (var ii in pcobj['_data']) keysForTableOrder[ii]=voidMark;
}
// 2. 对每个pvobj且不在pcobj的再添加到最后
keysForTableOrder=Object.assign(keysForTableOrder,pvobj)
for (var ii in keysForTableOrder) {
// 3. 对于pcobj有但是pvobj中没有的, 弹出提示, (正常情况下editor_file会补全成null)
// 事实上能执行到这一步工程没崩掉打不开,就继续吧..
if(keysForTableOrder[ii]===voidMark){
if(typeof id_815975ad_ee6f_4684_aac7_397b7e392702==="undefined"){
alert('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
console.error('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
id_815975ad_ee6f_4684_aac7_397b7e392702=1;
}
pvobj[ii]=null;
}
var field = pfield + "['" + ii + "']";
var cfield = pcfield + "['_data']['" + ii + "']";
var vobj = pvobj[ii];
var cobj = null;
if (pcobj && pcobj['_data'] && pcobj['_data'][ii]) {
// cobj存在时直接取
cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii]);
} else {
// 当其函数时代入参数算出cobj, 不存在时只取defaultcobj
if (pcobj && (pcobj['_data'] instanceof Function)) cobj = Object.assign({}, defaultcobj, pcobj['_data'](ii));
else cobj = Object.assign({}, defaultcobj);
}
var args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}
// 当cobj的参数为函数时,代入args算出值
for (var key in cobj) {
if (key === '_data') continue;
if (cobj[key] instanceof Function) cobj[key] = cobj[key](args);
}
// 标记为_hide的属性不展示
if (cobj._hide)continue;
if (!cobj._leaf) {
// 不是叶节点时, 插入展开的标记并继续遍历, 此处可以改成按钮用来添加新项或折叠等
outstr.push(["<tr><td>----</td><td>----</td><td>", field, "</td></tr>\n"].join(''));
recursionParse(field, cfield, vobj, cobj);
} else {
// 是叶节点时, 调objToTr_渲染<tr>
var leafnode = editor_mode.objToTr_(obj, commentObj, field, cfield, vobj, cobj);
outstr.push(leafnode[0]);
guids.push(leafnode[1]);
}
}
}
// 开始遍历
recursionParse("", "", obj, commentObj);
var checkRange = function (cobj, thiseval) {
if (cobj._range) {
return eval(cobj._range);
}
if (cobj._select) {
return cobj._select.values.indexOf(thiseval)!==-1;
}
if (cobj._bool) {
return [true,false].indexOf(thiseval)!==-1;
}
return true;
}
var listen = function (guids) {
// 每个叶节点的事件绑定
guids.forEach(function (guid) {
// tr>td[title=field]
// >td[title=comment,cobj=cobj:json]
// >td>div>input[value=thiseval]
var thisTr = document.getElementById(guid);
var input = thisTr.children[2].children[0].children[0];
var field = thisTr.children[0].getAttribute('title');
var cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
var modeNode = thisTr.parentNode;
while (!editor_mode._ids.hasOwnProperty(modeNode.getAttribute('id'))) {
modeNode = modeNode.parentNode;
}
input.onchange = function () {
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
var thiseval = null;
if (input.checked != null) input.value = input.checked;
try {
thiseval = JSON.parse(input.value);
} catch (ee) {
printe(field + ' : ' + ee);
throw ee;
}
if (checkRange(cobj, thiseval)) {
editor_mode.addAction(['change', field, thiseval]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
} else {
printe(field + ' : 输入的值不合要求,请鼠标放置在注释上查看说明');
}
}
// 双击表格时
// 正常编辑: 尝试用事件编辑器或多行文本编辑器打开
// 添加: 在该项的同一级创建一个内容为null新的项, 刷新后生效并可以继续编辑
// 删除: 删除该项, 刷新后生效
// 在点击按钮 添加/删除 后,下一次双击将被视为 添加/删除
var dblclickfunc=function () {
if(editor_mode.doubleClickMode==='change'){
if (cobj._type === 'event') editor_blockly.import(guid, {type: cobj._event});
if (cobj._type === 'textarea') editor_multi.import(guid, {lint: cobj._lint, string: cobj._string});
}
if(editor_mode.doubleClickMode==='add'){
editor_mode.doubleClickMode='change';
addfunc()
}
if(editor_mode.doubleClickMode==='delete'){
editor_mode.doubleClickMode='change';
deletefunc()
}
}
input.ondblclick = dblclickfunc
var doubleClickCheck=[0];
thisTr.onclick = function(){
var newClick = new Date().getTime();
var lastClick = doubleClickCheck.shift();
doubleClickCheck.push(newClick);
if(newClick-lastClick<500){
dblclickfunc()
}
}
var deletefunc=function(){
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
if (checkRange(cobj, null)) {
editor_mode.addAction(['delete', field, undefined]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
} else {
printe(field + ' : 该值不允许为null无法删除');
}
}
var addfunc=function(){
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
var mode = document.getElementById('editModeSelect').value;
// 1.输入id
var newid=prompt('请输入新项的ID仅公共事件支持中文ID');
if (newid == null || newid.length==0) {
return;
}
// 检查commentEvents
if (mode !== 'commonevent') {
// 2.检查id是否符合规范或与已有id重复
if (!/^[a-zA-Z0-9_]+$/.test(newid)){
printe('id不符合规范, 请使用大小写字母数字下划线来构成');
return;
}
}
var conflict=true;
var basefield=field.replace(/\[[^\[]*\]$/,'');
if (basefield==="['main']"){
printe("全塔属性 ~ ['main'] 不允许添加新值");
return;
}
try {
var baseobj=eval('obj'+basefield);
conflict=newid in baseobj;
} catch (ee) {
// 理论上这里不会发生错误
printe(ee);
throw ee;
}
if (conflict){
printe('id已存在, 请直接修改该项的值');
return;
}
// 3.添加
editor_mode.addAction(['add',basefield+"['"+newid+"']",null]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
}
});
}
return {"HTML": outstr.join(''), "guids": guids, "listen": listen};
}
/**
* 返回叶节点<tr>形如
* tr>td[title=field]
* >td[title=comment,cobj=cobj:json]
* >td>div>input[value=thiseval]
* 参数意义在 objToTable_ 中已解释
* @param {Object} obj
* @param {Object} commentObj
* @param {String} field
* @param {String} cfield
* @param {Object} vobj
* @param {Object} cobj
*/
editor_mode.prototype.objToTr_ = function (obj, commentObj, field, cfield, vobj, cobj) {
var guid = editor.guid();
var thiseval = vobj;
var comment = String(cobj._data);
var charlength = 10;
// "['a']['b']" => "b"
var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
// 把长度超过 charlength 的字符改成 固定长度+...的形式
shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
// 完整的内容转义后供悬停查看
var commentHTMLescape = editor.HTMLescape(comment);
// 把长度超过 charlength 的字符改成 固定长度+...的形式
var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.HTMLescape(comment.slice(0, charlength)) + '...');
var cobjstr = Object.assign({}, cobj);
delete cobjstr._data;
// 把cobj塞到第二个td的[cobj]中, 方便绑定事件时取
cobjstr = editor.HTMLescape(JSON.stringify(cobjstr));
var outstr = ['<tr id="', guid, '"><td title="', field, '">', shortField, '</td>',
'<td title="', commentHTMLescape, '" cobj="', cobjstr, '">', shortCommentHTMLescape, '</td>',
'<td><div class="etableInputDiv">', editor_mode.objToTd_(obj, commentObj, field, cfield, vobj, cobj), '</div></td></tr>\n',
];
return [outstr.join(''), guid];
}
editor_mode.prototype.objToTd_ = function (obj, commentObj, field, cfield, vobj, cobj) {
var thiseval = vobj;
if (cobj._select) {
var values = cobj._select.values;
var outstr = ['<select>\n', "<option value='", JSON.stringify(thiseval), "'>", JSON.stringify(thiseval), '</option>\n'];
values.forEach(function (v) {
outstr.push(["<option value='", JSON.stringify(v), "'>", JSON.stringify(v), '</option>\n'].join(''))
});
outstr.push('</select>');
return outstr.join('');
} else if (cobj._input) {
return ["<input type='text' spellcheck='false' value='", JSON.stringify(thiseval), "'/>\n"].join('');
} else if (cobj._bool) {
return ["<input type='checkbox' ", (thiseval ? 'checked ' : ''), "/>\n"].join('');
} else {
var num = 0;//editor_mode.indent(field);
return ["<textarea spellcheck='false' >", JSON.stringify(thiseval, null, num), '</textarea>\n'].join('');
}
}
editor_mode.prototype.indent = function (field) {
var num = '\t';
if (field.indexOf("['main']") === 0) return 0;
if (field.indexOf("['flyRange']") !== -1) return 0;
if (field === "['special']") return 0;
return num;
}
@ -386,6 +87,9 @@ editor_mode = function (editor) {
case 'commonevent':
editor.file.editCommonEvent(actionList, cb);
break;
case 'plugins':
editor.file.editPlugins(actionList, cb);
break;
default:
break;
}
@ -395,7 +99,7 @@ editor_mode = function (editor) {
if (editor_mode.mode != mode) {
if (mode === 'save') editor_mode.doActionList(editor_mode.mode, editor_mode.actionList);
if (editor_mode.mode === 'nextChange' && mode) editor_mode.showMode(mode);
editor_mode.mode = mode;
if (mode !== 'save') editor_mode.mode = mode;
editor_mode.actionList = [];
}
}
@ -411,7 +115,7 @@ editor_mode = function (editor) {
if (editor_mode[mode]) editor_mode[mode]();
document.getElementById('editModeSelect').value = mode;
var tips = tip_in_showMode;
if (!selectBox.isSelected) printf('tips: ' + tips[~~(tips.length * Math.random())]);
if (!selectBox.isSelected()) printf('tips: ' + tips[~~(tips.length * Math.random())]);
}
editor_mode.prototype.loc = function (callback) {
@ -426,7 +130,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_3d846fc4_7644_44d1_aa04_433d266a73df').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
editor.drawPosSelection();
@ -469,7 +173,7 @@ editor_mode = function (editor) {
});
}
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
@ -483,7 +187,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_4a3b1b09_b2fb_4bdf_b9ab_9f4cdac14c74').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@ -496,7 +200,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_b6a03e4c_5968_4633_ac40_0dfdd2c9cde5').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@ -509,7 +213,7 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_e260a2be_5690_476a_b04e_dacddede78b3').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
@ -522,12 +226,25 @@ editor_mode = function (editor) {
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor_mode.objToTable_(objs[0], objs[1]);
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_b7bf0124_99fd_4af8_ae2f_0017f04a7c7d').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
}
editor_mode.prototype.plugins = function (callback) {
var objs = [];
editor.file.editPlugins([], function (objs_) {
objs = objs_;
//console.log(objs_)
});
//只查询不修改时,内部实现不是异步的,所以可以这么写
var tableinfo = editor.table.objToTable(objs[0], objs[1]);
document.getElementById('table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6').innerHTML = tableinfo.HTML;
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
}
/////////////////////////////////////////////////////////////////////////////
editor_mode.prototype.listen = function (callback) {
@ -609,8 +326,8 @@ editor_mode = function (editor) {
}
var width = parseInt(document.getElementById('newMapWidth').value);
var height = parseInt(document.getElementById('newMapHeight').value);
if (!core.isset(width) || !core.isset(height) || width<13 || height<13 || width*height>1000) {
printe("新建地图的宽高都不得小于13且宽高之积不能超过1000");
if (!core.isset(width) || !core.isset(height) || width<core.__SIZE__ || height<core.__SIZE__ || width*height>1000) {
printe("新建地图的宽高都不得小于"+core.__SIZE__+"且宽高之积不能超过1000");
return;
}
@ -674,8 +391,8 @@ editor_mode = function (editor) {
var width = parseInt(document.getElementById('newMapsWidth').value);
var height = parseInt(document.getElementById('newMapsHeight').value);
if (!core.isset(width) || !core.isset(height) || width<13 || height<13 || width*height>1000) {
printe("新建地图的宽高都不得小于13且宽高之积不能超过1000");
if (!core.isset(width) || !core.isset(height) || width<core.__SIZE__ || height<core.__SIZE__ || width*height>1000) {
printe("新建地图的宽高都不得小于"+core.__SIZE__+"且宽高之积不能超过1000");
return;
}
editor_mode.onmode('');
@ -757,21 +474,8 @@ editor_mode = function (editor) {
}
selectAppend.onchange();
var getPixel=function(imgData, x, y) {
var offset = (x + y * imgData.width) * 4;
var r = imgData.data[offset+0];
var g = imgData.data[offset+1];
var b = imgData.data[offset+2];
var a = imgData.data[offset+3];
return [r,g,b,a];
}
var setPixel=function(imgData, x, y, rgba) {
var offset = (x + y * imgData.width) * 4;
imgData.data[offset+0]=rgba[0];
imgData.data[offset+1]=rgba[1];
imgData.data[offset+2]=rgba[2];
imgData.data[offset+3]=rgba[3];
}
var getPixel=editor.util.getPixel
var setPixel=editor.util.setPixel
var autoAdjust = function (image, callback) {
var changed = false;
@ -792,7 +496,7 @@ editor_mode = function (editor) {
var pixel = getPixel(imgData, i, j);
if (pixel[3]==0) trans++;
if (pixel[0]==255 && pixel[1]==255 && pixel[2]==255 && pixel[3]==255) white++;
if (pixel[0]==0 && pixel[1]==0 && pixel[2]==0 && pixel[3]==255) black++;
// if (pixel[0]==0 && pixel[1]==0 && pixel[2]==0 && pixel[3]==255) black++;
}
}
if (white>black && white>trans*10 && confirm("看起来这张图片是以纯白为底色,是否自动调整为透明底色?")) {
@ -808,6 +512,7 @@ editor_mode = function (editor) {
tempCanvas.putImageData(imgData, 0, 0);
changed = true;
}
/*
if (black>white && black>trans*10 && confirm("看起来这张图片是以纯黑为底色,是否自动调整为透明底色?")) {
for (var i=0;i<image.width;i++) {
for (var j=0;j<image.height;j++) {
@ -821,6 +526,7 @@ editor_mode = function (editor) {
tempCanvas.putImageData(imgData, 0, 0);
changed = true;
}
*/
// Step 2: 检测长宽比
var ysize = selectAppend.value.indexOf('48') === -1 ? 32 : 48;
@ -928,113 +634,9 @@ editor_mode = function (editor) {
var nimgData=new ImageData(imgData.width,imgData.height);
// ImageData .data 形如一维数组,依次排着每个点的 R(0~255) G(0~255) B(0~255) A(0~255)
var convert=function(rgba,delta){
var round=Math.round;
// rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git
//--------------------------------------------
// The MIT License (MIT)
//
// Copyright (c) 2014 Carlos Cabo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//--------------------------------------------
// https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js
var rgbToHsl = function (rgba) {
var arg, r, g, b, h, s, l, d, max, min;
arg = rgba;
if (typeof arg[0] === 'number') {
r = arg[0];
g = arg[1];
b = arg[2];
} else {
r = arg[0][0];
g = arg[0][1];
b = arg[0][2];
}
r /= 255;
g /= 255;
b /= 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
//CARLOS
h = round(h * 360);
s = round(s * 100);
l = round(l * 100);
return [h, s, l];
}
//
var hue2rgb = function (p, q, t) {
if (t < 0) { t += 1; }
if (t > 1) { t -= 1; }
if (t < 1 / 6) { return p + (q - p) * 6 * t; }
if (t < 1 / 2) { return q; }
if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
return p;
}
var hslToRgb = function (hsl) {
var arg, r, g, b, h, s, l, q, p;
arg = hsl;
if (typeof arg[0] === 'number') {
h = arg[0] / 360;
s = arg[1] / 100;
l = arg[2] / 100;
} else {
h = arg[0][0] / 360;
s = arg[0][1] / 100;
l = arg[0][2] / 100;
}
if (s === 0) {
r = g = b = l; // achromatic
} else {
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [round(r * 255), round(g * 255), round(b * 255)];
}
var rgbToHsl = editor.util.rgbToHsl
var hue2rgb = editor.util.hue2rgb
var hslToRgb = editor.util.hslToRgb
//
var hsl=rgbToHsl(rgba)
hsl[0]=(hsl[0]+delta)%360

View File

@ -39,7 +39,7 @@ editor_multi = function () {
editor_multi.lintAutocomplete = false;
editor_multi.show = function () {
if (typeof(selectBox) !== typeof(undefined)) selectBox.isSelected = false;
if (typeof(selectBox) !== typeof(undefined)) selectBox.isSelected(false);
var valueNow = codeEditor.getValue();
//try{eval('function _asdygakufyg_() { return '+valueNow+'\n}');editor_multi.lintAutocomplete=true;}catch(ee){}
if (valueNow.slice(0, 8) === 'function') editor_multi.lintAutocomplete = true;
@ -103,7 +103,7 @@ editor_multi = function () {
var tmap = {};
var tstr = JSON.stringify(tobj, function (k, v) {
if (typeof(v) === typeof('') && v.slice(0, 8) === 'function') {
var id_ = editor.guid();
var id_ = editor.util.guid();
tmap[id_] = v.toString();
return id_;
} else return v
@ -146,7 +146,7 @@ editor_multi = function () {
var tmap = {};
var tstr = JSON.stringify(tobj, function (k, v) {
if (v instanceof Function) {
var id_ = editor.guid();
var id_ = editor.util.guid();
tmap[id_] = v.toString();
return id_;
} else return v

383
_server/editor_table.js Normal file
View File

@ -0,0 +1,383 @@
editor_table_wrapper = function (editor) {
editor_table = function () {
}
/////////////////////////////////////////////////////////////////////////////
// HTML模板
editor_table.prototype.select = function (value, values) {
let content = editor.table.option(value) +
values.map(function (v) {
return editor.table.option(v)
}).join('')
return `<select>\n${content}</select>\n`
}
editor_table.prototype.option = function (value) {
return `<option value='${JSON.stringify(value)}'>${JSON.stringify(value)}</option>\n`
}
editor_table.prototype.text = function (value) {
return `<input type='text' spellcheck='false' value='${JSON.stringify(value)}'/>\n`
}
editor_table.prototype.checkbox = function (value) {
return `<input type='checkbox' ${(value ? 'checked ' : '')}/>\n`
}
editor_table.prototype.textarea = function (value, indent) {
return `<textarea spellcheck='false'>${JSON.stringify(value, null, indent || 0)}</textarea>\n`
}
editor_table.prototype.title = function () {
return `\n<tr><td>条目</td><td>注释</td><td>值</td></tr>\n`
}
editor_table.prototype.gap = function (field) {
return `<tr><td>----</td><td>----</td><td>${field}</td></tr>\n`
}
editor_table.prototype.tr = function (guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr) {
return `<tr id="${guid}">
<td title="${field}">${shortField}</td>
<td title="${commentHTMLescape}" cobj="${cobjstr}">${shortCommentHTMLescape}</td>
<td><div class="etableInputDiv">${tdstr}</div></td>
</tr>\n`
}
/////////////////////////////////////////////////////////////////////////////
// 表格生成的控制
/**
* 注释对象的默认值
*/
editor_table.prototype.defaultcobj = {
// 默认是文本域
_type: 'textarea',
_data: '',
_string: function (args) {//object~[field,cfield,vobj,cobj]
var thiseval = args.vobj;
return (typeof (thiseval) === typeof ('')) && thiseval[0] === '"';
},
// 默认情况下 非对象和数组的视为叶节点
_leaf: function (args) {//object~[field,cfield,vobj,cobj]
var thiseval = args.vobj;
if (thiseval == null || thiseval == undefined) return true;//null,undefined
if (typeof (thiseval) === typeof ('')) return true;//字符串
if (Object.keys(thiseval).length === 0) return true;//数字,true,false,空数组,空对象
return false;
},
}
/**
* 把来自数据文件的obj和来自*comment.js的commentObj组装成表格
* commentObj在无视['_data']的意义下与obj同形
* : commentObj['_data']['a']['_data']['b'] obj['a']['b'] 是对应的
* 在此意义下, 两者的结构是一致的
* 在commentObj没有被定义的obj的分支, 会取defaultcobj作为默认值
* 因此在深度优先遍历时,维护
* field="['a']['b']"
* cfield="['_data']['a']['_data']['b']"
* vobj=obj['a']['b']
* cobj=commentObj['_data']['a']['_data']['b']
* cobj
* cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii])
* 每一项若未定义,就从defaultcobj中取
* 当其是函数不是具体值时,把args = {field: field, cfield: cfield, vobj: vobj, cobj: cobj}代入算出该值
* 得到的叶节点的<tr>结构如下
* tr>td[title=field]
* >td[title=comment,cobj=cobj:json]
* >td>div>input[value=thiseval]
* 返回结果
* 返回一个对象, 假设被命名为tableinfo
* 在把一个 table innerHTML 赋值为 tableinfo.HTML
* 再调 tableinfo.listen(tableinfo.guids) 进行绑定事件
* @param {Object} obj
* @param {Object} commentObj
* @returns {{"HTML":String,"guids":String[],"listen":Function}}
*/
editor_table.prototype.objToTable = function (obj, commentObj) {
// 表格抬头
var outstr = [editor.table.title()];
var guids = [];
var defaultcobj = this.defaultcobj
/**
* 深度优先遍历, p*即为父节点的四个属性
* @param {String} pfield
* @param {String} pcfield
* @param {Object} pvobj
* @param {Object} pcobj
*/
var recursionParse = function (pfield, pcfield, pvobj, pcobj) {
var keysForTableOrder = {};
var voidMark = {};
// 1. 按照pcobj排序生成
if (pcobj && pcobj['_data']) {
for (var ii in pcobj['_data']) keysForTableOrder[ii] = voidMark;
}
// 2. 对每个pvobj且不在pcobj的再添加到最后
keysForTableOrder = Object.assign(keysForTableOrder, pvobj)
for (var ii in keysForTableOrder) {
// 3. 对于pcobj有但是pvobj中没有的, 弹出提示, (正常情况下editor_file会补全成null)
// 事实上能执行到这一步工程没崩掉打不开,就继续吧..
if (keysForTableOrder[ii] === voidMark) {
if (typeof id_815975ad_ee6f_4684_aac7_397b7e392702 === "undefined") {
alert('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
console.error('comment和data不匹配,请在群 HTML5造塔技术交流群 959329661 内反馈')
id_815975ad_ee6f_4684_aac7_397b7e392702 = 1;
}
pvobj[ii] = null;
}
var field = pfield + "['" + ii + "']";
var cfield = pcfield + "['_data']['" + ii + "']";
var vobj = pvobj[ii];
var cobj = null;
if (pcobj && pcobj['_data'] && pcobj['_data'][ii]) {
// cobj存在时直接取
cobj = Object.assign({}, defaultcobj, pcobj['_data'][ii]);
} else {
// 当其函数时代入参数算出cobj, 不存在时只取defaultcobj
if (pcobj && (pcobj['_data'] instanceof Function)) cobj = Object.assign({}, defaultcobj, pcobj['_data'](ii));
else cobj = Object.assign({}, defaultcobj);
}
var args = { field: field, cfield: cfield, vobj: vobj, cobj: cobj }
// 当cobj的参数为函数时,代入args算出值
for (var key in cobj) {
if (key === '_data') continue;
if (cobj[key] instanceof Function) cobj[key] = cobj[key](args);
}
// 标记为_hide的属性不展示
if (cobj._hide) continue;
if (!cobj._leaf) {
// 不是叶节点时, 插入展开的标记并继续遍历, 此处可以改成按钮用来添加新项或折叠等
outstr.push(editor.table.gap(field));
recursionParse(field, cfield, vobj, cobj);
} else {
// 是叶节点时, 调objToTr_渲染<tr>
var leafnode = editor.table.objToTr(obj, commentObj, field, cfield, vobj, cobj);
outstr.push(leafnode[0]);
guids.push(leafnode[1]);
}
}
}
// 开始遍历
recursionParse("", "", obj, commentObj);
var listen = function (guids) {
// 每个叶节点的事件绑定
guids.forEach(function (guid) {
editor.table.guidListen(guid, obj, commentObj)
});
}
return { "HTML": outstr.join(''), "guids": guids, "listen": listen };
}
/**
* 返回叶节点<tr>形如
* tr>td[title=field]
* >td[title=comment,cobj=cobj:json]
* >td>div>input[value=thiseval]
* 参数意义在 objToTable 中已解释
* @param {Object} obj
* @param {Object} commentObj
* @param {String} field
* @param {String} cfield
* @param {Object} vobj
* @param {Object} cobj
*/
editor_table.prototype.objToTr = function (obj, commentObj, field, cfield, vobj, cobj) {
var guid = editor.util.guid();
var thiseval = vobj;
var comment = String(cobj._data);
var charlength = 10;
// "['a']['b']" => "b"
var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
// 把长度超过 charlength 的字符改成 固定长度+...的形式
shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
// 完整的内容转义后供悬停查看
var commentHTMLescape = editor.util.HTMLescape(comment);
// 把长度超过 charlength 的字符改成 固定长度+...的形式
var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.util.HTMLescape(comment.slice(0, charlength)) + '...');
var cobjstr = Object.assign({}, cobj);
delete cobjstr._data;
// 把cobj塞到第二个td的[cobj]中, 方便绑定事件时取
cobjstr = editor.util.HTMLescape(JSON.stringify(cobjstr));
var tdstr = editor.table.objToTd(obj, commentObj, field, cfield, vobj, cobj)
var outstr = editor.table.tr(guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr)
return [outstr, guid];
}
editor_table.prototype.objToTd = function (obj, commentObj, field, cfield, vobj, cobj) {
var thiseval = vobj;
if (cobj._select) {
var values = cobj._select.values;
return editor.table.select(thiseval, values);
} else if (cobj._input) {
return editor.table.text(thiseval);
} else if (cobj._bool) {
return editor.table.checkbox(thiseval);
} else {
var indent = 0;
return editor.table.textarea(thiseval, indent);
}
}
/////////////////////////////////////////////////////////////////////////////
// 表格的用户交互
/**
* 检查一个值是否允许被设置为当前输入
* @param {Object} cobj
* @param {*} thiseval
*/
editor_table.prototype.checkRange = function (cobj, thiseval) {
if (cobj._range) {
return eval(cobj._range);
}
if (cobj._select) {
return cobj._select.values.indexOf(thiseval) !== -1;
}
if (cobj._bool) {
return [true, false].indexOf(thiseval) !== -1;
}
return true;
}
/**
* 监听一个guid对应的表格项
* @param {String} guid
*/
editor_table.prototype.guidListen = function (guid, obj, commentObj) {
// tr>td[title=field]
// >td[title=comment,cobj=cobj:json]
// >td>div>input[value=thiseval]
var thisTr = document.getElementById(guid);
var input = thisTr.children[2].children[0].children[0];
var field = thisTr.children[0].getAttribute('title');
var cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
var modeNode = thisTr.parentNode;
while (!editor_mode._ids.hasOwnProperty(modeNode.getAttribute('id'))) {
modeNode = modeNode.parentNode;
}
input.onchange = function () {
editor.table.onchange(guid, obj, commentObj, thisTr, input, field, cobj, modeNode)
}
// 用检测两次单击的方式来实现双击(以支持手机端的双击)
var doubleClickCheck = [0];
thisTr.onclick = function () {
var newClick = new Date().getTime();
var lastClick = doubleClickCheck.shift();
doubleClickCheck.push(newClick);
if (newClick - lastClick < 500) {
editor.table.dblclickfunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode)
}
}
}
/**
* 表格的值变化时
*/
editor_table.prototype.onchange = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) {
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
var thiseval = null;
if (input.checked != null) input.value = input.checked;
try {
thiseval = JSON.parse(input.value);
} catch (ee) {
printe(field + ' : ' + ee);
throw ee;
}
if (editor.table.checkRange(cobj, thiseval)) {
editor_mode.addAction(['change', field, thiseval]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
} else {
printe(field + ' : 输入的值不合要求,请鼠标放置在注释上查看说明');
}
}
/**
* 双击表格时
* 正常编辑: 尝试用事件编辑器或多行文本编辑器打开
* 添加: 在该项的同一级创建一个内容为null新的项, 刷新后生效并可以继续编辑
* 删除: 删除该项, 刷新后生效
* 在点击按钮 添加/删除 ,下一次双击将被视为 添加/删除
*/
editor_table.prototype.dblclickfunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) {
if (editor_mode.doubleClickMode === 'change') {
if (cobj._type === 'event') editor_blockly.import(guid, { type: cobj._event });
if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string });
} else if (editor_mode.doubleClickMode === 'add') {
editor_mode.doubleClickMode = 'change';
editor.table.addfunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode)
} else if (editor_mode.doubleClickMode === 'delete') {
editor_mode.doubleClickMode = 'change';
editor.table.deletefunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode)
}
}
/**
* 删除表格项
*/
editor_table.prototype.deletefunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) {
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
if (editor.table.checkRange(cobj, null)) {
editor_mode.addAction(['delete', field, undefined]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
} else {
printe(field + ' : 该值不允许为null无法删除');
}
}
/**
* 添加表格项
*/
editor_table.prototype.addfunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) {
editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]);
var mode = document.getElementById('editModeSelect').value;
// 1.输入id
var newid = prompt('请输入新项的ID仅公共事件支持中文ID');
if (newid == null || newid.length == 0) {
return;
}
// 检查commentEvents
if (mode !== 'commonevent') {
// 2.检查id是否符合规范或与已有id重复
if (!/^[a-zA-Z0-9_]+$/.test(newid)) {
printe('id不符合规范, 请使用大小写字母数字下划线来构成');
return;
}
}
var conflict = true;
var basefield = field.replace(/\[[^\[]*\]$/, '');
if (basefield === "['main']") {
printe("全塔属性 ~ ['main'] 不允许添加新值");
return;
}
try {
var baseobj = eval('obj' + basefield);
conflict = newid in baseobj;
} catch (ee) {
// 理论上这里不会发生错误
printe(ee);
throw ee;
}
if (conflict) {
printe('id已存在, 请直接修改该项的值');
return;
}
// 3.添加
editor_mode.addAction(['add', basefield + "['" + newid + "']", null]);
editor_mode.onmode('save');//自动保存 删掉此行的话点保存按钮才会保存
}
/////////////////////////////////////////////////////////////////////////////
editor.constructor.prototype.table = new editor_table();
}
//editor_table_wrapper(editor);

150
_server/editor_util.js Normal file
View File

@ -0,0 +1,150 @@
editor_util_wrapper = function (editor) {
editor_util = function () {
}
editor_util.prototype.guid = function () {
return 'id_' + 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
editor_util.prototype.HTMLescape = function (str_) {
return String(str_).split('').map(function (v) {
return '&#' + v.charCodeAt(0) + ';'
}).join('');
}
editor_util.prototype.getPixel = function (imgData, x, y) {
var offset = (x + y * imgData.width) * 4;
var r = imgData.data[offset + 0];
var g = imgData.data[offset + 1];
var b = imgData.data[offset + 2];
var a = imgData.data[offset + 3];
return [r, g, b, a];
}
editor_util.prototype.setPixel = function (imgData, x, y, rgba) {
var offset = (x + y * imgData.width) * 4;
imgData.data[offset + 0] = rgba[0];
imgData.data[offset + 1] = rgba[1];
imgData.data[offset + 2] = rgba[2];
imgData.data[offset + 3] = rgba[3];
}
// rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git
//--------------------------------------------
// The MIT License (MIT)
//
// Copyright (c) 2014 Carlos Cabo
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//--------------------------------------------
// https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js
var round=Math.round;
var rgbToHsl = function (rgba) {
var arg, r, g, b, h, s, l, d, max, min;
arg = rgba;
if (typeof arg[0] === 'number') {
r = arg[0];
g = arg[1];
b = arg[2];
} else {
r = arg[0][0];
g = arg[0][1];
b = arg[0][2];
}
r /= 255;
g /= 255;
b /= 255;
max = Math.max(r, g, b);
min = Math.min(r, g, b);
l = (max + min) / 2;
if (max === min) {
h = s = 0; // achromatic
} else {
d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
//CARLOS
h = round(h * 360);
s = round(s * 100);
l = round(l * 100);
return [h, s, l];
}
//
var hue2rgb = function (p, q, t) {
if (t < 0) { t += 1; }
if (t > 1) { t -= 1; }
if (t < 1 / 6) { return p + (q - p) * 6 * t; }
if (t < 1 / 2) { return q; }
if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; }
return p;
}
var hslToRgb = function (hsl) {
var arg, r, g, b, h, s, l, q, p;
arg = hsl;
if (typeof arg[0] === 'number') {
h = arg[0] / 360;
s = arg[1] / 100;
l = arg[2] / 100;
} else {
h = arg[0][0] / 360;
s = arg[0][1] / 100;
l = arg[0][2] / 100;
}
if (s === 0) {
r = g = b = l; // achromatic
} else {
q = l < 0.5 ? l * (1 + s) : l + s - l * s;
p = 2 * l - q;
r = hue2rgb(p, q, h + 1 / 3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1 / 3);
}
return [round(r * 255), round(g * 255), round(b * 255)];
}
editor_util.prototype.rgbToHsl=rgbToHsl
editor_util.prototype.hue2rgb=hue2rgb
editor_util.prototype.hslToRgb=hslToRgb
editor.constructor.prototype.util = new editor_util();
}
//editor_util_wrapper(editor);

View File

@ -13,14 +13,21 @@ var events_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_type": "event",
"_range": "thiseval instanceof Array",
"_event": "commonEvent",
"_data": "打败怪物后进行加点"
"_data": "打败怪物后加点"
},
"毒衰咒处理": {
"_leaf": true,
"_type": "event",
"_range": "thiseval instanceof Array",
"_event": "commonEvent",
"_data": "对毒衰咒效果进行的处理"
"_data": "毒衰咒效果处理"
},
"滑冰事件": {
"_leaf": true,
"_type": "event",
"_range": "thiseval instanceof Array",
"_event": "commonEvent",
"_data": "滑冰事件"
},
}
if (obj[key]) return obj[key];

View File

@ -4,20 +4,19 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_type": "object",
"_data": {
"events": {
"_type": "object",
"_data": {
"initGame": {
"resetGame": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "游戏开始前的一些初始化操作"
"_data": "重置整个游戏"
},
"setInitData": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "不同难度分别设置初始属性"
"_data": "设置初始属性"
},
"win": {
"_leaf": true,
@ -35,127 +34,124 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "正在切换楼层过程的操作\n此函数的执行时间是在切换楼层过程中屏幕完全变黑的一刻"
"_data": "切换楼层中"
},
"afterChangeFloor": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "转换楼层结束的事件\n此函数会在整个楼层切换完全结束后执行"
"_data": "切换楼层后"
},
"addPoint": {
"flyTo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "加点事件"
"_data": "楼层飞行"
},
"beforeBattle": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "战前事件"
},
"afterBattle": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "战斗结束后触发的事件"
"_data": "战后事件"
},
"afterOpenDoor": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "开一个门后触发的事件"
"_data": "开门后事件"
},
"afterGetItem": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "获得一个道具后触发的事件"
"_data": "获得道具后事件"
},
"afterChangeLight": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "改变亮灯之后,可以触发的事件"
"_data": "改变亮灯事件"
},
"afterPushBox": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "推箱子后的事件"
"_data": "推箱子事件"
},
"afterUseBomb": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "使用炸弹/圣锤后的事件"
},
"beforeSaveData": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "即将存档前可以执行的操作"
},
"afterLoadData": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "读档事件后,载入事件前,可以执行的操作"
"_data": "炸弹事件"
},
"canUseQuickShop": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "当前能否使用快捷商店"
"_data": "能否用快捷商店"
}
}
},
"enemys": {
"_type": "object",
"_data": {
"getSpecials": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "怪物特殊属性定义(获得怪物的特殊属性)"
"_data": "怪物特殊属性定义"
},
"getEnemyInfo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "获得某个怪物的当前属性数据\n该函数主要是会被伤害计算和怪物手册等使用"
"_data": "获得怪物真实属性"
},
"getDamageInfo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "获得战斗伤害信息(实际伤害计算函数)"
"_data": "获得战斗伤害信息"
},
"updateEnemys": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "更新怪物数据,可以在这里对怪物属性和数据进行动态更新"
"_data": "更新怪物数据"
}
}
},
"actions": {
"_type": "object",
"_data": {
"onKeyUp": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "按键处理;可以在这里自定义快捷键,详见文档-个性化-自定义快捷键"
"_data": "按键处理"
}
}
},
"control": {
"_type": "object",
"_data": {
"flyTo": {
"saveData": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "使用楼层传送器飞到某层"
"_data": "存档操作"
},
"loadData": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "读档操作"
},
"updateStatusBar": {
"_leaf": true,
@ -167,55 +163,48 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "阻激夹域伤害值计算"
"_data": "阻激夹域伤害"
},
"moveOneStep": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "勇士每走一步的操作"
"_data": "每一步后的操作"
},
"moveDirectly": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "瞬间移动处理"
},
"parallelDo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "并行事件处理"
}
}
},
"ui": {
"_type": "object",
"_data": {
"drawStatusBar": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "自定义绘制状态栏。\n当状态栏canvas化开启时可以在这里对状态栏进行自定义绘制。\n仅当statusCanvas开启时有效。"
"_data": "自绘状态栏"
},
"drawStatistics": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "地图数据统计项的注册"
"_data": "地图数据统计"
},
"drawAbout": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "绘制“关于”界面"
}
}
},
"plugins": {
"_type": "object",
"_data": {
"parallelDo": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "并行事件处理"
},
"plugin": {
"_leaf": true,
"_type": "textarea",
"_lint": true,
"_data": "自定义插件编写"
"_data": "绘制关于界面"
}
}
}

View File

@ -0,0 +1,27 @@
var plugins_comment_c456ea59_6018_45ef_8bcc_211a24c627dc =
{
"_type": "object",
"_data": function (key) {
var obj = {
"init": {
"_leaf": true,
"_type": "textarea",
"_range": "typeof(thiseval)=='string'",
"_data": "自定义插件"
},
"drawLight": {
"_leaf": true,
"_type": "textarea",
"_range": "typeof(thiseval)=='string' || thiseval==null",
"_data": "绘制灯光效果"
},
}
if (obj[key]) return obj[key];
return {
"_leaf": true,
"_type": "textarea",
"_range": "typeof(thiseval)=='string' || thiseval==null",
"_data": "自定义插件"
}
}
}

101
_server/refactoring.md Normal file
View File

@ -0,0 +1,101 @@
# 重构
+ 按功能拆分文件
+ 左侧页面模块化, 方便添加
+ 不同的模式的文件操作尽可能模块化
## 文件结构
+ [ ] editor_blockly 图块化事件编辑器
+ [ ] editor_multi 多行文本编辑器
+ [x] editor_table 处理表格的生成, 及其响应的事件, 从原editor\_mode中分离
+ [ ] editor_file 调用fs.js编辑文件, 把原editor\_file模块化
+ [ ] editor_game 处理来自core的数据, 导入为editor的数据, 从原editor中分离
+ [x] editor_util 生成guid等函数, 从editor分离
+ [ ] editor 执行初始化流程加组合各组件
+ [ ] 原editor_mode 移除
+ [ ] 原vm 移除
+ [ ] \*comment.js 表格注释与结构, 移至comment/\*comment.js
## 对象结构
```
editor: {
__proto__: {
fs
util
file
table
multi
blockly
game
}
config: 编辑器配置
mode: 当前的模式(左侧的选择)
map: 当前编辑层的地图
isMobile: 编辑器是否是手机端
currentFloorData: 当前编辑的楼层数据
...
}
```
---
## 某些注意到的点&准备修改的内容
+ 插入公共事件的参数的转义处理, .g4中添加ObjectString, 要求其中的值可以JSON.parse, 生成的code中也是作为对象而不是字符串出现
+ 转义改由editor.blockly处理,editor.multi原样接受和返回
+ 地图的编辑与其他(如全塔属性和楼层属性), 现在的文件操作的模式是完全不同的
楼层文件的储存与其他不同
+ functions和plugins的借助JSON.stringify的replacer特殊处理
+ 目前editor.map中储存的是info\<object\>, 准备改为和core一致只储存数字
+ editor.file在修改是不再返回obj和commentobj,只在查询时返回
## 功能改进
+ [ ] 大地图
在切换时, 每次都回到最左上->每个楼层记录一个位置
四个箭头支持长按
? 滚动条
+ [ ] ? 表格折叠
变为四栏, 可以折叠展开
+ [x] blockly对于无法识别的图块原样返回
+ [ ] ? 简洁的事件方块注册
`editor.registerEvent('log',[['test','Int','测试',0],['floorId','Idstring','楼层','MT0']])`
+ [ ] 一个显示所有快捷键的文本
+ [ ] 更多快捷键
【全塔属性】、【楼层属性】等常用的编辑栏切换
+ [ ] ? 地图编辑优化
常用的地图编辑快捷键/命令复制ctrl+c、粘贴ctrl+v、复制可绑定为现在的“选中xx位置事件” 粘贴为复制xx事件到此处撤回ctrl+z、取消撤回ctrl+y
可以按住拖动图块与事件。
+ [ ] ? 自由建立快捷键到命令的注册表。
+ [ ] 画地图也自动保存
+ [ ] 修改系统的触发器(下拉菜单增加新项)
在编辑器修改`comment.js`现场发readFile请求读文件然后开脚本编辑器进行编辑
+ [ ] ? 删除注册项/修改图块ID
+ [ ] ? 怪物和道具也能像其他类型那样查看“图块信息”(而不只是具体的怪物属性)
## 左侧页面模式
标题? 保存按钮? 添加按钮? 删除按钮?
自定义内容?
表格?

View File

@ -1,12 +1,7 @@
// vue 相关处理
var exportMap = new Vue({
el: '#exportMap',
data: {
isExport: false,
},
methods: {
exportMap: function () {
var exportMap = document.getElementById('exportMap')
exportMap.isExport=false
exportMap.onclick=function(){
editor.updateMap();
var sx=editor.map.length-1,sy=editor.map[0].length-1;
@ -19,11 +14,11 @@ var exportMap = new Vue({
if ('idnum' in mapxy) mapxy = mapxy.idnum;
else {
// mapxy='!!?';
tip.whichShow = 3;
tip.whichShow(3);
return;
}
} else if (typeof(mapxy) == 'undefined') {
tip.whichShow = 3;
tip.whichShow(3);
return;
}
mapxy = String(mapxy);
@ -34,61 +29,63 @@ var exportMap = new Vue({
filestr += ']' + (yy == sy ? '' : ',\n');
}
pout.value = filestr;
editArea.mapArr = filestr;
this.isExport = true;
editArea.error = 0;
tip.whichShow = 2;
mapEditArea.mapArr(filestr);
exportMap.isExport = true;
mapEditArea.error(0);
tip.whichShow(2);
}
}
})
var editArea = new Vue({
el: '#editArea',
data: {
mapArr: '',
errors: [ // 编号1,2,3,4
var mapEditArea = document.getElementById('mapEditArea')
mapEditArea.errors=[ // 编号1,2
"格式错误!请使用正确格式(请使用地图生成器进行生成,且需要和本地图宽高完全一致)",
"当前有未定义ID在地图区域显示红块请修改ID或者到icons.js和maps.js中进行定义",
"ID越界在地图区域显示红块当前编辑器暂时支持编号小于400请修改编号",
// "发生错误!",
],
error: 0,
formatTimer: null,
},
watch: {
mapArr: function (val, oldval) {
var that = this;
if (val == '') return;
"当前有未定义ID在地图区域显示红块请修改ID或者到icons.js和maps.js中进行定义"
]
mapEditArea.formatTimer=null
mapEditArea._mapArr=''
mapEditArea.mapArr=function(value){
if(value!=null){
var val=value
var oldval=mapEditArea._mapArr
if (val==oldval) return;
if (exportMap.isExport) {
exportMap.isExport = false;
return;
}
if (that.formatArr()) {
that.error = 0;
if (mapEditArea.formatArr()) {
mapEditArea.error(0);
setTimeout(function () {
that.mapArr = that.formatArr();
that.drawMap();
tip.whichShow = 8
if (mapEditArea.formatArr())mapEditArea.mapArr(mapEditArea.formatArr());
mapEditArea.drawMap();
tip.whichShow(8)
}, 1000);
that.formatTimer = setTimeout(function () {
pout.value = that.formatArr();
clearTimeout(mapEditArea.formatTimer);
mapEditArea.formatTimer = setTimeout(function () {
pout.value = mapEditArea.formatArr();
}, 5000); //5s后再格式化不然光标跳到最后很烦
} else {
that.error = 1;
mapEditArea.error(1);
}
},
error: function () {
// console.log(editArea.mapArr);
if (this.error>0)
printe(this.errors[this.error-1])
}
},
methods: {
drawMap: function () {
var that = this;
// var mapArray = that.mapArr.split(/\D+/).join(' ').trim().split(' ');
var mapArray = JSON.parse('[' + that.mapArr + ']');
mapEditArea._mapArr=value
}
return mapEditArea._mapArr
}
pout.oninput=function(){
mapEditArea.mapArr(pout.value)
}
mapEditArea._error=0
mapEditArea.error=function(value){
if(value!=null){
mapEditArea._error=value
if (value>0)
printe(mapEditArea.errors[value-1])
}
return mapEditArea._error
}
mapEditArea.drawMap= function () {
// var mapArray = mapEditArea.mapArr().split(/\D+/).join(' ').trim().split(' ');
var mapArray = JSON.parse('[' + mapEditArea.mapArr() + ']');
var sy=editor.map.length,sx=editor.map[0].length;
for (var y = 0; y < sy; y++)
for (var x = 0; x < sx; x++) {
@ -96,21 +93,21 @@ var editArea = new Vue({
if (num == 0)
editor.map[y][x] = 0;
else if (typeof(editor.indexs[num][0]) == 'undefined') {
that.error = 2;
mapEditArea.error(2);
editor.map[y][x] = undefined;
} else editor.map[y][x] = editor.ids[[editor.indexs[num][0]]];
}
editor.updateMap();
},
formatArr: function () {
}
mapEditArea.formatArr= function () {
var formatArrStr = '';
var that = this;
clearTimeout(that.formatTimer);
console.log(1)
var si=editor.map.length,sk=editor.map[0].length;
if (this.mapArr.split(/\D+/).join(' ').trim().split(' ').length != si*sk) return false;
var arr = this.mapArr.replace(/\s+/g, '').split('],[');
if (mapEditArea.mapArr().split(/\D+/).join(' ').trim().split(' ').length != si*sk) return false;
var arr = mapEditArea.mapArr().replace(/\s+/g, '').split('],[');
if (arr.length != si) return;
for (var i = 0; i < si; i++) {
@ -131,43 +128,31 @@ var editArea = new Vue({
}
return formatArrStr;
}
}
});
var copyMap = new Vue({
el: '#copyMap',
data: {
err: ''
},
methods: {
copyMap: function () {
tip.whichShow = 0;
var copyMap=document.getElementById('copyMap')
copyMap.err=''
copyMap.onclick=function(){
tip.whichShow(0);
if (pout.value.trim() != '') {
if (editArea.error) {
this.err = editArea.errors[editArea.error - 1];
tip.whichShow = 5
if (mapEditArea.error()) {
copyMap.err = mapEditArea.errors[mapEditArea.error() - 1];
tip.whichShow(5)
return;
}
try {
pout.focus();
pout.setSelectionRange(0, pout.value.length);
document.execCommand("Copy");
tip.whichShow = 6;
tip.whichShow(6);
} catch (e) {
this.err = e;
tip.whichShow = 5;
copyMap.err = e;
tip.whichShow(5);
}
} else {
tip.whichShow = 7;
tip.whichShow(7);
}
}
},
})
var clearMap = new Vue({
el: '#clearMap',
methods: {
clearMap: function () {
var clearMapButton=document.getElementById('clearMapButton')
clearMapButton.onclick=function () {
editor.mapInit();
editor_mode.onmode('');
editor.file.saveFloorFile(function (err) {
@ -178,19 +163,15 @@ var clearMap = new Vue({
;printf('地图清除成功');
});
editor.updateMap();
clearTimeout(editArea.formatTimer);
clearTimeout(mapEditArea.formatTimer);
clearTimeout(tip.timer);
pout.value = '';
editArea.mapArr = '';
tip.whichShow = 4;
editArea.error = 0;
mapEditArea.mapArr('');
tip.whichShow(4);
mapEditArea.error(0);
}
}
})
var deleteMap = new Vue({
el: '#deleteMap',
methods: {
deleteMap: function () {
var deleteMap=document.getElementById('deleteMap')
deleteMap.onclick=function () {
editor_mode.onmode('');
var index = core.floorIds.indexOf(editor.currentFloorId);
if (index>=0) {
@ -205,22 +186,20 @@ var deleteMap = new Vue({
}
else printe('删除成功,请F5刷新编辑器生效');
}
}
})
printf = function (str_, type) {
selectBox.isSelected = false;
selectBox.isSelected(false);
if (!type) {
tip.whichShow = 11;
tip.whichShow(11);
} else {
tip.whichShow = 12;
tip.whichShow(12);
}
setTimeout(function () {
if (!type) {
tip.msgs[11] = String(str_);
tip.whichShow = 12;
tip.whichShow(12);
} else {
tip.msgs[10] = String(str_);
tip.whichShow = 11;
tip.whichShow(11);
}
}, 1);
}
@ -233,18 +212,96 @@ tip_in_showMode = [
'事件编辑器中的显示文本和自定义脚本的方块也可以双击',
"画出的地图要点击\"保存地图\"才会写入到文件中",
];
var tip = new Vue({
el: '#tip',
data: {
infos: {},
hasId: true,
isAutotile: false,
isSelectedBlock: false,
isClearBlock: false,
isAirwall: false,
geneMapSuccess: false,
timer: null,
msgs: [ //分别编号1,2,3,4,5,6,7,8,9,10奇数警告偶数成功
var tip=document.getElementById('tip')
tip._infos= {}
tip.infos=function(value){
if(value!=null){
var val=value
var oldval=tip._infos
tip.isClearBlock(false);
tip.isAirwall(false);
if (typeof(val) != 'undefined') {
if (val == 0) {
tip.isClearBlock(true);
return;
}
if ('id' in val) {
if (val.idnum == 17) {
tip.isAirwall(true);
return;
}
tip.hasId = true;
} else {
tip.hasId = false;
}
tip.isAutotile = false;
if (val.images == "autotile" && tip.hasId) tip.isAutotile = true;
document.getElementById('isAirwall-else').innerHTML=(tip.hasId?`<p>图块编号:<span class="infoText">${ value['idnum'] }</span></p>
<p>图块ID<span class="infoText">${ value['id'] }</span></p>`:`
<p class="warnText">该图块无对应的数字或ID存在请先前往icons.js和maps.js中进行定义</p>`)+`
<p>图块所在素材<span class="infoText">${ value['images'] + (tip.isAutotile ? '( '+value['id']+' )' : '') }</span>
</p>
<p>图块索引<span class="infoText">${ value['y'] }</span></p>`
}
tip._infos=value
}
return tip._infos
}
tip.hasId= true
tip.isAutotile= false
tip._isSelectedBlock= false
tip.isSelectedBlock=function(value){
if(value!=null){
var dshow=document.getElementById('isSelectedBlock-if')
var dhide=document.getElementById('isSelectedBlock-else')
if(!value){
var dtemp=dshow
dshow=dhide
dhide=dtemp
}
dshow.style.display=''
dhide.style.display='none'
tip._isSelectedBlock=value
}
return tip._isSelectedBlock
}
tip._isClearBlock= false
tip.isClearBlock=function(value){
if(value!=null){
var dshow=document.getElementById('isClearBlock-if')
var dhide=document.getElementById('isClearBlock-else')
if(!value){
var dtemp=dshow
dshow=dhide
dhide=dtemp
}
dshow.style.display=''
dhide.style.display='none'
tip._isClearBlock=value
}
return tip._isClearBlock
}
tip._isAirwall= false
tip.isAirwall=function(value){
if(value!=null){
var dshow=document.getElementById('isAirwall-if')
var dhide=document.getElementById('isAirwall-else')
if(!value){
var dtemp=dshow
dshow=dhide
dhide=dtemp
}
dshow.style.display=''
dhide.style.display='none'
tip._isAirwall=value
}
return tip._isAirwall
}
tip.geneMapSuccess= false
tip.timer= null
tip.msgs= [ //分别编号1,2,3,4,5,6,7,8,9,10奇数警告偶数成功
"当前未选择任何图块,请先在右边选择要画的图块!",
"生成地图成功!可点击复制按钮复制地图数组到剪切板",
"生成失败! 地图中有未定义的图块,建议先用其他有效图块覆盖或点击清除地图!",
@ -257,63 +314,56 @@ var tip = new Vue({
"更新背景图片成功!",
"11:警告",
"12:成功"
],
mapMsg: '',
whichShow: 0,
},
watch: {
infos: {
handler: function (val, oldval) {
this.isClearBlock = false;
this.isAirwall = false;
if (typeof(val) != 'undefined') {
if (val == 0) {
this.isClearBlock = true;
return;
]
tip._mapMsg= ''
tip.mapMsg=function(value){
if(value!=null){
document.getElementById('whichShow-if').innerText=value
tip._mapMsg=value
}
if ('id' in val) {
if (val.idnum == 17) {
this.isAirwall = true;
return;
return tip._mapMsg
}
this.hasId = true;
} else {
this.hasId = false;
}
this.isAutotile = false;
if (val.images == "autotile" && this.hasId) this.isAutotile = true;
}
},
deep: true
},
tip._whichShow= 0
tip.whichShow=function(value){
if(value!=null){
whichShow: function () {
var that = this;
that.mapMsg = '';
that.msgs[4] = "复制失败!" + editTip.err;
clearTimeout(that.timer);
if (that.whichShow) {
that.mapMsg = that.msgs[that.whichShow - 1];
that.timer = setTimeout(function () {
if (!(that.whichShow % 2))
that.whichShow = 0;
var dshow=document.getElementById('whichShow-if')
var dhide=null
if(!value){
var dtemp=dshow
dshow=dhide
dhide=dtemp
}
if(dshow)dshow.style.display=''
if(dhide)dhide.style.display='none'
if(dshow)dshow.setAttribute('class',(value%2) ? 'warnText' : 'successText')
tip.mapMsg('');
tip.msgs[4] = "复制失败!" + editTip.err;
clearTimeout(tip.timer);
if (value) {
tip.mapMsg(tip.msgs[value - 1]);
tip.timer = setTimeout(function () {
if (!(value % 2))
value = 0;
}, 5000); //5秒后自动清除successwarn不清除
}
tip._whichShow=value
}
return tip._whichShow
}
})
var selectBox = new Vue({
el: '#selectBox',
data: {
isSelected: false
},
watch: {
isSelected: function () {
tip.isSelectedBlock = this.isSelected;
tip.whichShow = 0;
var selectBox=document.getElementById('selectBox')
var dataSelection=document.getElementById('dataSelection')
selectBox._isSelected=false
selectBox.isSelected=function(value){
if(value!=null){
selectBox._isSelected=value;
tip.isSelectedBlock(value);
tip.whichShow(0);
clearTimeout(tip.timer);
dataSelection.style.display=value?'':'none'
}
return selectBox._isSelected
}
})

View File

@ -18,9 +18,8 @@
<div id="arrEditor">
<table class="col" id='arrColMark'></table>
<table class="row" id='arrRowMark'></table>
<div id="editArea" v-cloak>
<textarea cols="10" rows="10" id="pout" v-model="mapArr"></textarea>
<!-- <p class="warnText" v-if="error">{{ errors[error-1] }}</p> -->
<div id="mapEditArea">
<textarea cols="10" rows="10" id="pout"></textarea>
</div>
<div id="editTip">
<input id='newFileName' placeholder="新楼层id" style="width: 100px"/>
@ -34,10 +33,10 @@
<input type="button" value="新建空白地图" id='newMap'/>
</div>
<div id='editBtns'>
<input type="button" value="导出地图" id="exportMap" v-on:click="exportMap"/>
<input type="button" value="复制地图" id="copyMap" v-on:click="copyMap"/>
<input type="button" value="清除地图" id='clearMap' v-on:click="clearMap"/>
<input type="button" value="删除地图" id="deleteMap" v-on:click="deleteMap"/>
<input type="button" value="导出地图" id="exportMap"/>
<input type="button" value="复制地图" id="copyMap"/>
<input type="button" value="清除地图" id='clearMapButton'/>
<input type="button" value="删除地图" id="deleteMap"/>
</div>
<input type="button" value="批量创建空白地图 ↓" id='newMaps'/>
<div id='newFloors' style='display:none'>
@ -260,6 +259,23 @@
</div>
</div>
</div>
<div id="left10" class='leftTab' style="z-index:-1;opacity: 0;"><!-- plugins -->
<h3 class="leftTabHeader">插件编写&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">保存</button>&nbsp;&nbsp;<button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button>&nbsp;&nbsp;<button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button>
</h3>
<div class="leftTabContent">
<div class='etable'>
<table>
<tbody id='table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6'>
<tr>
<td>条目</td>
<td>注释</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="mid">
<div class="col" id='mapColMark'></div>
<div class="row" id='mapRowMark'></div>
@ -277,28 +293,23 @@
<div id="iconLib">
<div id="iconImages"></div>
<div id="selectBox">
<div id='dataSelection' v-show="isSelected" v-cloak></div>
<div id='dataSelection' style="display:none"></div>
</div>
</div>
</div>
<div id="down">
<div style="margin:0.5rem">
<div class="tools">
<div id="tip" v-cloak>
<div v-if="isSelectedBlock">
<p v-if="isClearBlock" class="infoText">当前选择为清除块,可擦除地图上块</p>
<p v-if="isAirwall" class="infoText">当前选择为空气墙, 在编辑器中可视, 在游戏中隐藏的墙, 用来配合前景/背景的贴图</p>
<div v-else>
<p v-if="hasId">图块编号:<span class="infoText">{{ infos['idnum'] }}</span></p>
<p v-if="hasId">图块ID<span class="infoText">{{ infos['id'] }}</span></p>
<p v-else class="warnText">该图块无对应的数字或ID存在请先前往icons.js和maps.js中进行定义</p>
<p>图块所在素材:<span class="infoText">{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}</span>
</p>
<p>图块索引:<span class="infoText">{{ infos['y'] }}</span></p>
<div id="tip">
<div id="isSelectedBlock-if" style="display:none">
<p id="isClearBlock-if" style="display:none" class="infoText">当前选择为清除块,可擦除地图上块</p>
<div id="isClearBlock-else"><p id="isAirwall-if" style="display:none" class="infoText">当前选择为空气墙, 在编辑器中可视, 在游戏中隐藏的墙, 用来配合前景/背景的贴图</p>
<div id="isAirwall-else">
</div></div>
</div>
</div>
<div v-else>
<p v-if="whichShow" v-bind:class="[ (whichShow%2) ? 'warnText' : 'successText']">{{ mapMsg }}</p>
<div id="isSelectedBlock-else">
<p id="whichShow-if" style="display:none"></p>
</div>
</div>
@ -329,6 +340,7 @@
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
<option value="commonevent">公共事件</option>
<option value="plugins">插件编写</option>
</select>
<select id="brushMod" style="clear:right">
<option value="line">画线</option>
@ -491,6 +503,14 @@
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
</div>
</div>
<div id='inputBackground' style='display: none'>
<div id='inputDialog'>
<p id="inputMessage">请输入文字...</p>
<input id='inputBox' type="text"/>
<button id='inputYes'>确定</button>
<button id='inputNo'>取消</button>
</div>
</div>
<!-- */</script> -->
<!-- =========================================================== -->
@ -505,7 +525,10 @@ if (location.protocol.indexOf("http")!=0) {
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
<script src='_server/vendor/polyfill.min.js'></script>
<script src='_server/fs.js'></script>
<script src='_server/editor_util.js'></script>
<script src='_server/editor_file.js'></script>
<script src='_server/editor_game.js'></script>
<script src='_server/editor_table.js'></script>
<script src='_server/editor_mode.js'></script>
<script src='_server/vm.js'></script>
<script src='libs/thirdparty/lz-string.min.js'></script>
@ -514,8 +537,8 @@ if (location.protocol.indexOf("http")!=0) {
<script>
//所有全局量
__all__ = ['Vue', 'fs', 'editor_file', 'editor_mode', 'main', 'core', 'hasOwnProp', 'printf', 'printe', 'editor', 'converter', 'ActionParser', 'MotaActionFunctions', 'MotaActionBlocks'];
__id__ = ['editArea', 'arrRowMark', 'mapRowMark', 'data', 'bg', 'dataSelection', 'blocklyDiv', 'codeAreaHL', 'entryType'];
__Vue__ = ['editArea', 'exportMap', 'copyMap', 'clearMap', 'deleteMap', 'tip', 'selectBox'];
__id__ = ['mapEditArea', 'arrRowMark', 'mapRowMark', 'data', 'bg', 'dataSelection', 'blocklyDiv', 'codeAreaHL', 'entryType'];
__Vue__ = ['mapEditArea', 'exportMap', 'copyMap', 'clearMap', 'deleteMap', 'tip', 'selectBox'];
//var event = document.getElementById('event');
var hasOwnProperty = Object.prototype.hasOwnProperty;

View File

@ -17,9 +17,8 @@
<div id="arrEditor">
<table class="col" id='arrColMark'></table>
<table class="row" id='arrRowMark'></table>
<div id="editArea" v-cloak>
<textarea cols="10" rows="10" id="pout" v-model="mapArr"></textarea>
<!-- <p class="warnText" v-if="error">{{ errors[error-1] }}</p> -->
<div id="mapEditArea">
<textarea cols="10" rows="10" id="pout"></textarea>
</div>
<div id="editTip">
<input type="button" value="新建空白地图" id='newMap'/>
@ -32,10 +31,10 @@
<span style='vertical-align: bottom; margin-left: -4px'>保留楼层属性</span>
</div>
<div id="editBtns">
<input type="button" value="导出地图" id="exportMap" v-on:click="exportMap"/>
<input type="button" value="复制地图" id="copyMap" v-on:click="copyMap"/>
<input type="button" value="清除地图" id='clearMap' v-on:click="clearMap"/>
<input type="button" value="删除地图" id="deleteMap" v-on:click="deleteMap"/>
<input type="button" value="导出地图" id="exportMap"/>
<input type="button" value="复制地图" id="copyMap"/>
<input type="button" value="清除地图" id='clearMapButton'/>
<input type="button" value="删除地图" id="deleteMap"/>
</div>
<input type="button" value="批量创建空白地图 ↓" id='newMaps'/>
<div id='newFloors' style='display:none'>
@ -256,6 +255,23 @@
</div>
</div>
</div>
<div id="left10" class='leftTab' style="z-index:-1;opacity: 0;"><!-- plugins -->
<h3 class="leftTabHeader">插件编写&nbsp;&nbsp;<button onclick="editor.mode.onmode('save')">保存</button>&nbsp;&nbsp;<button onclick="editor.mode.changeDoubleClickModeByButton('add')">添加</button>&nbsp;&nbsp;<button onclick="editor.mode.changeDoubleClickModeByButton('delete')">删除</button>
</h3>
<div class="leftTabContent">
<div class='etable'>
<table>
<tbody id='table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6'>
<tr>
<td>条目</td>
<td>注释</td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
<div id="mid">
<table class="col" id='mapColMark'></table>
<table class="row" id='mapRowMark'></table>
@ -268,21 +284,16 @@
<canvas class='egameCanvas' id='eui' width='416' height='416' style='z-index:100'></canvas>
</div>
<div class="tools">
<div id="tip" v-cloak>
<div v-if="isSelectedBlock">
<p v-if="isClearBlock" class="infoText">当前选择为清除块,可擦除地图上块</p>
<p v-else-if="isAirwall" class="infoText">当前选择为空气墙, 在编辑器中可视, 在游戏中隐藏的墙, 用来配合前景/背景的贴图</p>
<div v-else>
<p v-if="hasId">图块编号:<span class="infoText">{{ infos['idnum'] }}</span></p>
<p v-if="hasId">图块ID<span class="infoText">{{ infos['id'] }}</span></p>
<p v-else class="warnText">该图块无对应的数字或ID存在请先前往icons.js和maps.js中进行定义</p>
<p>图块所在素材:<span class="infoText">{{ infos['images'] + (isAutotile ? '( '+infos['id']+' )' : '') }}</span>
</p>
<p>图块索引:<span class="infoText">{{ infos['y'] }}</span></p>
<div id="tip">
<div id="isSelectedBlock-if" style="display:none">
<p id="isClearBlock-if" style="display:none" class="infoText">当前选择为清除块,可擦除地图上块</p>
<div id="isClearBlock-else"><p id="isAirwall-if" style="display:none" class="infoText">当前选择为空气墙, 在编辑器中可视, 在游戏中隐藏的墙, 用来配合前景/背景的贴图</p>
<div id="isAirwall-else">
</div></div>
</div>
</div>
<div v-else>
<p v-if="whichShow" v-bind:class="[ (whichShow%2) ? 'warnText' : 'successText']">{{ mapMsg }}</p>
<div id="isSelectedBlock-else">
<p id="whichShow-if" style="display:none"></p>
</div>
</div>
@ -296,6 +307,7 @@
<option value="functions">脚本编辑</option>
<option value="appendpic">追加素材</option>
<option value="commonevent">公共事件</option>
<option value="plugins">插件编写</option>
</select>
<br/>
<span style="font-size: 12px;">
@ -325,7 +337,7 @@
<div id="iconLib">
<div id="iconImages"></div>
<div id="selectBox">
<div id='dataSelection' v-show="isSelected" v-cloak></div>
<div id='dataSelection' style="display:none"></div>
</div>
</div>
</div>
@ -474,6 +486,14 @@
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
</div>
</div>
<div id='inputBackground' style='display: none'>
<div id='inputDialog'>
<p id="inputMessage">请输入文字...</p>
<input id='inputBox' type="text"/>
<button id='inputYes'>确定</button>
<button id='inputNo'>取消</button>
</div>
</div>
<!-- */</script> -->
<!-- =========================================================== -->
@ -488,7 +508,10 @@ if (location.protocol.indexOf("http")!=0) {
<!-- <script src="https://cdn.bootcss.com/vue/2.5.13/vue.js"></script> -->
<script src='_server/vendor/polyfill.min.js'></script>
<script src='_server/fs.js'></script>
<script src='_server/editor_util.js'></script>
<script src='_server/editor_file.js'></script>
<script src='_server/editor_game.js'></script>
<script src='_server/editor_table.js'></script>
<script src='_server/editor_mode.js'></script>
<script src='_server/vm.js'></script>
<script src='libs/thirdparty/lz-string.min.js'></script>
@ -497,8 +520,8 @@ if (location.protocol.indexOf("http")!=0) {
<script>
//所有全局量
__all__ = ['Vue', 'fs', 'editor_file', 'editor_mode', 'main', 'core', 'hasOwnProp', 'printf', 'printe', 'editor', 'converter', 'ActionParser', 'MotaActionFunctions', 'MotaActionBlocks'];
__id__ = ['editArea', 'arrRowMark', 'mapRowMark', 'data', 'bg', 'dataSelection', 'blocklyDiv', 'codeAreaHL', 'entryType'];
__Vue__ = ['editArea', 'exportMap', 'copyMap', 'clearMap', 'deleteMap', 'tip', 'selectBox'];
__id__ = ['mapEditArea', 'arrRowMark', 'mapRowMark', 'data', 'bg', 'dataSelection', 'blocklyDiv', 'codeAreaHL', 'entryType'];
__Vue__ = ['mapEditArea', 'exportMap', 'copyMap', 'clearMap', 'deleteMap', 'tip', 'selectBox'];
//var event = document.getElementById('event');
var hasOwnProperty = Object.prototype.hasOwnProperty;

View File

@ -25,6 +25,7 @@
<div id='startTopProgress'></div>
</div>
<p id='startTopLoadTips'>资源即将开始加载</p>
<p id='startTopHint'>HTML5魔塔游戏平台享受更多魔塔游戏<br/>https://h5mota.com/</p>
</div>
<img id='startBackground'>
<p id='startLogo'></p>
@ -148,10 +149,18 @@
<canvas class='gameCanvas' id='data' width='416' height='416'>此浏览器不支持HTML5</canvas>
</div>
</div>
<div id='inputDiv'>
<div id='inputDialog'>
<p id="inputMessage">请输入文字...</p>
<input id='inputBox' type="text"/>
<button id='inputYes'>确定</button>
<button id='inputNo'>取消</button>
</div>
</div>
<script src='libs/thirdparty/lz-string.min.js'></script>
<script src='libs/thirdparty/priority-queue.min.js'></script>
<script src='libs/thirdparty/localforage.min.js'></script>
<script id='mainScript' src='main.js'></script>
<script>main.init();main.listen();</script>
<script>main.init('play');main.listen();</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,9 @@
"use strict";
function core() {
this.__SIZE__ = 13;
this.__PIXELS__ = this.__SIZE__ * 32;
this.__HALF_SIZE__ = Math.floor(this.__SIZE__ / 2);
this.material = {
'animates': {},
'images': {},
@ -13,11 +16,10 @@ function core() {
'ground': null,
'items': {},
'enemys': {},
'icons': {},
'events': {}
'icons': {}
}
this.timeout = {
'getItemTipTimeout': null,
'tipTimeout': null,
'turnHeroTimeout': null,
'onDownTimeout': null,
'sleepTimeout': null,
@ -41,7 +43,6 @@ function core() {
'weather': {
'time': 0,
'type': null,
'level': 0,
'nodes': [],
'data': null,
'fog': null,
@ -65,6 +66,7 @@ function core() {
'isPC': true, // 是否是PC
'isAndroid': false, // 是否是Android
'isIOS': false, // 是否是iOS
'string': 'PC',
'isWeChat': false, // 是否是微信
'isQQ': false, // 是否是QQ
'isChrome': false, // 是否是Chrome
@ -79,19 +81,17 @@ function core() {
}
// 样式
this.domStyle = {
styles: [],
scale: 1.0,
screenMode: null,
isVertical: false,
toolbarBtn: false,
showStatusBar: true,
toolbarBtn: false,
}
this.bigmap = {
canvas: ["bg", "event", "event2", "fg", "damage"],
offsetX: 0, // in pixel
offsetY: 0,
width: 13, // map width and height
height: 13,
width: this.__SIZE__, // map width and height
height: this.__SIZE__,
tempCanvas: null, // A temp canvas for drawing
}
this.paint = {};
@ -102,7 +102,9 @@ function core() {
"data": null,
"time": 0,
"updated": false,
}
},
"favorite": [],
"favoriteName": {}
}
this.initStatus = {
'played': false,
@ -194,7 +196,6 @@ function core() {
},
'curtainColor': null,
'openingDoor': null,
'isSkiing': false,
// 动画
'globalAnimateObjs': [],
@ -213,38 +214,49 @@ function core() {
////// 初始化 //////
core.prototype.init = function (coreData, callback) {
this._forwardFuncs();
for (var key in coreData) {
for (var key in coreData)
core[key] = coreData[key];
this._init_flags();
this._init_platform();
this._init_others();
this._initPlugins();
core.loader._load(function () {
core._afterLoadResources(callback);
});
}
core.prototype._init_flags = function () {
core.flags = core.clone(core.data.flags);
core.values = core.clone(core.data.values);
core.firstData = core.data.getFirstData();
if (!core.flags.enableExperience)
core.flags.enableLevelUp = false;
if (!core.flags.enableLevelUp)
core.flags.levelUpLeftMode = false;
if (core.isset(core.firstData.shops)) {
core.firstData.shops.forEach(function (t) {
core.initStatus.shops[t.id] = t;
})
}
core.maps._setFloorSize();
core.firstData = core.clone(core.data.firstData);
this._init_sys_flags();
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.items.getItems();
(core.firstData.shops||[]).forEach(function (t) { core.initStatus.shops[t.id] = t; });
core.maps._setFloorSize();
// 初始化怪物、道具等
core.material.enemys = core.enemys.getEnemys();
core.material.items = core.items.getItems();
core.items._resetItems();
core.material.icons = core.icons.getIcons();
core.material.events = core.events.getEvents();
}
core.prototype._init_sys_flags = function () {
if (!core.flags.enableExperience) core.flags.enableLevelUp = false;
if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false;
if (core.flags.equipboxButton) core.flags.equipment = true;
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);
}
core.prototype._init_platform = function () {
core.platform.isOnline = location.protocol.indexOf("http") == 0;
if (core.platform.isOnline) {
if (!core.platform.isOnline) alert("请勿直接打开html文件使用启动服务或者APP进行离线游戏。");
window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext;
try {
core.musicStatus.audioContext = new window.AudioContext();
@ -254,8 +266,8 @@ core.prototype.init = function (coreData, callback) {
console.log("该浏览器不支持AudioContext");
core.musicStatus.audioContext = null;
}
}
core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true);
core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true);
["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"].forEach(function (t) {
if (navigator.userAgent.indexOf(t) >= 0) {
if (t == 'iPhone' || t == 'iPad' || t == 'iPod') core.platform.isIOS = true;
@ -263,21 +275,33 @@ core.prototype.init = function (coreData, callback) {
core.platform.isPC = false;
}
});
try {
core.platform.supportCopy = document.queryCommandSupported("copy");
}
catch (e) {
core.platform.supportCopy = false;
}
core.platform.string = core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : "";
core.platform.supportCopy = document.queryCommandSupported || document.queryCommandSupported("copy");
var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent);
if (core.isset(chrome) && parseInt(chrome[1])>=50)
core.platform.isChrome = true;
if (chrome && parseInt(chrome[1]) >= 50) core.platform.isChrome = true;
core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent);
core.platform.isQQ = /QQ/i.test(navigator.userAgent);
core.platform.isWeChat = /MicroMessenger/i.test(navigator.userAgent);
core.platform.useLocalForage = core.getLocalStorage('useLocalForage', !core.platform.isIOS);
this._init_checkLocalForage();
core.platform.extendKeyboard = core.getLocalStorage("extendKeyboard", false);
if (window.FileReader) {
core.platform.fileReader = new FileReader();
core.platform.fileReader.onload = function () {
core.readFileContent(core.platform.fileReader.result);
};
core.platform.fileReader.onerror = function () {
if (core.platform.errorCallback)
core.platform.errorCallback();
}
}
}
core.prototype._init_checkLocalForage = function () {
core.platform.useLocalForage = core.getLocalStorage('useLocalForage', true);
var _error = function (e) {
main.log(e);
core.platform.useLocalForage = false;
};
if (core.platform.useLocalForage) {
try {
core.setLocalForage("__test__", lzw_encode("__test__"), function () {
@ -289,125 +313,98 @@ core.prototype.init = function (coreData, callback) {
core.platform.useLocalForage = false;
}
else {
console.log("localForage supported!")
console.log("localForage supported!");
core.removeLocalForage("__test__");
}
}
catch (e) {main.log(e); core.platform.useLocalForage=false;}
}, function(e) {main.log(e); core.platform.useLocalForage=false;})
catch (e) {_error(e);}
}, _error)
}
catch (e) {main.log(e); core.platform.useLocalForage=false;}
}, function(e) {main.log(e); core.platform.useLocalForage=false;})
catch (e) {_error(e);}
}, _error)
}
catch (e) {main.log(e); core.platform.useLocalForage=false;}
}
core.platform.extendKeyboard = core.getLocalStorage("extendKeyboard", false);
if (window.FileReader) {
core.platform.fileReader = new FileReader();
core.platform.fileReader.onload = function () {
core.readFileContent(core.platform.fileReader.result);
};
core.platform.fileReader.onerror = function () {
if (core.isset(core.platform.errorCallback))
core.platform.errorCallback();
catch (e) {_error(e);}
}
}
// 先从存储中读取BGM状态
core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true);
if (!core.platform.isPC && (navigator.connection||{}).type!='wifi')
core.musicStatus.bgmStatus = false;
core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true);
// switchs
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);
core.prototype._init_others = function () {
// 一些额外的东西
core.material.groundCanvas = document.createElement('canvas').getContext('2d');
core.material.groundCanvas.canvas.width = core.material.groundCanvas.canvas.height = 32;
core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat');
core.animateFrame.weather.fog = new Image();
core.animateFrame.weather.fog.onerror = function () {
core.animateFrame.weather.fog = null;
}
core.animateFrame.weather.fog.src = "project/images/fog.png";
core.material.images.keyboard = new Image();
core.material.images.keyboard.onerror = function () {
core.material.images.keyboard = null;
}
core.material.images.keyboard.src = "project/images/keyboard.png";
core.bigmap.tempCanvas = document.createElement('canvas').getContext('2d');
////// 记录所有的存档编号!!! //////
core.loadImage('fog', function (name, img) { core.animateFrame.weather.fog = img; });
core.loadImage('keyboard', function (name, img) {core.material.images.keyboard = img; });
// 记录存档编号
core.saves.saveIndex = core.getLocalStorage('saveIndex', 1);
core.control.getSaveIndexes(function (indexes) {
core.saves.ids = indexes;
});
core.loader._load(function () {
console.log(core.material);
// 设置勇士高度
core.material.icons.hero.height = core.material.images.hero.height/4;
// 行走图
core.control.updateHeroIcon();
core.initStatus.maps = core.maps.initMaps(core.floorIds);
core.setRequestAnimationFrame();
if (main.mode=='play')
core.events.initGame();
if (core.isset(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins)) {
core.plugin = new function () {
this.__renderFrameFuncs = [];
};
core.plugin.__init__ = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.plugin;
core.plugin.__init__();
core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; });
}
core.prototype._afterLoadResources = function (callback) {
// 初始化地图
core.initStatus.maps = core.maps._initMaps();
core.control._setRequestAnimationFrame();
if (core.plugin._afterLoadResources)
core.plugin._afterLoadResources();
core.showStartAnimate();
if (callback) callback();
}
if (core.isset(callback)) callback();
core.prototype._initPlugins = function () {
core.plugin = new function () {};
});
for (var name in plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1) {
if (plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name] instanceof Function) {
try {
plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name].apply(core.plugin);
}
catch (e) {
main.log(e);
main.log("无法初始化插件"+name);
}
}
}
core._forwardFunc("plugin");
}
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);
this._forwardFunc(name);
}
}
core.prototype._forwardFunc = function (name, funcname) {
if (funcname == null) {
for (funcname in core[name]) {
if (funcname.charAt(0) != "_" && core[name][funcname] instanceof Function) {
this._forwardFunc(name, funcname);
}
}
return;
}
if (core[funcname]) {
main.log("Error in forwarding "+funcname+" from "+name+"!");
console.error("ERROR: 无法转发 "+name+" 中的函数 "+funcname+" 到 core 中!同名函数已存在。");
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}");
if (name == 'plugin') {
main.log("插件函数转发core."+funcname+" = core.plugin."+funcname);
}
}
core.prototype.doFunc = function (func, _this) {
if (typeof func == 'string') {
func = core.plugin[func];
_this = core.plugin;
}
return func.apply(_this, Array.prototype.slice.call(arguments, 2));
}
/**

View File

@ -10,7 +10,3 @@ data.prototype._init = function() {
this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags;
//delete(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d);
}
data.prototype.getFirstData = function() {
return core.clone(this.firstData);
}

View File

@ -9,7 +9,9 @@ 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') {
this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)};
this.enemydata.hasSpecial = function (a, b) {
return core.enemys.hasSpecial(a, b)
};
for (var enemyId in this.enemys) {
this.enemys[enemyId].id = enemyId;
}
@ -22,21 +24,21 @@ enemys.prototype.getEnemys = function () {
////// 判断是否含有某特殊属性 //////
enemys.prototype.hasSpecial = function (special, test) {
if (!core.isset(special)) return false;
if (special == null) return false;
if (special instanceof Array) {
return special.indexOf(test) >= 0;
}
if (typeof special == 'number') {
return special!=0 && (special%100==test||this.hasSpecial(parseInt(special/100), test));
return special === test;
}
if (typeof special == 'string') {
return this.hasSpecial(core.material.enemys[special], test);
}
if (core.isset(special.special)) {
if (special.special != null) {
return this.hasSpecial(special.special, test);
}
@ -47,24 +49,15 @@ enemys.prototype.getSpecials = function () {
return this.enemydata.getSpecials();
}
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);
}
return "";
}
////// 获得所有特殊属性的名称 //////
enemys.prototype.getSpecialText = function (enemy) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
if (!core.isset(enemy)) return [];
if (!enemy) return [];
var special = enemy.special;
var text = [];
var specials = this.getSpecials();
if (core.isset(specials)) {
if (specials) {
for (var i = 0; i < specials.length; i++) {
if (this.hasSpecial(special, specials[i][0]))
text.push(this._calSpecialContent(enemy, specials[i][1]));
@ -77,8 +70,8 @@ enemys.prototype.getSpecialText = function (enemy) {
enemys.prototype.getSpecialHint = function (enemy, special) {
var specials = this.getSpecials();
if (!core.isset(special)) {
if (!core.isset(specials)) return [];
if (special == null) {
if (specials == null) return [];
var hints = [];
for (var i = 0; i < specials.length; i++) {
if (this.hasSpecial(enemy, specials[i][0]))
@ -87,7 +80,7 @@ enemys.prototype.getSpecialHint = function (enemy, special) {
return hints;
}
if (!core.isset(specials)) return "";
if (specials == null) return "";
for (var i = 0; i < specials.length; i++) {
if (special == specials[i][0])
return this._calSpecialContent(enemy, specials[i][1]) + "" + this._calSpecialContent(enemy, specials[i][2]);
@ -95,6 +88,15 @@ enemys.prototype.getSpecialHint = function (enemy, special) {
return "";
}
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);
}
return "";
}
////// 能否获胜 //////
enemys.prototype.canBattle = function (enemy, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
@ -105,13 +107,13 @@ enemys.prototype.canBattle = function (enemy, x, y, floorId) {
////// 获得某个怪物的伤害 //////
enemys.prototype.getDamage = function (enemy, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var damage = this.calDamage(enemy, null, x, y, floorId);
var damage = this._calDamage(enemy, null, x, y, floorId);
if (damage == null) return null;
return damage + this.getExtraDamage(enemy);
return damage + this.getExtraDamage(enemy, x, y, floorId);
}
////// 获得某个怪物的额外伤害 //////
enemys.prototype.getExtraDamage = function (enemy) {
enemys.prototype.getExtraDamage = function (enemy, x, y, floorId) {
if (typeof enemy == 'string') enemy = core.material.enemys[enemy];
var extra_damage = 0;
if (this.hasSpecial(enemy.special, 17)) { // 仇恨
@ -155,6 +157,40 @@ enemys.prototype.getDamageString = function (enemy, x, y, floorId) {
};
}
////// 接下来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);
}
}
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 = [];
@ -209,7 +245,7 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f
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));
nextAtk = Math.ceil(nextAtk / core.getBuff('atk'));
if (nextAtk <= hero_atk) break;
if (nextAtk != pre) {
var nextInfo = this.getDamageInfo(enemy, {"atk": nextAtk}, x, y, floorId);
@ -225,46 +261,12 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f
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, null, x, y, floorId);
var nextDamage = this.calDamage(enemy, {"def": core.status.hero.def + k}, 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;
}
@ -282,7 +284,7 @@ enemys.prototype.getDamageInfo = function(enemy, hero, x, y, floorId) {
}
////// 获得在某个勇士属性下怪物伤害 //////
enemys.prototype.calDamage = function (enemy, hero, 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, x, y, floorId);
@ -302,8 +304,7 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
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) {
if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') == 0) {
this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId);
}
}
@ -312,14 +313,10 @@ enemys.prototype.getCurrentEnemys = function (floorId) {
enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) {
var enemy = core.material.enemys[enemyId];
if (!core.isset(enemy)) return null;
if (!enemy) return null;
// 检查displayIdInBook
var tmpId = enemy.displayIdInBook;
if (core.isset(core.material.enemys[tmpId])) {
enemy = core.material.enemys[tmpId];
}
return enemy;
return core.material.enemys[enemy.displayIdInBook] || enemy;
}
enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, floorId) {
@ -361,3 +358,7 @@ enemys.prototype._getCurrentEnemys_sort = function (enemys) {
return a.damage - b.damage;
});
}
enemys.prototype.hasEnemyLeft = function (floorId) {
return core.getCurrentEnemys(floorId).length > 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,35 @@ items.prototype.getItems = function () {
return core.clone(this.items);
}
items.prototype._resetItems = function () {
// 只有运行时才能执行此函数!
if (main.mode != 'play') return;
// 根据flag来对道具进行修改
if (core.flags.bigKeyIsBox) {
core.material.items.bigKey.cls = 'items';
core.material.items.bigKey.name = '钥匙盒';
}
if (core.flags.pickaxeFourDirections)
core.material.items.pickaxe.text = "可以破坏勇士四周的墙";
if (core.flags.bombFourDirections)
core.material.items.bomb.text = "可以炸掉勇士四周的怪物";
if (core.flags.snowFourDirections)
core.material.items.bomb.text = "可以将四周的熔岩变成平地";
if (core.flags.equipment) {
core.material.items.sword1.cls = 'equips';
core.material.items.sword2.cls = 'equips';
core.material.items.sword3.cls = 'equips';
core.material.items.sword4.cls = 'equips';
core.material.items.sword5.cls = 'equips';
core.material.items.shield1.cls = 'equips';
core.material.items.shield2.cls = 'equips';
core.material.items.shield3.cls = 'equips';
core.material.items.shield4.cls = 'equips';
core.material.items.shield5.cls = 'equips';
}
}
////// “即捡即用类”道具的使用效果 //////
items.prototype.getItemEffect = function (itemId, itemNum) {
var itemCls = core.material.items[itemId].cls;
@ -61,6 +90,21 @@ items.prototype.getItemEffectTip = function(itemId) {
return "";
}
////// 使用道具 //////
items.prototype.useItem = function (itemId, noRoute, callback) {
if (!this.canUseItem(itemId)) {
if (callback) callback();
return;
}
// 执行道具效果
this._useItemEffect(itemId);
// 执行完毕
this._afterUseItem(itemId);
// 记录路线
if (!noRoute) core.status.route.push("item:" + itemId);
if (callback) callback();
}
items.prototype._useItemEffect = function (itemId) {
if (itemId in this.useItemEffect) {
try {
@ -81,25 +125,13 @@ items.prototype._afterUseItem = function (itemId) {
if (core.status.hero.items[itemCls][itemId] <= 0)
delete core.status.hero.items[itemCls][itemId];
if (!core.status.event.id) {
core.status.event.data = null;
core.status.event.ui = null;
}
core.updateStatusBar();
}
////// 使用道具 //////
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();
}
////// 当前能否使用道具 //////
items.prototype.canUseItem = function (itemId) {
// 没有道具
@ -114,15 +146,17 @@ items.prototype.canUseItem = function (itemId) {
main.log(e);
}
}
if (!able) core.status.event.ui = null;
if (!able) {
core.status.event.data = null;
core.status.event.ui = null;
}
return able;
}
////// 获得某个物品的个数 //////
items.prototype.itemCount = function (itemId) {
if (!core.isset(core.status.hero)) return 0;
if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0;
if (!core.material.items[itemId] || !core.isPlaying()) return 0;
var itemCls = core.material.items[itemId].cls;
if (itemCls == "items") return 0;
return core.status.hero.items[itemCls][itemId] || 0;
@ -135,12 +169,9 @@ items.prototype.hasItem = function (itemId) {
////// 是否装备某件装备 //////
items.prototype.hasEquip = function (itemId) {
if (!core.isset(core.status.hero)) return null;
if (!(core.material.items[itemId] || {}).equip || !core.isPlaying()) return null;
if (!core.isset(itemId)) return null;
if (!core.isset((core.material.items[itemId]||{}).equip)) return null;
for (var i in core.status.hero.equipment||[])
for (var i in core.status.hero.equipment)
if (core.status.hero.equipment[i] == itemId)
return true;
return false
@ -148,19 +179,15 @@ items.prototype.hasEquip = function (itemId) {
////// 获得某个装备类型的当前装备 //////
items.prototype.getEquip = function (equipType) {
if (!core.isset(core.status.hero)) return null;
return (core.status.hero.equipment||[])[equipType]||null;
return core.status.hero.equipment[equipType] || null;
}
////// 设置某个物品的个数 //////
items.prototype.setItem = function (itemId, itemNum) {
if (!core.isset(core.status.hero)) return null;
itemNum = itemNum || 0;
var itemCls = core.material.items[itemId].cls;
if (itemCls == 'items') return;
if (!core.isset(core.status.hero.items[itemCls])) {
core.status.hero.items[itemCls] = {};
}
core.status.hero.items[itemCls][itemId] = itemNum;
if (core.status.hero.items[itemCls][itemId] <= 0) {
if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId];
@ -169,33 +196,13 @@ items.prototype.setItem = function (itemId, itemNum) {
core.updateStatusBar();
}
////// 删除某个物品 //////
items.prototype.removeItem = function (itemId, itemNum) {
if (!core.isset(core.status.hero)) return null;
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;
if (core.status.hero.items[itemCls][itemId] <= 0) {
if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId];
else core.status.hero.items[itemCls][itemId] = 0;
}
core.updateStatusBar();
return true;
}
////// 增加某个物品的个数 //////
items.prototype.addItem = function (itemId, itemNum) {
if (!core.isset(core.status.hero)) return null;
if (!core.isset(itemNum)) itemNum = 1;
if (itemNum == null) itemNum = 1;
var itemData = core.material.items[itemId];
var itemCls = itemData.cls;
if (itemCls == 'items') return;
if (!core.isset(core.status.hero.items[itemCls])) {
core.status.hero.items[itemCls] = {};
core.status.hero.items[itemCls][itemId] = 0;
}
else if (!core.isset(core.status.hero.items[itemCls][itemId])) {
if (core.status.hero.items[itemCls][itemId] == null) {
core.status.hero.items[itemCls][itemId] = 0;
}
core.status.hero.items[itemCls][itemId] += itemNum;
@ -209,8 +216,32 @@ items.prototype.addItem = function (itemId, itemNum) {
core.updateStatusBar();
}
////// 删除某个物品 //////
items.prototype.removeItem = function (itemId, itemNum) {
if (itemNum == null) itemNum = 1;
if (!core.hasItem(itemId)) return false;
var itemCls = core.material.items[itemId].cls;
core.status.hero.items[itemCls][itemId] -= itemNum;
if (core.status.hero.items[itemCls][itemId] <= 0) {
if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId];
else core.status.hero.items[itemCls][itemId] = 0;
}
core.updateStatusBar();
return true;
}
// ---------- 装备相关 ------------ //
items.prototype.getEquipTypeByName = function (name) {
var names = core.status.globalAttribute.equipName;
for (var i = 0; i < names.length; ++i) {
if (names[i] === name && !core.status.hero.equipment[i]) {
return i;
}
}
return -1;
}
items.prototype.getEquipTypeById = function (equipId) {
var type = core.material.items[equipId].equip.type;
if (typeof type == 'string')
@ -218,21 +249,11 @@ items.prototype.getEquipTypeById = function (equipId) {
return type;
}
items.prototype.getEquipTypeByName = function (name) {
var names = core.status.globalAttribute.equipName;
for (var i = 0; i < names.length; ++i) {
if (names[i] === name && !core.isset((core.status.hero.equipment||[])[i])) {
return i;
}
}
return -1;
}
// 当前能否撞上某装备
items.prototype.canEquip = function (equipId, hint) {
// 装备是否合法
var equip = core.material.items[equipId] || {};
if (!core.isset(equip.equip)) {
if (!equip.equip) {
if (hint) core.drawTip("不合法的装备!");
return false;
}
@ -245,7 +266,7 @@ items.prototype.canEquip = function (equipId, hint) {
// 可装备条件
var condition = this.equipCondition[equipId];
if (core.isset(condition) && condition.length>0) {
if (condition) {
try {
if (!eval(condition)) {
if (hint) core.drawTip("当前不可换上" + equip.name);
@ -260,32 +281,75 @@ items.prototype.canEquip = function (equipId, hint) {
return true;
}
////// 换上 //////
items.prototype.loadEquip = function (equipId, callback) {
if (!this.canEquip(equipId, true)) {
if (callback) callback();
return;
}
var loadEquip = core.material.items[equipId] || {};
var type = this.getEquipTypeById(equipId);
if (type < 0) {
core.drawTip("当前没有" + loadEquip.equip.type + "的空位!");
if (callback) callback();
return;
}
this._realLoadEquip(type, equipId, core.status.hero.equipment[type], callback);
}
////// 卸下 //////
items.prototype.unloadEquip = function (equipType, callback) {
var unloadEquipId = core.status.hero.equipment[equipType];
if (!unloadEquipId) {
if (callback) callback();
return;
}
this._realLoadEquip(equipType, null, unloadEquipId, callback);
}
items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) {
var result = {};
var first = core.material.items[compareEquipId], second = core.material.items[beComparedEquipId];
for (var name in core.status.hero) {
if (typeof core.status.hero[name] == 'number') {
var ans = 0;
if (first) ans += (first.equip || {})[name] || 0;
if (second) ans -= (second.equip || {})[name] || 0;
if (ans != 0) result[name] = ans;
}
}
return result;
}
////// 实际换装的效果 //////
items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentage) {
// 比较能力值
var result = core.compareEquipment(equipId, unloadEquipId);
if (isPercentage) {
for (var v in result)
core.addFlag('__'+v+'_buff__', result[v]/100);
for (var name in result)
core.addBuff(name, result[name] / 100);
}
else {
for (var v in result)
core.status.hero[v] += result[v];
for (var name in result)
core.status.hero[name] += result[name];
}
}
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 = {};
loadEquip.equip = loadEquip.equip || {};
unloadEquip.equip = unloadEquip.equip || {}
var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage;
if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) {
if (loadId && unloadId && (loadPercentage || false) != (unloadPercentage || false)) {
this.unloadEquip(type);
this.loadEquip(loadId);
if (core.isset(callback)) callback();
if (callback) callback();
return;
}
@ -301,65 +365,14 @@ items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) {
core.status.hero.equipment[type] = loadId || null;
// --- 提示
if (loadId) core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[loadId]);
else if (unloadId) core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadId]);
if (loadId) core.drawTip("已装备上" + loadEquip.name, loadId);
else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, 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 = [];
var unloadEquipId = core.status.hero.equipment[equipType];
if (!core.isset(unloadEquipId)) {
if (core.isset(callback)) callback();
return;
}
this._realLoadEquip(equipType, null, unloadEquipId, callback);
}
items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) {
var compareAtk = 0, compareDef = 0, compareMdef = 0;
if (core.isset(compareEquipId)) {
var compareEquip = core.material.items[compareEquipId];
compareAtk += (compareEquip.equip||{}).atk || 0;
compareDef += (compareEquip.equip||{}).def || 0;
compareMdef += (compareEquip.equip||{}).mdef || 0;
}
if (core.isset(beComparedEquipId)) {
var beComparedEquip = core.material.items[beComparedEquipId];
compareAtk -= (beComparedEquip.equip||{}).atk || 0;
compareDef -= (beComparedEquip.equip||{}).def || 0;
compareMdef -= (beComparedEquip.equip||{}).mdef || 0;
}
return {"atk":compareAtk,"def":compareDef,"mdef":compareMdef};
if (callback) callback();
}
////// 保存装备 //////
items.prototype.quickSaveEquip = function (index) {
if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = [];
var saveEquips = core.getFlag("saveEquips", []);
saveEquips[index] = core.clone(core.status.hero.equipment);
core.setFlag("saveEquips", saveEquips);
@ -369,7 +382,7 @@ items.prototype.quickSaveEquip = function (index) {
////// 读取装备 //////
items.prototype.quickLoadEquip = function (index) {
var current = core.getFlag("saveEquips", [])[index];
if (!core.isset(current)) {
if (!current) {
core.drawTip(index + "号套装不存在");
return;
}
@ -377,21 +390,20 @@ items.prototype.quickLoadEquip = function (index) {
var equipSize = core.status.globalAttribute.equipName.length;
for (var i = 0; i < equipSize; i++) {
var v = current[i];
if (core.isset(v) && !this.canEquip(v, true))
if (v && !this.canEquip(v, true))
return;
}
// 快速换装
if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = [];
for (var i = 0; i < equipSize; i++) {
var now = core.status.hero.equipment[i] || null;
if (now != null) {
var now = core.status.hero.equipment[i];
if (now) {
this.unloadEquip(i);
core.status.route.push("unEquip:" + i);
}
}
for (var i = 0; i < equipSize; i++) {
var to = current[i]||null;
if (to!=null) {
var to = current[i];
if (to) {
this.loadEquip(to);
core.status.route.push("equip:" + to);
}

View File

@ -13,12 +13,12 @@ loader.prototype._init = function () {
}
////// 设置加载进度条进度 //////
loader.prototype.setStartProgressVal = function (val) {
loader.prototype._setStartProgressVal = function (val) {
core.dom.startTopProgress.style.width = val + '%';
}
////// 设置加载进度条提示文字 //////
loader.prototype.setStartLoadTipText = function (text) {
loader.prototype._setStartLoadTipText = function (text) {
core.dom.startTopLoadTips.innerHTML = text;
}
@ -38,11 +38,11 @@ loader.prototype._load = function (callback) {
loader.prototype._loadIcons = function () {
this.loadImage("icons.png", function (id, image) {
var images = core.cropImage(image);
var images = core.splitImage(image);
for (var key in core.statusBar.icons) {
if (typeof core.statusBar.icons[key] == 'number') {
core.statusBar.icons[key] = images[core.statusBar.icons[key]];
if (core.isset(core.statusBar.image[key]))
if (core.statusBar.image[key] != null)
core.statusBar.image[key].src = core.statusBar.icons[key].src;
}
}
@ -73,7 +73,7 @@ loader.prototype._loadAutotiles = function (callback) {
});
setTimeout(function () {
core.maps.makeAutotileEdges();
core.maps._makeAutotileEdges();
});
callback();
@ -82,7 +82,7 @@ loader.prototype._loadAutotiles = function (callback) {
loader.prototype._loadTilesets = function (callback) {
core.material.images.tilesets = {};
if (!core.isset(core.tilesets)) core.tilesets = [];
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) {
@ -99,19 +99,19 @@ loader.prototype._loadTilesets = function (callback) {
}
loader.prototype.loadImages = function (names, toSave, callback) {
if (!core.isset(names) || names.length==0) {
if (core.isset(callback)) callback();
if (!names || names.length == 0) {
if (callback) callback();
return;
}
var items = 0;
for (var i = 0; i < names.length; i++) {
this.loadImage(names[i], function (id, image) {
core.loader.setStartLoadTipText('正在加载图片 ' + id + "...");
core.loader._setStartLoadTipText('正在加载图片 ' + id + "...");
toSave[id] = image;
items++;
core.loader.setStartProgressVal(items * (100 / names.length));
core.loader._setStartProgressVal(items * (100 / names.length));
if (items == names.length) {
if (core.isset(callback)) callback();
if (callback) callback();
}
})
}
@ -144,7 +144,7 @@ loader.prototype._loadAnimates = function () {
data.images = [];
data.images_rev = [];
content.bitmaps.forEach(function (t2) {
if (!core.isset(t2) || t2 == "") {
if (!t2) {
data.images.push(null);
}
else {
@ -237,30 +237,8 @@ loader.prototype.loadOneSound = function (name) {
}
}
loader.prototype.freeBgm = function (name) {
if (!core.isset(core.material.bgms[name])) return;
// 从cachedBgms中删除
core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {return t!=name; });
// 清掉缓存
core.material.bgms[name].removeAttribute("src");
core.material.bgms[name].load();
core.material.bgms[name] = null;
if (name == core.musicStatus.playingBgm) {
core.musicStatus.playingBgm = null;
}
// 三秒后重新加载
setTimeout(function () {
core.loader.loadOneMusic(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;
if (!core.material.bgms[name]) return;
// 如果没开启音乐,则不预加载
if (!core.musicStatus.bgmStatus) return;
// 是否已经预加载过
@ -280,3 +258,27 @@ loader.prototype.loadBgm = function (name) {
// 移动到缓存最前方
core.musicStatus.cachedBgms.unshift(name);
}
loader.prototype._preloadBgm = function (bgm) {
bgm.volume = 0;
bgm.play();
}
loader.prototype.freeBgm = function (name) {
if (!core.material.bgms[name]) return;
// 从cachedBgms中删除
core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {
return t != name;
});
// 清掉缓存
core.material.bgms[name].removeAttribute("src");
core.material.bgms[name].load();
core.material.bgms[name] = null;
if (name == core.musicStatus.playingBgm) {
core.musicStatus.playingBgm = null;
}
// 三秒后重新加载
setTimeout(function () {
core.loader.loadOneMusic(name);
}, 3000);
}

File diff suppressed because it is too large Load Diff

3126
libs/ui.js

File diff suppressed because it is too large Load Diff

View File

@ -61,12 +61,12 @@ utils.prototype.replaceText = function (text, need, times) {
////// 计算表达式的值 //////
utils.prototype.calValue = function (value, prefix, need, times) {
if (!core.isset(value)) return value;
if (!core.isset(value)) return null;
if (typeof value === 'string') {
value = value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')");
value = value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')");
value = value.replace(/flag:([\w\d_]+)/g, "core.getFlag('$1', 0)");
value=value.replace(/switch:([\w\d_]+)/g, "core.getFlag('"+(prefix||"global")+"@$1', 0)");
value = value.replace(/switch:([\w\d_]+)/g, "core.getFlag('" + (prefix || ":f@x@y") + "@$1', 0)");
return eval(value);
}
if (value instanceof Function) {
@ -75,38 +75,9 @@ utils.prototype.calValue = function (value, prefix, need, times) {
return value;
}
////// 字符串自动换行的分割 //////
utils.prototype.splitLines = function(canvas, text, maxLength, font) {
if (core.isset(font)) core.setFont(canvas, font);
var contents = [];
var last = 0;
for (var i=0;i<text.length;i++) {
if (text.charAt(i)=='\n') {
contents.push(text.substring(last, i));
last=i+1;
}
else if (text.charAt(i)=='\\' && text.charAt(i+1)=='n') {
contents.push(text.substring(last, i));
last=i+2;
}
else {
var toAdd = text.substring(last, i+1);
var width = core.calWidth(canvas, toAdd);
if (core.isset(maxLength) && width>maxLength) {
contents.push(text.substring(last, i));
last=i;
}
}
}
contents.push(text.substring(last));
return contents;
}
////// 向某个数组前插入另一个数组或元素 //////
utils.prototype.unshift = function (a, b) {
if (!(a instanceof Array) || !core.isset(b)) return;
if (!(a instanceof Array) || b == null) return;
if (b instanceof Array) {
core.clone(b).reverse().forEach(function (e) {
a.unshift(e);
@ -118,7 +89,7 @@ utils.prototype.unshift = function (a,b) {
////// 向某个数组后插入另一个数组或元素 //////
utils.prototype.push = function (a, b) {
if (!(a instanceof Array) || !core.isset(b)) return;
if (!(a instanceof Array) || b == null) return;
if (b instanceof Array) {
core.clone(b).forEach(function (e) {
a.push(e);
@ -128,10 +99,32 @@ utils.prototype.push = function (a,b) {
return a;
}
utils.prototype.decompress = function (value) {
try {
var output = lzw_decode(value);
if (output) return JSON.parse(output);
}
catch (e) {
}
try {
var output = LZString.decompress(value);
if (output) return JSON.parse(output);
}
catch (e) {
}
try {
return JSON.parse(value);
}
catch (e) {
main.log(e);
}
return null;
}
////// 设置本地存储 //////
utils.prototype.setLocalStorage = function (key, value) {
try {
if (!core.isset(value)) {
if (value == null) {
this.removeLocalStorage(key);
return;
}
@ -163,26 +156,6 @@ 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) {
var res = this.decompress(localStorage.getItem(core.firstData.name + "_" + key));
@ -200,15 +173,15 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal
if (!core.platform.useLocalForage) {
if (this.setLocalStorage(key, value)) {
if (core.isset(successCallback)) successCallback();
if (successCallback) successCallback();
}
else {
if (core.isset(errorCallback)) errorCallback();
if (errorCallback) errorCallback();
}
return;
}
if (!core.isset(value)) {
if (value == null) {
this.removeLocalForage(key);
return;
}
@ -218,13 +191,13 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal
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);
if (err) {
if (errorCallback) errorCallback(err);
}
else {
if (key == 'autoSave') core.saves.ids[0] = true;
else if (/^save\d+$/.test(key)) core.saves.ids[parseInt(key.substring(4))] = true;
if (core.isset(successCallback)) successCallback();
if (successCallback) successCallback();
}
});
}
@ -233,19 +206,17 @@ utils.prototype.getLocalForage = function (key, defaultValue, successCallback, e
if (!core.platform.useLocalForage) {
var value = this.getLocalStorage(key, defaultValue);
if (core.isset(successCallback)) {
successCallback(value);
}
if (successCallback) successCallback(value);
return;
}
localforage.getItem(core.firstData.name + "_" + key, function (err, value) {
if (core.isset(err)) {
if (core.isset(errorCallback)) errorCallback(err);
if (err) {
if (errorCallback) errorCallback(err);
}
else {
if (!core.isset(successCallback)) return;
if (core.isset(value)) {
if (!successCallback) return;
if (value != null) {
var res = core.utils.decompress(value);
successCallback(res == null ? defaultValue : res);
return;
@ -259,25 +230,25 @@ utils.prototype.removeLocalForage = function (key, successCallback, errorCallbac
if (!core.platform.useLocalForage) {
this.removeLocalStorage(key);
if (core.isset(successCallback)) successCallback();
if (successCallback) successCallback();
return;
}
localforage.removeItem(core.firstData.name + "_" + key, function (err) {
if (core.isset(err)) {
if (core.isset(errorCallback)) errorCallback(err);
if (err) {
if (errorCallback) errorCallback(err);
}
else {
if (key == 'autoSave') delete core.saves.ids[0];
else if (/^save\d+$/.test(key)) delete core.saves.ids[parseInt(key.substring(4))];
if (core.isset(successCallback)) successCallback();
if (successCallback) successCallback();
}
})
}
////// 深拷贝一个对象 //////
utils.prototype.clone = function (data) {
if (!core.isset(data)) return data;
if (!core.isset(data)) return null;
// date
if (data instanceof Date) {
var copy = new Date();
@ -311,37 +282,49 @@ utils.prototype.clone = function (data) {
}
////// 裁剪图片 //////
utils.prototype.cropImage = function (image, size) {
size = size||32;
utils.prototype.splitImage = function (image, width, height) {
if (typeof image == "string")
image = core.material.images.images[image];
if (!image) return [];
width = width || 32;
height = height || width;
var canvas = document.createElement("canvas");
var context = canvas.getContext("2d");
canvas.width = size;
canvas.height = size;
canvas.width = width;
canvas.height = height;
var ans = [];
for (var i=0;i<image.height;i+=size) {
context.drawImage(image, 0, i, size, size, 0, 0, size, size);
for (var j = 0; j < image.height; j += height) {
for (var i = 0; i < image.width; i += width) {
context.drawImage(image, i, j, width, height, 0, 0, width, height);
var img = new Image();
img.src = canvas.toDataURL("image/png");
ans.push(img);
context.clearRect(0,0,size,size);
context.clearRect(0, 0, width, height);
}
}
return ans;
}
////// 格式化时间为字符串 //////
utils.prototype.formatDate = function (date) {
if (!core.isset(date)) return "";
if (!date) date = new Date();
return "" + date.getFullYear() + "-" + core.setTwoDigits(date.getMonth() + 1) + "-" + core.setTwoDigits(date.getDate()) + " "
+ core.setTwoDigits(date.getHours()) + ":" + core.setTwoDigits(date.getMinutes()) + ":" + core.setTwoDigits(date.getSeconds());
}
////// 格式化时间为最简字符串 //////
utils.prototype.formatDate2 = function (date) {
if (!core.isset(date)) return "";
if (!date) date = new Date();
return "" + date.getFullYear() + core.setTwoDigits(date.getMonth() + 1) + core.setTwoDigits(date.getDate())
+ core.setTwoDigits(date.getHours()) + core.setTwoDigits(date.getMinutes()) + core.setTwoDigits(date.getSeconds());
}
utils.prototype.formatTime = function (time) {
return core.setTwoDigits(parseInt(time/3600000))
+":"+core.setTwoDigits(parseInt(time/60000)%60)
+":"+core.setTwoDigits(parseInt(time/1000)%60);
}
////// 两位数显示 //////
utils.prototype.setTwoDigits = function (x) {
return parseInt(x) < 10 ? "0" + x : x;
@ -391,12 +374,42 @@ utils.prototype.arrayToRGB = function (color) {
}
utils.prototype.arrayToRGBA = function (color) {
if (!this.isset(color[3])) color[3]=1;
if (color[3] == null) color[3] = 1;
var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255),
nowB = this.clamp(parseInt(color[2]), 0, 255), nowA = this.clamp(parseFloat(color[3]), 0, 1);
return "rgba(" + nowR + "," + nowG + "," + nowB + "," + nowA + ")";
}
////// 加密路线 //////
utils.prototype.encodeRoute = function (route) {
var ans = "", lastMove = "", cnt = 0;
route.forEach(function (t) {
if (t == 'up' || t == 'down' || t == 'left' || t == 'right') {
if (t != lastMove && cnt > 0) {
ans += lastMove.substring(0, 1).toUpperCase();
if (cnt > 1) ans += cnt;
cnt = 0;
}
lastMove = t;
cnt++;
}
else {
if (cnt > 0) {
ans += lastMove.substring(0, 1).toUpperCase();
if (cnt > 1) ans += cnt;
cnt = 0;
}
ans += core.utils._encodeRoute_encodeOne(t);
}
});
if (cnt > 0) {
ans += lastMove.substring(0, 1).toUpperCase();
if (cnt > 1) ans += cnt;
}
return LZString.compressToBase64(ans);
}
utils.prototype._encodeRoute_id2number = function (id) {
var number = core.maps.getNumberById(id);
return number == 0 ? id : number;
@ -433,37 +446,28 @@ utils.prototype._encodeRoute_encodeOne = function (t) {
return 'K' + t.substring(4);
else if (t.indexOf('random:') == 0)
return 'X' + t.substring(7);
return '';
return '('+t+')';
}
////// 密路线 //////
utils.prototype.encodeRoute = function (route) {
var ans="", lastMove = "", cnt=0;
////// 密路线 //////
utils.prototype.decodeRoute = function (route) {
if (!route) return route;
route.forEach(function (t) {
if (t=='up' || t=='down' || t=='left' || t=='right') {
if (t!=lastMove && cnt>0) {
ans+=lastMove.substring(0,1).toUpperCase();
if (cnt>1) ans+=cnt;
cnt=0;
// 解压缩
try {
var v = LZString.decompressFromBase64(route);
if (v != null && /^[-_a-zA-Z0-9+\/=:()]*$/.test(v)) {
if (v != "" || route.length < 8)
route = v;
}
lastMove=t;
cnt++;
} catch (e) {
}
else {
if (cnt>0) {
ans+=lastMove.substring(0,1).toUpperCase();
if (cnt>1) ans+=cnt;
cnt=0;
var decodeObj = {route: route, index: 0, ans: []};
while (decodeObj.index < decodeObj.route.length) {
this._decodeRoute_decodeOne(decodeObj, decodeObj.route.charAt(decodeObj.index++));
}
ans += core.utils._encodeRoute_encodeOne(t);
}
});
if (cnt>0) {
ans+=lastMove.substring(0,1).toUpperCase();
if (cnt>1) ans+=cnt;
}
return LZString.compressToBase64(ans);
return decodeObj.ans;
}
utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) {
@ -472,7 +476,7 @@ utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) {
num += decodeObj.route.charAt(decodeObj.index++);
}
if (num.length == 0) num = "1";
return core.isset(noparse)?num:parseInt(num);
return noparse ? num : parseInt(num);
}
utils.prototype._decodeRoute_getString = function (decodeObj) {
@ -487,67 +491,90 @@ utils.prototype._decodeRoute_getString = function (decodeObj) {
utils.prototype._decodeRoute_number2id = function (number) {
if (/^\d+$/.test(number)) {
var info = core.maps.blocksInfo[number];
if (core.isset(info)) return info.id;
if (info) return info.id;
}
return number;
}
utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) {
// --- 特殊处理自定义项
if (c == '(') {
var idx = decodeObj.route.indexOf(')', decodeObj.index);
if (idx >= 0) {
decodeObj.ans.push(decodeObj.route.substring(decodeObj.index, idx));
decodeObj.index = idx + 1;
return;
}
}
var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't') ?
this._decodeRoute_getString(decodeObj) : this._decodeRoute_getNumber(decodeObj);
var mp = {"U": "up", "D": "down", "L": "left", "R": "right"};
switch (c) {
case "U": case "D": case "L": case "R": for (var i=0;i<nxt;i++) decodeObj.ans.push(mp[c]); break;
case "I": decodeObj.ans.push("item:"+this._decodeRoute_number2id(nxt)); break;
case "u": decodeObj.ans.push("unEquip:"+nxt); break;
case "e": decodeObj.ans.push("equip:"+this._decodeRoute_number2id(nxt)); break;
case "F": decodeObj.ans.push("fly:"+nxt); break;
case "C": decodeObj.ans.push("choices:"+nxt); break;
case "S": decodeObj.ans.push("shop:"+nxt+":"+this._decodeRoute_getNumber(decodeObj, true)); break;
case "T": decodeObj.ans.push("turn"); break;
case "t": decodeObj.ans.push("turn:"+mp[nxt]); break;
case "G": decodeObj.ans.push("getNext"); break;
case "P": decodeObj.ans.push("input:"+nxt); break;
case "Q": decodeObj.ans.push("input2:"+nxt); break;
case "N": decodeObj.ans.push("no"); break;
case "M": ++decodeObj.index; decodeObj.ans.push("move:"+nxt+":"+this._decodeRoute_getNumber(decodeObj)); break;
case "K": decodeObj.ans.push("key:"+nxt); break;
case "X": decodeObj.ans.push("random:"+nxt); break;
case "U":
case "D":
case "L":
case "R":
for (var i = 0; i < nxt; i++) decodeObj.ans.push(mp[c]);
break;
case "I":
decodeObj.ans.push("item:" + this._decodeRoute_number2id(nxt));
break;
case "u":
decodeObj.ans.push("unEquip:" + nxt);
break;
case "e":
decodeObj.ans.push("equip:" + this._decodeRoute_number2id(nxt));
break;
case "F":
decodeObj.ans.push("fly:" + nxt);
break;
case "C":
decodeObj.ans.push("choices:" + nxt);
break;
case "S":
decodeObj.ans.push("shop:" + nxt + ":" + this._decodeRoute_getNumber(decodeObj, true));
break;
case "T":
decodeObj.ans.push("turn");
break;
case "t":
decodeObj.ans.push("turn:" + mp[nxt]);
break;
case "G":
decodeObj.ans.push("getNext");
break;
case "P":
decodeObj.ans.push("input:" + nxt);
break;
case "Q":
decodeObj.ans.push("input2:" + nxt);
break;
case "N":
decodeObj.ans.push("no");
break;
case "M":
++decodeObj.index;
decodeObj.ans.push("move:" + nxt + ":" + this._decodeRoute_getNumber(decodeObj));
break;
case "K":
decodeObj.ans.push("key:" + nxt);
break;
case "X":
decodeObj.ans.push("random:" + nxt);
break;
}
}
////// 解密路线 //////
utils.prototype.decodeRoute = function (route) {
if (!core.isset(route)) return route;
// 解压缩
try {
var v = LZString.decompressFromBase64(route);
if (core.isset(v) && /^[a-zA-Z0-9+\/=:]*$/.test(v)) {
route = v;
}
} catch (e) {}
var decodeObj = {route: route, index: 0, ans: []};
while (decodeObj.index < decodeObj.route.length) {
this._decodeRoute_decodeOne(decodeObj, decodeObj.route.charAt(decodeObj.index++));
}
return decodeObj.ans;
}
////// 判断某对象是否不为undefined也不会null //////
////// 判断某对象是否不为null也不为NaN //////
utils.prototype.isset = function (val) {
if (val == undefined || val == null || (typeof val=='number' && isNaN(val))) {
return false;
}
return true
return val != null && !(typeof val == 'number' && isNaN(val));
}
////// 获得子数组 //////
utils.prototype.subarray = function (a, b) {
if (!core.isset(a) || !core.isset(b) || !(a instanceof Array) || !(b instanceof Array) || a.length<b.length)
if (!(a instanceof Array) || !(b instanceof Array) || a.length < b.length)
return null;
var na = core.clone(a), nb = core.clone(b);
while (nb.length > 0) {
@ -557,7 +584,7 @@ utils.prototype.subarray = function (a, b) {
}
utils.prototype.inArray = function (array, element) {
return this.isset(array) && (array instanceof Array) && array.indexOf(element)>=0;
return (array instanceof Array) && array.indexOf(element) >= 0;
}
utils.prototype.clamp = function (x, a, b) {
@ -570,6 +597,33 @@ utils.prototype.getCookie = function (name) {
return match ? match[2] : null;
}
////// 设置statusBar的innerHTML会自动斜体和放缩也可以增加自定义css //////
utils.prototype.setStatusBarInnerHTML = function (name, value, css) {
if (!core.statusBar[name]) return;
if (typeof value == 'number') value = this.formatBigNumber(value);
// 判定是否斜体
var italic = /^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test(value);
var style = 'font-style: ' + (italic ? 'italic' : 'normal') + '; ';
// 判定是否需要缩放
var length = this.strlen(value) || 1;
style += 'font-size: ' + Math.min(1, 7 / length) + 'em; ';
if (css) style += css;
core.statusBar[name].innerHTML = "<span class='_status' style='" + style + "'>" + value + "</span>";
}
utils.prototype.strlen = function (str) {
var count = 0;
for (var i = 0, len = str.length; i < len; i++) {
count += str.charCodeAt(i) < 256 ? 1 : 2;
}
return count;
};
utils.prototype.reverseDirection = function (direction) {
direction = direction || core.getHeroLoc('direction');
return {"left":"right","right":"left","down":"up","up":"down"}[direction] || direction;
}
////// Base64加密 //////
utils.prototype.encodeBase64 = function (str) {
return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) {
@ -604,27 +658,12 @@ utils.prototype.convertBase = function (str, fromBase, toBase) {
return ans;
}
utils.prototype.__init_seed = function () {
var rand = new Date().getTime()%34834795 + 3534;
rand = this.__next_rand(rand);
rand = this.__next_rand(rand);
rand = this.__next_rand(rand);
core.setFlag('__seed__', rand);
core.setFlag('__rand__', rand);
}
utils.prototype.__next_rand = function (_rand) {
_rand=(_rand%127773)*16807-~~(_rand/127773)*2836;
_rand+=_rand<0?2147483647:0;
return _rand;
}
utils.prototype.rand = function (num) {
var rand = core.getFlag('__rand__');
rand = this.__next_rand(rand);
core.setFlag('__rand__', rand);
var ans = rand / 2147483647;
if (core.isset(num) && num>0)
if (num && num > 0)
return Math.floor(ans * num);
return ans;
}
@ -652,13 +691,28 @@ utils.prototype.rand2 = function (num) {
return value;
}
utils.prototype.__init_seed = function () {
var rand = new Date().getTime() % 34834795 + 3534;
rand = this.__next_rand(rand);
rand = this.__next_rand(rand);
rand = this.__next_rand(rand);
core.setFlag('__seed__', rand);
core.setFlag('__rand__', rand);
}
utils.prototype.__next_rand = function (_rand) {
_rand = (_rand % 127773) * 16807 - ~~(_rand / 127773) * 2836;
_rand += _rand < 0 ? 2147483647 : 0;
return _rand;
}
////// 读取一个本地文件内容 //////
utils.prototype.readFile = function (success, error, readType) {
core.platform.successCallback = success;
core.platform.errorCallback = error;
if (core.isset(window.jsinterface)) {
if (window.jsinterface) {
window.jsinterface.readFile();
return;
}
@ -666,14 +720,14 @@ utils.prototype.readFile = function (success, error, readType) {
// step 0: 不为http/https直接不支持
if (!core.platform.isOnline) {
alert("离线状态下不支持文件读取!");
if (core.isset(error)) error();
if (error) error();
return;
}
// Step 1: 如果不支持FileReader直接不支持
if (core.platform.fileReader == null) {
alert("当前浏览器不支持FileReader");
if (core.isset(error)) error();
if (error) error();
return;
}
@ -684,7 +738,7 @@ utils.prototype.readFile = function (success, error, readType) {
core.platform.fileInput.onchange = function () {
var files = core.platform.fileInput.files;
if (files.length == 0) {
if (core.isset(core.platform.errorCallback))
if (core.platform.errorCallback)
core.platform.errorCallback();
return;
}
@ -701,14 +755,14 @@ utils.prototype.readFile = function (success, error, readType) {
utils.prototype.readFileContent = function (content) {
var obj = null;
if (content.slice(0, 4) === 'data') {
if (core.isset(core.platform.successCallback))
if (core.platform.successCallback)
core.platform.successCallback(content);
return;
}
try {
obj = JSON.parse(content);
if (core.isset(obj)) {
if (core.isset(core.platform.successCallback))
if (obj) {
if (core.platform.successCallback)
core.platform.successCallback(obj);
return;
}
@ -717,16 +771,16 @@ utils.prototype.readFileContent = function (content) {
main.log(e);
alert(e);
}
alert("不是有效的JSON文件");
// alert("不是有效的JSON文件");
if (core.isset(core.platform.errorCallback))
if (core.platform.errorCallback)
core.platform.errorCallback();
}
////// 下载文件到本地 //////
utils.prototype.download = function (filename, content) {
if (core.isset(window.jsinterface)) {
if (window.jsinterface) {
window.jsinterface.download(filename, content);
return;
}
@ -791,8 +845,8 @@ utils.prototype.download = function (filename, content) {
////// 复制一段内容到剪切板 //////
utils.prototype.copy = function (data) {
if (core.isset(window.jsinterface)) {
window.jsinterface.copy(filename, content);
if (window.jsinterface) {
window.jsinterface.copy(data);
return true;
}
@ -824,12 +878,36 @@ utils.prototype.copy = function (data) {
return successful;
}
////// 显示一段confirm //////
utils.prototype.myconfirm = function (hint, yesCallback, noCallback) {
main.dom.inputDiv.style.display = 'block';
main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '<br/>');
main.dom.inputBox.style.display = 'none';
main.dom.inputYes.focus();
core.platform.successCallback = yesCallback;
core.platform.errorCallback = noCallback;
}
////// 让用户输入一段文字 //////
utils.prototype.myprompt = function (hint, value, callback) {
main.dom.inputDiv.style.display = 'block';
main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '<br/>');
main.dom.inputBox.style.display = 'block';
main.dom.inputBox.value = value==null?"":value;
setTimeout(function () {
main.dom.inputBox.focus();
});
core.platform.successCallback = core.platform.errorCallback = callback;
}
////// 动画显示某对象 //////
utils.prototype.show = function (obj, speed, callback) {
utils.prototype.showWithAnimate = function (obj, speed, callback) {
obj.style.display = 'block';
if (!core.isset(speed) && main.mode!='play') {
if (!speed && main.mode != 'play') {
obj.style.opacity = 1;
if (core.isset(callback)) callback();
if (callback) callback();
return;
}
obj.style.opacity = 0;
@ -839,18 +917,16 @@ utils.prototype.show = function (obj, speed, callback) {
obj.style.opacity = opacityVal;
if (opacityVal > 1) {
clearInterval(showAnimate);
if (core.isset(callback)) {
callback();
}
if (callback) callback();
}
}, speed);
}
////// 动画使某对象消失 //////
utils.prototype.hide = function (obj, speed, callback) {
if (!core.isset(speed) || main.mode!='play'){
utils.prototype.hideWithAnimate = function (obj, speed, callback) {
if (!speed || main.mode != 'play') {
obj.style.display = 'none';
if (core.isset(callback)) callback();
if (callback) callback();
return;
}
obj.style.opacity = 1;
@ -861,14 +937,12 @@ utils.prototype.hide = function (obj, speed, callback) {
if (opacityVal < 0) {
obj.style.display = 'none';
clearInterval(hideAnimate);
if (core.isset(callback)) {
callback();
}
if (callback) callback();
}
}, speed);
}
utils.prototype.encodeCanvas = function (ctx) {
utils.prototype._encodeCanvas = function (ctx) {
var list = [];
var width = ctx.canvas.width, height = ctx.canvas.height;
ctx.mozImageSmoothingEnabled = false;
@ -895,14 +969,14 @@ utils.prototype.encodeCanvas = function (ctx) {
}
////// 解析arr数组并绘制到tempCanvas上 //////
utils.prototype.decodeCanvas = function (arr, width, height) {
utils.prototype._decodeCanvas = function (arr, width, height) {
// 清空tempCanvas
var tempCanvas = core.bigmap.tempCanvas;
tempCanvas.canvas.width = width;
tempCanvas.canvas.height = height;
tempCanvas.clearRect(0, 0, width, height);
if (!core.isset(arr)) return null;
if (!arr) return null;
// to byte array
var curr = 0, list = [];
arr.forEach(function (x) {
@ -946,8 +1020,8 @@ utils.prototype.hashCode = function (obj) {
}
utils.prototype.same = function (a, b) {
if (!core.isset(a) && !core.isset(b)) return true;
if (!core.isset(a) || !core.isset(b)) return false;
if (a == null && b == null) return true;
if (a == null || b == null) return false;
if (a === b) return true;
if (a instanceof Array && b instanceof Array) {
if (a.length != b.length) return false;
@ -969,21 +1043,21 @@ utils.prototype.same = function (a, b) {
}
utils.prototype._export = function (floorIds) {
if (!core.isset(floorIds)) floorIds = [core.status.floorId];
if (!floorIds) floorIds = [core.status.floorId];
else if (floorIds == 'all') floorIds = core.clone(core.floorIds);
else if (typeof floorIds == 'string') floorIds = [floorIds];
var monsterMap = {};
// map
var content = floorIds.length+"\n13 13\n\n";
var content = floorIds.length + "\n" + core.__SIZE__ + " " + core.__SIZE__ + "\n\n";
floorIds.forEach(function (floorId) {
var arr = core.maps.getMapArray(core.status.maps[floorId].blocks, 13, 13);
var arr = core.maps._getMapArrayFromBlocks(core.status.maps[floorId].blocks);
content += arr.map(function (x) {
// check monster
x.forEach(function (t) {
var block = core.maps.initBlock(null, null, t);
if (core.isset(block.event) && block.event.cls.indexOf("enemy")==0) {
if (block.event.cls.indexOf("enemy") == 0) {
monsterMap[t] = block.event.id;
}
})
@ -993,7 +1067,9 @@ utils.prototype._export = function (floorIds) {
// values
content += ["redJewel", "blueJewel", "greenJewel", "redPotion", "bluePotion",
"yellowPotion", "greenPotion", "sword1", "shield1"].map(function (x) {return core.values[x]}).join(" ") + "\n\n";
"yellowPotion", "greenPotion", "sword1", "shield1"].map(function (x) {
return core.values[x]
}).join(" ") + "\n\n";
// monster
content += Object.keys(monsterMap).length + "\n";
@ -1014,34 +1090,26 @@ utils.prototype._export = function (floorIds) {
utils.prototype.http = function (type, url, formData, success, error, mimeType, responseType) {
var xhr = new XMLHttpRequest();
xhr.open(type, url, true);
if (core.isset(mimeType))
xhr.overrideMimeType(mimeType);
if (core.isset(responseType))
xhr.responseType = responseType;
if (mimeType) xhr.overrideMimeType(mimeType);
if (responseType) xhr.responseType = responseType;
xhr.onload = function (e) {
if (xhr.status == 200) {
if (core.isset(success)) {
success(xhr.response);
}
if (success) success(xhr.response);
}
else {
if (core.isset(error))
error("HTTP "+xhr.status);
if (error) error("HTTP " + xhr.status);
}
};
xhr.onabort = function () {
if (core.isset(error))
error("Abort");
if (error) error("Abort");
}
xhr.ontimeout = function () {
if (core.isset(error))
error("Timeout");
if (error) error("Timeout");
}
xhr.onerror = function () {
if (core.isset(error))
error("Error on Connection");
if (error) error("Error on Connection");
}
if (core.isset(formData))
if (formData)
xhr.send(formData);
else xhr.send();
}

62
main.js
View File

@ -2,7 +2,7 @@ function main() {
//------------------------ 用户修改内容 ------------------------//
this.version = "2.5.5"; // 游戏版本号如果更改了游戏内容建议修改此version以免造成缓存问题。
this.version = "2.6"; // 游戏版本号如果更改了游戏内容建议修改此version以免造成缓存问题。
this.useCompress = false; // 是否使用压缩文件
// 当你即将发布你的塔时请使用“JS代码压缩工具”将所有js代码进行压缩然后将这里的useCompress改为true。
@ -69,13 +69,19 @@ function main() {
'skillCol': document.getElementById('skillCol'),
'hard': document.getElementById('hard'),
'statusCanvas': document.getElementById('statusCanvas'),
'statusCanvasCtx': document.getElementById('statusCanvas').getContext('2d'),
'inputDiv': document.getElementById('inputDiv'),
'inputMessage': document.getElementById('inputMessage'),
'inputBox': document.getElementById('inputBox'),
'inputYes': document.getElementById('inputYes'),
'inputNo': document.getElementById('inputNo')
};
this.mode = 'play';
this.loadList = [
'loader', 'control', 'utils', 'items', 'icons', 'maps', 'enemys', 'events', 'actions', 'data', 'ui', 'core'
];
this.pureData = [
'data', 'enemys', 'icons', 'maps', 'items', 'functions', 'events'
'data', 'enemys', 'icons', 'maps', 'items', 'functions', 'events', 'plugins'
];
this.materials = [
'animates', 'enemys', 'hero', 'items', 'npcs', 'terrains', 'enemy48', 'npc48'
@ -182,18 +188,15 @@ function main() {
this.floors = {}
this.canvas = {};
this.__VERSION__ = "2.5.5";
this.__VERSION_CODE__ = 25;
this.__VERSION__ = "2.6";
this.__VERSION_CODE__ = 30;
}
main.prototype.init = function (mode, callback) {
for (var i = 0; i < main.dom.gameCanvas.length; i++) {
main.canvas[main.dom.gameCanvas[i].id] = main.dom.gameCanvas[i].getContext('2d');
}
if (({"editor":0}).hasOwnProperty(mode)) {
main.mode = mode;
if (mode === 'editor')main.editor = {'disableGlobalAnimate':true};
}
main.loadJs('project', main.pureData, function(){
var mainData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main;
@ -219,7 +222,7 @@ main.prototype.init = function (mode, callback) {
for (i = 0; i < main.loadList.length; i++) {
var name = main.loadList[i];
if (name === 'core') continue;
main.core[name] = new (eval(name))();
main.core[name] = new window[name]();
}
main.loadFloors(function() {
@ -229,7 +232,7 @@ main.prototype.init = function (mode, callback) {
coreData[t] = main[t];
})
main.core.init(coreData, callback);
main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight);
main.core.resize();
});
});
});
@ -330,13 +333,14 @@ main.prototype.listen = function () {
////// 窗口大小变化时 //////
window.onresize = function () {
try {
main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight);
main.core.resize();
}catch (e) { main.log(e); }
}
////// 在界面上按下某按键时 //////
main.dom.body.onkeydown = function(e) {
try {
if (main.dom.inputDiv.style.display == 'block') return;
if (main.core && (main.core.isPlaying() || main.core.status.lockControl))
main.core.onkeyDown(e);
} catch (ee) { main.log(ee); }
@ -345,6 +349,7 @@ main.dom.body.onkeydown = function(e) {
////// 在界面上放开某按键时 //////
main.dom.body.onkeyup = function(e) {
try {
if (main.dom.inputDiv.style.display == 'block') return;
if (main.core && (main.core.isPlaying() || main.core.status.lockControl))
main.core.onkeyUp(e);
} catch (ee) { main.log(ee); }
@ -359,7 +364,7 @@ main.dom.body.onselectstart = function () {
main.dom.data.onmousedown = function (e) {
try {
e.stopPropagation();
var loc = main.core.getClickLoc(e.clientX, e.clientY);
var loc = main.core.actions._getClickLoc(e.clientX, e.clientY);
if (loc == null) return;
main.core.ondown(loc);
} catch (ee) { main.log(ee); }
@ -369,7 +374,7 @@ main.dom.data.onmousedown = function (e) {
main.dom.data.onmousemove = function (e) {
try {
e.stopPropagation();
var loc = main.core.getClickLoc(e.clientX, e.clientY);
var loc = main.core.actions._getClickLoc(e.clientX, e.clientY);
if (loc == null) return;
main.core.onmove(loc);
}catch (ee) { main.log(ee); }
@ -396,7 +401,7 @@ main.dom.data.onmousewheel = function(e) {
main.dom.data.ontouchstart = function (e) {
try {
e.preventDefault();
var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
var loc = main.core.actions._getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
if (loc == null) return;
main.core.ondown(loc);
}catch (ee) { main.log(ee); }
@ -406,7 +411,7 @@ main.dom.data.ontouchstart = function (e) {
main.dom.data.ontouchmove = function (e) {
try {
e.preventDefault();
var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
var loc = main.core.actions._getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY);
if (loc == null) return;
main.core.onmove(loc);
}catch (ee) { main.log(ee); }
@ -670,7 +675,34 @@ window.onblur = function () {
if (main.core && main.core.control) {
try {
main.core.control.checkAutosave();
} catch (e) {main.log(e);}
} catch (e) {}
}
}
main.dom.inputYes.onclick = function () {
main.dom.inputDiv.style.display = 'none';
var func = core.platform.successCallback;
core.platform.successCallback = core.platform.errorCallback = null;
if (func) func(main.dom.inputBox.value);
}
main.dom.inputNo.onclick = function () {
main.dom.inputDiv.style.display = 'none';
var func = core.platform.errorCallback;
core.platform.successCallback = core.platform.errorCallback = null;
if (func) func(null);
}
main.dom.inputDiv.onkeyup = function (e) {
if (e.keyCode == 13) {
setTimeout(function () {
main.dom.inputYes.click();
}, 50);
}
else if (e.keyCode == 27) {
setTimeout(function () {
main.dom.inputNo.click();
}, 50);
}
}

View File

@ -71,13 +71,14 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"firstData": {
"title": "魔塔样板",
"name": "template",
"version": "Ver 2.5.5",
"version": "Ver 2.6",
"floorId": "sample0",
"hero": {
"name": "阳光",
"lv": 1,
"hpmax": 9999,
"hp": 1000,
"manamax": -1,
"mana": 0,
"atk": 100,
"def": 100,
@ -95,7 +96,6 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"tools": {},
"equips": {}
},
"flyRange": [],
"loc": {
"direction": "up",
"x": 6,
@ -250,6 +250,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"name": "贪婪之神",
"icon": "blueShop",
"textInList": "1F金币商店",
"commonTimes": false,
"mustEnable": false,
"use": "money",
"need": "20+10*times*(times+1)",
"text": "勇敢的武士啊,给我${need}金币就可以:",
@ -277,6 +279,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"name": "经验之神",
"icon": "pinkShop",
"textInList": "1F经验商店",
"commonTimes": false,
"mustEnable": false,
"use": "experience",
"need": "-1",
"text": "勇敢的武士啊,给我若干经验就可以:",
@ -297,6 +301,12 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"effect": "status:def+=5"
}
]
},
{
"id": "keyShop1",
"textInList": "回收钥匙商店",
"mustEnable": false,
"commonEvent": "回收钥匙商店"
}
],
"levelUp": [
@ -393,7 +403,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d =
"displayExtraDamage": true,
"enableGentleClick": true,
"potionWhileRouting": false,
"portalWithoutTrigger": true,
"ignoreChangeFloor": true,
"canGoDeadZone": false,
"enableMoveDirectly": true,
"enableDisabledShop": true,

View File

@ -4,60 +4,55 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"加点事件": [
{
"type": "comment",
"text": "flag:point表示当前应该的加点数值"
"text": "通过传参flag:arg1表示当前应该的加点数值"
},
{
"type": "choices",
"choices": [
{
"text": "攻击+${1*flag:point}",
"text": "攻击+${1*flag:arg1}",
"action": [
{
"type": "setValue",
"name": "status:atk",
"value": "status:atk+1*flag:point"
"value": "status:atk+1*flag:arg1"
}
]
},
{
"text": "防御+${2*flag:point}",
"text": "防御+${2*flag:arg1}",
"action": [
{
"type": "setValue",
"name": "status:def",
"value": "status:def+2*flag:point"
"value": "status:def+2*flag:arg1"
}
]
},
{
"text": "生命+${200*flag:point}",
"text": "生命+${200*flag:arg1}",
"action": [
{
"type": "setValue",
"name": "status:hp",
"value": "status:hp+200*flag:point"
"value": "status:hp+200*flag:arg1"
}
]
}
]
},
{
"type": "setValue",
"name": "flag:point",
"value": "null"
}
],
"毒衰咒处理": [
{
"type": "comment",
"text": "获得毒衰咒效果flag:debuff为要获得的类型"
"text": "获得毒衰咒效果flag:arg1为要获得的类型"
},
{
"type": "switch",
"condition": "flag:debuff",
"condition": "flag:arg1",
"caseList": [
{
"case": "'poison'",
"case": "0",
"action": [
{
"type": "comment",
@ -78,7 +73,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
]
},
{
"case": "'weak'",
"case": "1",
"action": [
{
"type": "comment",
@ -102,12 +97,12 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"text": ">=1直接扣数值"
},
{
"type": "setValue2",
"type": "addValue",
"name": "status:atk",
"value": "-core.values.weakValue"
},
{
"type": "setValue2",
"type": "addValue",
"name": "status:def",
"value": "-core.values.weakValue"
}
@ -118,14 +113,12 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
"text": "<1扣比例"
},
{
"type": "setValue2",
"name": "flag:__atk_buff__",
"value": "-core.values.weakValue"
"type": "function",
"function": "function(){\ncore.addBuff('atk', -core.values.weakValue);\n}"
},
{
"type": "setValue2",
"name": "flag:__def_buff__",
"value": "-core.values.weakValue"
"type": "function",
"function": "function(){\ncore.addBuff('def', -core.values.weakValue);\n}"
}
]
}
@ -135,7 +128,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
]
},
{
"case": "'curse'",
"case": "2",
"action": [
{
"type": "comment",
@ -156,11 +149,187 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 =
]
}
]
}
],
"滑冰事件": [
{
"type": "comment",
"text": "公共事件:滑冰事件"
},
{
"type": "if",
"condition": "core.canMoveHero()",
"true": [
{
"type": "comment",
"text": "检测下一个点是否可通行"
},
{
"type": "setValue",
"name": "flag:debuff",
"value": "null"
"name": "flag:nx",
"value": "core.nextX()"
},
{
"type": "setValue",
"name": "flag:ny",
"value": "core.nextY()"
},
{
"type": "if",
"condition": "core.noPass(flag:nx, flag:ny)",
"true": [
{
"type": "comment",
"text": "不可通行,触发下一个点的事件"
},
{
"type": "trigger",
"loc": [
"flag:nx",
"flag:ny"
]
}
],
"false": [
{
"type": "comment",
"text": "可通行,先移动到下个点,然后检查阻激夹域,并尝试触发该点事件"
},
{
"type": "moveHero",
"time": 80,
"steps": [
"forward"
]
},
{
"type": "function",
"function": "function(){\ncore.checkBlock();\n}"
},
{
"type": "comment",
"text": "【触发事件】如果该点存在事件则会立刻结束当前事件"
},
{
"type": "trigger",
"loc": [
"flag:nx",
"flag:ny"
]
},
{
"type": "comment",
"text": "如果该点不存在事件,则继续检测该点是否是滑冰点"
},
{
"type": "if",
"condition": "core.getBgNumber() == 167",
"true": [
{
"type": "function",
"function": "function(){\ncore.insertAction(\"滑冰事件\",null,null,null,true)\n}"
}
],
"false": []
}
]
}
],
"false": []
}
],
"回收钥匙商店": [
{
"type": "comment",
"text": "此事件在全局商店中被引用了(全局商店keyShop1)"
},
{
"type": "comment",
"text": "解除引用前勿删除此事件"
},
{
"type": "comment",
"text": "玩家在快捷列表V键中可以使用本公共事件"
},
{
"type": "while",
"condition": "1",
"data": [
{
"type": "choices",
"text": "\t[商人,woman]你有多余的钥匙想要出售吗?",
"choices": [
{
"text": "黄钥匙10金币",
"color": [
255,
255,
0,
1
],
"action": [
{
"type": "if",
"condition": "item:yellowKey >= 1",
"true": [
{
"type": "addValue",
"name": "item:yellowKey",
"value": "-1"
},
{
"type": "addValue",
"name": "status:money",
"value": "10"
}
],
"false": [
"\t[商人,woman]你没有黄钥匙!"
]
}
]
},
{
"text": "蓝钥匙50金币",
"color": [
0,
0,
255,
1
],
"action": [
{
"type": "if",
"condition": "item:blueKey >= 1",
"true": [
{
"type": "addValue",
"name": "item:blueKey",
"value": "-1"
},
{
"type": "addValue",
"name": "status:money",
"value": "50"
}
],
"false": [
"\t[商人,woman]你没有蓝钥匙!"
]
}
]
},
{
"text": "离开",
"action": [
{
"type": "exit"
}
]
}
]
}
]
}
]
}

View File

@ -151,7 +151,7 @@ main.floors.sample1=
"type": "hide"
},
{
"type": "setFg",
"type": "setCurtain",
"color": [
0,
0,
@ -184,7 +184,7 @@ main.floors.sample1=
"2,11": [
"\t[杰克,thief]喂!醒醒!快醒醒!",
{
"type": "setFg",
"type": "setCurtain",
"time": 1500
},
"\t[hero]额,我这是在什么地方?",
@ -205,10 +205,8 @@ main.floors.sample1=
"type": "move",
"time": 750,
"steps": [
{
"direction": "right",
"value": 2
},
"right",
"right",
"down"
]
},
@ -606,7 +604,6 @@ main.floors.sample1=
"choices": [
{
"text": "黄钥匙(${9+flag:woman_times}金币)",
"color": [255,255,0,1],
"action": [
{
"type": "if",
@ -634,7 +631,6 @@ main.floors.sample1=
},
{
"text": "蓝钥匙(${18+2*flag:woman_times}金币)",
"color": [0,0,255,1],
"action": [
{
"type": "if",
@ -662,7 +658,6 @@ main.floors.sample1=
},
{
"text": "红钥匙(${36+4*flag:woman_times}金币)",
"color": [255,0,0,1],
"action": [
{
"type": "if",
@ -769,8 +764,7 @@ main.floors.sample1=
],
"false": []
}
],
"10,12": null
]
},
"afterGetItem": {},
"afterOpenDoor": {},
@ -780,5 +774,5 @@ main.floors.sample1=
],
"fgmap": [
]
],
}

File diff suppressed because it is too large Load Diff

View File

@ -259,7 +259,7 @@ var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 =
"hammer": 48,
"jumpShoes": 49,
"skill1": 30,
"I73": 10
"wand": 10
},
"autotile": {
"autotile": 0,

View File

@ -303,7 +303,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"text": "可以打开或关闭主动技能二倍斩",
"hideInReplay": true
},
"I73": {
"wand": {
"cls": "items",
"name": "新物品"
}
@ -360,7 +360,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
},
"useItemEffect": {
"book": "core.ui.drawBook(0);",
"fly": "core.ui.drawFly(core.status.hero.flyRange.indexOf(core.status.floorId));",
"fly": "core.ui.drawFly(core.floorIds.indexOf(core.status.floorId));",
"earthquake": "core.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});",
"pickaxe": "core.playSound('pickaxe.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});",
"icePickaxe": "core.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});",
@ -372,9 +372,9 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
"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.addFlag(\"__atk_buff__\", core.values.weakValue);\n\tcore.addFlag(\"__def_buff__\", 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.addBuff(\"atk\", core.values.weakValue);\n\tcore.addBuff(\"def\", 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.addFlag(\"__atk_buff__\", core.values.weakValue);\n\t\tcore.addFlag(\"__def_buff__\", 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.addBuff(\"atk\", core.values.weakValue);\n\t\tcore.addBuff(\"def\", 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",
@ -389,17 +389,17 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a =
},
"canUseItemEffect": {
"book": "true",
"fly": "(function () {\n\treturn core.status.hero.flyRange.indexOf(core.status.floorId)>=0 && (core.status.maps[core.status.floorId]||{}).canFlyTo;\n})();",
"pickaxe": "(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 && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.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})();",
"icePickaxe": "(function() {\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.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.ui = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();",
"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})();",
"fly": "(function () {\n\treturn core.status.maps[core.status.floorId].canFlyTo;\n})();",
"pickaxe": "(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 (!block.disable && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.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})();",
"icePickaxe": "(function() {\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.ui = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();",
"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 (!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 (!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 (!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-1-core.getHeroLoc('x'), toY = core.bigmap.height-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<core.floorIds.length-1) {\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<mw && toY>=0 && toY<mh && core.getBlock(toX, toY, toId)==null) {\n\t\t\tcore.status.event.ui = {'id': toId, 'x': toX, 'y': toY};\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();",
"downFly": "(function() {\n\tvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\n\tif (index>0) {\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<mw && toY>=0 && toY<mh && core.getBlock(toX, toY, toId)==null) {\n\t\t\tcore.status.event.ui = {'id': toId, 'x': toX, 'y': toY};\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();",
"snow": "(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.id == 'lava' && core.nearHero(block.x, block.y)) {\n\t\t\tif (core.flags.snowFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.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})();",
"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})();",
"snow": "(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 (!block.disable && block.event.id == 'lava' && core.nearHero(block.x, block.y)) {\n\t\t\tif (core.flags.snowFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.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})();",
"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 (!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');",
"weakWine": "core.hasFlag('weak');",
"curseWine": "core.hasFlag('curse');",

View File

@ -67,7 +67,7 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e =
"70": {"cls":"items","id":"sword0"},
"71": {"cls":"items","id":"shield0"},
"72": {"cls":"items","id":"skill1"},
"73": {"cls":"items","id":"I73"},
"73": {"cls":"items","id":"wand"},
"81": {"cls":"terrains","id":"yellowDoor","trigger":"openDoor"},
"82": {"cls":"terrains","id":"blueDoor","trigger":"openDoor"},
"83": {"cls":"terrains","id":"redDoor","trigger":"openDoor"},

88
project/plugins.js Normal file
View File

@ -0,0 +1,88 @@
var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
{
"init": function () {
console.log("插件编写测试");
// 可以写一些直接执行的代码
// 在这里写的代码将会在【资源加载前】被执行,此时图片等资源尚未被加载。
// 请勿在这里对包括bgm图片等资源进行操作。
this._afterLoadResources = function () {
// 本函数将在所有资源加载完毕后,游戏开启前被执行
// 可以在这个函数里面对资源进行一些操作,比如切分图片等。
// 这是一个将assets.png拆分成若干个32x32像素的小图片并保存的样例。
// var arr = core.splitImage("assets.png", 32, 32);
// for (var i = 0; i < arr.length; i++) {
// core.material.images.images["asset"+i+".png"] = arr[i];
// }
}
// 可以在任何地方如afterXXX或自定义脚本事件调用函数方法为 core.plugin.xxx();
// 从V2.6开始插件中用this.XXX方式定义的函数也会被转发到core中详见文档-脚本-函数的转发。
},
"drawLight": function () {
// 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...)
// 【参数说明】
// name必填要绘制到的画布名可以是一个系统画布或者是个自定义画布如果不存在则创建
// color可选只能是一个0~1之间的数为不透明度的值。不填则默认为0.9。
// lights可选一个数组定义了每个独立的灯光。
// 其中每一项是三元组 [x,y,r] x和y分别为该灯光的横纵坐标r为该灯光的半径。
// lightDec可选0到1之间光从多少百分比才开始衰减在此范围内保持全亮不设置默认为0。
// 比如lightDec为0.5代表每个灯光部分内圈50%的范围全亮50%以后才开始快速衰减。
// 【调用样例】
// core.plugin.drawLight('curtain'); // 在curtain层绘制全图不透明度0.9,等价于更改画面色调为[0,0,0,0.9]。
// core.plugin.drawLight('ui', 0.95, [[25,11,46]]); // 在ui层绘制全图不透明度0.95,其中在(25,11)点存在一个半径为46的灯光效果。
// core.plugin.drawLight('test', 0.2, [[25,11,46,0.1]]); // 创建一个test图层不透明度0.2,其中在(25,11)点存在一个半径为46的灯光效果灯光中心不透明度0.1。
// core.plugin.drawLight('test2', 0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 创建test2图层且存在三个灯光效果分别是中心(25,11)半径46中心(105,121)半径88中心(301,221)半径106。
// core.plugin.drawLight('xxx', 0.3, [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果它们在内圈40%范围内保持全亮且40%后才开始衰减。
this.drawLight = function (name, color, lights, lightDec) {
// 清空色调层也可以修改成其它层比如animate/weather层或者用自己创建的canvas
var ctx = core.getContextByName(name);
if (ctx == null) {
if (typeof name == 'string')
ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 98);
else return;
}
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
core.clearMap(name);
// 绘制色调层,默认不透明度
if (color == null) color = 0.9;
ctx.fillStyle = "rgba(0,0,0," + color + ")";
ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);
lightDec = core.clamp(lightDec, 0, 1);
// 绘制每个灯光效果
ctx.globalCompositeOperation = 'destination-out';
lights.forEach(function (light) {
// 坐标,半径,中心不透明度
var x = light[0],
y = light[1],
r = light[2];
// 计算衰减距离
var decDistance = parseInt(r * lightDec);
// 正方形区域的直径和左上角坐标
var grd = ctx.createRadialGradient(x, y, decDistance, x, y, r);
grd.addColorStop(0, "rgba(0,0,0,1)");
grd.addColorStop(1, "rgba(0,0,0,0)");
ctx.beginPath();
ctx.fillStyle = grd;
ctx.arc(x, y, r, 0, 2 * Math.PI);
ctx.fill();
});
ctx.globalCompositeOperation = 'source-over';
// 可以在任何地方如afterXXX或自定义脚本事件调用函数方法为 core.plugin.xxx();
}
}
}

View File

@ -79,6 +79,15 @@
z-index: 15;
}
#startTopHint {
color: #66CCFF;
position: absolute;
bottom: 0;
left: 5%;
z-index: 15;
font-size: 18px;
}
#startBackground {
position:absolute;
top:50%;
@ -142,10 +151,8 @@
}
#floorMsgGroup {
/* width: 100%;
height: 100%; */
/* top: 0;
right: 0; */
top: 3px;
right: 3px;
position: absolute;
text-align: center;
display: none;
@ -181,11 +188,15 @@
background: url(project/images/ground.png) repeat;
z-index: 185;
display: none;
top: 0;
left: 0;
padding: 3px;
}
#statusBar .status{
position: relative;
display: block;
float: left;
width: 100%;
}
.status img{
vertical-align: middle;
@ -194,7 +205,6 @@
max-height: 1.6em;
}
#statusBar span{
color: white;
font: bold italic 1.1em Verdana;
}
#statusBar p {
@ -214,6 +224,8 @@
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
display: none;
left: 0;
padding: 3px;
}
#toolBar .tools{
position: relative;
@ -300,17 +312,57 @@ p#name {
}
#ui {
z-index: 160;
z-index: 140;
}
#data {
z-index: 170;
}
.clearfix:before,
.clearfix:after {
content: ".";
display: block;
height: 0;
visibility: hidden;
#inputDiv {
display: none;
width: 100%;
height: 100%;
position: fixed;
top: 0;
left: 0;
background: rgba(127,127,127,0.6);
z-index: 2000
}
#inputDialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -60%);
background: white;
width: 250px;
min-height: 50px;
max-height: 250px;
}
#inputMessage {
word-wrap: break-word;
text-align: left;
margin-left: 8%;
margin-right: 5%;
}
#inputBox {
margin-left: 8%;
width: 80%;
margin-bottom: 10px;
padding: 5px 3px;
border: 1px solid;
background: #F0F0F0;
}
#inputYes {
margin-bottom: 15px;
margin-left: 8%;
}
#inputNo {
float:right;
margin-right: 10%;
}