diff --git a/API列表.txt b/API列表.txt index 4bbd2864..71fa3a6b 100644 --- a/API列表.txt +++ b/API列表.txt @@ -230,9 +230,10 @@ core.onmove(loc) 注册的onmove交互函数需要接受x, y, px, py四个参数,代表当前的的位置和像素坐标。 -core.onup() -当从屏幕上离开时的操作。请注意此函数是没有参数的。 +core.onup(loc) +当从屏幕上离开时的操作。loc为当前的坐标信息。 请勿直接覆盖或调用此函数,如有需要请注册一个"onup"的交互函数。 +注册的onup交互函数需要接受x, y, px, py四个参数,代表当前的的位置和像素坐标。 core.onclick(x, y) @@ -253,7 +254,7 @@ core.keyDownCtrl() core.longClick() 当长按住屏幕时执行的操作。 -请勿直接覆盖或调用此函数,如有需要请注册一个"keyDownCtrl"的交互函数。 +请勿直接覆盖或调用此函数,如有需要请注册一个"longClick"的交互函数。 注册的交互函数如果某一项返回true,则之后仍然会继续触发该长按, 如果全部返回false则将停止本次长按行为,直到手指离开屏幕并重新进行长按为止。 ``` diff --git a/README.md b/README.md index 0b5d5987..e4811ade 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,21 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2019.12.31 HTML5魔塔样板V2.6.6 + +* [x] 编辑器增加【最近使用的图块】的区域 +* [x] 编辑器拉伸到铺满全屏幕,还可以Ctrl+滚轮放缩 +* [x] 编辑器支持连续Ctrl+Z的撤销,Ctrl+Y的重做 +* [x] 新增tileset右键绑定宽高,以替代贴图模式 +* [x] 多重自动存档,可以连续A键读档 +* [x] 等待用户操作增设分歧选项 +* [x] 增设压缩模式,会对图片等进行zip压缩 +* [x] 追加素材现在可以同时进行自动注册 +* [x] 可以复制和粘贴怪物或道具的属性 +* [x] 折叠素材时设置每一列个数 +* [x] 标题界面和显示选择项时光标跟随鼠标 +* [x] 修复所有已知的bug,大量细节优化 + ### 2019.12.1 HTML5魔塔样板V2.6.5 * [x] 事件:设置怪物属性;穿脱装备 diff --git a/_docs/V2.0.md b/_docs/V2.0.md index 8e468781..00d1084e 100644 --- a/_docs/V2.0.md +++ b/_docs/V2.0.md @@ -1,6 +1,6 @@ # V2.0版本介绍 -?> 目前版本**v2.6.5*,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6*,上次更新时间:* {docsify-updated} * 目前样板已经更新到V2.0版本以上,本章将对V2.0的一些内容进行介绍。 diff --git a/_docs/api.md b/_docs/api.md index 4b938e8d..4e2125e3 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -1,6 +1,6 @@ # 附录:API列表 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。 @@ -1624,6 +1624,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为真,则会执行该动画所对应的回调函数。 @@ -2166,7 +2172,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 f8197b4f..2b386a88 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 diff --git a/_docs/event.md b/_docs/event.md index 899978e8..cce0cbe6 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 @@ -486,7 +486,8 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ![](img/events/13.jpg) -从V2.6.5开始,默认`addValue`不会刷新状态栏、地图显伤和自动事件,除非设置了`"refresh": true`。 +从V2.6.5开始,当设置了`"norefresh": true`后可以不刷新状态栏、地图显伤和自动事件,从而加速事件执行。 + 在刷新的情况下,如果hp被设置成了0或以下,将触发lose事件,直接死亡。 @@ -509,7 +510,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ![](img/events/14.jpg) -从V2.6.5开始,默认`addValue`不会刷新状态栏、地图显伤和自动事件,除非设置了`"refresh": true`。 +从V2.6.5开始,当设置了`"norefresh": true`后可以不刷新状态栏、地图显伤和自动事件,从而加速事件执行。 ### setEnemy:设置怪物属性 @@ -1963,6 +1964,31 @@ yes和no均为必填项,即用户点击确认或取消后执行的事件。 ![](img/events/52.jpg) +从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": "当点击地图左上角时执行此事件"}, + ]}, + ]}, +] +``` + +![](img/events/52.png) + +`data`是一个数组,每一项中,case只能为`keyboard`和`mouse`二选一,分别对应键盘和鼠标(即`type=0`和`type=1`)。 + +如果是键盘,则可以指定`keycode`为键盘的按键内容;否则指定`px`和`py`为点击的像素区间。 + +action为如果满足该条件时应该执行的事件列表。 + + + ### waitAsync:等待所有异步事件执行完毕 上面有很多很多的异步事件(也就是执行时不等待执行完毕)。 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/index.md b/_docs/index.md index e427c4e6..d3943d2c 100644 --- a/_docs/index.md +++ b/_docs/index.md @@ -1,6 +1,6 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 diff --git a/_docs/personalization.md b/_docs/personalization.md index 7b6dd439..ca4755ae 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 diff --git a/_docs/script.md b/_docs/script.md index a700fd5b..76903d02 100644 --- a/_docs/script.md +++ b/_docs/script.md @@ -1,6 +1,6 @@ # 脚本 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。 diff --git a/_docs/start.md b/_docs/start.md index a49d99ac..880bfd08 100644 --- a/_docs/start.md +++ b/_docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.6.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6.6**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index c309d06d..e436f5d6 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -589,27 +589,27 @@ return code; */; setValue_s - : '数值操作' ':' '名称' idString_e '值' expression '刷新状态栏和显伤' Bool 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 colour : this.dataColor -Bool_0 = Bool_0 ? ', "refresh": true' : ''; +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 '刷新状态栏和显伤' Bool 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 colour : this.dataColor -Bool_0 = Bool_0 ? ', "refresh": true' : ''; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; var code = '{"type": "addValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"' + Bool_0 + '},\n'; return code; */; @@ -1988,18 +1988,56 @@ return code; wait_s - : '等待用户操作并获得按键或点击信息' + : '等待用户操作并获得按键或点击信息' BGNL? Newline waitContext* BEND Newline /* wait_s -tooltip : wait: 等待用户操作并获得按键或点击信息(具体用法看文档) +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 : '等待所有异步事件执行完毕' @@ -3398,7 +3436,7 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['setValue_s'].xmlText([ this.tryToUseEvFlag_e('idString_e', [data.name]), MotaActionBlocks['evalString_e'].xmlText([data.value]), - data.refresh || false, + data.norefresh || false, this.next]); break; case "setValue2": @@ -3406,7 +3444,7 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['addValue_s'].xmlText([ this.tryToUseEvFlag_e('idString_e', [data.name]), MotaActionBlocks['evalString_e'].xmlText([data.value]), - data.refresh || false, + data.norefresh || false, this.next]); break; case "setEnemy": @@ -3547,8 +3585,22 @@ ActionParser.prototype.parseAction = function() { data.time||0,data.noSkip||false,this.next]); break; case "wait": // 等待用户操作 + var case_waitList = null; + if (data.data) { + for(var ii=data.data.length-1,caseNow;caseNow=data.data[ii];ii--) { + if (caseNow["case"] == "keyboard") { + case_waitList = MotaActionBlocks['waitContext_1'].xmlText([ + caseNow.keycode || 0, this.insertActionList(caseNow.action), case_waitList + ]); + } else if (caseNow["case"] == "mouse") { + case_waitList = MotaActionBlocks['waitContext_2'].xmlText([ + caseNow.px[0], caseNow.px[1], caseNow.py[0], caseNow.py[1], this.insertActionList(caseNow.action), case_waitList + ]); + } + } + } this.next = MotaActionBlocks['wait_s'].xmlText([ - this.next]); + case_waitList, this.next]); break; case "waitAsync": // 等待所有异步事件执行完毕 this.next = MotaActionBlocks['waitAsync_s'].xmlText([ diff --git a/_server/css/editor.css b/_server/css/editor.css index 92172a43..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; diff --git a/_server/css/editor_mobile.css b/_server/css/editor_mobile.css index 40e28ff1..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; } diff --git a/_server/css/editor_mode.css b/_server/css/editor_mode.css index d521a617..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 > * { diff --git a/_server/editor.js b/_server/editor.js index 252b8e4b..525f8abe 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -8,6 +8,7 @@ function editor() { 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'), @@ -26,9 +27,13 @@ function editor() { brushMod2:document.getElementById('brushMod2'), brushMod3:document.getElementById('brushMod3'), bgc : document.getElementById('bg'), + bgCtx : document.getElementById('bg').getContext('2d'), fgc : document.getElementById('fg'), - evc : document.getElementById('event'), + 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'), @@ -46,6 +51,10 @@ function editor() { 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'), }; this.uivalues={ @@ -56,12 +65,9 @@ function editor() { startPos:null, endPos:null, // 撤销/恢复 - currDrawData : { - pos: [], - info: {} - }, - reDo : null, - preMapData : null, + preMapData : [], + preMapMax: 10, + postMapData: [], // shortcut:{}, copyedInfo : null, @@ -82,8 +88,19 @@ function editor() { loc: null, n: -1, enemys: [] - } + }, + // 复制怪物或道具属性 + copyEnemyItem : { + type: null, + data: {} + }, + + // tile + tileSize: [1,1], + + // 最近使用的图块 + lastUsed: [], }; window.onerror = function (msg, url, lineNo, columnNo, error) { @@ -155,7 +172,9 @@ editor.prototype.init = function (callback) { editor_mode = editor_mode(editor); editor.mode = editor_mode; core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.clone(core.initStatus.maps)); - core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function () { + var lastFloorId = core.getLocalStorage('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); @@ -205,9 +224,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++) { @@ -240,7 +259,8 @@ editor.prototype.changeFloor = function (floorId, callback) { }); editor.currentFloorData[name]=mapArray; } - editor.uivalues.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 () { editor.game.fetchMapFromCore(); @@ -252,6 +272,7 @@ editor.prototype.changeFloor = function (floorId, callback) { var loc = editor.viewportLoc[floorId] || [], x = loc[0] || 0, y = loc[1] || 0; editor.setViewport(x, y); + core.setLocalStorage('editorLastFloorId', floorId); if (callback) callback(); }); } @@ -259,7 +280,7 @@ editor.prototype.changeFloor = function (floorId, 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(); @@ -310,7 +331,7 @@ editor.prototype.drawEventBlock = function () { 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); @@ -362,20 +383,43 @@ 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.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) { + var x = i % core.__SIZE__, y = parseInt(i / core.__SIZE__); + var info = editor.uivalues.lastUsed[i]; + if (!info || !info.images) continue; + if (info.isTile) { + 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') { + 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); + } + } } editor.prototype.setViewport=function (x, y) { @@ -402,8 +446,9 @@ editor.prototype.drawInitData = function (icons) { editor.widthsX = {}; editor.uivalues.folded = core.getLocalStorage('folded', false); // editor.uivalues.folded = true; - editor.uivalues.foldPerCol = 50; + editor.uivalues.foldPerCol = core.getLocalStorage('foldPerCol', 50); // var imgNames = Object.keys(images); //还是固定顺序吧; + editor.uivalues.lastUsed = core.getLocalStorage("lastUsed", []); var imgNames = ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"]; for (var ii = 0; ii < imgNames.length; ii++) { @@ -596,7 +641,10 @@ editor.prototype.setSelectBoxFromInfo=function(thisevent){ 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);}); + setTimeout(function(){ + selectBox.isSelected(true); + editor.updateLastUsedMap(); + }); editor.info = JSON.parse(JSON.stringify(thisevent)); tip.infos(JSON.parse(JSON.stringify(thisevent))); editor.pos=pos; diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 29630e30..f40b7fb9 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -163,7 +163,10 @@ 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(), @@ -219,10 +222,10 @@ editor_blockly = function () { ], '值块':[ MotaActionBlocks['addValue_s'].xmlText([ - MotaActionBlocks['idString_1_e'].xmlText(['status','生命']) + MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false ]), MotaActionBlocks['setValue_s'].xmlText([ - MotaActionBlocks['idString_1_e'].xmlText(['status','生命']) + MotaActionBlocks['idString_1_e'].xmlText(['status','生命']), '', false ]), MotaActionBlocks['expression_arithmetic_0'].xmlText(), MotaActionBlocks['evFlag_e'].xmlText(), @@ -689,14 +692,20 @@ function omitedcheckUpdateFunction(event) { "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" + "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); - // console.log(obj); - if (obj.length > 0 && b.type.startsWith(obj[0].type)) { + 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]]); diff --git a/_server/editor_datapanel.js b/_server/editor_datapanel.js index 08678104..948ce9c0 100644 --- a/_server/editor_datapanel.js +++ b/_server/editor_datapanel.js @@ -210,7 +210,57 @@ editor_datapanel_wrapper = function (editor) { } } + 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请再重新选中该道具方可查看更新后的表格。"); + }) + } + } + + } + + + } @@ -490,7 +540,7 @@ editor_datapanel_wrapper = function (editor) { } //画灰白相间的格子 - var bgc = editor.dom.bg.getContext('2d'); + var bgc = editor.dom.bgCtx; var colorA = ["#f8f8f8", "#cccccc"]; var colorIndex; var sratio = 4; @@ -586,6 +636,8 @@ editor_datapanel_wrapper = function (editor) { editor.uifunctions.appendConfirm_func = function () { + var appendRegister = document.getElementById('appendRegister'); + var appendConfirm = document.getElementById('appendConfirm'); appendConfirm.onclick = function () { @@ -648,15 +700,29 @@ editor_datapanel_wrapper = function (editor) { 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().split(',')[1]; - fs.writeFile('./project/images/' + editor_mode.appendPic.imageName + '.png', imgbase64, 'base64', function (err, data) { + 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) } - printf('追加素材成功,你可以继续追加其他素材,最后再刷新以显示在素材区'); - editor.dom.sprite.style.height = (editor.dom.sprite.height = (editor.dom.sprite.height + ysize)) + "px"; + 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('追加素材成功!你可以继续追加其他素材,最后再刷新以使用。'); + } }); } @@ -679,15 +745,29 @@ editor_datapanel_wrapper = function (editor) { } dt = editor.dom.spriteCtx.getImageData(0, 0, editor.dom.sprite.width, editor.dom.sprite.height); - var imgbase64 = editor.dom.sprite.toDataURL().split(',')[1]; - fs.writeFile('./project/images/' + editor_mode.appendPic.imageName + '.png', imgbase64, 'base64', function (err, data) { + 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) } - printf('快速追加素材成功,你可以继续追加其他素材,最后再刷新以显示在素材区'); - editor.dom.sprite.style.height = (editor.dom.sprite.height = (editor.dom.sprite.height + ysize)) + "px"; + 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('快速追加素材成功!你可以继续追加其他素材,最后再刷新以使用。'); + } }); } diff --git a/_server/editor_file_unsorted.js b/_server/editor_file_unsorted.js index c11bd4d8..7ee709c8 100644 --- a/_server/editor_file_unsorted.js +++ b/_server/editor_file_unsorted.js @@ -897,6 +897,8 @@ editor_file = function (editor, callback) { callback('出错了,要设置的文件名不识别'); } + editor.file.saveSetting = saveSetting; + return editor_file; } //editor_file = editor_file(editor); \ No newline at end of file diff --git a/_server/editor_legacy.js b/_server/editor_legacy.js index 7242553c..35e5518d 100644 --- a/_server/editor_legacy.js +++ b/_server/editor_legacy.js @@ -216,7 +216,7 @@ tip.showHelp = function(value) { '双击事件编辑器的图块可以进行长文本编辑/脚本编辑/地图选点/UI绘制预览等操作', 'ESC或点击空白处可以自动保存当前修改', 'H键可以打开操作帮助哦', - 'tileset贴图模式下可以按选中tileset素材,并在地图上拖动来一次绘制一个区域', + 'tileset贴图模式可以在地图上拖动来一次绘制一个区域;右键额外素材也可以绑定宽高', '可以拖动地图上的图块和事件,或按Ctrl+C, Ctrl+X和Ctrl+V进行复制,剪切和粘贴,Delete删除', 'Alt+数字键保存图块,数字键读取保存的图块', ]; diff --git a/_server/editor_listen.js b/_server/editor_listen.js index dec2bc2f..e4668d9a 100644 --- a/_server/editor_listen.js +++ b/_server/editor_listen.js @@ -24,6 +24,7 @@ editor_listen_wrapper = function (editor) { 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 @@ -33,6 +34,8 @@ editor_listen_wrapper = function (editor) { 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.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; @@ -133,6 +136,7 @@ editor_listen_wrapper = function (editor) { editor.uifunctions.newIdIdnum_func() editor.uifunctions.changeId_func() + editor.uifunctions.copyPasteEnemyItem_func(); editor.uifunctions.selectFloor_func() editor.uifunctions.saveFloor_func() diff --git a/_server/editor_mappanel.js b/_server/editor_mappanel.js index 953cd7b1..c25f3e68 100644 --- a/_server/editor_mappanel.js +++ b/_server/editor_mappanel.js @@ -206,7 +206,7 @@ editor_mappanel_wrapper = function (editor) { } editor.uivalues.holdingPath = 0; if (editor.uivalues.stepPostfix && editor.uivalues.stepPostfix.length) { - editor.uivalues.preMapData = JSON.parse(JSON.stringify({ map: editor.map, fgmap: editor.fgmap, bgmap: editor.bgmap })); + editor.savePreMap(); if (editor.brushMod !== 'line') { var x0 = editor.uivalues.stepPostfix[0].x; var y0 = editor.uivalues.stepPostfix[0].y; @@ -221,11 +221,20 @@ editor_mappanel_wrapper = function (editor) { } } } - editor.uivalues.currDrawData.pos = JSON.parse(JSON.stringify(editor.uivalues.stepPostfix)); - editor.uivalues.currDrawData.info = JSON.parse(JSON.stringify(editor.info)); - editor.uivalues.reDo = null; - // console.log(editor.uivalues.stepPostfix); - if (editor.brushMod === 'tileset' && core.tilesets.indexOf(editor.info.images) !== -1) { + 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; @@ -242,6 +251,10 @@ editor_mappanel_wrapper = function (editor) { 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})); + core.setLocalStorage("lastUsed", editor.uivalues.lastUsed); + } editor.updateMap(); editor.uivalues.holdingPath = 0; editor.uivalues.stepPostfix = []; @@ -511,8 +524,7 @@ editor_mappanel_wrapper = function (editor) { editor.uifunctions.copyLoc_click = function (e) { editor.uifunctions.hideMidMenu(); e.stopPropagation(); - editor.uivalues.preMapData = null; - editor.uivalues.reDo = null; + editor.savePreMap(); editor_mode.onmode(''); var now = editor.pos, last = editor.uivalues.lastRightButtonPos[1]; if (now.x == last.x && now.y == last.y) return; @@ -535,8 +547,7 @@ editor_mappanel_wrapper = function (editor) { editor.uifunctions.moveLoc_click = function (e) { editor.uifunctions.hideMidMenu(); e.stopPropagation(); - editor.uivalues.preMapData = null; - editor.uivalues.reDo = null; + editor.savePreMap(); editor_mode.onmode(''); editor.exchangePos(editor.pos, editor.uivalues.lastRightButtonPos[1]); } @@ -547,7 +558,6 @@ editor_mappanel_wrapper = function (editor) { */ editor.uifunctions.clearEvent_click = function (e) { e.stopPropagation(); - editor.uivalues.reDo = null; editor.clearPos(false); } @@ -557,7 +567,6 @@ editor_mappanel_wrapper = function (editor) { */ editor.uifunctions.clearLoc_click = function (e) { e.stopPropagation(); - editor.uivalues.reDo = null; editor.clearPos(true); } @@ -582,6 +591,7 @@ editor_mappanel_wrapper = function (editor) { * 切换画笔模式 */ editor.uifunctions.brushMod3_onchange = function () { + alert("从V2.6.6开始,tileset贴图模式已被废弃。\n请右键额外素材,并输入所需要绘制的宽高,然后单击地图以绘制一个区域。"); // tip.showHelp(5) tip.isSelectedBlock(false) tip.msgs[11] = String('tileset贴图模式下可以按选中tileset素材,并在地图上拖动来一次绘制一个区域'); @@ -705,6 +715,20 @@ editor_mappanel_wrapper = function (editor) { 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; + } + ///////////////////////////////////////////////////////////////////////////// @@ -768,6 +792,21 @@ editor_mappanel_wrapper = function (editor) { 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; @@ -809,7 +848,7 @@ editor_mappanel_wrapper = function (editor) { var fields = Object.keys(editor.file.comment._data.floors._data.loc._data); pos = pos || editor.pos; editor.uifunctions.hideMidMenu(); - editor.uivalues.preMapData = null; + editor.savePreMap(); editor.info = 0; editor_mode.onmode(''); if (clearPos) @@ -843,7 +882,4 @@ editor_mappanel_wrapper = function (editor) { - - - } \ No newline at end of file diff --git a/_server/editor_materialpanel.js b/_server/editor_materialpanel.js index 2ba50d82..6b81cf1e 100644 --- a/_server/editor_materialpanel.js +++ b/_server/editor_materialpanel.js @@ -29,10 +29,18 @@ editor_materialpanel_wrapper = function (editor) { * editor.dom.iconExpandBtn.onclick */ editor.uifunctions.fold_material_click = function () { - if (confirm(editor.uivalues.folded ? "你想要展开素材吗?\n展开模式下将显示全素材内容。" - : ("你想要折叠素材吗?\n折叠模式下每个素材将仅显示单列,并且每" + editor.uivalues.foldPerCol + "个自动换列。"))) { - core.setLocalStorage('folded', !editor.uivalues.folded); - window.location.reload(); + if (editor.uivalues.folded) { + if (confirm("你想要展开素材吗?\n展开模式下将显示全素材内容。")) { + core.setLocalStorage('folded', false); + window.location.reload(); + } + } else { + var perCol = parseInt(prompt("请输入折叠素材模式下每列的个数:", "50")) || 0; + if (perCol > 0) { + core.setLocalStorage('foldPerCol', perCol); + core.setLocalStorage('folded', true); + window.location.reload(); + } } } @@ -42,6 +50,7 @@ editor_materialpanel_wrapper = function (editor) { */ 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; @@ -51,6 +60,7 @@ editor_materialpanel_wrapper = function (editor) { '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]) { @@ -118,10 +128,26 @@ editor_materialpanel_wrapper = function (editor) { 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(); } } diff --git a/_server/editor_table.js b/_server/editor_table.js index b2e8cf3f..c21220fd 100644 --- a/_server/editor_table.js +++ b/_server/editor_table.js @@ -293,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); diff --git a/_server/editor_ui.js b/_server/editor_ui.js index a82601e3..ad37245e 100644 --- a/_server/editor_ui.js +++ b/_server/editor_ui.js @@ -49,7 +49,7 @@ editor_ui_wrapper = function (editor) { } } if (unselect) { - if (clickpath.indexOf('eui') === -1) { + if (clickpath.indexOf('eui') === -1 && clickpath.indexOf('lastUsed') === -1) { if (selectBox.isSelected()) { editor_mode.onmode(''); editor.file.saveFloorFile(function (err) { @@ -81,14 +81,14 @@ editor_ui_wrapper = function (editor) { editor.uifunctions.body_shortcut = function (e) { // UI预览 & 地图选点 - if (uievent && uievent.isOpen) { + if (editor.uievent && editor.uievent.isOpen) { e.preventDefault(); - if (e.keyCode == 27) uievent.close(); - else if (e.keyCode == 13) uievent.confirm(); - else if (e.keyCode == 87) uievent.move(0, -1) - else if (e.keyCode == 65) uievent.move(-1, 0) - else if (e.keyCode == 83) uievent.move(0, 1); - else if (e.keyCode == 68) uievent.move(1, 0); + 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; } @@ -111,29 +111,6 @@ editor_ui_wrapper = function (editor) { if (editor_multi.id != "" || editor_blockly.id != "") return; - //Ctrl+z 撤销上一步undo - if (e.keyCode == 90 && e.ctrlKey && editor.uivalues.preMapData && editor.uivalues.currDrawData.pos.length && selectBox.isSelected()) { - editor.map = JSON.parse(JSON.stringify(editor.uivalues.preMapData.map)); - editor.fgmap = JSON.parse(JSON.stringify(editor.uivalues.preMapData.fgmap)); - editor.bgmap = JSON.parse(JSON.stringify(editor.uivalues.preMapData.bgmap)); - editor.updateMap(); - editor.uivalues.reDo = JSON.parse(JSON.stringify(editor.uivalues.currDrawData)); - editor.uivalues.currDrawData = { pos: [], info: {} }; - editor.uivalues.preMapData = null; - return; - } - //Ctrl+y 重做一步redo - if (e.keyCode == 89 && e.ctrlKey && editor.uivalues.reDo && editor.uivalues.reDo.pos.length && selectBox.isSelected()) { - editor.uivalues.preMapData = JSON.parse(JSON.stringify({ map: editor.map, fgmap: editor.fgmap, bgmap: editor.bgmap })); - for (var j = 0; j < editor.uivalues.reDo.pos.length; j++) - editor.map[editor.uivalues.reDo.pos[j].y][editor.uivalues.reDo.pos[j].x] = JSON.parse(JSON.stringify(editor.uivalues.reDo.info)); - - editor.updateMap(); - editor.uivalues.currDrawData = JSON.parse(JSON.stringify(editor.uivalues.reDo)); - editor.uivalues.reDo = null; - return; - } - // PGUP和PGDOWN切换楼层 if (e.keyCode == 33 || e.keyCode == 34) { e.preventDefault(); @@ -151,7 +128,37 @@ editor_ui_wrapper = function (editor) { var focusElement = document.activeElement; if (!focusElement || focusElement.tagName.toLowerCase() == 'body' - || focusElement.id == 'selectFloor') { + || 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(); diff --git a/_server/table/comment.js b/_server/table/comment.js index 6e549b88..20783952 100644 --- a/_server/table/comment.js +++ b/_server/table/comment.js @@ -143,7 +143,7 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_leaf": true, "_type": "textarea", "_range": "thiseval==null || thiseval instanceof Array || (thiseval==~~thiseval && thiseval>=0)", - "_data": "特殊属性\n\n0:无,1:先攻,2:魔攻,3:坚固,4:2连击,\n5:3连击,6:n连击,7:破甲,8:反击,9:净化,\n10:模仿,11:吸血,12:中毒,13:衰弱,14:诅咒,\n15:领域,16:夹击,17:仇恨,18:阻击,19:自爆,\n20:无敌,21:退化,22:固伤,23:重生,24:激光,25:光环\n\n多个属性例如用[1,4,11]表示先攻2连击吸血" + "_data": "特殊属性\n\n0:无,1:先攻,2:魔攻,3:坚固,4:2连击,\n5:3连击,6:n连击,7:破甲,8:反击,9:净化,\n10:模仿,11:吸血,12:中毒,13:衰弱,14:诅咒,\n15:领域,16:夹击,17:仇恨,18:阻击,19:自爆,\n20:无敌,21:退化,22:固伤,23:重生,24:激光,25:光环\n26:支援,27:捕捉\n多个属性例如用[1,4,11]表示先攻2连击吸血" }, "value": { "_leaf": true, diff --git a/editor-mobile.html b/editor-mobile.html index fe371abd..d586ea90 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -77,6 +77,7 @@ + 自动注册

色相: @@ -135,6 +136,10 @@ +

+ + +
@@ -308,6 +313,12 @@
+