diff --git a/API列表.txt b/API列表.txt
new file mode 100644
index 00000000..2f846828
--- /dev/null
+++ b/API列表.txt
@@ -0,0 +1,2185 @@
+# 附录:API列表
+
+?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} *
+
+这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。
+
+本附录量较大,如有什么需求请自行Ctrl+F进行搜索。
+
+如有任何疑问,请联系小艾寻求帮助。
+
+## core.js
+
+core.js中只有很少的几个函数,主要是游戏开始前的初始化等。
+
+但是,core中定义了很多游戏运行时的状态,这些状态很多都会被使用到。
+
+``` text
+core.__SIZE__, core.__PIXELS__
+游戏窗口大小;对于13x13的游戏而言这两个值分别是13和416,15x15来说分别是15和480。
+
+
+core.material
+游戏中的所有资源列表,具体分为如下内容:
+core.material.animates (动画)
+core.material.bgms (背景音乐)
+core.material.enemys (怪物信息,来自于 project/enemys.js)
+core.material.icons (图标信息,来自于 project/icons.js)
+core.material.images (图片素材,存放了各项素材图片如items.png等)
+ core.material.images.autotile (所有的自动元件图片)
+ core.material.images.tilesets (所有的额外素材图片)
+ core.material.images.images (用户引入的其他图片)
+core.material.items (道具信息)
+core.material.sounds (音效)
+
+
+core.animateFrame
+主要是记录和requestAnimationFrame相关的一些数据,常用的如下:
+core.animateFrame.totalTime (游戏总的运行时时间)
+core.animateFrame.weather (当前的天气信息)
+core.animateFrame.asyncId (当前的异步处理事件的内容)
+
+
+core.musicStatus
+主要是记录和音效相关的内容,常用的如下:
+core.musicStatus.bgmStatus (音乐开启状态)
+core.musicStatus.soundStatus (音效开启状态)
+core.musicStatus.playingBgm (当前正在播放的BGM)
+core.musicStatus.lastBgm (最近一次尝试播放的BGM)
+core.musicStatus.volume (当前的音量)
+core.musicStatus.cachedBgms (背景音乐的缓存内容)
+core.musicStatus.cacheBgmCount (背景音乐的缓存数量,默认值是4)
+
+
+core.platform
+游戏平台相关信息,常见的几个如下:
+core.platform.isPC (是否是电脑端)
+core.platform.isAndroid (是否是安卓端)
+core.platform.isIOS (是否是iOS端)
+core.platform.useLocalForage (是否开启了新版存档)
+
+
+core.domStyle
+游戏的界面信息,包含如下几个:
+core.domStyle.scale (当前的放缩比)
+core.domStyle.isVertical (当前是否是竖屏状态)
+core.domStyle.showStatusBar (当前是否显示状态栏)
+core.domStyle.toolbarBtn (当前是否显示工具栏)
+
+
+core.bigmap
+当前的地图的尺寸信息,主要包含如下几个
+core.bigmap.width (当前地图的宽度)
+core.bigmap.height (当前地图的高度)
+core.bigmap.offsetX (当前地图针对窗口左上角的偏移像素x)
+core.bigmap.offsetX (当前地图针对窗口左上角的偏移像素y)
+core.bigmap.tempCanvas (一个临时画布,可以用来临时绘制很多东西)
+
+
+core.saves
+和存档相关的信息,包含如下几个:
+core.saves.saveIndex (上次保存或读取的存档编号)
+core.saves.ids (当前存在存档的编号列表)
+core.saves.autosave (自动存档的信息)
+core.saves.favorite (收藏的存档)
+core.saves.favoriteNames (自定义存档的名称)
+
+
+core.status
+游戏的状态相关,是整个游戏中最重要的东西,其核心是如下几条:
+请注意,每次重新开始、存档或读档时,core.status都会重新初始化。
+core.status.played (当前是否在游戏中)
+core.status.gameOver (当前是否已经游戏结束,即win或lose)
+core.status.hero (勇士信息;此项和全塔属性中的hero大体是对应的)
+ core.status.hero.name 勇士名
+ core.status.hero.lv 当前等级
+ core.status.hero.hpmax 当前生命上限
+ core.status.hero.hp 当前生命值
+ core.status.hero.manamax 当前魔力上限
+ core.status.hero.mana 当前魔力值
+ core.status.hero.atk 当前攻击力
+ core.status.hero.def 当前防御力
+ core.status.hero.mdef 当前魔防值
+ core.status.hero.money 当前金币值
+ core.status.hero.experience 当前经验值
+ core.status.hero.loc 当前的位置信息
+ core.status.hero.equipment 当前装上的装备
+ core.status.hero.items 当前拥有的道具信息
+ core.status.hero.flags 当前的各项flag信息
+ core.status.hero.step 当前的步数值
+ core.status.hero.statistics 当前的统计信息
+core.status.floorId (当前所在的楼层)
+core.status.maps (所有的地图信息)
+core.status.thisMap (当前的地图信息,等价于core.status.maps[core.status.floorId])
+core.status.bgmaps (所有背景层的信息)
+core.status.fgmaps (所有的前景层的信息)
+core.status.checkBlock (地图上的阻激夹域信息,也作为光环的缓存)
+core.status.lockControl (当前是否是控制锁定状态)
+core.status.automaticRoute (当前的自动寻路信息)
+core.status.route (当前记录的录像)
+core.status.replay (录像回放时要用到的信息)
+core.status.shops (所有全局商店信息)
+core.status.textAttribute (当前的文字属性,如颜色、背景等信息,和setText事件对应)
+core.status.globalAttribute (当前的全局属性,如边框色、装备栏等)
+core.status.curtainColor (当前色调层的颜色)
+core.status.globalAnimateObjs (当前的全局帧动画效果)
+core.status.floorAnimateObjs (当前的楼层贴图帧动画效果)
+core.status.boxAnimateObjs (当前的盒子帧动画效果,例如怪物手册中的怪物)
+core.status.autotileAnimateObjs (当前楼层的自动元件动画效果)
+core.status.globalAnimateStatus (当前的帧动画的状态)
+core.status.animateObjs (当前的播放动画信息)
+
+
+core.floorIds
+一个数组,表示所有的楼层ID,和全塔属性中的floorIds一致。
+
+
+core.floors
+从楼层文件中读取全部的地图数据。
+和core.status.maps不同的是,后者在每次重新开始和读档时都会重置,也允许被修改(会存入存档)。
+而core.floors全程唯一,不允许被修改。
+
+
+core.statusBar
+状态栏信息,例如状态栏图片,图标,以及各个内容的DOM定义等。
+core.statusBar.images (所有的系统图标,和icons.png对应)
+core.statusBar.icons (状态栏中绘制的图标内容)
+
+
+core.values
+所有的全局数值信息,和全塔属性中的values一致。
+此项允许被直接修改,会存入存档。
+
+
+core.flags
+所有的全塔开关,和全塔属性中的flags一致。
+此项不允许被直接修改,如有需要请使用“设置系统开关”事件,或者调用core.setGlobalFlag这个API。
+
+
+core.plugin
+定义的插件函数。
+
+
+core.doFunc(func, _this)
+执行一个函数,func为函数体或者插件中的函数名,_this为使用的this。
+如果func为一个字符串,则视为插件中的函数名,同时_this将被设置成core.plugin。
+此函数剩余参数将作为参数被传入func。
+```
+
+## actions.js
+
+actions.js主要是处理一些和用户交互相关的内容。
+
+```text
+core.registerAction(action, name, func, priority)
+注册一个用户交互行为。
+action:要注册的交互类型,如 ondown, onclick, keyDown 等等。
+name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。
+func:执行函数;可以是一个具体的函数体,或者是一个插件中的函数名。
+priority:优先级;优先级高的被注册项将会被执行。此项可不填,默认为0。
+返回:如果func返回true,则不会再继续执行其他的交互函数;否则会继续执行其他的交互函数。
+
+
+core.unregisterAction(action, name)
+注销一个用户交互行为。
+
+
+core.doRegisteredAction(action)
+执行一个用户交互行为。
+此函数将在该交互行为所注册的所有函数中,按照优先级从高到底依次执行。
+此函数剩余的参数将会作为参数传入该执行函数中。
+当某个执行函数返回true时将终止这一过程。
+
+
+core.onkeyDown(e)
+当按下某个键时的操作,e为KeyboardEvent。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onkeyDown"的交互函数。
+
+
+core.onkeyUp(e)
+当放开某个键时的操作,e为KeyboardEvent。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onkeyUp"的交互函数。
+
+
+core.pressKey(keyCode)
+当按住某个键不动时的操作,目前只对方向键有效。
+如果需要添加对于其他键的长按,请复写_sys_onkeyDown和_sys_onkeyUp。
+请勿直接覆盖或调用此函数,如有需要请注册一个"pressKey"的交互函数。
+
+
+core.keyDown(keyCode)
+当按下某个键时的操作,参数为该键的keyCode值。
+请勿直接覆盖或调用此函数,如有需要请注册一个"keyDown"的交互函数。
+
+
+core.keyUp(keyCode, altKey, fromReplay)
+当按下某个键时的操作,参数为该键的keyCode值。
+altKey标志了Alt键是否同时被按下,fromReplay表示是否是从录像回放中调用的。
+请勿直接覆盖或调用此函数,如有需要请注册一个"keyUp"的交互函数。
+
+
+core.ondown(loc)
+当点击屏幕时的操作。loc为点击的信息。
+请勿直接覆盖或调用此函数,如有需要请注册一个"ondown"的交互函数。
+注册的ondown交互函数需要接受x, y, px, py四个参数,代表点击的位置和像素坐标。
+
+
+core.onmove(loc)
+当在屏幕上滑动时的操作。loc为当前的坐标信息。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onmove"的交互函数。
+注册的onmove交互函数需要接受x, y, px, py四个参数,代表当前的的位置和像素坐标。
+
+
+core.onup(loc)
+当从屏幕上离开时的操作。loc为当前的坐标信息。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onup"的交互函数。
+注册的onup交互函数需要接受x, y, px, py四个参数,代表当前的的位置和像素坐标。
+
+
+core.onclick(x, y)
+当点击屏幕上的某点位置时执行的操作,请注意这里的x和y是位置坐标。
+一般而言,一个完整的ondown到onup将触发一个onclick事件。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onclick"的交互函数。
+
+
+core.onmousewheel(direct)
+当滚动鼠标滑轮时执行的操作。direct为滑轮方向,上为1,下为-1。
+请勿直接覆盖或调用此函数,如有需要请注册一个"onmousewheel"的交互函数。
+
+
+core.keyDownCtrl()
+当长按Ctrl键不动时执行的操作。
+请勿直接覆盖或调用此函数,如有需要请注册一个"keyDownCtrl"的交互函数。
+
+
+core.longClick()
+当长按住屏幕时执行的操作。
+请勿直接覆盖或调用此函数,如有需要请注册一个"longClick"的交互函数。
+注册的交互函数如果某一项返回true,则之后仍然会继续触发该长按,
+如果全部返回false则将停止本次长按行为,直到手指离开屏幕并重新进行长按为止。
+```
+
+## control.js
+
+control.js将负责整个游戏的核心控制系统,分为如下几个部分:
+- requestAnimationFrame相关
+- 标题界面,开始和重新开始游戏
+- 自动寻路和人物行走相关
+- 画布、位置、阻激夹域、显伤等相关
+- 录像的回放相关
+- 存读档,自动存档,同步存档等相关
+- 人物属性和状态、位置、变量等相关
+- 天气、色调、音乐和音效的播放
+- 状态栏和工具栏相关
+- 界面resize相关
+
+```text
+// ------ requestAnimationFrame 相关 ------ //
+
+core.registerAnimationFrame(name, needPlaying, func)
+注册一个animationFrame。它将在每次浏览器的帧刷新时(约16.6ms)被执行。
+name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。
+needPlaying:如果此项为true,则仅在游戏开始后才会被执行(标题界面不执行)
+func:执行函数;可以是一个具体的函数体,或者是一个插件中的函数名。
+func可以接受一个timestamp作为参数,表示从整个页面加载完毕到当前时刻所经过的毫秒数。
+如果func执行报错,将在控制台打出一条信息,并自动进行注销。
+
+
+core.unregisterAnimationFrame(name)
+注销一个animationFrame,参数是你的上面的自定义名称。
+
+// ------ 开始界面相关 ------ //
+
+core.showStartAnimate(noAnimate, callback)
+重置所有内容并显示游戏标题界面。
+noAnimate如果为true则不会有淡入动画,callback为执行完毕的回调。
+
+
+core.hideStartAnimate(callback)
+淡出隐藏游戏标题界面,callback为执行完毕的回调。
+
+
+core.isPlaying()
+当前是否正在游戏中。
+
+
+core.clearStatus()
+清除所有的游戏状态和数据,包括状态栏的显示。
+
+// ------ 自动寻路、人物行走 ------ //
+
+core.stopAutomaticRoute()
+停止自动寻路的操作
+
+
+core.saveAndStopAutomaticRoute()
+保存剩下的寻路路线并停止自动寻路操作。主要用于打怪开门后继续寻路使用。
+
+
+core.continueAutomaticRoute()
+继续剩下的自动寻路操作。主要用于打怪开门后继续寻路使用。
+
+
+core.clearContinueAutomaticRoute()
+清空剩下的自动寻路操作。
+
+
+core.setAutomaticRoute(destX, destY, stepPostfix)
+尝试开始进行一个自动寻路。stepPostfix是鼠标拖动的路径。
+此函数将检测是否在寻路中(在则停止或双击瞬移),检测是否点击自己(转身或轻按),
+检测是否能单击瞬移,最后找寻自动寻路路线并开始寻路。
+
+
+core.setAutoHeroMove(steps)
+设置勇士的自动行走路线,并立刻开始行走。
+
+
+core.setHeroMoveInterval(callback)
+设置勇士行走动画。callback是每一步行走完毕后的回调。
+
+
+core.moveOneStep(x, y)
+每走完一步后执行的操作,被转发到了脚本编辑中,执行脚本编辑moveOneStep中的内容。
+
+
+core.moveAction(callback)
+尝试执行单步行走。callback是执行完毕的回调。
+如果勇士面对的方向是noPass的,将直接触发事件并执行回调。
+
+
+core.moveHero(direction, callback)
+令勇士朝一个方向行走。如果设置了callback,则只会行走一步,并执行回调。
+否则,将一直朝该方向行走,直到core.status.heroStop为true为止。
+direction可为"up","down","right","left",分别对应上,下,右,左。
+
+
+core.isMoving()
+当前是否正在处于行走状态
+
+
+core.waitHeroToStop(callback)
+停止勇士的行走,等待行动结束后,再异步执行回调。
+
+
+core.turnHero(direction)
+转向。如果设置了direction则会转到该方向,否则会右转。该函数会自动计入录像。
+direction可为"up","down","right","left",分别对应上,下,右,左。
+
+
+core.moveDirectly(destX, destY)
+尝试瞬间移动到某点,被转发到了脚本编辑中,执行脚本编辑中的内容。
+此函数返回非负值代表成功进行瞬移,返回值是省略的步数;如果返回-1则代表没有成功瞬移。
+
+
+core.tryMoveDirectly(destX, destY)
+尝试单击瞬移到某点。
+如果该点可被直接瞬间移动到,则直接瞬移到该点;否则尝试瞬移到相邻的上下左右点并行走一步。
+
+
+core.drawHero(status, offset)
+绘制勇士。
+status可选,为'stop','leftFoot'和'rightFoot'之一,不填或null默认是'stop'。
+offset可选,表示具体当前格子的偏移量。不填默认为0。
+此函数将重新计算地图的偏移量,调整窗口位置,绘制勇士和跟随者信息。
+
+// ------ 画布、位置、阻激夹域、显伤 ------ //
+
+core.setGameCanvasTranslate(canvas, x, y)
+设置某个画布的偏移量
+
+
+core.addGameCanvasTranslate(x, y)
+加减所有系统画布(ui和data除外)的偏移量。主要是被“画面震动”所使用。
+
+
+core.updateViewport()
+根据大地图的偏移量来更新窗口的视野范围。
+
+
+core.nextX(n) / core.nextY(n)
+获得勇士面对的第n个位置的横纵坐标。n可不填,默认为1。
+
+
+core.nearHero(x, y, n)
+判定某个点是否和勇士的距离不大于n。n可不填,默认为1。
+
+
+core.gatherFollowers()
+聚集所有的跟随者到勇士的位置。
+
+
+core.updateFollowers()
+更新跟随者们的坐标。
+
+
+core.updateCheckBlock(floorId)
+更新阻激夹域的信息,被转发到了脚本编辑中。
+
+
+core.checkBlock()
+检查勇士坐标点的阻激夹域信息。
+
+
+core.updateDamage(floorId, ctx)
+更新全地图的显伤。floorId可选,默认为当前楼层。
+ctx可选,为画布;如果不为空,则将会绘制到该画布上而不是damage层上。
+
+// ------ 录像相关 ------ //
+
+core.chooseReplayFile()
+弹出选择文件窗口,让用户选择录像文件。
+
+
+core.startReplay(list)
+开始播放一段录像。list为录像的操作数组。
+
+
+core.triggerReplay()
+播放或暂停录像,实际上是pauseReplay或resumeReplay之一。
+
+
+core.pauseReplay() / core.resumeReplay()
+暂停和继续录像播放。
+
+
+core.speedUpReplay() / core.speedDownReplay()
+加速和减速录像播放。
+
+
+core.setReplaySpeed(speed)
+直接设置录像回放速度。
+
+
+core.stopReplay(force)
+停止录像回放。如果force为true则强制停止。
+
+
+core.rewindReplay()
+回退一个录像节点。
+
+
+core.saveReplay() / core.bookReplay() / core.viewMapReplay()
+回放录像时的存档、查看怪物手册、浏览地图操作。
+
+
+core.isReplaying()
+当前是否正在录像播放中。
+
+
+core.registerReplayAction(name, func)
+注册一个自定义的录像行为。
+name:自定义名称,可用户注销使用。
+func:具体执行录像的函数,是一个函数体或者插件中的函数名。
+func需要接受action参数,代表录像回放时的当前操作行为。
+如果func返回true,则代表成功处理了此次操作,返回false代表没有进行处理。
+自己添加的录像项只能由数字、大小写、下划线线、冒号等符号组成,否则无法正常压缩和解压缩。
+对于自定义内容(比如中文文本或数组)请使用JSON.stringify再core.encodeBase64处理。
+请注意回放录像时的二次记录问题(即回放时录像会重新记录路线)。
+
+
+core.unregisterReplayAction(name)
+注销一个录像行为。此函数一般不应当被使用。
+
+// ------ 存读档相关 ------ //
+
+core.autosave(remoreLast)
+进行一个自动存档,实际上是加入到缓存之中。
+removeLast如果为true则会从路线中删除最后一项再存(打怪开门前的状态)。
+在事件处理中不允许调用本函数,如有需要请呼出存档页面。
+
+
+core.checkAutosave()
+将缓存的自动存档写入存储中。平均每五秒钟,或在窗口失去焦点时被执行。
+
+
+core.doSL(id, type)
+实际执行一个存读档事件。id为存档编号,自动存档为'autoSave'。
+type只能为'save', 'load', 'replayLoad'之一,代表存档、读档和从存档回放录像。
+
+
+core.syncSave(type) / core.syncLoad()
+向服务器同步存档,从服务器加载存档。type如果为'all'则会向服务器同步所有存档。
+
+
+core.saveData()
+获得要存档的内容,实际转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.loadData(data, callback)
+实际执行一次读档行为,data为读取到的数据,callback为执行完毕的回调。
+实际转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.getSave(index, callback)
+获得某个存档位的存档。index为存档编号,0代表自动存档。
+
+
+core.getSaves(ids, callback)
+获得若干个存档位的存档。ids为一个存档编号数组,0代表自动存档。
+
+
+core.getAllSaves(callback)
+获得全部的存档内容。目前仅被同步全部存档和下载全部存档所调用。
+
+
+core.getSaveIndexes(callback)
+刷新全部的存档信息,将哪些档位有存档的记录到core.saves.ids中。
+
+
+core.hasSave(index)
+判定某个存档位是否存在存档。index为存档编号,0代表自动存档。
+
+
+core.removeSave(index)
+删除某个存档。index为存档编号,0代表自动存档。
+
+
+// ------ 属性、状态、位置、变量等 ------ //
+
+core.setStatus(name, value)
+设置勇士当前的某个属性,name可为"atk","def","hp"等。
+如core.setStatus("atk", 100)则为设置勇士攻击为100。
+
+
+core.addStatus(name, value)
+加减勇士当前的某个属性,name可为"atk","def","hp"等。
+如core.addStatus("atk", 100)则为增加勇士攻击100点。
+等价于 core.setStatus(name, core.getStatus(name) + value)。
+
+
+core.getStatus(name)
+获得勇士的某个原始属性值,该值不受百分比增幅影响。
+譬如你有一件道具加10%的攻击,你可以使用该函数获得你的攻击被增幅前的数值
+
+
+core.getStatusOrDefault(status, name)
+尝试从status中获得某个原始属性值,该值不受百分比增幅影响;如果status为null或不存在对应属性值则从勇士属性中获取。
+此项在伤害计算函数中使用较多,例如传递新的攻击和防御来计算临界和1防减伤。
+
+
+core.getRealStatus(name)
+获得勇士的某个计算属性值。该属性值是在加成buff之后得到的。
+该函数等价于 core.getStatus(name) * core.getBuff(name)
+
+
+core.getRealStatusOrDefault(status, name)
+尝试从status中获得某个原始属性值再进行增幅,如果不存在则获取勇士本身的计算属性值。
+
+
+core.setBuff(name, value)
+设置勇士的某个属性的增幅值。value为1代表无增幅。
+
+
+core.addBuff(name, value)
+增减勇士的某个属性的增幅值。等价于 core.setBuff(name, core.getBuff(name) + value)
+
+
+core.getBuff(name)
+获得勇士的某个属性的增幅值。默认值是1。
+
+
+core.setHeroLoc(name, value, noGather)
+设置勇士位置属性。name只能为'x'(勇士x坐标), 'y'(勇士y坐标)和'direction'(勇士朝向)之一。
+如果noGather为true,则不会聚集所有的跟随者。
+譬如core.setHeroLoc("x", 1, true)则为设置勇士x坐标为1,不聚集所有跟随者。
+
+
+core.getHeroLoc(name)
+获得勇士的某个位置属性。如果name为null则直接返回core.status.hero.loc。
+譬如core.getHeroLoc("x")则返回勇士当前x坐标
+
+
+core.getLvName(lv)
+获得某个等级对应的名称,其在全塔属性的levelUp中定义。如果不存在则返回原始数值。
+
+
+core.setFlag(name, value)
+设置某个自定义变量或flag。如果value为null则会调用core.removeFlag进行删除。
+这里的变量与事件中使用的变量等价
+譬如core.setFlag("xxx",1)则为设置变量xxx为1。
+
+
+core.addFlag(name, value)
+加减某个自定义的变量或flag。等价于 core.setFlag(name, core.getFlag(name, 0) + value)
+这里的变量与事件中使用的变量等价
+譬如core.addFlag("xxx",1)则为增加变量xxx1
+
+
+core.getFlag(name, defaultValue)
+获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue的值。
+这里的变量与事件中使用的变量等价
+譬如core.getFlag("xxx",1)则为获得变量xxx的值,如变量xxx不存在则返回1
+
+
+core.hasFlag(name)
+判定是否拥有某个自定义变量或flag。等价于 !!core.getFlag(name, 0)
+这里的变量与事件中使用的变量等价
+譬如core.hasFlag("xxx",1)则为判断变量xxx是否存在
+
+core.removeFlag(name)
+删除一个自定义变量或flag。
+
+
+core.lockControl() / core.unlockControl()
+锁定和解锁控制。常常应用于事件处理。
+
+
+core.debug()
+开启调试模式。此模式下可以按住Ctrl进行穿墙。
+
+// ------ 天气,色调,音乐和音效 ------ //
+
+core.setWeather(type, level)
+设置当前的天气。type只能为'rain', 'snow'或'fog',level为1-10之间代表强度信息。
+
+
+core.setCurtain(color, time, callback)
+更改画面色调。color为更改到的色调,是个三元或四元组;time为渐变时间,0代表立刻切换。
+譬如core.setCurtain([255,255,255,1], 0)即为无回调无等待更改画面色调为白色
+
+
+
+core.screenFlash(color, time, times, callback)
+画面闪烁。color为色调,三元或四元组;time为单次闪烁时间,times为总闪烁次数。
+
+
+core.playBgm(bgm, startTime)
+播放一个bgm。startTime可以控制开始时间,不填默认为0。
+如果bgm不存在、不被支持,或当前不允许播放背景音乐,则会跳过。
+
+
+core.pauseBgm() / core.resumeBgm()
+暂停和恢复当前bgm的播放。
+
+
+core.triggerBgm()
+更改当前bgm的播放状态。
+
+
+core.playSound(sound) / core.stopSound()
+播放一个音效,停止全部音效。
+如果sound不存在、不被支持,或当前不允许播放音效,则会忽略。
+
+
+core.checkBgm()
+检查bgm的状态。
+有的时候,刚打开页面时,浏览器是不允许自动播放标题界面bgm的,一定要经过一次用户操作行为。
+这时候我们可以给开始按钮增加core.checkBgm(),如果之前没有成功播放则重新播放。
+
+// ------ 状态栏和工具栏相关 ------ //
+
+core.clearStatusBar()
+清空状态栏的数据。
+
+
+core.updateStatusBar(doNotCheckAutoEvents)
+更新状态栏,被转发到了脚本编辑中。此函数还会根据是否在回放来设置工具栏的图标。
+如果doNotCheckAutoEvents为true则此时不检查自动事件。
+
+core.showStatusBar() / core.hideStatusBar(showToolbox)
+显示和隐藏状态栏。
+如果showToolbox为true,则在竖屏模式下不隐藏工具栏,方便手机存读档操作。
+
+
+core.updateHeroIcon()
+更新状态栏上的勇士图标。
+
+
+core.updateGlobalAttribute()
+更新全局属性,例如状态栏的背景图等。
+
+
+core.setToolbarButton(useButtom)
+设置工具栏是否是拓展键盘。
+
+// ------ resize 相关 ------ //
+
+core.registerResize(name, func)
+注册一个resize函数。
+name为自定义名称,可供注销使用。
+func可以是一个函数,或插件中的函数名,可以接受一个obj作为参数。
+具体详见resize函数。
+
+
+core.unregisterResize(name)
+注销一个resize函数。
+
+
+core.resize()
+屏幕分辨率改变后的重新自适应。
+此函数将根据当前的屏幕分辨率信息,生成一个obj,并传入各个注册好的resize函数中执行。
+```
+
+## enemys.js
+
+enemys.js中定义了一系列和怪物相关的API函数。
+
+```text
+core.hasSpecial(special, test)
+判断是否含有某个特殊属性。test为要检查的特殊属性编号。
+special为要测试的内容,允许接收如下类型参数:
+ - 一个数字:将直接和test进行判等。
+ - 一个数组:将检查test是否在该数组之中存在。
+ - 一个怪物信息:将检查test是否在该怪物的特殊属性中存在
+ - 一个字符串:视为怪物ID,将检查该怪物的特殊属性
+
+
+core.getSpecials()
+获得所有特殊属性的列表。实际上被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.getSpecialText(enemy)
+获得某个怪物的全部特殊属性名称。enemy可以是怪物信息或怪物ID。
+将返回一个数组,每一项是该怪物所拥有的一个特殊属性的名称。
+
+
+core.getSpecialHint(enemy, special)
+获得怪物的某个特殊属性的描述。enemy可以是怪物信息或怪物ID,special为该特殊属性编号。
+
+
+core.canBattle(enemy, x, y, floorId)
+判定当前能否战胜某个怪物。
+enemy可以是怪物信息或怪物ID,x,y,floorId为当前坐标和楼层。(下同)
+能战胜返回true,不能战胜返回false。
+
+
+core.getDamage(enemy, x, y, floorId)
+获得某个怪物的全部伤害值。
+如果没有破防或无法战斗则返回null,否则返回具体的伤害值。
+
+
+core.getExtraDamage(enemy, x, y, floorId)
+获得某个怪物的额外伤害值(不可被魔防减伤)。
+目前暂时只包含了仇恨和固伤两者,如有需要可复写该函数。
+
+
+core.getDamageString(enemy, x, y, floorId)
+获得某个怪物伤害字符串和颜色信息,以便于在地图上绘制显伤。
+
+
+core.nextCriticals(enemy, number, x, y, floorId)
+获得接下来的N个临界值和临界减伤。enemy可以是怪物信息或怪物ID,x,y,floorId为当前坐标和楼层。
+number为要计算的临界值数量,不填默认为1。
+如果全塔属性中的useLoop开关被开启,则将使用循环法或二分法计算临界,否则使用回合法计算临界。
+返回一个二维数组 [[x1,y1],[x2,y2],...] 表示接下来的每个临界值和减伤值。
+
+
+core.getDefDamage(enemy, k, x, y, floorId)
+获得某个怪物的k防减伤值。k可不填默认为1,x,y,floorId为当前xy坐标和楼层。
+
+
+core.getEnemyInfo(enemy, hero, x, y, floorId)
+获得某个怪物的实际计算时的属性。该函数实际被转发到了脚本编辑中。
+hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, "atk")来获得攻击力数值。
+该函数应当返回一个对象,记录了怪物的实际计算时的属性。
+
+
+core.getDamageInfo(enemy, hero, x, y, floorId)
+获得某个怪物的战斗信息。该函数实际被转发到了脚本编辑中。
+hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, "atk")来获得攻击力数值。
+如果该函数返回null,则代表不可战斗(如没有破防,或无敌等)。
+否则,该函数应该返回一个对象,记录了战斗伤害信息,如战斗回合数等。
+从V2.5.5开始,该函数也允许直接返回一个数字,代表战斗伤害值,此时回合数将视为0。
+
+
+core.getCurrentEnemys(floorId)
+获得某个楼层不重复的怪物信息,floorId不填默认为当前楼层。该函数会被怪物手册所调用。
+该函数将返回一个列表,每一项都是一个不同的怪物,按照伤害值从小到大排序。
+另外值得注意的是,如果设置了某个怪物的displayIdInBook,则会返回对应的怪物。
+
+
+core.hasEnemyLeft(enemyId, floorId)
+检查某个楼层是否还有剩余的(指定)怪物。
+floorId为楼层ID,可忽略表示当前楼层。也可以填数组如["MT0","MT1"]同时检测多个楼层。
+enemyId如果不填或null则检查是否剩余任何怪物,否则只检查是否剩余指定的某类怪物。
+```
+
+## events.js
+
+events.js将处理所有和事件相关的操作,主要分为五个部分:
+- 游戏的开始和结束
+- 系统事件的处理
+- 自定义事件的处理
+- 点击状态栏图标所进行的操作
+- 一些具体事件的执行内容
+
+
+```text
+// ------ 游戏的开始和结束 ------ //
+
+core.resetGame(hero, hard, floorId, maps, values)
+重置整个游戏。该函数实际被转发到了脚本编辑中。
+
+
+core.startGame(hard, seed, route, callback)
+开始新游戏。
+hard为难度字符串,会被设置为core.status.hard。
+seed为开始时要设置的的种子,route为要开始播放的录像,callback为回调函数。
+该函数将重置整个游戏,调用setInitData,执行startText事件,上传游戏人数统计信息等。
+
+
+core.setInitData()
+根据难度分歧来初始化难度,包括设置flag:hard,设置初始属性等。
+该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.win(reason, norank)
+游戏胜利,reason为结局名,norank如果为真则该结局不计入榜单。
+该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.lose(reason)
+游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.gameOver(ending, fromReplay, norank)
+游戏结束。ending为获胜结局名,null代表失败;fromReplay标识是否是录像触发的。
+此函数将询问是否上传成绩(如果ending不是null),是否下载录像等,并重新开始。
+
+
+core.restart()
+重新开始游戏。本质上就是播放标题界面的BGM并调用showStartAnimate。
+
+
+core.confirmRestart()
+确认用户是否需要重新开始。
+
+// ------ 系统事件处理 ------ //
+
+core.registerSystemEvent(type, func)
+注册一个系统事件,即通过图块的默认触发器所触发的事件。
+type为一个要注册的事件类型,func为要执行的函数体或插件中的函数名。
+func需要接受(data, callback)作为参数,分别是触发点的图块信息,和执行完毕时的回调。
+如果注册一个已经存在的系统事件,比如openDoor,则会覆盖系统的默认函数。
+
+
+core.unregisterSystemEvent(type)
+注销一个系统事件。type是上面你注册的事件类型。
+
+
+core.doSystemEvent(type, data, callback)
+执行一个系统事件。type为事件类型,data为该事件点的图块信息,callback为执行完毕的回调。
+
+
+core.battle(id, x, y, force, callback)
+和怪物进行战斗。
+id为怪物的ID,x和y为怪物坐标,force如果为真将强制战斗,callback为执行完毕的回调。
+如果填写了怪物坐标,则会删除对应点的图块并执行该点战后事件。
+如果是在事件流的执行过程中调用此函数,则不会进行自动存档,且会强制战斗。
+
+
+core.beforeBattle(enemyId, x, y)
+战前事件。实际被转发到了脚本编辑中,执行脚本编辑中的内容,可以用于加上一些战前特效。
+此函数在“检测能否战斗和自动存档”【之后】执行。
+如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。
+此函数返回true则将继续本次战斗,返回false将不再战斗。
+
+
+core.afterBattle(enemyId, x, y, callback)
+战后事件,将执行扣血、加金币经验、特殊属性处理、战后事件处理等操作。
+实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.openDoor(x, y, needKey, callback)
+尝试开一个门。x和y为门的坐标,needKey表示是否需要钥匙,callback为执行完毕的回调。
+如果不是一个有效的门,需要钥匙且未持有等,均会忽略此事件并直接执行callback。
+
+
+core.afterOpenDoor(doorId, x, y, callback)
+开完一个门后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.getItem(id, num, x, y, callback)
+获得若干个道具。itemId为道具ID,itemNum为获得的道具个数,不填默认为1。
+x和y为道具点的坐标,如果设置则会擦除地图上的该点,也可不填。
+譬如core.getItem("yellowKey",2)会直接获得两把黄钥匙。
+
+
+core.afterGetItem(id, x, y, callback)
+获得一个道具后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.getNextItem(noRoute)
+轻按,即获得面对的道具。如果noRoute为真则这个轻按行为不会计入录像。
+
+
+core.changeFloor(floorId, stair, heroLoc, time, callback, fromLoad)
+楼层切换。floorId为目标楼层ID,stair为是什么楼梯,heroLoc为目标点坐标。
+time为切换时间,callback为切换完毕的回调,fromLoad标志是否是从读档造成的切换。
+floorId也可以填":before"和":next"表示前一层和后一层。
+heroLoc为{"x": 0, "y": 0, "direction": "up"}的形式。不存在则从勇士位置取。
+如果stair不为null,则会在该楼层中找对应的图块作为目标点的坐标并覆盖heroLoc。
+一般设置的是"upFloor"和"downFloor",但也可以用任何其他的图块ID。
+
+
+core.changingFloor(floorId, heroLoc, fromLoad)
+正在执行楼层切换中执行的操作,实际被转发到了脚本编辑中。
+
+
+core.hasVisitedFloor(floorId)
+是否曾经到达过某一层。
+
+
+core.visitFloor(floorId)
+标记曾经到达了某一层。
+
+
+core.passNet(data)
+执行一个路障处理。这里只有毒衰咒网的处理,血网被移动到了updateCheckBlock中。
+
+
+core.pushBox(data)
+执行一个推箱子事件。
+
+
+core.afterPushBox()
+推箱子之后触发的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
+
+
+core.changeLight(id, x, y)
+踩灯后的事件。
+
+// ------ 自定义事件的处理 ------ //
+
+core.registerEvent(type, func)
+注册一个自定义事件。type为事件名,func为执行事件的函数体或插件中的函数名。
+func可以接受(data, x, y, prefix)参数,其中data为事件内容,x和y为该点坐标,prefix为该点前缀。
+同名注册的事件将进行覆盖。
+请记得在自定义处理事件完毕后调用core.doAction()再继续执行下一个事件!
+
+
+core.unregisterEvent(type)
+注销一个自定义事件。
+
+
+core.doEvent(data, x, y, prefix)
+执行一个自定义事件。data为事件内容,将根据data.type去注册的事件列表中查找对应的执行函数。
+x和y为该点坐标,prefix为该点前缀。执行事件时也会把(data, x, y, prefix)传入执行函数。
+
+
+core.setEvents(list, x, y, callback)
+设置自定义事件的执行列表,坐标和回调函数。
+
+
+core.startEvents(list, x, y, callback)
+开始执行一系列的自定义事件。list为事件列表,x和y为事件坐标,callback为执行完毕的回调。
+此函数将调用core.setEvents,然后停止勇士,再执行core.doAction()。
+
+
+core.doAction(keepUI)
+执行下一个自定义事件。
+此函数将检测事件列表是否全部执行完毕,如果是则执行回调函数。
+否则,将从事件列表中弹出下一个事件,并调用core.doEvent进行执行。
+如果keepUI为true,则不会清掉UI层和selector,适合于自己用脚本的绘制。
+
+
+core.insertAction(action, x, y, callback, addToLast)
+向当前的事件列表中插入一个或多个事件并执行。
+如果当前并不是在事件执行流中,则会调用core.startEvents()开始执行事件,否则仅仅执行插入操作。
+action为要插入的事件,可以是一个单独的事件,或者是一个事件列表。
+x,y,callback如果设置了且不为null,则会覆盖当前的坐标和回调函数。
+addToLast如果为真,则会插入到事件执行列表的尾部,否则是插入到执行列表的头部。
+
+
+core.getCommonEvent(name)
+根据名称获得某个公共事件内容。
+
+
+core.recoverEvents(data)
+恢复事件现场。一般用于呼出怪物手册、呼出存读档页面等时,恢复事件执行流。
+
+
+core.checkAutoEvents()
+检测自动事件并执行。
+
+
+core.precompile(events)
+尝试预编译一段事件。
+
+
+// ------ 点击状态栏图标时执行的一些操作 ------ //
+
+core.openBook(fromUserAction)
+尝试打开怪物手册。fromUserAction标志是否是从用户的行为触发,如按键或点击状态栏。(下同)
+不建议复写此函数,否则【呼出怪物手册】事件会出问题。
+
+
+core.useFly(fromUserAction)
+尝试使用楼传器。可以安全的复写此函数,参见文档-个性化-覆盖楼传事件。
+
+
+core.flyTo(toId, callback)
+尝试飞行到某个楼层,被转发到了脚本编辑中。
+如果此函数返回true代表成功进行了飞行,false代表不能进行飞行。
+
+
+core.openEquipbox(fromUserAction) / core.openToolbox(fromUserAction)
+尝试打开道具栏和装备栏。可以安全复写这两个函数。
+
+
+core.openQuickShop(fromUserAction) / core.openKeyBoard(fromUserAction)
+尝试打开快捷商店和虚拟键盘。可以安全复写这两个函数。
+
+
+core.save(fromUserAction) / core.load(fromUserAction)
+尝试打开存读档页面。
+不建议复写这两个函数,否则【呼出存读档页面】事件会出问题。
+
+
+core.openSettings(fromUserAction)
+尝试打开系统菜单。不建议复写此函数。
+
+
+// ------ 一些具体事件的执行内容 ------ //
+
+core.hasAsync()
+当前是否存在未执行完毕的异步事件。请注意正在播放的动画也算异步事件。
+
+
+core.follow(name) / core.unfollow(name)
+跟随勇士/取消跟随。name为行走图名称。
+在取消跟随时如果指定了name,则会从跟随列表中选取一个该行走图取消,否则取消所有跟随。
+跟随和取消跟随都会调用core.gatherFollowers()来聚集所有的跟随者。
+
+
+core.setValue(name, value, prefix) / core.addValue(name, value, prefix)
+设置/增减某个数值。name可以是status:xxx,item:xxx或flag:xxx。
+value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。
+
+
+core.doEffect(effect, need, times)
+执行一个effect操作。该函数目前仅被全局商店的status:xxx+=yyy所调用。
+
+
+core.setEnemy(id, name, value, prefix)
+设置一个怪物属性。id为怪物的ID,name为要设置的项,比如hp,atk,def等等。
+value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。
+
+
+core.setFloorInfo(name, values, floorId, prefix)
+设置某层楼的楼层属性,其中name为该楼层属性对应的条目,values为要设置的值,floorId为楼层id,prefix一般直接忽略。
+譬如core.setFloorInfo("name","4", "MT1")则为设置MT1显示在状态栏中的层数为4
+
+
+core.setGlobalAttribute(name, value)
+设置一个全局属性,如边框颜色等。
+
+
+core.setGlobalFlag(name, value)
+设置一个全局开关,如enableXXX等。
+如果需要设置一个全局数值如红宝石数值,可以直接简单的修改core.values,因此没有单独列出函数。
+
+
+core.closeDoor(x, y, id, callback)
+执行一个关门事件。如果不是一个合法的门,或者该点不为空地,则会忽略本事件。
+
+
+core.showImage(code, image, sloc, loc, opacityVal, time, callback)
+显示一张图片。code为图片编号,image为图片内容或图片名。
+sloc为[x,y,w,h]形式,表示在原始图片上裁剪的区域,也可直接设为null表示整张图片。
+loc为[x,y,w,h]形式,表示在界面上绘制的位置和大小,w和h可忽略表示使用绘制大小。
+opacityVal为绘制的不透明度,time为淡入时间。
+此函数将创建一个画布,其z-index是100+code,即图片编号为1则是101,编号50则是150。
+请注意,curtain层的z-index是125,UI层的z-index是140;因此可以通过图片编号来调整覆盖关系。
+
+
+core.hideImage(code, time, callback)
+隐藏一张图片。code为图片编号,time为淡出时间。
+
+
+core.moveImage(code, to, opacityVal, time, callback)
+移动一张图片。code为图片编号,to为[x,y]表示目标位置,opacityVal目标不透明度,time为移动时间。
+
+
+core.showGif(name, x, y)
+绘制一张gif图片或取消所有绘制内容。如果name不设置则视为取消。x和y为左上角像素坐标。
+
+
+core.setVolume(value, time, callback)
+设置音量。value为目标音量大小,在0到1之间。time为音量渐变的时间。
+
+
+core.vibrate(time, callback)
+画面震动。time为震动时间。
+请注意,画面震动时间必须是500的倍数,系统也会自动把time调整为上整的500倍数值。
+
+
+core.eventMoveHero(steps, time, callback)
+使用事件移动勇士。time为每步的移动时间。
+steps为移动数组,可以接受'up','down','left','right','forward'和'backward'项。
+使用事件移动勇士将不会触发任何地图上的事件。
+
+
+core.jumpHero(ex, ey, time, callback)
+跳跃勇士。ex和ey为目标点的坐标,可以为null表示原地跳跃。time为总跳跃时间。
+
+
+core.openShop(shopId, needVisited)
+打开一个全局商店。needVisited表示是否需要该商店原本就是启用状态。
+如果该商店对应的实际上是一个全局事件,则会直接插入并执行。
+
+
+core.disableQuickShop(shopId)
+禁用一个全局商店,即把一个商店从启用变成禁用状态。
+
+
+core.canUseQuickShop(shopId)
+当前能否使用某个全局商店,实际被转发到了脚本编辑中。
+如果此函数返回null则表示可以使用,返回一个字符串表示不可以,该字符串表示不可以的原因。
+
+
+core.setHeroIcon(name, noDraw)
+设置勇士的行走图。
+name为行走图名称,noDraw如果为真则不会调用core.drawHero()函数进行刷新。
+
+
+core.checkLvUp()
+检查升级事件。该函数将判定当前是否升级(或连续升级),然后执行升级事件。
+
+
+core.tryUseItem(itemId)
+尝试使用一个道具。
+对于怪物手册和楼传器,将分别调用core.openBook()和core.useFly()函数。
+对于中心对称飞行器,则会调用core.drawCenterFly()函数。
+对于其他的道具,将检查是否拥有,能否使用,并且进行使用。
+
+
+core.afterUseBomb()
+使用炸弹或圣锤后的事件。实际被转发到了脚本编辑中。
+```
+
+## icons.js
+
+icons.js主要是负责素材相关信息,比如某个素材在对应的图片上的位置。
+
+```text
+core.getClsFromId(id)
+根据某个素材的ID获得该素材的cls
+
+
+core.getTilesetOffset(id)
+根据某个素材来获得对应的tileset和坐标信息。
+如果该素材不是tileset,则返回null。
+```
+
+## items.js
+
+items.js主要负责一切和道具相关的内容。
+
+```text
+core.getItemEffect(itemId, itemNum)
+即捡即用类的道具获得时的效果。实际对应道具图块属性中的itemEffect框。
+
+
+core.getItemEffectTip(itemId)
+即捡即用类的道具获得时的额外提示,比如“,攻击+100”。
+实际对应道具图块属性中的itemEffectTip框。
+
+
+core.useItem(itemId, noRoute, callback)
+尝试使用一个道具。实际对应道具图块属性中的useItemEffect框。
+此函数也会调用一遍core.canUseItem(),如果无法使用将直接返回。
+noRoute如果为真,则这次使用道具的过程不会被计入录像。
+使用道具完毕后,对于消耗道具将自动扣除,永久道具不会扣除。
+
+
+core.canUseItem(itemId)
+当前能否使用某个道具。
+有些系统道具如破炸和上下楼器等,会在计算出目标点的坐标后存入core.status.event.ui。
+使用道具时将直接从core.status.event.ui调用,不会重新计算。
+
+
+core.itemCount(itemId)
+获得某个道具的个数。
+
+
+core.hasItem(itemId)
+当前是否拥有某个道具。等价于 core.itemCount(itemId) > 0
+请注意,装备上的装备不视为拥有该道具,即core.hasEquip()和core.hasItem()是完全不同的。
+
+
+core.hasEquip(itemId)
+当前是否装备上某个装备。
+请注意,装备上的装备不视为拥有该道具,即core.hasEquip()和core.hasItem()是完全不同的。
+
+
+core.getEquip(equipType)
+获得某个装备位的当前装备。equipType为装备类型,从0开始。
+如果该装备位没有装备则返回null,否则返回当前装备的ID。
+
+
+core.setItem(itemId, itemNum)
+设置某个道具的个数。
+
+
+core.addItem(itemId, itemNum)
+增减某个道具的个数,itemNum可不填默认为1。
+
+
+core.getEquipTypeByName(name)
+根据装备位名称来找到一个空的装备孔,适用于多重装备,装备位名称可在全塔属性中设置。
+如果没有一个装备孔是该装备名称,则返回-1。
+譬如:core.getEquipTypeByName("武器")默认返回全塔属性中武器对应的装备孔号0。
+
+
+core.getEquipTypeById(equipId)
+获得某个装备的装备类型。
+如果其type写的是装备名(多重装备),则调用core.getEquipTypeByName()函数。
+
+
+core.canEquip(equipId, hint)
+当前能否穿上某个装备。如果hint为真,则不可装备时会气泡提示原因。
+
+
+core.loadEquip(equipId, callback)
+穿上某个装备,equipId为装备id。
+
+
+core.unloadEquip(equipType, callback)
+脱下某个装备孔的装备。
+譬如core.unloadEquip(0)则为脱下0号装备孔中的装备,默认0号装备孔对应“武器”,1号装备孔对应“盾牌”
+
+
+core.compareEquipment(compareEquipId, beComparedEquipId)
+比较两个套装的差异。
+此函数将对所有的勇士属性包括生命魔力攻防魔防金币等进行比较。
+如果存在差异的,将作为一个对象返回其差异内容。
+
+
+core.quickSaveEquip(index)
+保存当前套装。index为保存的套装编号。
+
+
+core.quickLoadEquip()
+读取当前套装。index为读取的套装编号。
+
+
+core.getEquippedStatus(name)
+获得装备直接增加的属性数据。
+```
+
+## loader.js
+
+loader.js主要负责资源加载相关的内容。
+
+```text
+core.loadImage(imgName, callback)
+从 project/images/ 中加载一张图片。imgName为图片名。
+callback为执行完毕的回调函数,接收(imgName, image)即图片名和图片内容作为参数。
+如果图片不存在或加载失败则会在控制台打出一条错误日志,不会执行回调。
+
+
+core.loadImages(names, toSave, callback)
+从 project/images/ 中加载若干张图片。
+names为一个图片名的列表,toSave为加载并存到的对象。
+callback为全部加载完毕执行的回调。
+
+
+core.loadOneMusic(name)
+从 project/sounds/ 或第三方中加载一个音乐,并存入core.material.bgms中。name为音乐名。
+
+
+core.loadOneSound(name)
+从 project/sounds/ 中加载一个音效,并存入core.material.sounds中。name为音效名。
+
+
+core.loadBgm(name)
+预加载一个bgm并加入缓存列表core.musicStatus.cachedBgms。
+此函数将会检查bgm的缓存,预加载和静音播放。
+如果缓存列表溢出(core.musicStatus.cacheBgmCount)则通过LRU算法选择一个bgm并调用core.freeBgm()。
+
+
+core.freeBgm(name)
+释放一个bgm的内存并移出缓存列表。如果该bgm正在播放则也会立刻停止。
+```
+
+## map.js
+
+maps.js负责一切和地图相关的处理内容,包括如下几个方面:
+- 地图的初始化,保存和读取,地图数组的生成
+- 是否可移动或瞬间移动的判定
+- 地图的绘制
+- 获得某个点的图块信息
+- 启用和禁用图块,改变图块
+- 移动/跳跃图块,淡入淡出图块
+- 全局动画控制,动画的绘制
+
+```text
+// ------ 地图的初始化,保存和读取,地图数组的生成 ------ //
+
+core.loadFloor(floorId, map)
+从楼层或者存档中生成core.status.maps的内容。
+map为存档信息,如果某项在map中不存在则会从core.floors中读取。
+
+
+core.getNumberById(id)
+给定一个图块ID,找到图块对应的图块编号。
+
+
+core.initBlock(x, y, id, addInfo, eventFloor)
+给定一个数字,初始化一个图块信息。
+x和y为坐标,id为数字或者可以:t或:f结尾表示初始是启用还是禁用状态。
+addInfo如果为true则会填充上图块的默认信息,比如给怪物添加battle触发器。
+eventFloor如果设置为某个楼层信息,则会填充上该点的自定义或楼层切换事件。
+
+
+core.compressMap(mapArr, floorId)
+压缩地图。mapArr为要压缩的二维数组,floorId为对应的楼层。
+此函数将把mapArr和对应的楼层中的数组进行比较,并只取差异值进行存储。
+通过这种压缩地图的方式,不仅节省了存档空间,还支持了任意修改地图的接档。
+
+
+core.decompressMap(mapArr, floorId)
+解压缩地图。mapArr为压缩后的地图,floorId为对应的楼层。
+此函数返回解压后的二维数组。
+
+
+core.saveMap(floorId)
+将某层楼的数据生成存档所保存的内容。在core.saveData()中被调用。
+
+
+core.loadMap(data, floorId)
+从data中读取楼层数据,并调用core.loadFloor()进行初始化。
+
+
+core.removeMaps(fromId, toId)
+删除某个区域的地图。调用此函数后,这些楼层将不可飞,不可被浏览地图,也不计入存档。
+fromId和toId为要删除的起终点楼层ID;toId也可以不填代表只删除某一层。
+此函数适用于高层塔的砍层,例如每100层一个区域且互相独立,不可再返回的情况。
+
+
+core.resizeMap(floorId)
+根据某层楼的地图大小来调整大地图的画布大小。floorId可为null表示当前层。
+
+
+core.getMapArray(floorId, showDisable)
+生成某层楼的二维数组。floorId可不填代表当前楼层。
+showDisable若为真,则对于禁用的点会加上:f表示,否则视为0。
+
+
+core.getMapBlocksObj(floorId, showDisable)
+以x,y的形式返回每个点的图块信息。floorId可不填表示当前楼层。
+此函数将返回 {"0,0": {...}, "0,1": {...}} 这样的结构,其中内部为对应点的block信息。
+
+
+core.getBgMapArray(floorId, noCache)
+获得某层楼的背景层的二维数组。floorId可不填表示当前楼层。
+如果noCache为真则重新从剧本中读取而不使用缓存数据。
+
+
+core.getFgMapArray(floorId, noCache)
+获得某层楼的前景层的二维数组。floorId可不填表示当前楼层。
+如果noCache为真则重新从剧本中读取而不使用缓存数据。
+
+
+core.getBgNumber(x, y, floorId, noCache)
+获得某层楼的背景层中某个点的数字。floorId可不填表示当前楼层。
+如果noCache为真则重新从剧本中读取而不使用缓存数据。
+本函数实际等价于 core.getBgMapArray(floorId, noCache)[y][x]
+
+
+core.getBgNumber(x, y, floorId, noCache)
+获得某层楼的前景层中某个点的数字。参数和方法同上。
+
+// ------ 是否可移动或瞬间移动的判定 ------ //
+
+core.generateMovableArray(floorId, x, y, direction)
+生成全图或某个点的可通行方向数组。floorId为楼层Id,可不填默认为当前点。
+这里的可通行方向数组,指的是["up","down","left","right"]中的一个或多个组成的数组。
+ - 如果不设置x和y,则会返回一个三维数组,其中每个点都是一个该点可通行方向的数组。
+ - 如果设置了x和y但没有设置direction,则只会返回该点的可通行方向数组,
+ - 如果设置了x和y以及direction,则会判定direction是否在该点可通行方向数组中,并返回true或false。
+可以使用core.inArray()来判定某个方向是否在可通行方向数组中。
+
+
+core.canMoveHero(x, y, direction, floorId)
+某个点是否可朝某个方向移动。x和y可选,不填或为null则默认为勇士当前点。
+direction可选,不填或为null则默认勇士当前朝向。floorId不填则默认为当前楼层。
+此函数将直接调用 core.generateMovableArray() 进行判定。
+
+
+core.canMoveDirectly(destX, destY)
+当前能否瞬间移动到某个点。
+如果可以瞬移则返回非负数,其值为该次瞬移所少走的步数;如果不能瞬移则返回-1。
+
+
+core.automaticRoute(destX, destY)
+找寻到目标点的一条自动寻路路径。
+
+// ------ 绘制地图相关 ------ //
+
+core.drawBlock(block, animate)
+重新绘制一个图块,block为图块信息。
+如果animate不为null则代表是通过全局动画的绘制,其值为当前的帧数。
+
+
+core.generateGroundPattern(floorId)
+生成某个楼层的地板信息。floorId不填默认为当前楼层。
+该函数可被怪物手册、对话框帧动画等地方使用。
+
+
+core.drawMap(floorId, callback)
+绘制某层楼的地图。floorId为目标楼层ID,可不填表示当前楼层。
+此函数会将core.status.floorId设置为floorId,并设置core.status.thisMap。
+将依次调用core.drawBg(), core.drawEvents()和core.drawFg()函数,最后绘制勇士和更新地图显伤。
+
+
+core.drawBg(floorId, ctx)
+绘制背景层。floorId为目标楼层ID,可不填表示当前楼层。
+如果ctx不为null,则背景层将绘制在该画布上而不是bg层上(drawThumbnail使用)。
+可以通过复写该函数,调整_drawFloorImages和_drawBgFgMap的顺序来调整背景图块和贴图的遮挡顺序。
+
+
+core.drawEvents(floorId, blocks, ctx)
+绘制事件层。floorId为目标楼层ID,可不填表示当前楼层。
+block表示要绘制的图块列表,可不填使用当前楼层的图块列表。
+如果ctx不为null,则背景层将绘制在该画布上而不是event层上(drawThumbnail使用)。
+
+
+core.drawFg(floorId, ctx)
+绘制前景层。floorId为目标楼层ID,可不填表示当前楼层。
+如果ctx不为null,则背景层将绘制在该画布上而不是fg层上(drawThumbnail使用)。
+可以通过复写该函数,调整_drawFloorImages和_drawBgFgMap的顺序来调整前景图块和贴图的遮挡顺序。
+
+
+core.drawThumbnail(floorId, blocks, options, toDraw)
+绘制一个楼层的缩略图。floorId为目标楼层ID,可不填表示当前楼层。
+block表示要绘制的图块列表,可不填使用当前楼层的图块列表。
+options为绘制选项(可为null),包括:
+ heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤;
+ flags:当前的flags(在存读档时使用)
+toDraw为要绘制到的信息(可为null,或为一个画布名),包括:
+ ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:绘制大小(默认416/480);
+ all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心)
+
+// ------ 获得某个点的图块信息 ------ //
+
+core.noPass(x, y, floorId)
+判定某个点是否有noPass(不可通行)的图块。
+
+
+core.npcExists(x, y, floorId)
+判定某个点是否有NPC的存在。
+
+
+core.terrainExists(x, y, id, floorId)
+判定某个点是否有(id对应的)地形存在。
+如果id为null,则只要存在terrains即为真,否则还会判定对应点的ID。
+
+
+core.stairExists(x, y, floorId)
+判定某个点是否存在楼梯。
+
+
+core.nearStair()
+判定当前勇士是否在楼梯上或旁边(距离不超过1)。
+
+
+core.enemyExists(x, y, id, floorId)
+判定某个点是否有(id对应的)怪物存在。
+如果id为null,则只要存在怪物即为真,否则还会判定对应点的怪物ID。
+请注意,如果需要判定某个楼层是否存在怪物请使用core.hasEnemyLeft()函数。
+
+
+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。如果该点不存在图块则返回null。
+
+
+core.getBlockCls(x, y, floorId, showDisable)
+获得某个点的图块类型。如果该点不存在图块则返回null。
+
+
+core.getBlockInfo(block)
+根据某个的图块信息获得其详细的素材信息。
+如果参数block为字符串,则视为图块ID;如果参数为数字,则视为图块的数字。
+此函数将返回一个非常详尽的素材信息,目前包括如下几项:
+number:素材数字;id:素材id;cls:素材类型;image:素材所在的素材图片;animate:素材的帧数。
+posX, posY:素材在该素材图片上的位置;height:素材的高度;faceIds:NPC朝向记录。
+
+
+core.searchBlock(id, floorId, showDisable)
+搜索一个图块出现过的所有位置。id为图块ID,也可以传入图块的数字。
+id支持通配符搜索,比如"*Door"可以搜索所有的门,"unknownEvent*"可以所有所有的unknownEvent。
+floorId为要搜索的楼层,可以是一个楼层ID,或者一个楼层数组。如果floorId不填则只搜索当前楼层。
+showDisable如果为真,则对于禁用的图块也会返回。
+此函数将返回一个数组,每一项为一个搜索到的结果:
+{"floorId": ..., "index": ..., "block": {...}, "x": ..., "y": ...}
+即包含该图块所在的楼层ID,在该楼层的blocks数组的索引,图块内容,和横纵坐标。
+
+
+// ------ 启用和禁用图块,改变图块 ------ //
+
+core.showBlock(x, y, floorId)
+将某个点从禁用变成启用状态。floorId可不填或null表示当前楼层。
+
+
+core.hideBlock(x, y, floorId)
+将某个点从启用变成禁用状态,但不会对其进行删除。floorId可不填或null表示当前楼层。
+此函数不会实际将该块从地图中进行删除,而是将该点设置为禁用,以供以后可能的启用事件。
+
+
+core.removeBlock(x, y, floorId)
+将从启用变成禁用状态,并尽可能将其从地图上删除。
+和hideBlock相比,如果该点不存在自定义事件(比如门或普通的怪物),则将直接从地图中删除。
+如果存在自定义事件,则简单的禁用它,以供以后可能的启用事件。
+
+
+core.removeBlockById(index, floorId)
+每个楼层的图块存成一个数组,index即为该数组中的索引,每个索引对应该地图中的一个图块
+根据索引从地图的block数组中尽可能删除一个图块。floorId可不填或null表示当前楼层。
+
+
+core.removeBlockByIds(floorId, ids)
+ids为由索引组成的数组,如[0,1]等
+根据索引数组从地图的block数组中尽可能删除一系列图块。floorId可不填或null表示当前楼层。
+
+
+core.canRemoveBlock(block, floorId)
+block为图块信息,可由core.getBlock获取
+判定当前能否完全删除某个图块。floorId可不填或null表示当前楼层。
+如果该点存在自定义事件,或者是重生怪,则不可进行删除。
+
+
+core.showBgFgMap(name, loc, floorId, callback)
+显示某层楼中某个背景/前景层的图块。name只能为'bg'或'fg'表示背景或前景层。
+loc为该点坐标,floorId可不填默认为当前楼层。callback为执行完毕的回调。
+
+
+core.hideBgFgMap(name, loc, floorId, callback)
+隐藏某层楼中某个背景/前景层的图块。name只能为'bg'或'fg'表示背景或前景层。
+loc为该点坐标,floorId可不填默认为当前楼层。callback为执行完毕的回调。
+
+
+core.showFloorImage(loc, floorId, callback)
+显示某层楼中的某个楼层贴图。loc为该贴图的左上角坐标。floorId可省略表示当前楼层。
+
+
+core.hideFloorImage(loc, floorId, callback)
+隐藏某层楼中的某个楼层贴图。loc为该贴图的左上角坐标。floorId可省略表示当前楼层。
+
+
+core.setBlock(number, x, y, floorId)
+改变某个楼层的某个图块。
+number为要改变到的数字,也可以传入图块id(将调用core.getNumberById()来获得数字)。
+x,y和floorId为目标点坐标和楼层,可忽略为当前点和当前楼层。
+
+
+core.replaceBlock(fromNumber, toNumber, floorId)
+将某个或某些楼层中的所有某个图块替换成另一个图块
+fromNumber和toNumber为要被替换和替换到的数字。
+floorId可为某个楼层ID,或者一个楼层数组;如果不填只视为当前楼层。
+值得注意的是,使用此函数转了的点上的自定义事件可能无法被执行。
+如有需要,再对那些存在事件的点执行core.setBlock()即可
+
+
+core.setBgFgBlock(name, number, x, y, floorId)
+设置前景/背景层的某个图块。name只能为'bg'或'fg'表示前景或背景层。
+number为要设置到的图块数字,x,y和floorId为目标点坐标和楼层,可忽略为当前点和当前楼层。
+
+
+core.resetMap(floorId)
+重置某层或若干层的地图和楼层属性。
+floorId可为某个楼层ID,或者一个楼层数组如["MT1","MT2"](同时重置若干层);如果不填则只重置当前楼层。
+
+// ------ 移动/跳跃图块,淡入淡出图块 ------ //
+
+core.moveBlock(x, y, steps, time, keep, callback)
+移动一个图块,x和y为图块的坐标。
+steps为移动的数组,每一项只能是"up","down","left","right"之一。
+time为每一步的移动时间,不填默认为500ms。
+如果keep为真,则在移动完毕后将自动调用一个setBlock事件,改变目标点的图块(即不消失),
+否则会按照time时间来淡出消失。callback会执行完毕后的回调。
+
+
+core.jumpBlock(sx, sy, ex, ey, time, keep, callback)
+跳跃一个图块,sx和sy为图块的坐标,ex和ey为目标坐标。time为整个跳跃过程中的全程用时,不填默认500。
+如果keep为真,则在移动完毕后将自动调用一个setBlock事件,改变目标点的图块(即不消失),
+否则会按照time时间来淡出消失。callback会执行完毕后的回调。
+
+
+core.animateBlock(loc, type, time, callback)
+淡入/淡出一个或多个图块。
+loc为一个图块坐标,或者一个二维数组表示一系列图块坐标(将同时显示和隐藏)。
+type只能为'show'或'hide'表示是淡入但是淡出。time为动画时间,callback为执行完毕的回调。
+
+// ------ 全局动画控制,动画的绘制 ------ //
+
+core.addGlobalAnimate(block)
+添加一个全局帧动画。
+
+
+core.removeGlobalAnimate(x, y, name)
+删除一个或全部的全局帧动画。name可为'bg',null或'fg'表示某个图层。
+x和y如果为null,则会删除全部的全局帧动画,否则只会删除该点的该层的帧动画。
+
+
+core.drawBoxAnimate()
+绘制UI层的box动画,如怪物手册和对话框中的帧动画等。
+
+
+core.drawAnimate(name, x, y, callback)
+绘制一个动画。name为动画名,x和y为绘制的基准坐标,callback为绘制完毕的回调函数。
+此函数将播放动画音效,并异步开始绘制该动画。
+此函数会返回一个动画id,可以通过core.stopAnimate()立刻停止该动画的播放。
+
+
+core.stopAnimate(id, doCallback)
+立刻停止某个动画的播放。id为上面core.drawAnimate的返回值。
+如果doCallback为真,则会执行该动画所对应的回调函数。
+```
+
+## ui.js
+
+ui.js负责一切UI界面的绘制。主要包括三个部分:
+- 设置某个画布的属性的相关API
+- 具体的某个UI界面的绘制
+- 动态创建画布相关的API
+
+```text
+// ------ 设置某个画布的属性的相关API ------//
+这系列函数的name一般都是画布名,可以是系统画布或动态创建的画布。
+但也同时也允许直接传画布的context本身,将返回自身。
+
+
+core.getContextByName(name)
+根据画布名找到一个画布的context;支持系统画布和自定义画布。
+如果不存在画布此函数返回null。
+该参数也可以直接传画布的context自身,则返回自己。
+
+
+core.clearMap(name)
+清空某个画布图层。
+该函数的name也可以是'all',若为'all'则为清空所有系统画布。
+
+
+core.fillText(name, text, x, y, style, font, maxWidth)
+在某个画布上绘制一段文字。
+text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同)
+style可直接使用"red","white"等或用"rgba(255,255,255,1)"或用"#FFFFFF"等方式来获得字体对应的颜色
+font的格式为"20px Verdana"前者为字体大小,后者为字体
+如果maxWidth不为null,则视为文字最大宽度,如果超过此宽度则会自动放缩文字直到自适应为止。
+请注意textAlign和textBaseline将决定绘制的左右对齐和上下对齐方式。
+具体可详见core.setTextAlign()和core.setTextBaseline()函数。
+譬如:core.fillText("ui", "这是要描绘的文字", 10, 10, "red", "20px Verdana", 100)
+即是在ui图层上,以10,10为起始点,描绘20像素大小,Verdana字体的红色字,长度不超过100像素
+
+
+core.fillBoldText(name, text, x, y, style, font)
+在某个画布上绘制一个描黑边的文字。
+
+
+core.fillRect(name, x, y, width, height, style)
+绘制一个矩形。width, height为矩形宽高,style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同)
+
+
+core.strokeRect(name, x, y, width, height, style, lineWidth)
+绘制一个矩形的边框。style可选为绘制样式,如果设置将调用core.setStrokeStyle()。
+lineWidth如果设置将调用core.setLineWidth()。(下同)
+
+
+core.drawLine(name, x1, y1, x2, y2, style, lineWidth)
+绘制一条线,x1y1为起始点像素,x2y2为终止点像素。
+
+
+core.drawArrow(name, x1, y1, x2, y2, style, lineWidth)
+绘制一个箭头,x1y1为起始点像素,x2y2为终止点像素。
+
+
+core.setFont(name, font) / core.setLineWidth(name, lineWidth)
+设置一个画布的字体/线宽。
+
+
+core.setAlpha(name, font) / core.setOpacity(name, font)
+设置一个画布的绘制不透明度和画布本身的不透明度。
+两者区别如下:
+ - setAlpha是设置"接下来绘制的内容的不透明度",不会对已经绘制的内容产生影响。
+ > 比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。
+ - setOpacity是设置"画布本身的不透明度",已经绘制的内容也会产生影响。
+ > 比如我已经在UI层绘制了一段文字,再setOpacity则也会让已经绘制的文字变得透明。
+尽量不要对系统画布使用setOpacity(因为会对已经绘制的内容产生影响),自定义创建的画布则不受此限制。
+
+
+core.setFillStyle(name, style) / core.setStrokeStyle(name, style)
+设置一个画布的填充样式/描边样式。
+
+
+core.setTextAlign(name, align)
+设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center',分别对应左对齐,右对齐,居中。
+默认为'left'。
+
+
+core.setTextBaseline(name, baseline)
+设置一个画布的纵向对齐模式。有关textBaseline的说明可参见如下资料:
+http://www.runoob.com/tags/canvas-textbaseline.html
+默认值是'alphabetic'。
+请注意,系统画布在绘制前都是没有设置过textBaseline的,都是按照alphabetic进行坐标绘制。
+因此,如果你修改了系统画布的textBaseline来绘图,记得再绘制完毕后修改回来。
+
+
+core.calWidth(name, text, font)
+计算一段文字在某个画布上的绘制宽度,此函数其实是ctx.measureText()的包装。
+font可选,如果存在则会先设置该画布上的字体。
+此函数不会对文字进行换行,如需换行版本请使用core.splitLines()函数。
+
+
+core.splitLines(name, text, maxWidth, font)
+计算一段文字在某画布上换行分割的结果。
+text为文字内容,maxWidth为最大宽度,可为null表示不自动换行。
+font可选,如果存在则会先设置该画布上的字体。
+此函数将返回一个换行完毕的文本列表。
+
+
+core.drawImage(name, image, x, y, w, h, x1, y1, w1, h1)
+在一张画布上绘制一张图片,此函数其实是ctx.drawImage()的包装。
+可以查看下面的文档以了解各项参数的信息:
+http://www.w3school.com.cn/html5/canvas_drawimage.asp
+这里的image允许传一个图片,画布。也允许传递图片名,将从你导入的图片中获取图片内容。
+
+
+core.drawIcon(name, id, x, y, w, h)
+在一张画布上绘制一个图标。
+id为注册过的图标ID,也可以使用状态栏的图标ID,例如lv, hp, up, save, settings等。
+x和y为绘制的左上角坐标;w和h可选为绘制的宽高,如果不填或null则使用该图标的默认宽高。
+
+
+// ------ 具体的某个UI界面的绘制 ------ //
+core.closePanel()
+结束一切事件和UI绘制,关闭UI窗口,返回游戏。
+此函数将以此调用core.clearUI(),core.unlockControl(),并清空core.status.event里面的内容。
+
+
+core.clearUI()
+重置UI窗口。此函数将清掉所有的UI帧动画和光标,清空UI画布,并将alpha设为1。
+
+
+core.drawTip(text, id, clear)
+在左上角以气泡的形式绘制一段提示。
+text为文字内容,仅支持${}的表达式计算,不支持换行和变色。
+id可选,为同时绘制的图标ID,如果不为null则会同时绘制该图标(仅对32x32的素材有效)。
+也可以使用状态栏的图标ID,例如lv, hp, up, save, settings等。
+如果clear为true,则会清空当前所有正在显示的提示。
+
+
+core.clearTip()
+清空当前所有正在显示的提示。
+
+
+core.drawText(content, callback)
+绘制一段文字。contents为一个字符串或一个字符串数组,callback为全部绘制完毕的回调。
+支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t和\b的语法。
+如果当前在事件处理中或录像回放中,则会自动转成core.insertAction处理。
+不建议使用该函数,如有绘制文字的需求请尽量使用core.insertAction()插入剧情文本事件。
+
+
+core.drawWindowSelector(background, x, y, w, h)
+绘制一个WindowSkin的闪烁光标。background可为winskin的图片名或图片本身。
+x,y,w,h为绘制的左上角位置和宽高,都是像素为单位。
+
+
+core.drawWindowSkin(background, ctx, x, y, w, h, direction, px, py)
+绘制一个WindowSkin。background可为winskin的图片名或图片本身。
+ctx为画布名或画布本身,x,y,w,h为左上角位置和宽高,都是像素为单位。
+direction, px, py可选,如果设置则会绘制一个对话框箭头。
+
+
+core.drawBackground(left, top, right, bottom, posInfo)
+绘制一个背景图。此函数将使用你在【剧情文本设置】中设置的背景,即用纯色或WindowSkin来绘制。
+left, top, right, bottom为你要绘制的左上角和右下角的坐标。
+posInfo如果不为null则是一个含position, px和py的对象,表示一个对话框箭头的绘制。
+
+
+core.drawTextContent(ctx, content, config)
+根据配置在某个画布上绘制一段文字。此函数会被core.drawTextBox()所调用。
+ctx为画布名或画布本身,如果不设置则会忽略该函数。
+content为要绘制的文字内容,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等)
+ ,但不支持支持\t和\b的语法。
+config为绘制的配置项,目前可以包括如下几项:
+ - left, top:在该画布上绘制的左上角像素位置,不设置默认为(0,0)。
+ > 该函数绘制时会将textBaseline设置为'top',因此只需要考虑第一个字的左上角位置。
+ - maxWidth:单行最大宽度,超过此宽度将自动换行,不设置不会自动换行。
+ - color:默认颜色,为#XXXXXX形式。如果不设置则使用剧情文本设置中的正文颜色。
+ - bold:是否粗体。如果不设置默认为false。
+ - align:文字对齐方式,仅在maxWidth设置时有效,默认为'left'。
+ - fontSize:字体大小,如果不设置则使用剧情文本设置中的正文字体大小。
+ - lineHeight:绘制的行距值,如果不设置则使用fontSize*1.3(即1.3倍行距)。
+ - time:打字机效果。若不为0,则会逐个字进行绘制,并设置core.status.event.interval定时器。
+ - interval:字符间的间距。值表示绘制每个字符之间间隔的距离,默认为0。
+
+
+core.drawTextBox(content, showAll)
+绘制一个对话框。content为一个字符串或一个字符串数组。
+支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t和\b的语法。
+该函数将使用用户在剧情文本设置中的配置项进行绘制。
+实际执行时,会计算文本框宽度并绘制背景,绘制标题和头像,再调用core.drawTextContent()绘制正文内容。
+showAll可选,如果为true则不会使用打字机效果而全部显示,主要用于打字机效果的点击显示全部。
+
+
+core.drawScrollText(content, time, lineHeight, callback)
+绘制一个滚动字幕。content为绘制内容,time为总时间(默认为5000),lineHeight为行距比例(默认为1.4)。
+滚动字幕将绘制在UI上,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),但不支持\t和\b效果。
+可以通过剧情文本设置中的align控制是否居中绘制,offset控制其距离左边的偏移量。
+
+
+core.textImage(content, lineHeight)
+将文本图片化。content为绘制内容,lineHeight为行距比例(默认为1.4)。
+可以通过剧情文本设置中的align控制是否居中绘制。
+此函数将返回一个临时画布的canvas,供转绘到其他画布上使用。
+
+
+core.drawChoices(content, choices)
+绘制一个选项框。
+content可选,为选项上方的提示文字,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t。
+choices必选,为要绘制的选项内容,是一个列表。其中的每一项:
+ - 可以是一个字符串,表示选项文字,将使用剧情文本设置中的正文颜色来绘制,仅支持${}表达式计算。
+ - 或者是一个包含text, color和icon的对象。
+ > text必选,为要绘制的文字内容,仅支持${}的表达式计算,
+ > color为要绘制的选项颜色,可以是#XXXXXX的格式或RGBA数组。不设置则使用正文颜色。
+ > icon为要绘制的图标ID,支持使用素材的ID,或者系统图标。
+
+
+core.drawConfirmBox(text, yesCallback, noCallback)
+绘制一个确认框。text为确认文字,支持\n换行(但不支持自动换行)和${}表达式计算。
+yesCallback和noCallback分别为确定和取消的回调函数。
+可以在调用此函数前设置core.status.event.selection来控制默认的选中项(0确定1取消)。
+此函数和core.myconfirm的区别主要在于:
+ - 此函数会清掉UI层原有的绘制信息,core.myconfirm不会清除。
+ - 此函数可以用键盘进行操作,core.myconfirm必须用鼠标点击。
+另外请注意:本函数和事件流的执行不兼容,选择也不会进录像。
+如果需要在事件流中调用请使用提供选择项。
+
+
+core.drawWaiting(text)
+绘制一个等待界面,一般用于同步存档之类的操作。
+调用此函数后,需要再调用core.closePanel()才会恢复游戏。
+
+
+core.drawPagination(page, totalPage, y)
+绘制一个分页。y如果不设置则绘制在最后一行。
+
+
+core.drawBook(index) / core.drawBookDetail(index)
+绘制怪物手册,绘制怪物的详细信息。
+
+
+core.drawFly(page) / core.drawCenterFly() / core.drawShop(shopId)
+绘制楼传页面,中心对称飞行器,绘制商店
+
+
+core.drawToolbox(index) / core.drawEquipbox(index) / core.drawKeyBoard()
+绘制道具栏,绘制装备栏,绘制虚拟键盘。
+
+
+core.drawMaps(index, x, y) / core.drawSLPanel(index, refresh)
+绘制浏览地图,绘制存读档界面。
+
+
+core.drawStatusBar()
+自定义绘制状态栏,仅在状态栏canvas化开启时有效,实际被转发到了脚本编辑中。
+
+
+core.drawStatistics()
+绘制数据统计。将从脚本编辑中获得要统计的数据列表,再遍历所有地图进行统计。
+
+
+core.drawAbout() / core.drawPaint() / core.drawHelp()
+绘制关于界面,绘图模式,帮助界面。
+
+// ------ 动态创建画布相关的API ------ //
+
+
+core.ui.createCanvas(name, x, y, width, height, z)
+动态创建一个自定义画布。name为要创建的画布名,如果已存在则会直接取用当前存在的。
+x,y为创建的画布相对窗口左上角的像素坐标,width,height为创建的长宽。
+z值为创建的纵向高度(关系到画布之间的覆盖),z值高的将覆盖z值低的;系统画布的z值可在个性化中查看。
+返回创建的画布的context,也可以通过core.dymCanvas[name]或core.getContextByName获得。
+
+
+core.ui.relocateCanvas(name, x, y)
+重新定位一个自定义画布。x和y为画布的左上角坐标,name为画布名。
+
+
+core.ui.resizeCanvas(name, width, height, styleOnly)
+重新设置一个自定义画布的大小。width和height为新设置的宽高。
+styleOnly控制是否只修改画布的显示大小(而不修改画布的内部大小)。
+如果styleOnly为true,则只修改其显示大小(即canvas.style.width);
+否则,则会同时修改画布的显示大小和内部大小并清空画布内容。
+
+
+core.ui.deleteCanvas(name)
+删除一个自定义画布。
+
+
+core.ui.deleteAllCanvas()
+删除所有的自定义画布。
+```
+
+## utils.js
+
+utils.js是一个工具函数库,里面有各个样板中使用到的工具函数。
+
+```text
+core.replayText(text, need, times)
+将一段文字中的${}(表达式)进行替换。need和time一般可以直接忽略。
+
+
+core.replaceValue(value)
+对一个表达式中的特殊规则进行替换,如status:xxx等。
+请注意,此项不会对独立开关如switch:A进行替换。
+
+
+core.calValue(value, prefix, need, time)
+计算一个表达式的值,支持status:xxx等的计算。
+prefix为前缀(switch:xxx的独立开关使用),need和time一般可以直接忽略。
+
+
+core.unshift(a, b) / core.push(a, b)
+将b插入到列表a之前或之后。b可以是一个元素或者一个数组。
+
+
+core.decompress(value)
+解压缩一个字符串并进行JSON解析。value可能会被LZString或LZW算法进行压缩。
+返回解压后的JSON格式内容,如果无法解压则返回null。
+
+
+core.setLocalStorage(key, value)
+将一个键值对存入localStorage中,会立刻返回结果。
+此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。
+value为要存储的内容,存储前会被JSON转成字符串形式,并LZW算法进行压缩。
+如果value为null,则实际会调用core.removeLocalStorage()函数清除该key。
+localStorage为浏览器的默认存储,和存档无关,只有5M的空间大小。
+此函数立刻返回true或false,如果为false则代表存储失败,一般指的是空间满了。
+
+
+core.getLocalStorage(key, defaultValue)
+从localStorage中获得一个键的值,会立刻返回结果。
+此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。
+如果对应的键值不存在或为null,则会返回defaultValue。
+返回的结果会被调用core.decompress进行解压缩和JSON解析。
+
+
+core.removeLocalStorage(key)
+从localStorage中删除一个键的值,会立刻返回。
+此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。
+
+
+core.setLocalForage(key, value, successCallback, errorCallback)
+将一个键值对存入localForage中,异步返回结果。
+如果用户没有开启【新版存档】开关,则仍然会使用core.setLocalStorage()。
+localForage为一个开源库,项目地址 https://github.com/localForage/localForage
+一般存入的是indexedDB,这是一个浏览器的自带数据库,没有空间限制。
+successCallback和errorCallback均可选,表示该次存储成功或失败的回调,
+此函数为异步的,只能通过回调函数来获得存储的成功或失败信息。
+
+
+core.getLocalForage(key, defaultValue, successCallback, errorCallback)
+从localForage中获得一个键的值,异步返回结果。
+如果对应的键值不存在,则会使用defaultValue。
+如果获得成功,则会将core.decompress后的结果传入successCallback回调函数执行。
+errorCallback可选,如果失败,则会将错误信息传入errorCallback()。
+此函数是异步的,只能通过回调函数来获得读取的结果或错误信息。
+
+
+core.setGlobal(key, value)
+设置一个全局存储,适用于global:xxx。
+录像播放时将忽略此函数,否则直接调用core.setLocalStorage。
+
+
+core.getGlobal(key, value)
+获得一个全局存储,适用于global:xxx,支持录像。
+正常游戏时将使用core.getLocalStorage获得具体的数据,并将结果存放到录像中。
+录像播放时会直接从录像中获得对应的数据。
+
+
+core.clone(data, filter, recursion)
+深拷贝一个对象。有关浅拷贝,深拷贝,基本类型和引用类型等相关知识可参见:
+https://zhuanlan.zhihu.com/p/26282765
+filter为过滤函数,如果设置且不为null则需传递一个可接受(name, value)的函数,
+并返回true或false,表示该项是否应该被深拷贝。
+recursion表示该filter是否应递归向下传递,如果为true则递归函数也将传该filter。
+例如:
+core.clone(core.status.hero, function(name, value) {
+ return name == 'items' || typeof value == 'number';
+}, false);
+这个例子将会深拷贝勇士的属性和道具。
+
+
+core.splitImage(image, width, height)
+等比例切分一张图片。width和height为每张子图片的宽高。
+请确保原始图片的宽度和高度都是是width和height的倍数。
+此函数将返回一个一维数组,每一项都是一张切分好的图片,横向再纵向排列。
+例如4x3的图片按1x1切分得到一个长度为12的数组,按如下方式进行排列:
+0 1 2 3
+4 5 6 7
+8 9 10 11
+可以将很多需要的图片拼在一张大图上,然后在插件的_afterLoadResources中切分。
+切分好的图片再存入core.material.images.images中,这样可以少很多IO请求。
+
+
+core.formatDate(date) / core.formatDate2(date) / core.formatTime(time)
+格式化日期和时间。
+
+
+core.setTwoDigits(x)
+将x变成两位数。其实就是 parseInt(x) < 10 ? "0" + x : x
+
+
+core.formatBigNumber(x, onMap)
+大数据格式化。x为要格式化的内容,如果不合法会返回???。
+onMap标记是否在地图上调用,如果为真则尝试格式化成六位,否则五位。
+
+
+core.arrayToRGB(color) / core.arrayToRGBA(color)
+将一个颜色数组,例如[255,0,0,1]转成#FF0000或rgba(255,0,0,1)的形式。
+
+
+core.encodeRoute(route)
+录像压缩和解压缩。route为要压缩的路线数组。
+此函数将尽可能对录像进行压缩。对于无法识别的项目(比如自己添加的),将不压缩而原样放入。
+例如,["up","up","left","move:3:5","test:2333","getNext","item:bomb","down"]
+将被压缩成"U2LM3:5(test:2333)GIbomb:D"。
+自己添加的录像项只能由数字、大小写、下划线线、冒号等符号组成,否则无法正常压缩和解压缩。
+对于自定义内容(比如中文文本或数组)请使用JSON.stringify再core.encodeBase64处理。
+压缩的结果将再次进行LZString.compressToBase64()的压缩以进一步节省空间。
+
+
+core.decodeRoute(route)
+解压缩一个录像,返回解压完毕的路线数组。
+
+
+core.isset(v)
+判定v是不是null, undefined或NaN。
+请尽量避免使用此函数,而是直接判定 v == null (请注意 null==undefined !)
+
+
+core.subarray(a, b)
+判定数组b是不是数组a的一个前缀子数组。
+如果是,则返回a中除去b后的剩余数组,否则返回null。
+
+
+core.inArray(array, element)
+判定array是不是一个数组,以及element是否在该数组中。
+
+
+core.clamp(x, a, b)
+将x限定在[a,b]区间内。
+
+
+core.getCookie(name)
+获得一个cookie值,如果不存在该cookie则返回null。
+
+
+core.setStatusBarInnerHTML(name, value, css)
+设置一个状态栏的innerHTML。此函数会自动设置状态栏的文字放缩和斜体等效果。
+name为状态栏的名称,如atk, def等。需要是core.statusBar中的一个合法项。
+value为要设置到的数值,如果是数字则会先core.formatBigNumber()进行格式化。
+css可选,为增添的额外css内容,比如可以设定颜色等。
+
+
+core.strlen(str)
+计算某个字符串的实际长度。每个字符的长度,ASCII码视为1,中文等视为2。
+
+
+core.reverseDirection(direction)
+翻转方向,即"up"转成"down", "left"转成"right"等。
+
+
+core.matchWildcard(pattern, string)
+进行通配符的匹配判定,目前仅支持*(可匹配0或任意个字符)。比如"a*b*c"可以匹配"aa012bc"。
+
+
+core.encodeBase64(str) / core.decodeBase64(str)
+将字符串进行base64加密或解密。
+可用于解压缩录像数据
+
+
+core.convertBase(str, fromBase, toBase)
+任意进制转换。此函数可能执行的非常慢,慎用。
+
+
+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大法。
+但是,此函数会将生成的随机数值存入录像,因此如果调用次数太多则会导致录像文件过大。
+对于需要大量生成随机数,但又想使用真随机支持SL大法的(例如随机生成地图等),可以采用如下方式:
+ var x = core.rand2(100); for (var i = 0; i < x; i++) core.rand()
+即先生成一个真随机数,根据该数来推进伪随机的种子,这样就可以放心调用core.rand()啦。
+
+
+core.readFile(success, error, accept)
+读取一个本地文件内容。success和error分别为读取成功或失败的回调函数。
+accept如果设置则控制能选择的文件类型。
+iOS平台暂不支持读取文件操作。
+
+
+core.readFileContent(content)
+读取到的文件内容。此函数会被APP等调用,来传递文件的具体内容。
+
+
+core.download(filename, content)
+生成一个文件并下载。filename为文件名,content为具体的文件内容。
+iOS平台暂不支持下载文件操作。
+
+
+core.copy(data)
+将一段内容拷贝到剪切板。
+
+
+core.myconfirm(hint, yesCallback, noCallback)
+弹窗绘制一段提示信息并让用户确认。hint为提示信息。
+yesCallback和noCallback分别为确定和取消的回调函数。
+此函数和core.drawConfirmBox的区别主要在于:
+ - drawConfirmBox会清掉UI层原有的绘制信息,此函数不会清除。
+ - drawConfirmBox可以用键盘进行操作,此函数必须用鼠标点击。
+另外请注意:本函数的选择也不会进录像,一般用于全局的提示。
+如果需要在事件流中调用请使用显示确认框或显示选择项。
+
+
+core.myprompt(hint, value, callback)
+弹窗让用户输入一段内容。hint为提示信息,value为框内的默认填写内容。
+callback为用户点击确认或取消后的回调。
+如果用户点击了确认,则会把框内的内容(可能是空串)传递给callback,否则把null传递给callback。
+
+
+core.showWithAnimate(obj, speed, callback) / core.hideWithAnimate(obj, speed, callback)
+动画淡入或淡出一个对象。
+
+
+core.consoleOpened()
+检测当前的控制台是否处于开启状态。仅在全塔属性中的检查控制台开关开启时有效。
+此函数有可能会存在误伤行为,即没开过控制台仍认为开启过。
+
+
+core.hashCode(obj)
+计算一个对象的哈希值。
+
+
+core.same(a, b)
+判定a和b是否相同,包括类型相同和值相同。
+如果a和b都是数组,则会递归依次比较数组中的值;如果都是对象亦然。
+
+
+core.utils.http(type, url, formData, success, error, mimeType, responseType)
+发送一个异步HTTP请求。
+type为'GET'或者'POST';url为目标地址;formData如果是POST请求则为表单数据。
+success为成功后的回调,error为失败后的回调。
+mimeType和responseType如果设置将会覆盖默认值。
+
+
+lzw_encode(s) / lzw_decode(s)
+LZW压缩算法,来自https://gist.github.com/revolunet/843889
+```
diff --git a/README.md b/README.md
index da2183a4..17ab6be6 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
``` bash
├── /_server/ # 为可视化地图编辑器提供一些支持的目录
├── /docs/ # 文档目录
+├── /extensions/ # 拓展工具目录,发布到网站后不会加载
├── /libs/ # 系统库目录
│ ├─ /thirdparty/ # 游戏所用到的第三方库文件
│ ├─ actions.js # 处理用户交互的文件
@@ -25,6 +26,7 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
│ ├─ data.js # 记录了一些初始化信息
│ ├─ enemys.js # 记录了怪物的信息,包括特殊属性、伤害计算公式、临界值计算等。
│ ├─ events.js # 处理事件的文件,所有自定义事件都会在此文件中进行处理
+│ ├─ extensions.js # 加载拓展工具的文件
│ ├─ icons.js # 图标信息,会被转发到project下
│ ├─ items.js # 道具信息,会被转发到project下
│ ├─ loader.js # 动态加载JS代码、图片、音效等
@@ -55,6 +57,108 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏!
## 更新说明
+### 2019.12.31 HTML5魔塔样板V2.6.6
+
+* [x] 编辑器增加【最近使用的图块】的区域
+* [x] 编辑器拉伸到铺满全屏幕,还可以Ctrl+滚轮放缩
+* [x] 编辑器支持连续Ctrl+Z的撤销,Ctrl+Y的重做
+* [x] 新增tileset右键绑定宽高,以替代贴图模式
+* [x] 多重自动存档,可以连续A键读档
+* [x] 高层塔分区域支持
+* [x] 自绘状态栏点击事件
+* [x] 绘制的锁定模式
+* [x] 等待用户操作增设分歧选项
+* [x] 增设压缩模式,会对图片等进行zip压缩
+* [x] 追加素材现在可以同时进行自动注册
+* [x] 可以复制和粘贴怪物或道具的属性
+* [x] 折叠素材时设置每一列个数
+* [x] 标题界面和显示选择项时光标跟随鼠标
+* [x] 修复所有已知的bug,大量细节优化
+
+### 2019.12.1 HTML5魔塔样板V2.6.5
+
+* [x] 事件:设置怪物属性;穿脱装备
+* [x] 新值块:enemy:xxx:atk可获得怪物数据
+* [x] 新值块:blockId:x,y获得某点图块ID
+* [x] 部分事件预编译,加快执行速度
+* [x] 在系统设置中可以设置bgm的播放音量
+* [x] 通关事件可以不退出游戏
+* [x] 失败时允许直接读取自动存档
+* [x] NPC48自动注册可以自动绑定faceIds
+* [x] 编辑器Alt+1-9存图块,1-9读取图块
+* [x] 编辑器现在可以跨楼层复制粘贴图块了
+* [x] 可以对flags.进行自动补全
+* [x] 部分Bug修复,大量细节优化
+
+### 2019.10.29 HTML5魔塔样板V2.6.4
+
+* [x] 自动事件,多事件页
+* [x] 增加开场logo动画
+* [x] 拓展:游戏时动态修改地图和怪物数据
+* [x] 插件:道具商店,支持买入和卖出道具
+* [x] 编辑器可以搜索变量出现位置
+* [x] 变量的中文替换
+* [x] 可以给图块绑定自定义脚本,碰触时触发
+* [x] 编辑器右键可以绑定机关门和出生点
+* [x] 支持多个drawTip同时出现
+* [x] 闪烁光标同时支持多个同时存在
+* [x] 插件:镜头平滑移动,默认禁用
+* [x] 素材的快速追加
+* [x] 批量导出动画
+* [x] 部分Bug修复,大量细节优化
+
+### 2019.7.24 V2.6.3
+
+* [x] 标题界面大幅美化,增加闪烁光标,支持键盘开始游戏
+* [x] 事件编辑器支持自动补全,能对flag和API列表等进行补全
+* [x] 剧情文本中\\c修改字体大小,\\d和\\e切换粗体和斜体
+* [x] 事件:设置视角&移动视角
+* [x] 可以指定显示选择项的出现条件并动态生成
+* [x] 楼层传送器的平面传送模式(哪里离开飞回到哪里)
+* [x] UI绘制事件增添绘制圆和绘制圆边框
+* [x] 所有的UI绘制事件均可以双击预览
+* [x] 播放BGM事件可以一直持续播放直到下次调用
+* [x] \f立绘支持alpha值
+* [x] 支持在脚本编辑中直接flags.xxx调用自定义变量
+* [x] 首次获得道具将给予提示
+* [x] 等待用户操作支持滚轮,视为PgUp和PgDn
+* [x] 脚本编辑器语法错误将禁止保存
+* [x] 录像播放时B键查看数据统计
+* [x] 所有已知bug的修复,大量细节优化
+
+### 2019.6.7 V2.6.2
+
+* [x] 可以拖动地图上的图块和事件,复制剪切和跨楼层粘贴
+* [x] 新增事件的地图选点功能,可以在地图上选择落点
+* [x] 现在素材区可以进行折叠与自动换列了
+* [x] 新增UI绘制系列事件,并且可以进行预览
+* [x] 显示文本事件的标题解析
+* [x] 新增常用工具:额外素材合并工具
+* [x] 进一步提升24倍速的播放速度
+* [x] 楼层转换增加对称点
+* [x] 增加编辑器快捷键说明,H键查看
+* [x] 文档-事件增加事件编辑器截图
+* [x] 大量细节优化,所有已知的Bug修复
+
+### 2019.5.2 V2.6.1
+
+* [x] 区域优化的录像播放功能,R键使用
+* [x] 强制战斗可以指定怪物坐标,将自动隐藏并执行该点战后事件
+* [x] flag:xxx也支持中文,例如 flag:2楼机关门
+* [x] 增加文件名映射,可以用中文映射到某个图片或bgm文件并使用
+* [x] 勇士宽度可以超过32(例如48x48的勇士行走图)
+* [x] 现在允许修改floorId和图块ID了(在表格下方)
+* [x] 增加事件:自动存档,返回标题界面;部分事件优化
+* [x] 商店长按空格可以连续加点
+* [x] 增设global:xxx使用全局存储,可被录像支持
+* [x] 支持\b[hero]和\b[null,x,y]来自动调整上下方向
+* [x] 支持\t[yellowKey]等只显示图标而没有标题
+* [x] 编辑器中前景层对于有事件的点半透明显示
+* [x] 存档改成1000页,长按上下页可快速翻页
+* [x] 录像播放初始默认暂停,N键可以单步执行
+* [x] 增设本地API文档,部分API和事件的优化
+* [x] 所有已知的bug修复,大量细节优化
+
### 2019.4.13 V2.6
* [x] 拆分整个项目,大幅重构代码,新增大量API
diff --git a/_docs/V2.0.md b/_docs/V2.0.md
index f10852d8..00d1084e 100644
--- a/_docs/V2.0.md
+++ b/_docs/V2.0.md
@@ -1,6 +1,6 @@
# V2.0版本介绍
-?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6*,上次更新时间:* {docsify-updated} *
目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。
diff --git a/_docs/api.md b/_docs/api.md
index 3efce8eb..4965d648 100644
--- a/_docs/api.md
+++ b/_docs/api.md
@@ -1,6 +1,6 @@
# 附录:API列表
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。
@@ -57,7 +57,6 @@ core.platform.isPC (是否是电脑端)
core.platform.isAndroid (是否是安卓端)
core.platform.isIOS (是否是iOS端)
core.platform.useLocalForage (是否开启了新版存档)
-core.platform.extendKeyBoard (是否开启了拓展键盘)
core.domStyle
@@ -339,7 +338,7 @@ core.setHeroMoveInterval(callback)
core.moveOneStep(x, y)
-每走完一步后执行的操作,被转发到了脚本编辑中。
+每走完一步后执行的操作,被转发到了脚本编辑中,执行脚本编辑moveOneStep中的内容。
core.moveAction(callback)
@@ -350,6 +349,7 @@ core.moveAction(callback)
core.moveHero(direction, callback)
令勇士朝一个方向行走。如果设置了callback,则只会行走一步,并执行回调。
否则,将一直朝该方向行走,直到core.status.heroStop为true为止。
+direction可为"up","down","right","left",分别对应上,下,右,左。
core.isMoving()
@@ -362,10 +362,11 @@ core.waitHeroToStop(callback)
core.turnHero(direction)
转向。如果设置了direction则会转到该方向,否则会右转。该函数会自动计入录像。
+direction可为"up","down","right","left",分别对应上,下,右,左。
core.moveDirectly(destX, destY)
-尝试瞬间移动到某点,被转发到了脚本编辑中。
+尝试瞬间移动到某点,被转发到了脚本编辑中,执行脚本编辑中的内容。
此函数返回非负值代表成功进行瞬移,返回值是省略的步数;如果返回-1则代表没有成功瞬移。
@@ -500,12 +501,12 @@ core.syncSave(type) / core.syncLoad()
core.saveData()
-获得要存档的内容,实际转发到了脚本编辑中。
+获得要存档的内容,实际转发到了脚本编辑中,执行脚本编辑中的内容。
core.loadData(data, callback)
实际执行一次读档行为,data为读取到的数据,callback为执行完毕的回调。
-实际转发到了脚本编辑中。
+实际转发到了脚本编辑中,执行脚本编辑中的内容。
core.getSave(index, callback)
@@ -535,19 +536,23 @@ core.removeSave(index)
// ------ 属性、状态、位置、变量等 ------ //
core.setStatus(name, value)
-设置勇士当前的某个属性。
+设置勇士当前的某个属性,name可为"atk","def","hp"等。
+如core.setStatus("atk", 100)则为设置勇士攻击为100。
core.addStatus(name, value)
-加减勇士当前的某个属性。等价于 core.setStatus(name, core.getStatus(name) + value)
+加减勇士当前的某个属性,name可为"atk","def","hp"等。
+如core.addStatus("atk", 100)则为增加勇士攻击100点。
+等价于 core.setStatus(name, core.getStatus(name) + value)。
core.getStatus(name)
-获得勇士的某个原始属性值。
+获得勇士的某个原始属性值,该值不受百分比增幅影响。
+譬如你有一件道具加10%的攻击,你可以使用该函数获得你的攻击被增幅前的数值
core.getStatusOrDefault(status, name)
-尝试从status中获得某个原始属性值;如果status为null或不存在对应属性值则从勇士属性中获取。
+尝试从status中获得某个原始属性值,该值不受百分比增幅影响;如果status为null或不存在对应属性值则从勇士属性中获取。
此项在伤害计算函数中使用较多,例如传递新的攻击和防御来计算临界和1防减伤。
@@ -573,12 +578,14 @@ core.getBuff(name)
core.setHeroLoc(name, value, noGather)
-设置勇士位置属性。name只能为'x', 'y'和'direction'之一。
+设置勇士位置属性。name只能为'x'(勇士x坐标), 'y'(勇士y坐标)和'direction'(勇士朝向)之一。
如果noGather为true,则不会聚集所有的跟随者。
+譬如core.setHeroLoc("x", 1, true)则为设置勇士x坐标为1,不聚集所有跟随者。
core.getHeroLoc(name)
获得勇士的某个位置属性。如果name为null则直接返回core.status.hero.loc。
+譬如core.getHeroLoc("x")则返回勇士当前x坐标
core.getLvName(lv)
@@ -587,19 +594,26 @@ core.getLvName(lv)
core.setFlag(name, value)
设置某个自定义变量或flag。如果value为null则会调用core.removeFlag进行删除。
+这里的变量与事件中使用的变量等价
+譬如core.setFlag("xxx",1)则为设置变量xxx为1。
core.addFlag(name, value)
加减某个自定义的变量或flag。等价于 core.setFlag(name, core.getFlag(name, 0) + value)
+这里的变量与事件中使用的变量等价
+譬如core.addFlag("xxx",1)则为增加变量xxx1
core.getFlag(name, defaultValue)
-获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue值。
+获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue的值。
+这里的变量与事件中使用的变量等价
+譬如core.getFlag("xxx",1)则为获得变量xxx的值,如变量xxx不存在则返回1
core.hasFlag(name)
判定是否拥有某个自定义变量或flag。等价于 !!core.getFlag(name, 0)
-
+这里的变量与事件中使用的变量等价
+譬如core.hasFlag("xxx",1)则为判断变量xxx是否存在
core.removeFlag(name)
删除一个自定义变量或flag。
@@ -620,6 +634,8 @@ core.setWeather(type, level)
core.setCurtain(color, time, callback)
更改画面色调。color为更改到的色调,是个三元或四元组;time为渐变时间,0代表立刻切换。
+譬如core.setCurtain([255,255,255,1], 0)即为无回调无等待更改画面色调为白色
+
core.screenFlash(color, time, times, callback)
@@ -655,9 +671,9 @@ core.clearStatusBar()
清空状态栏的数据。
-core.updateStatusBar()
+core.updateStatusBar(doNotCheckAutoEvents)
更新状态栏,被转发到了脚本编辑中。此函数还会根据是否在回放来设置工具栏的图标。
-
+如果doNotCheckAutoEvents为true则此时不检查自动事件。
core.showStatusBar() / core.hideStatusBar(showToolbox)
显示和隐藏状态栏。
@@ -708,7 +724,7 @@ special为要测试的内容,允许接收如下类型参数:
core.getSpecials()
-获得所有特殊属性的列表。实际上被转发到了脚本编辑中。
+获得所有特殊属性的列表。实际上被转发到了脚本编辑中,执行脚本编辑中的内容。
core.getSpecialText(enemy)
@@ -748,7 +764,7 @@ number为要计算的临界值数量,不填默认为1。
core.getDefDamage(enemy, k, x, y, floorId)
-获得某个怪物的k防减伤值。k可不填默认为1。
+获得某个怪物的k防减伤值。k可不填默认为1,x,y,floorId为当前xy坐标和楼层。
core.getEnemyInfo(enemy, hero, x, y, floorId)
@@ -765,10 +781,6 @@ hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero,
从V2.5.5开始,该函数也允许直接返回一个数字,代表战斗伤害值,此时回合数将视为0。
-core.updateEnemys()
-更新怪物数据。该函数实际被转发到了脚本编辑中。详见文档-事件-更新怪物数据。
-
-
core.getCurrentEnemys(floorId)
获得某个楼层不重复的怪物信息,floorId不填默认为当前楼层。该函数会被怪物手册所调用。
该函数将返回一个列表,每一项都是一个不同的怪物,按照伤害值从小到大排序。
@@ -776,7 +788,8 @@ core.getCurrentEnemys(floorId)
core.hasEnemyLeft(enemyId, floorId)
-检查某个楼层是否还有剩余的(指定)怪物。floorId为楼层ID,可忽略表示当前楼层。
+检查某个楼层是否还有剩余的(指定)怪物。
+floorId为楼层ID,可忽略表示当前楼层。也可以填数组如["MT0","MT1"]同时检测多个楼层。
enemyId如果不填或null则检查是否剩余任何怪物,否则只检查是否剩余指定的某类怪物。
```
@@ -806,16 +819,16 @@ seed为开始时要设置的的种子,route为要开始播放的录像,callb
core.setInitData()
根据难度分歧来初始化难度,包括设置flag:hard,设置初始属性等。
-该函数实际被转发到了脚本编辑中。
+该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.win(reason, norank)
游戏胜利,reason为结局名,norank如果为真则该结局不计入榜单。
-该函数实际被转发到了脚本编辑中。
+该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.lose(reason)
-游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中。
+游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.gameOver(ending, fromReplay, norank)
@@ -855,7 +868,7 @@ id为怪物的ID,x和y为怪物坐标,force如果为真将强制战斗,cal
core.beforeBattle(enemyId, x, y)
-战前事件。实际被转发到了脚本编辑中,可以在这里加上一些战前特效。
+战前事件。实际被转发到了脚本编辑中,执行脚本编辑中的内容,可以用于加上一些战前特效。
此函数在“检测能否战斗和自动存档”【之后】执行。
如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。
此函数返回true则将继续本次战斗,返回false将不再战斗。
@@ -863,7 +876,7 @@ core.beforeBattle(enemyId, x, y)
core.afterBattle(enemyId, x, y, callback)
战后事件,将执行扣血、加金币经验、特殊属性处理、战后事件处理等操作。
-实际被转发到了脚本编辑中。
+实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.openDoor(x, y, needKey, callback)
@@ -872,16 +885,17 @@ core.openDoor(x, y, needKey, callback)
core.afterOpenDoor(doorId, x, y, callback)
-开完一个门后执行的事件,实际被转发到了脚本编辑中。
+开完一个门后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.getItem(id, num, x, y, callback)
获得若干个道具。itemId为道具ID,itemNum为获得的道具个数,不填默认为1。
-x和y为道具点的坐标,如果设置则会擦除地图上的该点。
+x和y为道具点的坐标,如果设置则会擦除地图上的该点,也可不填。
+譬如core.getItem("yellowKey",2)会直接获得两把黄钥匙。
core.afterGetItem(id, x, y, callback)
-获得一个道具后执行的事件,实际被转发到了脚本编辑中。
+获得一个道具后执行的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.getNextItem(noRoute)
@@ -918,7 +932,7 @@ core.pushBox(data)
core.afterPushBox()
-推箱子之后触发的事件,实际被转发到了脚本编辑中。
+推箱子之后触发的事件,实际被转发到了脚本编辑中,执行脚本编辑中的内容。
core.changeLight(id, x, y)
@@ -951,10 +965,11 @@ core.startEvents(list, x, y, callback)
此函数将调用core.setEvents,然后停止勇士,再执行core.doAction()。
-core.doAction()
+core.doAction(keepUI)
执行下一个自定义事件。
此函数将检测事件列表是否全部执行完毕,如果是则执行回调函数。
否则,将从事件列表中弹出下一个事件,并调用core.doEvent进行执行。
+如果keepUI为true,则不会清掉UI层和selector,适合于自己用脚本的绘制。
core.insertAction(action, x, y, callback, addToLast)
@@ -972,6 +987,15 @@ core.getCommonEvent(name)
core.recoverEvents(data)
恢复事件现场。一般用于呼出怪物手册、呼出存读档页面等时,恢复事件执行流。
+
+core.checkAutoEvents()
+检测自动事件并执行。
+
+
+core.precompile(events)
+尝试预编译一段事件。
+
+
// ------ 点击状态栏图标时执行的一些操作 ------ //
core.openBook(fromUserAction)
@@ -1019,15 +1043,21 @@ core.follow(name) / core.unfollow(name)
core.setValue(name, value, prefix) / core.addValue(name, value, prefix)
设置/增减某个数值。name可以是status:xxx,item:xxx或flag:xxx。
-value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用。
+value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。
core.doEffect(effect, need, times)
执行一个effect操作。该函数目前仅被全局商店的status:xxx+=yyy所调用。
+core.setEnemy(id, name, value, prefix)
+设置一个怪物属性。id为怪物的ID,name为要设置的项,比如hp,atk,def等等。
+value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用,脚本中一般忽略。
+
+
core.setFloorInfo(name, values, floorId, prefix)
-设置某层楼的楼层属性。
+设置某层楼的楼层属性,其中name为该楼层属性对应的条目,values为要设置的值,floorId为楼层id,prefix一般直接忽略。
+譬如core.setFloorInfo("name","4", "MT1")则为设置MT1显示在状态栏中的层数为4
core.setGlobalAttribute(name, value)
@@ -1186,8 +1216,9 @@ core.addItem(itemId, itemNum)
core.getEquipTypeByName(name)
-根据装备位名称来找到一个空的装备孔,适用于多重装备。
+根据装备位名称来找到一个空的装备孔,适用于多重装备,装备位名称可在全塔属性中设置。
如果没有一个装备孔是该装备名称,则返回-1。
+譬如:core.getEquipTypeByName("武器")默认返回全塔属性中武器对应的装备孔号0。
core.getEquipTypeById(equipId)
@@ -1200,11 +1231,12 @@ core.canEquip(equipId, hint)
core.loadEquip(equipId, callback)
-穿上某个装备。
+穿上某个装备,equipId为装备id。
core.unloadEquip(equipType, callback)
脱下某个装备孔的装备。
+譬如core.unloadEquip(0)则为脱下0号装备孔中的装备,默认0号装备孔对应“武器”,1号装备孔对应“盾牌”
core.compareEquipment(compareEquipId, beComparedEquipId)
@@ -1219,6 +1251,10 @@ core.quickSaveEquip(index)
core.quickLoadEquip()
读取当前套装。index为读取的套装编号。
+
+
+core.getEquippedStatus(name)
+获得装备直接增加的属性数据。
```
## loader.js
@@ -1276,7 +1312,7 @@ map为存档信息,如果某项在map中不存在则会从core.floors中读取
core.getNumberById(id)
-给定一个图块ID,找到对应的数字。
+给定一个图块ID,找到图块对应的图块编号。
core.initBlock(x, y, id, addInfo, eventFloor)
@@ -1305,6 +1341,12 @@ core.loadMap(data, floorId)
从data中读取楼层数据,并调用core.loadFloor()进行初始化。
+core.removeMaps(fromId, toId)
+删除某个区域的地图。调用此函数后,这些楼层将不可飞,不可被浏览地图,也不计入存档。
+fromId和toId为要删除的起终点楼层ID;toId也可以不填代表只删除某一层。
+此函数适用于高层塔的砍层,例如每100层一个区域且互相独立,不可再返回的情况。
+
+
core.resizeMap(floorId)
根据某层楼的地图大小来调整大地图的画布大小。floorId可为null表示当前层。
@@ -1412,7 +1454,7 @@ toDraw为要绘制到的信息(可为null,或为一个画布名),包括
// ------ 获得某个点的图块信息 ------ //
core.noPass(x, y, floorId)
-判定某个点是否有noPass的图块。
+判定某个点是否有noPass(不可通行)的图块。
core.npcExists(x, y, floorId)
@@ -1420,7 +1462,7 @@ core.npcExists(x, y, floorId)
core.terrainExists(x, y, id, floorId)
-判定某个点是否有(指定的)地形存在。
+判定某个点是否有(id对应的)地形存在。
如果id为null,则只要存在terrains即为真,否则还会判定对应点的ID。
@@ -1433,7 +1475,7 @@ core.nearStair()
core.enemyExists(x, y, id, floorId)
-判定某个点是否有(指定的)怪物存在。
+判定某个点是否有(id对应的)怪物存在。
如果id为null,则只要存在怪物即为真,否则还会判定对应点的怪物ID。
请注意,如果需要判定某个楼层是否存在怪物请使用core.hasEnemyLeft()函数。
@@ -1490,14 +1532,17 @@ core.removeBlock(x, y, floorId)
core.removeBlockById(index, floorId)
+每个楼层的图块存成一个数组,index即为该数组中的索引,每个索引对应该地图中的一个图块
根据索引从地图的block数组中尽可能删除一个图块。floorId可不填或null表示当前楼层。
core.removeBlockByIds(floorId, ids)
+ids为由索引组成的数组,如[0,1]等
根据索引数组从地图的block数组中尽可能删除一系列图块。floorId可不填或null表示当前楼层。
core.canRemoveBlock(block, floorId)
+block为图块信息,可由core.getBlock获取
判定当前能否完全删除某个图块。floorId可不填或null表示当前楼层。
如果该点存在自定义事件,或者是重生怪,则不可进行删除。
@@ -1541,7 +1586,7 @@ number为要设置到的图块数字,x,y和floorId为目标点坐标和楼层
core.resetMap(floorId)
重置某层或若干层的地图和楼层属性。
-floorId可为某个楼层ID,或者一个楼层数组(同时重置若干层);如果不填则只重置当前楼层。
+floorId可为某个楼层ID,或者一个楼层数组如["MT1","MT2"](同时重置若干层);如果不填则只重置当前楼层。
// ------ 移动/跳跃图块,淡入淡出图块 ------ //
@@ -1585,6 +1630,12 @@ core.drawAnimate(name, x, y, callback)
此函数会返回一个动画id,可以通过core.stopAnimate()立刻停止该动画的播放。
+core.drawHeroAnimate(name, callback)
+绘制一个跟随勇士行动的动画。name为动画名,callback为绘制完毕的回调函数。
+此函数将播放动画音效,并异步开始绘制该动画。
+此函数会返回一个动画id,可以通过core.stopAnimate()立刻停止该动画的播放。
+
+
core.stopAnimate(id, doCallback)
立刻停止某个动画的播放。id为上面core.drawAnimate的返回值。
如果doCallback为真,则会执行该动画所对应的回调函数。
@@ -1614,11 +1665,16 @@ core.clearMap(name)
该函数的name也可以是'all',若为'all'则为清空所有系统画布。
-core.fillText(name, text, x, y, style, font)
+core.fillText(name, text, x, y, style, font, maxWidth)
在某个画布上绘制一段文字。
text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同)
+style可直接使用"red","white"等或用"rgba(255,255,255,1)"或用"#FFFFFF"等方式来获得字体对应的颜色
+font的格式为"20px Verdana"前者为字体大小,后者为字体
+如果maxWidth不为null,则视为文字最大宽度,如果超过此宽度则会自动放缩文字直到自适应为止。
请注意textAlign和textBaseline将决定绘制的左右对齐和上下对齐方式。
具体可详见core.setTextAlign()和core.setTextBaseline()函数。
+譬如:core.fillText("ui", "这是要描绘的文字", 10, 10, "red", "20px Verdana", 100)
+即是在ui图层上,以10,10为起始点,描绘20像素大小,Verdana字体的红色字,长度不超过100像素
core.fillBoldText(name, text, x, y, style, font)
@@ -1626,7 +1682,7 @@ core.fillBoldText(name, text, x, y, style, font)
core.fillRect(name, x, y, width, height, style)
-绘制一个矩形。style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同)
+绘制一个矩形。width, height为矩形宽高,style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同)
core.strokeRect(name, x, y, width, height, style, lineWidth)
@@ -1635,11 +1691,11 @@ lineWidth如果设置将调用core.setLineWidth()。(下同)
core.drawLine(name, x1, y1, x2, y2, style, lineWidth)
-绘制一条线。
+绘制一条线,x1y1为起始点像素,x2y2为终止点像素。
core.drawArrow(name, x1, y1, x2, y2, style, lineWidth)
-绘制一个箭头。
+绘制一个箭头,x1y1为起始点像素,x2y2为终止点像素。
core.setFont(name, font) / core.setLineWidth(name, lineWidth)
@@ -1661,7 +1717,7 @@ core.setFillStyle(name, style) / core.setStrokeStyle(name, style)
core.setTextAlign(name, align)
-设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center'。
+设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center',分别对应左对齐,右对齐,居中。
默认为'left'。
@@ -1692,6 +1748,13 @@ core.drawImage(name, image, x, y, w, h, x1, y1, w1, h1)
http://www.w3school.com.cn/html5/canvas_drawimage.asp
这里的image允许传一个图片,画布。也允许传递图片名,将从你导入的图片中获取图片内容。
+
+core.drawIcon(name, id, x, y, w, h)
+在一张画布上绘制一个图标。
+id为注册过的图标ID,也可以使用状态栏的图标ID,例如lv, hp, up, save, settings等。
+x和y为绘制的左上角坐标;w和h可选为绘制的宽高,如果不填或null则使用该图标的默认宽高。
+
+
// ------ 具体的某个UI界面的绘制 ------ //
core.closePanel()
结束一切事件和UI绘制,关闭UI窗口,返回游戏。
@@ -1702,16 +1765,21 @@ core.clearUI()
重置UI窗口。此函数将清掉所有的UI帧动画和光标,清空UI画布,并将alpha设为1。
-core.drawTip(text, id)
+core.drawTip(text, id, clear)
在左上角以气泡的形式绘制一段提示。
text为文字内容,仅支持${}的表达式计算,不支持换行和变色。
id可选,为同时绘制的图标ID,如果不为null则会同时绘制该图标(仅对32x32的素材有效)。
也可以使用状态栏的图标ID,例如lv, hp, up, save, settings等。
+如果clear为true,则会清空当前所有正在显示的提示。
+
+
+core.clearTip()
+清空当前所有正在显示的提示。
core.drawText(content, callback)
绘制一段文字。contents为一个字符串或一个字符串数组,callback为全部绘制完毕的回调。
-支持所有的文字效果(如\n,${},\r,\\i等),也支持\t和\b的语法。
+支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t和\b的语法。
如果当前在事件处理中或录像回放中,则会自动转成core.insertAction处理。
不建议使用该函数,如有绘制文字的需求请尽量使用core.insertAction()插入剧情文本事件。
@@ -1736,7 +1804,8 @@ posInfo如果不为null则是一个含position, px和py的对象,表示一个
core.drawTextContent(ctx, content, config)
根据配置在某个画布上绘制一段文字。此函数会被core.drawTextBox()所调用。
ctx为画布名或画布本身,如果不设置则会忽略该函数。
-content为要绘制的文字内容,支持所有的文字效果(如\n,${},\r,\\i等),但不支持支持\t和\b的语法。
+content为要绘制的文字内容,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等)
+ ,但不支持支持\t和\b的语法。
config为绘制的配置项,目前可以包括如下几项:
- left, top:在该画布上绘制的左上角像素位置,不设置默认为(0,0)。
> 该函数绘制时会将textBaseline设置为'top',因此只需要考虑第一个字的左上角位置。
@@ -1745,13 +1814,14 @@ config为绘制的配置项,目前可以包括如下几项:
- bold:是否粗体。如果不设置默认为false。
- align:文字对齐方式,仅在maxWidth设置时有效,默认为'left'。
- fontSize:字体大小,如果不设置则使用剧情文本设置中的正文字体大小。
- - lineHeight:绘制的行距值,如果不设置则使用fontSize*1.3(即1.3被行距)。
+ - lineHeight:绘制的行距值,如果不设置则使用fontSize*1.3(即1.3倍行距)。
- time:打字机效果。若不为0,则会逐个字进行绘制,并设置core.status.event.interval定时器。
+ - interval:字符间的间距。值表示绘制每个字符之间间隔的距离,默认为0。
core.drawTextBox(content, showAll)
绘制一个对话框。content为一个字符串或一个字符串数组。
-支持所有的文字效果(如\n,${},\r,\\i等),也支持\t和\b的语法。
+支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t和\b的语法。
该函数将使用用户在剧情文本设置中的配置项进行绘制。
实际执行时,会计算文本框宽度并绘制背景,绘制标题和头像,再调用core.drawTextContent()绘制正文内容。
showAll可选,如果为true则不会使用打字机效果而全部显示,主要用于打字机效果的点击显示全部。
@@ -1759,7 +1829,7 @@ showAll可选,如果为true则不会使用打字机效果而全部显示,主
core.drawScrollText(content, time, lineHeight, callback)
绘制一个滚动字幕。content为绘制内容,time为总时间(默认为5000),lineHeight为行距比例(默认为1.4)。
-滚动字幕将绘制在UI上,支持所有的文字效果(如\n,${},\r,\\i等),但不支持\t和\b效果。
+滚动字幕将绘制在UI上,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),但不支持\t和\b效果。
可以通过剧情文本设置中的align控制是否居中绘制,offset控制其距离左边的偏移量。
@@ -1771,7 +1841,7 @@ core.textImage(content, lineHeight)
core.drawChoices(content, choices)
绘制一个选项框。
-content可选,为选项上方的提示文字,支持所有的文字效果(如\n,${},\r,\\i等),也支持\t效果。
+content可选,为选项上方的提示文字,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),也支持\t。
choices必选,为要绘制的选项内容,是一个列表。其中的每一项:
- 可以是一个字符串,表示选项文字,将使用剧情文本设置中的正文颜色来绘制,仅支持${}表达式计算。
- 或者是一个包含text, color和icon的对象。
@@ -1838,11 +1908,14 @@ z值为创建的纵向高度(关系到画布之间的覆盖),z值高的将
core.ui.relocateCanvas(name, x, y)
-重新定位一个自定义画布。x和y为画布的左上角坐标。
+重新定位一个自定义画布。x和y为画布的左上角坐标,name为画布名。
-core.ui.resizeCanvas(name, width, height)
-重新设置一个自定义画布的大小。width和height为新设置的宽高。此操作会清空画布。
+core.ui.resizeCanvas(name, width, height, styleOnly)
+重新设置一个自定义画布的大小。width和height为新设置的宽高。
+styleOnly控制是否只修改画布的显示大小(而不修改画布的内部大小)。
+如果styleOnly为true,则只修改其显示大小(即canvas.style.width);
+否则,则会同时修改画布的显示大小和内部大小并清空画布内容。
core.ui.deleteCanvas(name)
@@ -1862,6 +1935,11 @@ core.replayText(text, need, times)
将一段文字中的${}(表达式)进行替换。need和time一般可以直接忽略。
+core.replaceValue(value)
+对一个表达式中的特殊规则进行替换,如status:xxx等。
+请注意,此项不会对独立开关如switch:A进行替换。
+
+
core.calValue(value, prefix, need, time)
计算一个表达式的值,支持status:xxx等的计算。
prefix为前缀(switch:xxx的独立开关使用),need和time一般可以直接忽略。
@@ -1914,6 +1992,17 @@ errorCallback可选,如果失败,则会将错误信息传入errorCallback()
此函数是异步的,只能通过回调函数来获得读取的结果或错误信息。
+core.setGlobal(key, value)
+设置一个全局存储,适用于global:xxx。
+录像播放时将忽略此函数,否则直接调用core.setLocalStorage。
+
+
+core.getGlobal(key, value)
+获得一个全局存储,适用于global:xxx,支持录像。
+正常游戏时将使用core.getLocalStorage获得具体的数据,并将结果存放到录像中。
+录像播放时会直接从录像中获得对应的数据。
+
+
core.clone(data, filter, recursion)
深拷贝一个对象。有关浅拷贝,深拷贝,基本类型和引用类型等相关知识可参见:
https://zhuanlan.zhihu.com/p/26282765
@@ -2013,6 +2102,7 @@ core.matchWildcard(pattern, string)
core.encodeBase64(str) / core.decodeBase64(str)
将字符串进行base64加密或解密。
+可用于解压缩录像数据
core.convertBase(str, fromBase, toBase)
@@ -2035,8 +2125,9 @@ num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一
即先生成一个真随机数,根据该数来推进伪随机的种子,这样就可以放心调用core.rand()啦。
-core.readFile(success, error)
+core.readFile(success, error, accept)
读取一个本地文件内容。success和error分别为读取成功或失败的回调函数。
+accept如果设置则控制能选择的文件类型。
iOS平台暂不支持读取文件操作。
@@ -2087,7 +2178,16 @@ core.same(a, b)
如果a和b都是数组,则会递归依次比较数组中的值;如果都是对象亦然。
-core.utils.http(type, url, formData, success, error, mimeType, responseType)
+core.unzip(blobOrUrl, success, error, convertToText)
+解压一个zip文件。
+blobOrUrl为传入的二进制zip文件Blob格式,或zip文件的地址。
+success为成功后的回调,接收 文件名-文件内容 形式的对象,即
+{"filename1": ..., "filename2": ...}
+error为失败的回调,接收参数message为错误信息。
+convertToText如果为true则会将每个文件内容转成纯文本而不是二进制格式。
+
+
+core.http(type, url, formData, success, error, mimeType, responseType)
发送一个异步HTTP请求。
type为'GET'或者'POST';url为目标地址;formData如果是POST请求则为表单数据。
success为成功后的回调,error为失败后的回调。
diff --git a/_docs/element.md b/_docs/element.md
index 4fed9b92..2b386a88 100644
--- a/_docs/element.md
+++ b/_docs/element.md
@@ -1,6 +1,6 @@
# 元件说明
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。
@@ -282,10 +282,13 @@ floorId指定的是目标楼层的唯一标识符(ID)。
- 使用`${}`来计算一个表达式的值,如`${status:atk+status:def}`。
- 使用`\f[...]`来同时插入一张立绘图,如`\f[1.png,100,200]`。
- 使用`\\i[...]`来在对话框中绘制一个图标,如`\\i[fly]`。
+- 使用`\\c[...]`来修改字体大小,如`\\b[16]`。
+- 使用`\\d`来加粗或者取消粗体。
+- 使用`\\e`来加斜体或取消斜体。
从V2.5.2开始,也允许绘制一张头像图在对话框中,只要通过`\t[1.png]`或`\t[标题,1.png]`的写法。
-**使用`\\i[...]`绘制图标请注意:在事件块中,允许只写一个反斜杠`\i`,系统会自动转义成`\\i`;但是在脚本中必须两个反斜杠都写上!**
+**使用`\\i,\\c,\\d,\\e`时请注意:在事件块中,允许只写一个反斜杠`\`,系统会自动转义成`\\`;但是在脚本中必须两个反斜杠都写上!**
详细信息请参见[剧情文本控制](event#text:显示一段文字(剧情))中的说明。
diff --git a/_docs/event.md b/_docs/event.md
index bb586464..cce0cbe6 100644
--- a/_docs/event.md
+++ b/_docs/event.md
@@ -1,6 +1,6 @@
# 事件
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
本章内将对样板所支持的事件进行介绍。
@@ -24,7 +24,7 @@
它能通过拖动、复制粘贴等方式帮助你快速生成事件列表,而不用手动打大量字符。
-下述所说的都是在事件编辑器右边所展示的,该事件的代码化写法。
+下述所说的都是在事件编辑器右边所展示的,该事件的代码化写法;部分增加了可视化事件编辑器的截图示意(感谢秋橙的制作)。
强烈建议要对每个事件的写法进行了解,因为在脚本编辑,`insertAction`等地方需要插入自定义事件时,还是很有必要的。
@@ -154,6 +154,8 @@
]
```
+
+
该项可以简写成直接的字符串的形式,即下面这种方式也是可以的:
``` js
@@ -188,6 +190,10 @@
从V2.5.2以后,新增了绘制大头像的功能。绘制大头像图的基本写法是`\t[1.png]`或者`\t[标题,1.png]`。
+从V2.6开始,所有图块都允许只写ID,对于非怪物则仅当图块属性中设置了name才有标题(否则不显示标题)。
+
+另外注意的是,名字可以用null从而只显示动画而不显示标题。
+
``` js
[
"一段普通文字",
@@ -198,10 +204,15 @@
"\t[小妖精,fairy]这是一段小妖精说的话,使用仙子(fairy)的图标",
"\t[你赢了]直接显示标题为【你赢了】",
"\t[1.png]绘制1.png这个头像图",
- "\t[标题,1.png]同时绘制标题和1.png这个头像图"
+ "\t[标题,1.png]同时绘制标题和1.png这个头像图",
+ "\t[sword1]获得铁剑,没有标题",
+ "\t[man]没有标题的npc动画",
+ "\t[null,greenSlime]只绘制怪物动画而不显示标题"
]
```
+
+
!> 大头像的头像图需要在全塔属性中注册,且必须是png格式,不可以用jpg或者其他格式,请自行转换。
除此以外,我们还能实现“对话框效果”,只要有`\b[...]`就可以。
@@ -227,9 +238,7 @@
]
```
-从V2.6开始,`\b`提供了更多功能,包括:
-
-- `\b[hero]`
+
!> `\t[...]`必须在`\b[...]`前面!不然两者都无法正常显示。
@@ -243,10 +252,14 @@
]
```
+
+
从V2.5.3以后,也可以使用`\f[...]`来同时绘制一张图片。
其基本写法是`\f[img,x,y]`,或者`\f[img,x,y,w,h]`,或者`\f[img,sx,sy,sw,sh,x,y,w,h]`。
+从V2.6.3开始,也可以在最后加上alpha值,即`\f[img,sx,sy,sw,sh,x,y,w,h,alpha]`。
+
需要注意的是,这个图片是绘制在UI层上的,下一个事件执行时即会擦除;同时如果使用了\t的图标动画效果,重叠的地方也会被图标动画给覆盖掉。
``` js
@@ -254,10 +267,13 @@
"\t[勇士]\b[up,hero]\f[1.png,100,100]以(100,100)为左上角绘制1.png图片",
"\t[hero]\f[1.png,100,100]\f[2.png,300,300]同时绘制了两张图片",
"\f[1.png,100,100,300,300]也可以填写宽高,这样会把图片强制进行放缩到指定的宽高值",
- "\f[1.png,64,64,128,128,100,100,128,128]裁剪1.png上以(64,64)开始的128x128图片,并绘制到画布的(100,100)处"
+ "\f[1.png,64,64,128,128,100,100,128,128]裁剪1.png上以(64,64)开始的128x128图片,并绘制到画布的(100,100)处",
+ "\f[1.png,64,64,128,128,100,100,128,128,0.5]同上,不透明度0.5",
]
```
+
+
从V2.5.5以后,也可以使用`\\i[...]`来在对话框中绘制一个图标。
这里可以使用一个合法ID(32x48图块除外),或使用一个系统图标(`core.statusBar.icons`中的内容)。
@@ -269,10 +285,24 @@
]
```
+
+
**可以在控制台中输入`core.statusBar.icons`以查看所有的系统图标定义。**
!> 注意,在事件块中,允许只写一个反斜杠`\i`,系统会自动转义成`\\i`;但是在脚本中必须两个反斜杠都写上!
+从V2.6.3开始,也可以使用`\\c[...]`来切换当前字体,`\\d`来加粗或取消粗体,`\\e`来加斜体或取消斜体。
+
+``` js
+[
+ "这是原始字体,\\c[20]使用20号字体,\\c[10]使用10号字体",
+ "\\c如果不加中括号则切换回原始字体。",
+ "\\d这是粗体\\d取消粗体,\\e加斜体\\e取消斜体"
+]
+```
+
+!> 注意,在事件块中,允许只写一个反斜杠`\c`,系统会自动转义成`\\c`;但是在脚本中必须两个反斜杠都写上!`\d`和`\e`同理。
+
另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。
``` js
@@ -283,18 +313,32 @@
我们可以使用 `status:xxx` 代表勇士的一个属性值;`item:xxx` 代表某个道具的个数;`flag:xxx` 代表某个自定义的变量或flag值。
+从V2.6开始,也可以使用`global:xxx`代表全局存储(和存档无关的存储)。
+
+从V2.6.5开始,也可以使用`enemy:id:atk`来获得某个怪物的属性,`blockId:x,y`来获得某个点的图块ID,`equip:x`来获得某个装备孔的装备ID。
+
``` js
[
"你当前的攻击力是${status:atk}, 防御是${status:def},坐标是(${status:x},${status:y})",
"你的攻防和的十倍是${10*(status:atk+status:def)}",
"你的红黄蓝钥匙总数为${item:yellowKey+item:blueKey+item:redKey}",
"你访问某个老人的次数为${flag:man_times}",
+ "当前的存档编号是${global:saveIndex}",
+ "绿色史莱姆的攻击力是${enemy:greenSlime:atk}",
+ "(2,3)点的图块ID是${blockId:2,3},图块类型是${blockCls:2,3}",
+ "装备孔0的当前装备ID是${equip:0}",
]
```
+
+
- `status:xxx` 获取勇士属性时只能使用如下几个:hp(生命值),atk(攻击力),def(防御力),mdef(魔防值),money(金币),experience(经验),x(勇士的横坐标),y(勇士的纵坐标),direction(勇士的方向)。
- `item:xxx` 中的xxx为道具ID。所有道具的ID定义在items.js中,请自行查看。例如,`item:centerFly` 代表中心对称飞行器的个数。
-- `flag:xxx` 中的xxx为一个自定义的变量/Flag;如果没有对其进行赋值则默认值为false。
+- `flag:xxx` 中的xxx为一个自定义的变量/Flag(支持中文);如果没有对其进行赋值则默认值为0。
+- `global:xxx` 中的xxx为一个全局存储的名称(支持中文);如果没有对其进行赋值则默认值为0。
+- `enemy:xxx:yyy` 中的xxx为怪物ID;yyy为要获得的项,比如hp, atk, def等等
+- `blockId:x,y` 和 `blockCls:x,y` 中的x,y为坐标值
+- `equip:x` 中的x为装备孔编号,从0开始。
### autoText:自动剧情文本
@@ -306,6 +350,8 @@
]
```
+
+
text为文本正文内容,和上面的写法完全一致。
time为可选项,代表该自动文本的时间。可以不指定,不指定默认为3000毫秒。
@@ -326,6 +372,8 @@ time为可选项,代表该自动文本的时间。可以不指定,不指定
]
```
+
+
text为正文文本内容。可以使用`${ }`来计算表达式的值,且使用`\n`手动换行。系统不会对滚动剧情文本进行自动换行。
time为可选项,代表总的滚动时间。默认为5000毫秒。
@@ -351,6 +399,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
]
```
+
+
title为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示标题(名字)颜色。 默认值:`[255,215,0,1]`
text为可选项,如果设置则为一个RGB三元组或RGBA四元组,表示正文颜色。 默认值:`[255,255,255,1]`
@@ -371,6 +421,8 @@ textfont为可选项,表示正文字体大小(px为单位)。默认值:`
time为可选项,表示文字添加的速度。若此项设置为0将直接全部显示,若大于0则会设置为相邻字符依次显示的时间间隔。 默认值:`0`
+interval为可选项,表示文字之间的间距。单位为像素值。默认值:`0`
+
### tip:显示一段提示文字
`{"type": "tip"}`可以在左上角显示一段提示文字。
@@ -381,6 +433,8 @@ time为可选项,表示文字添加的速度。若此项设置为0将直接全
]
```
+
+
text必填,为显示的内容,支持`${}`的表达式计算。
icon是可选的,如果设置则会绘制图标,其可以是一个有效的ID,或者`core.statusBar.icons`中的系统图标。
@@ -395,6 +449,8 @@ icon是可选的,如果设置则会绘制图标,其可以是一个有效的I
]
```
+
+
这个事件将在运行时被游戏跳过。
### setValue:设置勇士的某个属性、道具个数,或某个变量/Flag的值
@@ -413,7 +469,7 @@ icon是可选的,如果设置则会绘制图标,其可以是一个有效的I
name为你要修改的属性/道具/Flag,每次只能修改一个值。写法和上面完全相同,`status:xxx` 表示勇士一个属性,`item:xxx` 表示某个道具个数,`flag:xxx` 表示某个变量或flag值。参见上面的介绍。
-value是一个表达式,将通过这个表达式计算出的结果赋值给name。该表达式同样可以使用`status:xxx`, `item:xxx`, `flag:xxx`的写法表示勇士当前属性,道具个数和某个变量/Flag值。
+value是一个表达式,将通过这个表达式计算出的结果赋值给name。该表达式同样可以使用`status:xxx`, `item:xxx`, `flag:xxx`, `global:xxx`的写法表示勇士当前属性,道具个数,某个变量/Flag值和某个全局存储值。
``` js
[
@@ -424,10 +480,16 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam
{"type": "setValue", "name": "item:bomb", "value": "item:bomb+10" } // 炸弹个数+10
{"type": "setValue", "name": "flag:man_times", "value": "0" } // 将变量man_times设为0
{"type": "setValue", "name": "flag:man_times", "value": "flag:man_times+2*status:atk" } // 将变量man_times的值加上勇士的攻击数值的两倍
+ {"type": "setValue", "name": "global:123", "value": "4"} // 设置全局存储233为4(任何存档都可以读取它)
]
```
-另外注意一点的是,如果hp被设置成了0或以下,将触发lose事件,直接死亡。
+
+
+从V2.6.5开始,当设置了`"norefresh": true`后可以不刷新状态栏、地图显伤和自动事件,从而加速事件执行。
+
+
+在刷新的情况下,如果hp被设置成了0或以下,将触发lose事件,直接死亡。
### addValue:增减勇士的某个属性、道具个数,或某个变量/Flag的值
@@ -446,6 +508,30 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam
]
```
+
+
+从V2.6.5开始,当设置了`"norefresh": true`后可以不刷新状态栏、地图显伤和自动事件,从而加速事件执行。
+
+### setEnemy:设置怪物属性
+
+使用`{"type":"setEnemy"}`可以设置某个怪物的某个属性
+
+``` js
+[
+ {"type": "setEnemy", "id": "greenSlime", "name": "hp", "value": "1000"}, // 设置绿色史莱姆生命1000
+ {"type": "setEnemy", "id": "redSlime", "name": "special", "value": "[1,2]"}, // 设置红色史莱姆先攻魔攻
+ {"type": "setEnemy", "id": "redSlime", "name": "name", "value": "'小史莱姆'"}, // 设置怪物名称
+]
+```
+
+
+
+id为必填项,代表要修改的怪物ID。
+
+name为必填项,代表要修改的项,例如`hp`, `atk`, `def`, `money`, `experience`, `point`, `special`, `name`。
+
+value为必填项,代表要修改到的内容。对于修改名称的,必须加单引号。
+
### setFloor:设置楼层属性
使用`{"type":"setFloor"}`可以设置某层楼的楼层属性。
@@ -462,6 +548,8 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam
]
```
+
+
name为必填项,代表要修改的楼层属性,和楼层属性中的一一对应。
floorId为可选项,代表要修改的楼层ID;可以省略代表当前楼层。
@@ -480,6 +568,8 @@ value为必填项,代表要修改到的数值。其应该和楼层属性中的
]
```
+
+
name必填项,代表要修改的全局属性。
value为必填项,代表要修改到的结果。此项无需再手动加单引号。
@@ -494,6 +584,8 @@ value为必填项,代表要修改到的结果。此项无需再手动加单引
]
```
+
+
name必填项,代表要修改的全局数值,其和全塔属性中的values一一对应。
value为必填项,代表要修改到的结果。该项必须是个数值。
@@ -508,6 +600,8 @@ value为必填项,代表要修改到的结果。该项必须是个数值。
]
```
+
+
name必填项,代表要修改的系统开关,其是全塔属性中的flags中的一部分。
value为必填项,只能为true或false,代表要修改到的结果。
@@ -528,6 +622,8 @@ value为必填项,只能为true或false,代表要修改到的结果。
]
```
+
+
show事件需要用loc指定目标点的坐标,可以简单的写[x,y]代表一个点,也可以写个二维数组[[x1,y1],[x2,y2],...]来同时显示多个点。
从V2.2开始,loc也可以用变量来代替,例如 `"loc": ["flag:x", "flag:y"]`。下同。
@@ -566,28 +662,30 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}`
]
```
+
+
### trigger:立即触发另一个地点的事件
`{"type":"trigger"}` 会立刻触发当层另一个地点的自定义事件。
-上面我们说到,show事件会让一个禁用事件启用且可被交互;但是如果我想立刻让它执行应该怎么办呢?使用trigger就行。
-
其基本写法如下:
``` js
[
{"type": "trigger", "loc": [3,6]}, // 立即触发loc位置的事件,当前剩下的事件全部不再执行
- "执行trigger后,这段文字将不会再被显示"
+ {"type": "trigger", "loc": [3,6], "keep": true}, // 触发loc位置的事件,不结束当前事件
]
```
+
+
其后面带有loc选项,代表另一个地点的坐标。
-执行trigger事件后,当前事件将立刻被结束,剩下所有内容被忽略;然后重新启动另一个地点的action事件。
+keep可选,如果此项为true则不会结束当前的事件列表,否则会中断当前的事件流。
-例如上面这个例子,下面的文字将不会再被显示,而是直接跳转到`"3,6"`对应的事件列表从头执行。
+从V2.5.4开始允许执行另一个点的系统事件,如打怪开门拾取道具等等,对应点的战后等事件也会被插入执行。
-!> 从V2.5.4开始,允许执行另一个点的“系统事件”,如打怪、开门、拾取道具等等。对应点的战后事件等也会被执行。
+值得注意的是,此事件会**改变当前点坐标**为目标点。
### insert:插入公共事件或另一个地点的事件并执行
@@ -606,6 +704,8 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}`
]
```
+
+
`insert`的写法有两种,可以写`name`,或者`loc`。
- 如果写了`"name": "xxx"`,则会去公共事件列表中找寻对应的事件,并执行。
@@ -615,11 +715,12 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}`
- floorId可选,代表另一个地点所在的楼层;如果不写则默认为当前层。
- 从V2.6开始,还可以传可选的which,可以为`afterBattle`/`afterGetItem`/`afterOpenDoor`,代表插入该点的战后/获得道具后/开门后事件。
-和`type:trigger`不同的是,**`type:trigger`是立刻将当前事件结束(剩下所有内容都忽略),然后重新启动另一个地点的action事件。**
+和`type:trigger`不同点如下:
+- `type:trigger`只能指定当前楼层且会改变当前点坐标,`type:insert`可以跨楼层且不会改变当前点坐标。
+- `type:trigger`如果不设置`keep:true`则还会结束当前事件,`type:insert`而是将另一个点的事件插入到当前事件列表中执行。
+- `type:trigger`可以触发系统事件,`type:insert`只能触发该点的自定义事件或战后事件等。
-但是`type:insert`不会结束当前事件,而是直接将另一个地点的事件列表“插入”到当前事件列表中执行。
-
-**这个过程中,当前事件不会被结束,当前的楼层和事件坐标不会发生改变。** 插入的事件执行完毕后,会继续执行接下来的内容。
+插入的事件执行完毕后,会继续执行接下来的内容。
从V2.6开始,插入事件允许传参。如果需要传参,则需要增加一个`args`数组。
@@ -642,6 +743,8 @@ revisit和trigger完全相同,只不过是立刻触发的还是本地点的事
]
```
+
+
revisit其实是trigger的简写,只不过是loc固定为当前点。
revisit常常使用在一些商人之类的地方,当用户购买物品后不是离开,而是立刻重新访问重新进入购买页面。
@@ -661,6 +764,8 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不
]
```
+
+
### setBlock:设置某个图块
我们可以采用 `{"type": "setBlock"}` 来改变某个地图块。
@@ -674,6 +779,8 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不
]
```
+
+
floorId为可选的,表示要更改的目标楼层。如果忽略此项,则默认为当前楼层。
loc为可选的,表示要更改地图块的坐标。如果忽略此项,则默认为当前事件点。
@@ -704,6 +811,8 @@ number为**要更改到的数字**,有关“数字”的定义详见参见[素
]
```
+
+
loc为要隐藏的贴图的左上角坐标,可以简单的写[x,y]代表一个点,也可以写个二维数组[[x1,y1],[x2,y2],...]来同时显示多个点。
如果同时存在若干个贴图都是是该坐标为左上角,则这些贴图全部会被隐藏。
@@ -736,6 +845,8 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。
]
```
+
+
name为必选的,且只能是`bg`和`fg`之一,分别代表背景图层和前景图层。
loc为要隐藏的贴图的左上角坐标,可以简单的写[x,y]代表一个点,也可以写个二维数组[[x1,y1],[x2,y2],...]来同时显示多个点。
@@ -766,6 +877,8 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。
]
```
+
+
name为必选的,且只能是`bg`和`fg`之一,分别代表背景层和前景层。
floorId为可选的,表示要更改的目标楼层。如果忽略此项,则默认为当前楼层。
@@ -786,6 +899,8 @@ loc为可选的,表示要更改地图块的坐标。如果忽略此项,则
]
```
+
+
name是可选的,代表目标行走图的文件名。
!> **目标行走图必须在全塔属性的this.images中被定义过,且宽度必须是128像素(高度不限)。**
@@ -808,11 +923,13 @@ name是可选的,代表目标行走图的文件名。
使用`{"type": "showStatusBar"}`会重新显示状态栏。
-### updateEnemys:更新怪物数据
+### hideHero:隐藏勇士
-使用 `{"type": "updateEnemys"}` 可以动态修改怪物数据。
+使用`{"type": "hideHero"}`可以隐藏勇士。
-详见[怪物数据的动态修改](#怪物数据的动态修改)。
+### showHero:显示勇士
+
+使用`{"type": "showHero"}`会重新显示勇士。
### sleep:等待多少毫秒
@@ -828,6 +945,8 @@ name是可选的,代表目标行走图的文件名。
]
```
+
+
默认的等待事件可以被Ctrl跳过,下面两种情况下不可呗跳过:
- 加上`"noSkip": true`后
- 当前存在尚未执行完毕的异步事件。
@@ -836,28 +955,22 @@ name是可选的,代表目标行走图的文件名。
调用battle可强制与某怪物进行战斗(而无需去触碰到它)。
-其基本写法是: `{"type": "battle", "id": xxx}`,其中xxx为怪物ID。
-
``` js
[
- "\t[blackKing]你终于还是来了。",
- "\t[hero]放开我们的公主!",
- "\t[blackKing]如果我不愿意呢?",
- "\t[hero]无需多说,拔剑吧!",
- {"type": "battle", "id": "blackKing"}, // 强制战斗
- // 如果战斗失败直接死亡,不会继续触发接下来的剧情。
- {"type": "hide", "loc": [10,2]}, // 战斗后需要手动使怪物消失;战斗后不会引发afterBattle事件。
- {"type": "openDoor", "loc": [8,7]}, // 开门口的机关门
- "\t[blackKing]没想到你已经变得这么强大了... 算你厉害。\n公主就交给你了,请好好对她。",
- {"type": "hide"} // 隐藏本事件
+ {"type": "battle", "id": "blackKing"}, // 强制战斗黑衣魔王
+ {"type": "battle", "loc": [2,3]}, // 强制战斗(2,3)点的怪物
],
```
-上面就是样板层中右上角的强制战斗例子。
+
-如果强制战斗失败,则会立刻生命归0并死亡,调用lose函数,接下来的事件不会再被执行。
+从V2.6开始,有两种写法:
+- 写id,则视为和空降怪物进行强制战斗,不会执行一些战后事件,也不会隐藏任何点。
+- 写loc(可选,不填默认当前点),则视为和某点怪物进行强制战斗,会隐藏该点并且插入该点战后事件执行。
-强制战斗没有指定loc的选项,因此战斗后需要调用hide使怪物消失(如果有必要)。
+强制战斗不会自动存档,如果战斗失败则立刻死亡。
+
+值得注意的是,如果是和某个点的怪物强制战斗,并且该点存在战后事件,执行时会**修改当前点坐标**为目标点。
### openDoor:开门
@@ -867,10 +980,12 @@ name是可选的,代表目标行走图的文件名。
[
{"type": "openDoor", "loc": [3,6], "floorId": "MT1"}, // 打开MT1层的[3,6]位置的门
{"type": "openDoor", "loc": [3,6]}, // 如果是本层则可省略floorId
- {"type": "openDoor", "loc": [3,6], "needKey": true} // 打开此门需要钥匙
+ {"type": "openDoor", "loc": [3,6], "needKey": true, "async": true} // 打开此门需要钥匙,异步执行
]
```
+
+
loc指定门的坐标,floorId指定门所在的楼层ID。如果是当前层则可以忽略floorId选项。
如果loc所在的点是一个墙壁,则作为暗墙来开启。
@@ -879,8 +994,12 @@ loc指定门的坐标,floorId指定门所在的楼层ID。如果是当前层
needKey是可选的,如果设置为true则需要钥匙才能打开此门。如果没有钥匙则跳过此事件。
+async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
+
!> needKey仅对当前楼层开门有效!跨楼层的门仍然不需要钥匙即可打开,如有需求请自行判定。
+值得注意的是,如果该点存在开门事件,执行时会**修改当前点坐标**为目标点。
+
### closeDoor:关门
从V2.6开始提供了关门事件`{"type": "closeDoor"}`,拥有关门动画和对应的音效。
@@ -892,6 +1011,8 @@ needKey是可选的,如果设置为true则需要钥匙才能打开此门。如
]
```
+
+
id为你要关门的ID,需要是一个合法的门,系统默认只支持如下几种:
```
@@ -903,6 +1024,8 @@ yellowWall, blueWall, whiteWall
loc可选,为要关的位置,不填默认为当前点。
+async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
+
关门事件需要保证该点是空地,否则将无视此事件。
### changeFloor:楼层切换
@@ -918,6 +1041,8 @@ changeFloor的事件写法大致如下。
]
```
+
+
可以看到,与上面的楼梯、传送门的写法十分类似。
但是相比那个而言,不支持stair楼梯位置(只能写坐标),没有穿透选项。
@@ -942,24 +1067,54 @@ time为可选的,指定的话将作为楼层切换动画的时间。
]
```
+
+
### useItem:使用道具
调用`{"type": "useItem"}`可以使用一个道具。
``` js
[
- {"type": "changePos", "id": "pickaxe"}, // 尝试使用破
- {"type": "changePos", "id": "bomb"}, // 尝试使用炸
- {"type": "changePos", "id": "centerFly"} // 尝试使用飞
+ {"type": "useItem", "id": "pickaxe"}, // 尝试使用破
+ {"type": "useItem", "id": "bomb"}, // 尝试使用炸
+ {"type": "useItem", "id": "centerFly"} // 尝试使用飞
]
```
+
+
使用道具事件会消耗对应的道具。
如果当前不可使用该道具(如没有,或者达不到使用条件),则会进行提示并跳过本事件。
不可使用“怪物手册”(请使用【呼出怪物手册】事件)或楼层传送器(如果[覆盖楼传事件](personalization#覆盖楼传事件)则可忽视本项)。
+### loadEquip:装上装备
+
+使用`{"type": "loadEquip"}`可以装上一个装备。
+
+``` js
+[
+ {"type": "loadEquip", "id": "sword1"}, // 尝试装上铁剑
+]
+```
+
+id必填,为需要装备的ID。
+
+使用装备时仍会检查条件(比如装备是否存在,能否装备等等)。
+
+### unloadEquip:卸下装备
+
+使用`{"type": "unloadEquip"}`卸下某个装备孔的装备。
+
+``` js
+[
+ {"type": "unloadEquip", "pos": 0}, // 卸下装备孔0的装备
+]
+```
+
+pos必填,为要卸下的装备孔编号,从0开始。
+
### openShop:打开一个全局商店
使用openShop可以打开一个全局商店。有关全局商店的说明可参见[全局商店](#全局商店)。
@@ -990,7 +1145,7 @@ name所指定的图片必须存在,在全塔属性中的images中被定义过
``` js
[
{"type": "unfollow", "name": "npc.png"}, // 将 npc.png 这个行走图取消跟随
- {"type": "follow"}, // 取消所有跟随
+ {"type": "unfollow"}, // 取消所有跟随
]
```
@@ -1023,6 +1178,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
]
```
+
+
name为动画名,**请确保动画在全塔属性中的animates中被定义过。**
loc为动画的位置,可以是`[x,y]`表示在(x,y)点显示,也可以是字符串`"hero"`表示在勇士点显示。
@@ -1046,6 +1203,8 @@ loc可忽略,如果忽略则显示为事件当前点。
]
```
+
+
code为图片编号,如果两张图片重叠,编号较大会覆盖编号较小的。该值需要在1~50之间。
image为图片名。**请确保图片在全塔属性中的images中被定义过。**
@@ -1132,6 +1291,8 @@ loc为动图左上角坐标,以像素为单位进行计算。
]
```
+
+
code为图片编号。该值需要在1~50之间。
to为终点图片左上角坐标,以像素为单位进行计算,不填写则视为当前图片位置。
@@ -1154,6 +1315,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
]
```
+
+
color为需要更改画面色调的颜色。它是一个数组,分别指定目标颜色的R,G,B,A值。
- 常见RGB颜色: 纯黑[0,0,0],纯白[255,255,255],纯红[255,0,0],等等。
- 第四元为Alpha值,即不透明度,为一个0到1之间的数。可以不指定,则默认为Alpha=1
@@ -1221,6 +1384,8 @@ level为天气的强度等级,在1-10之间。1级为最弱,10级为最强
]
```
+
+
time选项必须指定,为每移动一步所需要用到的时间。
loc为需要移动的事件位置。可以省略,如果省略则移动本事件。
@@ -1251,6 +1416,8 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该
}
```
+
+
即,在移动的到达点指定一个事件,然后move事件中指定"keep":true,然后就可以触发目标点的事件了。
async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。
@@ -1329,6 +1496,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
目前支持mp3/ogg/wav等多种格式的音乐播放。
+从V2.6.3开始,还提供了keep项。如果此项为真,则会记录该bgm,并且持续到下次调用本事件位置(楼层切换不改变bgm,读档也有效)。
+
有关BGM播放的详细说明参见[背景音乐](element#背景音乐)
### pauseBgm:暂停背景音乐
@@ -1375,6 +1544,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
使用方法: `{"type": "setVolume", "value": 90, "time": 500, "async": true}`
+
+
value为音量大小,在0到100之间,默认为100。设置后,BGM将使用该音量进行播放。SE的音量大小不会发生改变。
可以设置time为音量渐变时间。
@@ -1434,6 +1605,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行
]
```
+
+
text为提示文字,可以在这里给输入提示文字。这里同样可以使用${ }来计算表达式的值。
当执行input事件时,将显示一个弹窗,并提示用户输入一个内容。
@@ -1453,6 +1626,8 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以
]
```
+
+
text为提示文字,可以在这里给输入提示文字。这里同样可以使用${ }来计算表达式的值。
当执行input2事件时,将显示一个弹窗,并提示用户输入一个内容。
@@ -1504,6 +1679,8 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以
]
```
+
+
需要额外注意的几点:
- 给定的表达式(condition)一般需要返回true或false。
@@ -1569,6 +1746,8 @@ nobreak是可选的,如果设置,则在当前条件满足并插入事件后
]
```
+
+
需要额外注意的几点:
- 各个条件分支的判断是顺序执行的,因此若多个分支的条件都满足,将只执行最靠前的分支。
@@ -1597,6 +1776,7 @@ nobreak是可选的,如果设置,则在当前条件满足并插入事件后
]
```
+
### choices:给用户提供选项
@@ -1702,12 +1882,16 @@ yes和no均为必填项,即用户点击确认或取消后执行的事件。
]
```
+
+
### dowhile:后置条件循环
`type:dowhile`可以制作一个后置条件循环。
其写法与参数和`type:while`完全一致,不过与其不同的是,会先执行一次事件列表,再对条件进行判定,就和C/C++中的 `do {...} while (...);` 语法一样。
+
+
### break:跳出循环
使用 `{"type": "break"}` 可以跳出当前循环。
@@ -1737,6 +1921,8 @@ yes和no均为必填项,即用户点击确认或取消后执行的事件。
]
```
+
+
!> 如果continue事件不在任何循环中被执行,则和exit等价,即会立刻结束当前事件!
### wait:等待用户操作
@@ -1776,6 +1962,33 @@ yes和no均为必填项,即用户点击确认或取消后执行的事件。
]
```
+
+
+从V2.6.6开始,也允许直接在`type:wait`中增加`data`项判定按键或点击坐标。
+
+```js
+[
+ {"type": "wait", "data": [
+ {"case": "keyboard", "keycode": 13, "action": [
+ {"type": "comment", "text": "当按下回车(keycode=13)时执行此事件"},
+ ]},
+ {"case": "mouse", "px": [0,32], "py": [0,32], "action": [
+ {"type": "comment", "text": "当点击地图左上角时执行此事件"},
+ ]},
+ ]},
+]
+```
+
+
+
+`data`是一个数组,每一项中,case只能为`keyboard`和`mouse`二选一,分别对应键盘和鼠标(即`type=0`和`type=1`)。
+
+如果是键盘,则可以指定`keycode`为键盘的按键内容;否则指定`px`和`py`为点击的像素区间。
+
+action为如果满足该条件时应该执行的事件列表。
+
+
+
### waitAsync:等待所有异步事件执行完毕
上面有很多很多的异步事件(也就是执行时不等待执行完毕)。
@@ -1789,6 +2002,290 @@ yes和no均为必填项,即用户点击确认或取消后执行的事件。
该事件会进行等待,直到所有可能的异步事件(异步动画除外)执行完毕。
+### previewUI:UI绘制并预览
+
+此项可在地图编辑器中预览UI界面的绘制效果。
+
+在编辑器中将会把此项包含的所有UI绘制事件进行绘制从而可以进行预览。
+
+值得注意的是,在游戏中,UI绘制事件都是绘制在uievent层上的。
+
+### clearMap:清除画布
+
+UI绘制事件。
+
+`{"type": "clearMap"}`可以清除`uievent`画布的内容。
+
+```js
+[
+ {"type": "clearMap", "x": 0, "y": 0, "width": "flag:width", "height": 416}, // 清除画布的一部分
+ {"type": "clearMap"}, // 清空并删除画布
+]
+```
+
+x, y, width, height均可选,表示要清除的坐标和长宽。也可以使用`flag:xxx`。
+
+如果存在某一项不填则会清空全部画布并删除。
+
+### setAttribute:设置画布属性
+
+UI绘制事件。
+
+此项可以设置`uievent`画布的各项属性。
+
+```js
+[
+ {"type": "setAttribute", "font": "17px Verdana", "fillStyle": [255,0,0,1]},
+]
+```
+
+可以选择性的设置如下几项内容:
+- `font`:字体,必须是`[italic] [bold] 14px Verdana`这种形式
+- `fillStyle`:填充样式,必须是三元组RGB或四元组RGBA
+- `strokeStyle`:边框样式,必须是三元组RGB或者四元组RGBA
+- `lineWidth`:线宽度,必须是正整数
+- `alpha`:不透明度,必须是0到1之间的浮点数
+- `align`:对齐方式,只能是`left`, `center`, `right`,分别代表左对齐,居中和右对齐
+- `baseline`:基准线,只能是`top`, `middle`, `alphabetic`, `bottom`,分别代表顶部,居中,标准值和底部。
+- `z`:画布的z值,必须是正整数。初始创建时画布的z值是135。请注意,闪烁光标所在画布的z值永远比该画布大1。
+
+### fillText:绘制文本
+
+UI绘制事件。
+
+此项可以绘制一行文本。
+
+```js
+[
+ {"type": "fillText", "text":"要绘制的文本", "x": 10, "y": 20, "maxWidth": 50}
+]
+```
+
+text必填,为要绘制的文本,支持`${}`的写法,不支持一切转义字符或换行符。
+
+x和y必填,为要绘制的左上角坐标。请使用`setAttribute`来设置绘制的对齐方式和基准线。
+
+style可选,如果设置需要是三元组RGB或四元组RBGA,代表绘制样式。
+
+font可选,如果设置则是要绘制的字体。
+
+maxWidth可选,如果设置且不为0,则代表要绘制的最大宽度;超过此宽度会自动放缩。
+
+### fillBoldText:绘制描边文本
+
+UI绘制事件。
+
+此项可以绘制一行描边文本。
+
+```js
+[
+ {"type": "fillText", "text":"要绘制的描边文本", "x": 10, "y": 20, "style": [255,0,0,1]}
+]
+```
+
+text必填,为要绘制的文本,支持`${}`的写法,不支持一切转义字符或换行符。
+
+x和y必填,为要绘制的左上角坐标。请使用`setAttribute`来设置绘制的对齐方式和基准线。
+
+style可选,如果设置需要是三元组RGB或四元组RBGA,代表绘制样式。
+
+font可选,如果设置则是要绘制的字体。
+
+### drawTextContent:绘制多行文本
+
+UI绘制事件。
+
+此项可以绘制多行文本。
+
+```js
+[
+ {"type": "drawTextContent", "text":"要绘制的多行文本", "left": 10, "top": 20, "maxWidth": 100}
+]
+```
+
+text必填,为要绘制的文本,支持所有的文字效果(如\n,${},\r,\\i,\\c,\\d,\\e等),但不支持支持\t和\b的语法。
+
+left和top必填,为要绘制的起始像素坐标。实际绘制时会将textBaseline设置为'top',因此只需要考虑第一个字的左上角位置。
+
+maxWidth可选,为单行最大宽度,超过此宽度将自动换行,不设置不会自动换行。
+
+color可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。如果不设置则使用剧情文本设置中的正文颜色。
+
+bold可选,是否粗体。如果不设置默认为false。
+
+align可选,文字对齐方式,仅在maxWidth设置时有效,默认为'left'。
+
+fontSize可选,为字体大小,如果不设置则使用剧情文本设置中的正文字体大小。
+
+lineHeight可选,绘制的行距值,如果不设置则使用fontSize*1.3(即1.3倍行距)。
+
+此项不支持字体样式的设置,使用的是全塔属性中的全局字体;如有需要请使用“设置全局属性”事件来设置字体样式。
+
+### fillRect:绘制矩形
+
+UI绘制事件。此项可以绘制一个矩形。
+
+```js
+[
+ {"type": "fillRect", "x": 100, "y": 100, "width": 120, "height": 120, "style": [255,0,0,1]}
+]
+```
+
+x, y, width, height必填,为要绘制的起点坐标和宽高;也可以用`flag:xxx`。
+
+color可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。
+
+### strokeRect:绘制矩形边框
+
+UI绘制事件。此项可以绘制一个矩形边框。
+
+```js
+[
+ {"type": "strokeRect", "x": 100, "y": 100, "width": 120, "height": 120, "style": [255,0,0,1], "lineWidth": 4}
+]
+```
+
+x, y, width, height必填,为要绘制的起点坐标和宽高;也可以用`flag:xxx`。
+
+style可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。
+
+lineWidth可选,表示边框的线宽。
+
+### drawLine:绘制线段
+
+UI绘制事件。此事件可以绘制一个函数。
+
+```js
+[
+ {"type": "drawLine", "x1": 0, "y1": 0, "x2": "flag:x", "y2": 200, "style": [255,0,0,1]}
+]
+```
+
+x1, y1, x2, x2必填,为要绘制的起点和终点坐标;也可以用`flag:xxx`的写法。
+
+style可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。
+
+lineWidth可选,表示边框的线宽。
+
+### drawArrow:绘制箭头
+
+UI绘制事件。此事件可以绘制一个箭头。
+
+参数和写法与`drawLine`完全一致,只不过是会多画一个箭头标记。
+
+### fillPolygon:绘制多边形
+
+UI绘制事件。此事件可以绘制一个多边形。
+
+```js
+[
+ {"type": "fillPolygon", "nodes": [[0,0],[0,100],[100,0]], "style": [255,0,0,1]}
+]
+```
+
+nodes必填,为一个二维数组,其中每一项都是多边形一个顶点坐标。(与显示/隐藏事件写法相同)
+
+style可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。
+
+### strokePolygon:绘制多边形边框
+
+UI绘制事件。此事件可以绘制一个多边形边框。
+
+参数列表和`fillPolygon`基本相同,不过多了一个`lineWidth`表示的绘制线宽。
+
+### fillCircle:绘制圆
+
+UI绘制事件。此项可以绘制一个圆。
+
+```js
+[
+ {"type": "fillCircle", "x": 100, "y": 100, "r": 10, "style": [255,0,0,1]}
+]
+```
+
+x, y, r必填,为要绘制的圆心和半径;也可以用`flag:xxx`。
+
+color可选,表示绘制时的颜色,为三元组RGB或四元组RGBA。
+
+### strokeCircle:绘制圆边框
+
+UI绘制事件。此项可以绘制一个圆边框。
+
+参数列表和`fillCircle`基本相同,不过多了一个`lineWidth`表示的绘制线宽。
+
+### drawImage:绘制图片
+
+UI绘制事件。此事件可以绘制一个图片。
+
+```js
+[
+ {"type": "drawImage", "image": "bg.jpg", "x": 0, "y": 0}, // 在(0,0)绘制bg.jpg
+ {"type": "drawImage", "image": "bg.jpg", "x": 0, "y": 0, "w": 100, "h": 100}, // 在(0,0)绘制bg.jpg,且放缩到100x100
+ // 裁剪并放缩图片
+ {"type": "drawImage", "image": "bg.jpg", "x": 0, "y": 0, "w": 100, "h": 100, "x1": 0, "y1": 0, "w1": 100, "h1": 100}
+]
+```
+
+image必填,为图片名。图片必须在全塔属性中被注册过。
+
+此函数有三种写法:
+
+- 只写x和y:表示要绘制到的位置。
+- 写x, y, w, h:表示要绘制到的位置,且将图片放缩到指定宽高。
+- 写x, y, w, h, x1, y1, w1, h1:从原始图片上裁剪[x,y,w,h]的图片,并绘制画布上的[x1,y1,w1,h1]
+
+可以查看下面的文档以了解各项参数的信息:
+http://www.w3school.com.cn/html5/canvas_drawimage.asp
+
+### drawIcon:绘制图标
+
+UI绘制事件。此事件可以绘制一个图标。
+
+```js
+[
+ {"type": "drawIcon", "id": "yellowKey", "x": 100, "y": 100}, // 在(100,100)绘制黄钥匙
+]
+```
+
+id必填,为要绘制的图标ID。可以是一个注册过的图标ID,也可以使用状态栏的图标ID,例如lv, hp, up, save, settings等。
+
+x, y必填,为要绘制的左上角坐标。width和height可选,如果设置则会将图标放缩成对应的宽高。
+
+### drawBackground:绘制背景图
+
+UI绘制事件。此事件可以绘制一个背景图。
+
+```js
+[
+ {"type": "drawBackground", "background": "winskin.png", "x": 0, "y": 0, "width": 100, "height": 100},
+]
+```
+
+background必填,为要绘制的背景图内容。其可以是一个三元组RGB或四元组RGBA(纯色绘制),或一个WindowSkin的图片名。
+
+x, y, width, height必填,分别为要绘制的起点坐标和长宽。
+
+可以使用“设置画布属性”来设置不透明度和纯色绘制时的边框颜色。
+
+### drawSelector:绘制闪烁光标
+
+UI绘制事件。此事件可以绘制闪烁光标。
+
+```js
+[
+ {"type": "drawSelector", "image": "winskin.png", "x": 0, "y": 0, "width": 100, "height": 100, "clear": true},
+ {"type": "drawSelector"} // 清除闪烁光标
+]
+```
+
+image为要绘制的WindowSkin图片名;如果不填则视为“清除闪烁光标”。
+
+x, y, width, height分别为要绘制的起点坐标和长宽。clear可选,如果为true则在绘制前清空已有光标。
+
+请注意,同时只会有一个闪烁光标存在,如果创建多个则后者会替换前者。
+
+闪烁光标将会一直存在即使事件流结束;请使用本事件并不填`image`来清除闪烁光标。
+
### function: 自定义JS脚本
上述给出了这么多事件,但有时候往往不能满足需求,这时候就需要执行自定义脚本了。
@@ -1825,11 +2322,31 @@ core.insertAction([
!> 从V2.5.3开始,提供了一个"不自动执行下一个事件"的选项(`"async": true`)。如果设置了此项,那么在该部分代码执行完毕后,不会立刻执行下一个事件。你需要在脚本中手动调用`core.events.doAction()`来执行下一个事件。可以通过此项来实现一些异步的代码,即在异步函数的回调中再执行下一个事件。使用此选项请谨慎,最好向开发者寻求咨询。
+## 自动事件
+
+从V2.6.4开始,提供了自动事件。每个点都可以绑定若干个自动事件,其类似于RM的事件页。
+
+自动事件可以设置一个触发条件,当满足此条件时将自动执行。
+
+
+
+自动事件可以设置如下几项内容:
+
+- 条件:当满足此条件时将自动执行
+- 优先级:当多个自动事件的条件同时满足时,将按照优先级从大到小执行;相同优先级的按照楼层和坐标排序。
+- 仅在本层检测:是否仅在本层检测该条件。
+- 事件流中延迟执行:如果此项为true,则若满足条件时正在事件流的处理中,则将该自动事件延迟到事件流结束时执行。
+- 允许多次执行:如果此项为true,则该自动事件允许被多次触发;否则只会被触发一次。值得注意的是,即使允许多次触发,也不允许在正在执行本自动事件时再触发。(即在执行本自动事件时将暂时禁用自身,直到执行完毕为止)
+
+自动事件的检测时机为刷新状态栏,即每次刷新状态栏时都会进行检测。
+
+可以给自动事件加上【转变图块】,从而达到类似RM的多事件页并转变图块的效果
+
## 独立开关
从V2.5.3开始,针对每个事件都提供了独立开关。
-独立开关的写法是`switch:A`, `switch:A`直到`switch:Z`,共计26个;不过样板中的值块默认只提供前6个。
+独立开关的写法是`switch:A`, `switch:A`直到`switch:Z`,共计26个。
独立开关算是特殊的flag,它在事件中使用时会和事件的楼层及坐标进行绑定;换句话说每个事件对应的`switch:A`都是不同的。
@@ -1840,6 +2357,8 @@ core.insertAction([
通过独立开关的方式,我们无需对某些NPC的对话都设立单独的互不重复flag,只需要关注该事件自身的逻辑即可。
+
+
## 同一个点的多事件处理
我们可以发现,就目前而且,每个点的事件是和该点进行绑定,并以该点坐标作为唯一索引来查询。
@@ -1884,6 +2403,8 @@ core.insertAction([
}
```
+
+
### 获得圣水后变成墙
这个例子要求获得圣水时不前进(也就是不能走到圣水地方),然后把圣水位置变成墙。
@@ -1911,6 +2432,8 @@ core.insertAction([
}
```
+
+
总之,记住如下两点:
- 可以使用setBlock来更改一个图块。
@@ -2092,11 +2615,13 @@ if (core.flags.enableAddPoint && point > 0) {
]
```
+
+
`id`, `textInList`, `mustEnable`和上述完全相同。
`commonEvent`为公共事件名,即选择此项时要执行的公共事件。
-`args`为向该公共事件传递的参数,参见[type:insert](#insert:插入公共事件或另一个地点的事件并执行)的说明。
+`args`可选,为向该公共事件传递的参数,参见[type:insert](#insert:插入公共事件或另一个地点的事件并执行)的说明。
## 系统引发的自定义事件
@@ -2134,6 +2659,8 @@ if (core.flags.enableAddPoint && point > 0) {
},
```
+
+
!> 多个机关门请分别设置开门变量如door1, door2等等。请勿存在两个机关门用相同的变量!
除此以外,每层楼还提供了`firstArrive`和`eachArrive`事件,分别为首次到达该楼层和每次到达该楼层时执行的事件。
@@ -2197,43 +2724,6 @@ if (core.flags.enableAddPoint && point > 0) {
}
```
-## 怪物数据的动态修改
-
-有时候我们可能还需要在游戏过程中动态修改怪物数据,例如50层魔塔的封印魔王,或者根据难度分歧来调整最终Boss的属性数据。
-
-而在我们的存档中,是不会对怪物数据进行存储的,只会存各个变量和Flag,因此我们需要在读档后根据变量或Flag来调整怪物数据。
-
-我们可以在脚本编辑中的`updateEnemys`进行处理。
-
-``` js
-"updateEnemys" : function () {
- // 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改
- // 比如下面这个例子,如果flag:xxx为真,则将绿头怪的攻击设为100,红头怪的金币设为20
- // 推荐写变化后的具体数值,以免多次变化导致冲突
- /*
- // 如果flag:xxx为真;你也可以写其他判断语句比如core.hasItem(...)等等
- if (core.hasFlag('xxx')) {
- core.material.enemys.greenSlime.atk = 100;
- core.material.enemys.redSlime.money = 20;
- }
- */
- // 别忘了在事件中调用“更新怪物数据”事件!
-}
-```
-
-当我们获得一个道具(或者触发某个事件等)后,需要在事件中调用“更新怪物数据”事件。
-
-``` js
-// 调用`updateEnemys`(更新怪物数据)事件就可以触发了
-[
- "将flag:xxx置为真,就可以让怪物数据发生改变!",
- {"type": "setValue", "name": "flag:xxx", "value": "true"}, // 将flag:xxx置为真
- {"type": "updateEnemys"} // 更新怪物数据;此时绿头怪攻击就会变成100了
-]
-```
-
-事实上,除了动态修改怪物属性外,也可以在这里动态修改道具的类型、使用效果等等。都是一样的。
-
## 战前剧情
有时候光战后事件`afterBattle`是不够的,我们可能还需要战前剧情,例如Boss战之前和Boss进行一段对话。
@@ -2253,6 +2743,8 @@ if (core.flags.enableAddPoint && point > 0) {
}
```
+
+
另外,从V2.6开始,脚本编辑中提供了战前事件`beforeBattle`,这里不再详细展开,如有需求可自行前往研究。
## 经验升级(进阶/境界塔)
@@ -2282,6 +2774,8 @@ if (core.flags.enableAddPoint && point > 0) {
]
```
+
+
`levelUp`是一个数组,里面分别定义了每个等级的信息。里面每一项有三个参数`need`, `title`, `effect`
- `need` 该等级所需要的经验值,可以是个表达式。请确保数组中的need依次递增。
- `title` 该等级的名称,比如“佣兵下级”等。该项可以忽略,以使用系统默认的等级。该项将显示在状态栏中。
@@ -2335,6 +2829,8 @@ if (core.flags.enableAddPoint && point > 0) {
]
```
+
+
==========================================================================================
[继续阅读下一章:个性化](personalization)
diff --git a/_docs/img/autoEvent.png b/_docs/img/autoEvent.png
new file mode 100644
index 00000000..06dd923e
Binary files /dev/null and b/_docs/img/autoEvent.png differ
diff --git a/_docs/img/events/1.jpg b/_docs/img/events/1.jpg
new file mode 100644
index 00000000..6cc44ab5
Binary files /dev/null and b/_docs/img/events/1.jpg differ
diff --git a/_docs/img/events/10.jpg b/_docs/img/events/10.jpg
new file mode 100644
index 00000000..9e7166a6
Binary files /dev/null and b/_docs/img/events/10.jpg differ
diff --git a/_docs/img/events/11.jpg b/_docs/img/events/11.jpg
new file mode 100644
index 00000000..c6f3aa1b
Binary files /dev/null and b/_docs/img/events/11.jpg differ
diff --git a/_docs/img/events/12.jpg b/_docs/img/events/12.jpg
new file mode 100644
index 00000000..12551990
Binary files /dev/null and b/_docs/img/events/12.jpg differ
diff --git a/_docs/img/events/13.jpg b/_docs/img/events/13.jpg
new file mode 100644
index 00000000..af81a7f0
Binary files /dev/null and b/_docs/img/events/13.jpg differ
diff --git a/_docs/img/events/14.jpg b/_docs/img/events/14.jpg
new file mode 100644
index 00000000..53221968
Binary files /dev/null and b/_docs/img/events/14.jpg differ
diff --git a/_docs/img/events/15.jpg b/_docs/img/events/15.jpg
new file mode 100644
index 00000000..14aa4cd2
Binary files /dev/null and b/_docs/img/events/15.jpg differ
diff --git a/_docs/img/events/15.png b/_docs/img/events/15.png
new file mode 100644
index 00000000..b1fe91cc
Binary files /dev/null and b/_docs/img/events/15.png differ
diff --git a/_docs/img/events/16.jpg b/_docs/img/events/16.jpg
new file mode 100644
index 00000000..4e77816f
Binary files /dev/null and b/_docs/img/events/16.jpg differ
diff --git a/_docs/img/events/17.jpg b/_docs/img/events/17.jpg
new file mode 100644
index 00000000..a8e94528
Binary files /dev/null and b/_docs/img/events/17.jpg differ
diff --git a/_docs/img/events/18.jpg b/_docs/img/events/18.jpg
new file mode 100644
index 00000000..8cbe6f94
Binary files /dev/null and b/_docs/img/events/18.jpg differ
diff --git a/_docs/img/events/19.jpg b/_docs/img/events/19.jpg
new file mode 100644
index 00000000..e250b7bd
Binary files /dev/null and b/_docs/img/events/19.jpg differ
diff --git a/_docs/img/events/2.jpg b/_docs/img/events/2.jpg
new file mode 100644
index 00000000..e2461d34
Binary files /dev/null and b/_docs/img/events/2.jpg differ
diff --git a/_docs/img/events/20.jpg b/_docs/img/events/20.jpg
new file mode 100644
index 00000000..3c616d9e
Binary files /dev/null and b/_docs/img/events/20.jpg differ
diff --git a/_docs/img/events/21.jpg b/_docs/img/events/21.jpg
new file mode 100644
index 00000000..6cccb422
Binary files /dev/null and b/_docs/img/events/21.jpg differ
diff --git a/_docs/img/events/22.jpg b/_docs/img/events/22.jpg
new file mode 100644
index 00000000..e814be0c
Binary files /dev/null and b/_docs/img/events/22.jpg differ
diff --git a/_docs/img/events/23.jpg b/_docs/img/events/23.jpg
new file mode 100644
index 00000000..5cad5714
Binary files /dev/null and b/_docs/img/events/23.jpg differ
diff --git a/_docs/img/events/24.jpg b/_docs/img/events/24.jpg
new file mode 100644
index 00000000..2852e509
Binary files /dev/null and b/_docs/img/events/24.jpg differ
diff --git a/_docs/img/events/25.jpg b/_docs/img/events/25.jpg
new file mode 100644
index 00000000..d5492386
Binary files /dev/null and b/_docs/img/events/25.jpg differ
diff --git a/_docs/img/events/26.jpg b/_docs/img/events/26.jpg
new file mode 100644
index 00000000..6eaca21b
Binary files /dev/null and b/_docs/img/events/26.jpg differ
diff --git a/_docs/img/events/27.jpg b/_docs/img/events/27.jpg
new file mode 100644
index 00000000..6c5b3a25
Binary files /dev/null and b/_docs/img/events/27.jpg differ
diff --git a/_docs/img/events/28.jpg b/_docs/img/events/28.jpg
new file mode 100644
index 00000000..5f6c6a19
Binary files /dev/null and b/_docs/img/events/28.jpg differ
diff --git a/_docs/img/events/29.jpg b/_docs/img/events/29.jpg
new file mode 100644
index 00000000..a04439c1
Binary files /dev/null and b/_docs/img/events/29.jpg differ
diff --git a/_docs/img/events/3.jpg b/_docs/img/events/3.jpg
new file mode 100644
index 00000000..b5aff14b
Binary files /dev/null and b/_docs/img/events/3.jpg differ
diff --git a/_docs/img/events/30.jpg b/_docs/img/events/30.jpg
new file mode 100644
index 00000000..c1e9aca2
Binary files /dev/null and b/_docs/img/events/30.jpg differ
diff --git a/_docs/img/events/31.jpg b/_docs/img/events/31.jpg
new file mode 100644
index 00000000..663f3a30
Binary files /dev/null and b/_docs/img/events/31.jpg differ
diff --git a/_docs/img/events/32.jpg b/_docs/img/events/32.jpg
new file mode 100644
index 00000000..9a0fddfa
Binary files /dev/null and b/_docs/img/events/32.jpg differ
diff --git a/_docs/img/events/33.jpg b/_docs/img/events/33.jpg
new file mode 100644
index 00000000..10246b96
Binary files /dev/null and b/_docs/img/events/33.jpg differ
diff --git a/_docs/img/events/34.jpg b/_docs/img/events/34.jpg
new file mode 100644
index 00000000..222ad18b
Binary files /dev/null and b/_docs/img/events/34.jpg differ
diff --git a/_docs/img/events/35.jpg b/_docs/img/events/35.jpg
new file mode 100644
index 00000000..ff8ef556
Binary files /dev/null and b/_docs/img/events/35.jpg differ
diff --git a/_docs/img/events/36.jpg b/_docs/img/events/36.jpg
new file mode 100644
index 00000000..40a951fa
Binary files /dev/null and b/_docs/img/events/36.jpg differ
diff --git a/_docs/img/events/37.jpg b/_docs/img/events/37.jpg
new file mode 100644
index 00000000..5267ed13
Binary files /dev/null and b/_docs/img/events/37.jpg differ
diff --git a/_docs/img/events/38.jpg b/_docs/img/events/38.jpg
new file mode 100644
index 00000000..b6ccf550
Binary files /dev/null and b/_docs/img/events/38.jpg differ
diff --git a/_docs/img/events/39.jpg b/_docs/img/events/39.jpg
new file mode 100644
index 00000000..d30c8d79
Binary files /dev/null and b/_docs/img/events/39.jpg differ
diff --git a/_docs/img/events/4.jpg b/_docs/img/events/4.jpg
new file mode 100644
index 00000000..d447565f
Binary files /dev/null and b/_docs/img/events/4.jpg differ
diff --git a/_docs/img/events/40.jpg b/_docs/img/events/40.jpg
new file mode 100644
index 00000000..e10f56b7
Binary files /dev/null and b/_docs/img/events/40.jpg differ
diff --git a/_docs/img/events/41.jpg b/_docs/img/events/41.jpg
new file mode 100644
index 00000000..ec9b7e49
Binary files /dev/null and b/_docs/img/events/41.jpg differ
diff --git a/_docs/img/events/42.jpg b/_docs/img/events/42.jpg
new file mode 100644
index 00000000..24d0c2f4
Binary files /dev/null and b/_docs/img/events/42.jpg differ
diff --git a/_docs/img/events/43.jpg b/_docs/img/events/43.jpg
new file mode 100644
index 00000000..cb8f1c31
Binary files /dev/null and b/_docs/img/events/43.jpg differ
diff --git a/_docs/img/events/44.jpg b/_docs/img/events/44.jpg
new file mode 100644
index 00000000..59b3ecb7
Binary files /dev/null and b/_docs/img/events/44.jpg differ
diff --git a/_docs/img/events/45.jpg b/_docs/img/events/45.jpg
new file mode 100644
index 00000000..44dec550
Binary files /dev/null and b/_docs/img/events/45.jpg differ
diff --git a/_docs/img/events/46.jpg b/_docs/img/events/46.jpg
new file mode 100644
index 00000000..1eea4e37
Binary files /dev/null and b/_docs/img/events/46.jpg differ
diff --git a/_docs/img/events/47.jpg b/_docs/img/events/47.jpg
new file mode 100644
index 00000000..dd7bb88e
Binary files /dev/null and b/_docs/img/events/47.jpg differ
diff --git a/_docs/img/events/48.jpg b/_docs/img/events/48.jpg
new file mode 100644
index 00000000..2086b1c3
Binary files /dev/null and b/_docs/img/events/48.jpg differ
diff --git a/_docs/img/events/49.jpg b/_docs/img/events/49.jpg
new file mode 100644
index 00000000..f81e0451
Binary files /dev/null and b/_docs/img/events/49.jpg differ
diff --git a/_docs/img/events/5.jpg b/_docs/img/events/5.jpg
new file mode 100644
index 00000000..333c972c
Binary files /dev/null and b/_docs/img/events/5.jpg differ
diff --git a/_docs/img/events/50.jpg b/_docs/img/events/50.jpg
new file mode 100644
index 00000000..568eabf0
Binary files /dev/null and b/_docs/img/events/50.jpg differ
diff --git a/_docs/img/events/51.jpg b/_docs/img/events/51.jpg
new file mode 100644
index 00000000..1a3f70c3
Binary files /dev/null and b/_docs/img/events/51.jpg differ
diff --git a/_docs/img/events/52.jpg b/_docs/img/events/52.jpg
new file mode 100644
index 00000000..b66d2a22
Binary files /dev/null and b/_docs/img/events/52.jpg differ
diff --git a/_docs/img/events/52.png b/_docs/img/events/52.png
new file mode 100644
index 00000000..3c0c13c8
Binary files /dev/null and b/_docs/img/events/52.png differ
diff --git a/_docs/img/events/53.jpg b/_docs/img/events/53.jpg
new file mode 100644
index 00000000..c3e488bb
Binary files /dev/null and b/_docs/img/events/53.jpg differ
diff --git a/_docs/img/events/54.jpg b/_docs/img/events/54.jpg
new file mode 100644
index 00000000..6dbfc95e
Binary files /dev/null and b/_docs/img/events/54.jpg differ
diff --git a/_docs/img/events/55.jpg b/_docs/img/events/55.jpg
new file mode 100644
index 00000000..fff606c2
Binary files /dev/null and b/_docs/img/events/55.jpg differ
diff --git a/_docs/img/events/56.jpg b/_docs/img/events/56.jpg
new file mode 100644
index 00000000..15fac681
Binary files /dev/null and b/_docs/img/events/56.jpg differ
diff --git a/_docs/img/events/57.jpg b/_docs/img/events/57.jpg
new file mode 100644
index 00000000..60196800
Binary files /dev/null and b/_docs/img/events/57.jpg differ
diff --git a/_docs/img/events/58.jpg b/_docs/img/events/58.jpg
new file mode 100644
index 00000000..e9ff8af9
Binary files /dev/null and b/_docs/img/events/58.jpg differ
diff --git a/_docs/img/events/59.jpg b/_docs/img/events/59.jpg
new file mode 100644
index 00000000..48c58e01
Binary files /dev/null and b/_docs/img/events/59.jpg differ
diff --git a/_docs/img/events/6.jpg b/_docs/img/events/6.jpg
new file mode 100644
index 00000000..7be2810b
Binary files /dev/null and b/_docs/img/events/6.jpg differ
diff --git a/_docs/img/events/60.jpg b/_docs/img/events/60.jpg
new file mode 100644
index 00000000..408cebb3
Binary files /dev/null and b/_docs/img/events/60.jpg differ
diff --git a/_docs/img/events/7.jpg b/_docs/img/events/7.jpg
new file mode 100644
index 00000000..546a8bab
Binary files /dev/null and b/_docs/img/events/7.jpg differ
diff --git a/_docs/img/events/7.png b/_docs/img/events/7.png
new file mode 100644
index 00000000..a2f60686
Binary files /dev/null and b/_docs/img/events/7.png differ
diff --git a/_docs/img/events/8.jpg b/_docs/img/events/8.jpg
new file mode 100644
index 00000000..1c78a313
Binary files /dev/null and b/_docs/img/events/8.jpg differ
diff --git a/_docs/img/events/9.jpg b/_docs/img/events/9.jpg
new file mode 100644
index 00000000..bb6d752d
Binary files /dev/null and b/_docs/img/events/9.jpg differ
diff --git a/_docs/index.md b/_docs/index.md
index d2f290e2..d3943d2c 100644
--- a/_docs/index.md
+++ b/_docs/index.md
@@ -1,6 +1,6 @@
# HTML5 魔塔样板说明文档
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。
diff --git a/_docs/personalization.md b/_docs/personalization.md
index c8f517e6..ca4755ae 100644
--- a/_docs/personalization.md
+++ b/_docs/personalization.md
@@ -1,6 +1,6 @@
# 个性化
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。
@@ -22,6 +22,7 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们
- paint**[D]**:绘图层;主要用来进行绘图模式。(z-index: 95)
- curtain:色调层;用来控制当前楼层的画面色调 (z-index: 125)
- image1\~50**[D]**:图片层;用来绘制图片等操作。(z-index: 100+code, 101~150)
+- uievent**[D]**:自定义UI绘制层;用来进行自定义UI绘制等操作。(z-index:135,可以通过事件设置该值)
- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 140)
- data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 (z-index: 170)
@@ -29,6 +30,8 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们
而,色调层的z-index是25,ui层的z-index是140;因此,图片编号在1~24的将被色调层遮挡,25~40的将被ui层遮挡,41~50的将遮挡UI层。
+uievent层为自定义UI绘制所在的层,其z值初始是135,可以通过事件设置;自定义绘制的闪烁光标所在层的z值永远比该值大1。
+
### 动态创建canvas
从V2.5.3开始,可以在H5样板中任意动态创建canvas并进行使用。
@@ -559,8 +562,6 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0);
如果flag:skill不为0,则代表当前处于某个技能开启状态,且状态栏显示flag:skillName值。伤害计算函数中只需要对flag:skill进行处理即可。
-!> 关于魔力上限:样板中默认没有提供status:manamax
-
### 状态栏的显示
从V2.5开始,魔力值和技能名的状态栏项目已经被添加,可以直接使用。
diff --git a/_docs/script.md b/_docs/script.md
index 96a48838..76903d02 100644
--- a/_docs/script.md
+++ b/_docs/script.md
@@ -1,6 +1,6 @@
# 脚本
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。
@@ -224,7 +224,11 @@ function () {
- 清晰明了。很容易方便知道自己修改过什么,尤其是可以和系统原有代码进行对比。
- 方便整理成新的插件,给其他的塔使用。
-如果我想对xxx文件中的yyy函数进行重写,其模式一般是:`core.xxx.yyy = function (参数列表) { ... }`
+一般而言,复写规则如下:
+
+**对xxx文件中的yyy函数进行复写,规则是`core.xxx.yyy = function (参数列表) { ... }`。**
+
+但是,对于`registerXXX`所注册的函数是无效的,例如直接复写`core.control._animationFrame_globalAnimate`函数是没有效果的。对于这种情况引入的函数,需要注册同名函数,可参见最下面的样例。
下面是几个例子,从简单到复杂。
@@ -317,6 +321,32 @@ core.maps.drawMap = function (floorId, callback) {
详见[call和apply的用法](https://www.jianshu.com/p/80ea0d1c04f8)。
+### 复写全局动画绘制函数
+
+全局动画绘制在`control.js`的`_animationFrame_globalAnimate`函数。
+
+注意到此函数是由`registerAnimationFrame`注册的,因此直接复写是无效的。
+
+其在control.js的注册的定义如下:
+
+```js
+// 注册全局动画函数
+this.registerAnimationFrame("globalAnimate", true, this._animationFrame_globalAnimate);
+```
+
+因此,可以在插件中自行注册一个**同名**的函数来覆盖原始的内容。
+
+```js
+// 插件中复写全局动画绘制函数
+this.myGlobalAnimate = function (timestamp) {
+ // ...... 实际复写的函数内容
+}
+
+// 注册同名(globalAnimate)函数来覆盖系统原始内容
+core.registerAnimationFrame("globalAnimate", true, "myGlobalAnimate");
+```
+
+
==========================================================================================
[继续阅读下一章:API列表](api)
diff --git a/_docs/start.md b/_docs/start.md
index 004ea21f..880bfd08 100644
--- a/_docs/start.md
+++ b/_docs/start.md
@@ -1,6 +1,6 @@
# 快速上手
-?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} *
+?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} *
在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔!
@@ -235,7 +235,7 @@ HTML5的塔都是可以进行控制台调试的。
## 编辑器的基本操作
-- **Alt+0~9, Ctrl+0~9** 保存和读取当前选中图块
+- **Alt+0~9, 0~9** 保存和读取当前选中图块
- **W/A/S/D** 移动大地图
- **Ctrl+Z** 撤销上次绘图
- **Ctrl+Y** 重做上次绘图
diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4
index b9bf42d0..5bc7ce65 100644
--- a/_server/MotaAction.g4
+++ b/_server/MotaAction.g4
@@ -10,7 +10,7 @@ event_m
/* event_m
tooltip : 编辑魔塔的事件
-helpUrl : https://h5mota.com/games/template/docs/#/event
+helpUrl : https://h5mota.com/games/template/_docs/#/event
default : [false,null,null,null,null]
B_0_List_0=eval(B_0_List_0);
var code = {
@@ -26,6 +26,27 @@ return code;
*/;
+//自动事件 事件编辑器入口之一
+autoEvent_m
+ : '自动事件:' '触发条件' EvalString '优先级' Int BGNL? Newline '仅在本层检测' Bool '事件流中延迟执行' Bool '允许多次执行' Bool BGNL? Newline action+ BEND
+
+
+/* autoEvent_m
+tooltip : ?????
+helpUrl : https://h5mota.com/games/template/_docs/#/event
+default : ["flag:__door__==2",0,true,false,false,null]
+var code = {
+ "condition": EvalString_0, // 条件不可为null
+ "currentFloor": Bool_0, // 是否仅在本层检测
+ "priority": Int_0, // 优先级
+ "delayExecute": Bool_1, // 延迟执行
+ "multiExecute": Bool_2, // 是否允许多次执行
+ "data": 'autoEvent_asdfefw', // 事件列表
+};
+code=JSON.stringify(code,null,2).split('"autoEvent_asdfefw"').join('[\n'+action_0+']\n');
+return code;
+*/;
+
//升级 事件编辑器入口之一
level_m
: '等级提升' BGNL? Newline levelCase+ BEND
@@ -33,7 +54,7 @@ level_m
/* level_m
tooltip : 升级事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%bb%8f%e9%aa%8c%e5%8d%87%e7%ba%a7%ef%bc%88%e8%bf%9b%e9%98%b6%2f%e5%a2%83%e7%95%8c%e5%a1%94%ef%bc%89
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%bb%8f%e9%aa%8c%e5%8d%87%e7%ba%a7%ef%bc%88%e8%bf%9b%e9%98%b6%2f%e5%a2%83%e7%95%8c%e5%a1%94%ef%bc%89
var code = '[\n'+levelCase_0+']\n';
return code;
*/;
@@ -44,7 +65,7 @@ levelCase
/* levelCase
tooltip : 升级设定
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%bb%8f%e9%aa%8c%e5%8d%87%e7%ba%a7%ef%bc%88%e8%bf%9b%e9%98%b6%2f%e5%a2%83%e7%95%8c%e5%a1%94%ef%bc%89
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%bb%8f%e9%aa%8c%e5%8d%87%e7%ba%a7%ef%bc%88%e8%bf%9b%e9%98%b6%2f%e5%a2%83%e7%95%8c%e5%a1%94%ef%bc%89
default : [0,"",false,null]
colour : this.subColor
Bool_0 = Bool_0?', "clear": true':'';
@@ -58,13 +79,14 @@ shop_m
/* shop_m
tooltip : 全局商店列表
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
var code = '['+shoplist_0+']\n';
return code;
*/;
shoplist
: shopsub
+ | shopitem
| shopcommonevent
| emptyshop
;
@@ -79,11 +101,11 @@ return code;
*/;
shopcommonevent
- : '商店 id' IdString '快捷商店栏中名称' EvalString BGNL? '未开启状态则不显示在列表中' Bool BGNL? '执行的公共事件 id' EvalString '参数列表' EvalString?
+ : '公共事件版商店 id' IdString '快捷商店栏中名称' EvalString BGNL? '未开启状态则不显示在列表中' Bool BGNL? '执行的公共事件 id' EvalString '参数列表' EvalString?
/* shopcommonevent
tooltip : 全局商店, 执行一个公共事件
-helpUrl : https://h5mota.com/games/template/docs/#/
+helpUrl : https://h5mota.com/games/template/_docs/#/
default : ["shop1","回收钥匙商店",false,"回收钥匙商店",""]
if (EvalString_2) {
if (EvalString_2.indexOf('"')>=0)
@@ -109,12 +131,12 @@ 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
+ : '商店 id' IdString '标题' EvalString '图标' IdString BGNL? Newline '快捷商店栏中名称' EvalString '共用times' Bool BGNL? Newline '未开启状态则不显示在列表中' Bool BGNL? Newline '使用' ShopUse_List '消耗' EvalString BGNL? Newline '显示文字' EvalString BGNL? Newline shopChoices+ BEND
/* shopsub
tooltip : 全局商店,消耗填-1表示每个选项的消耗不同,正数表示消耗数值
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
default : ["shop1","贪婪之神","blueShop","1F金币商店",false,false,null,"20+10*times*(times+1)","勇敢的武士啊, 给我${need}金币就可以:"]
var code = {
'id': IdString_0,
@@ -138,7 +160,7 @@ shopChoices
/* shopChoices
tooltip : 商店选项,商店消耗是-1时,这里的消耗对应各自选项的消耗,商店消耗不是-1时这里的消耗不填
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
default : ["攻击+1",""]
colour : this.subColor
EvalString_1 = EvalString_1 && (', "need": "'+EvalString_1+'"');
@@ -156,6 +178,45 @@ var code = idString_e_0+'+='+expression_0+';'
return code;
*/;
+shopitem
+ : '道具商店 id' IdString '快捷商店栏中名称' EvalString BGNL? '未开启状态则不显示在列表中' Bool BGNL? Newline shopItemChoices+ BEND
+
+
+/* shopitem
+tooltip : 道具商店
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
+default : ["itemShop","道具商店",false]
+var code = {
+ 'id': IdString_0,
+ 'item': true,
+ 'textInList': EvalString_0,
+ 'mustEnable': Bool_0,
+ 'choices': 'choices_aqwedsa'
+}
+code=JSON.stringify(code,null,2).split('"choices_aqwedsa"').join('[\n'+shopItemChoices_0+']\n')+',\n';
+return code;
+*/;
+
+shopItemChoices
+ : '道具名' IdString '存量' EvalString? '买入价格' EvalString? '卖出价格' EvalString? '出现条件' EvalString? BEND
+
+
+
+/* shopItemChoices
+tooltip : 道具商店选项,每一项是道具名;买入或卖出可以不填表示只能卖出或买入
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e5%85%a8%e5%b1%80%e5%95%86%e5%ba%97
+default : ["yellowKey","","10","",""]
+colour : this.subColor
+if (EvalString_0 && !/^\d+$/.test(EvalString_0)) throw "存量必须不填或非负整数";
+EvalString_0 = EvalString_0 ? (', "number": '+EvalString_0) : '';
+EvalString_1 = EvalString_1 ? (', "money": "'+EvalString_1+'"') : '';
+EvalString_2 = EvalString_2 ? (', "sell": "'+EvalString_2+'"') : '';
+if (!EvalString_1 && !EvalString_2) throw "买入金额和卖出金额至少需要填写一个";
+EvalString_3 = EvalString_3 ? (', "condition": "'+EvalString_3+'"') : '';
+var code = '{"id": "' + IdString_0 + '"' + EvalString_0 + EvalString_1 + EvalString_2 + EvalString_3 + '},\n';
+return code;
+*/;
+
//afterBattle 事件编辑器入口之一
afterBattle_m
: '战斗结束后' BGNL? Newline action+ BEND
@@ -163,7 +224,7 @@ afterBattle_m
/* afterBattle_m
tooltip : 系统引发的自定义事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -175,7 +236,7 @@ afterGetItem_m
/* afterGetItem_m
tooltip : 系统引发的自定义事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -187,7 +248,7 @@ afterOpenDoor_m
/* afterOpenDoor_m
tooltip : 系统引发的自定义事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -199,7 +260,7 @@ firstArrive_m
/* firstArrive_m
tooltip : 首次到达楼层
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -211,7 +272,7 @@ eachArrive_m
/* eachArrive_m
tooltip : 每次到达楼层
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=%e7%b3%bb%e7%bb%9f%e5%bc%95%e5%8f%91%e7%9a%84%e8%87%aa%e5%ae%9a%e4%b9%89%e4%ba%8b%e4%bb%b6
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -223,12 +284,12 @@ changeFloor_m
/* changeFloor_m
tooltip : 楼梯, 传送门, 如果目标楼层有多个楼梯, 写upFloor或downFloor可能会导致到达的楼梯不确定, 这时候请使用loc方式来指定具体的点位置
-helpUrl : https://h5mota.com/games/template/docs/#/element?id=%e8%b7%af%e9%9a%9c%ef%bc%8c%e6%a5%bc%e6%a2%af%ef%bc%8c%e4%bc%a0%e9%80%81%e9%97%a8
-default : [null,"MT1",null,0,0,null,500,null]
+helpUrl : https://h5mota.com/games/template/_docs/#/element?id=%e8%b7%af%e9%9a%9c%ef%bc%8c%e6%a5%bc%e6%a2%af%ef%bc%8c%e4%bc%a0%e9%80%81%e9%97%a8
+default : [null,"MTx",null,0,0,null,500,null]
var toFloorId = IdString_0;
if (Floor_List_0!='floorId') toFloorId = Floor_List_0;
var loc = ', "loc": ['+Number_0+', '+Number_1+']';
-if (Stair_List_0==='now')loc = '';
+if (Stair_List_0===':now') loc = '';
else 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):'';
@@ -244,7 +305,19 @@ commonEvent_m
/* commonEvent_m
tooltip : 公共事件
-helpUrl : https://h5mota.com/games/template/docs/#/event
+helpUrl : https://h5mota.com/games/template/_docs/#/event
+var code = '[\n'+action_0+']\n';
+return code;
+*/;
+
+//item 事件编辑器入口之一
+item_m
+ : '使用道具事件' BGNL? Newline action+ BEND
+
+
+/* item_m
+tooltip : 使用道具事件
+helpUrl : https://h5mota.com/games/template/_docs/#/event
var code = '[\n'+action_0+']\n';
return code;
*/;
@@ -261,6 +334,7 @@ action
| tip_s
| setValue_s
| addValue_s
+ | setEnemy_s
| setFloor_s
| setGlobalAttribute_s
| setGlobalValue_s
@@ -282,17 +356,23 @@ action
| update_s
| showStatusBar_s
| hideStatusBar_s
- | updateEnemys_s
+ | showHero_s
+ | hideHero_s
| sleep_s
| wait_s
| waitAsync_s
| battle_s
+ | battle_1_s
| openDoor_s
| closeDoor_s
| changeFloor_s
| changePos_0_s
| changePos_1_s
+ | setViewport_s
+ | moveViewport_s
| useItem_s
+ | loadEquip_s
+ | unloadEquip_s
| openShop_s
| disableShop_s
| follow_s
@@ -340,6 +420,27 @@ action
| callSave_s
| autoSave_s
| callLoad_s
+ | previewUI_s
+ | clearMap_s
+ | clearMap_1_s
+ | setAttribute_s
+ | fillText_s
+ | fillBoldText_s
+ | drawTextContent_s
+ | fillRect_s
+ | strokeRect_s
+ | drawLine_s
+ | drawArrow_s
+ | fillPolygon_s
+ | strokePolygon_s
+ | fillCircle_s
+ | strokeCircle_s
+ | drawImage_s
+ | drawImage_1_s
+ | drawIcon_s
+ | drawBackground_s
+ | drawSelector_s
+ | drawSelector_1_s
| unknown_s
| function_s
| pass_s
@@ -351,7 +452,7 @@ text_0_s
/* text_0_s
tooltip : text:显示一段文字(剧情)
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=text%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%96%87%E5%AD%97%EF%BC%88%E5%89%A7%E6%83%85%EF%BC%89
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=text%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%96%87%E5%AD%97%EF%BC%88%E5%89%A7%E6%83%85%EF%BC%89
default : ["欢迎使用事件编辑器(双击方块进入多行编辑)"]
var code = '"'+EvalString_0+'",\n';
return code;
@@ -363,7 +464,7 @@ text_1_s
/* text_1_s
tooltip : text:显示一段文字(剧情),选项较多请右键点击帮助
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=text%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%96%87%E5%AD%97%EF%BC%88%E5%89%A7%E6%83%85%EF%BC%89
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=text%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%96%87%E5%AD%97%EF%BC%88%E5%89%A7%E6%83%85%EF%BC%89
default : ["小妖精","fairy","","欢迎使用事件编辑器(双击方块进入多行编辑)"]
var title='';
if (EvalString_0==''){
@@ -373,7 +474,7 @@ if (EvalString_0==''){
if (IdString_0=='')title='\\t['+EvalString_0+']';
else title='\\t['+EvalString_0+','+IdString_0+']';
}
-if(EvalString_1 && !(/^(up|down)(,hero)?(,([+-]?\d+),([+-]?\d+))?$/.test(EvalString_1))) {
+if(EvalString_1 && !(/^(up|center|down|hero|null)(,(hero|null|\d+,\d+|\d+))?$/.test(EvalString_1))) {
throw new Error('对话框效果的用法请右键点击帮助');
}
EvalString_1 = EvalString_1 && ('\\b['+EvalString_1+']');
@@ -387,7 +488,7 @@ comment_s
/* comment_s
tooltip : comment:添加一段会被游戏跳过的注释内容
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=comment%ef%bc%9a%e6%b7%bb%e5%8a%a0%e6%b3%a8%e9%87%8a
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=comment%ef%bc%9a%e6%b7%bb%e5%8a%a0%e6%b3%a8%e9%87%8a
default : ["可以在这里写添加任何注释内容"]
colour : this.commentColor
var code = '{"type": "comment", "text": "'+EvalString_0+'"},\n';
@@ -400,7 +501,7 @@ autoText_s
/* autoText_s
tooltip : autoText:自动剧情文本,用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=autotext%EF%BC%9A%E8%87%AA%E5%8A%A8%E5%89%A7%E6%83%85%E6%96%87%E6%9C%AC
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=autotext%EF%BC%9A%E8%87%AA%E5%8A%A8%E5%89%A7%E6%83%85%E6%96%87%E6%9C%AC
default : ["小妖精","fairy","",3000,"用户无法跳过自动剧情文本,大段剧情文本请添加“是否跳过剧情”的提示"]
var title='';
if (EvalString_0==''){
@@ -424,7 +525,7 @@ scrollText_s
/* 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
+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,1.4,false,"时间是总时间,可以使用setText事件来控制字体、颜色、大小、偏移量等"]
Bool_0 = Bool_0?', "async": true':'';
var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+', "lineHeight": '+Number_0+'},\n';
@@ -432,16 +533,16 @@ return code;
*/;
setText_s
- : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? '对齐' SetTextAlign_List? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline
+ : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? '对齐' TextAlign_List? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' 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,"",null,"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',null,"","",""]
+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,"",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)?$/;
+TextAlign_List_0 = TextAlign_List_0==='null'?'': ', "align": "'+TextAlign_List_0+'"';
+var colorRe = MotaActionFunctions.pattern.colorRe;
if (EvalString_0) {
if (!/^\d+$/.test(EvalString_0))throw new Error('像素偏移量必须是整数或不填');
EvalString_0 = ', "offset": '+EvalString_0;
@@ -477,8 +578,12 @@ if (EvalString_6) {
if (!/^\d+$/.test(EvalString_6))throw new Error('打字时间间隔必须是整数或不填');
EvalString_6 = ', "time": '+EvalString_6;
}
+if (EvalString_7) {
+ if (!/^\d+$/.test(EvalString_7))throw new Error('字符间距必须是整数或不填');
+ EvalString_7 = ', "interval": '+EvalString_7;
+}
B_1_List_0 = B_1_List_0==='null'?'':', "bold": '+B_1_List_0;
-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';
+var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+TextAlign_List_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+EvalString_6+EvalString_7+'},\n';
return code;
*/;
@@ -488,7 +593,7 @@ tip_s
/* tip_s
tooltip : tip:显示一段提示文字
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=tip%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%8F%90%E7%A4%BA%E6%96%87%E5%AD%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=tip%EF%BC%9A%E6%98%BE%E7%A4%BA%E4%B8%80%E6%AE%B5%E6%8F%90%E7%A4%BA%E6%96%87%E5%AD%97
default : ["这段话将在左上角以气泡形式显示",""]
IdString_0 = IdString_0 && (', "icon": "' + IdString_0 + '"');
var code = '{"type": "tip", "text": "'+EvalString_0+'"'+IdString_0+'},\n';
@@ -496,36 +601,53 @@ return code;
*/;
setValue_s
- : '数值操作' ':' '名称' idString_e '值' expression Newline
+ : '数值操作' ':' '名称' idString_e '值' expression '不刷新状态栏' Bool Newline
/* setValue_s
tooltip : setValue:设置勇士的某个属性、道具个数, 或某个变量/Flag的值
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setvalue%EF%BC%9A%E8%AE%BE%E7%BD%AE%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%8Fflag%E7%9A%84%E5%80%BC
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setvalue%EF%BC%9A%E8%AE%BE%E7%BD%AE%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%8Fflag%E7%9A%84%E5%80%BC
colour : this.dataColor
-var code = '{"type": "setValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n';
+Bool_0 = Bool_0 ? ', "norefresh": true' : '';
+var code = '{"type": "setValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"' + Bool_0 + '},\n';
return code;
*/;
addValue_s
- : '数值增减' ':' '名称' idString_e '+=' expression Newline
+ : '数值增减' ':' '名称' idString_e '+=' expression '不刷新状态栏' Bool Newline
/* 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
+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": "addValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n';
+Bool_0 = Bool_0 ? ', "norefresh": true' : '';
+var code = '{"type": "addValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"' + Bool_0 + '},\n';
return code;
*/;
+
+setEnemy_s
+ : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List '值' expression Newline
+
+
+/* setEnemy_s
+tooltip : setEnemy:设置某个怪物的属性
+default : ["greenSlime", "atk", "0"]
+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": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'", "value": "'+expression_0+'"},\n';
+return code;
+*/;
+
+
setFloor_s
: '设置楼层属性' ':' Floor_Meta_List '楼层名' IdString? '值' EvalString Newline
/* setFloor_s
tooltip : setFloor:设置楼层属性;该楼层属性和编辑器中的楼层属性一一对应
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setFloor%ef%bc%9a%e8%ae%be%e7%bd%ae%e6%a5%bc%e5%b1%82%e5%b1%9e%e6%80%a7
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setFloor%ef%bc%9a%e8%ae%be%e7%bd%ae%e6%a5%bc%e5%b1%82%e5%b1%9e%e6%80%a7
default : ["title","","'字符串类型的值要加引号,其他类型则不用'"]
colour : this.dataColor
IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"');
@@ -540,7 +662,7 @@ setGlobalAttribute_s
/* setGlobalAttribute_s
tooltip : setGlobalAttribute:设置全局属性
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setGlobalAttribute%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e5%85%a8%e5%b1%80%e5%b1%9e%e6%80%a7
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setGlobalAttribute%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e5%85%a8%e5%b1%80%e5%b1%9e%e6%80%a7
default : ["font","Verdana"]
colour : this.dataColor
var code = '{"type": "setGlobalAttribute", "name": "'+Global_Attribute_List_0+'", "value": "'+EvalString_0+'"},\n';
@@ -554,7 +676,7 @@ setGlobalValue_s
/* setGlobalValue_s
tooltip : setGlobalValue:设置全局属性
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setGlobalValue%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e5%85%a8%e5%b1%80%e6%95%b0%e5%80%bc
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setGlobalValue%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e5%85%a8%e5%b1%80%e6%95%b0%e5%80%bc
default : ["lavaDamage","100"]
colour : this.dataColor
var code = '{"type": "setGlobalValue", "name": "'+Global_Value_List_0+'", "value": '+EvalString_0+'},\n';
@@ -568,7 +690,7 @@ setGlobalFlag_s
/* setGlobalFlag_s
tooltip : setGlobalFlag:设置系统开关
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setGlobalFlag%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e7%b3%bb%e7%bb%9f%e5%bc%80%e5%85%b3
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setGlobalFlag%ef%bc%9a%e8%ae%be%e7%bd%ae%e4%b8%80%e4%b8%aa%e7%b3%bb%e7%bb%9f%e5%bc%80%e5%85%b3
default : ["enableFloor","true"]
colour : this.dataColor
var code = '{"type": "setGlobalFlag", "name": "'+Global_Flag_List_0+'", "value": '+Bool_0+'},\n';
@@ -582,12 +704,12 @@ show_s
/* show_s
tooltip : show: 将禁用事件启用,楼层和动画时间可不填,xy可用逗号分隔表示多个点
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=show%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E7%A6%81%E7%94%A8%E4%BA%8B%E4%BB%B6%E5%90%AF%E7%94%A8
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=show%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E7%A6%81%E7%94%A8%E4%BA%8B%E4%BB%B6%E5%90%AF%E7%94%A8
default : ["","","",500,false]
colour : this.mapColor
var floorstr = '';
if (EvalString_0 && EvalString_1) {
- var pattern1 = /^flag:[0-9a-zA-Z_][0-9a-zA-Z_\-:]*$/;
+ var pattern1 = MotaActionFunctions.pattern.id;
if(pattern1.test(EvalString_0) || pattern1.test(EvalString_1)){
EvalString_0=MotaActionFunctions.PosString_pre(EvalString_0);
EvalString_1=MotaActionFunctions.PosString_pre(EvalString_1);
@@ -615,12 +737,12 @@ hide_s
/* hide_s
tooltip : hide: 将一个启用事件禁用,所有参数均可不填,代表禁用事件自身,xy可用逗号分隔表示多个点
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=hide%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E5%90%AF%E7%94%A8%E4%BA%8B%E4%BB%B6%E7%A6%81%E7%94%A8
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=hide%EF%BC%9A%E5%B0%86%E4%B8%80%E4%B8%AA%E5%90%AF%E7%94%A8%E4%BA%8B%E4%BB%B6%E7%A6%81%E7%94%A8
default : ["","","",500,false]
colour : this.mapColor
var floorstr = '';
if (EvalString_0 && EvalString_1) {
- var pattern1 = /^flag:[0-9a-zA-Z_][0-9a-zA-Z_\-:]*$/;
+ var pattern1 = MotaActionFunctions.pattern.id;
if(pattern1.test(EvalString_0) || pattern1.test(EvalString_1)){
EvalString_0=MotaActionFunctions.PosString_pre(EvalString_0);
EvalString_1=MotaActionFunctions.PosString_pre(EvalString_1);
@@ -643,15 +765,16 @@ return code;
*/;
trigger_s
- : '触发事件' 'x' PosString ',' 'y' PosString Newline
+ : '触发事件' 'x' PosString ',' 'y' PosString '不结束当前事件' Bool Newline
/* trigger_s
tooltip : trigger: 立即触发另一个地点的事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=trigger%EF%BC%9A%E7%AB%8B%E5%8D%B3%E8%A7%A6%E5%8F%91%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%9C%B0%E7%82%B9%E7%9A%84%E4%BA%8B%E4%BB%B6
-default : ["0","0"]
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=trigger%EF%BC%9A%E7%AB%8B%E5%8D%B3%E8%A7%A6%E5%8F%91%E5%8F%A6%E4%B8%80%E4%B8%AA%E5%9C%B0%E7%82%B9%E7%9A%84%E4%BA%8B%E4%BB%B6
+default : ["0","0",false]
colour : this.eventColor
-var code = '{"type": "trigger", "loc": ['+PosString_0+','+PosString_1+']},\n';
+Bool_0 = Bool_0 ?', "keep": true':'';
+var code = '{"type": "trigger", "loc": ['+PosString_0+','+PosString_1+']'+Bool_0+'},\n';
return code;
*/;
@@ -661,7 +784,7 @@ insert_1_s
/* 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
+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 : ["加点事件", ""]
colour : this.eventColor
if (EvalString_1) {
@@ -681,12 +804,12 @@ return code;
*/;
insert_2_s
- : '插入事件' 'x' PosString ',' 'y' PosString Event_List? '楼层' IdString? '参数列表' EvalString? ENewline
+ : '插入事件' 'x' PosString ',' 'y' PosString Event_List? '楼层' IdString? '参数列表' EvalString? Newline
/* 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
+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",null,"",""]
colour : this.eventColor
IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"');
@@ -714,7 +837,7 @@ revisit_s
/* revisit_s
tooltip : revisit: 立即重启当前事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=revisit%EF%BC%9A%E7%AB%8B%E5%8D%B3%E9%87%8D%E5%90%AF%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=revisit%EF%BC%9A%E7%AB%8B%E5%8D%B3%E9%87%8D%E5%90%AF%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6
colour : this.eventColor
var code = '{"type": "revisit"},\n';
return code;
@@ -726,24 +849,37 @@ exit_s
/* exit_s
tooltip : exit: 立刻结束当前事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=exit%EF%BC%9A%E7%AB%8B%E5%88%BB%E7%BB%93%E6%9D%9F%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=exit%EF%BC%9A%E7%AB%8B%E5%88%BB%E7%BB%93%E6%9D%9F%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6
colour : this.eventColor
var code = '{"type": "exit"},\n';
return code;
*/;
setBlock_s
- : '转变图块为' EvalString 'x' PosString? ',' 'y' PosString? '楼层' IdString? Newline
+ : '转变图块为' EvalString 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? Newline
/* setBlock_s
tooltip : setBlock:设置某个图块,忽略坐标楼层则为当前事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setblock%EF%BC%9A%E8%AE%BE%E7%BD%AE%E6%9F%90%E4%B8%AA%E5%9B%BE%E5%9D%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setblock%EF%BC%9A%E8%AE%BE%E7%BD%AE%E6%9F%90%E4%B8%AA%E5%9B%BE%E5%9D%97
colour : this.mapColor
default : ["yellowDoor","","",""]
var floorstr = '';
-if (PosString_0 && PosString_1) {
- floorstr = ', "loc": ['+PosString_0+','+PosString_1+']';
+if (EvalString_1 && EvalString_2) {
+ var pattern1 = MotaActionFunctions.pattern.id;
+ if(pattern1.test(EvalString_1) || pattern1.test(EvalString_2)){
+ EvalString_1=MotaActionFunctions.PosString_pre(EvalString_1);
+ EvalString_2=MotaActionFunctions.PosString_pre(EvalString_2);
+ EvalString_1=[EvalString_1,EvalString_2]
+ } else {
+ var pattern2 = /^([+-]?\d+)(,[+-]?\d+)*$/;
+ if(!pattern2.test(EvalString_1) || !pattern2.test(EvalString_2))throw new Error('坐标格式错误,请右键点击帮助查看格式');
+ EvalString_1=EvalString_1.split(',');
+ EvalString_2=EvalString_2.split(',');
+ if(EvalString_1.length!==EvalString_2.length)throw new Error('坐标格式错误,请右键点击帮助查看格式');
+ for(var ii=0;ii50) throw new Error('图片编号在1~50之间');
@@ -1196,7 +1435,7 @@ showImage_1_s
/* 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
+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之间');
@@ -1215,7 +1454,7 @@ showTextImage_s
/* 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
+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.4,1,0,false]
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
@@ -1230,7 +1469,7 @@ hideImage_s
/* hideImage_s
tooltip : hideImage:清除图片
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=hideImage%ef%bc%9a%e6%b8%85%e9%99%a4%e5%9b%be%e7%89%87
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=hideImage%ef%bc%9a%e6%b8%85%e9%99%a4%e5%9b%be%e7%89%87
colour : this.printColor
default : [1,0,false]
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
@@ -1245,7 +1484,7 @@ showGif_0_s
/* showGif_0_s
tooltip : showGif:显示动图
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=showgif%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%8A%A8%E5%9B%BE
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=showgif%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%8A%A8%E5%9B%BE
default : ["bg.gif","0","0"]
colour : this.printColor
var code = '{"type": "showGif", "name": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+']},\n';
@@ -1258,7 +1497,7 @@ showGif_1_s
/* showGif_1_s
tooltip : showGif:清除所有显示的动图
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=showgif%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%8A%A8%E5%9B%BE
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=showgif%EF%BC%9A%E6%98%BE%E7%A4%BA%E5%8A%A8%E5%9B%BE
colour : this.printColor
var code = '{"type": "showGif"},\n';
return code;
@@ -1271,7 +1510,7 @@ moveImage_s
/* moveImage_s
tooltip : moveImage:图片移动
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=moveImage%ef%bc%9a%e5%9b%be%e7%89%87%e7%a7%bb%e5%8a%a8
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=moveImage%ef%bc%9a%e5%9b%be%e7%89%87%e7%a7%bb%e5%8a%a8
default : [1,'','','',500,false]
colour : this.printColor
if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间');
@@ -1290,10 +1529,10 @@ setCurtain_0_s
/* 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
+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)?$/;
+var colorRe = MotaActionFunctions.pattern.colorRe;
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':'';
@@ -1307,7 +1546,7 @@ setCurtain_1_s
/* 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
+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):'';
@@ -1321,10 +1560,10 @@ screenFlash_s
/* screenFlash_s
tooltip : screenFlash: 画面闪烁,动画时间可不填
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=screenFlash%EF%BC%9A%E7%94%BB%E9%9D%A2%E9%97%AA%E7%83%81
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=screenFlash%EF%BC%9A%E7%94%BB%E9%9D%A2%E9%97%AA%E7%83%81
default : ["255,255,255,1",'rgba(255,255,255,1)',500,1,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)?$/;
+var colorRe = MotaActionFunctions.pattern.colorRe;
if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
Int_1 = Int_1!=='' ?(', "times": '+Int_1):'';
var async = Bool_0?', "async": true':'';
@@ -1338,7 +1577,7 @@ setWeather_s
/* setWeather_s
tooltip : setWeather:更改天气
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setweather%EF%BC%9A%E6%9B%B4%E6%94%B9%E5%A4%A9%E6%B0%94
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setweather%EF%BC%9A%E6%9B%B4%E6%94%B9%E5%A4%A9%E6%B0%94
default : [null,1]
colour : this.soundColor
if(Int_0<1 || Int_0>10) throw new Error('天气的强度等级, 在1-10之间');
@@ -1353,8 +1592,8 @@ move_s
/* move_s
tooltip : move: 让某个NPC/怪物移动,位置可不填代表当前事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=move%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AAnpc%E6%80%AA%E7%89%A9%E7%A7%BB%E5%8A%A8
-default : ["","",500,false,false,"上右3下2左上左2"]
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=move%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AAnpc%E6%80%AA%E7%89%A9%E7%A7%BB%E5%8A%A8
+default : ["","",500,false,false,"上右3下2后4左前2"]
colour : this.mapColor
var floorstr = '';
if (PosString_0 && PosString_1) {
@@ -1373,7 +1612,7 @@ moveHero_s
/* moveHero_s
tooltip : moveHero:移动勇士,用这种方式移动勇士的过程中将无视一切地形, 无视一切事件, 中毒状态也不会扣血
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=movehero%EF%BC%9A%E7%A7%BB%E5%8A%A8%E5%8B%87%E5%A3%AB
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=movehero%EF%BC%9A%E7%A7%BB%E5%8A%A8%E5%8B%87%E5%A3%AB
default : [500,false,"上右3下2后4左前2"]
colour : this.dataColor
Int_0 = Int_0!=='' ?(', "time": '+Int_0):'';
@@ -1388,7 +1627,7 @@ jump_s
/* jump_s
tooltip : jump: 让某个NPC/怪物跳跃
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=jump%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AANPC%2F%E6%80%AA%E7%89%A9%E8%B7%B3%E8%B7%83
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=jump%EF%BC%9A%E8%AE%A9%E6%9F%90%E4%B8%AANPC%2F%E6%80%AA%E7%89%A9%E8%B7%B3%E8%B7%83
default : ["","","","",500,true,false]
colour : this.mapColor
var floorstr = '';
@@ -1411,7 +1650,7 @@ jumpHero_s
/* jumpHero_s
tooltip : jumpHero: 跳跃勇士
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=jumpHero%EF%BC%9A%E8%B7%B3%E8%B7%83%E5%8B%87%E5%A3%AB
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=jumpHero%EF%BC%9A%E8%B7%B3%E8%B7%83%E5%8B%87%E5%A3%AB
default : ["","",500,false]
colour : this.dataColor
var floorstr = '';
@@ -1425,15 +1664,16 @@ return code;
*/;
playBgm_s
- : '播放背景音乐' EvalString Newline
+ : '播放背景音乐' EvalString '持续到下个本事件' Bool Newline
/* playBgm_s
tooltip : playBgm: 播放背景音乐
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
-default : ["bgm.mp3"]
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=playbgm%EF%BC%9A%E6%92%AD%E6%94%BE%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
+default : ["bgm.mp3", true]
colour : this.soundColor
-var code = '{"type": "playBgm", "name": "'+EvalString_0+'"},\n';
+Bool_0 = Bool_0 ? ', "keep": true' : '';
+var code = '{"type": "playBgm", "name": "'+EvalString_0+'"'+Bool_0+'},\n';
return code;
*/;
@@ -1443,7 +1683,7 @@ pauseBgm_s
/* pauseBgm_s
tooltip : pauseBgm: 暂停背景音乐
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=pausebgm%EF%BC%9A%E6%9A%82%E5%81%9C%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=pausebgm%EF%BC%9A%E6%9A%82%E5%81%9C%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
colour : this.soundColor
var code = '{"type": "pauseBgm"},\n';
return code;
@@ -1455,7 +1695,7 @@ resumeBgm_s
/* resumeBgm_s
tooltip : resumeBgm: 恢复背景音乐
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=resumebgm%EF%BC%9A%E6%81%A2%E5%A4%8D%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=resumebgm%EF%BC%9A%E6%81%A2%E5%A4%8D%E8%83%8C%E6%99%AF%E9%9F%B3%E4%B9%90
colour : this.soundColor
var code = '{"type": "resumeBgm"},\n';
return code;
@@ -1467,7 +1707,7 @@ loadBgm_s
/* loadBgm_s
tooltip : loadBgm: 预加载某个背景音乐,之后可以直接播放
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=loadBgm%ef%bc%9a%e9%a2%84%e5%8a%a0%e8%bd%bd%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=loadBgm%ef%bc%9a%e9%a2%84%e5%8a%a0%e8%bd%bd%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90
default : ["bgm.mp3"]
colour : this.soundColor
var code = '{"type": "loadBgm", "name": "'+EvalString_0+'"},\n';
@@ -1480,7 +1720,7 @@ freeBgm_s
/* freeBgm_s
tooltip : freeBgm: 释放背景音乐的缓存
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=freeBgm%ef%bc%9a%e9%87%8a%e6%94%be%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90%e7%9a%84%e7%bc%93%e5%ad%98
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=freeBgm%ef%bc%9a%e9%87%8a%e6%94%be%e4%b8%80%e4%b8%aa%e8%83%8c%e6%99%af%e9%9f%b3%e4%b9%90%e7%9a%84%e7%bc%93%e5%ad%98
default : ["bgm.mp3"]
colour : this.soundColor
var code = '{"type": "freeBgm", "name": "'+EvalString_0+'"},\n';
@@ -1493,7 +1733,7 @@ playSound_s
/* 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
+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",false]
colour : this.soundColor
Bool_0 = Bool_0 ? ', "stop": true' : '';
@@ -1507,7 +1747,7 @@ stopSound_s
/* stopSound_s
tooltip : stopSound: 停止所有音效
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=stopSound%ef%bc%9a%e5%81%9c%e6%ad%a2%e6%89%80%e6%9c%89%e9%9f%b3%e6%95%88
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=stopSound%ef%bc%9a%e5%81%9c%e6%ad%a2%e6%89%80%e6%9c%89%e9%9f%b3%e6%95%88
colour : this.soundColor
var code = '{"type": "stopSound"},\n';
return code;
@@ -1519,7 +1759,7 @@ setVolume_s
/* setVolume_s
tooltip : setVolume: 设置音量
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=setvolume%EF%BC%9A%E8%AE%BE%E7%BD%AE%E9%9F%B3%E9%87%8F
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setvolume%EF%BC%9A%E8%AE%BE%E7%BD%AE%E9%9F%B3%E9%87%8F
default : [90, 500, false]
colour : this.soundColor
Int_1 = Int_1!==''?(', "time": '+Int_1):""
@@ -1529,15 +1769,16 @@ return code;
*/;
win_s
- : '游戏胜利,结局' ':' EvalString? '不计入榜单' Bool Newline
+ : '游戏胜利,结局' ':' EvalString? '不计入榜单' Bool '不结束游戏' Bool Newline
/* win_s
tooltip : win: 获得胜利, 该事件会显示获胜页面, 并重新游戏
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=win%EF%BC%9A%E8%8E%B7%E5%BE%97%E8%83%9C%E5%88%A9
-default : ["",false]
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=win%EF%BC%9A%E8%8E%B7%E5%BE%97%E8%83%9C%E5%88%A9
+default : ["",false, false]
Bool_0 = Bool_0?', "norank": 1':'';
-var code = '{"type": "win", "reason": "'+EvalString_0+'"'+Bool_0+'},\n';
+Bool_1 = Bool_1?', "noexit": 1':'';
+var code = '{"type": "win", "reason": "'+EvalString_0+'"'+Bool_0+Bool_1+'},\n';
return code;
*/;
@@ -1547,7 +1788,7 @@ lose_s
/* lose_s
tooltip : lose: 游戏失败, 该事件会显示失败页面, 并重新开始游戏
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=lose%EF%BC%9A%E6%B8%B8%E6%88%8F%E5%A4%B1%E8%B4%A5
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=lose%EF%BC%9A%E6%B8%B8%E6%88%8F%E5%A4%B1%E8%B4%A5
default : [""]
var code = '{"type": "lose", "reason": "'+EvalString_0+'"},\n';
return code;
@@ -1559,7 +1800,7 @@ restart_s
/* restart_s
tooltip : restart: 直接回到标题界面
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=restart%ef%bc%9a%e7%9b%b4%e6%8e%a5%e5%9b%9e%e5%88%b0%e6%a0%87%e9%a2%98%e7%95%8c%e9%9d%a2
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=restart%ef%bc%9a%e7%9b%b4%e6%8e%a5%e5%9b%9e%e5%88%b0%e6%a0%87%e9%a2%98%e7%95%8c%e9%9d%a2
var code = '{"type": "restart"},\n';
return code;
*/;
@@ -1570,7 +1811,7 @@ input_s
/* input_s
tooltip : input:接受用户输入数字, 事件只能接受非负整数输入, 所有非法的输入将全部变成0
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=input%ef%bc%9a%e6%8e%a5%e5%8f%97%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e6%95%b0%e5%ad%97
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=input%ef%bc%9a%e6%8e%a5%e5%8f%97%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e6%95%b0%e5%ad%97
default : ["请输入一个数"]
colour : this.dataColor
var code = '{"type": "input", "text": "'+EvalString_0+'"},\n';
@@ -1583,7 +1824,7 @@ input2_s
/* input2_s
tooltip : input2:接受用户输入文本, 允许用户输入任何形式的文本
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=input2%ef%bc%9a%e6%8e%a5%e5%8f%97%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e6%96%87%e6%9c%ac
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=input2%ef%bc%9a%e6%8e%a5%e5%8f%97%e7%94%a8%e6%88%b7%e8%be%93%e5%85%a5%e6%96%87%e6%9c%ac
default : ["请输入文本"]
colour : this.dataColor
var code = '{"type": "input2", "text": "'+EvalString_0+'"},\n';
@@ -1596,7 +1837,7 @@ if_s
/* if_s
tooltip : if: 条件判断
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=if%EF%BC%9A%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=if%EF%BC%9A%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD
colour : this.eventColor
var code = ['{"type": "if", "condition": "',expression_0,'",\n',
'"true": [\n',action_0,'],\n',
@@ -1611,7 +1852,7 @@ if_1_s
/* if_1_s
tooltip : if: 条件判断
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=if%EF%BC%9A%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=if%EF%BC%9A%E6%9D%A1%E4%BB%B6%E5%88%A4%E6%96%AD
colour : this.eventColor
var code = ['{"type": "if", "condition": "',expression_0,'",\n',
'"true": [\n',action_0,'],\n',
@@ -1625,7 +1866,7 @@ switch_s
/* switch_s
tooltip : switch: 多重条件分歧
-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
+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 : ["判别值"]
colour : this.eventColor
var code = ['{"type": "switch", "condition": "',expression_0,'", "caseList": [\n',
@@ -1640,7 +1881,7 @@ switchCase
/* 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
+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
Bool_0 = Bool_0?', "nobreak": true':'';
@@ -1654,7 +1895,7 @@ choices_s
/* choices_s
tooltip : choices: 给用户提供选项
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9
default : ["","流浪者","woman"]
var title='';
if (EvalString_1==''){
@@ -1673,23 +1914,24 @@ return code;
*/;
choicesContext
- : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour BGNL? Newline action+
+ : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour '出现条件' EvalString? BGNL? Newline action+
/* choicesContext
tooltip : 选项的选择
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9
-default : ["提示文字:红钥匙","",""]
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9
+default : ["提示文字:红钥匙","","",""]
colour : this.subColor
if (EvalString_1) {
- 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)?$/;
+ var colorRe = MotaActionFunctions.pattern.colorRe;
if (colorRe.test(EvalString_1))
EvalString_1 = ', "color": ['+EvalString_1+']';
else
EvalString_1 = ', "color": "'+EvalString_1+'"';
}
+EvalString_2 = EvalString_2 && (', "condition": "'+EvalString_2+'"')
IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):'';
-var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']},\n';
+var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+EvalString_2+', "action": [\n'+action_0+']},\n';
return code;
*/;
@@ -1698,7 +1940,7 @@ confirm_s
/* confirm_s
tooltip : 弹出确认框
-helpUrl : https://h5mota.com/games/template/docs/#/
+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',
@@ -1713,7 +1955,7 @@ while_s
/* while_s
tooltip : while:前置条件循环
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=while%ef%bc%9a%e5%89%8d%e7%bd%ae%e6%9d%a1%e4%bb%b6%e5%be%aa%e7%8e%af
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=while%ef%bc%9a%e5%89%8d%e7%bd%ae%e6%9d%a1%e4%bb%b6%e5%be%aa%e7%8e%af
colour : this.eventColor
var code = ['{"type": "while", "condition": "',expression_0,'",\n',
'"data": [\n',action_0,'],\n',
@@ -1726,7 +1968,7 @@ dowhile_s
/* dowhile_s
tooltip : dowhile:后置条件循环
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=dowhile%ef%bc%9a%e5%90%8e%e7%bd%ae%e6%9d%a1%e4%bb%b6%e5%be%aa%e7%8e%af
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=dowhile%ef%bc%9a%e5%90%8e%e7%bd%ae%e6%9d%a1%e4%bb%b6%e5%be%aa%e7%8e%af
colour : this.eventColor
var code = ['{"type": "dowhile", "condition": "',expression_0,'",\n',
'"data": [\n',action_0,'],\n',
@@ -1735,11 +1977,11 @@ return code;
*/;
break_s
- : '跳出循环' Newline
+ : '跳出当前循环或公共事件' Newline
/* break_s
tooltip : break:跳出循环, 如果break事件不在任何循环中被执行,则和exit等价,即会立刻结束当前事件!
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=break%EF%BC%9A%E8%B7%B3%E5%87%BA%E5%BE%AA%E7%8E%AF
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=break%EF%BC%9A%E8%B7%B3%E5%87%BA%E5%BE%AA%E7%8E%AF
colour : this.eventColor
var code = '{"type": "break"},\n';
return code;
@@ -1750,7 +1992,7 @@ continue_s
/* continue_s
tooltip : continue:继续执行当前循环的下一轮, 如果continue事件不在任何循环中被执行,则和exit等价,即会立刻结束当前事件!
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=continue%EF%BC%9A%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E5%BD%93%E5%89%8D%E5%BE%AA%E7%8E%AF
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=continue%EF%BC%9A%E7%BB%A7%E7%BB%AD%E6%89%A7%E8%A1%8C%E5%BD%93%E5%89%8D%E5%BE%AA%E7%8E%AF
colour : this.eventColor
var code = '{"type": "continue"},\n';
return code;
@@ -1758,25 +2000,63 @@ return code;
wait_s
- : '等待用户操作并获得按键或点击信息'
+ : '等待用户操作并获得按键或点击信息' BGNL? Newline waitContext* BEND Newline
/* wait_s
-tooltip : wait: 等待用户操作并获得按键或点击信息(具体用法看文档)
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=wait%EF%BC%9A%E7%AD%89%E5%BE%85%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C
+tooltip : wait: 等待用户操作并获得按键或点击信息
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=wait%EF%BC%9A%E7%AD%89%E5%BE%85%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C
colour : this.soundColor
-var code = '{"type": "wait"},\n';
+waitContext_0 = waitContext_0 ? (', "data": [\n' + waitContext_0 + ']') : '';
+var code = '{"type": "wait"' + waitContext_0 + '},\n';
return code;
*/;
+waitContext
+ : waitContext_1
+ | waitContext_2
+ | waitContext_empty;
+
+
+waitContext_1
+ : '按键的场合' '键值' Int BGNL? Newline action+ BEND Newline
+
+/* waitContext_1
+tooltip : wait: 等待用户操作并获得按键或点击信息
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=wait%EF%BC%9A%E7%AD%89%E5%BE%85%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C
+colour : this.subColor
+var code = '{"case": "keyboard", "keycode": ' + Int_0 + ', "action": [\n' + action_0 + ']},\n';
+return code;
+*/;
+
+
+waitContext_2
+ : '点击的场合' '像素x范围' PosString '~' PosString '; y范围' PosString '~' PosString BGNL? Newline action+ BEND Newline
+
+/* waitContext_2
+tooltip : wait: 等待用户操作并获得按键或点击信息
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=wait%EF%BC%9A%E7%AD%89%E5%BE%85%E7%94%A8%E6%88%B7%E6%93%8D%E4%BD%9C
+default : [0,32,0,32]
+colour : this.subColor
+var code = '{"case": "mouse", "px": [' + PosString_0 + ',' + PosString_1 + '], "py": [' + PosString_2 + ',' + PosString_3 + '], "action": [\n' + action_0 + ']},\n';
+return code;
+*/;
+
+waitContext_empty : Newline
+
+/* waitContext_empty
+return '';
+*/;
+
+
waitAsync_s
: '等待所有异步事件执行完毕'
/* waitAsync_s
tooltip : waitAsync: 等待所有异步事件执行完毕
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=waitAsync%ef%bc%9a%e7%ad%89%e5%be%85%e6%89%80%e6%9c%89%e5%bc%82%e6%ad%a5%e4%ba%8b%e4%bb%b6%e6%89%a7%e8%a1%8c%e5%ae%8c%e6%af%95
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=waitAsync%ef%bc%9a%e7%ad%89%e5%be%85%e6%89%80%e6%9c%89%e5%bc%82%e6%ad%a5%e4%ba%8b%e4%bb%b6%e6%89%a7%e8%a1%8c%e5%ae%8c%e6%af%95
colour : this.soundColor
var code = '{"type": "waitAsync"},\n';
return code;
@@ -1789,7 +2069,7 @@ callBook_s
/* callBook_s
tooltip : callBook: 呼出怪物手册;返回游戏后将继续执行后面的事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=callBook%ef%bc%9a%e5%91%bc%e5%87%ba%e6%80%aa%e7%89%a9%e6%89%8b%e5%86%8c
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=callBook%ef%bc%9a%e5%91%bc%e5%87%ba%e6%80%aa%e7%89%a9%e6%89%8b%e5%86%8c
colour : this.soundColor
var code = '{"type": "callBook"},\n';
return code;
@@ -1802,7 +2082,7 @@ callSave_s
/* callSave_s
tooltip : callSave: 呼出存档页面
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=callSave%ef%bc%9a%e5%91%bc%e5%87%ba%e5%ad%98%e6%a1%a3%e7%95%8c%e9%9d%a2
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=callSave%ef%bc%9a%e5%91%bc%e5%87%ba%e5%ad%98%e6%a1%a3%e7%95%8c%e9%9d%a2
colour : this.soundColor
var code = '{"type": "callSave"},\n';
return code;
@@ -1810,36 +2090,463 @@ return code;
autoSave_s
- : '自动存档'
+ : '自动存档' '不提示' Bool Newline
/* autoSave_s
tooltip : autoSave: 自动存档
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=autoSave%ef%bc%9a%e8%87%aa%e5%8a%a8%e5%ad%98%e6%a1%a3
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=autoSave%ef%bc%9a%e8%87%aa%e5%8a%a8%e5%ad%98%e6%a1%a3
colour : this.soundColor
-var code = '{"type": "autoSave"},\n';
+default : [false]
+Bool_0 = Bool_0 ? (', "nohint": true') : '';
+var code = '{"type": "autoSave"'+Bool_0+'},\n';
return code;
*/;
callLoad_s
- : '呼出读档页面'
+ : '呼出读档页面' Newline
/* callLoad_s
tooltip : callLoad: 呼出存档页面;返回游戏后将继续执行后面的事件
-helpUrl : https://h5mota.com/games/template/docs/#/event?id=callLoad%ef%bc%9a%e5%91%bc%e5%87%ba%e8%af%bb%e6%a1%a3%e7%95%8c%e9%9d%a2
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=callLoad%ef%bc%9a%e5%91%bc%e5%87%ba%e8%af%bb%e6%a1%a3%e7%95%8c%e9%9d%a2
colour : this.soundColor
var code = '{"type": "callLoad"},\n';
return code;
*/;
+
+previewUI_s
+ : 'ui绘制并预览' '(双击此项可进行预览)' BGNL? Newline action+ BEND Newline
+
+
+/* previewUI_s
+tooltip : previewUI: ui绘制并预览
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=previewUI%ef%bc%9aUI%e7%bb%98%e5%88%b6%e5%b9%b6%e9%a2%84%e8%a7%88
+var code = ['{"type": "previewUI", "action": [\n', action_0,']},\n'].join('');
+return code;
+*/;
+
+
+clearMap_s
+ : '清除画布' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString Newline
+
+/* clearMap_s
+tooltip : clearMap: 清除画布
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=clearMap%ef%bc%9a%e6%b8%85%e9%99%a4%e7%94%bb%e5%b8%83
+colour : this.subColor
+default : ["0", "0", "100", "100"]
+var code = '{"type": "clearMap", "x": ' + PosString_0 + ', "y": ' + PosString_1 +
+ ', "width": ' + PosString_2 + ', "height": ' + PosString_3 + '},\n';
+return code;
+*/;
+
+
+clearMap_1_s
+ : '清空画布' Newline
+
+/* clearMap_1_s
+tooltip : clearMap: 清除画布
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=clearMap%ef%bc%9a%e6%b8%85%e9%99%a4%e7%94%bb%e5%b8%83
+colour : this.subColor
+var code = '{"type": "clearMap"},\n';
+return code;
+*/;
+
+
+setAttribute_s
+ : '设置画布属性' '字体' EvalString? '填充样式' EvalString? Colour '边框样式' EvalString? Colour BGNL? '线宽度' EvalString? '不透明度' EvalString? '对齐' TextAlign_List '基准线' TextBaseline_List 'z值' EvalString? Newline
+
+/* setAttribute_s
+tooltip : setAttribute:设置画布属性
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=setAttribute%ef%bc%9a%e8%ae%be%e7%bd%ae%e7%94%bb%e5%b8%83%e5%b1%9e%e6%80%a7
+colour : this.subColor
+default : ["","",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"","",null,null,""]
+TextAlign_List_0 = TextAlign_List_0==='null'?'': ', "align": "'+TextAlign_List_0+'"';
+TextBaseline_List_0 = TextBaseline_List_0==='null'?'': ', "baseline": "'+TextBaseline_List_0+'"';
+var colorRe = MotaActionFunctions.pattern.colorRe;
+var fontRe = MotaActionFunctions.pattern.fontRe;
+if (EvalString_0) {
+ if (!fontRe.test(EvalString_0)) throw new Error('字体必须是 [italic] [bold] 14px Verdana 这种形式或不填');
+ EvalString_0 = ', "font": "' + EvalString_0 + '"';
+}
+if (EvalString_1) {
+ if (!colorRe.test(EvalString_1))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_1 = ', "fillStyle": ['+EvalString_1+']';
+}
+if (EvalString_2) {
+ if (!colorRe.test(EvalString_2))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_2 = ', "strokeStyle": ['+EvalString_2+']';
+}
+if (EvalString_3) {
+ if (!/^\d+$/.test(EvalString_3))throw new Error('线宽必须是整数或不填');
+ EvalString_3 = ', "lineWidth": '+EvalString_3;
+}
+if (EvalString_4) {
+ var f = parseFloat(EvalString_4);
+ if (isNaN(f) || f<0 || f>1) throw new Error('不透明度必须是0到1的浮点数或不填');
+ EvalString_4 = ', "alpha": '+EvalString_4;
+}
+if (EvalString_5) {
+ if (!/^\d+$/.test(EvalString_5))throw new Error('z值必须是整数或不填');
+ EvalString_5 = ', "z": '+EvalString_5;
+}
+var code = '{"type": "setAttribute"'+EvalString_0+EvalString_1+EvalString_2+EvalString_3+EvalString_4+TextAlign_List_0+TextBaseline_List_0+EvalString_5+'},\n';
+return code;
+*/;
+
+fillText_s
+ : '绘制文本' 'x' PosString 'y' PosString '样式' EvalString? Colour '字体' EvalString? '最大宽度' EvalString? BGNL? EvalString Newline
+
+/* fillText_s
+tooltip : fillText:绘制一行文本;可以设置最大宽度进行放缩
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=fillText%ef%bc%9a%e7%bb%98%e5%88%b6%e6%96%87%e6%9c%ac
+colour : this.subColor
+default : ["0","0","",'rgba(255,255,255,1)',"","","绘制一行文本"]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+var fontRe = MotaActionFunctions.pattern.fontRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+if (EvalString_1) {
+ if (!fontRe.test(EvalString_1)) throw new Error('字体必须是 [italic] [bold] 14px Verdana 这种形式或不填');
+ EvalString_1 = ', "font": "' + EvalString_1 + '"';
+}
+if (EvalString_2) {
+ if (!/^\d+$/.test(EvalString_2)) throw new Error('最大宽度必须是整数或不填');
+ EvalString_2 = ', "maxWidth": ' + EvalString_2;
+}
+var code = '{"type": "fillText", "x": '+PosString_0+', "y": '+PosString_1+EvalString_0+EvalString_1+EvalString_2+', "text": "'+EvalString_3+'"},\n';
+return code;
+*/;
+
+fillBoldText_s
+ : '绘制描边文本' 'x' PosString 'y' PosString '样式' EvalString? Colour '字体' EvalString? BGNL? EvalString Newline
+
+/* fillBoldText_s
+tooltip : fillBoldText:绘制一行描边文本
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=fillBoldText%ef%bc%9a%e7%bb%98%e5%88%b6%e6%8f%8f%e8%be%b9%e6%96%87%e6%9c%ac
+colour : this.subColor
+default : ["0","0","",'rgba(255,255,255,1)',"","绘制一行描边文本"]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+var fontRe = MotaActionFunctions.pattern.fontRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+if (EvalString_1) {
+ if (!fontRe.test(EvalString_1)) throw new Error('字体必须是 [italic] [bold] 14px Verdana 这种形式或不填');
+ EvalString_1 = ', "font": "' + EvalString_1 + '"';
+}
+var code = '{"type": "fillBoldText", "x": '+PosString_0+', "y": '+PosString_1+EvalString_0+EvalString_1+', "text": "'+EvalString_2+'"},\n';
+return code;
+*/;
+
+drawTextContent_s
+ : '绘制多行文本' EvalString BGNL? '起点像素' 'x' PosString 'y' PosString '最大宽度' EvalString? '颜色' EvalString? Colour BGNL? '对齐' TextAlign_List '字体大小' EvalString? '行距' EvalString? '粗体' Bool Newline
+
+/* drawTextContent_s
+tooltip : drawTextContent:绘制多行文本
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=drawTextContent%ef%bc%9a%e7%bb%98%e5%88%b6%e5%a4%9a%e8%a1%8c%e6%96%87%e6%9c%ac
+colour : this.subColor
+default : ["绘制多行文本\\n可双击编辑","0","0","","",'rgba(255,255,255,1)',null,"","",false]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+TextAlign_List_0 = TextAlign_List_0==='null'?'': ', "align": "'+TextAlign_List_0+'"';
+Bool_0 = Bool_0 ? (', "bold": true') : '';
+if (EvalString_1) {
+ if (!/^\d+$/.test(EvalString_1)) throw new Error('最大宽度必须是整数或不填');
+ EvalString_1 = ', "maxWidth": ' + EvalString_1;
+}
+if (EvalString_2) {
+ if (!colorRe.test(EvalString_2))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_2 = ', "color": ['+EvalString_2+']';
+}
+if (EvalString_3) {
+ if (!/^\d+$/.test(EvalString_3)) throw new Error('字体大小必须是整数或不填');
+ EvalString_3 = ', "fontSize": ' + EvalString_3;
+}
+if (EvalString_4) {
+ if (!/^\d+$/.test(EvalString_4)) throw new Error('行距必须是整数或不填');
+ EvalString_4 = ', "lineHeight": ' + EvalString_4;
+}
+var code = '{"type": "drawTextContent", "text": "'+EvalString_0+'", "left": '+PosString_0+', "top": '+PosString_1+TextAlign_List_0+EvalString_1+EvalString_2+EvalString_3+EvalString_4+Bool_0+'},\n';
+return code;
+*/;
+
+fillRect_s
+ : '绘制矩形' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '颜色' EvalString? Colour Newline
+
+/* fillRect_s
+tooltip : fillRect:绘制矩形
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=fillRect%ef%bc%9a%e7%bb%98%e5%88%b6%e7%9f%a9%e5%bd%a2
+colour : this.subColor
+default : ["0","0","flag:x","300","",null]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+var code = '{"type": "fillRect", "x": '+PosString_0+', "y": '+PosString_1+', "width": '+PosString_2+', "height": '+PosString_3+EvalString_0+'},\n';
+return code;
+*/;
+
+strokeRect_s
+ : '绘制矩形边框' '起点像素' 'x' PosString 'y' PosString '宽' PosString '高' PosString '颜色' EvalString? Colour '线宽' EvalString? Newline
+
+/* strokeRect_s
+tooltip : strokeRect:绘制矩形边框
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=strokeRect%ef%bc%9a%e7%bb%98%e5%88%b6%e7%9f%a9%e5%bd%a2%e8%be%b9%e6%a1%86
+colour : this.subColor
+default : ["0","0","flag:x","300","",null,""]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+if (EvalString_1) {
+ if (!/^\d+$/.test(EvalString_1))throw new Error('线宽必须是整数或不填');
+ EvalString_1 = ', "lineWidth": '+EvalString_1;
+}
+var code = '{"type": "strokeRect", "x": '+PosString_0+', "y": '+PosString_1+', "width": '+PosString_2+', "height": '+PosString_3+EvalString_0+EvalString_1+'},\n';
+return code;
+*/;
+
+drawLine_s
+ : '绘制线段' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' EvalString? Colour '线宽' EvalString? Newline
+
+/* drawLine_s
+tooltip : drawLine:绘制线段
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=drawLine%ef%bc%9a%e7%bb%98%e5%88%b6%e7%ba%bf%e6%ae%b5
+colour : this.subColor
+default : ["0","0","flag:x","300","",null,""]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+if (EvalString_1) {
+ if (!/^\d+$/.test(EvalString_1))throw new Error('线宽必须是整数或不填');
+ EvalString_1 = ', "lineWidth": '+EvalString_1;
+}
+var code = '{"type": "drawLine", "x1": '+PosString_0+', "y1": '+PosString_1+', "x2": '+PosString_2+', "y2": '+PosString_3+EvalString_0+EvalString_1+'},\n';
+return code;
+*/;
+
+drawArrow_s
+ : '绘制箭头' '起点像素' 'x' PosString 'y' PosString '终点像素' 'x' PosString 'y' PosString '颜色' EvalString? Colour '线宽' EvalString? Newline
+
+/* drawArrow_s
+tooltip : drawArrow:绘制箭头
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=drawArrow%ef%bc%9a%e7%bb%98%e5%88%b6%e7%ae%ad%e5%a4%b4
+colour : this.subColor
+default : ["0","0","flag:x","300","",null,""]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+if (EvalString_0) {
+ if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1');
+ EvalString_0 = ', "style": ['+EvalString_0+']';
+}
+if (EvalString_1) {
+ if (!/^\d+$/.test(EvalString_1))throw new Error('线宽必须是整数或不填');
+ EvalString_1 = ', "lineWidth": '+EvalString_1;
+}
+var code = '{"type": "drawArrow", "x1": '+PosString_0+', "y1": '+PosString_1+', "x2": '+PosString_2+', "y2": '+PosString_3+EvalString_0+EvalString_1+'},\n';
+return code;
+*/;
+
+
+fillPolygon_s
+ : '绘制多边形' '顶点像素列表' 'x' EvalString 'y' EvalString '颜色' EvalString? Colour Newline
+
+/* fillPolygon_s
+tooltip : fillPolygon:绘制多边形
+helpUrl : https://h5mota.com/games/template/_docs/#/event?id=fillPolygon%ef%bc%9a%e7%bb%98%e5%88%b6%e5%a4%9a%e8%be%b9%e5%bd%a2
+colour : this.subColor
+default : ["0,0,100","0,100,0","",null]
+var colorRe = MotaActionFunctions.pattern.colorRe;
+var pattern2 = /^([+-]?\d+)(,[+-]?\d+)*$/;
+if(!pattern2.test(EvalString_0) || !pattern2.test(EvalString_1))throw new Error('坐标格式错误,请右键点击帮助查看格式');
+EvalString_0=EvalString_0.split(',');
+EvalString_1=EvalString_1.split(',');
+if(EvalString_0.length!==EvalString_1.length)throw new Error('坐标格式错误,请右键点击帮助查看格式');
+for(var ii=0;ii'+xml_text+'');
@@ -2852,19 +3870,22 @@ MotaActionFunctions.parse = function(obj,type) {
MotaActionFunctions.EvalString_pre = function(EvalString){
if (EvalString.indexOf('__door__')!==-1) throw new Error('请修改开门变量__door__,如door1,door2,door3等依次向后。请勿存在两个门使用相同的开门变量。');
+ EvalString = MotaActionFunctions.replaceFromName(EvalString);
return EvalString.replace(/([^\\])"/g,'$1\\"').replace(/^"/g,'\\"').replace(/""/g,'"\\"');
}
MotaActionFunctions.IdString_pre = function(IdString){
if (IdString.indexOf('__door__')!==-1) throw new Error('请修改开门变量__door__,如door1,door2,door3等依次向后。请勿存在两个门使用相同的开门变量。');
- if (IdString && !(/^[0-9a-zA-Z_][0-9a-zA-Z_\-:]*$/.test(IdString)))throw new Error('id: '+IdString+'中包含了0-9 a-z A-Z _ - :之外的字符');
+ IdString = MotaActionFunctions.replaceFromName(IdString);
+ if (IdString && !(MotaActionFunctions.pattern.id.test(IdString)) && !(MotaActionFunctions.pattern.idWithoutFlag.test(IdString)))
+ throw new Error('id: '+IdString+'中包含了0-9 a-z A-Z _ - :之外的字符');
return IdString;
}
MotaActionFunctions.PosString_pre = function(PosString){
if (!PosString || /^-?\d+$/.test(PosString)) return PosString;
- if (!(/^flag:[0-9a-zA-Z_][0-9a-zA-Z_:]*$/.test(PosString)))throw new Error(PosString+'中包含了0-9 a-z A-Z _ :之外的字符,或者是没有以flag: 开头');
- return '"'+PosString+'"';
+ //if (!(MotaActionFunctions.pattern.id.test(PosString)))throw new Error(PosString+'中包含了0-9 a-z A-Z _ 和中文之外的字符,或者是没有以flag: 开头');
+ return '"'+MotaActionFunctions.replaceFromName(PosString)+'"';
}
MotaActionFunctions.StepString_pre = function(StepString){
@@ -2905,4 +3926,153 @@ MotaActionFunctions.StepString_pre = function(StepString){
return ans;
}
+MotaActionFunctions.pattern=MotaActionFunctions.pattern||{};
+MotaActionFunctions.pattern.id=/^(flag|global):([a-zA-Z0-9_\u4E00-\u9FCC]+)$/;
+MotaActionFunctions.pattern.id2=/^flag:([a-zA-Z0-9_\u4E00-\u9FCC]+),flag:([a-zA-Z0-9_\u4E00-\u9FCC]+)$/;
+MotaActionFunctions.pattern.idWithoutFlag=/^[0-9a-zA-Z_][0-9a-zA-Z_\-:]*$/;
+MotaActionFunctions.pattern.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)?$/;
+MotaActionFunctions.pattern.fontRe=/^(italic )?(bold )?(\d+)px ([a-zA-Z0-9_\u4E00-\u9FCC]+)$/;
+
+
+MotaActionFunctions.pattern.replaceStatusList = [
+ // 保证顺序!
+ ["hpmax", "生命上限"],
+ ["hp", "生命"],
+ ["name", "名称"],
+ ["lv", "等级"],
+ ["atk", "攻击"],
+ ["def", "防御"],
+ ["mdef", "魔防"],
+ ["manamax", "魔力上限"],
+ ["mana", "魔力"],
+ ["money", "金币"],
+ ["experience", "经验"],
+ ["steps", "步数"],
+];
+
+MotaActionFunctions.pattern.replaceItemList = [
+ // 保证顺序!
+ ["yellowKey", "黄钥匙"],
+ ["blueKey", "蓝钥匙"],
+ ["redKey", "红钥匙"],
+ ["redJewel", "红宝石"],
+ ["blueJewel", "蓝宝石"],
+ ["greenJewel", "绿宝石"],
+ ["yellowJewel", "黄宝石"],
+ ["redPotion", "红血瓶"],
+ ["bluePotion", "蓝血瓶"],
+ ["yellowPotion", "黄血瓶"],
+ ["greenPotion", "绿血瓶"],
+ ["sword1", "铁剑"],
+ ["sword2", "银剑"],
+ ["sword3", "骑士剑"],
+ ["sword4", "圣剑"],
+ ["sword5", "神圣剑"],
+ ["shield1", "铁盾"],
+ ["shield2", "银盾"],
+ ["shield3", "骑士盾"],
+ ["shield4", "圣盾"],
+ ["shield5", "神圣盾"],
+ ["superPotion", "圣水"],
+ ["moneyPocket", "金钱袋"],
+ ["book", "怪物手册"],
+ ["fly", "楼层传送器"],
+ ["coin", "幸运金币"],
+ ["snow", "冰冻徽章"],
+ ["cross", "十字架"],
+ ["knife", "屠龙匕首"],
+ ["shoes", "绿鞋"],
+ ["bigKey", "大黄门钥匙"],
+ ["greenKey", "绿钥匙"],
+ ["steelKey", "铁门钥匙"],
+ ["pickaxe", "破墙镐"],
+ ["icePickaxe", "破冰镐"],
+ ["bomb", "炸弹"],
+ ["centerFly", "中心对称飞行器"],
+ ["upFly", "上楼器"],
+ ["downFly", "下楼器"],
+ ["earthquake", "地震卷轴"],
+ ["poisonWine", "解毒药水"],
+ ["weakWine", "解衰药水"],
+ ["curseWine", "解咒药水"],
+ ["superWine", "万能药水"],
+ ["hammer", "圣锤"],
+ ["lifeWand", "生命魔杖"],
+ ["jumpShoes", "跳跃靴"],
+];
+
+MotaActionFunctions.pattern.replaceEnemyList = [
+ // 保证顺序!
+ ["name", "名称"],
+ ["atk", "攻击"],
+ ["def", "防御"],
+ ["money", "金币"],
+ ["experience", "经验"],
+ ["point", "加点"],
+ ["special", "属性"],
+];
+
+MotaActionFunctions.disableReplace = false;
+
+MotaActionFunctions.replaceToName = function (str) {
+ if (!str || MotaActionFunctions.disableReplace) return str;
+ var map = {}, list = [];
+ MotaActionFunctions.pattern.replaceStatusList.forEach(function (v) {
+ map[v[0]] = v[1]; list.push(v[0]);
+ });
+ str = str.replace(new RegExp("status:(" + list.join("|") + ")", "g"), function (a, b) {
+ return map[b] ? ("状态:" + map[b]) : b;
+ }).replace(/status:/g, "状态:");
+ map = {}; list = [];
+ MotaActionFunctions.pattern.replaceItemList.forEach(function (v) {
+ map[v[0]] = v[1]; list.push(v[0]);
+ });
+ str = str.replace(new RegExp("item:(" + list.join("|") + ")", "g"), function (a, b) {
+ return map[b] ? ("物品:" + map[b]) : b;
+ }).replace(/item:/g, "物品:");
+ str = str.replace(/flag:/g, "变量:").replace(/switch:/g, "独立开关:").replace(/global:/g, "全局存储:");
+
+ map = {}; list = [];
+ MotaActionFunctions.pattern.replaceEnemyList.forEach(function (v) {
+ map[v[0]] = v[1]; list.push(v[0]);
+ });
+ str = str.replace(new RegExp("enemy:([a-zA-Z0-9_]+).(" + list.join("|") + ")", "g"), function (a, b, c) {
+ return map[c] ? ("怪物:" + b + ":" + map[c]) : c;
+ }).replace(/enemy:/g, "怪物:");
+
+ str = str.replace(/blockId:/g, "图块ID:").replace(/blockCls:/g, "图块类别:").replace(/equip:/g, "装备孔:");
+ return str;
+}
+
+MotaActionFunctions.replaceFromName = function (str) {
+ if (!str || MotaActionFunctions.disableReplace) return str;
+ var map = {}, list = [];
+ MotaActionFunctions.pattern.replaceStatusList.forEach(function (v) {
+ map[v[1]] = v[0]; list.push(v[1]);
+ });
+ str = str.replace(new RegExp("状态[::](" + list.join("|") + ")", "g"), function (a, b) {
+ return map[b] ? ("status:" + map[b]) : b;
+ }).replace(/状态[::]/g, "status:");
+ map = {}; list = [];
+ MotaActionFunctions.pattern.replaceItemList.forEach(function (v) {
+ map[v[1]] = v[0]; list.push(v[1]);
+ });
+ str = str.replace(new RegExp("物品[::](" + list.join("|") + ")", "g"), function (a, b) {
+ return map[b] ? ("item:" + map[b]) : b;
+ }).replace(/物品[::]/g, "item:");
+ str = str.replace(/变量[::]/g, "flag:").replace(/独立开关[::]/g, "switch:").replace(/全局存储[::]/g, "global:");
+
+ map = {}; list = [];
+ MotaActionFunctions.pattern.replaceEnemyList.forEach(function (v) {
+ map[v[1]] = v[0]; list.push(v[1]);
+ });
+ str = str.replace(new RegExp("(enemy:|怪物[::])([a-zA-Z0-9_]+)[::](" + list.join("|") + ")", "g"), function (a, b, c, d) {
+ return map[d] ? ("enemy:" + c + ":" + map[d]) : d;
+ }).replace(/怪物[::]/g, "enemy:");
+
+ str = str.replace(/图块I[dD][::]/g, "blockId:").replace(/图块类别[::]/g, "blockCls:").replace(/装备孔[::]/g, "equip:");
+
+ return str;
+}
+
*/
\ No newline at end of file
diff --git a/_server/README.md b/_server/README.md
index d23bfb43..7bd750b1 100644
--- a/_server/README.md
+++ b/_server/README.md
@@ -1,142 +1,57 @@
# editor
-[重构](refactoring.md)
+直接使用游戏运行时(之后简称core)的代码来绘制游戏画面, 借助fs.js来实现浏览器编辑文件. 通过表格编辑数据, blockly图块编辑事件, code mirror编辑文本的可视化魔塔编辑器.
->! 以下均是v2.0时的说明, 未及时改动
+
-本目录下所有文件,以及`../editor.html`和`../启动服务.exe`([源码](http://github.com/ckcz123/mota-js-server/))是地图编辑器的所有组件.
+左侧数据区, 中间地图区, 右侧素材区
-`editor.js`,`editor_file.js`和`editor_mode.js`耦合较强,`editor_blockly.js`和`editor_multi.js`和`fs.js`基本可以独立使用.
+
-## 各组件功能
+事件编辑器
-### 总体上
+
-以`display:none`的形式引入了`index.html`的`dom`,修改了原来的`.gameCanvas #ui #data`等的名字以避免冲突
+脚本编辑器
-通过`main.init('editor')`加载数据
+> 此文件是editor的结构说明, 不是使用文档
-`editor`模式关闭了部分动画
+## 组成
-`core.drawMap`中`editor`模式下不再画图,而是生成画图的函数提供给`editor`
+本目录下所有文件,以及`../editor.html`,`../editor-mobile.html`和`../启动服务.exe`,`../server.py`是地图编辑器的所有组件.
-`editor`模式下`GlobalAnimate`可以独立的选择是否播放
+### 父目录
++ editor(-mobile).html
+ 编辑器的[入口页面](http://127.0.0.1:1055/editor.html)
+ 以`display:none`的形式引入了core的`index.html`的`dom`,修改了原来的`.gameCanvas #ui #data`等的名字以避免冲突
++ 启动服务.exe [源码](http://github.com/ckcz123/mota-js-server/)
+ 为fs.js提供后端支持, 同时集成了一些实用工具
++ server.py
+ 非windows平台中为fs.js提供后端支持
-`core.playBgm`和`core.playSound`中非`play`模式不再播放声音
+### core
-`core.show`和`core.hide`中非`play`模式不再进行动画而是立刻完成并执行回调
+游戏运行时中部分代码根据`main.mod=='editor'`进行了调整
-`editor`模式不执行`core.resize`
++ 通过`main.init('editor')`加载数据
-### editor.js
++ `editor`模式关闭了部分动画
-``` js
-editor.mapInit();//清空地图
-editor.changeFloor('MT2')//切换地图
-editor.util.guid()//产生一个可以作为id的长随机字符串
-```
++ `core.drawMap`中`editor`模式下不再画图,而是生成画图的函数提+ 供给`editor`
-`editor.updateMap`中画未定义快的报错
++ `editor`模式下`GlobalAnimate`可以独立的选择是否播放
-### editor_file.js
++ `core.playBgm`和`core.playSound`中非`play`模式不再播放声音
-提供了以下函数进行楼层`map`数组相关的操作
-```javascript
-editor.file.getFloorFileList
-editor.file.loadFloorFile
-editor.file.saveFloorFile
-editor.file.saveFloorFileAs
-```
++ `core.show`和`core.hide`中非`play`模式不再进行动画而是立刻+ 完成并执行回调
-编辑模式有关的查询
-```javascript
-editor.file.editItem('redJewel',[],function(a){console.log(a)});
-editor.file.editEnemy('redBat',[],function(a){console.log(a)});
-editor.file.editLoc(2,0,[],function(a){console.log(a)});
-editor.file.editFloor([],function(a){console.log(a)});
-editor.file.editTower([],function(a){console.log(a)});
-editor.file.editFunctions([],function(a){console.log(a)});
-```
++ `editor`模式不执行`core.resize`
-编辑模式有关的编辑
-```javascript
-editor.info={images: "terrains", y: 9};
-editor.file.changeIdAndIdnum('yellowWall2',16,editor.info,function(a){console.log(a)});
-editor.file.editItem('book',[["change","['items']['name']","怪物手册的新名字"]],function(a){console.log(a)});
-editor.file.editEnemy('redBat',[['change',"['atk']",20]],function(a){console.log(a)});
-editor.file.editLoc(2,6,[["change","['afterBattle']",null]],function(a){console.log(a)});
-editor.file.editFloor([["change","['title']",'样板 33 层']],function(a){console.log(a)});
-editor.file.editTower([["change","['values']['lavaDamage']",200]],function(a){console.log(a)});
-editor.file.editFunctions(["change","['events']['afterChangeLight']","function(x,y){console.log(x,y)}"],function(a){console.log(a)});
-```
-
-### editor_mode.js
-生成表格并绑定事件的函数
-```javascript
-editor.mode.loc();
-editor.mode.enemyitem();
-editor.mode.floor();
-editor.mode.tower();
-editor.mode.functions();
-```
-
-切换模式
-```javascript
-editor.mode.onmode('');//清空
-editor.mode.onmode('save');//保存
-editor.mode.onmode('nextChange');//下次onmode时前端进行切换
-
-editor.mode.onmode('loc');
-editor.mode.onmode('enemyitem');
-editor.mode.onmode('floor');
-editor.mode.onmode('tower');
-editor.mode.onmode('functions');
-editor.mode.onmode('map');
-editor.mode.onmode('appendpic');
-```
-在`onmode('save')`时,改动才会保存到文件,涉及到图片的改动需要刷新页面使得`editor`能看到
-
-表格的`onchange`的实现中,获得当前模式的方式.不注意的话,修改`index.html`中页面的结构,会被坑
-```javascript
-var node = thisTr.parentNode;
-while (!editor_mode._ids.hasOwnProperty(node.getAttribute('id'))) {
- node = node.parentNode;
-}
-editor_mode.onmode(editor_mode._ids[node.getAttribute('id')]);
-```
-
-`editor.mode.listen`中提供了追加素材的支持.
-
-
-### editor_blockly.js
-
-把选定`id_`的事件用blockly编辑
-``` js
-editor_blockly.import(id_,{type:'event'});
-```
-
-把文本区域的代码转换成图块
-``` js
-editor_blockly.parse();
-```
-
-### editor_multi.js
-
-用[CodeMirror](https://github.com/codemirror/CodeMirror) 实现有高亮的多行文本编辑
-
-编辑选定`id_`的文本域
-``` js
-editor_multi.import(id_,{lint:true})
-```
-
-编辑blockly方块的特定域
-``` js
-editor_multi.multiLineEdit(value,b,f,{lint:true},callback)
-```
### fs.js
-模仿node的fs模块提供如下api,与`启动服务.exe`配合为js提供文件读写功能
+依照[issue#31](https://github.com/ckcz123/mota-js/issues/13)的约定, 模仿node的fs模块提供如下api,与`启动服务.exe`,`server.py`配合为js提供文件读写功能, 是编辑器成立的前提
+
``` js
fs.readFile('file.in','utf-8',callback)
//读文本文件
@@ -164,3 +79,195 @@ fs.readdir(path, callback)
//所有参数不允许缺省
```
+### editor_multi.js
+
+用[CodeMirror](https://github.com/codemirror/CodeMirror) 实现有高亮的多行文本编辑
+
+编辑选定`id_`的文本域
+``` js
+editor_multi.import(id_,{lint:true})
+```
+
+编辑blockly方块的特定域
+``` js
+editor_multi.multiLineEdit(value,b,f,{lint:true},callback)
+```
+
+配置表格
+``` js
+editor_multi.editCommentJs(mod)
+```
+
+### MotaAction.g4
+
+通过[antlr-blockly](https://github.com/zhaouv/antlr-blockly)的语法定义core中各事件对应的方块.
+
+借助google的[blockly](https://github.com/google/blockly)来实现事件的可视化编辑.
+
+入口方块以`_m`结尾
+
+一般语句写在`action`中, 以`_s`结尾
+
+### editor_blockly.js
+
+把选定`id_`的事件用blockly编辑
+``` js
+editor_blockly.import(id_,{type:'event'});
+```
+
+把文本区域的代码转换成图块
+``` js
+editor_blockly.parse();
+```
+
+`initscript中`的`toolboxObj`定义了侧边栏中显示的图块
+
+自定义`Blockly.FieldColour.prototype.createWidget_`修改了颜色选择器的行为
+
+自定义`Blockly.FieldTextInput.prototype.showInlineEditor_`添加了自动补全
+
+
+### editor_mode.js
+
+用于切换数据区
+
+加载数据
+```javascript
+editor.mode.loc();
+editor.mode.enemyitem();
+editor.mode.floor();
+editor.mode.tower();
+editor.mode.functions();
+```
+
+切换模式
+```javascript
+editor.mode.onmode('');//清空
+editor.mode.onmode('save');//保存
+editor.mode.onmode('nextChange');//下次onmode时前端进行切换
+
+editor.mode.onmode('loc');
+editor.mode.onmode('enemyitem');
+editor.mode.onmode('floor');
+editor.mode.onmode('tower');
+editor.mode.onmode('functions');
+editor.mode.onmode('map');
+editor.mode.onmode('appendpic');
+```
+在`onmode('save')`时,改动才会保存到文件,涉及到图片的改动需要刷新页面使得`editor`能看到
+
+数据区一些通用的函数也定义在这里
+
+### editor_table.js
+
+处理表格的生成, 及其响应的事件
+
+其接受来自../project/\*.js的数据`obj`和来自table/\*.comment.js的注释`commentObj`
+
+commentObj的结构如示例
+``` js
+{
+ "_type": "object",
+ "_data": {
+ "events": {
+ "_type": "object",
+ "_data": {
+ "resetGame": {
+ "_leaf": true,
+ "_type": "textarea",
+ "_lint": true,
+ "_data": "重置整个游戏"
+ },
+ "setInitData": {
+ "_leaf": true,
+ "_type": "textarea",
+ "_lint": true,
+ "_data": "设置初始属性"
+ },
+```
+一层正常数据, 一层`_`开头的结构说明, 忽略`_`层的话与obj同结构
+
+通过
+``` js
+editor.table.objToTable(obj, commentObj)
+editor.table.objToTr
+editor.table.objToTd
+```
+遍历这两个对象来生成表格, 叶节点根据`_type`渲染成对应的dom
+
+表格的值变化`onchange`, 双击`dblclickfunc`, 删除`deletefunc`, 添加`addfunc`也定义在此文件
+
+### editor_mappanel.js
+
+与地图区相关的功能
++ 画地图 线/矩形/tileset
++ 通过地图选中事件或素材
++ 右键菜单
++ 切换楼层
++ 大地图移动可视窗口
+
+### editor_materialpanel.js
+
+与素材区相关的功能
++ 选中
++ 展开/折叠
+
+### editor_datapanel.js
+
+与数据区相关的功能 (且与表格无关的功能)
++ 地图编辑
+ - 创建新地图
+ - 批量创建
++ 地图选点
++ 图块属性
+ - 注册素材
+ - 修改id
++ 楼层属性
+ - 修改楼层id
++ 全塔属性
++ 脚本编辑
++ 追加素材
+ - 选择导入的区域
+ - 导入图片
+ - 改色相
+ - 选中图片中的格子
+ - 确认追加
++ 公共事件
++ 插件编写
+
+### editor_ui.js
+
+ui事件中没有具体到前三个区中的函数
++ 响应点击
++ 快捷键
++ 显示帮助
++ UI预览 & 地图选点相关
+
+### editor_util.js
+
+一些通用的函数
++ 生成id
++ HTML转义
++ 像素处理
++ base64的encode/decode
++ 检查值是否为空
+
+### editor_listen.js
+
+界面与功能的绑定
+
+### editor_file.js
+
+包装fs.js, 把数据读写到对应的文件
+
+### editor_game.js
+
+游戏数据的处理
+
+此部分的重构未完成, 实际上是由editor_file.js和editor_file_unsorted.js来做的
+
+### editor.js
+
+初始化加整合各模块
+
+现状是还放了一些游戏数据有关的函数未挪到editor_game, 以及部分和入口页面生成有关的函数
\ No newline at end of file
diff --git a/_server/colorPicker/LICENSE.md b/_server/colorPicker/LICENSE.md
deleted file mode 100644
index 8394aa4a..00000000
--- a/_server/colorPicker/LICENSE.md
+++ /dev/null
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2014 Peter Dematté
-
-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.
\ No newline at end of file
diff --git a/_server/config.json b/_server/config.json
new file mode 100644
index 00000000..fe6a45a9
--- /dev/null
+++ b/_server/config.json
@@ -0,0 +1 @@
+{"lastUsed":[],"foldPerCol":50,"folded":false,"editorLastFloorId":null,"disableBlocklyReplace":false,"shortcut":{"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0}}
\ No newline at end of file
diff --git a/_server/css/editor.css b/_server/css/editor.css
index dd9c0e18..642fd168 100644
--- a/_server/css/editor.css
+++ b/_server/css/editor.css
@@ -40,7 +40,7 @@ body {
width: 104px;
}
-#left, #mid, #right {
+#left, #mid, #mid2, #right {
border-radius: 2px;
box-sizing: border-box;
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .14), 0 3px 1px -2px rgba(0, 0, 0, .2), 0 1px 5px 0 rgba(0, 0, 0, .12);
@@ -130,6 +130,14 @@ body {
height: 630px;
}
+#mid2 {
+ position: absolute;
+ left: 448px;
+ top: 650px;
+ width: 440px;
+ bottom: 10px;
+}
+
#mapEdit {
overflow: hidden;
}
@@ -142,6 +150,13 @@ body {
height: 416px;
}
+#lastUsedDiv {
+ height: auto;
+ bottom: 0;
+ margin-top: 20px;
+ overflow: hidden;
+}
+
#mid .tools {
position: absolute;
width: 425px;
@@ -239,15 +254,15 @@ body {
position: absolute;
left: 900px;
top: 10px;
- width: 440px;
- height: 630px;
+ right: 0;
+ bottom: 0;
/* border: 1px solid rgb(238, 13, 13); */
}
#iconLib {
position: absolute;
- width: 435px;
- height: 620px;
+ right: 0;
+ bottom: 0;
left: 5px;
top: 5px;
overflow: auto;
@@ -262,10 +277,6 @@ body {
position: absolute;
}
-.egameCanvas {
- position: absolute;
-}
-
.gameCanvas {
position: absolute;
}
@@ -287,6 +298,15 @@ body {
0 0 0 3px #000;
}
+#iconExpandBtn {
+ position: absolute;
+ left: 20px;
+ bottom: 30px;
+ font-size: 15px;
+ padding: 6px;
+ display: none;
+}
+
.warnText {
color: #D50000;
font-weight: 700;
@@ -458,4 +478,88 @@ table.row td {
left: 6px;
top: 6px;
background-image:url('data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGJhc2VQcm9maWxlPSJmdWxsIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpldj0iaHR0cDovL3d3dy53My5vcmcvMjAwMS94bWwtZXZlbnRzIj4KPGc%2BCgk8cG9seWdvbiBmaWxsPSIjNjY2IiBwb2ludHM9IjkuMjA3LDYuMTI2IDcuNzkzLDcuNTQxIDExLjc5MywxMS41NDEgMTMuMjA3LDEwLjEyNiIgLz4KCTxwYXRoIGZpbGw9IiM2NjYiIGQ9Ik01LjkxNywyYzEuNjA4LDAsMi45MTcsMS4zMDgsMi45MTcsMi45MTdTNy41MjUsNy44MzMsNS45MTcsNy44MzNTMyw2LjUyNSwzLDQuOTE3UzQuMzA4LDIsNS45MTcsMgoJCSBNNS45MTcsMEMzLjIwMSwwLDEsMi4yMDEsMSw0LjkxN3MyLjIwMSw0LjkxNyw0LjkxNyw0LjkxN3M0LjkxNy0yLjIwMSw0LjkxNy00LjkxN0MxMC44MzMsMi4yMDEsOC42MzIsMCw1LjkxNywwTDUuOTE3LDB6IiAvPgo8L2c%2BCjwvc3ZnPgo%3D');
+}
+
+#uieventDiv {
+ display: none;
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background: rgba(127,127,127,0.6);
+ z-index: 2000
+}
+
+#uieventDialog {
+ position: fixed;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -60%);
+ background: white;
+ width: 436px;
+}
+
+#uieventHead {
+ margin: 10px 20px;
+}
+
+#uieventTitle {
+ font-weight: bold;
+}
+
+#uieventNo {
+ float: right;
+}
+
+#uieventYes {
+ display: none;
+ float: right;
+ margin-right: 15px;
+}
+
+#uieventBody {
+ width: 416px;
+ height: 416px;
+ position: relative;
+ margin-left: 10px;
+ margin-bottom: 5px;
+ overflow: hidden;
+}
+
+#uievent {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+}
+
+#selectPoint {
+ display: none;
+ margin-left: 10px;
+ margin-bottom: 10px;
+}
+
+#selectPointFloor {
+ margin-right: 10px;
+}
+
+#selectPointButtons {
+ display: inline;
+}
+
+#selectPointBox {
+ position: absolute;
+ z-index: 75;
+ width: 26px;
+ height: 26px;
+ margin: 3px 0 0 3px;
+ padding: 0;
+ /* display: none; */
+ box-sizing: border-box;
+ background-color: rgba(255, 255, 255, 0.0);
+ border: 1px solid #000;
+ box-shadow: 0 0 0 2px #fff,
+ 0 0 0 3px #000;
}
\ No newline at end of file
diff --git a/_server/css/editor_mobile.css b/_server/css/editor_mobile.css
index 1120c9fd..6dfaa651 100644
--- a/_server/css/editor_mobile.css
+++ b/_server/css/editor_mobile.css
@@ -110,6 +110,10 @@ body {
position: absolute;
}
+#mid2 {
+ display: none;
+}
+
#mapEdit {
overflow: hidden;
}
@@ -247,10 +251,6 @@ body {
position: absolute;
}
-.egameCanvas {
- position: absolute;
-}
-
.gameCanvas {
position: absolute;
}
@@ -272,6 +272,15 @@ body {
0 0 0 3px #000;
}
+#iconExpandBtn {
+ position: absolute;
+ left: 20px;
+ bottom: 30px;
+ font-size: 15px;
+ padding: 6px;
+ display: none;
+}
+
.warnText {
color: #D50000;
font-weight: 700;
@@ -433,7 +442,7 @@ div.row .rowtd .rowtext{
font: normal 2.5vw Arial, sans-serif;
list-style: none;
margin: 0;
- padding: 4px 7em 4px 28px;
+ padding: 4px 7em 4px 4px;
white-space: nowrap;
/* padding-left: 12px; */
@@ -482,4 +491,88 @@ div.row .rowtd .rowtext{
margin: 2px 0;
border-radius: 3px;
width: 90px;
+}
+
+#uieventDiv {
+ display: none;
+ width: 100%;
+ height: 100%;
+ position: fixed;
+ top: 0;
+ left: 0;
+ background: rgba(127,127,127,0.6);
+ z-index: 2000
+}
+
+#uieventDialog {
+ position: fixed;
+ top: 50%;
+ left: 0;
+ transform: translateY(-50%);
+ background: white;
+ width: 100vw;
+}
+
+#uieventHead {
+ margin: 10px 20px;
+}
+
+#uieventTitle {
+ font-weight: bold;
+}
+
+#uieventNo {
+ float: right;
+}
+
+#uieventYes {
+ display: none;
+ float: right;
+ margin-right: 15px;
+}
+
+#uieventBody {
+ width: 100vw;
+ height: 100vw;
+ position: relative;
+ margin-left: 0;
+ margin-bottom: 5px;
+ overflow: hidden;
+}
+
+#uievent {
+ position: absolute;
+ width: 100%;
+ height: 100%;
+ left: 0;
+ top: 0;
+}
+
+#selectPoint {
+ display: none;
+ margin-left: 10px;
+ margin-bottom: 10px;
+}
+
+#selectPointFloor {
+ margin-right: 10px;
+}
+
+#selectPointButtons {
+ display: inline;
+}
+
+#selectPointBox {
+ position: absolute;
+ z-index: 75;
+ width: 26px;
+ height: 26px;
+ margin: 3px 0 0 3px;
+ padding: 0;
+ /* display: none; */
+ box-sizing: border-box;
+ background-color: rgba(255, 255, 255, 0.0);
+ border: 1px solid #000;
+ box-shadow: 0 0 0 2px #fff,
+ 0 0 0 3px #000;
}
\ No newline at end of file
diff --git a/_server/css/editor_mode.css b/_server/css/editor_mode.css
index a1859f65..33f1a9bd 100644
--- a/_server/css/editor_mode.css
+++ b/_server/css/editor_mode.css
@@ -7,7 +7,7 @@
.leftTab {
overflow: auto;
position: absolute;
- height: 630px;
+ bottom: 0;
}
.leftTab > * {
@@ -121,6 +121,7 @@
display: block;
width: 100%;
overflow: auto;
+ word-break: break-all;
}
.etable table th {
@@ -157,14 +158,19 @@
}
.etable tr > :nth-child(3) {
- width: 60%
+ width: 35%;
+}
+
+.etable tr > :nth-child(4) {
+ width: 25%;
+ padding: 0;
}
.etable table {
overflow: visible;
}
-.etable tr:not(:first-child) > :last-child:hover {
+.etable tr:not(:first-child) > :nth-child(3):hover {
border: 1px solid rgb(87, 198, 232);
box-shadow: 0px 0px 3px rgb(87, 198, 232);
}
@@ -175,14 +181,17 @@
box-shadow: 0px 0px 3px rgb(87, 232, 198);
}
-.etable tr:not(:first-child) > :last-child {
+.etable tr:not(:first-child) > :nth-child(3) {
margin: 0;
padding: 0;
height: 100%;
- width: 100%;
position: relative;
}
+.etable tr > :nth-child(4) {
+ text-align: center;
+}
+
div.etableInputDiv {
position: absolute;
padding: 5px 0 0 5px;
diff --git a/_server/css/editor_mode_mobile.css b/_server/css/editor_mode_mobile.css
index 3098df27..bb680213 100644
--- a/_server/css/editor_mode_mobile.css
+++ b/_server/css/editor_mode_mobile.css
@@ -135,6 +135,7 @@
display: block;
width: 100%;
overflow: auto;
+ word-break: break-all;
}
.etable table th {
@@ -171,14 +172,19 @@
}
.etable tr > :nth-child(3) {
- width: 60%
+ width: 30%;
+}
+
+.etable tr > :nth-child(4) {
+ width: 30%;
+ text-align: center;
}
.etable table {
overflow: visible;
}
-.etable tr:not(:first-child) > :last-child:hover {
+.etable tr:not(:first-child) > :nth-child(3):hover {
border: 1px solid rgb(87, 198, 232);
box-shadow: 0px 0px 3px rgb(87, 198, 232);
}
@@ -189,11 +195,10 @@
box-shadow: 0px 0px 3px rgb(87, 232, 198);
}
-.etable tr:not(:first-child) > :last-child {
+.etable tr:not(:first-child) > :nth-child(3) {
margin: 0;
padding: 0;
height: 100%;
- width: 100%;
position: relative;
}
diff --git a/_server/editor.js b/_server/editor.js
index 812d901d..7ddc0f60 100644
--- a/_server/editor.js
+++ b/_server/editor.js
@@ -4,6 +4,107 @@ function editor() {
this.layerMod = "map";//["fgmap","map","bgmap"]
this.isMobile = false;
+ this.dom={
+ body:document.body,
+ eui:document.getElementById('eui'),
+ euiCtx:document.getElementById('eui').getContext('2d'),
+ efgCtx:document.getElementById('efg').getContext('2d'),
+ mid:document.getElementById('mid'),
+ mapEdit:document.getElementById('mapEdit'),
+ selectFloor:document.getElementById('selectFloor'),
+ iconExpandBtn :document.getElementById('iconExpandBtn'),
+ dataSelection : document.getElementById('dataSelection'),
+ iconLib:document.getElementById('iconLib'),
+ midMenu:document.getElementById('midMenu'),
+ extraEvent: document.getElementById('extraEvent'),
+ chooseThis : document.getElementById('chooseThis'),
+ chooseInRight : document.getElementById('chooseInRight'),
+ copyLoc : document.getElementById('copyLoc'),
+ moveLoc : document.getElementById('moveLoc'),
+ clearEvent : document.getElementById('clearEvent'),
+ clearLoc : document.getElementById('clearLoc'),
+ brushMod:document.getElementById('brushMod'),
+ brushMod2:document.getElementById('brushMod2'),
+ brushMod3:document.getElementById('brushMod3'),
+ bgc : document.getElementById('bg'),
+ bgCtx : document.getElementById('bg').getContext('2d'),
+ fgc : document.getElementById('fg'),
+ fgCtx : document.getElementById('fg').getContext('2d'),
+ evc : document.getElementById('event'),
+ evCtx : document.getElementById('event').getContext('2d'),
+ ev2c : document.getElementById('event2'),
+ ev2Ctx : document.getElementById('event2').getContext('2d'),
+ layerMod:document.getElementById('layerMod'),
+ layerMod2:document.getElementById('layerMod2'),
+ layerMod3:document.getElementById('layerMod3'),
+ viewportButtons:document.getElementById('viewportButtons'),
+ appendPicCanvas : document.getElementById('appendPicCanvas'),
+ bg : document.getElementById('appendPicCanvas').children[0],
+ source : document.getElementById('appendPicCanvas').children[1],
+ picClick : document.getElementById('appendPicCanvas').children[2],
+ sprite : document.getElementById('appendPicCanvas').children[3],
+ sourceCtx:document.getElementById('appendPicCanvas').children[1].getContext('2d'),
+ spriteCtx:document.getElementById('appendPicCanvas').children[3].getContext('2d'),
+ appendPicSelection : document.getElementById('appendPicSelection'),
+ selectAppend : document.getElementById('selectAppend'),
+ selectFileBtn :document.getElementById('selectFileBtn'),
+ changeFloorId :document.getElementById('changeFloorId'),
+ left1 : document.getElementById('left1'),
+ editModeSelect :document.getElementById('editModeSelect'),
+ mid2 : document.getElementById('mid2'),
+ lastUsedDiv: document.getElementById('lastUsedDiv'),
+ lastUsed: document.getElementById('lastUsed'),
+ lastUsedCtx: document.getElementById('lastUsed').getContext('2d'),
+ lockMode: document.getElementById('lockMode'),
+ };
+
+ this.uivalues={
+ // 绘制区拖动有关
+ holdingPath : 0,
+ stepPostfix : null,//用于存放寻路检测的第一个点之后的后续移动
+ mouseOutCheck : 2,
+ startPos:null,
+ endPos:null,
+ // 撤销/恢复
+ preMapData : [],
+ preMapMax: 10,
+ postMapData: [],
+ //
+ shortcut:{},
+ copyedInfo : null,
+ // 折叠素材
+ scrollBarHeight :0,
+ folded:false,
+ foldPerCol: 50,
+ // 画图区菜单
+ lastRightButtonPos:[{x:0,y:0},{x:0,y:0}],
+ lastCopyedInfo : [null, null],
+ //
+ ratio : 1,
+ // blockly转义
+ disableBlocklyReplace: false,
+
+ // 绑定机关门事件相关
+ bindSpecialDoor: {
+ loc: null,
+ n: -1,
+ enemys: []
+ },
+
+ // 复制怪物或道具属性
+ copyEnemyItem : {
+ type: null,
+ data: {}
+ },
+
+ // tile
+ tileSize: [1,1],
+ lockMode: false,
+
+ // 最近使用的图块
+ lastUsed: [],
+ };
+
window.onerror = function (msg, url, lineNo, columnNo, error) {
var string = msg.toLowerCase();
var substring = "script error";
@@ -30,6 +131,8 @@ function editor() {
};
}
+editor.prototype.uifunctions={};
+
/*
editor.loc
editor.pos
@@ -48,11 +151,20 @@ editor.prototype.init = function (callback) {
editor.airwallImg.src = './project/images/airwall.png';
main.init('editor', function () {
- editor_util_wrapper(editor);
- editor_game_wrapper(editor, main, core);
- editor_table_wrapper(editor);
- editor_unsorted_1_wrapper(editor);
- afterMainInit();
+ editor.config = new editor_config();
+ editor.config.load(function() {
+ editor_util_wrapper(editor);
+ editor_game_wrapper(editor, main, core);
+ editor_file_wrapper(editor);
+ editor_table_wrapper(editor);
+ editor_ui_wrapper(editor);
+ editor_mappanel_wrapper(editor);
+ editor_datapanel_wrapper(editor);
+ editor_materialpanel_wrapper(editor);
+ editor_listen_wrapper(editor);
+ editor.printe=printe;
+ afterMainInit();
+ })
});
var afterMainInit = function () {
@@ -63,10 +175,11 @@ editor.prototype.init = function (callback) {
editor_file = editor_file(editor, function () {
editor.file = editor_file;
editor_mode = editor_mode(editor);
- editor_unsorted_2_wrapper(editor_mode);
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 () {
+ core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.clone(core.initStatus.maps));
+ var lastFloorId = editor.config.get('editorLastFloorId', core.status.floorId);
+ if (core.floorIds.indexOf(lastFloorId) < 0) lastFloorId = core.status.floorId;
+ core.changeFloor(lastFloorId, null, core.firstData.hero.loc, null, function () {
afterCoreReset();
}, true);
core.events.setInitData(null);
@@ -96,6 +209,17 @@ editor.prototype.init = function (callback) {
editor_multi = editor_multi();
editor_blockly = editor_blockly();
+ // --- 所有用到的flags
+ editor.used_flags = {};
+ for (var floorId in editor.main.floors) {
+ editor.addUsedFlags(JSON.stringify(editor.main.floors[floorId]));
+ }
+ if (events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent) {
+ for (var name in events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent) {
+ editor.addUsedFlags(JSON.stringify(events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent[name]));
+ }
+ }
+
if (editor.useCompress == null) editor.useCompress = useCompress;
if (Boolean(callback)) callback();
@@ -105,9 +229,9 @@ editor.prototype.init = function (callback) {
}
editor.prototype.mapInit = function () {
- var ec = document.getElementById('event').getContext('2d');
+ var ec = editor.dom.evCtx;
ec.clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32);
- document.getElementById('event2').getContext('2d').clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32);
+ editor.dom.ev2Ctx.clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32);
editor.map = [];
var sy=editor.currentFloorData.map.length,sx=editor.currentFloorData.map[0].length;
for (var y = 0; y < sy; y++) {
@@ -140,53 +264,80 @@ editor.prototype.changeFloor = function (floorId, callback) {
});
editor.currentFloorData[name]=mapArray;
}
- editor.preMapData = null;
+ editor.uivalues.preMapData = [];
+ editor.uivalues.postMapData = [];
+ editor.uifunctions._extraEvent_bindSpecialDoor_doAction(true);
core.changeFloor(floorId, null, {"x": 0, "y": 0, "direction": "up"}, null, function () {
- core.bigmap.offsetX=0;
- core.bigmap.offsetY=0;
- editor.moveViewport(0,0);
-
editor.game.fetchMapFromCore();
editor.updateMap();
editor_mode.floor();
editor.drawEventBlock();
- if (callback) callback();
+
+ editor.viewportLoc = editor.viewportLoc || {};
+ var loc = editor.viewportLoc[floorId] || [], x = loc[0] || 0, y = loc[1] || 0;
+ editor.setViewport(x, y);
+
+ editor.config.set('editorLastFloorId', floorId, function() {
+ if (callback) callback();
+ });
});
}
/////////// 游戏绘图相关 ///////////
editor.prototype.drawEventBlock = function () {
- var fg=document.getElementById('efg').getContext('2d');
+ var fg=editor.dom.efgCtx;
fg.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
+ var firstData = editor.game.getFirstData();
for (var i=0;i= 0) {
+ fg.textAlign = 'right';
+ editor.game.doCoreFunc("fillBoldText", fg, index + 1,
+ 32 * i + 28, 32 * j + 15, '#FF7F00', '14px Verdana');
+ }
}
}
}
editor.prototype.drawPosSelection = function () {
this.drawEventBlock();
- var fg=document.getElementById('efg').getContext('2d');
+ var fg=editor.dom.efgCtx;
fg.strokeStyle = 'rgba(255,255,255,0.7)';
fg.lineWidth = 4;
fg.strokeRect(32*editor.pos.x - core.bigmap.offsetX + 4, 32*editor.pos.y - core.bigmap.offsetY + 4, 24, 24);
@@ -238,30 +389,61 @@ editor.prototype.updateMap = function () {
//ctx.drawImage(core.material.images[tileInfo.images], 0, tileInfo.y*32, 32, 32, x*32, y*32, 32, 32);
}
// 绘制地图 start
- var eventCtx = document.getElementById('event').getContext("2d");
- var fgCtx = document.getElementById('fg').getContext("2d");
- var bgCtx = document.getElementById('bg').getContext("2d");
- for (var y = 0; y < editor.map.length; y++)
+ for (var y = 0; y < editor.map.length; y++) {
for (var x = 0; x < editor.map[0].length; x++) {
var tileInfo = editor.map[y][x];
- drawTile(eventCtx, x, y, tileInfo);
+ drawTile(editor.dom.evCtx, x, y, tileInfo);
tileInfo = editor.fgmap[y][x];
- drawTile(fgCtx, x, y, tileInfo);
+ drawTile(editor.dom.fgCtx, x, y, tileInfo);
tileInfo = editor.bgmap[y][x];
- drawTile(bgCtx, x, y, tileInfo);
+ drawTile(editor.dom.bgCtx, x, y, tileInfo);
}
+ }
// 绘制地图 end
-
+
+ this.updateLastUsedMap();
}
-editor.prototype.moveViewport=function(x,y){
- 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__);
+editor.prototype.updateLastUsedMap = function () {
+ // 绘制最近使用事件
+ var ctx = editor.dom.lastUsedCtx;
+ ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
+ ctx.strokeStyle = 'rgba(255,128,0,0.85)';
+ ctx.lineWidth = 4;
+ for (var i = 0; i < editor.uivalues.lastUsed.length; ++i) {
+ try {
+ var x = i % core.__SIZE__, y = parseInt(i / core.__SIZE__);
+ var info = editor.uivalues.lastUsed[i];
+ if (!info || !info.images) continue;
+ if (info.isTile && core.material.images.tilesets[info.images]) {
+ ctx.drawImage(core.material.images.tilesets[info.images], 32 * info.x, 32 * info.y, 32, 32, x*32, y*32, 32, 32);
+ } else if (info.images == 'autotile' && core.material.images.autotile[info.id]) {
+ ctx.drawImage(core.material.images.autotile[info.id], 0, 0, 32, 32, x * 32, y * 32, 32, 32);
+ } else {
+ var per_height = info.images.endsWith('48') ? 48 : 32;
+ ctx.drawImage(core.material.images[info.images], 0, info.y * per_height, 32, per_height, x * 32, y * 32, 32, 32);
+ }
+ if (selectBox.isSelected() && editor.info.id == info.id) {
+ ctx.strokeRect(32 * x + 2, 32 * y + 2, 28, 28);
+ }
+ } catch (e) {}
+ }
+}
+
+editor.prototype.setViewport=function (x, y) {
+ core.bigmap.offsetX = core.clamp(x, 0, 32*core.bigmap.width-core.__PIXELS__);
+ core.bigmap.offsetY = core.clamp(y, 0, 32*core.bigmap.height-core.__PIXELS__);
+ editor.viewportLoc = editor.viewportLoc || {};
+ editor.viewportLoc[editor.currentFloorId] = [core.bigmap.offsetX, core.bigmap.offsetY];
core.control.updateViewport();
editor.buildMark();
editor.drawPosSelection();
}
+editor.prototype.moveViewport=function(x,y){
+ editor.setViewport(core.bigmap.offsetX+32*x, core.bigmap.offsetY+32*y);
+}
+
/////////// 界面交互相关 ///////////
editor.prototype.drawInitData = function (icons) {
@@ -270,7 +452,11 @@ editor.prototype.drawInitData = function (icons) {
var maxHeight = 700;
var sumWidth = 0;
editor.widthsX = {};
+ editor.uivalues.folded = editor.config.get('folded', false);
+ // editor.uivalues.folded = true;
+ editor.uivalues.foldPerCol = editor.config.get('foldPerCol', 50);
// var imgNames = Object.keys(images); //还是固定顺序吧;
+ editor.uivalues.lastUsed = editor.config.get("lastUsed", []);
var imgNames = ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"];
for (var ii = 0; ii < imgNames.length; ii++) {
@@ -280,20 +466,21 @@ editor.prototype.drawInitData = function (icons) {
for (var im in autotiles) {
tempy += autotiles[im].height;
}
- editor.widthsX[img] = [img, sumWidth / 32, (sumWidth + 3 * 32) / 32, tempy];
- sumWidth += 3 * 32;
+ var tempx = editor.uivalues.folded ? 32 : 3 * 32;
+ editor.widthsX[img] = [img, sumWidth / 32, (sumWidth + tempx) / 32, tempy];
+ sumWidth += tempx;
maxHeight = Math.max(maxHeight, tempy);
continue;
}
- if (img == 'terrains') {
- editor.widthsX[img] = [img, sumWidth / 32, (sumWidth + images[img].width) / 32, images[img].height + 32*2]
- sumWidth += images[img].width;
- maxHeight = Math.max(maxHeight, images[img].height + 32*2);
- continue;
+ var width = images[img].width, height = images[img].height, mh = height;
+ if (editor.uivalues.folded) {
+ var per_height = (img == 'enemy48' || img == 'npc48' ? 48 : 32);
+ width = Math.ceil(height / per_height / editor.uivalues.foldPerCol) * 32;
+ if (width > 32) mh = per_height * editor.uivalues.foldPerCol;
}
- editor.widthsX[img] = [img, sumWidth / 32, (sumWidth + images[img].width) / 32, images[img].height];
- sumWidth += images[img].width;
- maxHeight = Math.max(maxHeight, images[img].height);
+ editor.widthsX[img] = [img, sumWidth / 32, (sumWidth + width) / 32, height];
+ sumWidth += width;
+ maxHeight = Math.max(maxHeight, mh + 64);
}
var tilesets = images.tilesets;
for (var ii in core.tilesets) {
@@ -310,82 +497,75 @@ editor.prototype.drawInitData = function (icons) {
if (fullWidth > edata.width) edata.style.width = (edata.width = fullWidth) / ratio + 'px';
edata.style.height = (edata.height = fullHeight) / ratio + 'px';
*/
+ var iconImages = document.getElementById('iconImages');
iconImages.style.width = (iconImages.width = fullWidth) / ratio + 'px';
iconImages.style.height = (iconImages.height = fullHeight) / ratio + 'px';
- var dc = {drawImage:function(){
- var image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight;
- var a=Array.prototype.slice.call(arguments)
- if(arguments.length==3){
- // [image, dx, dy]=arguments
- // [sx, sy, sWidth, sHeight, dWidth, dHeight]=[0,0,image.width,image.height,image.width,image.height]
- image=a[0]
- a=[a[0],0,0,image.width,image.height,a[1],a[2],image.width,image.height]
- }
- if(arguments.length==5){
- // [image, dx, dy, dWidth, dHeight]=arguments
- // [sx, sy, sWidth, sHeight]=[0,0,image.width,image.height]
- image=a[0]
- a=[a[0],0,0,image.width,image.height,a[1],a[2],a[3],a[4]]
- }
- if(arguments.length==9){
- // [image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight]=arguments
- }
- image=a[0];
- sx=a[1];
- sy=a[2];
- sWidth=a[3];
- sHeight=a[4];
- dx=a[5];
- dy=a[6];
- dWidth=a[7];
- dHeight=a[8];
- //放弃对 dWidth, dHeight 的支持, 始终画一样大的
- var dimg=new Image()
- dimg.src = image.src;
- dimg.style.clip=['rect(',sy,'px,',sx+sWidth,'px,',sy+sHeight,'px,',sx,'px)'].join('')
- dimg.style.top=dy-sy+'px'
- dimg.style.left=dx-sx+'px'
- dimg.width=image.width/ratio
- dimg.height=image.height/ratio
- iconImages.appendChild(dimg)
- }}
- // var dc = edata.getContext('2d');
- var nowx = 0;
- var nowy = 0;
+ var drawImage = function (image, x, y) {
+ image.style.left = x + 'px';
+ image.style.top = y + 'px';
+ iconImages.appendChild(image);
+ }
+
+ var nowx = 0, nowy = 0;
for (var ii = 0; ii < imgNames.length; ii++) {
var img = imgNames[ii];
if (img == 'terrains') {
- (function(image,dc,nowx){
+ (function(image,nowx){
if (image.complete) {
- dc.drawImage(image, nowx, 32);
+ drawImage(image, nowx, 32);
core.material.images.airwall = image;
delete(editor.airwallImg);
} else image.onload = function () {
- dc.drawImage(image, nowx, 32);
+ drawImage(image, nowx, 32);
core.material.images.airwall = image;
delete(editor.airwallImg);
editor.updateMap();
}
- })(editor.airwallImg,dc,nowx);
- dc.drawImage(images[img], nowx, 32*2);
- nowx += images[img].width;
+ })(editor.airwallImg,nowx);
+ if (editor.uivalues.folded) {
+ // --- 单列 & 折行
+ var subimgs = core.splitImage(images[img], 32, editor.uivalues.foldPerCol * 32);
+ var frames = images[img].width / 32;
+ for (var i = 0; i < subimgs.length; i+=frames) {
+ drawImage(subimgs[i], nowx, i==0?2*32:0);
+ nowx += 32;
+ }
+ }
+ else {
+ drawImage(images[img], nowx, 32*2);
+ nowx += images[img].width;
+ }
continue;
}
if (img == 'autotile') {
var autotiles = images[img];
+ var tempx = editor.uivalues.folded ? 32 : 96;
for (var im in autotiles) {
- dc.drawImage(autotiles[im], 0, 0, 96, 128, nowx, nowy, 96, 128);
+ var subimgs = core.splitImage(autotiles[im], tempx, autotiles[im].height);
+ drawImage(subimgs[0], nowx, nowy);
nowy += autotiles[im].height;
}
- nowx += 3 * 32;
+ nowx += tempx;
continue;
}
- dc.drawImage(images[img], nowx, 0)
- nowx += images[img].width;
+ if (editor.uivalues.folded) {
+ // --- 单列 & 折行
+ var per_height = img.endsWith('48') ? 48 : 32;
+ var subimgs = core.splitImage(images[img], 32, editor.uivalues.foldPerCol * per_height);
+ var frames = images[img].width / 32;
+ for (var i = 0; i < subimgs.length; i+=frames) {
+ drawImage(subimgs[i], nowx, 0);
+ nowx += 32;
+ }
+ }
+ else {
+ drawImage(images[img], nowx, 0);
+ nowx += images[img].width;
+ }
}
for (var ii in core.tilesets) {
var img = core.tilesets[ii];
- dc.drawImage(tilesets[img], nowx, 0)
+ drawImage(tilesets[img], nowx, 0);
nowx += tilesets[img].width;
}
//editor.mapInit();
@@ -459,14 +639,20 @@ editor.prototype.setSelectBoxFromInfo=function(thisevent){
pos.x=editor.widthsX[thisevent.images][1];
pos.y=thisevent.y;
if(thisevent.x)pos.x+=thisevent.x;
- if(thisevent.images=='terrains')pos.y+=2;
ysize = thisevent.images.endsWith('48') ? 48 : 32;
+ if (editor.uivalues.folded && core.tilesets.indexOf(thisevent.images)==-1) {
+ pos.x += Math.floor(pos.y / editor.uivalues.foldPerCol);
+ pos.y %= editor.uivalues.foldPerCol;
+ }
+ if(pos.x == 0) pos.y+=2;
}
- var dataSelection = document.getElementById('dataSelection');
- 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);});
+ editor.dom.dataSelection.style.left = pos.x * 32 + 'px';
+ editor.dom.dataSelection.style.top = pos.y * ysize + 'px';
+ editor.dom.dataSelection.style.height = ysize - 6 + 'px';
+ setTimeout(function(){
+ selectBox.isSelected(true);
+ editor.updateLastUsedMap();
+ });
editor.info = JSON.parse(JSON.stringify(thisevent));
tip.infos(JSON.parse(JSON.stringify(thisevent)));
editor.pos=pos;
@@ -474,12 +660,31 @@ editor.prototype.setSelectBoxFromInfo=function(thisevent){
editor_mode.onmode('enemyitem');
}
+editor.prototype.addUsedFlags = function (s) {
+ s.replace(/flag:([a-zA-Z0-9_\u4E00-\u9FCC]+)/g, function (s0, s1) {
+ editor.used_flags[s1] = true; return s0;
+ });
+ s.replace(/flags\.([a-zA-Z_]\w*)/g, function (s0, s1) {
+ editor.used_flags[s1] = true; return s0;
+ });
+ if (window.flags) {
+ for (var s in editor.used_flags) {
+ if (!(s in window.flags)) {
+ window.flags[s] = null;
+ }
+ }
+ }
+}
+
editor.prototype.listen = function () {
- // 移动至 editor_unsorted_1.js
+ // 移动至 editor_listen.js
}//绑定事件
editor.prototype.mobile_listen=function(){
- // 移动至 editor_unsorted_1.js
+ // 移动至 editor_listen.js
}
+
+
+
editor = new editor();
\ No newline at end of file
diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js
index 02453bab..aa221608 100644
--- a/_server/editor_blockly.js
+++ b/_server/editor_blockly.js
@@ -2,7 +2,11 @@ editor_blockly = function () {
var editor_blockly = {};
- initscript = String.raw`
+/////////////////initscript start/////////////////////////////
+// do not use String.raw because of highlighting
+// Comment tagged templates
+// https://marketplace.visualstudio.com/items?itemName=bierner.comment-tagged-templates
+ initscript = /* js */`
(function(){
var getCategory = function(name,custom){
for(var node of document.getElementById('toolbox').children) {
@@ -22,6 +26,16 @@ editor_blockly = function () {
"本事件触发一次后会消失",
{"type": "hide", "time": 500},
],'event'),
+ MotaActionFunctions.actionParser.parse({
+ "condition": "flag:__door__==2",
+ "currentFloor": true,
+ "priority": 0,
+ "delayExecute": false,
+ "multiExecute": false,
+ "data": [
+ {"type": "openDoor", "loc": [10,5]}
+ ],
+ },'autoEvent'),
MotaActionBlocks['changeFloor_m'].xmlText(),
MotaActionFunctions.actionParser.parse([{
"id": "moneyShop1",
@@ -30,12 +44,17 @@ editor_blockly = function () {
"textInList": "1F金币商店",
"use": "money",
"need": "20+10*times*(times+1)",
- "text": "勇敢的武士啊,给我\${need}金币就可以:",
+ "text": "勇敢的武士啊,给我\\\${need}金币就可以:",
"choices": [
{"text": "生命+800", "effect": "status:hp+=800"},
{"text": "攻击+4", "effect": "status:atk+=4"},
- {"text": "防御+4", "effect": "status:def+=4"},
- {"text": "魔防+10", "effect": "status:mdef+=10"}
+ ]
+ },{
+ "id": "itemShop",
+ "item": true,
+ "textInList": "道具商店",
+ "choices": [
+ {"id": "yellowKey", "number": 10, "money": 10}
]
},{
"id": "keyShop1",
@@ -50,6 +69,7 @@ editor_blockly = function () {
MotaActionBlocks['eachArrive_m'].xmlText(),
MotaActionBlocks['level_m'].xmlText(),
MotaActionBlocks['commonEvent_m'].xmlText(),
+ MotaActionBlocks['item_m'].xmlText(),
],
'显示文字':[
MotaActionBlocks['text_0_s'].xmlText(),
@@ -72,20 +92,21 @@ editor_blockly = function () {
MotaActionBlocks['confirm_s'].xmlText(),
MotaActionBlocks['choices_s'].xmlText([
'选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([
- '剑','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
+ '剑','','',null,'',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]),
MotaActionBlocks['choicesContext'].xmlText([
- '盾','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]),
+ '盾','','',null,'',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]),
])
])
]),
],
'数据相关':[
- MotaActionBlocks['setValue_s'].xmlText([
- MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
- ]),
MotaActionBlocks['addValue_s'].xmlText([
- MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
+ MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false
]),
+ MotaActionBlocks['setValue_s'].xmlText([
+ MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false
+ ]),
+ MotaActionBlocks['setEnemy_s'].xmlText(),
MotaActionBlocks['setFloor_s'].xmlText(),
MotaActionBlocks['setGlobalAttribute_s'].xmlText(),
MotaActionBlocks['setGlobalValue_s'].xmlText(),
@@ -93,7 +114,6 @@ editor_blockly = function () {
MotaActionBlocks['input_s'].xmlText(),
MotaActionBlocks['input2_s'].xmlText(),
MotaActionBlocks['update_s'].xmlText(),
- MotaActionBlocks['updateEnemys_s'].xmlText(),
MotaActionBlocks['moveHero_s'].xmlText(),
MotaActionBlocks['jumpHero_s'].xmlText(),
MotaActionBlocks['changeFloor_s'].xmlText(),
@@ -101,6 +121,8 @@ editor_blockly = function () {
MotaActionBlocks['changePos_1_s'].xmlText(),
MotaActionBlocks['battle_s'].xmlText(),
MotaActionBlocks['useItem_s'].xmlText(),
+ MotaActionBlocks['loadEquip_s'].xmlText(),
+ MotaActionBlocks['unloadEquip_s'].xmlText(),
MotaActionBlocks['openShop_s'].xmlText(),
MotaActionBlocks['disableShop_s'].xmlText(),
MotaActionBlocks['setHeroIcon_s'].xmlText(),
@@ -108,6 +130,7 @@ editor_blockly = function () {
MotaActionBlocks['unfollow_s'].xmlText(),
],
'地图处理':[
+ MotaActionBlocks['battle_1_s'].xmlText(),
MotaActionBlocks['openDoor_s'].xmlText(),
MotaActionBlocks['closeDoor_s'].xmlText(),
MotaActionBlocks['show_s'].xmlText(),
@@ -122,8 +145,8 @@ editor_blockly = function () {
MotaActionBlocks['hideFloorImg_s'].xmlText(),
],
'事件控制':[
- MotaActionBlocks['if_s'].xmlText(),
MotaActionBlocks['if_1_s'].xmlText(),
+ MotaActionBlocks['if_s'].xmlText(),
MotaActionFunctions.actionParser.parseList({"type": "switch", "condition": "判别值", "caseList": [
{"action": [{"type": "comment", "text": "当判别值是值的场合执行此事件"}]},
{"action": [], "nobreak": true},
@@ -141,12 +164,19 @@ editor_blockly = function () {
],
'特效/声音':[
MotaActionBlocks['sleep_s'].xmlText(),
- MotaActionBlocks['wait_s'].xmlText(),
+ MotaActionFunctions.actionParser.parseList({"type": "wait", "data": [
+ {"case": "keyboard", "keycode": 13, "action": [{"type": "comment", "text": "当按下回车(keycode=13)时执行此事件"}]},
+ {"case": "mouse", "px": [0,32], "py": [0,32], "action": [{"type": "comment", "text": "当点击地图左上角时执行此事件"}]},
+ ]}),
MotaActionBlocks['waitAsync_s'].xmlText(),
MotaActionBlocks['vibrate_s'].xmlText(),
MotaActionBlocks['animate_s'].xmlText(),
+ MotaActionBlocks['setViewport_s'].xmlText(),
+ MotaActionBlocks['moveViewport_s'].xmlText(),
MotaActionBlocks['showStatusBar_s'].xmlText(),
MotaActionBlocks['hideStatusBar_s'].xmlText(),
+ MotaActionBlocks['showHero_s'].xmlText(),
+ MotaActionBlocks['hideHero_s'].xmlText(),
MotaActionBlocks['setCurtain_0_s'].xmlText(),
MotaActionBlocks['setCurtain_1_s'].xmlText(),
MotaActionBlocks['screenFlash_s'].xmlText(),
@@ -164,16 +194,39 @@ editor_blockly = function () {
MotaActionBlocks['autoSave_s'].xmlText(),
MotaActionBlocks['callLoad_s'].xmlText(),
],
+ 'UI绘制':[
+ MotaActionBlocks['previewUI_s'].xmlText(),
+ MotaActionBlocks['clearMap_s'].xmlText(),
+ MotaActionBlocks['clearMap_1_s'].xmlText(),
+ MotaActionBlocks['setAttribute_s'].xmlText(),
+ MotaActionBlocks['fillText_s'].xmlText(),
+ MotaActionBlocks['fillBoldText_s'].xmlText(),
+ MotaActionBlocks['drawTextContent_s'].xmlText(),
+ MotaActionBlocks['fillRect_s'].xmlText(),
+ MotaActionBlocks['strokeRect_s'].xmlText(),
+ MotaActionBlocks['drawLine_s'].xmlText(),
+ MotaActionBlocks['drawArrow_s'].xmlText(),
+ MotaActionBlocks['fillPolygon_s'].xmlText(),
+ MotaActionBlocks['strokePolygon_s'].xmlText(),
+ MotaActionBlocks['fillCircle_s'].xmlText(),
+ MotaActionBlocks['strokeCircle_s'].xmlText(),
+ MotaActionBlocks['drawImage_s'].xmlText(),
+ MotaActionBlocks['drawImage_1_s'].xmlText(),
+ MotaActionBlocks['drawIcon_s'].xmlText(),
+ MotaActionBlocks['drawBackground_s'].xmlText(),
+ MotaActionBlocks['drawSelector_s'].xmlText(),
+ MotaActionBlocks['drawSelector_1_s'].xmlText(),
+ ],
'原生脚本':[
MotaActionBlocks['function_s'].xmlText(),
MotaActionBlocks['unknown_s'].xmlText(),
],
'值块':[
- MotaActionBlocks['setValue_s'].xmlText([
- MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
- ]),
MotaActionBlocks['addValue_s'].xmlText([
- MotaActionBlocks['idString_1_e'].xmlText(['status','hp'])
+ MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false
+ ]),
+ MotaActionBlocks['setValue_s'].xmlText([
+ MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false
]),
MotaActionBlocks['expression_arithmetic_0'].xmlText(),
MotaActionBlocks['evFlag_e'].xmlText(),
@@ -182,33 +235,37 @@ editor_blockly = function () {
MotaActionBlocks['idString_e'].xmlText(),
MotaActionBlocks['idString_1_e'].xmlText(),
MotaActionBlocks['idString_2_e'].xmlText(),
+ MotaActionBlocks['idString_3_e'].xmlText(),
+ MotaActionBlocks['idString_4_e'].xmlText(),
+ MotaActionBlocks['idString_5_e'].xmlText(),
+ MotaActionBlocks['idString_6_e'].xmlText(),
MotaActionBlocks['evalString_e'].xmlText(),
],
'常见事件模板':[
'',
MotaActionFunctions.actionParser.parseList({"type": "if", "condition": "!core.musicStatus.bgmStatus",
"true": [
- "\t[系统提示]你当前音乐处于关闭状态,本塔开音乐游戏效果更佳"
+ "\\t[系统提示]你当前音乐处于关闭状态,本塔开音乐游戏效果更佳"
],
"false": []
}),
'',
MotaActionFunctions.actionParser.parse([
- {"type": "choices", "text": "\t[老人,man]少年,你需要钥匙吗?\n我这里有大把的!",
+ {"type": "choices", "text": "\\t[老人,man]少年,你需要钥匙吗?\\n我这里有大把的!",
"choices": [
- {"text": "黄钥匙(\${9+flag:shop_times}金币)", "color": [255,255,0,1], "action": [
+ {"text": "黄钥匙(\\\${9+flag:shop_times}金币)", "color": [255,255,0,1], "action": [
{"type": "if", "condition": "status:money>=9+flag:shop_times",
"true": [
{"type": "addValue", "name": "status:money", "value": "-(9+flag:shop_times)"},
{"type": "addValue", "name": "item:yellowKey", "value": "1"},
],
"false": [
- "\t[老人,man]你的金钱不足!",
+ "\\t[老人,man]你的金钱不足!",
{"type": "revisit"}
]
}
]},
- {"text": "蓝钥匙(\${18+2*flag:shop_times}金币)", "color": [0,0,255,1], "action": [
+ {"text": "蓝钥匙(\\\${18+2*flag:shop_times}金币)", "color": [0,0,255,1], "action": [
]},
{"text": "离开", "action": [
{"type": "exit"}
@@ -361,7 +418,7 @@ function omitedcheckUpdateFunction(event) {
}
}
try {
- var code = Blockly.JavaScript.workspaceToCode(workspace).replace(/\\i/g, '\\\\i');
+ var code = Blockly.JavaScript.workspaceToCode(workspace).replace(/\\\\(i|c|d|e)/g, '\\\\\\\\$1');
codeAreaHL.setValue(code);
} catch (error) {
codeAreaHL.setValue(String(error));
@@ -433,6 +490,18 @@ function omitedcheckUpdateFunction(event) {
}
})();
`;
+/////////////////initscript end /////////////////////////////
+
+ editor.uivalues.disableBlocklyReplace = editor.config.get("disableBlocklyReplace", false);
+ var replaceCheckbox = document.getElementById('blocklyReplace');
+ replaceCheckbox.checked = !editor.uivalues.disableBlocklyReplace;
+
+ editor_blockly.triggerReplace = function () {
+ editor.uivalues.disableBlocklyReplace = !replaceCheckbox.checked;
+ editor.config.set("disableBlocklyReplace", !replaceCheckbox.checked);
+ if (MotaActionFunctions) MotaActionFunctions.disableReplace = !replaceCheckbox.checked;
+ alert("已" + (replaceCheckbox.checked ? "开启" : "关闭") + "中文变量名替换!\n关闭并重开事件编辑器以生效。");
+ }
var input_ = '';
editor_blockly.runOne = function () {
@@ -463,6 +532,7 @@ function omitedcheckUpdateFunction(event) {
}
input_ = xhr.responseText;
editor_blockly.runOne();
+ MotaActionFunctions.disableReplace = editor.uivalues.disableBlocklyReplace;
}
xhr.open('GET', '_server/MotaAction.g4', true);
xhr.send(null);
@@ -503,8 +573,7 @@ function omitedcheckUpdateFunction(event) {
MotaActionFunctions.parse(
eval('obj=' + codeAreaHL.getValue().replace(/[<>&]/g, function (c) {
return {'<': '<', '>': '>', '&': '&'}[c];
- }).replace(/\\r/g, '\\\\r').replace(/\\f/g, '\\\\f')
- .replace(/\\i/,'\\\\i')),
+ }).replace(/\\(r|f|i|c|d|e)/g,'\\\\$1')),
document.getElementById('entryType').value
);
}
@@ -578,14 +647,86 @@ function omitedcheckUpdateFunction(event) {
return;
}
var code = Blockly.JavaScript.workspaceToCode(editor_blockly.workspace);
- code = code.replace(/\\i/g, '\\\\i');
+ code = code.replace(/\\(i|c|d|e)/g, '\\\\$1');
eval('var obj=' + code);
+ if (this.checkAsync(obj) && confirm("警告!存在不等待执行完毕的事件但却没有用【等待所有异步事件处理完毕】来等待" +
+ "它们执行完毕,这样可能会导致录像检测系统出问题。\n你要返回修改么?")) return;
setvalue(JSON.stringify(obj));
}
+ // 检查"不等待处理完毕"
+ editor_blockly.checkAsync = function (obj) {
+ if (!(obj instanceof Array)) return false;
+ var hasAsync = false;
+ for (var i = 0; i < obj.length; ++i) {
+ var one = obj[i];
+ if (one.type == 'if' && (this.checkAsync(one['true']) || this.checkAsync(one['false'])))
+ return true;
+ if ((one.type == 'while' || one.type == 'dowhile') && this.checkAsync(one.data))
+ return true;
+ if (one.type == 'if' && (this.checkAsync(one.yes) || this.checkAsync(one.no)))
+ return true;
+ if (one.type == 'choices') {
+ var list = one.choices;
+ if (list instanceof Array) {
+ for (var j = 0; j < list.length; j++) {
+ if (this.checkAsync(list[j].action)) return true;
+ }
+ }
+ }
+ if (one.type == 'switch') {
+ var list = one.caseList;
+ if (list instanceof Array) {
+ for (var j = 0; j < list.length; j++) {
+ if (this.checkAsync(list[j].action)) return true;
+ }
+ }
+ }
+ if (one.async && one.type != 'animate') hasAsync = true;
+ if (one.type == 'waitAsync') hasAsync = false;
+ }
+ return hasAsync;
+ }
+
+ var previewBlock = function (b) {
+ var types = [
+ "previewUI_s", "clearMap_s", "clearMap_1_s", "setAttribute_s", "fillText_s",
+ "fillBoldText_s", "fillRect_s", "strokeRect_s", "drawLine_s",
+ "drawArrow_s", "fillPolygon_s", "strokePolygon_s", "fillCircle_s", "strokeCircle_s",
+ "drawImage_s", "drawImage_1_s", "drawIcon_s", "drawBackground_s", "drawSelector_s", "drawSelector_1_s",
+ "waitContext_2"
+ ];
+ if (b && types.indexOf(b.type)>=0) {
+ try {
+ var code = "[" + Blockly.JavaScript.blockToCode(b).replace(/\\(i|c|d|e)/g, '\\\\$1') + "]";
+ eval("var obj="+code);
+ if (obj.length > 0 && b.type == 'waitContext_2') {
+ var dt = obj[0];
+ editor.uievent.previewUI([{"type": "fillRect", "x": dt.px[0], "y": dt.py[0],
+ "width": "(" + dt.px[1] + ")-(" + dt.px[0] + ")", "height": "(" + dt.py[1] + ")-(" + dt.py[0] + ")",
+ "style": "rgba(255,0,0,0.5)"}])
+ }
+ else if (obj.length > 0 && b.type.startsWith(obj[0].type)) {
+ if (b.type == 'previewUI_s')
+ editor.uievent.previewUI(obj[0].action);
+ else editor.uievent.previewUI([obj[0]]);
+ }
+ } catch (e) {main.log(e);}
+ return true;
+ }
+ return false;
+ }
+
editor_blockly.doubleClickBlock = function (blockId) {
var b = editor_blockly.workspace.getBlockById(blockId);
- //console.log(b);
+
+ if (previewBlock(b)) return;
+
+ if (b && b.type in selectPointBlocks) { // selectPoint
+ this.selectPoint();
+ return;
+ }
+
var textStringDict = {
'text_0_s': 'EvalString_0',
'text_1_s': 'EvalString_2',
@@ -597,6 +738,7 @@ function omitedcheckUpdateFunction(event) {
'function_s': 'RawEvalString_0',
'shopsub': 'EvalString_3',
'confirm_s': 'EvalString_0',
+ 'drawTextContent_s': 'EvalString_0',
}
var f = b ? textStringDict[b.type] : null;
if (f) {
@@ -615,7 +757,7 @@ function omitedcheckUpdateFunction(event) {
'comment_s',
'show_s',
'hide_s',
- 'setValue_s',
+ 'addValue_s',
'if_s',
'battle_s',
'openDoor_s',
@@ -644,40 +786,26 @@ function omitedcheckUpdateFunction(event) {
// Index from 1 - 9
editor_blockly.openToolbox = function(index) {
- // var element = document.getElementById(':'+index);
- // if (element == null || element.getAttribute("aria-selected")=="true") return;
- // element.click();
- editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index-1]);
+ if (index < 0) index += editor_blockly.workspace.toolbox_.tree_.children_.length;
+ editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index]);
}
editor_blockly.reopenToolbox = function(index) {
- // var element = document.getElementById(':'+index);
- // if (element == null) return;
- // if (element.getAttribute("aria-selected")=="true") element.click();
- // element.click();
- editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index-1]);
- editor_blockly.workspace.getFlyout_().show(editor_blockly.workspace.toolbox_.tree_.children_[index-1].blocks);
+ if (index < 0) index += editor_blockly.workspace.toolbox_.tree_.children_.length;
+ editor_blockly.workspace.toolbox_.tree_.setSelectedItem(editor_blockly.workspace.toolbox_.tree_.children_[index]);
+ editor_blockly.workspace.getFlyout_().show(editor_blockly.workspace.toolbox_.tree_.children_[index].blocks);
}
editor_blockly.closeToolbox = function() {
- /*
- for (var i=1; i<=10; i++) {
- var element = document.getElementById(':'+i);
- if (element && element.getAttribute("aria-selected")=="true") {
- element.click();
- return;
- }
- }
- */
editor_blockly.workspace.toolbox_.clearSelection();
}
var searchInput = document.getElementById("searchBlock");
searchInput.onfocus = function () {
- editor_blockly.reopenToolbox(10);
+ editor_blockly.reopenToolbox(-1);
}
searchInput.oninput = function () {
- editor_blockly.reopenToolbox(10);
+ editor_blockly.reopenToolbox(-1);
}
editor_blockly.searchBlock = function (value) {
@@ -702,6 +830,342 @@ function omitedcheckUpdateFunction(event) {
return results.length == 0 ? editor_blockly.lastUsedType : results;
}
+ // ------ select point ------
+
+ // id: [x, y, floorId, forceFloor]
+ var selectPointBlocks = {
+ "changeFloor_m": ["Number_0", "Number_1", "IdString_0", true],
+ "jumpHero_s": ["PosString_0", "PosString_1"],
+ "changeFloor_s": ["PosString_0", "PosString_1", "IdString_0", true],
+ "changePos_0_s": ["PosString_0", "PosString_1"],
+ "battle_1_s": ["PosString_0", "PosString_1"],
+ "openDoor_s": ["PosString_0", "PosString_1", "IdString_0"],
+ "closeDoor_s": ["PosString_0", "PosString_1"],
+ "show_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "hide_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "setBlock_s": ["EvalString_1", "EvalString_2", "IdString_0"],
+ "move_s": ["PosString_0", "PosString_1"],
+ "jump_s": ["PosString_2", "PosString_3"], // 跳跃暂时只考虑终点
+ "showBgFgMap_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "hideBgFgMap_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "setBgFgBlock_s": ["EvalString_1", "EvalString_2", "IdString_0"],
+ "showFloorImg_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "hideFloorImg_s": ["EvalString_0", "EvalString_1", "IdString_0"],
+ "trigger_s": ["PosString_0", "PosString_1"],
+ "insert_2_s": ["PosString_0", "PosString_1", "IdString_0"],
+ "animate_s": ["EvalString_0", "EvalString_0"],
+ "setViewport_s": ["PosString_0", "PosString_1"]
+ }
+
+ editor_blockly.selectPoint = function () {
+ var block = Blockly.selected, arr = null;
+ var floorId = editor.currentFloorId, pos = editor.pos, x = pos.x, y = pos.y;
+ if (block != null && block.type in selectPointBlocks) {
+ arr = selectPointBlocks[block.type];
+ var xv = parseInt(block.getFieldValue(arr[0])), yv = parseInt(block.getFieldValue(arr[1]));
+ if (block.type == 'animate_s') {
+ var v = block.getFieldValue(arr[0]).split(",");
+ xv = parseInt(v[0]); yv = parseInt(v[1]);
+ }
+ if (!isNaN(xv)) x = xv;
+ if (!isNaN(yv)) y = yv;
+ if (arr[2] != null) floorId = block.getFieldValue(arr[2]) || floorId;
+ }
+ editor.uievent.selectPoint(floorId, x, y, arr && arr[2] == null, function (fv, xv, yv) {
+ if (!arr) return;
+ if (arr[2] != null) {
+ if (fv != editor.currentFloorId) block.setFieldValue(fv, arr[2]);
+ else block.setFieldValue(arr[3] ? fv : "", arr[2]);
+ }
+ if (block.type == 'animate_s') {
+ block.setFieldValue(xv+","+yv, arr[0]);
+ }
+ else {
+ block.setFieldValue(xv+"", arr[0]);
+ block.setFieldValue(yv+"", arr[1]);
+ }
+ if (block.type == 'changeFloor_m') {
+ block.setFieldValue("floorId", "Floor_List_0");
+ block.setFieldValue("loc", "Stair_List_0");
+ }
+ });
+ }
+
+ editor_blockly.getAutoCompletions = function (content) {
+ // --- content为当前框中输入内容;将返回一个列表,为后续所有可补全内容
+
+ // 检查 status:xxx,item:xxx和flag:xxx
+ var index = Math.max(content.lastIndexOf(":"), content.lastIndexOf(":"));
+ if (index >= 0) {
+ var ch = content.charAt(index);
+ var before = content.substring(0, index), token = content.substring(index+1);
+ if (/^[a-zA-Z0-9_\u4E00-\u9FCC]*$/.test(token)) {
+ if (before.endsWith("状态") || (ch == ':' && before.endsWith("status"))) {
+ var list = Object.keys(core.status.hero);
+ if (before.endsWith("状态") && MotaActionFunctions) {
+ list = MotaActionFunctions.pattern.replaceStatusList.map(function (v) {
+ return v[1];
+ }).concat(list);
+ }
+ return list.filter(function (one) {
+ return one != token && one.startsWith(token);
+ }).sort();
+ }
+ else if (before.endsWith("物品") || (ch == ':' && before.endsWith("item"))) {
+ var list = Object.keys(core.material.items);
+ if (before.endsWith("物品") && MotaActionFunctions) {
+ list = MotaActionFunctions.pattern.replaceItemList.map(function (v) {
+ return v[1];
+ }).concat(list);
+ }
+ return list.filter(function (one) {
+ return one != token && one.startsWith(token);
+ }).sort();
+ }
+ else if (before.endsWith("变量") || (ch == ':' && before.endsWith("flag"))) {
+ return Object.keys(editor.used_flags || {}).filter(function (one) {
+ return one != token && one.startsWith(token);
+ }).sort();
+ } else if (before.endsWith("怪物") || (ch == ':' && before.endsWith("enemy"))) {
+ return Object.keys(core.material.enemys).filter(function (one) {
+ return one != token && one.startsWith(token);
+ })
+ } else {
+ var index2 = Math.max(content.lastIndexOf(":", index-1), content.lastIndexOf(":", index-1));
+ var ch2 = content.charAt(index2);
+ if (index2 >= 0) {
+ before = content.substring(0, index2);
+ if (before.endsWith("怪物") || (ch == ':' && ch2 == ':' && before.endsWith("enemy"))) {
+ var list = ["name", "hp", "atk", "def", "money", "experience", "point", "special"];
+ if (before.endsWith("怪物") && MotaActionFunctions) {
+ list = MotaActionFunctions.pattern.replaceEnemyList.map(function (v) {
+ return v[1];
+ }).concat(list);
+ }
+ return list.filter(function (one) {
+ return one != token && one.startsWith(token);
+ })
+ }
+ }
+
+ }
+ }
+ }
+
+ // 提供 core.xxx 的补全
+ index = content.lastIndexOf("core.");
+ if (index >= 0) {
+ var s = content.substring(index + 5);
+ if (/^[\w.]*$/.test(s)) {
+ var tokens = s.split(".");
+ var now = core, prefix = tokens[tokens.length - 1];
+ for (var i = 0; i < tokens.length - 1; ++i) {
+ now = now[tokens[i]];
+ if (now == null) break;
+ }
+ if (now != null) {
+ var candidates = [];
+ for (var i in now) {
+ candidates.push(i);
+ }
+ return candidates.filter(function (one) {
+ return one != prefix && one.startsWith(prefix);
+ }).sort();
+ }
+ }
+ }
+
+ // 提供 flags.xxx 补全
+ index = content.lastIndexOf("flags.");
+ if (index >= 0) {
+ var token = content.substring(index+6);
+ return Object.keys(editor.used_flags || {}).filter(function (one) {
+ return one != token && one.startsWith(token)
+ && /^[a-zA-Z_]\w*$/.test(one);
+ }).sort();
+ }
+
+ return [];
+ }
+
+ editor_blockly.completeItems = [];
return editor_blockly;
}
-//editor_blockly=editor_blockly();
\ No newline at end of file
+
+// --- modify Blockly
+
+Blockly.FieldColour.prototype.createWidget_ = function() {
+ Blockly.WidgetDiv.hide();
+
+ // console.log('here')
+ var self=this;
+ var pb=self.sourceBlock_
+ var args = MotaActionBlocks[pb.type].args
+ var targetf=args[args.indexOf(self.name)-1]
+
+ var getValue=function(){
+ // return self.getValue() // css颜色
+ var f = pb.getFieldValue(targetf);
+ if (/^(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)?$/.test(f)) {
+ return f;
+ }
+ return "";
+ // 也可以用 pb.getFieldValue(targetf) 获得颜色块左边的域的内容
+ }
+
+ var setValue=function(newValue){ // css颜色
+ self.setValue(newValue)
+ var c=new Colors();
+ c.setColor(newValue)
+ var rgbatext = [c.colors.webSmart.r,c.colors.webSmart.g,c.colors.webSmart.b,c.colors.alpha].join(",");
+ pb.setFieldValue(rgbatext, targetf) // 放在颜色块左边的域中
+ }
+
+ setTimeout(function () {
+ document.getElementById("colorPicker").value = getValue();
+ window.jsColorPicker.confirm = setValue;
+ // 设置位置
+ triggerColorPicker(Blockly.WidgetDiv.DIV.style.left, Blockly.WidgetDiv.DIV.style.top);
+ });
+
+ return document.createElement('table');
+};
+
+Blockly.FieldTextInput.prototype.showInlineEditor_ = function(quietInput) {
+ Blockly.WidgetDiv.show(this, this.sourceBlock_.RTL, this.widgetDispose_());
+ var div = Blockly.WidgetDiv.DIV;
+ // Create the input.
+ var htmlInput =
+ goog.dom.createDom(goog.dom.TagName.INPUT, 'blocklyHtmlInput');
+ htmlInput.setAttribute('spellcheck', this.spellcheck_);
+ var fontSize =
+ (Blockly.FieldTextInput.FONTSIZE * this.workspace_.scale) + 'pt';
+ div.style.fontSize = fontSize;
+ htmlInput.style.fontSize = fontSize;
+
+ Blockly.FieldTextInput.htmlInput_ = htmlInput;
+ div.appendChild(htmlInput);
+
+ htmlInput.value = htmlInput.defaultValue = this.text_;
+ htmlInput.oldValue_ = null;
+
+ // console.log('here')
+ var self=this;
+ var pb=self.sourceBlock_
+ var args = MotaActionBlocks[pb.type].args
+ var targetf=args[args.indexOf(self.name)+1]
+
+ // ------ colour
+
+ if(targetf && targetf.slice(0,7)==='Colour_'){
+ var inputDom = htmlInput;
+ // var getValue=function(){ // 获得自己的字符串
+ // return pb.getFieldValue(self.name);
+ // }
+ var setValue = function(newValue){ // 设置右边颜色块的css颜色
+ pb.setFieldValue(newValue, targetf)
+ }
+ // 给inputDom绑事件
+ inputDom.oninput=function(){
+ var value=inputDom.value
+ if(/[0-9 ]+,[0-9 ]+,[0-9 ]+(,[0-9. ]+)?/.test(value)){
+ setValue('rgba('+value+')')
+ }
+ }
+ }
+ else {
+
+ htmlInput.onkeydown = function (e) {
+ if (e.keyCode == 13 && awesomplete.opened && awesomplete.selected) {
+ e.stopPropagation();
+ e.stopImmediatePropagation();
+ e.preventDefault();
+ awesomplete.select();
+ return false;
+ }
+ }
+
+ // --- awesomplete
+ var awesomplete = new Awesomplete(htmlInput, {
+ minChars: pb.type == "idString_3_e" ? 1 : 2,
+ maxItems: 12,
+ autoFirst: true,
+ replace: function (text) {
+ text = text.toString();
+ var value = this.input.value, index = this.input.selectionEnd;
+ if (index == null) index = value.length;
+ if (index < awesomplete.prefix.length) index = awesomplete.prefix.length;
+ var str = value.substring(0, index - awesomplete.prefix.length) + text + value.substring(index);
+ this.input.value = str;
+ pb.setFieldValue(str, self.name);
+ index += text.length - awesomplete.prefix.length;
+ this.input.setSelectionRange(index, index);
+
+ editor_blockly.completeItems = editor_blockly.completeItems.filter(function (x) {
+ return x != text;
+ });
+ editor_blockly.completeItems.unshift(text);
+ },
+ filter: function () {return true;},
+ item: function (text, input) {
+ var li = document.createElement("li");
+ li.setAttribute("role", "option");
+ li.setAttribute("aria-selected", "false");
+ input = awesomplete.prefix.trim();
+ if (input != "") text = text.replace(new RegExp("^"+input, "i"), "$&");
+ li.innerHTML = text;
+ return li;
+ },
+ sort: function (a, b) {
+ a = a.toString(); b = b.toString();
+ var ia = editor_blockly.completeItems.indexOf(a), ib = editor_blockly.completeItems.indexOf(b);
+ if (ia < 0) ia = editor_blockly.completeItems.length;
+ if (ib < 0) ib = editor_blockly.completeItems.length;
+ if (ia != ib) return ia - ib;
+ if (a.length != b.length) return a.length - b.length;
+ return a < b ? -1 : 1;
+ }
+ });
+
+ htmlInput.oninput = function () {
+ var value = htmlInput.value, index = htmlInput.selectionEnd;
+ if (index == null) index = value.length;
+ value = value.substring(0, index);
+ // cal prefix
+ awesomplete.prefix = "";
+ for (var i = index - 1; i>=0; i--) {
+ var c = value.charAt(i);
+ if (!/^[a-zA-Z0-9_\u4E00-\u9FCC]$/.test(c)) {
+ awesomplete.prefix = value.substring(i+1);
+ break;
+ }
+ }
+
+ var list = editor_blockly.getAutoCompletions(value);
+ if (pb.type == "idString_3_e") {
+ list = list.concat(Object.keys(core.material.enemys).filter(function (one) {
+ return one != value && one.startsWith(value);
+ }));
+ list.sort();
+ }
+
+ awesomplete.list = list;
+ awesomplete.ul.style.marginLeft = getCaretCoordinates(htmlInput, htmlInput.selectionStart).left -
+ htmlInput.scrollLeft - 20 + "px";
+ awesomplete.evaluate();
+ }
+
+ awesomplete.container.style.width = "100%";
+
+ window.awesomplete = awesomplete;
+ }
+
+ if (!quietInput) {
+ htmlInput.focus();
+ htmlInput.select();
+ }
+ this.validate_();
+ this.resizeEditor_();
+
+ this.bindEvents_(htmlInput);
+};
\ No newline at end of file
diff --git a/_server/editor_config.js b/_server/editor_config.js
new file mode 100644
index 00000000..016b316c
--- /dev/null
+++ b/_server/editor_config.js
@@ -0,0 +1,34 @@
+function editor_config() {
+ this.address = "_server/config.json";
+}
+
+editor_config.prototype.load = function(callback) {
+ var _this = this;
+ fs.readFile(this.address, "utf-8", function(e, d) {
+ if (e) {
+ console.warn("无法读取配置文件, 已重新生成");
+ _this.config = {};
+ _this.save(callback);
+ } else {
+ _this.config = JSON.parse(d);
+ if (callback) callback();
+ }
+ });
+}
+
+editor_config.prototype.get = function(key, defaultValue) {
+ value = this.config[key];
+ return value != null ? value : defaultValue;
+}
+
+editor_config.prototype.set = function(key, value, callback) {
+ this.config[key] = value;
+ if (callback !== false) this.save(callback);
+}
+
+editor_config.prototype.save = function(callback) {
+ fs.writeFile(this.address, JSON.stringify(this.config) ,'utf-8', function(e) {
+ if (e) alert("写入配置文件失败");
+ if (callback instanceof Function) callback();
+ })
+}
diff --git a/_server/editor_datapanel.js b/_server/editor_datapanel.js
new file mode 100644
index 00000000..948ce9c0
--- /dev/null
+++ b/_server/editor_datapanel.js
@@ -0,0 +1,809 @@
+editor_datapanel_wrapper = function (editor) {
+
+ // 此文件内的内容仅做了分类, 未仔细整理函数
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 地图编辑 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+ editor.uifunctions.newMap_func = function () {
+
+ var newMap = document.getElementById('newMap');
+ var newFileName = document.getElementById('newFileName');
+ newMap.onclick = function () {
+ if (!newFileName.value) return;
+ if (core.floorIds.indexOf(newFileName.value) >= 0) {
+ printe("该楼层已存在!");
+ return;
+ }
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(newFileName.value)) {
+ printe("楼层名不合法!请使用字母、数字、下划线,且不能以数字开头!");
+ return;
+ }
+ var width = parseInt(document.getElementById('newMapWidth').value);
+ var height = parseInt(document.getElementById('newMapHeight').value);
+ if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width * height > 1000) {
+ printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且宽高之积不能超过1000");
+ return;
+ }
+
+ editor_mode.onmode('');
+ editor.file.saveNewFile(newFileName.value, function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ core.floorIds.push(newFileName.value);
+ editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_);
+ if (objs_.slice(-1)[0] != null) {
+ printe(objs_.slice(-1)[0]);
+ throw (objs_.slice(-1)[0])
+ }
+ ; printe('新建成功,请F5刷新编辑器生效');
+ });
+ });
+ }
+
+ }
+
+
+ editor.uifunctions.createNewMaps_func = function () {
+ var newMaps = document.getElementById('newMaps');
+ var newFloors = document.getElementById('newFloors');
+ newMaps.onclick = function () {
+ if (newFloors.style.display == 'none') newFloors.style.display = 'block';
+ else newFloors.style.display = 'none';
+ }
+
+ var createNewMaps = document.getElementById('createNewMaps');
+ createNewMaps.onclick = function () {
+ var floorIds = document.getElementById('newFloorIds').value;
+ if (!floorIds) return;
+ var from = parseInt(document.getElementById('newMapsFrom').value),
+ to = parseInt(document.getElementById('newMapsTo').value);
+ if (!core.isset(from) || !core.isset(to) || from > to || from < 0 || to < 0) {
+ printe("请输入有效的起始和终止楼层");
+ return;
+ }
+ if (to - from >= 100) {
+ printe("一次最多创建99个楼层");
+ return;
+ }
+ var floorIdList = [];
+ for (var i = from; i <= to; i++) {
+ var floorId = floorIds.replace(/\${(.*?)}/g, function (word, value) {
+ return eval(value);
+ });
+ if (core.floorIds.indexOf(floorId) >= 0) {
+ printe("要创建的楼层 " + floorId + " 已存在!");
+ return;
+ }
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(floorId)) {
+ printe("楼层名 " + floorId + " 不合法!请使用字母、数字、下划线,且不能以数字开头!");
+ return;
+ }
+ if (floorIdList.indexOf(floorId) >= 0) {
+ printe("尝试重复创建楼层 " + floorId + " !");
+ return;
+ }
+ floorIdList.push(floorId);
+ }
+
+ var width = parseInt(document.getElementById('newMapsWidth').value);
+ var height = parseInt(document.getElementById('newMapsHeight').value);
+ if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width * height > 1000) {
+ printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且宽高之积不能超过1000");
+ return;
+ }
+ editor_mode.onmode('');
+
+ editor.file.saveNewFiles(floorIdList, from, to, function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ core.floorIds = core.floorIds.concat(floorIdList);
+ editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_);
+ if (objs_.slice(-1)[0] != null) {
+ printe(objs_.slice(-1)[0]);
+ throw (objs_.slice(-1)[0])
+ }
+ ; printe('批量创建 ' + floorIdList[0] + '~' + floorIdList[floorIdList.length - 1] + ' 成功,请F5刷新编辑器生效');
+ });
+ });
+ }
+
+ }
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 地图选点 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+ // 添加自动事件页,无需双击
+ editor.uifunctions.addAutoEvent = function () {
+ if (editor_mode.mode != 'loc') return false;
+ var newid = '2';
+ var ae = editor.currentFloorData.autoEvent[editor_mode.pos.x + ',' + editor_mode.pos.y];
+ if (ae != null) {
+ var testid;
+ for (testid = 2; Object.hasOwnProperty.call(ae, testid); testid++);
+ newid = testid + '';
+ }
+ editor_mode.addAction(['add', "['autoEvent']['" + newid + "']", null]);
+ editor_mode.onmode('save');
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 图块属性 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+ editor.uifunctions.newIdIdnum_func = function () {
+ var newIdIdnum = document.getElementById('newIdIdnum');
+ newIdIdnum.children[2].onclick = function () {
+ if (newIdIdnum.children[0].value && newIdIdnum.children[1].value) {
+ var id = newIdIdnum.children[0].value;
+ var idnum = parseInt(newIdIdnum.children[1].value);
+ if (!core.isset(idnum)) {
+ printe('不合法的idnum');
+ return;
+ }
+ if (!/^[0-9a-zA-Z_]+$/.test(id)) {
+ printe('不合法的id,请使用字母、数字或下划线')
+ return;
+ }
+ editor.file.changeIdAndIdnum(id, idnum, editor_mode.info, function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ printe('添加id和idnum成功,请F5刷新编辑器');
+ });
+ } else {
+ printe('请输入id和idnum');
+ }
+ }
+ newIdIdnum.children[4].onclick = function () {
+ editor.file.autoRegister(editor_mode.info, function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ printe('该列所有剩余项全部自动注册成功,请F5刷新编辑器');
+ })
+ }
+ }
+
+ editor.uifunctions.changeId_func = function () {
+ var changeId = document.getElementById('changeId');
+ changeId.children[1].onclick = function () {
+ var id = changeId.children[0].value;
+ if (id) {
+ if (!/^[0-9a-zA-Z_]+$/.test(id)) {
+ printe('不合法的id,请使用字母、数字或下划线')
+ return;
+ }
+ editor.file.changeIdAndIdnum(id, null, editor_mode.info, function (err) {
+ if (err) {
+ printe(err);
+ throw (err);
+ }
+ printe('修改id成功,请F5刷新编辑器');
+ });
+ } else {
+ printe('请输入要修改到的ID');
+ }
+ }
+ }
+
+ editor.uifunctions.copyPasteEnemyItem_func = function () {
+ var copyEnemyItem = document.getElementById('copyEnemyItem');
+ var pasteEnemyItem = document.getElementById('pasteEnemyItem');
+
+ copyEnemyItem.onclick = function () {
+ var cls = (editor_mode.info || {}).images;
+ if (editor_mode.mode != 'enemyitem' || (cls != 'enemys' && cls != 'enemy48' && cls != 'items')) return;
+ editor.uivalues.copyEnemyItem.type = cls;
+ var id = editor_mode.info.id;
+ if (cls == 'enemys' || cls == 'enemy48') {
+ editor.uivalues.copyEnemyItem.data = core.clone(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80[id]);
+ printf("怪物属性复制成功");
+ } else {
+ editor.uivalues.copyEnemyItem.data = {};
+ for (var x in items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a) {
+ if (items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a[x][id] != null) {
+ editor.uivalues.copyEnemyItem.data[x] = core.clone(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a[x][id]);
+ }
+ }
+ printf("道具属性复制成功");
+ }
+ }
+
+ pasteEnemyItem.onclick = function () {
+ var cls = (editor_mode.info || {}).images;
+ if (editor_mode.mode != 'enemyitem' || !cls || cls != editor.uivalues.copyEnemyItem.type) return;
+ var id = editor_mode.info.id;
+ if (cls == 'enemys' || cls == 'enemy48') {
+ if (confirm("你确定要覆盖此怪物的全部属性么?这是个不可逆操作!")) {
+ enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80[id] = core.clone(editor.uivalues.copyEnemyItem.data);
+ editor.file.saveSetting('enemys', [], function (err) {
+ if (err) printe(err);
+ else printf("怪物属性粘贴成功\n请再重新选中该怪物方可查看更新后的表格。");
+ })
+ }
+ } else {
+ if (confirm("你确定要覆盖此道具的全部属性么?这是个不可逆操作!")) {
+ for (var x in editor.uivalues.copyEnemyItem.data) {
+ items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a[x][id] = core.clone(editor.uivalues.copyEnemyItem.data[x]);
+ }
+ editor.file.saveSetting('items', [], function (err) {
+ if (err) printe(err);
+ else printf("道具属性粘贴成功\n请再重新选中该道具方可查看更新后的表格。");
+ })
+ }
+ }
+
+ }
+
+
+ }
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 楼层属性 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+ editor.uifunctions.changeFloorId_func = function () {
+
+ editor.dom.changeFloorId.children[1].onclick = function () {
+ var floorId = editor.dom.changeFloorId.children[0].value;
+ if (floorId) {
+ if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(floorId)) {
+ printe("楼层名 " + floorId + " 不合法!请使用字母、数字、下划线,且不能以数字开头!");
+ return;
+ }
+ if (main.floorIds.indexOf(floorId) >= 0) {
+ printe("楼层名 " + floorId + " 已存在!");
+ return;
+ }
+ var currentFloorId = editor.currentFloorId;
+ editor.currentFloorId = floorId;
+ editor.currentFloorData.floorId = floorId;
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err);
+ }
+ core.floorIds[core.floorIds.indexOf(currentFloorId)] = floorId;
+ editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_);
+ if (objs_.slice(-1)[0] != null) {
+ printe(objs_.slice(-1)[0]);
+ throw (objs_.slice(-1)[0])
+ }
+ alert("修改floorId成功,需要刷新编辑器生效。\n请注意,原始的楼层文件没有删除,请根据需要手动删除。");
+ window.location.reload();
+ });
+ });
+ } else {
+ printe('请输入要修改到的floorId');
+ }
+ }
+ }
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 全塔属性 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 脚本编辑 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 追加素材 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+
+ editor.uifunctions.fixCtx_func = function () {
+ [editor.dom.sourceCtx, editor.dom.spriteCtx].forEach(function (ctx) {
+ ctx.mozImageSmoothingEnabled = false;
+ ctx.webkitImageSmoothingEnabled = false;
+ ctx.msImageSmoothingEnabled = false;
+ ctx.imageSmoothingEnabled = false;
+ })
+ }
+
+ editor.uifunctions.selectAppend_func = function () {
+
+ var selectAppend_str = [];
+ ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"].forEach(function (image) {
+ selectAppend_str.push(["\n'].join(''));
+ });
+ editor.dom.selectAppend.innerHTML = selectAppend_str.join('');
+ editor.dom.selectAppend.onchange = function () {
+
+ var value = editor.dom.selectAppend.value;
+
+ if (value == 'autotile') {
+ editor_mode.appendPic.imageName = 'autotile';
+ for (var jj = 0; jj < 4; jj++) editor.dom.appendPicSelection.children[jj].style = 'display:none';
+ if (editor_mode.appendPic.img) {
+ editor.dom.sprite.style.width = (editor.dom.sprite.width = editor_mode.appendPic.img.width) / editor.uivalues.ratio + 'px';
+ editor.dom.sprite.style.height = (editor.dom.sprite.height = editor_mode.appendPic.img.height) / editor.uivalues.ratio + 'px';
+ editor.dom.spriteCtx.clearRect(0, 0, editor.dom.sprite.width, editor.dom.sprite.height);
+ editor.dom.spriteCtx.drawImage(editor_mode.appendPic.img, 0, 0);
+ }
+ return;
+ }
+
+ var ysize = editor.dom.selectAppend.value.endsWith('48') ? 48 : 32;
+ editor_mode.appendPic.imageName = value;
+ var img = core.material.images[value];
+ editor_mode.appendPic.toImg = img;
+ var num = ~~img.width / 32;
+ editor_mode.appendPic.num = num;
+ editor_mode.appendPic.index = 0;
+ var selectStr = '';
+ for (var ii = 0; ii < num; ii++) {
+ editor.dom.appendPicSelection.children[ii].style = 'left:0;top:0;height:' + (ysize - 6) + 'px';
+ selectStr += '{"x":0,"y":0},'
+ }
+ editor_mode.appendPic.selectPos = eval('[' + selectStr + ']');
+ for (var jj = num; jj < 4; jj++) {
+ editor.dom.appendPicSelection.children[jj].style = 'display:none';
+ }
+ editor.dom.sprite.style.width = (editor.dom.sprite.width = img.width) / editor.uivalues.ratio + 'px';
+ editor.dom.sprite.style.height = (editor.dom.sprite.height = img.height + ysize) / editor.uivalues.ratio + 'px';
+ editor.dom.spriteCtx.drawImage(img, 0, 0);
+ }
+ editor.dom.selectAppend.onchange();
+ }
+
+ editor.uifunctions.selectFileBtn_func = function () {
+
+ var autoAdjust = function (image, callback) {
+ var changed = false;
+
+ // Step 1: 检测白底
+ var tempCanvas = document.createElement('canvas').getContext('2d');
+ tempCanvas.canvas.width = image.width;
+ tempCanvas.canvas.height = image.height;
+ tempCanvas.mozImageSmoothingEnabled = false;
+ tempCanvas.webkitImageSmoothingEnabled = false;
+ tempCanvas.msImageSmoothingEnabled = false;
+ tempCanvas.imageSmoothingEnabled = false;
+ tempCanvas.drawImage(image, 0, 0);
+ var imgData = tempCanvas.getImageData(0, 0, image.width, image.height);
+ var trans = 0, white = 0, black = 0;
+ for (var i = 0; i < image.width; i++) {
+ for (var j = 0; j < image.height; j++) {
+ var pixel = editor.util.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 (white > black && white > trans * 10 && confirm("看起来这张图片是以纯白为底色,是否自动调整为透明底色?")) {
+ for (var i = 0; i < image.width; i++) {
+ for (var j = 0; j < image.height; j++) {
+ var pixel = editor.util.getPixel(imgData, i, j);
+ if (pixel[0] == 255 && pixel[1] == 255 && pixel[2] == 255 && pixel[3] == 255) {
+ editor.util.setPixel(imgData, i, j, [0, 0, 0, 0]);
+ }
+ }
+ }
+ tempCanvas.clearRect(0, 0, image.width, image.height);
+ tempCanvas.putImageData(imgData, 0, 0);
+ changed = true;
+ }
+ /*
+ if (black>white && black>trans*10 && confirm("看起来这张图片是以纯黑为底色,是否自动调整为透明底色?")) {
+ for (var i=0;i= num) editor_mode.appendPic.index = ii + 1 - num;
+ else editor_mode.appendPic.index++;
+ editor_mode.appendPic.selectPos[ii] = pos;
+ editor.dom.appendPicSelection.children[ii].style = [
+ 'left:', pos.x * 32, 'px;',
+ 'top:', pos.y * pos.ysize, 'px;',
+ 'height:', pos.ysize - 6, 'px;'
+ ].join('');
+ }
+ }
+
+ editor.uifunctions.appendConfirm_func = function () {
+
+ var appendRegister = document.getElementById('appendRegister');
+
+ var appendConfirm = document.getElementById('appendConfirm');
+ appendConfirm.onclick = function () {
+
+ var confirmAutotile = function () {
+ var image = editor_mode.appendPic.img;
+ if (image.width % 96 != 0 || image.height != 128) {
+ printe("不合法的Autotile图片!");
+ return;
+ }
+ var imgData = editor.dom.sourceCtx.getImageData(0, 0, image.width, image.height);
+ editor.dom.spriteCtx.putImageData(imgData, 0, 0);
+ var imgbase64 = editor.dom.sprite.toDataURL().split(',')[1];
+
+ // Step 1: List文件名
+ fs.readdir('./project/images', function (err, data) {
+ if (err) {
+ printe(err);
+ throw (err);
+ }
+
+ // Step 2: 选择Autotile文件名
+ var filename;
+ for (var i = 1; ; ++i) {
+ filename = 'autotile' + i;
+ if (data.indexOf(filename + ".png") == -1) break;
+ }
+
+ // Step 3: 写入文件
+ fs.writeFile('./project/images/' + filename + ".png", imgbase64, 'base64', function (err, data) {
+ if (err) {
+ printe(err);
+ throw (err);
+ }
+ // Step 4: 自动注册
+ editor.file.registerAutotile(filename, function (err) {
+ if (err) {
+ printe(err);
+ throw (err);
+ }
+ printe('自动元件' + filename + '注册成功,请F5刷新编辑器');
+ })
+
+ })
+
+ })
+
+ }
+
+ if (editor.dom.selectAppend.value == 'autotile') {
+ confirmAutotile();
+ return;
+ }
+
+ var ysize = editor.dom.selectAppend.value.endsWith('48') ? 48 : 32;
+ for (var ii = 0, v; v = editor_mode.appendPic.selectPos[ii]; ii++) {
+ // var imgData = editor.dom.sourceCtx.getImageData(v.x * 32, v.y * ysize, 32, ysize);
+ // editor.dom.spriteCtx.putImageData(imgData, ii * 32, editor.dom.sprite.height - ysize);
+ // editor.dom.spriteCtx.drawImage(editor_mode.appendPic.img, v.x * 32, v.y * ysize, 32, ysize, ii * 32, height, 32, ysize)
+
+ editor.dom.spriteCtx.drawImage(editor.dom.sourceCtx.canvas, v.x * 32, v.y * ysize, 32, ysize, 32 * ii, editor.dom.sprite.height - ysize, 32, ysize);
+ }
+ var dt = editor.dom.spriteCtx.getImageData(0, 0, editor.dom.sprite.width, editor.dom.sprite.height);
+ var imgbase64 = editor.dom.sprite.toDataURL('image/png');
+ var imgName = editor_mode.appendPic.imageName;
+ fs.writeFile('./project/images/' + imgName + '.png', imgbase64.split(',')[1], 'base64', function (err, data) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ var currHeight = editor.dom.sprite.height;
+ editor.dom.sprite.style.height = (editor.dom.sprite.height = (currHeight + ysize)) + "px";
+ editor.dom.spriteCtx.putImageData(dt, 0, 0);
+ core.material.images[imgName].src = imgbase64;
+ editor.widthsX[imgName][3] = currHeight;
+ if (appendRegister && appendRegister.checked) {
+ editor.file.autoRegister({images: imgName}, function (e) {
+ if (e) {
+ printe(e);
+ throw e;
+ }
+ printf('追加素材并自动注册成功!你可以继续追加其他素材,最后再刷新以使用。');
+ });
+ } else {
+ printf('追加素材成功!你可以继续追加其他素材,最后再刷新以使用。');
+ }
+ });
+ }
+
+ var quickAppendConfirm = document.getElementById('quickAppendConfirm');
+ quickAppendConfirm.onclick = function () {
+ var value = editor.dom.selectAppend.value;
+ if (value != 'enemys' && value != 'enemy48' && value != 'npcs' && value != 'npc48')
+ return printe("只有怪物或NPC才能快速导入!");
+ var ysize = value.endsWith('48') ? 48 : 32;
+ if (editor.dom.sourceCtx.canvas.width != 128 || editor.dom.sourceCtx.canvas.height != 4 * ysize)
+ return printe("只有 4*4 的素材图片才可以快速导入!");
+
+ var dt = editor.dom.spriteCtx.getImageData(0, 0, editor.dom.sprite.width, editor.dom.sprite.height);
+ editor.dom.sprite.style.height = (editor.dom.sprite.height = (editor.dom.sprite.height + 3 * ysize)) + "px";
+ editor.dom.spriteCtx.putImageData(dt, 0, 0);
+ if (editor.dom.sprite.width == 64) { // 两帧
+ editor.dom.spriteCtx.drawImage(editor.dom.sourceCtx.canvas, 32, 0, 64, 4 * ysize, 0, editor.dom.sprite.height - 4 * ysize, 64, 4 * ysize);
+ } else { // 四帧
+ editor.dom.spriteCtx.drawImage(editor.dom.sourceCtx.canvas, 0, 0, 128, 4 * ysize, 0, editor.dom.sprite.height - 4 * ysize, 128, 4 * ysize);
+ }
+
+ dt = editor.dom.spriteCtx.getImageData(0, 0, editor.dom.sprite.width, editor.dom.sprite.height);
+ var imgbase64 = editor.dom.sprite.toDataURL('image/png');
+ var imgName = editor_mode.appendPic.imageName;
+ fs.writeFile('./project/images/' + imgName + '.png', imgbase64.split(',')[1], 'base64', function (err, data) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ var currHeight = editor.dom.sprite.height;
+ editor.dom.sprite.style.height = (editor.dom.sprite.height = (currHeight + ysize)) + "px";
+ editor.dom.spriteCtx.putImageData(dt, 0, 0);
+ core.material.images[imgName].src = imgbase64;
+ editor.widthsX[imgName][3] = currHeight;
+ if (appendRegister && appendRegister.checked) {
+ editor.file.autoRegister({images: imgName}, function (e) {
+ if (e) {
+ printe(e);
+ throw e;
+ }
+ printf('快速追加素材并自动注册成功!你可以继续追加其他素材,最后再刷新以使用。');
+ })
+ } else {
+ printf('快速追加素材成功!你可以继续追加其他素材,最后再刷新以使用。');
+ }
+ });
+
+ }
+ }
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 公共事件 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ///////////////////////////////////////////////////////////////////////
+ //////////////////// 插件编写 //////////////////////////////////////////
+ ///////////////////////////////////////////////////////////////////////
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/_server/editor_file.js b/_server/editor_file.js
index 1a8a9fa0..f737f910 100644
--- a/_server/editor_file.js
+++ b/_server/editor_file.js
@@ -1,827 +1,65 @@
-editor_file = function (editor, callback) {
-
- var editor_file = {};
-
-
- var commentjs = {
- 'comment': 'comment',
- 'data.comment': 'dataComment',
- 'functions.comment': 'functionsComment',
- 'events.comment': 'eventsComment',
- 'plugins.comment': 'pluginsComment',
- }
- for (var key in commentjs) {
- (function (key) {
- var value = commentjs[key];
- var script = document.createElement('script');
- if (window.location.href.indexOf('_server') !== -1)
- script.src = key + '.js';
- else
- script.src = '_server/table/' + key + '.js';
- document.body.appendChild(script);
- script.onload = function () {
- editor_file[value] = eval(key.replace('.', '_') + '_c456ea59_6018_45ef_8bcc_211a24c627dc');
- var loaded = Boolean(callback);
- for (var key_ in commentjs) {
- loaded = loaded && editor_file[commentjs[key_]]
- }
- if (loaded) callback();
- }
- })(key);
+editor_file_wrapper = function (editor) {
+ editor_file_proto = function () {
+ /**
+ * 以
+ * {
+ * "floor.MT1":,
+ * "plugins":
+ * }
+ * 的形式记录所有更改过的文件,save时写入
+ * 的内容暂时还没想好
+ */
+ this.fileMark = {}
}
-
- editor_file.getFloorFileList = function (callback) {
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
+ // 这个函数之后挪到editor.table?
+ editor_file_proto.prototype.loadCommentjs = function (callback) {
+ var commentjs = {
+ 'comment': 'comment',
+ 'data.comment': 'dataComment',
+ 'functions.comment': 'functionsComment',
+ 'events.comment': 'eventsComment',
+ 'plugins.comment': 'pluginsComment',
}
- ;
- /* var fs = editor.fs;
- fs.readdir('project/floors',function(err, data){
- callback([data,err]);
- }); */
- callback([editor.core.floorIds, null]);
- }
- //callback([Array,err:String])
- editor_file.loadFloorFile = function (filename, callback) {
- //filename不含'/'不含'.js'
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
-
- editor.currentFloorId = editor.core.status.floorId;
- editor.currentFloorData = editor.core.floors[editor.currentFloorId];
- }
- //callback(err:String)
- editor_file.saveFloorFile = function (callback) {
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- /* if (!isset(editor.currentFloorId) || !isset(editor.currentFloorData)) {
- callback('未选中文件或无数据');
- } */
- var filename = 'project/floors/' + editor.currentFloorId + '.js';
- var datastr = ['main.floors.', editor.currentFloorId, '=\n'];
- if (editor.currentFloorData.map == 'new') {
- /*
- editor.currentFloorData.map = editor.map.map(function (v) {
- return v.map(function () {
- return 0
- })
- });
- */
- var width = parseInt(document.getElementById('newMapWidth').value);
- var height = parseInt(document.getElementById('newMapHeight').value);
- var row = [];
- for (var i=0;i0)
- saveSetting('icons', iconActions, tempcallback);
- else tempcallback(null);
-
- saveSetting('maps', mapActions, tempcallback);
-
- if (image=='items')
- saveSetting('items', templateActions, tempcallback);
- else if (image.indexOf('enemy')==0)
- saveSetting('enemys', templateActions, tempcallback);
- else tempcallback(null);
- }
-
- editor_file.registerAutotile = function (filename, callback) {
- var idnum = 140;
- while (editor.core.maps.blocksInfo[idnum]) idnum++;
-
- var iconActions = [];
- var mapActions = [];
-
- iconActions.push(["add", "['autotile']['" + filename + "']", 0]);
- mapActions.push(["add", "['" + idnum + "']", {'cls': 'autotile', 'id': filename, 'noPass': true}]);
-
- var templist = [];
- var tempcallback = function (err) {
- templist.push(err);
- if (templist.length == 2) {
- if (templist[0] != null || templist[1] != null)
- callback((templist[0] || '') + '\n' + (templist[1] || ''));
- //这里如果一个成功一个失败会出严重bug
- else
- callback(null);
- }
- }
-
- saveSetting('icons', iconActions, tempcallback);
- saveSetting('maps', mapActions, tempcallback);
- }
-
- editor_file.changeIdAndIdnum = function (id, idnum, info, callback) {
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- //检查maps中是否有重复的idnum或id
- var change = -1;
- for (var ii in editor.core.maps.blocksInfo) {
- if (ii == idnum) {
- //暂时只允许创建新的不允许修改已有的
- //if (info.idnum==idnum){change=ii;break;}//修改id
- callback('idnum重复了');
- return;
- }
- if (editor.core.maps.blocksInfo[ii].id == id) {
- //if (info.id==id){change=ii;break;}//修改idnum
- callback('id重复了');
- return;
- }
- }
- /*
- if (change!=-1 && change!=idnum){//修改idnum
- editor.core.maps.blocksInfo[idnum] = editor.core.maps.blocksInfo[change];
- delete(editor.core.maps.blocksInfo[change]);
- } else if (change==idnum) {//修改id
- var oldid = editor.core.maps.blocksInfo[idnum].id;
- editor.core.maps.blocksInfo[idnum].id = id;
- for(var ii in editor.core.icons.icons){
- if (ii.hasOwnProperty(oldid)){
- ii[id]=ii[oldid];
- delete(ii[oldid]);
- }
- }
- } else {//创建新的
- editor.core.maps.blocksInfo[idnum]={'cls': info.images, 'id':id};
- editor.core.icons.icons[info.images][id]=info.y;
- }
- */
- var templist = [];
- var tempcallback = function (err) {
- templist.push(err);
- if (templist.length == 2) {
- if (templist[0] != null || templist[1] != null)
- callback((templist[0] || '') + '\n' + (templist[1] || ''));
- //这里如果一个成功一个失败会出严重bug
- else
- callback(null);
- }
- }
- saveSetting('maps', [["add", "['" + idnum + "']", {'cls': info.images, 'id': id}]], tempcallback);
- saveSetting('icons', [["add", "['" + info.images + "']['" + id + "']", info.y]], tempcallback);
- if (info.images === 'items') {
- saveSetting('items', [["add", "['items']['" + id + "']", editor_file.comment._data.items_template]], function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- });
- }
- if (info.images === 'enemys' || info.images === 'enemy48') {
- saveSetting('enemys', [["add", "['" + id + "']", editor_file.comment._data.enemys_template]], function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- });
- }
-
- callback(null);
- }
- //callback(err:String)
- editor_file.editItem = function (id, actionList, callback) {
- /*actionList:[
- ["change","['items']['name']","红宝石的新名字"],
- ["add","['items']['新的和name同级的属性']",123],
- ["change","['itemEffectTip']","',攻击力+'+editor.core.values.redJewel"],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- actionList.forEach(function (value) {
- var tempindex = value[1].indexOf(']') + 1;
- value[1] = [value[1].slice(0, tempindex), "['" + id + "']", value[1].slice(tempindex)].join('');
- });
- saveSetting('items', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var locObj_ = {};
- Object.keys(editor_file.comment._data.items._data).forEach(function (v) {
- if (isset(editor.core.items[v][id]) && v !== 'items')
- locObj_[v] = editor.core.items[v][id];
- else
- locObj_[v] = null;
- });
- locObj_['items'] = (function () {
- var locObj = Object.assign({}, editor.core.items.items[id]);
- Object.keys(editor_file.comment._data.items._data.items._data).forEach(function (v) {
- if (!isset(editor.core.items.items[id][v]))
- locObj[v] = null;
- });
- return locObj;
- })();
- return locObj_;
- })(),
- editor_file.comment._data.items,
- null]);
- }
- //只有items.cls是items的才有itemEffect和itemEffectTip,keys和constants和tools只有items
- }
- //callback([obj,commentObj,err:String])
- editor_file.editEnemy = function (id, actionList, callback) {
- /*actionList:[
- ["change","['name']","初级巫师的新名字"],
- ["add","['新的和name同级的属性']",123],
- ["change","['bomb']",null],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- actionList.forEach(function (value) {
- value[1] = "['" + id + "']" + value[1];
- });
- saveSetting('enemys', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var locObj = Object.assign({}, editor.core.enemys.enemys[id]);
- Object.keys(editor_file.comment._data.enemys._data).forEach(function (v) {
- if (!isset(editor.core.enemys.enemys[id][v]))
- /* locObj[v]=editor.core.enemys.enemys[id][v];
- else */
- locObj[v] = null;
- });
- return locObj;
- })(),
- editor_file.comment._data.enemys,
- null]);
+ })(key);
}
}
- //callback([obj,commentObj,err:String])
- editor_file.editMapBlocksInfo = function (idnum, actionList, callback) {
- /*actionList:[
- ["change","['events']",["\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值,可参见样板中初级巫师的写法。"]],
- ["change","['afterBattle']",null],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- var tempmap=[];
- for(var ii=0;ii=editor.core.icons.tilesetStartOffset && !isset(editor.core.maps.blocksInfo[idnum]) && tempmap.indexOf(idnum)===-1){
- actionList.splice(ii,0,["add","['" + idnum + "']",{"cls": "tileset", "id": "X"+idnum, "noPass": true}]);
- tempmap.push(idnum);
- ii++;
- }
- value[1] = "['" + idnum + "']" + value[1];
- }
- saveSetting('maps', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var sourceobj=editor.core.maps.blocksInfo[idnum];
- if(!isset(sourceobj) && idnum>=editor.core.icons.tilesetStartOffset)sourceobj={"cls": "tileset", "id": "X"+idnum, "noPass": true}
- var locObj = Object.assign({}, sourceobj);
- Object.keys(editor_file.comment._data.maps._data).forEach(function (v) {
- if (!isset(sourceobj[v]))
- locObj[v] = null;
- });
- locObj.idnum = idnum;
- return locObj;
- })(),
- editor_file.comment._data.maps,
- null]);
+ editor_file_proto.prototype.alertWhenCompress = function () {
+ if (editor.useCompress === true) {
+ editor.useCompress = 'alerted';
+ setTimeout("alert('当前游戏使用的是压缩文件,修改完成后请使用启动服务.exe->Js代码压缩工具重新压缩,或者把main.js的useCompress改成false来使用原始文件')", 1000)
}
}
- //callback([obj,commentObj,err:String])
- ////////////////////////////////////////////////////////////////////
-
- editor_file.editLoc = function (x, y, actionList, callback) {
- /*actionList:[
- ["change","['events']",["\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值,可参见样板中初级巫师的写法。"]],
- ["change","['afterBattle']",null],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- actionList.forEach(function (value) {
- value[1] = value[1] + "['" + x + "," + y + "']";
- });
- saveSetting('floorloc', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var locObj = {};
- Object.keys(editor_file.comment._data.floors._data.loc._data).forEach(function (v) {
- if (isset(editor.currentFloorData[v][x + ',' + y]))
- locObj[v] = editor.currentFloorData[v][x + ',' + y];
- else
- locObj[v] = null;
- });
- return locObj;
- })(),
- editor_file.comment._data.floors._data.loc,
- null]);
- }
-
- }
- //callback([obj,commentObj,err:String])
-
- ////////////////////////////////////////////////////////////////////
-
- editor_file.editFloor = function (actionList, callback) {
- /*actionList:[
- ["change","['title']",'样板 3 层'],
- ["change","['color']",null],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- saveSetting('floors', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var locObj = Object.assign({}, editor.currentFloorData);
- Object.keys(editor_file.comment._data.floors._data.floor._data).forEach(function (v) {
- if (!isset(editor.currentFloorData[v]))
- /* locObj[v]=editor.currentFloorData[v];
- else */
- locObj[v] = null;
- });
- Object.keys(editor_file.comment._data.floors._data.loc._data).forEach(function (v) {
- delete(locObj[v]);
- });
- delete(locObj.map);
- delete(locObj.bgmap);
- delete(locObj.fgmap);
- return locObj;
- })(),
- editor_file.comment._data.floors._data.floor,
- null]);
- }
- }
- //callback([obj,commentObj,err:String])
-
- ////////////////////////////////////////////////////////////////////
-
- editor_file.editTower = function (actionList, callback) {
- /*actionList:[
- ["change","['firstData']['version']",'Ver 1.0.1 (Beta)'],
- ["change","['values']['lavaDamage']",200],
- ]
- 为[]时只查询不修改
- */
- var data_obj = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- saveSetting('data', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- //var locObj=Object.assign({'main':{}},editor.core.data);
- var locObj = Object.assign({}, data_obj, {'main': {}});
- Object.keys(editor_file.dataComment._data.main._data).forEach(function (v) {
- if (isset(editor.main[v]))
- locObj.main[v] = data_obj.main[v];
- else
- locObj.main[v] = null;
- });
- return locObj;
- })(),
- editor_file.dataComment,
- null]);
- }
- }
- //callback([obj,commentObj,err:String])
-
- ////////////////////////////////////////////////////////////////////
-
- var fmap = {};
- var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a, function (k, v) {
- if (v instanceof Function) {
- var id_ = editor.util.guid();
- fmap[id_] = v.toString();
- return id_;
- } else return v
- }, 4);
- var fobj = JSON.parse(fjson);
- editor_file.functionsMap = fmap;
- editor_file.functionsJSON = fjson;
- var buildlocobj = function (locObj) {
- for (var key in locObj) {
- if (typeof(locObj[key]) !== typeof('')) buildlocobj(locObj[key]);
- else locObj[key] = fmap[locObj[key]];
- }
- };
-
- editor_file.editFunctions = function (actionList, callback) {
- /*actionList:[
- ["change","['events']['afterChangeLight']","function(x,y){console.log(x,y)}"],
- ["change","['ui']['drawAbout']","function(){...}"],
- ]
- 为[]时只查询不修改
- */
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- saveSetting('functions', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- (function () {
- var locObj = JSON.parse(fjson);
- buildlocobj(locObj);
- return locObj;
- })(),
- editor_file.functionsComment,
- null]);
- }
- }
- //callback([obj,commentObj,err:String])
-
- ////////////////////////////////////////////////////////////////////
-
- editor_file.editCommonEvent = function (actionList, callback) {
- /*actionList:[
- ["change","['test']",['123']],
- ]
- 为[]时只查询不修改
- */
- var data_obj = events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent;
- if (!isset(callback)) {
- printe('未设置callback');
- throw('未设置callback')
- }
- ;
- if (isset(actionList) && actionList.length > 0) {
- actionList.forEach(function (value) {
- value[1] = "['commonEvent']" + value[1];
- });
- saveSetting('events', actionList, function (err) {
- callback([err]);
- });
- } else {
- callback([
- Object.assign({},data_obj),
- editor_file.eventsComment._data.commonEvent,
- null]);
- }
- }
- //callback([obj,commentObj,err:String])
-
- ////////////////////////////////////////////////////////////////////
-
- 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([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;
- }
- return true
- }
-
- var formatMap = function (mapArr,trySimplify) {
- if(!mapArr || JSON.stringify(mapArr)==JSON.stringify([]))return '';
- if(trySimplify){
+ editor_file_proto.prototype.formatMap = function (mapArr, trySimplify) {
+ if (!mapArr || JSON.stringify(mapArr) == JSON.stringify([])) return '';
+ if (trySimplify) {
//检查是否是全0二维数组
- var jsoncheck=JSON.stringify(mapArr).replace(/\D/g,'');
- if(jsoncheck==Array(jsoncheck.length+1).join('0'))return '';
+ var jsoncheck = JSON.stringify(mapArr).replace(/\D/g, '');
+ if (jsoncheck == Array(jsoncheck.length + 1).join('0')) return '';
}
//把二维数组格式化
var formatArrStr = '';
var arr = JSON.stringify(mapArr).replace(/\s+/g, '').split('],[');
- var si=mapArr.length-1,sk=mapArr[0].length-1;
+ var si = mapArr.length - 1, sk = mapArr[0].length - 1;
for (var i = 0; i <= si; i++) {
var a = [];
formatArrStr += ' [';
@@ -836,168 +74,75 @@ editor_file = function (editor, callback) {
return formatArrStr;
}
- var encode = editor.util.encode64
+ editor_file_proto.prototype.saveFloor = function (floorData, callback) {
+ //callback(err:String)
+ var floorId = floorData.floorId;
+ var filename = 'project/floors/' + floorId + '.js';
+ var datastr = ['main.floors.', floorId, '=\n'];
- var alertWhenCompress = function(){
- if(editor.useCompress===true){
- editor.useCompress='alerted';
- setTimeout("alert('当前游戏使用的是压缩文件,修改完成后请使用启动服务.exe->Js代码压缩工具重新压缩,或者把main.js的useCompress改成false来使用原始文件')",1000)
- }
+ var tempJsonObj = Object.assign({}, floorData);
+ 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];
+ });
+ var tempJson = JSON.stringify(tempJsonObj, editor.game.replacerForSaving, 4);
+ tempMap.forEach(function (v) {
+ tempJson = tempJson.replace('"' + v[1] + '"', '[\n' + editor.file.formatMap(v[2], v[0] != 'map') + '\n]')
+ });
+ datastr = datastr.concat([tempJson]);
+ datastr = datastr.join('');
+ editor.file.alertWhenCompress();
+ editor.fs.writeFile(filename, editor.util.encode64(datastr), 'base64', function (err, data) {
+ editor.addUsedFlags(datastr);
+ callback(err);
+ });
}
- var saveSetting = function (file, actionList, callback) {
- //console.log(file);
- //console.log(actionList);
- alertWhenCompress();
-
- if (file == 'icons') {
- actionList.forEach(function (value) {
- eval("icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1" + value[1] + '=' + JSON.stringify(value[2]));
- });
- var datastr = 'var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 = \n';
- datastr += JSON.stringify(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1, null, '\t');
- fs.writeFile('project/icons.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'maps') {
- actionList.forEach(function (value) {
- eval("maps_90f36752_8815_4be8_b32b_d7fad1d0542e" + value[1] + '=' + JSON.stringify(value[2]));
- });
- var datastr = 'var maps_90f36752_8815_4be8_b32b_d7fad1d0542e = \n';
- //datastr+=JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e,null,4);
+ editor_file_proto.prototype.saveScript = function (name, varName, dataObj, callback) {
+ // 此处格式化以及写入 project/xxx.js 形式的文件
+ editor.file.alertWhenCompress();
+ if (['maps', 'enemys'].indexOf(name) === -1) {
+ // 全部用\t展开
+ var content = JSON.stringify(dataObj, editor.game.replacerForSaving, '\t');
+ } else {
+ // 只用\t展开第一层
var emap = {};
- var estr = JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e, function (k, v) {
+ var estr = JSON.stringify(dataObj, function (_k, v) {
if (v.id != null) {
var id_ = editor.util.guid();
- emap[id_] = JSON.stringify(v);
+ emap[id_] = JSON.stringify(v, editor.game.replacerForSaving);
return id_;
} else return v
}, '\t');
for (var id_ in emap) {
- estr = estr.replace('"' + id_ + '"', emap[id_])
+ estr = estr.replace('"' + id_ + '"', emap[id_]);
}
- datastr += estr;
+ var content = estr;
+ }
- fs.writeFile('project/maps.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'items') {
- actionList.forEach(function (value) {
- eval("items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a" + value[1] + '=' + JSON.stringify(value[2]));
- });
- var datastr = 'var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = \n';
- datastr += JSON.stringify(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a, null, '\t');
- fs.writeFile('project/items.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'enemys') {
- actionList.forEach(function (value) {
- eval("enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80" + value[1] + '=' + JSON.stringify(value[2]));
- });
- var datastr = 'var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 = \n';
- var emap = {};
- var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80, function (k, v) {
- if (v.hp != null) {
- var id_ = editor.util.guid();
- emap[id_] = JSON.stringify(v);
- return id_;
- } else return v
- }, '\t');
- for (var id_ in emap) {
- estr = estr.replace('"' + id_ + '"', emap[id_])
- }
- datastr += estr;
- fs.writeFile('project/enemys.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'data') {
- actionList.forEach(function (value) {
- eval("data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d" + value[1] + '=' + JSON.stringify(value[2]));
- });
- if (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.floorIds.indexOf(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.floorId) < 0)
- data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.floorId = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.floorIds[0];
- var datastr = 'var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = \n';
- datastr += JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, null, '\t');
- fs.writeFile('project/data.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'functions') {
- actionList.forEach(function (value) {
- eval("fmap[fobj" + value[1] + ']=' + JSON.stringify(value[2]));
- });
- var fraw = fjson;
- for (var id_ in fmap) {
- fraw = fraw.replace('"' + id_ + '"', fmap[id_])
- }
- var datastr = 'var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = \n';
- datastr += fraw;
- fs.writeFile('project/functions.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- return;
- }
- if (file == 'floorloc') {
- actionList.forEach(function (value) {
- // 检测null/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);
- return;
- }
- if (file == 'floors') {
- actionList.forEach(function (value) {
- eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2]));
- });
- editor_file.saveFloorFile(callback);
- return;
- }
- if (file == 'events') {
- actionList.forEach(function (value) {
- eval("events_c12a15a8_c380_4b28_8144_256cba95f760" + value[1] + '=' + JSON.stringify(value[2]));
- });
- var datastr = 'var events_c12a15a8_c380_4b28_8144_256cba95f760 = \n';
- datastr += JSON.stringify(events_c12a15a8_c380_4b28_8144_256cba95f760, null, '\t');
- fs.writeFile('project/events.js', encode(datastr), 'base64', function (err, data) {
- callback(err);
- });
- 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('出错了,要设置的文件名不识别');
+ var strToWrite = `var ${varName} = \n${content}`;
+ editor.fs.writeFile(`project/${name}.js`, editor.util.encode64(strToWrite), 'base64', function (err, data) {
+ callback(err);
+ });
}
- return editor_file;
-}
-//editor_file = editor_file(editor);
\ No newline at end of file
+ editor_file_proto.prototype.saveCommentJs = function () {
+ // 无需格式化的写入, 把multi的那部分略微修改
+ }
+
+ editor_file_proto.prototype.saveImage = function () {
+ // 给追加素材使用
+ }
+
+ editor_file_proto.prototype.addMark = function (name) {
+ // 把name对应的文件在editor.file.fileMark添加标记
+ }
+
+ editor_file_proto.prototype.save = function (callback) {
+ // 根据 editor.file.fileMark 把游戏对象格式化写入文件
+ }
+
+
+}
\ No newline at end of file
diff --git a/_server/editor_file_unsorted.js b/_server/editor_file_unsorted.js
new file mode 100644
index 00000000..7ee709c8
--- /dev/null
+++ b/_server/editor_file_unsorted.js
@@ -0,0 +1,904 @@
+editor_file = function (editor, callback) {
+
+ var editor_file = new editor_file_proto();
+ editor.file=editor_file;
+
+ editor.file.loadCommentjs(callback);
+
+ editor.file.saveFloorFile = function (callback) {
+ //callback(err:String)
+ checkCallback(callback);
+ /* if (!isset(editor.currentFloorId) || !isset(editor.currentFloorData)) {
+ callback('未选中文件或无数据');
+ } */
+ var filename = 'project/floors/' + editor.currentFloorId + '.js';
+ var datastr = ['main.floors.', editor.currentFloorId, '=\n'];
+
+ if (core.floorIds.indexOf(editor.currentFloorId) >= 0) {
+ for(var ii=0,name;name=['map','bgmap','fgmap'][ii];ii++){
+ var mapArray=editor[name].map(function (v) {
+ return v.map(function (v) {
+ return v.idnum || v || 0
+ })
+ });
+ editor.currentFloorData[name]=mapArray;
+ }
+ }
+ editor.file.saveFloor(editor.currentFloorData, callback)
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+
+ editor.file.saveNewFile = function (saveFilename, callback) {
+ //saveAsFilename不含'/'不含'.js'
+ checkCallback(callback);
+ var currData=editor.currentFloorData;
+ var saveStatus = document.getElementById('newMapStatus').checked;
+
+ var title = saveStatus?currData.title:"新建楼层";
+ var name = saveStatus?currData.name:"0";
+ if (/^mt\d+$/i.test(saveFilename)) {
+ name = saveFilename.substring(2);
+ title = "主塔 "+name+" 层";
+ }
+
+ var width = parseInt(document.getElementById('newMapWidth').value);
+ var height = parseInt(document.getElementById('newMapHeight').value);
+ var row = [], map = [];
+ for (var i=0;i0)
+ saveSetting('icons', iconActions, tempcallback);
+ else tempcallback(null);
+
+ saveSetting('maps', mapActions, tempcallback);
+
+ if (image=='items')
+ saveSetting('items', templateActions, tempcallback);
+ else if (image.indexOf('enemy')==0)
+ saveSetting('enemys', templateActions, tempcallback);
+ else tempcallback(null);
+ }
+
+ editor.file.registerAutotile = function (filename, callback) {
+ var idnum = 140;
+ while (editor.core.maps.blocksInfo[idnum]) idnum++;
+
+ var iconActions = [];
+ var mapActions = [];
+
+ iconActions.push(["add", "['autotile']['" + filename + "']", 0]);
+ mapActions.push(["add", "['" + idnum + "']", {'cls': 'autotile', 'id': filename, 'noPass': true}]);
+
+ var templist = [];
+ var tempcallback = function (err) {
+ templist.push(err);
+ if (templist.length == 2) {
+ if (templist[0] != null || templist[1] != null)
+ callback((templist[0] || '') + '\n' + (templist[1] || ''));
+ //这里如果一个成功一个失败会出严重bug
+ else
+ callback(null);
+ }
+ }
+
+ saveSetting('icons', iconActions, tempcallback);
+ saveSetting('maps', mapActions, tempcallback);
+ }
+
+ editor.file.changeIdAndIdnum = function (id, idnum, info, callback) {
+ checkCallback(callback);
+
+ var changeOrNew=core.isset(editor_mode.info.id)?'change':'new'
+ if(changeOrNew=='new'){
+ //检查maps中是否有重复的idnum或id
+ for (var ii in editor.core.maps.blocksInfo) {
+ if (ii == idnum) {
+ callback('idnum重复了');
+ return;
+ }
+ if (editor.core.maps.blocksInfo[ii].id == id) {
+ callback('id重复了');
+ return;
+ }
+ }
+ var templist = [];
+ var tempcallback = function (err) {
+ templist.push(err);
+ if (templist.length == 2) {
+ if (templist[0] != null || templist[1] != null)
+ callback((templist[0] || '') + '\n' + (templist[1] || ''));
+ //这里如果一个成功一个失败会出严重bug
+ else
+ callback(null);
+ }
+ }
+ saveSetting('maps', [["add", "['" + idnum + "']", {'cls': info.images, 'id': id}]], tempcallback);
+ saveSetting('icons', [["add", "['" + info.images + "']['" + id + "']", info.y]], tempcallback);
+ if (info.images === 'items') {
+ saveSetting('items', [["add", "['items']['" + id + "']", editor.file.comment._data.items_template]], function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ });
+ }
+ if (info.images === 'enemys' || info.images === 'enemy48') {
+ saveSetting('enemys', [["add", "['" + id + "']", editor.file.comment._data.enemys_template]], function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ });
+ }
+
+ callback(null);
+
+ }else{
+ //检查maps中是否有重复的idnum或id
+ for (var ii in editor.core.maps.blocksInfo) {
+ if (editor.core.maps.blocksInfo[ii].id == id) {
+ callback('id重复了');
+ return;
+ }
+ }
+ idnum = info.idnum;
+
+ maps_90f36752_8815_4be8_b32b_d7fad1d0542e[idnum].id = id;
+
+ var arr=[icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1,items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a,{enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80:enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80}]
+ arr.forEach(function (obj) {
+ for(var jj in obj){
+ var ii=obj[jj]
+ if (ii.hasOwnProperty(info.id)){
+ ii[id]=ii[info.id];
+ delete(ii[info.id]);
+ }
+ }
+ });
+
+ editor.file.save_icons_maps_items_enemys(callback)
+
+ }
+ }
+ //callback(err:String)
+ editor.file.editItem = function (id, actionList, callback) {
+ /*actionList:[
+ ["change","['items']['name']","红宝石的新名字"],
+ ["add","['items']['新的和name同级的属性']",123],
+ ["change","['itemEffectTip']","',攻击力+'+editor.core.values.redJewel"],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ actionList.forEach(function (value) {
+ var tempindex = value[1].indexOf(']') + 1;
+ value[1] = [value[1].slice(0, tempindex), "['" + id + "']", value[1].slice(tempindex)].join('');
+ });
+ saveSetting('items', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var locObj_ = {};
+ Object.keys(editor.file.comment._data.items._data).forEach(function (v) {
+ if (isset(editor.core.items[v][id]) && v !== 'items')
+ locObj_[v] = editor.core.items[v][id];
+ else
+ locObj_[v] = null;
+ });
+ locObj_['items'] = (function () {
+ var locObj = Object.assign({}, editor.core.items.items[id]);
+ Object.keys(editor.file.comment._data.items._data.items._data).forEach(function (v) {
+ if (!isset(editor.core.items.items[id][v]))
+ locObj[v] = null;
+ });
+ return locObj;
+ })();
+ return locObj_;
+ })(),
+ editor.file.comment._data.items,
+ null]);
+ }
+ //只有items.cls是items的才有itemEffect和itemEffectTip,keys和constants和tools只有items
+ }
+ //callback([obj,commentObj,err:String])
+ editor.file.editEnemy = function (id, actionList, callback) {
+ /*actionList:[
+ ["change","['name']","初级巫师的新名字"],
+ ["add","['新的和name同级的属性']",123],
+ ["change","['bomb']",null],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ actionList.forEach(function (value) {
+ value[1] = "['" + id + "']" + value[1];
+ });
+ saveSetting('enemys', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var locObj = Object.assign({}, editor.core.enemys.enemys[id]);
+ Object.keys(editor.file.comment._data.enemys._data).forEach(function (v) {
+ if (!isset(editor.core.enemys.enemys[id][v]))
+ /* locObj[v]=editor.core.enemys.enemys[id][v];
+ else */
+ locObj[v] = null;
+ });
+ return locObj;
+ })(),
+ editor.file.comment._data.enemys,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ editor.file.editMapBlocksInfo = function (idnum, actionList, callback) {
+ /*actionList:[
+ ["change","['events']",["\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值,可参见样板中初级巫师的写法。"]],
+ ["change","['afterBattle']",null],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ var tempmap=[];
+ for(var ii=0;ii=editor.core.icons.tilesetStartOffset && !isset(editor.core.maps.blocksInfo[idnum]) && tempmap.indexOf(idnum)===-1){
+ actionList.splice(ii,0,["add","['" + idnum + "']",{"cls": "tileset", "id": "X"+idnum, "noPass": true}]);
+ tempmap.push(idnum);
+ ii++;
+ }
+ value[1] = "['" + idnum + "']" + value[1];
+ }
+ saveSetting('maps', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var sourceobj=editor.core.maps.blocksInfo[idnum];
+ if(!isset(sourceobj) && idnum>=editor.core.icons.tilesetStartOffset)sourceobj={"cls": "tileset", "id": "X"+idnum, "noPass": true}
+ var locObj = Object.assign({}, sourceobj);
+ Object.keys(editor.file.comment._data.maps._data).forEach(function (v) {
+ if (!isset(sourceobj[v]))
+ locObj[v] = null;
+ });
+ locObj.idnum = idnum;
+ return locObj;
+ })(),
+ editor.file.comment._data.maps,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ editor.file.editLoc = function (x, y, actionList, callback) {
+ /*actionList:[
+ ["change","['events']",["\t[老人,magician]领域、夹击。\n请注意领域怪需要设置value为伤害数值,可参见样板中初级巫师的写法。"]],
+ ["change","['afterBattle']",null],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ actionList.forEach(function (value) {
+ if(/\['autoEvent'\]\['\d+'\]$/.test(value[1]))value[1]=value[1].replace(/\['\d+'\]$/,function(v){return "['" + x + "," + y + "']"+v})
+ else value[1] = value[1] + "['" + x + "," + y + "']";
+ });
+ saveSetting('floorloc', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var locObj = {};
+ Object.keys(editor.file.comment._data.floors._data.loc._data).forEach(function (v) {
+ if (isset(editor.currentFloorData[v][x + ',' + y]))
+ locObj[v] = editor.currentFloorData[v][x + ',' + y];
+ else
+ locObj[v] = null;
+ });
+ return locObj;
+ })(),
+ editor.file.comment._data.floors._data.loc,
+ null]);
+ }
+
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ editor.file.editFloor = function (actionList, callback) {
+ /*actionList:[
+ ["change","['title']",'样板 3 层'],
+ ["change","['color']",null],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ saveSetting('floors', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var locObj = Object.assign({}, editor.currentFloorData);
+ Object.keys(editor.file.comment._data.floors._data.floor._data).forEach(function (v) {
+ if (!isset(editor.currentFloorData[v]))
+ /* locObj[v]=editor.currentFloorData[v];
+ else */
+ locObj[v] = null;
+ });
+ Object.keys(editor.file.comment._data.floors._data.loc._data).forEach(function (v) {
+ delete(locObj[v]);
+ });
+ delete(locObj.map);
+ delete(locObj.bgmap);
+ delete(locObj.fgmap);
+ return locObj;
+ })(),
+ editor.file.comment._data.floors._data.floor,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ editor.file.editTower = function (actionList, callback) {
+ /*actionList:[
+ ["change","['firstData']['version']",'Ver 1.0.1 (Beta)'],
+ ["change","['values']['lavaDamage']",200],
+ ]
+ 为[]时只查询不修改
+ */
+ var data_obj = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d;
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ saveSetting('data', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ //var locObj=Object.assign({'main':{}},editor.core.data);
+ var locObj = Object.assign({}, data_obj, {'main': {}});
+ Object.keys(editor.file.dataComment._data.main._data).forEach(function (v) {
+ if (isset(editor.main[v]))
+ locObj.main[v] = data_obj.main[v];
+ else
+ locObj.main[v] = null;
+ });
+ return locObj;
+ })(),
+ editor.file.dataComment,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ var fmap = {};
+ var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a, function (k, v) {
+ if (v instanceof Function) {
+ var id_ = editor.util.guid();
+ fmap[id_] = v.toString();
+ return id_;
+ } else return v
+ }, 4);
+ var fobj = JSON.parse(fjson);
+ editor.file.functionsMap = fmap;
+ editor.file.functionsJSON = fjson;
+ var buildlocobj = function (locObj) {
+ for (var key in locObj) {
+ if (typeof(locObj[key]) !== typeof('')) buildlocobj(locObj[key]);
+ else locObj[key] = fmap[locObj[key]];
+ }
+ };
+
+ editor.file.editFunctions = function (actionList, callback) {
+ /*actionList:[
+ ["change","['events']['afterChangeLight']","function(x,y){console.log(x,y)}"],
+ ["change","['ui']['drawAbout']","function(){...}"],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ saveSetting('functions', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ (function () {
+ var locObj = JSON.parse(fjson);
+ buildlocobj(locObj);
+ return locObj;
+ })(),
+ editor.file.functionsComment,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ editor.file.editCommonEvent = function (actionList, callback) {
+ /*actionList:[
+ ["change","['test']",['123']],
+ ]
+ 为[]时只查询不修改
+ */
+ var data_obj = events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent;
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ actionList.forEach(function (value) {
+ value[1] = "['commonEvent']" + value[1];
+ });
+ saveSetting('events', actionList, function (err) {
+ callback([err]);
+ });
+ } else {
+ callback([
+ Object.assign({},data_obj),
+ editor.file.eventsComment._data.commonEvent,
+ null]);
+ }
+ }
+ //callback([obj,commentObj,err:String])
+
+ ////////////////////////////////////////////////////////////////////
+
+ 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)}"],
+ ]
+ 为[]时只查询不修改
+ */
+ checkCallback(callback);
+ if (isset(actionList) && actionList.length > 0) {
+ saveSetting('plugins', actionList, function (err) {
+ callback([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;
+ }
+ return true
+ }
+
+ var checkCallback=function(callback){
+ if (!isset(callback)) {
+ printe('未设置callback');
+ throw('未设置callback')
+ }
+ }
+
+ var encode = editor.util.encode64;
+
+ var alertWhenCompress = function(){
+ if(editor.useCompress===true){
+ editor.useCompress='alerted';
+ setTimeout("alert('当前游戏使用的是压缩文件,修改完成后请使用启动服务.exe->Js代码压缩工具重新压缩,或者把main.js的useCompress改成false来使用原始文件')",1000)
+ }
+ }
+
+ editor.file.save_icons_maps_items_enemys=function(callback){
+ var check=[]
+ saveSetting('icons',[],function(err){
+ if(err){callback(err);return;}
+ check.push('icons')
+ if(check.length==4)callback(null);
+ })
+ saveSetting('maps',[],function(err){
+ if(err){callback(err);return;}
+ check.push('maps')
+ if(check.length==4)callback(null);
+ })
+ saveSetting('items',[],function(err){
+ if(err){callback(err);return;}
+ check.push('items')
+ if(check.length==4)callback(null);
+ })
+ saveSetting('enemys',[],function(err){
+ if(err){callback(err);return;}
+ check.push('enemys')
+ if(check.length==4)callback(null);
+ })
+ }
+
+ var saveSetting = function (file, actionList, callback) {
+ //console.log(file);
+ //console.log(actionList);
+ editor.file.alertWhenCompress();
+
+ if (file == 'icons') {
+ actionList.forEach(function (value) {
+ eval("icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ var datastr = 'var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 = \n';
+ datastr += JSON.stringify(icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1, null, '\t');
+ fs.writeFile('project/icons.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'maps') {
+ actionList.forEach(function (value) {
+ eval("maps_90f36752_8815_4be8_b32b_d7fad1d0542e" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ var datastr = 'var maps_90f36752_8815_4be8_b32b_d7fad1d0542e = \n';
+ //datastr+=JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e,null,4);
+
+ var emap = {};
+ var estr = JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e, function (k, v) {
+ if (v.id != null) {
+ var id_ = editor.util.guid();
+ emap[id_] = JSON.stringify(v);
+ return id_;
+ } else return v
+ }, '\t');
+ for (var id_ in emap) {
+ estr = estr.replace('"' + id_ + '"', emap[id_])
+ }
+ datastr += estr;
+
+ fs.writeFile('project/maps.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'items') {
+ actionList.forEach(function (value) {
+ eval("items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ var datastr = 'var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = \n';
+ datastr += JSON.stringify(items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a, null, '\t');
+ fs.writeFile('project/items.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'enemys') {
+ actionList.forEach(function (value) {
+ eval("enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ var datastr = 'var enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80 = \n';
+ var emap = {};
+ var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80, function (k, v) {
+ if (v.hp != null) {
+ var id_ = editor.util.guid();
+ emap[id_] = JSON.stringify(v);
+ return id_;
+ } else return v
+ }, '\t');
+ for (var id_ in emap) {
+ estr = estr.replace('"' + id_ + '"', emap[id_])
+ }
+ datastr += estr;
+ fs.writeFile('project/enemys.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'data') {
+ actionList.forEach(function (value) {
+ eval("data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ if (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.floorIds.indexOf(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.floorId) < 0)
+ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.floorId = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.floorIds[0];
+ var datastr = 'var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = \n';
+ datastr += JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, null, '\t');
+ fs.writeFile('project/data.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'functions') {
+ actionList.forEach(function (value) {
+ eval("fmap[fobj" + value[1] + ']=' + JSON.stringify(value[2]));
+ });
+ var fraw = fjson;
+ for (var id_ in fmap) {
+ fraw = fraw.replace('"' + id_ + '"', fmap[id_])
+ }
+ var datastr = 'var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = \n';
+ datastr += fraw;
+ fs.writeFile('project/functions.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ return;
+ }
+ if (file == 'floorloc') {
+ actionList.forEach(function (value) {
+ // 检测null/undefined
+ if(/\['autoEvent'\]\['\d+,\d+'\]\['\d+'\]$/.test(value[1])){
+ var tempvalue=value[1].replace(/\['\d+'\]$/,'')
+ tempvalue="editor.currentFloorData" +tempvalue
+ tempvalue=tempvalue+'='+tempvalue+'||{}'
+ eval(tempvalue)
+ }
+ if (value[2]==null && value[0]!=='add')
+ eval("delete editor.currentFloorData" + value[1]);
+ else
+ eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ editor.file.saveFloorFile(callback);
+ return;
+ }
+ if (file == 'floors') {
+ actionList.forEach(function (value) {
+ eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ editor.file.saveFloorFile(callback);
+ return;
+ }
+ if (file == 'events') {
+ actionList.forEach(function (value) {
+ eval("events_c12a15a8_c380_4b28_8144_256cba95f760" + value[1] + '=' + JSON.stringify(value[2]));
+ });
+ var datastr = 'var events_c12a15a8_c380_4b28_8144_256cba95f760 = \n';
+ datastr += JSON.stringify(events_c12a15a8_c380_4b28_8144_256cba95f760, null, '\t');
+ fs.writeFile('project/events.js', encode(datastr), 'base64', function (err, data) {
+ callback(err);
+ });
+ 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('出错了,要设置的文件名不识别');
+ }
+
+ editor.file.saveSetting = saveSetting;
+
+ return editor_file;
+}
+//editor_file = editor_file(editor);
\ No newline at end of file
diff --git a/_server/editor_game.js b/_server/editor_game.js
index efd447bf..4690f17c 100644
--- a/_server/editor_game.js
+++ b/_server/editor_game.js
@@ -1,37 +1,83 @@
editor_game_wrapper = function (editor, main, core) {
+ // 原则上重构后只有此文件允许`\s(main|core)`形式的调用, 以及其初始化 editor_game_wrapper(editor, main, core)
editor_game = function () {
+ this.replacerRecord = {}
+ }
+
+ //////////////////// 修改数据相关 ////////////////////
+ // 三个 replacer 和 replacerRecord 暂时放在此处
+
+ editor_game.prototype.replacerForLoading = function (_key, value) {
+ var rmap = editor.game.replacerRecord;
+ if (value instanceof Function) {
+ var guid_ = editor.util.guid()
+ rmap[guid_] = value.toString()
+ return guid_
+ } else if (value === null) {
+ // 为了包含plugins的新建
+ var guid_ = editor.util.guid()
+ rmap[guid_] = null
+ return guid_
+ }
+ return value
+ }
+
+ editor_game.prototype.replacerForSaving = function (_key, value) {
+ var rmap = editor.game.replacerRecord;
+ if (rmap.hasOwnProperty(value)) {
+ return rmap[value]
+ }
+ return value
+ }
+
+ editor_game.prototype.getValue = function (field) {
+ var rmap = editor.game.replacerRecord;
+ var value = eval(field)
+ if (rmap.hasOwnProperty(oldval)) {
+ return rmap[value]
+ } else {
+ return value
+ }
+ }
+
+ editor_game.prototype.setValue = function (field, value) {
+ var rmap = editor.game.replacerRecord;
+ var oldval = eval(field)
+ if (rmap.hasOwnProperty(oldval)) {
+ rmap[value] = eval(value)
+ } else {
+ eval(field + '=' + value)
+ }
+ }
+
+ editor_game.prototype.replacerWithoutRecord = function (_key, value) {
+ if (value instanceof Function) {
+ return value.toString()
+ } else return value
}
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
- }));
+ var rf = editor.game.replacerWithoutRecord
+ core.floors = JSON.parse(JSON.stringify(core.floors, rf));
+ core.data = JSON.parse(JSON.stringify(core.data, rf));
+ data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = JSON.parse(JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, rf));
}
+ //////////////////// 加载游戏数据相关 ////////////////////
+
+ // 初始化数字与地图图块的对应
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;iiMAX_NUM && v MAX_NUM && v < core.icons.tilesetStartOffset) MAX_NUM = v;
}
- editor.MAX_NUM=MAX_NUM;
+ editor.MAX_NUM = MAX_NUM;
var getInfoById = function (id) {
var block = maps.initBlock(0, 0, id);
if (Object.prototype.hasOwnProperty.call(block, 'event')) {
@@ -46,15 +92,15 @@ editor_game_wrapper = function (editor, main, core) {
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'});
+ 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]});
+ editor.ids.push({ 'idnum': indexId, 'id': id, 'images': allCls[j], 'y': icons[allCls[j]][id] });
point++;
editor.indexs[i].push(point);
}
@@ -62,36 +108,39 @@ editor_game_wrapper = function (editor, main, core) {
}
}
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的整数倍, 请修改后刷新页面');
+ var width = Math.floor(img.width / 32), height = Math.floor(img.height / 32);
+ if (img.width % 32 || img.height % 32) {
+ // alert(imgName + '的长或宽不是32的整数倍, 请修改后刷新页面');
+ console.warn(imgName + '的长或宽不是32的整数倍, 请修改后刷新页面');
}
- if(img.width*img.height > 32*32*3000){
- alert(imgName+'上的图块数量超过了3000,请修改后刷新页面');
+ if (img.width * img.height > 32 * 32 * 3000) {
+ // alert(imgName + '上的图块数量超过了3000,请修改后刷新页面');
+ console.warn(imgName + '上的图块数量超过了3000,请修改后刷新页面');
}
- for (var id=startOffset; id,err:String])
+ editor.util.checkCallback(callback);
+ /* editor.fs.readdir('project/floors',function(err, data){
+ callback([data,err]);
+ }); */
+ callback([editor.core.floorIds, null]);
+ }
+
+ editor_game.prototype.doCoreFunc = function (funcname) {
+ return core[funcname].apply(core, Array.prototype.slice.call(arguments, 1));
+ }
+
+ editor_game.prototype.getEnemy = function (id) {
+ return core.material.enemys[id];
+ }
+
+ editor_game.prototype.getFirstData = function () {
+ return core.firstData;
+ }
editor.constructor.prototype.game = new editor_game();
}
diff --git a/_server/editor_unsorted_3.js b/_server/editor_legacy.js
similarity index 90%
rename from _server/editor_unsorted_3.js
rename to _server/editor_legacy.js
index 170238e9..35e5518d 100644
--- a/_server/editor_unsorted_3.js
+++ b/_server/editor_legacy.js
@@ -1,4 +1,6 @@
-
+// 由于历史遗留原因, 以下变量作为全局变量使用
+// exportMap mapEditArea pout mapEditArea copyMap clearMapButton deleteMap printf printe tip selectBox
+// 除对这些量的功能修改外, 误在此文件中增加新变量或函数
exportMap = document.getElementById('exportMap')
exportMap.isExport=false
exportMap.onclick=function(){
@@ -206,13 +208,21 @@ printf = function (str_, type) {
printe = function (str_) {
printf(str_, 'error')
}
-tip_in_showMode = [
- '涉及图片的更改需要F5刷新浏览器来生效',
- '文本域可以通过双击,在文本编辑器或事件编辑器中编辑',
- '事件编辑器中的显示文本和自定义脚本的方块也可以双击',
- "画出的地图要点击\"保存地图\"才会写入到文件中",
-];
tip=document.getElementById('tip')
+tip.showHelp = function(value) {
+ var tips = [
+ '表格的文本域可以双击进行编辑',
+ '双击地图可以选中素材,右键可以弹出菜单',
+ '双击事件编辑器的图块可以进行长文本编辑/脚本编辑/地图选点/UI绘制预览等操作',
+ 'ESC或点击空白处可以自动保存当前修改',
+ 'H键可以打开操作帮助哦',
+ 'tileset贴图模式可以在地图上拖动来一次绘制一个区域;右键额外素材也可以绑定宽高',
+ '可以拖动地图上的图块和事件,或按Ctrl+C, Ctrl+X和Ctrl+V进行复制,剪切和粘贴,Delete删除',
+ 'Alt+数字键保存图块,数字键读取保存的图块',
+ ];
+ if (value == null) value = Math.floor(Math.random() * tips.length);
+ printf('tips: ' + tips[value])
+}
tip._infos= {}
tip.infos=function(value){
if(value!=null){
@@ -354,7 +364,6 @@ tip.whichShow=function(value){
return tip._whichShow
}
selectBox=document.getElementById('selectBox')
-dataSelection=document.getElementById('dataSelection')
selectBox._isSelected=false
selectBox.isSelected=function(value){
if(value!=null){
@@ -362,8 +371,9 @@ selectBox.isSelected=function(value){
tip.isSelectedBlock(value);
tip.whichShow(0);
clearTimeout(tip.timer);
- dataSelection.style.display=value?'':'none'
+ editor.dom.dataSelection.style.display=value?'':'none'
}
return selectBox._isSelected
}
+// 修改此文件前先看文件开头的说明
\ No newline at end of file
diff --git a/_server/editor_listen.js b/_server/editor_listen.js
new file mode 100644
index 00000000..31825aa5
--- /dev/null
+++ b/_server/editor_listen.js
@@ -0,0 +1,164 @@
+editor_listen_wrapper = function (editor) {
+
+ editor.constructor.prototype.listen = function () {
+
+ editor.dom.body.onmousedown = editor.uifunctions.body_click;
+
+ editor.dom.eui.oncontextmenu = function (e) { e.preventDefault() } // 自定义了右键菜单, 阻止默认行为
+ editor.dom.midMenu.oncontextmenu = function (e) { e.preventDefault() }
+
+ editor.dom.eui.ondblclick = editor.uifunctions.map_doubleClick
+
+ editor.dom.eui.onmousedown = editor.uifunctions.map_ondown
+ editor.dom.eui.onmousemove = editor.uifunctions.map_onmove
+ editor.dom.eui.onmouseup = editor.uifunctions.map_onup
+
+ editor.dom.mid.onmousewheel = editor.uifunctions.map_mousewheel
+
+ editor.uivalues.shortcut = editor.config.get('shortcut', { 48: 0, 49: 0, 50: 0, 51: 0, 52: 0, 53: 0, 54: 0, 55: 0, 56: 0, 57: 0 });
+ editor.dom.body.onkeydown = editor.uifunctions.body_shortcut
+
+ editor.uivalues.scrollBarHeight = editor.uifunctions.getScrollBarHeight();
+ editor.dom.iconExpandBtn.style.display = 'block';
+ editor.dom.iconExpandBtn.innerText = editor.uivalues.folded ? "展开素材区" : "折叠素材区";
+ editor.dom.iconExpandBtn.onclick = editor.uifunctions.fold_material_click
+
+ editor.dom.iconLib.onmousedown = editor.uifunctions.material_ondown
+ editor.dom.iconLib.oncontextmenu = function (e) { e.preventDefault() }
+
+ editor.dom.extraEvent.onmousedown = editor.uifunctions.extraEvent_click
+ editor.dom.chooseThis.onmousedown = editor.uifunctions.chooseThis_click
+ editor.dom.chooseInRight.onmousedown = editor.uifunctions.chooseInRight_click
+ editor.dom.copyLoc.onmousedown = editor.uifunctions.copyLoc_click
+ editor.dom.moveLoc.onmousedown = editor.uifunctions.moveLoc_click
+ editor.dom.clearEvent.onmousedown = editor.uifunctions.clearEvent_click
+ editor.dom.clearLoc.onmousedown = editor.uifunctions.clearLoc_click
+
+ editor.dom.lastUsed.onmousedown = editor.uifunctions.lastUsed_click;
+ editor.dom.lockMode.onchange = editor.uifunctions.lockMode_onchange;
+
+ editor.dom.brushMod.onchange = editor.uifunctions.brushMod_onchange
+ if (editor.dom.brushMod2) editor.dom.brushMod2.onchange = editor.uifunctions.brushMod2_onchange;
+ if (editor.dom.brushMod3) editor.dom.brushMod3.onchange = editor.uifunctions.brushMod3_onchange;
+
+ editor.dom.layerMod.onchange = editor.uifunctions.layerMod_onchange
+ if (editor.dom.layerMod2) editor.dom.layerMod2.onchange = editor.uifunctions.layerMod2_onchange;
+ if (editor.dom.layerMod3) editor.dom.layerMod3.onchange = editor.uifunctions.layerMod3_onchange;
+
+ editor.uifunctions.viewportButtons_func()
+ }
+
+ editor.constructor.prototype.mobile_listen = function () {
+ if (!editor.isMobile) return;
+
+ var mobileview = document.getElementById('mobileview');
+ var mid = document.getElementById('mid');
+ var right = document.getElementById('right');
+ // var mobileeditdata = document.getElementById('mobileeditdata');
+
+
+ editor.showdataarea = function (callShowMode) {
+ mid.style = 'z-index:-1;opacity: 0;';
+ right.style = 'z-index:-1;opacity: 0;';
+ // mobileeditdata.style = '';
+ if (callShowMode) editor.mode.showMode(editor.dom.editModeSelect.value);
+ editor.uifunctions.hideMidMenu();
+ }
+ mobileview.children[0].onclick = function () {
+ editor.showdataarea(true)
+ }
+ mobileview.children[1].onclick = function () {
+ mid.style = '';
+ right.style = 'z-index:-1;opacity: 0;';
+ // mobileeditdata.style = 'z-index:-1;opacity: 0;';
+ editor.lastClickId = '';
+ }
+ mobileview.children[3].onclick = function () {
+ mid.style = 'z-index:-1;opacity: 0;';
+ right.style = '';
+ // mobileeditdata.style = 'z-index:-1;opacity: 0;';
+ editor.lastClickId = '';
+ }
+
+ /*
+ var gettrbyid = function () {
+ if (!editor.lastClickId) return false;
+ thisTr = document.getElementById(editor.lastClickId);
+ input = thisTr.children[2].children[0].children[0];
+ field = thisTr.children[0].getAttribute('title');
+ cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
+ return [thisTr, input, field, cobj];
+ }
+ mobileeditdata.children[0].onclick = function () {
+ var info = gettrbyid()
+ if (!info) return;
+ info[1].ondblclick()
+ }
+ mobileeditdata.children[1].onclick = function () {
+ var info = gettrbyid()
+ if (!info) return;
+ printf(info[2])
+ }
+ mobileeditdata.children[2].onclick = function () {
+ var info = gettrbyid()
+ if (!info) return;
+ printf(info[0].children[1].getAttribute('title'))
+ }
+ */
+
+ //=====
+
+ document.body.ontouchstart = document.body.onmousedown;
+ document.body.onmousedown = null;
+
+ editor.dom.eui.ontouchstart = editor.dom.eui.onmousedown
+ editor.dom.eui.onmousedown = null
+ editor.dom.eui.ontouchmove = editor.dom.eui.onmousemove
+ editor.dom.eui.onmousemove = null
+ editor.dom.eui.ontouchend = editor.dom.eui.onmouseup
+ editor.dom.eui.onmouseup = null
+
+
+ editor.dom.chooseThis.ontouchstart = editor.dom.chooseThis.onmousedown
+ editor.dom.chooseThis.onmousedown = null
+ editor.dom.chooseInRight.ontouchstart = editor.dom.chooseInRight.onmousedown
+ editor.dom.chooseInRight.onmousedown = null
+ editor.dom.copyLoc.ontouchstart = editor.dom.copyLoc.onmousedown
+ editor.dom.copyLoc.onmousedown = null
+ editor.dom.moveLoc.ontouchstart = editor.dom.moveLoc.onmousedown
+ editor.dom.moveLoc.onmousedown = null
+ editor.dom.clearLoc.ontouchstart = editor.dom.clearLoc.onmousedown
+ editor.dom.clearLoc.onmousedown = null
+ }
+
+ editor.constructor.prototype.mode_listen = function (callback) {
+
+ // 这里的函数还没有写jsdoc, 通过_func()的方式先完成分类
+
+ editor.uifunctions.newIdIdnum_func()
+ editor.uifunctions.changeId_func()
+ editor.uifunctions.copyPasteEnemyItem_func();
+
+ editor.uifunctions.selectFloor_func()
+ editor.uifunctions.saveFloor_func()
+
+ editor.uifunctions.newMap_func()
+
+ editor.uifunctions.createNewMaps_func()
+
+ editor.uifunctions.changeFloorId_func()
+
+ editor.uifunctions.fixCtx_func()
+
+ editor.uifunctions.selectAppend_func()
+ editor.uifunctions.selectFileBtn_func()
+ editor.uifunctions.changeColorInput_func()
+ editor.uifunctions.picClick_func()
+ editor.uifunctions.appendConfirm_func()
+
+ editor.dom.editModeSelect.onchange = editor.mode.editModeSelect_onchange
+
+ if (Boolean(callback)) callback();
+ }
+
+}
\ No newline at end of file
diff --git a/_server/editor_mappanel.js b/_server/editor_mappanel.js
new file mode 100644
index 00000000..9068eff9
--- /dev/null
+++ b/_server/editor_mappanel.js
@@ -0,0 +1,898 @@
+editor_mappanel_wrapper = function (editor) {
+
+ // 暂时先 注释+分类 内部函数未完成重构
+
+ /**
+ * 在绘图区格子内画一个随机色块
+ */
+ editor.uifunctions.fillPos = function (pos) {
+ editor.dom.euiCtx.fillStyle = '#' + ~~(Math.random() * 8) + ~~(Math.random() * 8) + ~~(Math.random() * 8);
+ editor.dom.euiCtx.fillRect(pos.x * 32 + 12 - core.bigmap.offsetX, pos.y * 32 + 12 - core.bigmap.offsetY, 8, 8);
+ }
+
+ /**
+ * 从鼠标点击返回可用的组件内坐标
+ */
+ editor.uifunctions.eToLoc = function (e) {
+ var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
+ var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
+ var xx = e.clientX, yy = e.clientY
+ if (editor.isMobile) { xx = e.touches[0].clientX, yy = e.touches[0].clientY }
+ editor.loc = {
+ 'x': scrollLeft + xx - editor.dom.mid.offsetLeft - editor.dom.mapEdit.offsetLeft,
+ 'y': scrollTop + yy - editor.dom.mid.offsetTop - editor.dom.mapEdit.offsetTop,
+ 'size': editor.isMobile ? (32 * innerWidth * 0.96 / core.__PIXELS__) : 32
+ };
+ return editor.loc;
+ }
+
+ /**
+ * 组件内坐标转地图位置
+ * @param {Boolean} addViewportOffset 是否加上大地图的偏置
+ */
+ editor.uifunctions.locToPos = function (loc, addViewportOffset) {
+ var offsetX = 0, offsetY = 0;
+ if (addViewportOffset) {
+ offsetX = core.bigmap.offsetX / 32;
+ offsetY = core.bigmap.offsetY / 32;
+ }
+ editor.pos = { 'x': ~~(loc.x / loc.size) + offsetX, 'y': ~~(loc.y / loc.size) + offsetY }
+ return editor.pos;
+ }
+
+ /**
+ * editor.dom.eui.ondblclick
+ * 双击地图可以选中素材
+ */
+ editor.uifunctions.map_doubleClick = function (e) {
+ if (editor.uivalues.bindSpecialDoor.loc != null) return;
+ var loc = editor.uifunctions.eToLoc(e);
+ var pos = editor.uifunctions.locToPos(loc, true);
+ editor.setSelectBoxFromInfo(editor[editor.layerMod][pos.y][pos.x]);
+ return;
+ }
+
+ /**
+ * 用于鼠标移出map后清除状态
+ */
+ editor.uifunctions.clearMapStepStatus = function () {
+ if (editor.uivalues.mouseOutCheck > 1) {
+ editor.uivalues.mouseOutCheck--;
+ setTimeout(editor.uifunctions.clearMapStepStatus, 1000);
+ return;
+ }
+ editor.uivalues.holdingPath = 0;
+ editor.uivalues.stepPostfix = [];
+ editor.dom.euiCtx.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
+ editor.uivalues.startPos = editor.uivalues.endPos = null;
+ }
+
+ /**
+ * editor.dom.eui.onmousedown
+ * + 绑定机关门事件的选择怪物
+ * + 右键进入菜单
+ * + 非绘图时选中
+ * + 绘图时画个矩形在那个位置
+ */
+ editor.uifunctions.map_ondown = function (e) {
+ var loc = editor.uifunctions.eToLoc(e);
+ var pos = editor.uifunctions.locToPos(loc, true);
+ if (editor.uivalues.bindSpecialDoor.loc != null) {
+ var x = editor.pos.x, y = editor.pos.y, id = (editor.map[y][x] || {}).id;
+ // 检测是否是怪物
+ if (id && editor.game.getEnemy(id)) {
+ var locstr = x + "," + y, index = editor.uivalues.bindSpecialDoor.enemys.indexOf(locstr);
+ if (index >= 0) editor.uivalues.bindSpecialDoor.enemys.splice(index, 1);
+ else editor.uivalues.bindSpecialDoor.enemys.push(locstr);
+ editor.drawEventBlock();
+ editor.uifunctions._extraEvent_bindSpecialDoor_doAction();
+ }
+ return false;
+ }
+ if (e.button == 2) {
+ editor.uifunctions.showMidMenu(e.clientX, e.clientY);
+ return false;
+ }
+ if (!selectBox.isSelected()) {
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('loc');
+ //editor_mode.loc();
+ //tip.whichShow(1);
+ tip.showHelp(6);
+ editor.uivalues.startPos = pos;
+ editor.dom.euiCtx.strokeStyle = '#FF0000';
+ editor.dom.euiCtx.lineWidth = 3;
+ if (editor.isMobile) editor.uifunctions.showMidMenu(e.clientX, e.clientY);
+ return false;
+ }
+
+ editor.uivalues.holdingPath = 1;
+ editor.uivalues.mouseOutCheck = 2;
+ setTimeout(editor.uifunctions.clearMapStepStatus);
+ editor.dom.euiCtx.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
+ editor.uivalues.stepPostfix = [];
+ editor.uivalues.stepPostfix.push(pos);
+ if (editor.brushMod == 'line') editor.uifunctions.fillPos(pos);
+ return false;
+ }
+
+ /**
+ * editor.dom.eui.onmousemove
+ * + 非绘图模式时维护起止位置并画箭头
+ * + 绘图模式时找到与队列尾相邻的鼠标方向的点画个矩形
+ */
+ editor.uifunctions.map_onmove = function (e) {
+ if (!selectBox.isSelected()) {
+ if (editor.uivalues.startPos == null) return;
+ //tip.whichShow(1);
+ var loc = editor.uifunctions.eToLoc(e);
+ var pos = editor.uifunctions.locToPos(loc, true);
+ if (editor.uivalues.endPos != null && editor.uivalues.endPos.x == pos.x && editor.uivalues.endPos.y == pos.y) return;
+ if (editor.uivalues.endPos != null) {
+ editor.dom.euiCtx.clearRect(Math.min(32 * editor.uivalues.startPos.x - core.bigmap.offsetX, 32 * editor.uivalues.endPos.x - core.bigmap.offsetX),
+ Math.min(32 * editor.uivalues.startPos.y - core.bigmap.offsetY, 32 * editor.uivalues.endPos.y - core.bigmap.offsetY),
+ (Math.abs(editor.uivalues.startPos.x - editor.uivalues.endPos.x) + 1) * 32, (Math.abs(editor.uivalues.startPos.y - editor.uivalues.endPos.y) + 1) * 32)
+ }
+ editor.uivalues.endPos = pos;
+ if (editor.uivalues.startPos != null) {
+ if (editor.uivalues.startPos.x != editor.uivalues.endPos.x || editor.uivalues.startPos.y != editor.uivalues.endPos.y) {
+ core.drawArrow('eui',
+ 32 * editor.uivalues.startPos.x + 16 - core.bigmap.offsetX, 32 * editor.uivalues.startPos.y + 16 - core.bigmap.offsetY,
+ 32 * editor.uivalues.endPos.x + 16 - core.bigmap.offsetX, 32 * editor.uivalues.endPos.y + 16 - core.bigmap.offsetY);
+ }
+ }
+ // editor_mode.onmode('nextChange');
+ // editor_mode.onmode('loc');
+ //editor_mode.loc();
+ //tip.whichShow(1);
+ // tip.showHelp(6);
+ return false;
+ }
+
+ if (editor.uivalues.holdingPath == 0) {
+ return false;
+ }
+ editor.uivalues.mouseOutCheck = 2;
+ var loc = editor.uifunctions.eToLoc(e);
+ var pos = editor.uifunctions.locToPos(loc, true);
+ var pos0 = editor.uivalues.stepPostfix[editor.uivalues.stepPostfix.length - 1]
+ var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x]
+ var max = 0, index = 4;
+ for (var i = 0; i < 4; i++) {
+ if (directionDistance[i] > max) {
+ index = i;
+ max = directionDistance[i];
+ }
+ }
+ var pos = [{ 'x': 0, 'y': 1 }, { 'x': -1, 'y': 0 }, { 'x': 0, 'y': -1 }, { 'x': 1, 'y': 0 }, false][index]
+ if (pos) {
+ pos.x += pos0.x;
+ pos.y += pos0.y;
+ if (editor.brushMod == 'line') editor.uifunctions.fillPos(pos);
+ else {
+ var x0 = editor.uivalues.stepPostfix[0].x;
+ var y0 = editor.uivalues.stepPostfix[0].y;
+ var x1 = pos.x;
+ var y1 = pos.y;
+ if (x0 > x1) { x0 ^= x1; x1 ^= x0; x0 ^= x1; }//swap
+ if (y0 > y1) { y0 ^= y1; y1 ^= y0; y0 ^= y1; }//swap
+ // draw rect
+ editor.dom.euiCtx.clearRect(0, 0, editor.dom.euiCtx.canvas.width, editor.dom.euiCtx.canvas.height);
+ editor.dom.euiCtx.fillStyle = 'rgba(0, 127, 255, 0.4)';
+ editor.dom.euiCtx.fillRect(32 * x0 - core.bigmap.offsetX, 32 * y0 - core.bigmap.offsetY,
+ 32 * (x1 - x0) + 32, 32 * (y1 - y0) + 32);
+ }
+ editor.uivalues.stepPostfix.push(pos);
+ }
+ return false;
+ }
+
+ /**
+ * editor.dom.eui.onmouseup
+ * + 非绘图模式时, 交换首末点的内容
+ * + 绘图模式时, 根据画线/画矩形/画tileset 做对应的绘制
+ */
+ editor.uifunctions.map_onup = function (e) {
+ if (!selectBox.isSelected()) {
+ //tip.whichShow(1);
+ // editor.movePos(editor.uivalues.startPos, editor.uivalues.endPos);
+ if (editor.layerMod == 'map')
+ editor.exchangePos(editor.uivalues.startPos, editor.uivalues.endPos);
+ else
+ editor.exchangeBgFg(editor.uivalues.startPos, editor.uivalues.endPos, editor.layerMod);
+ editor.uivalues.startPos = editor.uivalues.endPos = null;
+ editor.dom.euiCtx.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
+ return false;
+ }
+ editor.uivalues.holdingPath = 0;
+ if (editor.uivalues.stepPostfix && editor.uivalues.stepPostfix.length) {
+ editor.savePreMap();
+ if (editor.brushMod !== 'line') {
+ var x0 = editor.uivalues.stepPostfix[0].x;
+ var y0 = editor.uivalues.stepPostfix[0].y;
+ var x1 = editor.uivalues.stepPostfix[editor.uivalues.stepPostfix.length - 1].x;
+ var y1 = editor.uivalues.stepPostfix[editor.uivalues.stepPostfix.length - 1].y;
+ if (x0 > x1) { x0 ^= x1; x1 ^= x0; x0 ^= x1; }//swap
+ if (y0 > y1) { y0 ^= y1; y1 ^= y0; y0 ^= y1; }//swap
+ editor.uivalues.stepPostfix = [];
+ for (var jj = y0; jj <= y1; jj++) {
+ for (var ii = x0; ii <= x1; ii++) {
+ editor.uivalues.stepPostfix.push({ x: ii, y: jj })
+ }
+ }
+ }
+ var useBrushMode = editor.brushMod == 'tileset';
+ if (editor.uivalues.stepPostfix.length == 1 && (editor.uivalues.tileSize[0] > 1 || editor.uivalues.tileSize[1] > 1)) {
+ useBrushMode = true;
+ var x0 = editor.uivalues.stepPostfix[0].x;
+ var y0 = editor.uivalues.stepPostfix[0].y;
+ editor.uivalues.stepPostfix = [];
+ for (var jj = y0; jj < y0 + editor.uivalues.tileSize[1]; ++jj) {
+ for (var ii = x0; ii < x0 + editor.uivalues.tileSize[0]; ++ii) {
+ if (jj >= editor[editor.layerMod].length || ii >= editor[editor.layerMod][0].length) continue;
+ editor.uivalues.stepPostfix.push({ x: ii, y: jj });
+ }
+ }
+ }
+ if (useBrushMode && core.tilesets.indexOf(editor.info.images) !== -1) {
+ var imgWidth = ~~(core.material.images.tilesets[editor.info.images].width / 32);
+ var x0 = editor.uivalues.stepPostfix[0].x;
+ var y0 = editor.uivalues.stepPostfix[0].y;
+ var idnum = editor.info.idnum;
+ for (var ii = 0; ii < editor.uivalues.stepPostfix.length; ii++) {
+ if (editor.uivalues.stepPostfix[ii].y != y0) {
+ y0++;
+ idnum += imgWidth;
+ }
+ editor[editor.layerMod][editor.uivalues.stepPostfix[ii].y][editor.uivalues.stepPostfix[ii].x] = editor.ids[editor.indexs[idnum + editor.uivalues.stepPostfix[ii].x - x0]];
+ }
+ } else {
+ for (var ii = 0; ii < editor.uivalues.stepPostfix.length; ii++)
+ editor[editor.layerMod][editor.uivalues.stepPostfix[ii].y][editor.uivalues.stepPostfix[ii].x] = editor.info;
+ }
+ // console.log(editor.map);
+ if (editor.info.y != null) {
+ editor.uivalues.lastUsed = [editor.info].concat(editor.uivalues.lastUsed.filter(function (e) { return e.id != editor.info.id}));
+ editor.config.set("lastUsed", editor.uivalues.lastUsed);
+ }
+ editor.updateMap();
+ editor.uivalues.holdingPath = 0;
+ editor.uivalues.stepPostfix = [];
+ editor.dom.euiCtx.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
+ }
+ return false;
+ }
+
+ /**
+ * editor.dom.mid.onmousewheel
+ * 在地图编辑区域滚轮切换楼层
+ */
+ editor.uifunctions.map_mousewheel = function (e) {
+ var wheel = function (direct) {
+ var index = editor.core.floorIds.indexOf(editor.currentFloorId);
+ var toId = editor.currentFloorId;
+
+ if (direct > 0 && index < editor.core.floorIds.length - 1)
+ toId = editor.core.floorIds[index + 1];
+ else if (direct < 0 && index > 0)
+ toId = editor.core.floorIds[index - 1];
+ else return;
+
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('floor');
+ editor.dom.selectFloor.value = toId;
+ editor.changeFloor(toId);
+ }
+
+ try {
+ if (e.wheelDelta)
+ wheel(Math.sign(e.wheelDelta))
+ else if (e.detail)
+ wheel(Math.sign(e.detail));
+ }
+ catch (ee) {
+ console.log(ee);
+ }
+ return false;
+ }
+
+ /**
+ * 显示右键菜单
+ */
+ editor.uifunctions.showMidMenu = function (x, y) {
+ editor.uivalues.lastRightButtonPos = JSON.parse(JSON.stringify(
+ [editor.pos, editor.uivalues.lastRightButtonPos[0]]
+ ));
+ // --- copy
+ editor.uivalues.lastCopyedInfo = [editor.copyFromPos(), editor.uivalues.lastCopyedInfo[0]];
+ var locStr = '(' + editor.uivalues.lastRightButtonPos[1].x + ',' + editor.uivalues.lastRightButtonPos[1].y + ')';
+ var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+ var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+
+ // 检测是否是上下楼
+ var thisevent = editor.map[editor.pos.y][editor.pos.x];
+ var extraEvent = editor.dom.extraEvent, parent = extraEvent.parentElement;
+ if (thisevent == 0) {
+ parent.removeChild(extraEvent);
+ parent.appendChild(extraEvent);
+ editor.dom.extraEvent.style.display = 'block';
+ editor.dom.extraEvent.children[0].innerHTML = '绑定出生点为此点';
+ } else if (thisevent.id == 'upFloor') {
+ parent.removeChild(extraEvent);
+ parent.insertBefore(extraEvent, parent.firstChild);
+ editor.dom.extraEvent.style.display = 'block';
+ editor.dom.extraEvent.children[0].innerHTML = '绑定上楼事件';
+ }
+ else if (thisevent.id == 'downFloor') {
+ parent.removeChild(extraEvent);
+ parent.insertBefore(extraEvent, parent.firstChild);
+ editor.dom.extraEvent.style.display = 'block';
+ editor.dom.extraEvent.children[0].innerHTML = '绑定下楼事件';
+ }
+ else if (['leftPortal', 'rightPortal', 'downPortal', 'upPortal'].indexOf(thisevent.id) >= 0) {
+ parent.removeChild(extraEvent);
+ parent.insertBefore(extraEvent, parent.firstChild);
+ editor.dom.extraEvent.style.display = 'block';
+ editor.dom.extraEvent.children[0].innerHTML = '绑定楼传事件';
+ }
+ else if (thisevent.id == 'specialDoor') {
+ parent.removeChild(extraEvent);
+ parent.insertBefore(extraEvent, parent.firstChild);
+ editor.dom.extraEvent.style.display = 'block';
+ editor.dom.extraEvent.children[0].innerHTML = '绑定机关门事件';
+ }
+ else editor.dom.extraEvent.style.display = 'none';
+
+ editor.dom.chooseThis.children[0].innerHTML = '选中此点' + '(' + editor.pos.x + ',' + editor.pos.y + ')'
+ editor.dom.copyLoc.children[0].innerHTML = '复制事件' + locStr + '到此处';
+ editor.dom.moveLoc.children[0].innerHTML = '交换事件' + locStr + '与此事件的位置';
+ editor.dom.midMenu.style = 'top:' + (y + scrollTop) + 'px;left:' + (x + scrollLeft) + 'px;';
+ }
+
+ /**
+ * 隐藏右键菜单
+ */
+ editor.uifunctions.hideMidMenu = function () {
+ if (editor.isMobile) {
+ setTimeout(function () {
+ editor.dom.midMenu.style = 'display:none';
+ }, 200)
+ } else {
+ editor.dom.midMenu.style = 'display:none';
+ }
+ }
+
+ /**
+ * editor.dom.extraEvent.onmousedown
+ * 菜单 附加点操作
+ */
+ editor.uifunctions.extraEvent_click = function (e) {
+ editor.uifunctions.hideMidMenu();
+ e.stopPropagation();
+
+ var thisevent = editor.map[editor.pos.y][editor.pos.x];
+ return editor.uifunctions._extraEvent_bindStartPoint(thisevent)
+ || editor.uifunctions._extraEvent_bindStair(thisevent)
+ || editor.uifunctions._extraEvent_bindSpecialDoor(thisevent);
+ }
+
+ /**
+ * 绑定该空地点为起始点
+ */
+ editor.uifunctions._extraEvent_bindStartPoint = function (thisevent) {
+ if (thisevent != 0) return false;
+ editor.mode.onmode('tower');
+ editor.mode.addAction(["change", "['firstData']['floorId']", editor.currentFloorId]);
+ editor.mode.addAction(["change", "['firstData']['hero']['loc']['x']", editor.pos.x]);
+ editor.mode.addAction(["change", "['firstData']['hero']['loc']['y']", editor.pos.y]);
+ editor.mode.onmode('save', function () {
+ core.firstData.floorId = editor.currentFloorId;
+ core.firstData.hero.loc.x = editor.pos.x;
+ core.firstData.hero.loc.y = editor.pos.y;
+ editor.drawPosSelection();
+ editor.drawEventBlock();
+ editor.mode.tower();
+ printf('绑定初始点成功');
+ });
+ }
+
+ /**
+ * 绑定该楼梯的楼传事件
+ */
+ editor.uifunctions._extraEvent_bindStair = function (thisevent) {
+ if (['upFloor', 'downFloor', 'leftPortal', 'rightPortal', 'upPortal', 'downPortal'].indexOf(thisevent.id) < 0)
+ return false;
+ var loc = editor.pos.x + "," + editor.pos.y;
+ if (thisevent.id == 'upFloor') {
+ editor.currentFloorData.changeFloor[loc] = { "floorId": ":next", "stair": "downFloor" };
+ }
+ else if (thisevent.id == 'downFloor') {
+ editor.currentFloorData.changeFloor[loc] = { "floorId": ":before", "stair": "upFloor" };
+ }
+ else if (thisevent.id == 'leftPortal' || thisevent.id == 'rightPortal') {
+ editor.currentFloorData.changeFloor[loc] = { "floorId": ":next", "stair": ":symmetry_x" }
+ }
+ else if (thisevent.id == 'upPortal' || thisevent.id == 'downPortal') {
+ editor.currentFloorData.changeFloor[loc] = { "floorId": ":next", "stair": ":symmetry_y" }
+ }
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ editor.drawPosSelection();
+ editor.drawEventBlock();
+ editor_mode.showMode('loc');
+ printf('添加楼梯事件成功');
+ });
+ return true;
+ }
+
+ /**
+ * 绑定该机关门的事件
+ */
+ editor.uifunctions._extraEvent_bindSpecialDoor = function (thisevent) {
+ if (thisevent.id != 'specialDoor') return false;
+ var number = parseInt(prompt("请输入该机关门的怪物数量", "0"))|| 0;
+ if (number <= 0) return true;
+ editor.uivalues.bindSpecialDoor.n = number;
+ editor.uivalues.bindSpecialDoor.loc = editor.pos.x + ',' + editor.pos.y;
+ editor.uivalues.bindSpecialDoor.enemys = [];
+ printf("请点击选择" + number + "个怪物;切换楼层或刷新页面取消操作。");
+ }
+
+ /**
+ * 确定绑定该机关门的事件
+ * cancel:是否取消此模式
+ */
+ editor.uifunctions._extraEvent_bindSpecialDoor_doAction = function (cancel) {
+ var bindSpecialDoor = editor.uivalues.bindSpecialDoor;
+ if (cancel) {
+ bindSpecialDoor.loc = null;
+ bindSpecialDoor.enemys = [];
+ bindSpecialDoor.n = 0;
+ editor.drawEventBlock();
+ printf("");
+ return;
+ }
+ if (bindSpecialDoor.loc == null || bindSpecialDoor.enemys.length != bindSpecialDoor.n) return;
+ // 添加机关门自动事件
+ var doorFlag = "flag:door_" + editor.currentFloorId + "_" + bindSpecialDoor.loc.replace(',', '_');
+ editor.currentFloorData.autoEvent[bindSpecialDoor.loc] = {
+ '0': {
+ "condition": doorFlag + "==" + bindSpecialDoor.n,
+ "currentFloor": true,
+ "priority": 0,
+ "delayExecute": false,
+ "multiExecute": false,
+ "data": [
+ {"type": "openDoor"}
+ ]
+ }
+ };
+ bindSpecialDoor.enemys.forEach(function (loc) {
+ editor.currentFloorData.afterBattle[loc] = [
+ {"type": "addValue", "name": doorFlag, "value": "1"}
+ ]
+ });
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ editor.drawEventBlock();
+ editor.drawPosSelection();
+ editor_mode.showMode('loc');
+ printf('绑定机关门事件成功');
+ });
+ bindSpecialDoor.loc = null;
+ bindSpecialDoor.enemys = [];
+ bindSpecialDoor.n = 0;
+ }
+
+ /**
+ * editor.dom.chooseThis.onmousedown
+ * 菜单 选中此点
+ */
+ editor.uifunctions.chooseThis_click = function (e) {
+ editor.uifunctions.hideMidMenu();
+ e.stopPropagation();
+ selectBox.isSelected(false);
+
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('loc');
+ //editor_mode.loc();
+ //tip.whichShow(1);
+ if (editor.isMobile) editor.showdataarea(false);
+ }
+
+ /**
+ * editor.dom.chooseInRight.onmousedown
+ * 菜单 在素材区选中此图块
+ */
+ editor.uifunctions.chooseInRight_click = function (e) {
+ editor.uifunctions.hideMidMenu();
+ e.stopPropagation();
+ var thisevent = editor[editor.layerMod][editor.pos.y][editor.pos.x];
+ editor.setSelectBoxFromInfo(thisevent);
+ }
+
+ /**
+ * editor.dom.copyLoc.onmousedown
+ * 菜单 复制此事件
+ */
+ editor.uifunctions.copyLoc_click = function (e) {
+ editor.uifunctions.hideMidMenu();
+ e.stopPropagation();
+ editor.savePreMap();
+ editor_mode.onmode('');
+ var now = editor.pos, last = editor.uivalues.lastRightButtonPos[1];
+ if (now.x == last.x && now.y == last.y) return;
+ editor.pasteToPos(editor.uivalues.lastCopyedInfo[1]);
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ ; printf('复制事件成功');
+ editor.drawPosSelection();
+ });
+ }
+
+ /**
+ * editor.dom.moveLoc.onmousedown
+ * 菜单 移动此事件
+ */
+ editor.uifunctions.moveLoc_click = function (e) {
+ editor.uifunctions.hideMidMenu();
+ e.stopPropagation();
+ editor.savePreMap();
+ editor_mode.onmode('');
+ editor.exchangePos(editor.pos, editor.uivalues.lastRightButtonPos[1]);
+ }
+
+ /**
+ * editor.dom.clearEvent.onmousedown
+ * 菜单 仅清空此点事件
+ */
+ editor.uifunctions.clearEvent_click = function (e) {
+ e.stopPropagation();
+ editor.clearPos(false);
+ }
+
+ /**
+ * editor.dom.clearLoc.onmousedown
+ * 菜单 清空此点及事件
+ */
+ editor.uifunctions.clearLoc_click = function (e) {
+ e.stopPropagation();
+ editor.clearPos(true);
+ }
+
+ /**
+ * editor.dom.lockMode.onchange
+ * 点击【】
+ */
+ editor.uifunctions.lockMode_onchange = function () {
+ tip.msgs[11] = String('锁定模式开启下将不再点击空白处自动保存,请谨慎操作。');
+ tip.whichShow(12);
+ editor.uivalues.lockMode = editor.dom.lockMode.checked;
+ }
+
+ /**
+ * editor.dom.brushMod.onchange
+ * 切换画笔模式
+ */
+ editor.uifunctions.brushMod_onchange = function () {
+ editor.brushMod = editor.dom.brushMod.value;
+ }
+
+ /**
+ * editor.dom.brushMod2.onchange
+ * 切换画笔模式
+ */
+ editor.uifunctions.brushMod2_onchange = function () {
+ editor.brushMod = editor.dom.brushMod2.value;
+ }
+
+ /**
+ * editor.dom.brushMod3.onchange
+ * 切换画笔模式
+ */
+ editor.uifunctions.brushMod3_onchange = function () {
+ if (!editor.config.get('alertTileMode') &&
+ !confirm("从V2.6.6开始,tileset贴图模式已被废弃。\n请右键额外素材,并输入所需要绘制的宽高,然后单击地图以绘制一个区域。\n\n点取消将不再显示此提示。")) {
+ editor.config.set('alertTileMode', true);
+ }
+ // tip.showHelp(5)
+ tip.isSelectedBlock(false)
+ tip.msgs[11] = String('tileset贴图模式下可以按选中tileset素材,并在地图上拖动来一次绘制一个区域');
+ tip.whichShow(12);
+ editor.brushMod = editor.dom.brushMod3.value;
+ }
+
+ /**
+ * editor.dom.layerMod.onchange
+ * 切换编辑的层
+ */
+ editor.uifunctions.layerMod_onchange = function () {
+ editor.layerMod = editor.dom.layerMod.value;
+ [editor.dom.bgc, editor.dom.fgc, editor.dom.evc, editor.dom.ev2c].forEach(function (x) {
+ x.style.opacity = 1;
+ });
+
+ // 手机端....
+ if (editor.isMobile) {
+ if (editor.dom.layerMod.value == 'bgmap') {
+ [editor.dom.fgc, editor.dom.evc, editor.dom.ev2c].forEach(function (x) {
+ x.style.opacity = 0.3;
+ });
+ }
+ if (editor.dom.layerMod.value == 'fgmap') {
+ [editor.dom.bgc, editor.dom.evc, editor.dom.ev2c].forEach(function (x) {
+ x.style.opacity = 0.3;
+ });
+ }
+ }
+ }
+
+ /**
+ * editor.dom.layerMod2.onchange
+ * 切换编辑的层
+ */
+ editor.uifunctions.layerMod2_onchange = function () {
+ editor.layerMod = editor.dom.layerMod2.value;
+ [editor.dom.fgc, editor.dom.evc, editor.dom.ev2c].forEach(function (x) {
+ x.style.opacity = 0.3;
+ });
+ editor.dom.bgc.style.opacity = 1;
+ }
+
+ /**
+ * editor.dom.layerMod3.onchange
+ * 切换编辑的层
+ */
+ editor.uifunctions.layerMod3_onchange = function () {
+ editor.layerMod = editor.dom.layerMod3.value;
+ [editor.dom.bgc, editor.dom.evc, editor.dom.ev2c].forEach(function (x) {
+ x.style.opacity = 0.3;
+ });
+ editor.dom.fgc.style.opacity = 1;
+ }
+
+ /**
+ * 移动大地图可视窗口的绑定
+ */
+ editor.uifunctions.viewportButtons_func = function () {
+ var pressTimer = null;
+ for (var ii = 0, node; node = editor.dom.viewportButtons.children[ii]; ii++) {
+ (function (x, y) {
+ var move = function () {
+ editor.moveViewport(x, y);
+ }
+ node.onmousedown = function () {
+ clearTimeout(pressTimer);
+ pressTimer = setTimeout(function () {
+ pressTimer = -1;
+ var f = function () {
+ if (pressTimer != null) {
+ move();
+ setTimeout(f, 150);
+ }
+ }
+ f();
+ }, 500);
+ };
+ node.onmouseup = function () {
+ if (pressTimer > 0) {
+ clearTimeout(pressTimer);
+ move();
+ }
+ pressTimer = null;
+ }
+ })([-1, 0, 0, 1][ii], [0, -1, 1, 0][ii]);
+ }
+ }
+
+ editor.uifunctions.selectFloor_func = function () {
+ var selectFloor = document.getElementById('selectFloor');
+ editor.game.getFloorFileList(function (floors) {
+ var outstr = [];
+ floors[0].forEach(function (floor) {
+ outstr.push(["\n'].join(''));
+ });
+ selectFloor.innerHTML = outstr.join('');
+ selectFloor.value = core.status.floorId;
+ selectFloor.onchange = function () {
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('floor');
+ editor.changeFloor(selectFloor.value);
+ }
+ });
+ }
+
+
+ editor.uifunctions.saveFloor_func = function () {
+ var saveFloor = document.getElementById('saveFloor');
+ editor_mode.saveFloor = function () {
+ editor_mode.onmode('');
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ ; printf('保存成功');
+ });
+ }
+ saveFloor.onclick = editor_mode.saveFloor;
+ }
+
+ editor.uifunctions.lastUsed_click = function (e) {
+ if (editor.isMobile) return;
+
+ var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
+ var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
+ var px = scrollLeft + e.clientX - editor.dom.mid2.offsetLeft - editor.dom.lastUsedDiv.offsetLeft,
+ py = scrollTop + e.clientY - editor.dom.mid2.offsetTop - editor.dom.lastUsedDiv.offsetTop;
+ var x = parseInt(px / 32), y = parseInt(py / 32);
+ var index = x + core.__SIZE__ * y;
+ if (index >= editor.uivalues.lastUsed.length) return;
+ editor.setSelectBoxFromInfo(editor.uivalues.lastUsed[index]);
+ return;
+ }
+
+
+
+ /////////////////////////////////////////////////////////////////////////////
+
+
+ editor.constructor.prototype.copyFromPos = function (pos) {
+ var fields = Object.keys(editor.file.comment._data.floors._data.loc._data);
+ pos = pos || editor.pos;
+ var map = core.clone(editor.map[pos.y][pos.x]);
+ var events = {};
+ fields.forEach(function(v){
+ events[v] = core.clone(editor.currentFloorData[v][pos.x+','+pos.y]);
+ })
+ return {map: map, events: events};
+ }
+
+ editor.constructor.prototype.pasteToPos = function (info, pos) {
+ if (info == null) return;
+ var fields = Object.keys(editor.file.comment._data.floors._data.loc._data);
+ pos = pos || editor.pos;
+ editor.map[pos.y][pos.x] = core.clone(info.map);
+ fields.forEach(function(v){
+ if (info.events[v] == null) delete editor.currentFloorData[v][pos.x+","+pos.y];
+ else editor.currentFloorData[v][pos.x+","+pos.y] = core.clone(info.events[v]);
+ });
+ }
+
+ editor.constructor.prototype.movePos = function (startPos, endPos, callback) {
+ if (!startPos || !endPos) return;
+ if (startPos.x == endPos.x && startPos.y == endPos.y) return;
+ var copyed = editor.copyFromPos(startPos);
+ editor.pasteToPos({map:0, events: {}}, startPos);
+ editor.pasteToPos(copyed, endPos);
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ ;printf('移动事件成功');
+ editor.drawPosSelection();
+ if (callback) callback();
+ });
+ }
+
+ editor.constructor.prototype.exchangePos = function (startPos, endPos, callback) {
+ if (!startPos || !endPos) return;
+ if (startPos.x == endPos.x && startPos.y == endPos.y) return;
+ var startInfo = editor.copyFromPos(startPos);
+ var endInfo = editor.copyFromPos(endPos);
+ editor.pasteToPos(startInfo, endPos);
+ editor.pasteToPos(endInfo, startPos);
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ ;printf('交换事件成功');
+ editor.drawPosSelection();
+ if (callback) callback();
+ });
+ }
+
+ editor.constructor.prototype.savePreMap = function () {
+ var dt = {
+ map: editor.map,
+ fgmap: editor.fgmap,
+ bgmap: editor.bgmap,
+ };
+ if (editor.uivalues.preMapData.length == 0
+ || !core.same(editor.uivalues.preMapData[editor.uivalues.preMapData.length - 1], dt)) {
+ editor.uivalues.preMapData.push(core.clone(dt));
+ if (editor.uivalues.preMapData.length > editor.uivalues.preMapMax) {
+ editor.uivalues.preMapData.shift();
+ }
+ }
+ }
+
+ editor.constructor.prototype.moveBgFg = function (startPos, endPos, name, callback) {
+ if (!startPos || !endPos || ["bgmap","fgmap"].indexOf(name)<0) return;
+ if (startPos.x == endPos.x && startPos.y == endPos.y) return;
+ editor[name][endPos.y][endPos.x] = editor[name][startPos.y][startPos.x];
+ editor[name][startPos.y][startPos.x] = 0;
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ ;printf('移动图块成功');
+ editor.drawPosSelection();
+ if (callback) callback();
+ });
+ }
+
+ editor.constructor.prototype.exchangeBgFg = function (startPos, endPos, name, callback) {
+ if (!startPos || !endPos || ["bgmap","fgmap"].indexOf(name)<0) return;
+ if (startPos.x == endPos.x && startPos.y == endPos.y) return;
+ var value = editor[name][endPos.y][endPos.x];
+ editor[name][endPos.y][endPos.x] = editor[name][startPos.y][startPos.x];
+ editor[name][startPos.y][startPos.x] = value;
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ ;printf('交换图块成功');
+ editor.drawPosSelection();
+ if (callback) callback();
+ });
+
+ }
+
+ editor.constructor.prototype.clearPos = function (clearPos, pos, callback) {
+ var fields = Object.keys(editor.file.comment._data.floors._data.loc._data);
+ pos = pos || editor.pos;
+ editor.uifunctions.hideMidMenu();
+ editor.savePreMap();
+ editor.info = 0;
+ editor_mode.onmode('');
+ if (clearPos)
+ editor.map[pos.y][pos.x]=editor.info;
+ editor.updateMap();
+ fields.forEach(function(v){
+ delete editor.currentFloorData[v][pos.x+','+pos.y];
+ })
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw(err)
+ }
+ ;printf(clearPos?'清空该点和事件成功':'只清空该点事件成功');
+ editor.drawPosSelection();
+ if (callback) callback();
+ });
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+}
\ No newline at end of file
diff --git a/_server/editor_materialpanel.js b/_server/editor_materialpanel.js
new file mode 100644
index 00000000..ca3713fb
--- /dev/null
+++ b/_server/editor_materialpanel.js
@@ -0,0 +1,158 @@
+editor_materialpanel_wrapper = function (editor) {
+
+ editor.uifunctions.getScrollBarHeight = function () {
+ var outer = document.createElement("div");
+ outer.style.visibility = "hidden";
+ outer.style.width = "100px";
+ outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
+
+ document.body.appendChild(outer);
+
+ var widthNoScroll = outer.offsetWidth;
+ // force scrollbars
+ outer.style.overflow = "scroll";
+
+ // add innerdiv
+ var inner = document.createElement("div");
+ inner.style.width = "100%";
+ outer.appendChild(inner);
+
+ var widthWithScroll = inner.offsetWidth;
+
+ // remove divs
+ outer.parentNode.removeChild(outer);
+
+ return widthNoScroll - widthWithScroll;
+ }
+
+ /**
+ * editor.dom.iconExpandBtn.onclick
+ */
+ editor.uifunctions.fold_material_click = function () {
+ if (editor.uivalues.folded) {
+ if (confirm("你想要展开素材吗?\n展开模式下将显示全素材内容。")) {
+ editor.config.set('folded', false, function() {
+ window.location.reload();
+ });
+ }
+ } else {
+ var perCol = parseInt(prompt("请输入折叠素材模式下每列的个数:", "50")) || 0;
+ if (perCol > 0) {
+ editor.config.set('foldPerCol', perCol, false);
+ editor.config.set('folded', true, function() {
+ window.location.reload();
+ });
+ }
+ }
+ }
+
+ /**
+ * editor.dom.iconLib.onmousedown
+ * 素材区的单击事件
+ */
+ editor.uifunctions.material_ondown = function (e) {
+ e.stopPropagation();
+ e.preventDefault();
+ if (!editor.isMobile && e.clientY >= editor.dom.iconLib.offsetHeight - editor.uivalues.scrollBarHeight) return;
+ var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
+ var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
+ var loc = {
+ 'x': scrollLeft + e.clientX + editor.dom.iconLib.scrollLeft - right.offsetLeft - editor.dom.iconLib.offsetLeft,
+ 'y': scrollTop + e.clientY + editor.dom.iconLib.scrollTop - right.offsetTop - editor.dom.iconLib.offsetTop,
+ 'size': 32
+ };
+ editor.loc = loc;
+ editor.uivalues.tileSize = [1,1];
+ var pos = editor.uifunctions.locToPos(loc);
+ for (var spriter in editor.widthsX) {
+ if (pos.x >= editor.widthsX[spriter][1] && pos.x < editor.widthsX[spriter][2]) {
+ var ysize = spriter.endsWith('48') ? 48 : 32;
+ loc.ysize = ysize;
+ pos.images = editor.widthsX[spriter][0];
+ pos.y = ~~(loc.y / loc.ysize);
+ if (!editor.uivalues.folded && core.tilesets.indexOf(pos.images) == -1) pos.x = editor.widthsX[spriter][1];
+ var autotiles = core.material.images['autotile'];
+ if (pos.images == 'autotile') {
+ var imNames = Object.keys(autotiles);
+ if ((pos.y + 1) * ysize > editor.widthsX[spriter][3])
+ pos.y = ~~(editor.widthsX[spriter][3] / ysize) - 4;
+ else {
+ for (var i = 0; i < imNames.length; i++) {
+ if (pos.y >= 4 * i && pos.y < 4 * (i + 1)) {
+ pos.images = imNames[i];
+ pos.y = 4 * i;
+ }
+ }
+ }
+ }
+ else {
+ var height = editor.widthsX[spriter][3], col = height / ysize;
+ if (editor.uivalues.folded && core.tilesets.indexOf(pos.images) == -1) {
+ col = (pos.x == editor.widthsX[spriter][2] - 1) ? ((col - 1) % editor.uivalues.foldPerCol + 1) : editor.uivalues.foldPerCol;
+ }
+ if (spriter == 'terrains' && pos.x == editor.widthsX[spriter][1]) col += 2;
+ pos.y = Math.min(pos.y, col - 1);
+ }
+
+ selectBox.isSelected(true);
+ // console.log(pos,core.material.images[pos.images].height)
+ editor.dom.dataSelection.style.left = pos.x * 32 + 'px';
+ editor.dom.dataSelection.style.top = pos.y * ysize + 'px';
+ editor.dom.dataSelection.style.height = ysize - 6 + 'px';
+
+ if (pos.x == 0 && pos.y == 0) {
+ // editor.info={idnum:0, id:'empty','images':'清除块', 'y':0};
+ editor.info = 0;
+ } else if (pos.x == 0 && pos.y == 1) {
+ editor.info = editor.ids[editor.indexs[17]];
+ } else {
+ if (autotiles[pos.images]) editor.info = { 'images': pos.images, 'y': 0 };
+ else if (core.tilesets.indexOf(pos.images) != -1) editor.info = { 'images': pos.images, 'y': pos.y, 'x': pos.x - editor.widthsX[spriter][1] };
+ else {
+ var y = pos.y;
+ if (editor.uivalues.folded) {
+ y += editor.uivalues.foldPerCol * (pos.x - editor.widthsX[spriter][1]);
+ }
+ if (pos.images == 'terrains' && pos.x == 0) y -= 2;
+ editor.info = { 'images': pos.images, 'y': y }
+ }
+
+ for (var ii = 0; ii < editor.ids.length; ii++) {
+ if ((core.tilesets.indexOf(pos.images) != -1 && editor.info.images == editor.ids[ii].images
+ && editor.info.y == editor.ids[ii].y && editor.info.x == editor.ids[ii].x)
+ || (Object.prototype.hasOwnProperty.call(autotiles, pos.images) && editor.info.images == editor.ids[ii].id
+ && editor.info.y == editor.ids[ii].y)
+ || (core.tilesets.indexOf(pos.images) == -1 && editor.info.images == editor.ids[ii].images
+ && editor.info.y == editor.ids[ii].y)
+ ) {
+
+ editor.info = editor.ids[ii];
+ break;
+ }
+ }
+
+ if (editor.info.isTile && e.button == 2) {
+ var v = prompt("请输入该额外素材区域绑定宽高,以逗号分隔", "1,1");
+ if (v != null && /^\d+,\d+$/.test(v)) {
+ v = v.split(",");
+ var x = parseInt(v[0]), y = parseInt(v[1]);
+ var widthX = editor.widthsX[editor.info.images];
+ if (x <= 0 || y <= 0 || editor.info.x + x > widthX[2] - widthX[1] || 32*(editor.info.y + y) > widthX[3]) {
+ alert("不合法的输入范围,已经越界");
+ } else {
+ editor.uivalues.tileSize = [x, y];
+ }
+ }
+ }
+
+ }
+ tip.infos(JSON.parse(JSON.stringify(editor.info)));
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('enemyitem');
+ editor.updateLastUsedMap();
+ //editor_mode.enemyitem();
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/_server/editor_mode.js b/_server/editor_mode.js
index 240baee0..8e42b7e0 100644
--- a/_server/editor_mode.js
+++ b/_server/editor_mode.js
@@ -21,7 +21,7 @@ editor_mode = function (editor) {
this.mode = '';
this.info = {};
this.appendPic = {};
- this.doubleClickMode='change';
+ this.doubleClickMode = 'change';
}
editor_mode.prototype.init = function (callback) {
@@ -49,15 +49,16 @@ editor_mode = function (editor) {
editor_mode.actionList.push(action);
}
- editor_mode.prototype.doActionList = function (mode, actionList) {
+ editor_mode.prototype.doActionList = function (mode, actionList, callback) {
if (actionList.length == 0) return;
printf('修改中...');
- var cb=function(objs_){
+ var cb = function (objs_) {
if (objs_.slice(-1)[0] != null) {
printe(objs_.slice(-1)[0]);
- throw(objs_.slice(-1)[0])
+ throw (objs_.slice(-1)[0])
}
- ;printf('修改成功');
+ ; printf('修改成功' + (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.name == 'template' ? '\n\n请注意:全塔属性的name尚未修改,请及时予以设置' : ''));
+ if (callback) callback();
}
switch (mode) {
case 'loc':
@@ -95,9 +96,9 @@ editor_mode = function (editor) {
}
}
- editor_mode.prototype.onmode = function (mode) {
+ editor_mode.prototype.onmode = function (mode, callback) {
if (editor_mode.mode != mode) {
- if (mode === 'save') editor_mode.doActionList(editor_mode.mode, editor_mode.actionList);
+ if (mode === 'save') editor_mode.doActionList(editor_mode.mode, editor_mode.actionList, callback);
if (editor_mode.mode === 'nextChange' && mode) editor_mode.showMode(mode);
if (mode !== 'save') editor_mode.mode = mode;
editor_mode.actionList = [];
@@ -109,15 +110,78 @@ editor_mode = function (editor) {
editor_mode.dom[name].style = 'z-index:-1;opacity: 0;';
}
editor_mode.dom[mode].style = '';
- editor_mode.doubleClickMode='change';
+ editor_mode.doubleClickMode = 'change';
// clear
editor.drawEventBlock();
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())]);
+ editor.dom.editModeSelect.value = mode;
+ if (!selectBox.isSelected()) tip.showHelp();
}
+ editor_mode.prototype.change = function (value) {
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode(value);
+ if (editor.isMobile) editor.showdataarea(false);
+ }
+
+
+ editor_mode.prototype.checkUnique = function (thiseval) {
+ if (!(thiseval instanceof Array)) return false;
+ var map = {};
+ for (var i = 0; i < thiseval.length; ++i) {
+ if (map[thiseval[i]]) {
+ alert("警告:存在重复定义!");
+ return false;
+ }
+ map[thiseval[i]] = true;
+ }
+ return true;
+ }
+
+ editor_mode.prototype.checkFloorIds = function (thiseval) {
+ if (!editor_mode.checkUnique(thiseval)) return false;
+ var oldvalue = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.floorIds;
+ fs.readdir('project/floors', function (err, data) {
+ if (err) {
+ printe(err);
+ throw Error(err);
+ }
+ var newfiles = thiseval.map(function (v) { return v + '.js' });
+ var notExist = '';
+ for (var name, ii = 0; name = newfiles[ii]; ii++) {
+ if (data.indexOf(name) === -1) notExist = name;
+ }
+ if (notExist) {
+ var discard = confirm('文件' + notExist + '不存在, 保存会导致工程无法打开, 是否放弃更改');
+ if (discard) {
+ editor.file.editTower([['change', "['main']['floorIds']", oldvalue]], function (objs_) {//console.log(objs_);
+ if (objs_.slice(-1)[0] != null) {
+ printe(objs_.slice(-1)[0]);
+ throw (objs_.slice(-1)[0])
+ }
+ ; printe('已放弃floorIds的修改,请F5进行刷新');
+ });
+ }
+ }
+ });
+ return true
+ }
+
+ editor_mode.prototype.changeDoubleClickModeByButton = function (mode) {
+ ({
+ delete: function () {
+ printf('下一次双击表格的项删除,切换下拉菜单可取消;编辑后需刷新浏览器生效。');
+ editor_mode.doubleClickMode = mode;
+ },
+ add: function () {
+ printf('下一次双击表格的项则在同级添加新项,切换下拉菜单可取消;编辑后需刷新浏览器生效。');
+ editor_mode.doubleClickMode = mode;
+ }
+ }[mode])();
+ }
+
+ /////////////////////////////////////////////////////////////////////////////
+
editor_mode.prototype.loc = function (callback) {
//editor.pos={x: 0, y: 0};
if (!core.isset(editor.pos)) return;
@@ -141,17 +205,19 @@ editor_mode = function (editor) {
//editor.info=editor.ids[editor.indexs[201]];
if (!core.isset(editor.info)) return;
- if (Object.keys(editor.info).length !== 0 && editor.info.idnum!=17) editor_mode.info = editor.info;//避免editor.info被清空导致无法获得是物品还是怪物
+ if (Object.keys(editor.info).length !== 0 && editor.info.idnum != 17) editor_mode.info = editor.info;//避免editor.info被清空导致无法获得是物品还是怪物
if (!core.isset(editor_mode.info.id)) {
// document.getElementById('table_a3f03d4c_55b8_4ef6_b362_b345783acd72').innerHTML = '';
- document.getElementById('enemyItemTable').style.display = 'none';
document.getElementById('newIdIdnum').style.display = 'block';
+ document.getElementById('enemyItemTable').style.display = 'none';
+ document.getElementById('changeId').style.display = 'none';
return;
}
document.getElementById('newIdIdnum').style.display = 'none';
document.getElementById('enemyItemTable').style.display = 'block';
+ document.getElementById('changeId').style.display = 'block';
var objs = [];
if (editor_mode.info.images == 'enemys' || editor_mode.info.images == 'enemy48') {
@@ -231,7 +297,7 @@ editor_mode = function (editor) {
tableinfo.listen(tableinfo.guids);
if (Boolean(callback)) callback();
}
-
+
editor_mode.prototype.plugins = function (callback) {
var objs = [];
editor.file.editPlugins([], function (objs_) {
@@ -245,11 +311,17 @@ editor_mode = function (editor) {
if (Boolean(callback)) callback();
}
-/////////////////////////////////////////////////////////////////////////////
+ /////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * editor.dom.editModeSelect.onchange
+ */
+ editor_mode.prototype.editModeSelect_onchange = function () {
+ editor_mode.change(editor.dom.editModeSelect.value);
+ }
editor_mode.prototype.listen = function (callback) {
-
- // 移动至 editor_unsorted_2.js
+ // 移动至 editor_listen.js -> editor.constructor.prototype.mode_listen
}
var editor_mode = new editor_mode();
diff --git a/_server/editor_multi.js b/_server/editor_multi.js
index 476536bb..b694bf51 100644
--- a/_server/editor_multi.js
+++ b/_server/editor_multi.js
@@ -81,6 +81,12 @@ editor_multi = function () {
_format();
}
+ editor_multi.hasError = function () {
+ if (!editor_multi.lintAutocomplete) return false;
+ return JSHINT.errors.filter(function (e) {
+ return e.code.startsWith("E")
+ }).length > 0;
+ }
editor_multi.import = function (id_, args) {
var thisTr = document.getElementById(id_);
@@ -94,6 +100,8 @@ editor_multi = function () {
editor_multi.lintAutocomplete = false;
if (args.lint === true) editor_multi.lintAutocomplete = true;
if (field.indexOf('Effect') !== -1) editor_multi.lintAutocomplete = true;
+ if ((!input.value || input.value == 'null') && editor_mode.mode == 'plugins')
+ input.value = '"function () {\\n\\t// 在此增加新插件\\n\\t\\n}"';
if (input.value.slice(0, 1) === '"' || args.string) {
editor_multi.isString = true;
codeEditor.setValue(JSON.parse(input.value) || '');
@@ -113,6 +121,7 @@ editor_multi = function () {
}
codeEditor.setValue(tstr || '');
}
+ document.getElementById('showPlugins').style.display = editor_mode.mode == 'plugins' ? 'block': 'none';
editor_multi.show();
return true;
}
@@ -124,6 +133,11 @@ editor_multi = function () {
}
editor_multi.confirm = function () {
+ if (editor_multi.hasError()) {
+ alert("当前好像存在严重的语法错误,请处理后再保存。\n严重的语法错误可能会导致整个编辑器的崩溃。");
+ return;
+ }
+
if (!editor_multi.id) {
editor_multi.id = '';
return;
@@ -173,6 +187,11 @@ editor_multi = function () {
setvalue(codeEditor.getValue() || '');
}
+ editor_multi.showPlugins = function () {
+ if (editor.isMobile && !confirm("你确定要跳转到云端插件列表吗?")) return;
+ window.open("https://h5mota.com/plugins/", "_blank");
+ }
+
var multiLineArgs = [null, null, null];
editor_multi.multiLineEdit = function (value, b, f, args, callback) {
editor_multi.id = 'callFromBlockly';
diff --git a/_server/editor_table.js b/_server/editor_table.js
index a3b742cd..c21220fd 100644
--- a/_server/editor_table.js
+++ b/_server/editor_table.js
@@ -12,34 +12,41 @@ editor_table_wrapper = function (editor) {
values.map(function (v) {
return editor.table.option(v)
}).join('')
- return `\n`
+ return /* html */`\n`
}
editor_table.prototype.option = function (value) {
- return `\n`
+ return /* html */`\n`
}
editor_table.prototype.text = function (value) {
- return `\n`
+ return /* html */`\n`
}
editor_table.prototype.checkbox = function (value) {
- return `\n`
+ return /* html */`\n`
}
editor_table.prototype.textarea = function (value, indent) {
- return `\n`
+ return /* html */`\n`
+ }
+ editor_table.prototype.editGrid = function (showComment) {
+ var html = "";
+ if (showComment) html += "
";
+ html += "";
+ return html;
}
editor_table.prototype.title = function () {
- return `\n| 条目 | 注释 | 值 |
\n`
+ return /* html */`\n| 条目 | 注释 | 值 | 操作 |
\n`
}
editor_table.prototype.gap = function (field) {
- return `| ---- | ---- | ${field} |
\n`
+ return /* html */`| ---- | ---- | ${field} | ---- |
\n`
}
editor_table.prototype.tr = function (guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr) {
- return `
+ return /* html */`
| ${shortField} |
${shortCommentHTMLescape} |
${tdstr} |
+ ${editor.table.editGrid(commentHTMLescape != shortCommentHTMLescape)} |
\n`
}
@@ -145,6 +152,7 @@ editor_table_wrapper = function (editor) {
if (key === '_data') continue;
if (cobj[key] instanceof Function) cobj[key] = cobj[key](args);
}
+ pvobj[ii] = vobj = args.vobj;
// 标记为_hide的属性不展示
if (cobj._hide) continue;
if (!cobj._leaf) {
@@ -193,7 +201,7 @@ editor_table_wrapper = function (editor) {
// "['a']['b']" => "b"
var shortField = field.split("']").slice(-2)[0].split("['").slice(-1)[0];
// 把长度超过 charlength 的字符改成 固定长度+...的形式
- shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
+ // shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...');
// 完整的内容转义后供悬停查看
var commentHTMLescape = editor.util.HTMLescape(comment);
@@ -285,6 +293,7 @@ editor_table_wrapper = function (editor) {
var thiseval = null;
if (input.checked != null) input.value = input.checked;
try {
+ if (input.value == '') input.value = 'null';
thiseval = JSON.parse(input.value);
} catch (ee) {
printe(field + ' : ' + ee);
@@ -298,6 +307,25 @@ editor_table_wrapper = function (editor) {
}
}
+ /**
+ * 当"显示完整注释"被按下时
+ */
+ editor_table.prototype.onCommentBtnClick = function (button) {
+ var tr = button.parentNode.parentNode;
+ printf(tr.children[1].getAttribute('title'));
+ }
+
+ /**
+ * 当"编辑表格内容"被按下时
+ */
+ editor_table.prototype.onEditBtnClick = function (button) {
+ var tr = button.parentNode.parentNode;
+ var guid = tr.getAttribute('id');
+ var cobj = JSON.parse(tr.children[1].getAttribute('cobj'));
+ 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 });
+ }
+
/**
* 双击表格时
* 正常编辑: 尝试用事件编辑器或多行文本编辑器打开
@@ -337,12 +365,22 @@ editor_table_wrapper = function (editor) {
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;
+ var mode = editor.dom.editModeSelect.value;
// 1.输入id
- var newid = prompt('请输入新项的ID(仅公共事件支持中文ID)');
- if (newid == null || newid.length == 0) {
- return;
+ var newid = '2';
+ if (mode == 'loc') {
+ var ae = editor.currentFloorData.autoEvent[editor_mode.pos.x + ',' + editor_mode.pos.y];
+ if (ae != null) {
+ var testid;
+ for (testid = 2; Object.hasOwnProperty.call(ae, testid); testid++); // 从3开始是因为comment中设置了始终显示012
+ newid = testid + '';
+ }
+ } else {
+ newid = prompt('请输入新项的ID(仅公共事件支持中文ID)');
+ if (newid == null || newid.length == 0) {
+ return;
+ }
}
// 检查commentEvents
diff --git a/_server/editor_ui.js b/_server/editor_ui.js
new file mode 100644
index 00000000..4a5e4386
--- /dev/null
+++ b/_server/editor_ui.js
@@ -0,0 +1,570 @@
+editor_ui_wrapper = function (editor) {
+
+
+ /**
+ * 根据鼠标点击, 得到从元素向上到body的所有id
+ */
+ editor.uifunctions.getClickpath = function (e) {
+ //console.log(e);
+ var clickpath = [];
+ var getpath = function (e) {
+ var path = [];
+ var currentElem = e.target;
+ while (currentElem) {
+ path.push(currentElem);
+ currentElem = currentElem.parentElement;
+ }
+ if (path.indexOf(window) === -1 && path.indexOf(document) === -1)
+ path.push(document);
+ if (path.indexOf(window) === -1)
+ path.push(window);
+ return path;
+ }
+ getpath(e).forEach(function (node) {
+ if (!node.getAttribute) return;
+ var id_ = node.getAttribute('id');
+ if (id_) {
+ if (['left', 'left1', 'left2', 'left3', 'left4', 'left5', 'left8', 'mobileview'].indexOf(id_) !== -1) clickpath.push('edit');
+ clickpath.push(id_);
+ }
+ });
+ return clickpath;
+ }
+
+ /**
+ * editor.dom.body.onmousedown
+ * 检测鼠标点击,
+ * + 如果选中了绘图区域之外, 就保存地图
+ * + 维护绘图区的菜单的隐藏
+ * + 记录最后一次点击的id(主要为了数据区服务)
+ */
+ editor.uifunctions.body_click = function (e) {
+ var clickpath = editor.uifunctions.getClickpath(e);
+
+ var unselect = true;
+ for (var ii = 0, thisId; thisId = ['edit', 'tip', 'brushMod', 'brushMod2', 'brushMod3', 'layerMod', 'layerMod2', 'layerMod3', 'viewportButtons'][ii]; ii++) {
+ if (clickpath.indexOf(thisId) !== -1) {
+ unselect = false;
+ break;
+ }
+ }
+ if (unselect && !editor.uivalues.lockMode) {
+ if (clickpath.indexOf('eui') === -1 && clickpath.indexOf('lastUsed') === -1) {
+ if (selectBox.isSelected()) {
+ editor_mode.onmode('');
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ ; printf('地图保存成功');
+ });
+ }
+ selectBox.isSelected(false);
+ editor.info = {};
+ }
+ }
+ //editor.mode.onmode('');
+ if (e.button != 2 && !editor.isMobile) {
+ editor.uifunctions.hideMidMenu();
+ }
+ if (clickpath.indexOf('down') !== -1 && editor.isMobile && clickpath.indexOf('midMenu') === -1) {
+ editor.uifunctions.hideMidMenu();
+ }
+ if (clickpath.length >= 2 && clickpath[0].indexOf('id_') === 0) { editor.lastClickId = clickpath[0] }
+ }
+
+ /**
+ * editor.dom.body.onkeydown
+ * 绑定快捷键
+ */
+ editor.uifunctions.body_shortcut = function (e) {
+
+ // UI预览 & 地图选点
+ if (editor.uievent && editor.uievent.isOpen) {
+ e.preventDefault();
+ if (e.keyCode == 27) editor.uievent.close();
+ else if (e.keyCode == 13) editor.uievent.confirm();
+ else if (e.keyCode == 87) editor.uievent.move(0, -1)
+ else if (e.keyCode == 65) editor.uievent.move(-1, 0)
+ else if (e.keyCode == 83) editor.uievent.move(0, 1);
+ else if (e.keyCode == 68) editor.uievent.move(1, 0);
+ return;
+ }
+
+ // 监听Ctrl+S保存
+ if (e.ctrlKey && e.keyCode == 83) {
+ e.preventDefault();
+ if (editor_multi.id != "") {
+ editor_multi.confirm(); // 保存脚本编辑器
+ }
+ else if (editor_blockly.id != "") {
+ editor_blockly.confirm(); // 保存事件编辑器
+ }
+ else {
+ editor_mode.saveFloor();
+ }
+ return;
+ }
+
+ // 如果是开启事件/脚本编辑器状态,则忽略
+ if (editor_multi.id != "" || editor_blockly.id != "")
+ return;
+
+ // PGUP和PGDOWN切换楼层
+ if (e.keyCode == 33 || e.keyCode == 34) {
+ e.preventDefault();
+ var index = editor.core.floorIds.indexOf(editor.currentFloorId);
+ var nextIndex = index + (e.keyCode == 33 ? 1 : -1);
+ if (nextIndex >= 0 && nextIndex < editor.core.floorIds.length) {
+ var toId = editor.core.floorIds[nextIndex];
+ editor_mode.onmode('nextChange');
+ editor_mode.onmode('floor');
+ document.getElementById('selectFloor').value = toId;
+ editor.changeFloor(toId);
+ }
+ return;
+ }
+
+ var focusElement = document.activeElement;
+ if (!focusElement || focusElement.tagName.toLowerCase() == 'body'
+ || focusElement.id == 'selectFloor') {
+
+ //Ctrl+z 撤销上一步undo
+ if (e.keyCode == 90 && e.ctrlKey) {
+ e.preventDefault();
+ if (editor.uivalues.preMapData.length > 0) {
+ var data = editor.uivalues.preMapData.pop();
+ editor.map = JSON.parse(JSON.stringify(data.map));
+ editor.fgmap = JSON.parse(JSON.stringify(data.fgmap));
+ editor.bgmap = JSON.parse(JSON.stringify(data.bgmap));
+ editor.updateMap();
+ editor.uivalues.postMapData.push(data);
+ printf("已撤销此操作,你可能需要重新保存地图。");
+ }
+ return;
+ }
+ //Ctrl+y 重做一步redo
+ if (e.keyCode == 89 && e.ctrlKey) {
+ e.preventDefault();
+ if (editor.uivalues.postMapData.length > 0) {
+ var data = editor.uivalues.postMapData.pop();
+ editor.map = JSON.parse(JSON.stringify(data.map));
+ editor.fgmap = JSON.parse(JSON.stringify(data.fgmap));
+ editor.bgmap = JSON.parse(JSON.stringify(data.bgmap));
+ editor.updateMap();
+ editor.uivalues.preMapData.push(data);
+ printf("已重做此操作,你可能需要重新保存地图。");
+ }
+ return;
+ }
+
+ // Ctrl+C, Ctrl+X, Ctrl+V
+ if (e.ctrlKey && e.keyCode == 67 && !selectBox.isSelected()) {
+ e.preventDefault();
+ editor.uivalues.copyedInfo = editor.copyFromPos();
+ printf('该点事件已复制');
+ return;
+ }
+ if (e.ctrlKey && e.keyCode == 88 && !selectBox.isSelected()) {
+ e.preventDefault();
+ editor.uivalues.copyedInfo = editor.copyFromPos();
+ editor.clearPos(true, null, function () {
+ printf('该点事件已剪切');
+ })
+ return;
+ }
+ if (e.ctrlKey && e.keyCode == 86 && !selectBox.isSelected()) {
+ e.preventDefault();
+ if (!editor.uivalues.copyedInfo) {
+ printe("没有复制的事件");
+ return;
+ }
+ editor.pasteToPos(editor.uivalues.copyedInfo);
+ editor.updateMap();
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ ; printf('粘贴事件成功');
+ editor.drawPosSelection();
+ });
+ return;
+ }
+ // DELETE
+ if (e.keyCode == 46 && !selectBox.isSelected()) {
+ editor.clearPos(true);
+ return;
+ }
+ // ESC
+ if (e.keyCode == 27) {
+ if (selectBox.isSelected()) {
+ editor_mode.onmode('');
+ editor.file.saveFloorFile(function (err) {
+ if (err) {
+ printe(err);
+ throw (err)
+ }
+ ; printf('地图保存成功');
+ });
+ }
+ selectBox.isSelected(false);
+ editor.info = {};
+ return;
+ }
+ //alt + 0~9 改变快捷图块
+ if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) {
+ var infoToSave = JSON.stringify(editor.info || 0);
+ if (infoToSave == JSON.stringify({})) return;
+ editor.uivalues.shortcut[e.keyCode] = JSON.parse(infoToSave);
+ printf('已保存该快捷图块, 数字键 ' + (e.keyCode - 48) + ' 使用.')
+ editor.config.set('shortcut', editor.uivalues.shortcut);
+ return;
+ }
+ //ctrl + 0~9 切换到快捷图块
+ if ([48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1) {
+ editor.setSelectBoxFromInfo(JSON.parse(JSON.stringify(editor.uivalues.shortcut[e.keyCode] || 0)));
+ return;
+ }
+ switch (e.keyCode) {
+ // WASD
+ case 87: editor.moveViewport(0, -1); break;
+ case 65: editor.moveViewport(-1, 0); break;
+ case 83: editor.moveViewport(0, 1); break;
+ case 68: editor.moveViewport(1, 0); break;
+ // Z~.
+ case 90: editor_mode.change('map'); break; // Z
+ case 88: editor_mode.change('loc'); break; // X
+ case 67: editor_mode.change('enemyitem'); break; // C
+ case 86: editor_mode.change('floor'); break; // V
+ case 66: editor_mode.change('tower'); break; // B
+ case 78: editor_mode.change('functions'); break; // N
+ case 77: editor_mode.change('appendpic'); break; // M
+ case 188: editor_mode.change('commonevent'); break; // ,
+ case 190: editor_mode.change('plugins'); break; // .
+ // H
+ case 72: editor.uifunctions.showHelp(); break;
+ }
+ return;
+ }
+ }
+
+ editor.uifunctions.showHelp = function () {
+ alert(
+ "快捷操作帮助:\n" +
+ "ESC / 点击空白处:自动保存当前修改" +
+ "WASD / 长按箭头:平移大地图\n" +
+ "PgUp, PgDn / 鼠标滚轮:上下切换楼层\n" +
+ "Z~.(键盘的第三排):快捷切换标签\n" +
+ "双击地图:选中对应点的素材\n" +
+ "右键地图:弹出菜单栏\n" +
+ "Alt+0~9:保存当前使用的图块\n" +
+ "0~9:选中保存的图块\n" +
+ "Ctrl+Z / Ctrl+Y:撤销/重做上次绘制\n" +
+ "Ctrl+S:事件与脚本编辑器的保存并退出\n" +
+ "双击事件编辑器:长文本编辑/脚本编辑/地图选点/UI绘制预览"
+ );
+ }
+
+
+ // ------ UI预览 & 地图选点相关 ------ //
+
+ var uievent = {
+ elements: {},
+ values: {},
+ isOpen: false,
+ mode: ""
+ };
+
+ uievent.elements.div = document.getElementById('uieventDiv');
+ uievent.elements.title = document.getElementById('uieventTitle');
+ uievent.elements.yes = document.getElementById('uieventYes');
+ uievent.elements.no = document.getElementById('uieventNo');
+ uievent.elements.selectBackground = document.getElementById('uieventBackground');
+ uievent.elements.selectPoint = document.getElementById('selectPoint');
+ uievent.elements.selectFloor = document.getElementById('selectPointFloor');
+ uievent.elements.selectPointBox = document.getElementById('selectPointBox');
+ uievent.elements.body = document.getElementById('uieventBody');
+ uievent.elements.selectPointButtons = document.getElementById('selectPointButtons');
+ uievent.elements.canvas = document.getElementById('uievent');
+ uievent.elements.usedFlags = document.getElementById('uieventUsedFlags');
+ uievent.elements.usedFlagList = document.getElementById('uieventUsedFlagList');
+
+ uievent.confirm = function () {
+ var callback = uievent.values.callback, floorId = uievent.values.floorId,
+ x = uievent.values.x, y = uievent.values.y;
+ uievent.close();
+ if (callback) {
+ callback(floorId, x, y);
+ }
+ }
+ uievent.elements.yes.onclick = uievent.confirm;
+
+ uievent.close = function () {
+ uievent.isOpen = false;
+ uievent.elements.div.style.display = 'none';
+ uievent.values = {};
+ }
+ uievent.elements.no.onclick = uievent.close;
+
+ uievent.elements.selectBackground.onchange = function () {
+ uievent.drawPreviewUI();
+ }
+
+ uievent.drawPreviewUI = function () {
+ core.setAlpha('uievent', 1);
+ core.clearMap('uievent');
+
+ // 绘制UI
+ var background = uievent.elements.selectBackground.value;
+ if (background == 'thumbnail') {
+ core.drawThumbnail(editor.currentFloorId, null, {}, 'uievent');
+ }
+ else {
+ core.fillRect('uievent', 0, 0, core.__PIXELS__, core.__PIXELS__, background);
+ }
+
+ if (uievent.values.list instanceof Array) {
+ uievent.values.list.forEach(function (data) {
+ var type = data.type;
+ if (!type || !core.ui["_uievent_" + type]) return;
+ core.ui["_uievent_" + type](data);
+ })
+ }
+ }
+
+ uievent.previewUI = function (list) {
+ uievent.isOpen = true;
+ uievent.elements.div.style.display = 'block';
+ uievent.mode = 'previewUI';
+ uievent.elements.selectPoint.style.display = 'none';
+ uievent.elements.yes.style.display = 'none';
+ uievent.elements.title.innerText = 'UI绘制预览';
+ uievent.elements.selectBackground.style.display = 'inline';
+ uievent.elements.selectBackground.value = 'thumbnail';
+ uievent.elements.selectFloor.style.display = 'none';
+ uievent.elements.selectPointBox.style.display = 'none';
+ uievent.elements.canvas.style.display = 'block';
+ uievent.elements.usedFlags.style.display = 'none';
+ uievent.elements.usedFlagList.style.display = 'none';
+ uievent.elements.body.style.overflow = "hidden";
+
+ uievent.values.list = list;
+ uievent.drawPreviewUI();
+ }
+
+ uievent.selectPoint = function (floorId, x, y, hideFloor, callback) {
+ uievent.values.hideFloor = hideFloor;
+ uievent.values.callback = callback;
+ uievent.values.size = editor.isMobile ? window.innerWidth / core.__SIZE__ : 32;
+ uievent.elements.selectPointBox.style.width = (uievent.values.size - 6) + "px";
+ uievent.elements.selectPointBox.style.height = (uievent.values.size - 6) + "px";
+
+ uievent.isOpen = true;
+ uievent.elements.div.style.display = 'block';
+ uievent.mode = 'selectPoint';
+ uievent.elements.selectPoint.style.display = 'block';
+ uievent.elements.yes.style.display = 'inline';
+ uievent.elements.selectBackground.style.display = 'none';
+ uievent.elements.selectFloor.style.display = hideFloor ? 'none' : 'inline';
+ uievent.elements.selectPointBox.style.display = 'block';
+ uievent.elements.canvas.style.display = 'block';
+ uievent.elements.usedFlags.style.display = 'none';
+ uievent.elements.usedFlagList.style.display = 'none';
+ uievent.elements.body.style.overflow = "hidden";
+
+ // Append children
+ var floors = "";
+ core.floorIds.forEach(function (f) {
+ floors += "";
+ })
+ uievent.elements.selectFloor.innerHTML = floors;
+
+ this.setPoint(floorId || editor.currentFloorId, core.calValue(x) || 0, core.calValue(y) || 0);
+ }
+
+ uievent.updateSelectPoint = function (redraw) {
+ uievent.elements.title.innerText = '地图选点 (' + uievent.values.x + "," + uievent.values.y + ')';
+ if (redraw) {
+ core.setAlpha('uievent', 1);
+ core.clearMap('uievent');
+ core.drawThumbnail(uievent.values.floorId, null, null,
+ {
+ ctx: 'uievent', centerX: uievent.values.left + core.__HALF_SIZE__,
+ centerY: uievent.values.top + core.__HALF_SIZE__
+ });
+ }
+ uievent.elements.selectPointBox.style.left = uievent.values.size * (uievent.values.x - uievent.values.left) + "px";
+ uievent.elements.selectPointBox.style.top = uievent.values.size * (uievent.values.y - uievent.values.top) + "px";
+ }
+
+ uievent.setPoint = function (floorId, x, y) {
+ if (core.floorIds.indexOf(floorId) == -1) floorId = editor.currentFloorId;
+ uievent.values.floorId = floorId;
+ uievent.elements.selectFloor.value = floorId;
+ uievent.values.x = x != null ? x : (uievent.values.x || 0);
+ uievent.values.y = y != null ? y : (uievent.values.y || 0);
+ uievent.values.width = core.floors[uievent.values.floorId].width || core.__SIZE__;
+ uievent.values.height = core.floors[uievent.values.floorId].height || core.__SIZE__;
+ uievent.values.left = core.clamp(uievent.values.x - core.__HALF_SIZE__, 0, uievent.values.width - core.__SIZE__);
+ uievent.values.top = core.clamp(uievent.values.y - core.__HALF_SIZE__, 0, uievent.values.height - core.__SIZE__);
+ uievent.updateSelectPoint(true);
+ }
+
+ uievent.elements.selectFloor.onchange = function () {
+ uievent.setPoint(uievent.elements.selectFloor.value);
+ }
+
+ uievent.elements.selectPointBox.onclick = function (e) {
+ e.stopPropagation();
+ }
+
+ uievent.elements.body.onclick = function (e) {
+ if (uievent.mode != 'selectPoint') return;
+ uievent.values.x = uievent.values.left + Math.floor(e.offsetX / uievent.values.size);
+ uievent.values.y = uievent.values.top + Math.floor(e.offsetY / uievent.values.size);
+ uievent.updateSelectPoint(false);
+ }
+
+ uievent.move = function (dx, dy) {
+ if (uievent.mode != 'selectPoint') return;
+ uievent.values.left = core.clamp(uievent.values.left + dx, 0, uievent.values.width - core.__SIZE__);
+ uievent.values.top = core.clamp(uievent.values.top + dy, 0, uievent.values.height - core.__SIZE__);
+ this.updateSelectPoint(true);
+ };
+
+ (function () {
+
+ var viewportButtons = uievent.elements.selectPointButtons;
+ var pressTimer = null;
+ for (var ii = 0, node; node = viewportButtons.children[ii]; ii++) {
+ (function (x, y) {
+ var move = function () {
+ uievent.move(x, y);
+ }
+ node.onmousedown = function () {
+ clearTimeout(pressTimer);
+ pressTimer = setTimeout(function () {
+ pressTimer = -1;
+ var f = function () {
+ if (pressTimer != null) {
+ move();
+ setTimeout(f, 150);
+ }
+ }
+ f();
+ }, 500);
+ };
+ node.onmouseup = function () {
+ if (pressTimer > 0) {
+ clearTimeout(pressTimer);
+ move();
+ }
+ pressTimer = null;
+ }
+ })([-1, 0, 0, 1][ii], [0, -1, 1, 0][ii]);
+ }
+ })();
+
+ uievent.elements.div.onmousewheel = function (e) {
+ if (uievent.mode != 'selectPoint' || uievent.values.hideFloor) return;
+ var index = core.floorIds.indexOf(uievent.values.floorId);
+ try {
+ if (e.wheelDelta)
+ index += Math.sign(e.wheelDelta);
+ else if (e.detail)
+ index += Math.sign(e.detail);
+ } catch (ee) { main.log(ee); }
+ index = core.clamp(index, 0, core.floorIds.length - 1);
+ uievent.setPoint(core.floorIds[index]);
+ }
+
+ // ------ 搜索变量出现的位置,也放在uievent好了 ------ //
+
+ uievent.searchUsedFlags = function () {
+ uievent.isOpen = true;
+ uievent.elements.div.style.display = 'block';
+ uievent.mode = 'searchUsedFlags';
+ uievent.elements.selectPoint.style.display = 'none';
+ uievent.elements.yes.style.display = 'none';
+ uievent.elements.title.innerText = '搜索变量';
+ uievent.elements.selectBackground.style.display = 'none';
+ uievent.elements.selectFloor.style.display = 'none';
+ uievent.elements.selectPointBox.style.display = 'none';
+ uievent.elements.canvas.style.display = 'none';
+ uievent.elements.usedFlags.style.display = 'inline';
+ uievent.elements.usedFlagList.style.display = 'block';
+ uievent.elements.body.style.overflow = "auto";
+
+ // build flags
+ var html = "";
+ Object.keys(editor.used_flags).sort().forEach(function (v) {
+ v = "flag:" + v;
+ html += "";
+ });
+ uievent.elements.usedFlags.innerHTML = html;
+
+ uievent.doSearchUsedFlags();
+ }
+
+ uievent.doSearchUsedFlags = function () {
+ var flag = uievent.elements.usedFlags.value;
+
+ var html = "该变量出现的所有位置如下:
";
+ var list = uievent._searchUsedFlags(flag);
+ list.forEach(function (v) {
+ var x = "- ";
+ if (v[0] != null) x += v[0] + "层 ";
+ else x += "公共事件 ";
+ x += v[1];
+ if (v[2] != null) x += " 的 (" + v[2] + ") 点";
+ x += "
";
+ html += x;
+ });
+ html += "
";
+ uievent.elements.usedFlagList.innerHTML = html;
+ }
+
+ var hasUsedFlags = function (obj, flag) {
+ if (obj == null) return false;
+ if (typeof obj != 'string') return hasUsedFlags(JSON.stringify(obj), flag);
+
+ var index = -1, length = flag.length;
+ while (true) {
+ index = obj.indexOf(flag, index + 1);
+ if (index < 0) return false;
+ if (!/^[a-zA-Z0-9_\u4E00-\u9FCC]$/.test(obj.charAt(index + length))) return true;
+ }
+ }
+
+ uievent._searchUsedFlags = function (flag) {
+ var list = [];
+ var events = ["events", "autoEvent", "changeFloor", "afterBattle", "afterGetItem", "afterOpenDoor"]
+ for (var floorId in core.floors) {
+ var floor = core.floors[floorId];
+ if (hasUsedFlags(floor.firstArrive, flag)) list.push([floorId, "firstArrive"]);
+ if (hasUsedFlags(floor.eachArrive, flag)) list.push([floorId, "eachArrive"]);
+ events.forEach(function (e) {
+ if (floor[e]) {
+ for (var loc in floor[e]) {
+ if (hasUsedFlags(floor[e][loc], flag)) {
+ list.push([floorId, e, loc]);
+ }
+ }
+ }
+ });
+ }
+ // 公共事件
+ if (core.events.commonEvent) {
+ for (var name in core.events.commonEvent) {
+ if (hasUsedFlags(core.events.commonEvent[name], flag))
+ list.push([null, name]);
+ }
+ }
+ return list;
+ }
+
+ editor.constructor.prototype.uievent=uievent;
+
+}
\ No newline at end of file
diff --git a/_server/editor_unsorted_1.js b/_server/editor_unsorted_1.js
deleted file mode 100644
index 0d3861d8..00000000
--- a/_server/editor_unsorted_1.js
+++ /dev/null
@@ -1,839 +0,0 @@
-editor_unsorted_1_wrapper=function(editor){
-
-editor.constructor.prototype.listen=function () {
- document.body.onmousedown = function (e) {
- //console.log(e);
- var clickpath = [];
- var getpath=function(e) {
- var path = [];
- var currentElem = e.target;
- while (currentElem) {
- path.push(currentElem);
- currentElem = currentElem.parentElement;
- }
- if (path.indexOf(window) === -1 && path.indexOf(document) === -1)
- path.push(document);
- if (path.indexOf(window) === -1)
- path.push(window);
- return path;
- }
- getpath(e).forEach(function (node) {
- if (!node.getAttribute) return;
- var id_ = node.getAttribute('id');
- if (id_) {
- if (['left', 'left1', 'left2', 'left3', 'left4', 'left5', 'left8', 'mobileview'].indexOf(id_) !== -1) clickpath.push('edit');
- clickpath.push(id_);
- }
- });
-
- var unselect=true;
- for(var ii=0,thisId;thisId=['edit','tip','brushMod','brushMod2','brushMod3','layerMod','layerMod2','layerMod3','viewportButtons'][ii];ii++){
- if (clickpath.indexOf(thisId) !== -1){
- unselect=false;
- break;
- }
- }
- if (unselect) {
- if (clickpath.indexOf('eui') === -1) {
- if (selectBox.isSelected()) {
- editor_mode.onmode('');
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf('地图保存成功');
- });
- }
- selectBox.isSelected(false);
- editor.info = {};
- }
- }
- //editor.mode.onmode('');
- if (e.button!=2 && !editor.isMobile){
- editor.hideMidMenu();
- }
- if (clickpath.indexOf('down') !== -1 && editor.isMobile && clickpath.indexOf('midMenu') === -1){
- editor.hideMidMenu();
- }
- if(clickpath.length>=2 && clickpath[0].indexOf('id_')===0){editor.lastClickId=clickpath[0]}
- }
-
- var eui=document.getElementById('eui');
- var uc = eui.getContext('2d');
-
- function fillPos(pos) {
- uc.fillStyle = '#' + ~~(Math.random() * 8) + ~~(Math.random() * 8) + ~~(Math.random() * 8);
- uc.fillRect(pos.x * 32 + 12 - core.bigmap.offsetX, pos.y * 32 + 12 - core.bigmap.offsetY, 8, 8);
- }//在格子内画一个随机色块
-
- function eToLoc(e) {
- var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft
- var scrollTop = document.documentElement.scrollTop || document.body.scrollTop
- var xx=e.clientX,yy=e.clientY
- if(editor.isMobile){xx=e.touches[0].clientX,yy=e.touches[0].clientY}
- editor.loc = {
- 'x': scrollLeft + xx - mid.offsetLeft - mapEdit.offsetLeft,
- 'y': scrollTop + yy - mid.offsetTop - mapEdit.offsetTop,
- 'size': editor.isMobile?(32*innerWidth*0.96/core.__PIXELS__):32
- };
- return editor.loc;
- }//返回可用的组件内坐标
-
- function locToPos(loc, addViewportOffset) {
- var offsetX=0, offsetY=0;
- if (addViewportOffset){
- offsetX=core.bigmap.offsetX/32;
- offsetY=core.bigmap.offsetY/32;
- }
- editor.pos = {'x': ~~(loc.x / loc.size)+offsetX, 'y': ~~(loc.y / loc.size)+offsetY}
- return editor.pos;
- }
-
- var holdingPath = 0;
- var stepPostfix = null;//用于存放寻路检测的第一个点之后的后续移动
-
- var mouseOutCheck = 2;
-
- function clear1() {
- if (mouseOutCheck > 1) {
- mouseOutCheck--;
- setTimeout(clear1, 1000);
- return;
- }
- holdingPath = 0;
- stepPostfix = [];
- uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
- }//用于鼠标移出canvas时的自动清除状态
-
- eui.oncontextmenu=function(e){e.preventDefault()}
-
- eui.ondblclick = function(e) {
- // 双击地图可以选中素材
- var loc = eToLoc(e);
- var pos = locToPos(loc,true);
- editor.setSelectBoxFromInfo(editor[editor.layerMod][pos.y][pos.x]);
- return;
- }
-
- eui.onmousedown = function (e) {
- if (e.button==2){
- var loc = eToLoc(e);
- var pos = locToPos(loc,true);
- editor.showMidMenu(e.clientX,e.clientY);
- return;
- }
- 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);
- if(editor.isMobile)editor.showMidMenu(e.clientX,e.clientY);
- return;
- }
-
-
- holdingPath = 1;
- mouseOutCheck = 2;
- setTimeout(clear1);
- e.stopPropagation();
- uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
- var loc = eToLoc(e);
- var pos = locToPos(loc,true);
- stepPostfix = [];
- stepPostfix.push(pos);
- fillPos(pos);
- }
-
- eui.onmousemove = function (e) {
- if (!selectBox.isSelected()) {
- //tip.whichShow(1);
- return;
- }
-
- if (holdingPath == 0) {
- return;
- }
- mouseOutCheck = 2;
- e.stopPropagation();
- var loc = eToLoc(e);
- var pos = locToPos(loc,true);
- var pos0 = stepPostfix[stepPostfix.length - 1]
- var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x]
- var max = 0, index = 4;
- for (var i = 0; i < 4; i++) {
- if (directionDistance[i] > max) {
- index = i;
- max = directionDistance[i];
- }
- }
- var pos = [{'x': 0, 'y': 1}, {'x': -1, 'y': 0}, {'x': 0, 'y': -1}, {'x': 1, 'y': 0}, false][index]
- if (pos) {
- pos.x += pos0.x;
- pos.y += pos0.y;
- stepPostfix.push(pos);
- fillPos(pos);
- }
- }
-
- eui.onmouseup = function (e) {
- if (!selectBox.isSelected()) {
- //tip.whichShow(1);
- return;
- }
- holdingPath = 0;
- e.stopPropagation();
- if (stepPostfix && stepPostfix.length) {
- editor.preMapData = JSON.parse(JSON.stringify({map:editor.map,fgmap:editor.fgmap,bgmap:editor.bgmap}));
- if(editor.brushMod!=='line'){
- var x0=stepPostfix[0].x;
- var y0=stepPostfix[0].y;
- var x1=stepPostfix[stepPostfix.length-1].x;
- var y1=stepPostfix[stepPostfix.length-1].y;
- if(x0>x1){x0^=x1;x1^=x0;x0^=x1;}//swap
- if(y0>y1){y0^=y1;y1^=y0;y0^=y1;}//swap
- stepPostfix=[];
- for(var jj=y0;jj<=y1;jj++){
- for(var ii=x0;ii<=x1;ii++){
- stepPostfix.push({x:ii,y:jj})
- }
- }
- }
- currDrawData.pos = JSON.parse(JSON.stringify(stepPostfix));
- currDrawData.info = JSON.parse(JSON.stringify(editor.info));
- reDo = null;
- // console.log(stepPostfix);
- if(editor.brushMod==='tileset' && core.tilesets.indexOf(editor.info.images)!==-1){
- var imgWidth=~~(core.material.images.tilesets[editor.info.images].width/32);
- var x0=stepPostfix[0].x;
- var y0=stepPostfix[0].y;
- var idnum=editor.info.idnum;
- for (var ii = 0; ii < stepPostfix.length; ii++){
- if(stepPostfix[ii].y!=y0){
- y0++;
- idnum+=imgWidth;
- }
- editor[editor.layerMod][stepPostfix[ii].y][stepPostfix[ii].x] = editor.ids[editor.indexs[idnum+stepPostfix[ii].x-x0]];
- }
- } else {
- for (var ii = 0; ii < stepPostfix.length; ii++)
- editor[editor.layerMod][stepPostfix[ii].y][stepPostfix[ii].x] = editor.info;
- }
- // console.log(editor.map);
- editor.updateMap();
- holdingPath = 0;
- stepPostfix = [];
- uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__);
- }
- }
-
- /*
- document.getElementById('mid').onkeydown = function (e) {
- console.log(e);
- if (e.keyCode==37) {
- editor.moveViewport(-1, 0);
- }
- if (e.keyCode==38) {
- editor.moveViewport(0, -1);
- }
- if (e.keyCode==39) {
- editor.moveViewport(1, 0);
- }
- if (e.keyCode==40) {
- editor.moveViewport(0, 1);
- }
- }
- */
-
- document.getElementById('mid').onmousewheel = function (e) {
- e.preventDefault();
- var wheel = function (direct) {
- var index=editor.core.floorIds.indexOf(editor.currentFloorId);
- var toId = editor.currentFloorId;
-
- if (direct>0 && index0)
- toId = editor.core.floorIds[index-1];
- else return;
-
- editor_mode.onmode('nextChange');
- editor_mode.onmode('floor');
- document.getElementById('selectFloor').value = toId;
- editor.changeFloor(toId);
- }
-
- try {
- if (e.wheelDelta)
- wheel(Math.sign(e.wheelDelta))
- else if (e.detail)
- wheel(Math.sign(e.detail));
- }
- catch (ee) {
- console.log(ee);
- }
- }
-
- editor.preMapData = null;
- var currDrawData = {
- pos: [],
- info: {}
- };
- var reDo = null;
- var shortcut = core.getLocalStorage('shortcut',{48: 0, 49: 0, 50: 0, 51: 0, 52: 0, 53: 0, 54: 0, 55: 0, 56: 0, 57: 0});
- document.body.onkeydown = function (e) {
-
- // 监听Ctrl+S保存
- if (e.ctrlKey && e.keyCode == 83) {
- e.preventDefault();
- if (editor_multi.id != "") {
- editor_multi.confirm(); // 保存脚本编辑器
- }
- else if (editor_blockly.id != "") {
- editor_blockly.confirm(); // 保存事件编辑器
- }
- else {
- editor_mode.saveFloor();
- }
- return;
- }
-
- // 如果是开启事件/脚本编辑器状态,则忽略
- if (editor_multi.id!="" || editor_blockly.id!="")
- return;
-
- // 禁止快捷键的默认行为
- if (e.ctrlKey && [89, 90, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1)
- e.preventDefault();
- 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()) {
- 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));
- editor.updateMap();
- reDo = JSON.parse(JSON.stringify(currDrawData));
- currDrawData = {pos: [], info: {}};
- editor.preMapData = null;
- }
- //Ctrl+y 重做一步redo
- 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));
-
- editor.updateMap();
- currDrawData = JSON.parse(JSON.stringify(reDo));
- reDo = null;
- }
-
- // PGUP和PGDOWN切换楼层
- if (e.keyCode==33) {
- e.preventDefault();
- var index=editor.core.floorIds.indexOf(editor.currentFloorId);
- if (index0) {
- var toId = editor.core.floorIds[index-1];
- editor_mode.onmode('nextChange');
- editor_mode.onmode('floor');
- document.getElementById('selectFloor').value = toId;
- editor.changeFloor(toId);
- }
- }
- //ctrl + 0~9 切换到快捷图块
- if (e.ctrlKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1){
- editor.setSelectBoxFromInfo(JSON.parse(JSON.stringify(shortcut[e.keyCode]||0)));
- }
- //alt + 0~9 改变快捷图块
- if (e.altKey && [48, 49, 50, 51, 52, 53, 54, 55, 56, 57].indexOf(e.keyCode) !== -1){
- var infoToSave = JSON.stringify(editor.info||0);
- if(infoToSave==JSON.stringify({}))return;
- shortcut[e.keyCode]=JSON.parse(infoToSave);
- printf('已保存该快捷图块, ctrl + '+(e.keyCode-48)+' 使用.')
- core.setLocalStorage('shortcut',shortcut);
- }
- var focusElement = document.activeElement;
- if (!focusElement || focusElement.tagName.toLowerCase()=='body') {
- // wasd平移大地图
- if (e.keyCode==87)
- editor.moveViewport(0,-1)
- else if (e.keyCode==65)
- editor.moveViewport(-1,0)
- else if (e.keyCode==83)
- editor.moveViewport(0,1);
- else if (e.keyCode==68)
- editor.moveViewport(1,0);
- }
- }
-
- var getScrollBarHeight = function () {
- var outer = document.createElement("div");
- outer.style.visibility = "hidden";
- outer.style.width = "100px";
- outer.style.msOverflowStyle = "scrollbar"; // needed for WinJS apps
-
- document.body.appendChild(outer);
-
- var widthNoScroll = outer.offsetWidth;
- // force scrollbars
- outer.style.overflow = "scroll";
-
- // add innerdiv
- var inner = document.createElement("div");
- inner.style.width = "100%";
- outer.appendChild(inner);
-
- var widthWithScroll = inner.offsetWidth;
-
- // remove divs
- outer.parentNode.removeChild(outer);
-
- return widthNoScroll - widthWithScroll;
- }
- var scrollBarHeight = getScrollBarHeight();
-
- var dataSelection = document.getElementById('dataSelection');
- var iconLib=document.getElementById('iconLib');
- iconLib.onmousedown = function (e) {
- e.stopPropagation();
- if (!editor.isMobile && e.clientY>=((core.__SIZE__==13?630:655) - scrollBarHeight)) return;
- var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
- var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
- var loc = {
- 'x': scrollLeft + e.clientX + iconLib.scrollLeft - right.offsetLeft - iconLib.offsetLeft,
- 'y': scrollTop + e.clientY + iconLib.scrollTop - right.offsetTop - iconLib.offsetTop,
- 'size': 32
- };
- editor.loc = loc;
- var pos = locToPos(loc);
- for (var spriter in editor.widthsX) {
- if (pos.x >= editor.widthsX[spriter][1] && pos.x < editor.widthsX[spriter][2]) {
- var ysize = spriter.indexOf('48') === -1 ? 32 : 48;
- loc.ysize = ysize;
- pos.images = editor.widthsX[spriter][0];
- pos.y = ~~(loc.y / loc.ysize);
- if(core.tilesets.indexOf(pos.images)==-1)pos.x = editor.widthsX[spriter][1];
- var autotiles = core.material.images['autotile'];
- if (pos.images == 'autotile') {
- var imNames = Object.keys(autotiles);
- if ((pos.y + 1) * ysize > editor.widthsX[spriter][3])
- pos.y = ~~(editor.widthsX[spriter][3] / ysize) - 4;
- else {
- for (var i = 0; i < imNames.length; i++) {
- if (pos.y >= 4 * i && pos.y < 4 * (i + 1)) {
- pos.images = imNames[i];
- pos.y = 4 * i;
- }
- }
- }
- } else if ((pos.y + 1) * ysize > editor.widthsX[spriter][3])
- pos.y = ~~(editor.widthsX[spriter][3] / ysize) - 1;
-
- 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';
- dataSelection.style.height = ysize - 6 + 'px';
-
- if (pos.x == 0 && pos.y == 0) {
- // editor.info={idnum:0, id:'empty','images':'清除块', 'y':0};
- editor.info = 0;
- } else if(pos.x == 0 && pos.y == 1){
- editor.info = editor.ids[editor.indexs[17]];
- } else {
- if (Object.prototype.hasOwnProperty.call(autotiles, pos.images)) editor.info = {'images': pos.images, 'y': 0};
- else if (pos.images == 'terrains') editor.info = {'images': pos.images, 'y': pos.y - 2};
- else if (core.tilesets.indexOf(pos.images)!=-1) editor.info = {'images': pos.images, 'y': pos.y, 'x': pos.x-editor.widthsX[spriter][1]};
- else editor.info = {'images': pos.images, 'y': pos.y};
-
- for (var ii = 0; ii < editor.ids.length; ii++) {
- if ((core.tilesets.indexOf(pos.images)!=-1 && editor.info.images == editor.ids[ii].images
- && editor.info.y == editor.ids[ii].y && editor.info.x == editor.ids[ii].x)
- || (Object.prototype.hasOwnProperty.call(autotiles, pos.images) && editor.info.images == editor.ids[ii].id
- && editor.info.y == editor.ids[ii].y)
- || (core.tilesets.indexOf(pos.images)==-1 && editor.info.images == editor.ids[ii].images
- && editor.info.y == editor.ids[ii].y )
- ) {
-
- editor.info = editor.ids[ii];
- break;
- }
- }
- }
- tip.infos(JSON.parse(JSON.stringify(editor.info)));
- editor_mode.onmode('nextChange');
- editor_mode.onmode('enemyitem');
- //editor_mode.enemyitem();
- }
- }
- }
-
- var midMenu=document.getElementById('midMenu');
- midMenu.oncontextmenu=function(e){e.preventDefault()}
- editor.lastRightButtonPos=[{x:0,y:0},{x:0,y:0}];
- editor.showMidMenu=function(x,y){
- editor.lastRightButtonPos=JSON.parse(JSON.stringify(
- [editor.pos,editor.lastRightButtonPos[0]]
- ));
- var locStr='('+editor.lastRightButtonPos[1].x+','+editor.lastRightButtonPos[1].y+')';
- var scrollLeft = document.documentElement.scrollLeft || document.body.scrollLeft;
- var scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
-
- // 检测是否是上下楼
- var thisevent = editor.map[editor.pos.y][editor.pos.x];
- if (thisevent.id=='upFloor') {
- addFloorEvent.style.display='block';
- addFloorEvent.children[0].innerHTML='绑定上楼事件';
- }
- else if (thisevent.id=='downFloor') {
- addFloorEvent.style.display='block';
- addFloorEvent.children[0].innerHTML='绑定下楼事件';
- }
- else addFloorEvent.style.display='none';
-
- chooseThis.children[0].innerHTML='选中此点'+'('+editor.pos.x+','+editor.pos.y+')'
- copyLoc.children[0].innerHTML='复制事件'+locStr+'到此处';
- moveLoc.children[0].innerHTML='交换事件'+locStr+'与此事件的位置';
- midMenu.style='top:'+(y+scrollTop)+'px;left:'+(x+scrollLeft)+'px;';
- }
- editor.hideMidMenu=function(){
- if(editor.isMobile){
- setTimeout(function(){
- midMenu.style='display:none';
- },200)
- } else {
- midMenu.style='display:none';
- }
- }
-
- var addFloorEvent = document.getElementById('addFloorEvent');
- addFloorEvent.onmousedown = function(e) {
- editor.hideMidMenu();
- e.stopPropagation();
- var thisevent = editor.map[editor.pos.y][editor.pos.x];
- if (thisevent.id=='upFloor') {
- editor.currentFloorData.changeFloor[editor.pos.x+","+editor.pos.y] = {"floorId": ":next", "stair": "downFloor"};
- }
- else if (thisevent.id=='downFloor') {
- editor.currentFloorData.changeFloor[editor.pos.x+","+editor.pos.y] = {"floorId": ":before", "stair": "upFloor"};
- }
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf('添加楼梯事件成功');
- editor.drawPosSelection();
- editor_mode.showMode('loc');
- });
- }
-
- var chooseThis = document.getElementById('chooseThis');
- chooseThis.onmousedown = function(e){
- editor.hideMidMenu();
- e.stopPropagation();
- selectBox.isSelected(false);
-
- editor_mode.onmode('nextChange');
- editor_mode.onmode('loc');
- //editor_mode.loc();
- //tip.whichShow(1);
- if(editor.isMobile)editor.showdataarea(false);
- }
-
- var chooseInRight = document.getElementById('chooseInRight');
- chooseInRight.onmousedown = function(e){
- editor.hideMidMenu();
- e.stopPropagation();
- var thisevent = editor[editor.layerMod][editor.pos.y][editor.pos.x];
- editor.setSelectBoxFromInfo(thisevent);
- }
-
- var fields = Object.keys(editor.file.comment._data.floors._data.loc._data);
-
- var copyLoc = document.getElementById('copyLoc');
- copyLoc.onmousedown = function(e){
- editor.hideMidMenu();
- e.stopPropagation();
- editor.preMapData = null;
- reDo = null;
- editor_mode.onmode('');
- var now = editor.pos;
- var last = editor.lastRightButtonPos[1];
- var lastevent = editor.map[last.y][last.x];
- var lastinfo = 0;
- if(lastevent==0){
- lastinfo = 0;
- } else {
- var ids=editor.indexs[lastevent.idnum];
- ids=ids[0]?ids[0]:ids;
- lastinfo=editor.ids[ids];
- }
- editor.map[now.y][now.x]=lastinfo;
- editor.updateMap();
- fields.forEach(function(v){
- editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y]
- })
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf('复制事件成功');
- editor.drawPosSelection();
- });
- }
-
- var moveLoc = document.getElementById('moveLoc');
- moveLoc.onmousedown = function(e){
- editor.hideMidMenu();
- e.stopPropagation();
- editor.preMapData = null;
- reDo = null;
- var thisevent = editor.map[editor.pos.y][editor.pos.x];
- if(thisevent==0){
- editor.info = 0;
- } else {
- var ids=editor.indexs[thisevent.idnum];
- ids=ids[0]?ids[0]:ids;
- editor.info=editor.ids[ids];
- }
- editor_mode.onmode('');
- var now = editor.pos;
- var last = editor.lastRightButtonPos[1];
-
- var lastevent = editor.map[last.y][last.x];
- var lastinfo = 0;
- if(lastevent==0){
- lastinfo = 0;
- } else {
- var ids=editor.indexs[lastevent.idnum];
- ids=ids[0]?ids[0]:ids;
- lastinfo=editor.ids[ids];
- }
- editor.map[last.y][last.x]=editor.info;
- editor.map[now.y][now.x]=lastinfo;
- editor.updateMap();
-
- fields.forEach(function(v){
- var temp_atsfcytaf=editor.currentFloorData[v][now.x+','+now.y];
- editor.currentFloorData[v][now.x+','+now.y]=editor.currentFloorData[v][last.x+','+last.y];
- editor.currentFloorData[v][last.x+','+last.y]=temp_atsfcytaf;
- })
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf('两位置的事件已互换');
- editor.drawPosSelection();
- });
- }
-
- var _clearPoint = function (clearPoint) {
- editor.hideMidMenu();
- editor.preMapData = null;
- reDo = null;
- editor.info = 0;
- editor_mode.onmode('');
- var now = editor.pos;
- if (clearPoint)
- editor.map[now.y][now.x]=editor.info;
- editor.updateMap();
- fields.forEach(function(v){
- delete editor.currentFloorData[v][now.x+','+now.y];
- })
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf(clearPoint?'清空该点和事件成功':'只清空该点事件成功');
- editor.drawPosSelection();
- });
- }
-
- var clearEvent = document.getElementById('clearEvent');
- clearEvent.onmousedown = function (e) {
- e.stopPropagation();
- _clearPoint(false);
- }
-
- var clearLoc = document.getElementById('clearLoc');
- clearLoc.onmousedown = function(e){
- e.stopPropagation();
- _clearPoint(true);
- }
-
- var brushMod=document.getElementById('brushMod');
- brushMod.onchange=function(){
- editor.brushMod=brushMod.value;
- }
-
- var brushMod2=document.getElementById('brushMod2');
- if(brushMod2)brushMod2.onchange=function(){
- editor.brushMod=brushMod2.value;
- }
-
- var brushMod3=document.getElementById('brushMod3');
- if(brushMod3)brushMod3.onchange=function(){
- editor.brushMod=brushMod3.value;
- }
-
- var bgc = document.getElementById('bg'), fgc = document.getElementById('fg'),
- evc = document.getElementById('event'), ev2c = document.getElementById('event2');
-
- var layerMod=document.getElementById('layerMod');
- layerMod.onchange=function(){
- editor.layerMod=layerMod.value;
- [bgc,fgc,evc,ev2c].forEach(function (x) {
- x.style.opacity = 1;
- });
-
- // 手机端....
- if (editor.isMobile) {
- if (layerMod.value == 'bgmap') {
- [fgc,evc,ev2c].forEach(function (x) {
- x.style.opacity = 0.3;
- });
- }
- if (layerMod.value == 'fgmap') {
- [bgc,evc,ev2c].forEach(function (x) {
- x.style.opacity = 0.3;
- });
- }
- }
- }
-
- var layerMod2=document.getElementById('layerMod2');
- if(layerMod2)layerMod2.onchange=function(){
- editor.layerMod=layerMod2.value;
- [fgc,evc,ev2c].forEach(function (x) {
- x.style.opacity = 0.3;
- });
- bgc.style.opacity = 1;
- }
-
- var layerMod3=document.getElementById('layerMod3');
- if(layerMod3)layerMod3.onchange=function(){
- editor.layerMod=layerMod3.value;
- [bgc,evc,ev2c].forEach(function (x) {
- x.style.opacity = 0.3;
- });
- fgc.style.opacity = 1;
- }
-
- var viewportButtons=document.getElementById('viewportButtons');
- for(var ii=0,node;node=viewportButtons.children[ii];ii++){
- (function(x,y){
- node.onclick=function(){
- editor.moveViewport(x,y);
- }
- })([-1,0,0,1][ii],[0,-1,1,0][ii]);
- }
-}
-
-editor.constructor.prototype.mobile_listen=function () {
- if(!editor.isMobile)return;
-
- var mobileview=document.getElementById('mobileview');
- var editModeSelect=document.getElementById('editModeSelect');
- var mid=document.getElementById('mid');
- var right=document.getElementById('right');
- var mobileeditdata=document.getElementById('mobileeditdata');
-
-
- editor.showdataarea=function(callShowMode){
- mid.style='z-index:-1;opacity: 0;';
- right.style='z-index:-1;opacity: 0;';
- mobileeditdata.style='';
- if(callShowMode)editor.mode.showMode(editModeSelect.value);
- editor.hideMidMenu();
- }
- mobileview.children[0].onclick=function(){
- editor.showdataarea(true)
- }
- mobileview.children[1].onclick=function(){
- mid.style='';
- right.style='z-index:-1;opacity: 0;';
- mobileeditdata.style='z-index:-1;opacity: 0;';
- editor.lastClickId='';
- }
- mobileview.children[3].onclick=function(){
- mid.style='z-index:-1;opacity: 0;';
- right.style='';
- mobileeditdata.style='z-index:-1;opacity: 0;';
- editor.lastClickId='';
- }
-
-
- var gettrbyid=function(){
- if(!editor.lastClickId)return false;
- thisTr = document.getElementById(editor.lastClickId);
- input = thisTr.children[2].children[0].children[0];
- field = thisTr.children[0].getAttribute('title');
- cobj = JSON.parse(thisTr.children[1].getAttribute('cobj'));
- return [thisTr,input,field,cobj];
- }
- mobileeditdata.children[0].onclick=function(){
- var info = gettrbyid()
- if(!info)return;
- info[1].ondblclick()
- }
- mobileeditdata.children[1].onclick=function(){
- var info = gettrbyid()
- if(!info)return;
- printf(info[2])
- }
- mobileeditdata.children[2].onclick=function(){
- var info = gettrbyid()
- if(!info)return;
- printf(info[0].children[1].getAttribute('title'))
- }
-
- //=====
-
- document.body.ontouchstart=document.body.onmousedown;
- document.body.onmousedown=null;
-
-
- var eui=document.getElementById('eui');
- eui.ontouchstart=eui.onmousedown
- eui.onmousedown=null
- eui.ontouchmove=eui.onmousemove
- eui.onmousemove=null
- eui.ontouchend=eui.onmouseup
- eui.onmouseup=null
-
-
- var chooseThis = document.getElementById('chooseThis');
- chooseThis.ontouchstart=chooseThis.onmousedown
- chooseThis.onmousedown=null
- var chooseInRight = document.getElementById('chooseInRight');
- chooseInRight.ontouchstart=chooseInRight.onmousedown
- chooseInRight.onmousedown=null
- var copyLoc = document.getElementById('copyLoc');
- copyLoc.ontouchstart=copyLoc.onmousedown
- copyLoc.onmousedown=null
- var moveLoc = document.getElementById('moveLoc');
- moveLoc.ontouchstart=moveLoc.onmousedown
- moveLoc.onmousedown=null
- var clearLoc = document.getElementById('clearLoc');
- clearLoc.ontouchstart=clearLoc.onmousedown
- clearLoc.onmousedown=null
-}
-
-}
\ No newline at end of file
diff --git a/_server/editor_unsorted_2.js b/_server/editor_unsorted_2.js
deleted file mode 100644
index ef032c86..00000000
--- a/_server/editor_unsorted_2.js
+++ /dev/null
@@ -1,581 +0,0 @@
-editor_unsorted_2_wrapper=function(editor_mode){
-
- editor_mode.constructor.prototype.listen=function (callback) {
- var newIdIdnum = document.getElementById('newIdIdnum');
- newIdIdnum.children[2].onclick = function () {
- if (newIdIdnum.children[0].value && newIdIdnum.children[1].value) {
- var id = newIdIdnum.children[0].value;
- var idnum = parseInt(newIdIdnum.children[1].value);
- if (!core.isset(idnum)) {
- printe('不合法的idnum');
- return;
- }
- if (!/^[0-9a-zA-Z_]+$/.test(id)) {
- printe('不合法的id,请使用字母、数字或下划线')
- return;
- }
- editor.file.changeIdAndIdnum(id, idnum, editor_mode.info, function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- printe('添加id的idnum成功,请F5刷新编辑器');
- });
- } else {
- printe('请输入id和idnum');
- }
- }
-
- newIdIdnum.children[4].onclick = function () {
- editor.file.autoRegister(editor_mode.info, function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- printe('该列所有剩余项全部自动注册成功,请F5刷新编辑器');
- })
- }
-
- var selectFloor = document.getElementById('selectFloor');
- editor.file.getFloorFileList(function (floors) {
- var outstr = [];
- floors[0].forEach(function (floor) {
- outstr.push(["\n'].join(''));
- });
- selectFloor.innerHTML = outstr.join('');
- selectFloor.value = core.status.floorId;
- selectFloor.onchange = function () {
- editor_mode.onmode('nextChange');
- editor_mode.onmode('floor');
- editor.changeFloor(selectFloor.value);
- }
- });
-
- var saveFloor = document.getElementById('saveFloor');
- editor_mode.saveFloor = function () {
- editor_mode.onmode('');
- editor.file.saveFloorFile(function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- ;printf('保存成功');
- });
- }
- saveFloor.onclick = editor_mode.saveFloor;
-
- var newMap = document.getElementById('newMap');
- var newFileName = document.getElementById('newFileName');
- newMap.onclick = function () {
- if (!newFileName.value) return;
- if (core.floorIds.indexOf(newFileName.value)>=0) {
- printe("该楼层已存在!");
- return;
- }
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(newFileName.value)) {
- printe("楼层名不合法!请使用字母、数字、下划线,且不能以数字开头!");
- return;
- }
- var width = parseInt(document.getElementById('newMapWidth').value);
- var height = parseInt(document.getElementById('newMapHeight').value);
- if (!core.isset(width) || !core.isset(height) || width1000) {
- printe("新建地图的宽高都不得小于"+core.__SIZE__+",且宽高之积不能超过1000");
- return;
- }
-
- editor_mode.onmode('');
- editor.file.saveNewFile(newFileName.value, function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- core.floorIds.push(newFileName.value);
- editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_);
- if (objs_.slice(-1)[0] != null) {
- printe(objs_.slice(-1)[0]);
- throw(objs_.slice(-1)[0])
- }
- ;printe('新建成功,请F5刷新编辑器生效');
- });
- });
- }
-
- var newMaps = document.getElementById('newMaps');
- var newFloors = document.getElementById('newFloors');
- newMaps.onclick = function () {
- if (newFloors.style.display == 'none') newFloors.style.display = 'block';
- else newFloors.style.display = 'none';
- }
-
- var createNewMaps = document.getElementById('createNewMaps');
- createNewMaps.onclick = function () {
- var floorIds = document.getElementById('newFloorIds').value;
- if (!floorIds) return;
- var from = parseInt(document.getElementById('newMapsFrom').value),
- to = parseInt(document.getElementById('newMapsTo').value);
- if (!core.isset(from) || !core.isset(to) || from>to || from<0 || to<0) {
- printe("请输入有效的起始和终止楼层");
- return;
- }
- if (to-from >= 100) {
- printe("一次最多创建99个楼层");
- return;
- }
- var floorIdList = [];
- for (var i = from; i<=to; i++) {
- var floorId = floorIds.replace(/\${(.*?)}/g, function (word, value) {
- return eval(value);
- });
- if (core.floorIds.indexOf(floorId)>=0) {
- printe("要创建的楼层 "+floorId+" 已存在!");
- return;
- }
- if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(floorId)) {
- printe("楼层名 "+floorId+" 不合法!请使用字母、数字、下划线,且不能以数字开头!");
- return;
- }
- if (floorIdList.indexOf(floorId)>=0) {
- printe("尝试重复创建楼层 "+floorId+" !");
- return;
- }
- floorIdList.push(floorId);
- }
-
- var width = parseInt(document.getElementById('newMapsWidth').value);
- var height = parseInt(document.getElementById('newMapsHeight').value);
- if (!core.isset(width) || !core.isset(height) || width1000) {
- printe("新建地图的宽高都不得小于"+core.__SIZE__+",且宽高之积不能超过1000");
- return;
- }
- editor_mode.onmode('');
-
- editor.file.saveNewFiles(floorIdList, from, to, function (err) {
- if (err) {
- printe(err);
- throw(err)
- }
- core.floorIds = core.floorIds.concat(floorIdList);
- editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_);
- if (objs_.slice(-1)[0] != null) {
- printe(objs_.slice(-1)[0]);
- throw(objs_.slice(-1)[0])
- }
- ;printe('批量创建 '+floorIdList[0]+'~'+floorIdList[floorIdList.length-1]+' 成功,请F5刷新编辑器生效');
- });
- });
- }
-
- var ratio = 1;
- var appendPicCanvas = document.getElementById('appendPicCanvas');
- var bg = appendPicCanvas.children[0];
- var source = appendPicCanvas.children[1];
- var source_ctx=source.getContext('2d');
- var picClick = appendPicCanvas.children[2];
- var sprite = appendPicCanvas.children[3];
- var sprite_ctx=sprite.getContext('2d');
- var appendPicSelection = document.getElementById('appendPicSelection');
-
- [source_ctx,sprite_ctx].forEach(function(ctx){
- ctx.mozImageSmoothingEnabled = false;
- ctx.webkitImageSmoothingEnabled = false;
- ctx.msImageSmoothingEnabled = false;
- ctx.imageSmoothingEnabled = false;
- })
-
- var selectAppend = document.getElementById('selectAppend');
- var selectAppend_str = [];
- ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"].forEach(function (image) {
- selectAppend_str.push(["\n'].join(''));
- });
- selectAppend.innerHTML = selectAppend_str.join('');
- selectAppend.onchange = function () {
-
- var value = selectAppend.value;
-
- if (value == 'autotile') {
- editor_mode.appendPic.imageName = 'autotile';
- for (var jj=0;jj<4;jj++) appendPicSelection.children[jj].style = 'display:none';
- if (editor_mode.appendPic.img) {
- sprite.style.width = (sprite.width = editor_mode.appendPic.img.width) / ratio + 'px';
- sprite.style.height = (sprite.height = editor_mode.appendPic.img.height) / ratio + 'px';
- sprite_ctx.clearRect(0, 0, sprite.width, sprite.height);
- sprite_ctx.drawImage(editor_mode.appendPic.img, 0, 0);
- }
- return;
- }
-
- var ysize = selectAppend.value.endsWith('48') ? 48 : 32;
- editor_mode.appendPic.imageName = value;
- var img = core.material.images[value];
- editor_mode.appendPic.toImg = img;
- var num = ~~img.width / 32;
- editor_mode.appendPic.num = num;
- editor_mode.appendPic.index = 0;
- var selectStr = '';
- for (var ii = 0; ii < num; ii++) {
- appendPicSelection.children[ii].style = 'left:0;top:0;height:' + (ysize - 6) + 'px';
- selectStr += '{"x":0,"y":0},'
- }
- editor_mode.appendPic.selectPos = eval('[' + selectStr + ']');
- for (var jj = num; jj < 4; jj++) {
- appendPicSelection.children[jj].style = 'display:none';
- }
- sprite.style.width = (sprite.width = img.width) / ratio + 'px';
- sprite.style.height = (sprite.height = img.height + ysize) / ratio + 'px';
- sprite_ctx.drawImage(img, 0, 0);
- }
- selectAppend.onchange();
-
- var getPixel=editor.util.getPixel
- var setPixel=editor.util.setPixel
-
- var autoAdjust = function (image, callback) {
- var changed = false;
-
- // Step 1: 检测白底
- var tempCanvas = document.createElement('canvas').getContext('2d');
- tempCanvas.canvas.width = image.width;
- tempCanvas.canvas.height = image.height;
- tempCanvas.mozImageSmoothingEnabled = false;
- tempCanvas.webkitImageSmoothingEnabled = false;
- tempCanvas.msImageSmoothingEnabled = false;
- tempCanvas.imageSmoothingEnabled = false;
- tempCanvas.drawImage(image, 0, 0);
- var imgData = tempCanvas.getImageData(0, 0, image.width, image.height);
- var trans = 0, white = 0, black=0;
- for (var i=0;iblack && white>trans*10 && confirm("看起来这张图片是以纯白为底色,是否自动调整为透明底色?")) {
- for (var i=0;iwhite && black>trans*10 && confirm("看起来这张图片是以纯黑为底色,是否自动调整为透明底色?")) {
- for (var i=0;i= num) editor_mode.appendPic.index = ii + 1 - num;
- else editor_mode.appendPic.index++;
- editor_mode.appendPic.selectPos[ii] = pos;
- appendPicSelection.children[ii].style = [
- 'left:', pos.x * 32, 'px;',
- 'top:', pos.y * pos.ysize, 'px;',
- 'height:', pos.ysize - 6, 'px;'
- ].join('');
- }
-
- var appendConfirm = document.getElementById('appendConfirm');
- appendConfirm.onclick = function () {
-
- var confirmAutotile = function () {
- var image = editor_mode.appendPic.img;
- if (image.width % 96 !=0 || image.height != 128) {
- printe("不合法的Autotile图片!");
- return;
- }
- var imgData = source_ctx.getImageData(0,0,image.width,image.height);
- sprite_ctx.putImageData(imgData, 0, 0);
- var imgbase64 = sprite.toDataURL().split(',')[1];
-
- // Step 1: List文件名
- fs.readdir('./project/images', function (err, data) {
- if (err) {
- printe(err);
- throw(err);
- }
-
- // Step 2: 选择Autotile文件名
- var filename;
- for (var i=1;;++i) {
- filename = 'autotile'+i;
- if (data.indexOf(filename+".png")==-1) break;
- }
-
- // Step 3: 写入文件
- fs.writeFile('./project/images/'+filename+".png", imgbase64, 'base64', function (err, data) {
- if (err) {
- printe(err);
- throw(err);
- }
- // Step 4: 自动注册
- editor_file.registerAutotile(filename, function (err) {
- if (err) {
- printe(err);
- throw(err);
- }
- printe('自动元件'+filename+'注册成功,请F5刷新编辑器');
- })
-
- })
-
- })
-
- }
-
- if (selectAppend.value == 'autotile') {
- confirmAutotile();
- return;
- }
-
- var ysize = selectAppend.value.endsWith('48') ? 48 : 32;
- for (var ii = 0, v; v = editor_mode.appendPic.selectPos[ii]; ii++) {
- // var imgData = source_ctx.getImageData(v.x * 32, v.y * ysize, 32, ysize);
- // sprite_ctx.putImageData(imgData, ii * 32, sprite.height - ysize);
- // sprite_ctx.drawImage(editor_mode.appendPic.img, v.x * 32, v.y * ysize, 32, ysize, ii * 32, height, 32, ysize)
-
- sprite_ctx.drawImage(source_ctx.canvas, v.x*32, v.y*ysize, 32, ysize, 32*ii, sprite.height - ysize, 32, ysize);
- }
- var dt = sprite_ctx.getImageData(0, 0, sprite.width, sprite.height);
- var imgbase64 = sprite.toDataURL().split(',')[1];
- fs.writeFile('./project/images/' + editor_mode.appendPic.imageName + '.png', imgbase64, 'base64', function (err, data) {
- if (err) {
- printe(err);
- throw(err)
- }
- printe('追加素材成功,请F5刷新编辑器,或继续追加当前素材');
- sprite.style.height = (sprite.height = (sprite.height+ysize)) + "px";
- sprite_ctx.putImageData(dt, 0, 0);
- });
- }
-
- var editModeSelect = document.getElementById('editModeSelect');
- editModeSelect.onchange = function () {
- editor_mode.onmode('nextChange');
- editor_mode.onmode(editModeSelect.value);
- if(editor.isMobile)editor.showdataarea(false);
- }
-
- editor_mode.checkUnique = function (thiseval) {
- if (!(thiseval instanceof Array)) return false;
- var map = {};
- for (var i = 0; i 目前状态: 按功能分类已基本完成, 未完成file/game的重写
+
+总体思路
+ 按功能拆分文件
+ 左侧页面模块化, 方便添加
+ 不同的模式的文件操作尽可能模块化
+目前主要在重构editor_file, 思路是editor.file负责把editor.game内的游戏数据格式化成字符串以及写入到文件, 由editor.game来修改数据
++ editor.file维护一些标记, 描述哪些数据需要格式化并写入, 在save时写入文件(自动保存的话就是每次修改数据都触发save)
++ editor.game修改数据, 并修改editor.file中的标记
++ 此思路下editor.file的大部分内容会挪到editor.game, editor.game和editor.table可能会再进一步合并拆分
+
+editor_file之后是更改editor.map的储存方式, 现有的存对象的模式要在对象和数字间来回转换, 非常繁琐和奇怪
## 文件结构
+(全部小写,必要时用下划线分割)
+
+ [ ] 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_file 调用fs.js编辑文件, 把原editor\_file模块化, 并且只负责文件写入
++ [ ] editor_game 处理游戏数据, 导入为editor的数据, 编辑数据, 从原editor和editor_file中抽离. **只有此文件允许`\s(main|core)`形式的调用**(以及其初始化`editor_game_wrapper(editor, main, core);`)
++ [x] editor_util 生成guid/处理颜色 等函数, 从editor分离
++ [ ] editor_listen 处理界面上的按钮/下拉框点击等用户的操作与功能函数的绑定, 维护editor.dom, unsorted_1/2中的绑定挪到此处, 其中的函数内容, 分类放在其他文件
++ [ ] editor_mappanel 与地图区相关的功能, <-unsorted_1/2/3
++ [ ] editor_datapanel 与数据区相关的功能, <-unsorted_1/2/3
++ [ ] editor_materialpanel 与素材区相关的功能, <-unsorted_1/2/3
++ [ ] editor_ui 维护printe/printf/tip, 以及之后可能的窗口化, ui事件中没有具体到前三个区中的函数 <-unsorted_1/2/3
+ [ ] editor 执行初始化流程加组合各组件
+ [ ] 原editor_mode 移除
+ [x] 原vm 移除
@@ -51,7 +67,7 @@ editor: {
+ 地图的编辑与其他(如全塔属性和楼层属性), 现在的文件操作的模式是完全不同的
楼层文件的储存与其他不同
-+ editor.file在修改时不再返回obj和commentobj,只在查询时返回
++ [x] editor.file在修改时不再返回obj和commentobj,只在查询时返回
+ editor.file中的各个条目, 非常相似, 但是细节的不同处理非常麻烦. 是类似的代码复制后修改一部分, 尝试模块化(或者重写)
@@ -61,9 +77,13 @@ editor: {
+ 目前editor.map中储存的是info\
色相:
@@ -100,7 +103,7 @@
-
+
+
+
+
@@ -186,6 +201,7 @@
-->
@@ -208,6 +225,10 @@
+
+
+
+ 开启中文名替换
@@ -226,6 +247,7 @@
语法检查
+
@@ -288,10 +310,16 @@
-
+
+
+