diff --git a/.gitignore b/.gitignore index b10100fd..b866a27a 100644 --- a/.gitignore +++ b/.gitignore @@ -56,3 +56,5 @@ fabric.properties node_modules package-lock.json + +_saves diff --git a/README.md b/README.md index b5c6c71f..872a268e 100644 --- a/README.md +++ b/README.md @@ -65,6 +65,22 @@ HTML5 canvas制作的魔塔样板,支持全平台游戏! ## 更新说明 +### 2021.9.1 HTML5魔塔样板V2.8.2 + +* [x] 在游戏中,可以在大地图长按后拖动预览。(超大地图福音!) +* [x] 编辑器支持快速选层操作,还可以搜索楼层。 +* [x] 离线游戏存档本地化,将直接存入本地的_saves目录。 +* [x] 支持播放存档剩余录像(接续播放录像的简化版本)。 +* [x] 编辑器中自绘状态栏支持直接预览。 +* [x] 可以以当前素材为模板追加新素材并修改色调。 +* [x] 对话框支持不等待用户操作,从而可做多对话框。 +* [x] 事件:设置勇士不透明度;同时移除显示和隐藏勇士事件。 +* [x] 在sample2层新增了大怪物使用样例。 +* [x] 大幅提升了高层塔加载的加载速度。 +* [x] 增加了高清显伤。 +* [x] 修复素材区折叠对齐的问题。 +* [x] 修复所有已知问题,大量细节优化。 + ### 2021.8.14 HTML5魔塔样板V2.8.1 * [x] 支持任意尺寸和任意朝向的怪物和NPC素材。 diff --git a/_docs/api.md b/_docs/api.md index 8513751f..94635318 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -56,7 +56,6 @@ core.platform core.platform.isPC (是否是电脑端) core.platform.isAndroid (是否是安卓端) core.platform.isIOS (是否是iOS端) -core.platform.useLocalForage (是否开启了新版存档) core.domStyle @@ -318,9 +317,6 @@ status: 只能为 stop, leftFoot 和 rightFoot,不填用stop。 offset: 相对主角逻辑位置的偏移量,不填视为无偏移。 frame: 绘制的第几帧 -fillPosWithPoint: fn(pos?: ?) -显示离散的寻路点 - gatherFollowers: fn() 立刻聚集所有的跟随者 @@ -611,6 +607,9 @@ noGather: 是否聚集跟随者 setHeroMoveInterval: fn(callback?: fn()) 设置行走的效果动画 +setHeroOpacity: fn(opacity?: number, moveMode?: string, time?: number, callback?: fn()) +改变勇士的不透明度 + setMusicBtn: fn() 设置音乐图标的显隐状态 @@ -683,9 +682,6 @@ triggerDebuff: fn(action: string, type: string|[string]) action: 要获得还是移除,'get'为获得,'remove'为移除 type: 获得或移除的内容(poison/weak/curse),可以为字符串或数组 -triggerHero: fn(type?: string, time?: number, callback?: fn()) -改变勇士的显隐状态 - triggerReplay: fn() 播放或暂停录像回放 @@ -1213,6 +1209,9 @@ seed: 随机种子,相同的种子保证了录像的可重复性 route: 经由base64压缩后的录像,用于从头开始的录像回放 callback: 回调函数,可选 +stopAsync: fn() +立刻停止所有正在进行的异步事件 + trigger: fn(x?: number, y?: number, callback?: fn()) 触发(x,y)点的系统事件;会执行该点图块的script属性,同时支持战斗(会触发战后)、道具(会触发道具后)、楼层切换等等 callback: 执行完毕的回调函数 @@ -1810,9 +1809,9 @@ showFloorImage: fn(loc?: [number]|[[number]], floorId?: string, callback?: fn()) stairExists: fn(x: number, y: number, floorId?: string) -> bool 某个点是否存在楼梯 -stopAnimate: fn(id: number, doCallback?: bool) +stopAnimate: fn(id?: number, doCallback?: bool) 立刻停止一个动画播放 -id: 播放动画的编号,即drawAnimate或drawHeroAnimate的返回值 +id: 播放动画的编号,即drawAnimate或drawHeroAnimate的返回值;不填视为停止所有动画 doCallback: 是否执行该动画的回调函数 terrainExists: fn(x: number, y: number, id?: string, floorId?: string) -> bool @@ -1999,7 +1998,7 @@ getToolboxItems: fn(cls: string) -> [string] loadCanvas: fn(name: string|CanvasRenderingContext2D) 加载某个canvas状态 -relocateCanvas: fn(name: string, x: number, y: number) +relocateCanvas: fn(name: string, x: number, y: number, useDelta: bool) 重新定位一个自定义画布 resizeCanvas: fn(name: string, x: number, y: number) diff --git a/_docs/element.md b/_docs/element.md index 22e2a058..f392ff0d 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -308,7 +308,7 @@ V2.8.1新增了怪物的大贴图绑定,编辑器1:1模式下大贴图会被 4. **额外素材:**`project/tilesets`中的文件名(需要后缀,只支持png)。 * 注册方法同上,最大的区别在于这个数组的顺序必须保持好。如果随意调换其中的顺序,或注销不在数组末尾的图片,就会导致地图上最终呈现的素材发生错位。因此,新勾选的图片总会被自动追加到数组的末尾。 * 比起常规素材,额外素材最大的好处有几点: - 1. 图片没有数量限制。常规素材的总数量最多只允许不到一万个,而额外素材每张图片上的图块数量最多允许一千个。 + 1. 图片没有数量限制。常规素材的总数量最多只允许不到10000个,而额外素材每张图片上的图块数量最多允许3000个。 2. 查看和绘制更为方便。常规素材每个图块独占一行,每列为一帧,导致不方便观察,且用多个图块拼图必须逐图块绘制。额外素材都是静止的,所以每个图块只占一格,多个图块可以在准备素材时就直接以相邻的样子绘制在同一张图片上,绘制地图时直接从素材区拖动来批量框选,再在地图区单击成片绘制或拖动平铺。 3. 批量替换也更为方便。譬如您如果想制作形如“一场大战/天灾过后/多年以后,村庄/城镇化为了一片废墟”的效果,可以预先准备两张甚至更多张相同规格的额外素材图片,然后在适当的时候遍历某个/某些楼层的图块ID,将以“X1”开头的图块统一替换为“X2”开头等。发布单机版游戏时,您也可以提供多张相同规格的额外素材图片供玩家直接替换皮肤风格。 5. **使用动画:**`project/animates`文件夹中的文件名(不含后缀,请注意与`animates.png`相区分)。 diff --git a/_docs/instruction.md b/_docs/instruction.md index 790473dd..6c48588a 100644 --- a/_docs/instruction.md +++ b/_docs/instruction.md @@ -581,8 +581,8 @@ core.insertAction({"type": "changeFloor", "floorId": "MT" + core.rand2(20)}) * V2.8.1起,支持暂时锁定视角,视角锁定期间,只有上下楼后才会将视角重置到勇士身上(但依然保持锁定)。 4. **显隐状态栏:**如题,如果隐藏状态栏期间勇士需要恢复行动,则建议不隐藏竖屏工具栏以方便手机玩家。 * 实际调用`core.showStatusBar()`和`core.hideStatusBar(showToolbox)` -5. **显隐勇士:**如题,动画时间为淡入淡出时间,异步勾选框用法如前。 - * 实际调用`core.triggerHero(type, time, callback)` +5. **设置勇士不透明度:**如题,动画时间为淡入淡出时间,异步勾选框用法如前。 + * 实际调用`core.setHeroOpacity(opacity, moveMode, time, callback)` 6. **更改画面色调:**色调可以用调色器调配,“动画时间”为渐变的总时间。 * 请注意渐变是在RGBA颜色空间中直线运动(V2.8.1支持加速度),因此效果可能不好,画面闪烁同理。 * 如需在勇士自由行动时反复执行,请使用并行脚本或自我回调。 diff --git a/_docs/script.md b/_docs/script.md index 3c5495cb..e6333c5f 100644 --- a/_docs/script.md +++ b/_docs/script.md @@ -215,7 +215,7 @@ function () { ``` registerAction: fn(action: string, name: string, func: string|fn(params: ?), priority?: number) 此函数将注册一个用户交互行为。 -action: 要注册的交互类型,如 ondown, onclick, keyDown 等等。 +action: 要注册的交互类型,如 ondown, onup, keyDown 等等。 name: 你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。 func: 执行函数。 如果func返回true,则不会再继续执行其他的交互函数;否则会继续执行其他的交互函数。 @@ -228,8 +228,8 @@ priority: 优先级;优先级高的将会被执行。此项可不填,默认 ```js // 当flag:abc是true时,点击屏幕左上角可以使用道具破墙镐 -// 注入一个 onclick 事件,名称为 my_pickaxe -core.registerAction('onclick', 'my_pickaxe', function (x, y, px, py) { +// 注入一个 ondown 事件,名称为 my_pickaxe +core.registerAction('ondown', 'my_pickaxe', function (x, y, px, py) { // 如果当前正在执行某个事件,则忽略之。 if (core.status.lockControl) return false; // 如果勇士正在行走中,则忽略之。 @@ -251,7 +251,7 @@ core.registerAction('onclick', 'my_pickaxe', function (x, y, px, py) { }, 100); // 当你不再需要上述监听时,可以通过下面这一句取消注入。 -// core.unregisterActon('onclick', 'my_pickaxe'); +// core.unregisterActon('ondown', 'my_pickaxe'); ``` 下面是另一个例子: @@ -339,12 +339,8 @@ core.registerAction('longClick', 'my_shop', '_my_shop_longClick', 100); - 如果是触摸屏,则只有手指按下滑动时才会触发`onmove`(并不存在什么悬浮的说法)。 - `onup`: 当屏幕被鼠标或手指放开时 - 对应的函数参数:`function (x, y, px, py)`,为此时放开时的格子坐标和像素坐标。 -- `onclick`: 当屏幕被鼠标或手机点击时 - - 对应的函数参数:`function (x, y, px, py, stepPostfix)`,为此时点击的格子坐标、像素坐标,和拖动路径 - - 此函数会在两种情况下被调用: - - 在锁定状态下(即角色不可以自由移动),会在`ondown`时直接触发`onclick`,此时`stepPostfix`为空数组。 - - 在自由状态下(即角色可以自由移动),会在`onup`时触发`onclick`;此时`stepPostfix`为拖动寻路的路径数组。 - - 推荐自定义的点击监听都使用`ondown`处理。 +- `onclick` 【已废弃】 + - 从V2.8.2起,此交互已被废弃,注册一个`onclick`会被直接转发至`ondown`。 - `onmousewheel`: 当鼠标滚轮滚动时 - 对应的函数参数:`function (direct)`,为此时滚轮方向。向下滚动是-1,向上滚动是1。 - 目前在楼传、怪物手册、存读档、浏览地图等多个地方绑定了鼠标滚轮事件。 diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index 0f4a426c..9eb4de71 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -1824,7 +1824,6 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "isPC": "bool", "isAndroid": "bool", "isIOS": "bool", - "useLocalForage": "bool" }, "domStyle": { "!doc": "界面样式", @@ -2240,9 +2239,9 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "半自动寻路,用于鼠标或手指拖动
例如:core.setAutomaticRoute(0, 0, [{direction: \"right\", x: 4, y: 9}, {direction: \"right\", x: 5, y: 9}]);
destX: 鼠标或手指的起拖点横坐标
destY: 鼠标或手指的起拖点纵坐标
stepPostfix: 拖动轨迹的数组表示,每项为一步的方向和目标点。", "!type": "fn(destX: number, destY: number, stepPostfix: [{x: number, y: number, direction: string}])" }, - "triggerHero": { - "!doc": "改变勇士的显隐状态", - "!type": "fn(type?: string, time?: number, callback?: fn())" + "setHeroOpacity": { + "!doc": "改变勇士的不透明度", + "!type": "fn(opacity?: number, moveMode?: string, time?: number, callback?: fn())" }, "gatherFollowers": { "!doc": "立刻聚集所有的跟随者", @@ -2344,10 +2343,6 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "连续行走
例如:core.setAutoHeroMove([{direction: \"up\", step: 1}, {direction: \"left\", step: 3}]); // 上左左左
steps: 压缩的步伐数组,每项表示朝某方向走多少步", "!type": "fn(steps: [?])" }, - "fillPosWithPoint": { - "!doc": "显示离散的寻路点", - "!type": "fn(pos?: ?)" - }, "unregisterResize": { "!doc": "注销一个resize函数", "!type": "fn(name: string)" @@ -3086,8 +3081,8 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(name: string, callback?: fn()) -> number" }, "stopAnimate": { - "!doc": "立刻停止一个动画播放
id: 播放动画的编号,即drawAnimate或drawHeroAnimate的返回值
doCallback: 是否执行该动画的回调函数", - "!type": "fn(id: number, doCallback?: bool)" + "!doc": "立刻停止一个动画播放
id: 播放动画的编号,即drawAnimate或drawHeroAnimate的返回值;不填视为所有动画br/>doCallback: 是否执行该动画的回调函数", + "!type": "fn(id?: number, doCallback?: bool)" }, "getPlayingAnimates": { "!doc": "获得当前正在播放的所有(指定)动画的id列表
name: 动画名;不填代表返回全部正在播放的动画
返回值: 一个数组,每一项为一个正在播放的动画;可用core.stopAnimate停止播放。", @@ -3525,7 +3520,7 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ }, "relocateCanvas": { "!doc": "重新定位一个自定义画布", - "!type": "fn(name: string, x: number, y: number)" + "!type": "fn(name: string, x: number, y: number, useDelta: bool)" }, "rotateCanvas": { "!doc": "设置一个自定义画布的旋转角度
centerX, centerY: 旋转中心(以屏幕像素为基准);不填视为图片正中心。", @@ -3840,6 +3835,10 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "当前是否有未处理完毕的异步事件(不包含动画和音效)", "!type": "fn() -> bool" }, + "stopAsync": { + "!doc": "立刻停止所有正在进行的异步事件", + "!type": "fn()" + }, "openEquipbox": { "!doc": "点击装备栏时的打开操作", "!type": "fn(fromUserAction?: bool)" diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 2aff6d8d..dc9a423b 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -636,8 +636,8 @@ return '{' + [ mainStyle_m - : '主要样式设置:' '标题界面背景图(554x422):' EvalString BGNL? Newline - '竖屏标题界面背景图(422x580)' EvalString BGNL? Newline + : '主要样式设置:' '标题界面背景图:' EvalString BGNL? Newline + '竖屏标题界面背景图:' EvalString BGNL? Newline '标题样式;可写 display: none 隐藏标题' EvalString BGNL? Newline '标题按钮样式:' EvalString BGNL? Newline '横屏状态栏背景;url(...) 0 0/100% 100% no-repeat 可将图片拉伸自适配' BGNL? Newline EvalString BGNL? Newline @@ -847,11 +847,11 @@ action | update_s | showStatusBar_s | hideStatusBar_s - | showHero_s - | hideHero_s + | setHeroOpacity_s | sleep_s | wait_s | waitAsync_s + | stopAsync_s | battle_s | battle_1_s | openDoor_s @@ -870,6 +870,7 @@ action | unfollow_s | animate_s | animate_1_s + | stopAnimate_s | vibrate_s | showImage_s | showImage_1_s @@ -969,7 +970,7 @@ return code+',\n'; */; text_1_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? '对话框编号' Int BGNL? Newline EvalString_Multi Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点 px' PosString? 'py' PosString? '宽' PosString? '编号' Int '不等待操作' Bool BGNL? Newline EvalString_Multi Newline /* text_1_s @@ -977,7 +978,7 @@ tooltip : text:显示一段文字(剧情),选项较多请右键点击帮 helpUrl : /_docs/#/instruction previewBlock : true allIds : ['EvalString_1'] -default : ["小妖精","fairy","","","","",0,"欢迎使用事件编辑器(双击方块可直接预览)"] +default : ["小妖精","fairy","","","","",0,false,"欢迎使用事件编辑器(双击方块可直接预览)"] var title=''; if (EvalString_0==''){ if (EvalString_1=='' )title=''; @@ -998,10 +999,11 @@ if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.t } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos || Int_0) { +if (block.isCollapsed() || !block.isEnabled() || pos || Int_0 || Bool_0) { code = '{"type": "text", "text": '+code; if (pos) code += ', "pos": ' + pos; if (Int_0) code += ', "code": ' + Int_0; + if (Bool_0) code += ', "async": true'; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; @@ -1010,7 +1012,7 @@ return code+',\n'; */; text_2_s - : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点像素 px' PosString? 'py' PosString? '宽度' PosString? '对话框编号' Int BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline + : '标题' EvalString? '图像' EvalString? '对话框效果' EvalString? '起点 px' PosString? 'py' PosString? '宽' PosString? '编号' Int '不等待操作' Bool BGNL? Newline EvalString_Multi BGNL? Newline textDrawingList* Newline /* text_2_s @@ -1039,10 +1041,11 @@ if(EvalString_2 && !(/^(up|center|down|hero|this)(,(hero|null|\d+,\d+|\d+))?$/.t } EvalString_2 = EvalString_2 && ('\\b['+EvalString_2+']'); var code = '"'+title+EvalString_2+textDrawingList_0.replace(/\s/g, '')+EvalString_Multi_0+'"'; -if (block.isCollapsed() || !block.isEnabled() || pos || Int_0) { +if (block.isCollapsed() || !block.isEnabled() || pos || Int_0 || Bool_0) { code = '{"type": "text", "text": '+code; if (pos) code += ', "pos": ' + pos; if (Int_0) code += ', "code": ' + Int_0; + if (Bool_0) code += ', "async": true'; if (block.isCollapsed()) code += ', "_collapsed": true'; if (!block.isEnabled()) code += ', "_disabled": true'; code += '}'; @@ -1255,19 +1258,20 @@ return code; setEnemy_s - : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List AssignOperator_List expression Newline + : '设置怪物属性' ':' '怪物ID' IdString '的' EnemyId_List AssignOperator_List expression '不刷新显伤' Bool Newline /* setEnemy_s tooltip : setEnemy:设置某个怪物的属性 helpUrl : /_docs/#/instruction -default : ["greenSlime", "atk", "="] +default : ["greenSlime", "atk", "=", "", false] allEnemys : ['IdString_0'] colour : this.dataColor if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; } else AssignOperator_List_0 = ''; -var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"},\n'; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; +var code = '{"type": "setEnemy", "id": "'+IdString_0+'", "name": "'+EnemyId_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"'+Bool_0+'},\n'; return code; */; @@ -1292,13 +1296,13 @@ return code; setEnemyOnPoint_s - : '设置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '的' EnemyPoint_List AssignOperator_List expression Newline + : '设置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '的' EnemyPoint_List AssignOperator_List expression '不刷新显伤' Bool Newline /* setEnemyOnPoint_s tooltip : setEnemyOnPoint:设置某个点上怪物的属性 helpUrl : /_docs/#/instruction -default : ["", "", "", "atk", "="] +default : ["", "", "", "atk", "=", "", false] selectPoint : ["EvalString_0", "EvalString_1", "IdString_0"] allFloorIds : ['IdString_0'] colour : this.dataColor @@ -1307,35 +1311,37 @@ if (AssignOperator_List_0 && AssignOperator_List_0 != '=') { AssignOperator_List_0 = ', "operator": "' + AssignOperator_List_0 + '"'; } else AssignOperator_List_0 = ''; IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -var code = '{"type": "setEnemyOnPoint"'+floorstr+IdString_0+', "name": "'+EnemyPoint_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"},\n'; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; +var code = '{"type": "setEnemyOnPoint"'+floorstr+IdString_0+', "name": "'+EnemyPoint_List_0+'"'+AssignOperator_List_0+', "value": "'+expression_0+'"'+Bool_0+'},\n'; return code; */; resetEnemyOnPoint_s - : '重置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? Newline + : '重置某点怪物属性' ':' 'x' EvalString? ',' 'y' EvalString? '楼层' IdString? '不刷新显伤' Bool Newline /* resetEnemyOnPoint_s tooltip : resetEnemyOnPoint:重置某个点上怪物的属性 helpUrl : /_docs/#/instruction -default : ["", "", ""] +default : ["", "", "", false] selectPoint : ["EvalString_0", "EvalString_1", "IdString_0"] allFloorIds : ['IdString_0'] colour : this.dataColor var floorstr = MotaActionFunctions.processMultiLoc(EvalString_0, EvalString_1); IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -var code = '{"type": "resetEnemyOnPoint"'+floorstr+IdString_0+'},\n'; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; +var code = '{"type": "resetEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; return code; */; moveEnemyOnPoint_s - : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '终点' 'x' PosString? 'y' PosString? '楼层' IdString? Newline + : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '终点' 'x' PosString? 'y' PosString? '楼层' IdString? '不刷新显伤' Bool Newline /* moveEnemyOnPoint_s tooltip : moveEnemyOnPoint:移动某个点上怪物的属性到其他点 helpUrl : /_docs/#/instruction -default : ["", "", "", "", ""] +default : ["", "", "", "", "", false] allFloorIds : ['IdString_0'] selectPoint : ["PosString_2", "PosString_3"] menu : [['选择起点位置','editor_blockly.selectPoint(block,["PosString_0", "PosString_1"])']] @@ -1343,25 +1349,27 @@ colour : this.dataColor IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); var floorstr = PosString_0 && PosString_1 ? ', "from": ['+PosString_0+','+PosString_1+']' : ''; if (PosString_2 && PosString_3) floorstr += ', "to": ['+PosString_2+','+PosString_3+']' -var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+'},\n'; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; +var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; return code; */; moveEnemyOnPoint_1_s - : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '增量' 'dx' PosString? 'dy' PosString? '楼层' IdString? Newline + : '移动某点怪物属性' ':' '起点' 'x' PosString? ',' 'y' PosString? '增量' 'dx' PosString? 'dy' PosString? '楼层' IdString? '不刷新显伤' Bool Newline /* moveEnemyOnPoint_1_s tooltip : moveEnemyOnPoint:移动某个点上怪物的属性到其他点 helpUrl : /_docs/#/instruction -default : ["", "", "", "", ""] +default : ["", "", "", "", "", false] allFloorIds : ['IdString_0'] selectPoint : ["PosString_0", "PosString_1"] colour : this.dataColor IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); var floorstr = PosString_0 && PosString_1 ? ', "from": ['+PosString_0+','+PosString_1+']' : ''; if (PosString_2 && PosString_3) floorstr += ', "dxy": ['+PosString_2+','+PosString_3+']' -var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+'},\n'; +Bool_0 = Bool_0 ? ', "norefresh": true' : ''; +var code = '{"type": "moveEnemyOnPoint"'+floorstr+IdString_0+Bool_0+'},\n'; return code; */; @@ -1775,33 +1783,19 @@ var code = '{"type": "hideStatusBar"'+Bool_0+'},\n'; return code; */; -showHero_s - : '显示勇士' '动画时间' IntString? '不等待执行完毕' Bool Newline +setHeroOpacity_s + : '设置勇士不透明度' Number '渐变方式' MoveMode_List '动画时间' IntString? '不等待执行完毕' Bool Newline - -/* showHero_s -tooltip : showHero: 显示勇士 +/* setHeroOpacity_s +tooltip : setHeroOpacity: 设置勇士不透明度 helpUrl : /_docs/#/instruction -default : ['',false] +default : [1,'','',false] colour : this.soundColor +if (Number_0 < 0 || Number_0 > 1) throw new Error('不透明度需要在0~1之间'); +MoveMode_List_0 = (MoveMode_List_0!=='') ? (', "moveMode": "'+MoveMode_List_0+'"'):''; IntString_0 = IntString_0 && (', "time": ' + IntString_0); Bool_0 = Bool_0 ? (', "async": true') : ''; -var code = '{"type": "showHero"'+IntString_0+Bool_0+'},\n'; -return code; -*/; - -hideHero_s - : '隐藏勇士' '动画时间' IntString? '不等待执行完毕' Bool Newline - - -/* hideHero_s -tooltip : hideHero: 隐藏勇士 -helpUrl : /_docs/#/instruction -default : ['',false] -colour : this.soundColor -IntString_0 = IntString_0 && (', "time": ' + IntString_0); -Bool_0 = Bool_0 ? (', "async": true') : ''; -var code = '{"type": "hideHero"'+IntString_0+Bool_0+'},\n'; +var code = '{"type": "setHeroOpacity", "opacity": '+Number_0+MoveMode_List_0+IntString_0+Bool_0+'},\n'; return code; */; @@ -2055,37 +2049,50 @@ return code; */; animate_s - : '显示动画' IdString '位置' 'x' PosString? 'y' PosString? '相对窗口坐标' Bool '不等待执行完毕' Bool Newline + : '显示动画' EvalString '位置' 'x' PosString? 'y' PosString? '相对窗口坐标' Bool '不等待执行完毕' Bool Newline /* animate_s tooltip : animate:显示动画,位置填hero或者1,2形式的位置,或者不填代表当前事件点 helpUrl : /_docs/#/instruction default : ["zone","","",false,false] -allAnimates : ['IdString_0'] -material : ["./project/animates/", "IdString_0"] +allAnimates : ['EvalString_0'] +material : ["./project/animates/", "EvalString_0"] menu : [['选择位置', 'editor_blockly.selectPoint(block, ["PosString_0", "PosString_1"])']] colour : this.soundColor var loc = PosString_0&&PosString_1?(', "loc": ['+PosString_0+','+PosString_1+']'):''; Bool_0 = Bool_0?', "alignWindow": true':''; Bool_1 = Bool_1?', "async": true':''; -var code = '{"type": "animate", "name": "'+IdString_0+'"'+loc+Bool_0+Bool_1+'},\n'; +var code = '{"type": "animate", "name": "'+EvalString_0+'"'+loc+Bool_0+Bool_1+'},\n'; return code; */; animate_1_s - : '显示动画并跟随角色' IdString '不等待执行完毕' Bool Newline + : '显示动画并跟随角色' EvalString '不等待执行完毕' Bool Newline /* animate_1_s tooltip : animate:显示动画并跟随角色 helpUrl : /_docs/#/instruction default : ["zone",false] -allAnimates : ['IdString_0'] -material : ["./project/animates/", "IdString_0"] +allAnimates : ['EvalString_0'] +material : ["./project/animates/", "EvalString_0"] colour : this.soundColor Bool_0 = Bool_0?', "async": true':''; -var code = '{"type": "animate", "name": "'+IdString_0+'", "loc": "hero"'+Bool_0+'},\n'; +var code = '{"type": "animate", "name": "'+EvalString_0+'", "loc": "hero"'+Bool_0+'},\n'; +return code; +*/; + +stopAnimate_s + : '停止所有动画' '执行动画回调' Bool Newline + +/* stopAnimate_s +tooltip : stopAnimate:停止所有动画 +helpUrl : /_docs/#/instruction +default : [false] +colour : this.soundColor +Bool_0 = Bool_0?', "doCallback": true':''; +var code = '{"type": "stopAnimate"'+Bool_0+'},\n'; return code; */; @@ -2804,7 +2811,7 @@ choices_s tooltip : choices: 给用户提供选项 helpUrl : /_docs/#/instruction previewBlock : true -default : ["","流浪者","trader",0,0,''] +default : ["","流浪者","trader",0,''] allIds : ['IdString_0'] var title=''; if (EvalString_0==''){ @@ -3072,6 +3079,19 @@ return code; */; +stopAsync_s + : '立刻结束所有异步事件' BGNL Newline + + +/* stopAsync_s +tooltip : stopAsync: 立刻结束所有异步事件 +helpUrl : /_docs/#/instruction +colour : this.soundColor +var code = '{"type": "stopAsync"},\n'; +return code; +*/; + + callBook_s : '呼出怪物手册' @@ -4034,8 +4054,8 @@ EquipValueType_List /*EquipValueType_List ['value','percentage']*/; Vibrate_List - : '左右'|'上下'|'左上-右下'|'左下-右上' - /*Vibrate_List ['horizontal','vertical','diagonal1','diagonal2']*/; + : '左右'|'上下'|'左上-右下'|'左下-右上'|'随机' + /*Vibrate_List ['horizontal','vertical','diagonal1','diagonal2','random']*/; Colour : 'sdeirughvuiyasdeb'+ //为了被识别为复杂词法规则 @@ -4070,8 +4090,8 @@ Direction_List /*Direction_List ['up','down','left','right']*/; DirectionEx_List - : '不变'|'朝上'|'朝下'|'朝左'|'朝右'|'左转'|'右转'|'背对' - /*DirectionEx_List ['null','up','down','left','right',':left',':right',':back']*/; + : '不变'|'朝上'|'朝下'|'朝左'|'朝右'|'左转'|'右转'|'背对'|'角色同向'|'角色反向' + /*DirectionEx_List ['null','up','down','left','right',':left',':right',':back',':hero',':backhero']*/; StepString : (Direction_List Int?)+ @@ -4110,12 +4130,12 @@ Move_List /*Move_List ['up','down','left','right','forward','backward','leftup','leftdown','rightup','rightdown','speed']*/; MoveMode_List - : '匀速移动'|'缓入快出'|'快入缓出'|'缓入缓出' - /*MoveMode_List ['', 'easeIn', 'easeOut', 'easeInOut']*/; + : '匀速移动'|'缓入快出'|'快入缓出'|'缓入缓出'|'随机' + /*MoveMode_List ['', 'easeIn', 'easeOut', 'easeInOut', 'random']*/; NameMap_List : '确定'|'取消'|'操作失败'|'光标移动'|'打开界面'|'读档'|'存档'|'获得道具'|'回血'|'宝石'|'炸弹'|'飞行器'|'开关门'|'上下楼'|'跳跃'|'破墙镐'|'破冰镐'|'阻激夹域'|'穿脱装备'|'商店' - /*NameMap_List ['确定','取消','操作失败','光标移动','打开界面','读档','存档','获得道具','回血','宝石','炸弹','飞行器','开关门','上下楼','跳跃','破墙镐','破冰稿','阻激夹域','穿脱装备','商店']*/; + /*NameMap_List ['确定','取消','操作失败','光标移动','打开界面','读档','存档','获得道具','回血','宝石','炸弹','飞行器','开关门','上下楼','跳跃','破墙镐','破冰镐','阻激夹域','穿脱装备','商店']*/; //转blockly后不保留需要加" EvalString diff --git a/_server/MotaActionParser.js b/_server/MotaActionParser.js index 7f642a9f..caa2cff1 100644 --- a/_server/MotaActionParser.js +++ b/_server/MotaActionParser.js @@ -292,12 +292,12 @@ ActionParser.prototype.parseAction = function() { } data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_2_s', [ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, info[3], buildTextDrawing(textDrawing), this.next + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, data.async||false, info[3], buildTextDrawing(textDrawing), this.next ], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); } else if (info[0] || info[1] || info[2] || data.pos || data.code) { data.pos = data.pos || []; this.next = MotaActionFunctions.xmlText('text_1_s',[ - info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); + info[0], info[1], info[2], data.pos[0], data.pos[1], data.pos[2], data.code||0, data.async||false, info[3], this.next], /* isShadow */false, /*comment*/ null, /*collapsed*/ data._collapsed, /*disabled*/ data._disabled); } else { this.next = MotaActionFunctions.xmlText('text_0_s', [info[3],this.next], @@ -322,7 +322,7 @@ ActionParser.prototype.parseAction = function() { data.time, data.lineHeight||1.4, data.async||false, this.EvalString_Multi(data.text), this.next]); break; case "comment": // 注释 - this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString_Multi(data.text),this.next],null,data.text); + this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString_Multi(data.text),this.next]); break; case "setText": // 设置剧情文本的属性 data.title=this.Colour(data.title); @@ -559,6 +559,9 @@ ActionParser.prototype.parseAction = function() { data.name,data.loc[0],data.loc[1],data.alignWindow||false,data.async||false,this.next]); } break; + case "stopAnimate": // 停止所有动画 + this.next = MotaActionBlocks['stopAnimate_s'].xmlText([data.doCallback||false,this.next]); + break; case "setViewport": // 设置视角 if (data.dxy) { this.next = MotaActionBlocks['setViewport_1_s'].xmlText([ @@ -750,7 +753,8 @@ ActionParser.prototype.parseAction = function() { break; case "setEnemy": this.next = MotaActionBlocks['setEnemy_s'].xmlText([ - MotaActionFunctions.replaceToName_token(data.id), data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); + MotaActionFunctions.replaceToName_token(data.id), data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), + data.norefresh||false, this.next]); break; case "setEnemyOnPoint": data.loc=data.loc||[]; @@ -762,7 +766,8 @@ ActionParser.prototype.parseAction = function() { y_str.push(t[1]); }) this.next = MotaActionBlocks['setEnemyOnPoint_s'].xmlText([ - x_str.join(','),y_str.join(','),data.floorId||'',data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), this.next]); + x_str.join(','),y_str.join(','),data.floorId||'',data.name, data["operator"]||'=', this.expandEvalBlock([data.value]), + data.norefresh||false, this.next]); break; case "resetEnemyOnPoint": data.loc=data.loc||[]; @@ -774,17 +779,17 @@ ActionParser.prototype.parseAction = function() { y_str.push(t[1]); }) this.next = MotaActionBlocks['resetEnemyOnPoint_s'].xmlText([ - x_str.join(','),y_str.join(','), data.floorId||'',this.next]); + x_str.join(','),y_str.join(','), data.floorId||'',data.norefresh||false,this.next]); break; case "moveEnemyOnPoint": data.from=data.from||['',''] if (data.dxy) { this.next = MotaActionBlocks['moveEnemyOnPoint_1_s'].xmlText([ - data.from[0], data.from[1], data.dxy[0], data.dxy[1], data.floorId||'',this.next]); + data.from[0], data.from[1], data.dxy[0], data.dxy[1], data.floorId||'',data.norefresh||false,this.next]); } else { data.to=data.to||['',''] this.next = MotaActionBlocks['moveEnemyOnPoint_s'].xmlText([ - data.from[0], data.from[1], data.to[0], data.to[1], data.floorId||'',this.next]); + data.from[0], data.from[1], data.to[0], data.to[1], data.floorId||'',data.norefresh||false,this.next]); } break; case "setEquip": @@ -929,13 +934,9 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['hideStatusBar_s'].xmlText([ data.toolbox||false,this.next]); break; - case "showHero": - this.next = MotaActionBlocks['showHero_s'].xmlText([ - data.time, data.async||false, this.next]); - break; - case "hideHero": - this.next = MotaActionBlocks['hideHero_s'].xmlText([ - data.time, data.async||false, this.next]); + case "setHeroOpacity": + this.next = MotaActionBlocks['setHeroOpacity_s'].xmlText([ + data.opacity, data.moveMode, data.time, data.async||false, this.next]); break; case "sleep": // 等待多少毫秒 this.next = MotaActionBlocks['sleep_s'].xmlText([ @@ -971,6 +972,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['waitAsync_s'].xmlText([ data.excludeAnimates||false, data.includeSounds||false, this.next]); break; + case "stopAsync": // 立刻停止所有异步事件 + this.next = MotaActionBlocks['stopAsync_s'].xmlText([ + this.next]); + break; case "callBook": // 呼出怪物手册 this.next = MotaActionBlocks['callBook_s'].xmlText([ this.next]); @@ -1464,7 +1469,7 @@ MotaActionFunctions.PosString_pre = function(PosString){ if (!PosString || /^-?\d+$/.test(PosString)) return PosString; //if (!(MotaActionFunctions.pattern.id.test(PosString)))throw new Error(PosString+'中包含了0-9 a-z A-Z _ 和中文之外的字符,或者是没有以flag: 开头'); var comma = PosString.indexOf(','); - if (comma >= 0 && PosString.substring(0, comma).ifndexOf('(') < 0) throw '此处不可写多点坐标'; + if (comma >= 0 && PosString.substring(0, comma).indexOf('(') < 0) throw '此处不可写多点坐标'; return '"'+MotaActionFunctions.replaceFromName(PosString)+'"'; } diff --git a/_server/css/editor.css b/_server/css/editor.css index 783e27e6..5132f8f2 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -1,5 +1,9 @@ /** editor **/ +:root { + --pixel: 416px; +} + html, body, div, img { margin: 0; padding: 0; @@ -128,15 +132,15 @@ body { position: absolute; left: 448px; top: 10px; - width: 440px; - height: 630px; + width: calc(24px + var(--pixel)); + height: calc(422px + var(--pixel) / 2); } #mid2 { position: absolute; left: 448px; - top: 650px; - width: 440px; + top: calc(442px + var(--pixel) / 2); + width: calc(24px + var(--pixel)); bottom: 10px; } @@ -148,8 +152,8 @@ body { position: absolute; left: 20px; top: 21px; - width: 416px; - height: 416px; + width: var(--pixel); + height: var(--pixel); } #lastUsedDiv { @@ -162,8 +166,8 @@ body { #mid .tools { position: absolute; - width: 425px; - height: 180px; + width: calc(var(--pixel) + 9px); + height: calc(388px - var(--pixel) / 2); left: 0; bottom: 0; padding: 10px 5px; @@ -214,7 +218,7 @@ body { #right { position: absolute; - left: 900px; + left: calc(484px + var(--pixel)); top: 10px; right: 0; bottom: 0; @@ -300,7 +304,7 @@ table.col { #mapColMark { top: 2px; left: 19px; - width: 418px; + width: var(--pixel); height: 16px; font-size: 13px; } @@ -312,7 +316,7 @@ table.col { #mapColMark td:hover .colBlock { position: absolute; top: 19px; - height: 416px; + height: var(--pixel); width: 32px; z-index: 100; } @@ -336,7 +340,7 @@ table.row { top: 1px; left: 2px; width: 16px; - height: 416px; + height: var(--pixel); font-size: 12px; } @@ -348,7 +352,7 @@ table.row { position: absolute; left: 18px; height: 32px; - width: 416px; + width: var(--pixel); z-index: 100; } @@ -421,8 +425,8 @@ table.row { position: fixed; top: 50%; left: 50%; - transform: translate(-50%, -60%); - width: 436px; + transform: translate(-50%, -55%); + width: 560px; } #uieventHead { @@ -444,8 +448,8 @@ table.row { } #uieventBody { - width: 416px; - height: 416px; + width: 540px; + height: 540px; position: relative; margin-left: 10px; margin-bottom: 5px; diff --git a/_server/css/editor_mobile.css b/_server/css/editor_mobile.css index 78604c15..44fe8651 100644 --- a/_server/css/editor_mobile.css +++ b/_server/css/editor_mobile.css @@ -1,5 +1,9 @@ /** editor **/ +:root { + --size: 13; +} + html{ font-size: 4vw; } @@ -276,14 +280,14 @@ table.col, div.col { #mapColMark .coltd, #mapColMark .coltd .coltext { position: absolute; - width: 7.15vw; + width: calc(93vw / var(--size)); height: 4vw; line-height: 4vw; padding: 0; border-bottom-width: 0px; border-top-width: 0px; - border-left-width: 0.117307vw; - border-right-width: 0.117307vw; + border-left-width: calc(1.5vw / var(--size)); + border-right-width: calc(1.5vw / var(--size)); } #mapColMark .coltd:hover .colBlock { @@ -291,7 +295,7 @@ table.col, div.col { top: 4vw; left:0; height: 96vw; - width: 7.384615vw; + width: calc(96vw / var(--size)); z-index: 100; } @@ -328,20 +332,20 @@ table.row,div.row .rowtext { #mapRowMark .rowtd, #mapRowMark .rowtd .rowtext{ - height: 7.15vw; - line-height: 7.15vw; + height: calc(93vw / var(--size)); + line-height: calc(93vw / var(--size)); padding: 0; border-left-width: 0px; border-right-width: 0px; - border-top-width: 0.117307vw; - border-bottom-width: 0.117397vw; + border-top-width: calc(1.5vw / var(--size)); + border-bottom-width: calc(1.5vw / var(--size)); } #mapRowMark .rowtd:hover .rowBlock { position: absolute; left: 4vw; top: 0; - height: 7.384615vw; + height: calc(96vw / var(--size)); width: 96vw; z-index: 100; } diff --git a/_server/editor.js b/_server/editor.js index de4ca35e..fbbd9e6b 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -57,6 +57,7 @@ function editor() { showMovable: document.getElementById('showMovable'), gameInject: document.getElementById('gameInject'), undoFloor: document.getElementById('undoFloor'), + selectFloorBtn: document.getElementById('selectFloorBtn'), editorTheme: document.getElementById('editorTheme'), bigmapBtn : document.getElementById('bigmapBtn'), mapRowMark: document.getElementById('mapRowMark'), @@ -206,6 +207,7 @@ editor.prototype.init = function (callback) { editor_file_wrapper(editor); editor_table_wrapper(editor); editor_ui_wrapper(editor); + editor_uievent_wrapper(editor); editor_mappanel_wrapper(editor); editor_datapanel_wrapper(editor); editor_materialpanel_wrapper(editor); @@ -396,20 +398,40 @@ editor.prototype.drawEventBlock = function () { var directions = (movableArray[x]||{})[y]; if (directions == null) continue; if (!directions.includes('left') && x != 0) { - core.drawLine(fg, 32 * i + 1, 32 * j + 10, 32 * i + 1, 32 * j + 22, '#FF0000', 2); - core.fillPolygon(fg, [[32 * i + 9, 32 * j + 12], [32 * i + 1, 32 * j + 16], [32 * i + 9, 32 * j + 20]], '#FF0000'); + var ndirections = (movableArray[x-1]||{})[y]; + if (ndirections != null && !ndirections.includes('right')) { + core.drawLine(fg, 32 * i + 1, 32 * j + 6, 32 * i + 1, 32 * j + 26, '#FF0000', 2); + } else { + core.drawLine(fg, 32 * i + 1, 32 * j + 10, 32 * i + 1, 32 * j + 22, '#FF0000', 2); + core.fillPolygon(fg, [[32 * i + 9, 32 * j + 12], [32 * i + 1, 32 * j + 16], [32 * i + 9, 32 * j + 20]], '#FF0000'); + } } if (!directions.includes('right') && x != editor.currentFloorData.width - 1) { - core.drawLine(fg, 32 * i + 31, 32 * j + 10, 32 * i + 31, 32 * j + 22, '#FF0000', 2); - core.fillPolygon(fg, [[32 * i + 23, 32 * j + 12], [32 * i + 31, 32 * j + 16], [32 * i + 23, 32 * j + 20]], '#FF0000'); + var ndirections = (movableArray[x+1]||{})[y]; + if (ndirections != null && !ndirections.includes('left')) { + core.drawLine(fg, 32 * i + 31, 32 * j + 6, 32 * i + 31, 32 * j + 26, '#FF0000', 2); + } else { + core.drawLine(fg, 32 * i + 31, 32 * j + 10, 32 * i + 31, 32 * j + 22, '#FF0000', 2); + core.fillPolygon(fg, [[32 * i + 23, 32 * j + 12], [32 * i + 31, 32 * j + 16], [32 * i + 23, 32 * j + 20]], '#FF0000'); + } } if (!directions.includes('up') && y != 0) { - core.drawLine(fg, 32 * i + 10, 32 * j + 1, 32 * i + 22, 32 * j + 1, '#FF0000', 2); - core.fillPolygon(fg, [[32 * i + 12, 32 * j + 9], [32 * i + 16, 32 * j + 1], [32 * i + 20, 32 * j + 9]], '#FF0000'); + var ndirections = movableArray[x][y-1]; + if (ndirections != null && !ndirections.includes('down')) { + core.drawLine(fg, 32 * i + 6, 32 * j + 1, 32 * i + 26, 32 * j + 1, '#FF0000', 2); + } else { + core.drawLine(fg, 32 * i + 10, 32 * j + 1, 32 * i + 22, 32 * j + 1, '#FF0000', 2); + core.fillPolygon(fg, [[32 * i + 12, 32 * j + 9], [32 * i + 16, 32 * j + 1], [32 * i + 20, 32 * j + 9]], '#FF0000'); + } } if (!directions.includes('down') && y != editor.currentFloorData.height - 1) { - core.drawLine(fg, 32 * i + 10, 32 * j + 31, 32 * i + 22, 32 * j + 31, '#FF0000', 2); - core.fillPolygon(fg, [[32 * i + 12, 32 * j + 23], [32 * i + 16, 32 * j + 31], [32 * i + 20, 32 * j + 23]], '#FF0000'); + var ndirections = movableArray[x][y+1]; + if (ndirections != null && !ndirections.includes('up')) { + core.drawLine(fg, 32 * i + 6, 32 * j + 31, 32 * i + 26, 32 * j + 31, '#FF0000', 2); + } else { + core.drawLine(fg, 32 * i + 10, 32 * j + 31, 32 * i + 22, 32 * j + 31, '#FF0000', 2); + core.fillPolygon(fg, [[32 * i + 12, 32 * j + 23], [32 * i + 16, 32 * j + 31], [32 * i + 20, 32 * j + 23]], '#FF0000'); + } } } } @@ -471,28 +493,48 @@ editor.prototype._drawEventBlock_bigmap = function () { var directions = (movableArray[i]||{})[j]; if (directions == null) continue; if (!directions.includes('left') && i != 0) { - core.drawLine(fg, info.left + size * i, info.top + size * j + size / 3, info.left + size * i + 1, info.top + size * j + size * 2 / 3, '#FF0000', 2); - core.fillPolygon(fg, [[info.left + size * i + size / 4, info.top + size * j + size * 3 / 8], - [info.left + size * i, info.top + size * j + size / 2], - [info.left + size * i + size / 4, info.top + size * j + size * 5 / 8]], '#FF0000'); + var ndirections = (movableArray[i-1]||{})[j]; + if (ndirections != null && !ndirections.includes('right')) { + core.drawLine(fg, info.left + size * i, info.top + size * j + size / 4, info.left + size * i, info.top + size * j + size * 3 / 4, '#FF0000', 2); + } else { + core.drawLine(fg, info.left + size * i, info.top + size * j + size / 3, info.left + size * i, info.top + size * j + size * 2 / 3, '#FF0000', 2); + core.fillPolygon(fg, [[info.left + size * i + size / 4, info.top + size * j + size * 3 / 8], + [info.left + size * i, info.top + size * j + size / 2], + [info.left + size * i + size / 4, info.top + size * j + size * 5 / 8]], '#FF0000'); + } } if (!directions.includes('right') && i != editor.currentFloorData.width - 1) { - core.drawLine(fg, info.left + size * i + size, info.top + size * j + size / 3, info.left + size * i + size, info.top + size * j + size * 2 / 3, '#FF0000', 2); - core.fillPolygon(fg, [[info.left + size * i + size * 3 / 4, info.top + size * j + size * 3 / 8], - [info.left + size * i + size, info.top + size * j + size / 2], - [info.left + size * i + size * 3 / 4, info.top + size * j + size * 5 / 8]], '#FF0000'); + var ndirections = (movableArray[i+1]||{})[j]; + if (ndirections != null && !ndirections.includes('left')) { + core.drawLine(fg, info.left + size * i + size, info.top + size * j + size / 4, info.left + size * i + size, info.top + size * j + size * 3 / 4, '#FF0000', 2); + } else { + core.drawLine(fg, info.left + size * i + size, info.top + size * j + size / 3, info.left + size * i + size, info.top + size * j + size * 2 / 3, '#FF0000', 2); + core.fillPolygon(fg, [[info.left + size * i + size * 3 / 4, info.top + size * j + size * 3 / 8], + [info.left + size * i + size, info.top + size * j + size / 2], + [info.left + size * i + size * 3 / 4, info.top + size * j + size * 5 / 8]], '#FF0000'); + } } if (!directions.includes('up') && j != 0) { - core.drawLine(fg, info.left + size * i + size / 3, info.top + size * j, info.left + size * i + size * 2 / 3, info.top + size * j, '#FF0000', 2); - core.fillPolygon(fg, [[info.left + size * i + size * 3 / 8, info.top + size * j + size / 4], - [info.left + size * i + size / 2, info.top + size * j], - [info.left + size * i + size * 5 / 8, info.top + size * j + size / 4]], '#FF0000'); + var ndirections = movableArray[i][j-1]; + if (ndirections != null && !ndirections.includes('down')) { + core.drawLine(fg, info.left + size * i + size / 4, info.top + size * j, info.left + size * i + size * 3 / 4, info.top + size * j, '#FF0000', 2); + } else { + core.drawLine(fg, info.left + size * i + size / 3, info.top + size * j, info.left + size * i + size * 2 / 3, info.top + size * j, '#FF0000', 2); + core.fillPolygon(fg, [[info.left + size * i + size * 3 / 8, info.top + size * j + size / 4], + [info.left + size * i + size / 2, info.top + size * j], + [info.left + size * i + size * 5 / 8, info.top + size * j + size / 4]], '#FF0000'); + } } if (!directions.includes('down') && j != editor.currentFloorData.height - 1) { - core.drawLine(fg, info.left + size * i + size / 3, info.top + size * j + size - 1, info.left + size * i + size * 2 / 3, info.top + size * j + size - 1, '#FF0000', 2); - core.fillPolygon(fg, [[info.left + size * i + size * 3 / 8, info.top + size * j + size * 3 / 4], - [info.left + size * i + size / 2, info.top + size * j + size], - [info.left + size * i + size * 5 / 8, info.top + size * j + size * 3 / 4]], '#FF0000'); + var ndirections = movableArray[i][j+1]; + if (ndirections != null && !ndirections.includes('up')) { + core.drawLine(fg, info.left + size * i + size / 4, info.top + size * j + size, info.left + size * i + size * 3 / 4, info.top + size * j + size, '#FF0000', 2); + } else { + core.drawLine(fg, info.left + size * i + size / 3, info.top + size * j + size, info.left + size * i + size * 2 / 3, info.top + size * j + size, '#FF0000', 2); + core.fillPolygon(fg, [[info.left + size * i + size * 3 / 8, info.top + size * j + size * 3 / 4], + [info.left + size * i + size / 2, info.top + size * j + size], + [info.left + size * i + size * 5 / 8, info.top + size * j + size * 3 / 4]], '#FF0000'); + } } } } @@ -714,6 +756,27 @@ editor.prototype.drawInitData = function (icons) { }); var imgNames = ["terrains", "animates", "enemys", "enemy48", "items", "npcs", "npc48", "autotile"]; + var splitCanvas = document.createElement('canvas'); + var splitCtx = splitCanvas.getContext('2d'); + splitCtx.imageSmoothingEnabled = false; + + var splitImage = function (image, width, height) { + if (image.width == width && image.height == height) { + return [image]; + } + var ans = []; + for (var j = 0; j < image.height; j += h) { + var h = Math.min(height, image.height - j); + splitCanvas.width = width; + splitCanvas.height = h; + core.drawImage(splitCtx, image, 0, j, width, h, 0, 0, width, h); + var data = new Image(); + data.src = splitCanvas.toDataURL("image/png"); + ans.push(data); + } + return ans; + } + for (var ii = 0; ii < imgNames.length; ii++) { var img = imgNames[ii], tempy = 0; if (img == 'autotile') { @@ -729,9 +792,14 @@ editor.prototype.drawInitData = function (icons) { } 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; + if (img == 'terrains') { + width = Math.ceil((height / 32 + 2) / editor.uivalues.foldPerCol) * 32; + if (width > 32) mh = 32 * editor.uivalues.foldPerCol; + } else { + 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 + width) / 32, height]; sumWidth += width; @@ -812,10 +880,13 @@ editor.prototype.drawInitData = function (icons) { })(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, img); + var canvas = document.createElement("canvas"); + canvas.width = 32; + canvas.height = images[img].height + 64; + canvas.getContext('2d').drawImage(images[img], 0, 64); + var subimgs = splitImage(canvas, 32, editor.uivalues.foldPerCol * 32); + for (var i = 0; i < subimgs.length; i++) { + drawImage(subimgs[i], nowx, 0, img); nowx += 32; } } @@ -830,7 +901,7 @@ editor.prototype.drawInitData = function (icons) { var tempx = editor.uivalues.folded ? 32 : 96; for (var im in autotiles) { var tempy = editor.uivalues.folded ? 32 : autotiles[im].height; - var subimgs = core.splitImage(autotiles[im], tempx, tempy); + var subimgs = splitImage(autotiles[im], tempx, tempy); drawImage(subimgs[0], nowx, nowy, img); nowy += tempy; } @@ -840,9 +911,8 @@ editor.prototype.drawInitData = function (icons) { 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) { + var subimgs = splitImage(images[img], 32, editor.uivalues.foldPerCol * per_height); + for (var i = 0; i < subimgs.length; i++) { drawImage(subimgs[i], nowx, 0, img); nowx += 32; } diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index af5b87bc..e83c764a 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -163,7 +163,7 @@ editor_blockly = function () { editor_blockly.hide(); } - editor_blockly.confirm = function () { + editor_blockly.confirm = function (keep) { if (!editor_blockly.id) { editor_blockly.id = ''; return; @@ -186,10 +186,13 @@ editor_blockly = function () { } var setvalue = function (value) { var thisTr = document.getElementById(editor_blockly.id); - editor_blockly.id = ''; var input = thisTr.children[2].children[0].children[0]; input.value = value; - editor_blockly.hide(); + if (!keep) { + editor_blockly.id = ''; + editor_blockly.hide(); + } + else alert('保存成功!'); input.onchange(); } if (codeAreaHL.getValue() === '') { @@ -244,8 +247,8 @@ editor_blockly = function () { } } if (one.type == 'previewUI' && this.checkAsync(one.action)) return true; - if (one.async && one.type != 'animate' && one.type != 'function') hasAsync = true; - if (one.type == 'waitAsync') hasAsync = false; + if (one.async && one.type != 'animate' && one.type != 'function' && one.type != 'text') hasAsync = true; + if (one.type == 'waitAsync' || one.type == 'stopAsync') hasAsync = false; } return hasAsync; } @@ -1188,4 +1191,17 @@ Blockly.FieldDropdown.prototype.doValueUpdate_ = function (newValue) { options.push([this.value_, this.value_]); this.selectedOption_ = options[options.length - 1]; } -}; \ No newline at end of file +}; + +Blockly.FieldMultilineInput.prototype.getDisplayText_ = function() { + var value = this.value_; + if (!value) return Blockly.Field.NBSP; + var curr = '', text = ''; + for (var i = 0; i < value.length; ++i) { + if (value[i] == '\n' || curr.length == this.maxDisplayLength) { + text += curr.replace(/\s/g, Blockly.Field.NBSP) + '\n'; + curr = value[i] == '\n' ? '' : value[i]; + } else curr += value[i]; + } + return text + curr; +}; diff --git a/_server/editor_blocklyconfig.js b/_server/editor_blocklyconfig.js index fb003876..0dc19af8 100644 --- a/_server/editor_blocklyconfig.js +++ b/_server/editor_blocklyconfig.js @@ -108,7 +108,7 @@ editor_blocklyconfig=(function(){ MotaActionBlocks['tip_s'].xmlText(), MotaActionBlocks['confirm_s'].xmlText(), MotaActionBlocks['choices_s'].xmlText([ - '选择剑或者盾','流浪者','man',0,0,'',MotaActionBlocks['choicesContext'].xmlText([ + '选择剑或者盾','流浪者','man',0,'',MotaActionBlocks['choicesContext'].xmlText([ '剑','','',null,'','',MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), ]) ]), @@ -196,16 +196,17 @@ editor_blocklyconfig=(function(){ {"case": "timeout", "action": [{"type": "comment", "text": "当超时未操作时执行此事件"}]}, ]}), MotaActionBlocks['waitAsync_s'].xmlText(), + MotaActionBlocks['stopAsync_s'].xmlText(), MotaActionBlocks['vibrate_s'].xmlText(), MotaActionBlocks['animate_s'].xmlText(), MotaActionBlocks['animate_1_s'].xmlText(), + MotaActionBlocks['stopAnimate_s'].xmlText(), MotaActionBlocks['setViewport_s'].xmlText(), MotaActionBlocks['setViewport_1_s'].xmlText(), MotaActionBlocks['lockViewport_s'].xmlText(), MotaActionBlocks['showStatusBar_s'].xmlText(), MotaActionBlocks['hideStatusBar_s'].xmlText(), - MotaActionBlocks['showHero_s'].xmlText(), - MotaActionBlocks['hideHero_s'].xmlText(), + MotaActionBlocks['setHeroOpacity_s'].xmlText(), MotaActionBlocks['setCurtain_0_s'].xmlText(), MotaActionBlocks['setCurtain_1_s'].xmlText(), MotaActionBlocks['screenFlash_s'].xmlText(), @@ -362,23 +363,7 @@ editor_blocklyconfig=(function(){ } ] } - ], 'event'), - '', - MotaActionFunctions.actionParser.parse({ - "trigger": "action", - "displayDamage": true, - "data": [ - ' ... 战前剧情', - {"type": "battle", "id": "greenSlime"}, - ' ... 战后剧情;请注意上面的强制战斗不会使怪物消失', - '需要下一句来调用{"type": "hide"}来隐藏事件', - {"type": "hide"}, - ] - },'event'), - '', - MotaActionFunctions.actionParser.parse([ - {"type": "function", "function": "function(){var x=core.status.event.data.x,y=core.status.event.data.y;if(core.isset(x)&&core.isset(y)){core.insertAction([{type:'hide',loc:[[x-1,y-2],[x,y-2],[x+1,y-2],[x-1,y-1],[x,y-1],[x+1,y-1],[x-1,y],[x+1,y]]}]);}}"}, - ],'afterBattle'), + ], 'event'), '', MotaActionFunctions.actionParser.parse([ { diff --git a/_server/editor_datapanel.js b/_server/editor_datapanel.js index bf699656..f5cccc56 100644 --- a/_server/editor_datapanel.js +++ b/_server/editor_datapanel.js @@ -180,6 +180,12 @@ editor_datapanel_wrapper = function (editor) { editor.uifunctions.createNewMaps_func = function () { + + document.getElementById('newMapWidth').value = core.__SIZE__; + document.getElementById('newMapHeight').value = core.__SIZE__; + document.getElementById('newMapsWidth').value = core.__SIZE__; + document.getElementById('newMapsHeight').value = core.__SIZE__; + var newMaps = document.getElementById('newMaps'); var newFloors = document.getElementById('newFloors'); newMaps.onclick = function () { @@ -301,6 +307,13 @@ editor_datapanel_wrapper = function (editor) { printe('不合法的id,请使用字母、数字或下划线,且不能以数字开头'); return; } + if (id == 'hero' || id == 'this' || id == 'none' || id == 'airwall') { + printe('不得使用保留关键字作为id!'); + return; + } + if (core.statusBar.icons[id] != null) { + alert('警告!此ID在状态栏图标中被注册;仍然允许使用,但是\\i[]等绘制可能出现冲突。'); + } editor.file.changeIdAndIdnum(id, idnum, editor_mode.info, function (err) { if (err) { printe(err); @@ -332,6 +345,9 @@ editor_datapanel_wrapper = function (editor) { window.location.reload(); }); } + newIdIdnum.children[6].onclick = function () { + editor.uifunctions.appendMaterialByInfo(editor_mode.info); + } } editor.uifunctions.changeId_func = function () { @@ -355,6 +371,9 @@ editor_datapanel_wrapper = function (editor) { printe('额外素材不可修改id!'); return; } + if (core.statusBar.icons[id] != null) { + alert('警告!此ID在状态栏图标中被注册;仍然允许使用,但是\\i[]等绘制可能出现冲突。'); + } editor.file.changeIdAndIdnum(id, null, editor_mode.info, function (err) { if (err) { printe(err); @@ -381,6 +400,9 @@ editor_datapanel_wrapper = function (editor) { window.location.reload(); }); } + changeId.children[3].onclick = function () { + editor.uifunctions.appendMaterialByInfo(editor_mode.info); + } } editor.uifunctions.copyPasteEnemyItem_func = function () { @@ -811,6 +833,10 @@ editor_datapanel_wrapper = function (editor) { } var loadImage = function (content, callback) { + if (content instanceof Image || content.getContext != null) { + callback(content); + return; + } var image = new Image(); try { image.onload = function () { @@ -1124,6 +1150,46 @@ editor_datapanel_wrapper = function (editor) { } reader.readAsDataURL(file); } + + editor.uifunctions.appendMaterialByInfo = function (info) { + if (info.isTile) { + printe('额外素材不支持此功能!'); + return; + } + var img = null; + var cls = info.images; + var height = cls == 'enemy48' || cls == 'npc48' ? 48 : 32; + + if (cls == 'autotile') { + img = core.material.images.autotile[info.id]; + } else { + var image = core.material.images[cls]; + var width = image.width; + img = document.createElement('canvas'); + img.width = width; + img.height = height; + img.getContext('2d').drawImage(image, 0, info.y * height, width, height, 0, 0, width, height); + } + + editor.mode.change('appendpic'); + editor.dom.selectAppend.value = cls; + editor.dom.selectAppend.onchange(); + + afterReadFile(img, function () { + changeColorInput.value = 0; + if (cls == 'autotile') return; + + editor_mode.appendPic.index = 0; + for (var ii = 0; ii < editor_mode.appendPic.num; ++ii) { + editor_mode.appendPic.selectPos[ii] = {x: ii, y: 0, ysize: height}; + editor.dom.appendPicSelection.children[ii].style = [ + 'left:', ii * 32, 'px;', + 'top:', 0, 'px;', + 'height:', height - 6, 'px;' + ].join(''); + } + }); + } } /////////////////////////////////////////////////////////////////////// diff --git a/_server/editor_file.js b/_server/editor_file.js index 14cee7db..41cacebf 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -219,7 +219,15 @@ editor_file = function (editor, callback) { color: currData.color, weather: currData.weather, }:{}); - + // 继承配置表格新增的基本楼层属性 + if (saveStatus) { + for (var x in currData) { + if (editor.currentFloorData[x] == null && (typeof currData[x] == 'number' || typeof currData[x] == 'string')) { + editor.currentFloorData[x] = currData[x]; + } + } + } + Object.keys(editor.currentFloorData).forEach(function (t) { if (editor.currentFloorData[t] == null) delete editor.currentFloorData[t]; @@ -577,7 +585,7 @@ editor_file = function (editor, callback) { (function () { var locObj = Object.assign({}, editor.core.items.items[id]); Object.keys(editor.file.comment._data.items._data).forEach(function (v) { - if (!isset(editor.core.items.items[id][v])) + if (!isset((editor.core.items.items[id]||{})[v])) locObj[v] = null; }); return locObj; @@ -609,7 +617,7 @@ editor_file = function (editor, 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])) + if (!isset((editor.core.enemys.enemys[id]||{})[v])) /* locObj[v]=editor.core.enemys.enemys[id][v]; else */ locObj[v] = null; diff --git a/_server/editor_listen.js b/_server/editor_listen.js index 5f876bad..474c10cd 100644 --- a/_server/editor_listen.js +++ b/_server/editor_listen.js @@ -37,6 +37,7 @@ editor_listen_wrapper = function (editor) { editor.dom.clearEvent.onmouseup = editor.uifunctions.clearEvent_click editor.dom.clearLoc.onmouseup = editor.uifunctions.clearLoc_click editor.dom.undoFloor.onclick = editor.uifunctions.undoFloor_click + editor.dom.selectFloorBtn.onclick = editor.uifunctions.selectFloorBtn_click editor.dom.editorTheme.onchange = editor.uifunctions.editorTheme_onchange editor.dom.lastUsed.onmouseup = editor.uifunctions.lastUsed_click; diff --git a/_server/editor_mappanel.js b/_server/editor_mappanel.js index 2adb4cac..d451d3c7 100644 --- a/_server/editor_mappanel.js +++ b/_server/editor_mappanel.js @@ -452,6 +452,23 @@ editor_mappanel_wrapper = function (editor) { editor.changeFloor(toId); } + editor.uifunctions.selectFloorBtn_click = function () { + editor.uievent.selectFloor(null, '选择楼层', function (floorId) { + if (!floorId || floorId == editor.currentFloorId) return; + + var saveFloor = document.getElementById('saveFloor'); + if (saveFloor && saveFloor.classList.contains('highlight')) { + printe('请先保存地图!'); + return; + } + + editor_mode.onmode('nextChange'); + editor_mode.onmode('floor'); + editor.dom.selectFloor.value = floorId; + editor.changeFloor(floorId); + }) + } + editor.uifunctions.editorTheme_onchange = function () { var theme = editor.dom.editorTheme.value; editor.config.set('theme', theme); diff --git a/_server/editor_materialpanel.js b/_server/editor_materialpanel.js index 8b7b8adb..cf18c927 100644 --- a/_server/editor_materialpanel.js +++ b/_server/editor_materialpanel.js @@ -150,10 +150,10 @@ editor_materialpanel_wrapper = function (editor) { } else { var height = editor.widthsX[spriter][3], col = height / ysize; + if (spriter == 'terrains') col += 2; 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); } @@ -177,7 +177,7 @@ editor_materialpanel_wrapper = function (editor) { if (editor.uivalues.folded) { y += editor.uivalues.foldPerCol * (pos.x - editor.widthsX[spriter][1]); } - if (pos.images == 'terrains' && pos.x == 0) y -= 2; + if (pos.images == 'terrains') y -= 2; editor.info = { 'images': pos.images, 'y': y } } diff --git a/_server/editor_multi.js b/_server/editor_multi.js index dfce058d..c02dc486 100644 --- a/_server/editor_multi.js +++ b/_server/editor_multi.js @@ -282,6 +282,18 @@ editor_multi = function () { }).length > 0; } + var _previewButton = document.getElementById('editor_multi_preview'); + + _previewButton.onclick = function () { + if (!editor_multi.preview) return; + _format(); + if (editor_multi.hasError()) { + alert("当前好像存在严重的语法错误,请处理后再预览。"); + return; + } + editor.uievent.previewEditorMulti(editor_multi.preview, codeEditor.getValue()); + } + editor_multi.import = function (id_, args) { var thisTr = document.getElementById(id_); if (!thisTr) return false; @@ -292,6 +304,8 @@ editor_multi = function () { editor_multi.id = id_; editor_multi.isString = false; editor_multi.lintAutocomplete = false; + editor_multi.preview = args.preview; + _previewButton.style.display = editor_multi.preview ? 'inline' : 'none'; if (args.lint === true) editor_multi.lintAutocomplete = true; if ((!input.value || input.value == 'null') && args.template) input.value = '"' + args.template + '"'; @@ -318,7 +332,7 @@ editor_multi = function () { _setValue(tstr || ''); } editor_multi.show(); - codeEditor.scrollTo(0, lastOffset[id_] || 0); + codeEditor.scrollTo(0, lastOffset[editor_multi.id] || 0); return true; } @@ -331,7 +345,7 @@ editor_multi = function () { multiLineArgs = [null, null, null]; } - editor_multi.confirm = function () { + editor_multi.confirm = function (keep) { if (editor_multi.hasError()) { alert("当前好像存在严重的语法错误,请处理后再保存。\n严重的语法错误可能会导致整个编辑器的崩溃。"); return; @@ -345,21 +359,18 @@ editor_multi = function () { if (editor_multi.id === 'callFromBlockly') { // ----- 自动格式化 _format(); - editor_multi.id = ''; - editor_multi.multiLineDone(); + editor_multi.multiLineDone(keep); return; } if (editor_multi.id === 'importFile') { _format(); - editor_multi.id = ''; - editor_multi.writeFileDone(); + editor_multi.writeFileDone(keep); return; } var setvalue = function (value) { var thisTr = document.getElementById(editor_multi.id); - editor_multi.id = ''; var input = thisTr.children[2].children[0].children[0]; if (editor_multi.isString) { input.value = JSON.stringify(value); @@ -378,7 +389,12 @@ editor_multi = function () { } input.value = tstr; } - editor_multi.hide(); + if (!keep) { + editor_multi.id = ''; + editor_multi.hide(); + } else { + alert('写入成功!'); + } input.onchange(); } lastOffset[editor_multi.id] = (codeEditor.getScrollInfo() || {}).top; @@ -410,11 +426,16 @@ editor_multi = function () { editor_multi.lintAutocomplete = Boolean(args.lint); editor_multi.show(); } - editor_multi.multiLineDone = function () { - editor_multi.hide(); + editor_multi.multiLineDone = function (keep) { if (!multiLineArgs[0] || !multiLineArgs[1] || !multiLineArgs[2]) return; var newvalue = codeEditor.getValue() || ''; multiLineArgs[2](newvalue, multiLineArgs[0], multiLineArgs[1]) + if (!keep) { + editor_multi.id = ''; + editor_multi.hide(); + } else { + alert('写入成功!'); + } } var _fileValues = [''] @@ -435,11 +456,16 @@ editor_multi = function () { }) } - editor_multi.writeFileDone = function () { + editor_multi.writeFileDone = function (keep) { fs.writeFile(_fileValues[0], editor.util.encode64(codeEditor.getValue() || ''), 'base64', function (err, data) { if (err) printe('文件写入失败,请手动粘贴至' + _fileValues[0] + '\n' + err); else { - editor_multi.hide(); + if (!keep) { + editor_multi.id = ''; + editor_multi.hide(); + } else { + alert('写入成功!'); + } printf(_fileValues[0] + " 写入成功,F5刷新后生效"); } }); diff --git a/_server/editor_table.js b/_server/editor_table.js index 1797b7f5..341164f2 100644 --- a/_server/editor_table.js +++ b/_server/editor_table.js @@ -419,7 +419,7 @@ editor_table_wrapper = function (editor) { var cobj = JSON.parse(tr.children[1].getAttribute('cobj')); var input = tr.children[2].children[0].children[0]; 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, template: cobj._template }); + if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string, template: cobj._template, preview: cobj._preview }); if (cobj._type === 'material') editor.table.selectMaterial(input, cobj); if (cobj._type === 'color') editor.table.selectColor(input); if (cobj._type === 'point') editor.table.selectPoint(input); @@ -451,7 +451,7 @@ editor_table_wrapper = function (editor) { editor_table.prototype.dblclickfunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) { if (editor_mode.doubleClickMode === 'change') { if (cobj._type === 'event') editor_blockly.import(guid, { type: cobj._event }); - if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string, template: cobj._template }); + if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string, template: cobj._template, preview: cobj._preview }); if (cobj._type === 'material') editor.table.selectMaterial(input, cobj); if (cobj._type === 'color') editor.table.selectColor(input); if (cobj._type === 'point') editor.table.selectPoint(input); diff --git a/_server/editor_ui.js b/_server/editor_ui.js index 20b4d436..4035d872 100644 --- a/_server/editor_ui.js +++ b/_server/editor_ui.js @@ -336,856 +336,4 @@ editor_ui_wrapper = function (editor) { "双击事件编辑器:长文本编辑/脚本编辑/地图选点/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.extraBody = document.getElementById('uieventExtraBody'); - - uievent.close = function () { - uievent.isOpen = false; - uievent.elements.div.style.display = 'none'; - if (uievent.values.interval) { - clearTimeout(uievent.values.interval); - clearInterval(uievent.values.interval); - } - 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'); - core.setFilter('uievent', null); - - // 绘制UI - var background = uievent.elements.selectBackground.value; - if (background == 'thumbnail') { - core.drawThumbnail(editor.currentFloorId, null, {ctx: 'uievent'}); - } - else { - core.fillRect('uievent', 0, 0, core.__PIXELS__, core.__PIXELS__, background); - } - - if (uievent.values.list instanceof Array) { - uievent.values.list.forEach(function (data) { - if (typeof data == 'string') data = { "type": "text", "text": data }; - var type = data.type; - if (type == "text") { - data.ctx = 'uievent'; - core.saveCanvas('uievent'); - core.drawTextBox(data.text, data); - core.loadCanvas('uievent'); - return; - } - else if (type == "choices") { - for (var i = 0; i < data.choices.length; i++) { - if (typeof data.choices[i] === 'string') - data.choices[i] = {"text": data.choices[i]}; - data.choices[i].text = core.replaceText(data.choices[i].text); - } - core.saveCanvas('uievent'); - core.status.event.selection = data.selected || 0; - core.drawChoices(core.replaceText(data.text), data.choices, data.width, 'uievent'); - core.status.event.selection = null; - core.loadCanvas('uievent'); - return; - } else if (type == "confirm") { - core.saveCanvas('uievent'); - core.drawConfirmBox(data.text, null, null, 'uievent'); - core.loadCanvas('uievent'); - } else if (core.ui["_uievent_" + type]) - 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.extraBody.style.display = 'none'; - uievent.elements.body.style.overflow = "hidden"; - - uievent.values.list = list; - uievent.drawPreviewUI(); - } - - uievent.selectPoint = function (floorId, x, y, bigmap, callback) { - uievent.values.bigmap = bigmap; - uievent.values.size = editor.isMobile ? window.innerWidth / core.__SIZE__ : 32; - - 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 = 'inline'; - uievent.elements.selectPointBox.style.display = 'block'; - uievent.elements.canvas.style.display = 'block'; - uievent.elements.usedFlags.style.display = 'none'; - uievent.elements.extraBody.style.display = 'none'; - uievent.elements.body.style.overflow = "hidden"; - uievent.elements.yes.onclick = function () { - var floorId = uievent.values.floorId, x = uievent.values.x, y = uievent.values.y; - var multipoints = uievent.values.multipoints || []; - uievent.close(); - if (callback) { - if (multipoints.length > 0) { - callback(floorId, multipoints.map(function (one) { return one.split(',')[0]}).join(','), - multipoints.map(function (one) { return one.split(',')[1]}).join(',')); - } else { - callback(floorId, x, y); - } - } - } - - // Append children - var floors = ""; - core.floorIds.forEach(function (f) { - floors += ""; - }) - uievent.elements.selectFloor.innerHTML = floors; - // 检查多选点 - if (/^\d+(,\d+)+$/.test(x) && /^\d+(,\d+)+$/.test(y)) { - var xx = x.split(','), yy = y.split(','); - uievent.values.multipoints = []; - for (var i = 0; i < xx.length; ++i) { - uievent.values.multipoints.push(xx[i] + "," + yy[i]); - } - x = xx[xx.length - 1]; - y = yy[yy.length - 1]; - } - 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 + ')'; - // 计算size - uievent.values.boxSize = uievent.values.size * - (uievent.values.bigmap ? (core.__SIZE__ / Math.max(uievent.values.width, uievent.values.height)) : 1); - uievent.values.boxLeft = uievent.values.bigmap ? - (core.__PIXELS__ * Math.max(0, (1 - uievent.values.width / uievent.values.height) / 2)) : 0; - uievent.values.boxTop = uievent.values.bigmap ? - (core.__PIXELS__ * Math.max(0, (1 - uievent.values.height / uievent.values.width) / 2)) : 0; - - if (uievent.values.bigmap) { - uievent.elements.selectPointBox.style.left = uievent.values.boxSize * uievent.values.x + uievent.values.boxLeft + "px"; - uievent.elements.selectPointBox.style.top = uievent.values.boxSize * uievent.values.y + uievent.values.boxTop + "px"; - } else { - uievent.elements.selectPointBox.style.left = uievent.values.boxSize * (uievent.values.x - uievent.values.left) + "px"; - uievent.elements.selectPointBox.style.top = uievent.values.boxSize * (uievent.values.y - uievent.values.top) + "px"; - } - uievent.elements.selectPointBox.style.width = uievent.values.boxSize - 6 + "px"; - uievent.elements.selectPointBox.style.height = uievent.values.boxSize - 6 + "px"; - - if (redraw) { - core.setAlpha('uievent', 1); - core.clearMap('uievent'); - core.drawThumbnail(uievent.values.floorId, null, { - ctx: 'uievent', centerX: uievent.values.left + core.__HALF_SIZE__, - centerY: uievent.values.top + core.__HALF_SIZE__, all: uievent.values.bigmap - }); - uievent.values.multipoints = uievent.values.multipoints || []; - core.setTextAlign('uievent', 'right'); - for (var i = 0; i < uievent.values.multipoints.length; ++i) { - var xy = uievent.values.multipoints[i].split(","), x = parseInt(xy[0]), y = parseInt(xy[1]); - core.fillBoldText('uievent', i + 1, - 32 * (x - uievent.values.left) + 28 , 32 * (y - uievent.values.top) + 26, '#FF7F00', null, '14px Verdana'); - } - core.setTextAlign('uievent', 'left'); - } - } - - 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.values.multipoints = []; - uievent.setPoint(uievent.elements.selectFloor.value); - } - - uievent.elements.selectPointBox.onclick = function (e) { - e.preventDefault(); - e.stopPropagation(); - return false; - } - - uievent.elements.body.onclick = function (e) { - if (uievent.mode != 'selectPoint') return; - if (uievent.values.bigmap) { - uievent.values.x = core.clamp(Math.floor((e.offsetX - uievent.values.boxLeft) / uievent.values.boxSize), 0, uievent.values.width - 1); - uievent.values.y = core.clamp(Math.floor((e.offsetY - uievent.values.boxTop) / uievent.values.boxSize), 0, uievent.values.height - 1); - } else { - 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.elements.body.oncontextmenu = function (e) { - e.preventDefault(); - e.stopPropagation(); - if (uievent.mode != 'selectPoint' || uievent.values.bigmap) return; - var x = uievent.values.left + Math.floor(e.offsetX / uievent.values.size); - var y = uievent.values.top + Math.floor(e.offsetY / uievent.values.size); - uievent.values.multipoints = uievent.values.multipoints || []; - if (uievent.values.multipoints.indexOf(x+","+y) >= 0) { - uievent.values.multipoints = uievent.values.multipoints.filter(function (o) { return o != x+","+y;}) - } else { - uievent.values.multipoints.push(x+","+y); - } - uievent.values.x = x; - uievent.values.y = y; - uievent.updateSelectPoint(true); - return false; - } - - uievent.move = function (dx, dy) { - if (uievent.mode != 'selectPoint') return; - if (uievent.values.bigmap) 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); - }; - - uievent.triggerBigmap = function () { - if (uievent.mode != 'selectPoint') return; - uievent.values.bigmap = !uievent.values.bigmap; - uievent.values.multipoints = []; - uievent.setPoint(uievent.values.floorId); - }; - - (function () { - - var viewportButtons = uievent.elements.selectPointButtons; - var pressTimer = null; - for (var ii = 0, node; node = viewportButtons.children[ii]; ii++) { - if (ii == 4) { - node.onclick = uievent.triggerBigmap; - continue; - } - if (ii == 5) { - node.onclick = function () { - alert(core.copy(uievent.values.floorId) ? ('楼层ID '+uievent.values.floorId+' 已成功复制到剪切板') : '无法复制楼层ID'); - } - } - (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') 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.values.multipoints = []; - uievent.setPoint(core.floorIds[index]); - } - - uievent.onKeyDown = function (e) { - if (e.keyCode == 27) editor.uievent.close(); - if (uievent.mode == 'selectPoint') { - if (e.keyCode == 87) editor.uievent.move(0, -1) - if (e.keyCode == 65) editor.uievent.move(-1, 0) - if (e.keyCode == 83) editor.uievent.move(0, 1); - if (e.keyCode == 68) editor.uievent.move(1, 0); - } - } - - // ------ 搜索变量出现的位置,也放在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.extraBody.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 = "

该变量出现的所有位置如下:

"; - uievent.elements.extraBody.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\u3040-\u30FF\u2160-\u216B\u0391-\u03C9]$/.test(obj.charAt(index + length))) return true; - } - } - - uievent._searchUsedFlags = function (flag) { - var list = []; - // 每个点的事件 - var events = ["events", "autoEvent", "changeFloor", "beforeBattle", "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 + ") 点"); - } - } - } - }); - } - // 公共事件 - for (var name in events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent) { - if (hasUsedFlags(events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent[name], flag)) - list.push("公共事件 " + name); - } - // 道具 & 装备属性 - for (var id in items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a) { - var item = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a[id]; - // 装备属性 - if (hasUsedFlags(item.equip, flag)) { - list.push("道具 " + (item.name || id) + " 的装备属性"); - } - // 使用事件 - if (hasUsedFlags(item.useItemEvent, flag)) { - list.push("道具 " + (item.name || id) + " 的使用事件"); - } - } - // 怪物战前 & 战后 - for (var id in enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80) { - var enemy = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80[id]; - if (hasUsedFlags(enemy.beforeBattle, flag)) { - list.push("怪物 " + (enemy.name || id) + " 的战前事件"); - } - if (hasUsedFlags(enemy.afterBattle, flag)) { - list.push("怪物 " + (enemy.name || id) + " 的战后事件"); - } - } - // 图块的碰触 & 门信息 - for (var id in maps_90f36752_8815_4be8_b32b_d7fad1d0542e) { - var mapInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e[id]; - if (hasUsedFlags(mapInfo.doorInfo, flag)) - list.push("图块 " + (mapInfo.name || mapInfo.id) + " 的门信息"); - if (hasUsedFlags(mapInfo.event, flag)) - list.push("图块 " + (mapInfo.name || mapInfo.id) + " 碰触事件"); - } - // 难度 & 标题事件 & 开场剧情 & 等级提升 - if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.levelChoose, flag)) - list.push("难度分歧"); - if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.startCanvas, flag)) - list.push("标题事件"); - if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.startText, flag)) - list.push("开场剧情"); - if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.levelUp, flag)) - list.push("等级提升"); - // 全局商店 - (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.shops || []).forEach(function (shop) { - if (hasUsedFlags(shop, flag)) list.push("商店 " + shop.id); - }); - - return list; - } - - // ------ 素材选择框 ------ // - uievent.selectMaterial = function (value, title, directory, transform, callback) { - var one = directory.split(':'); - if (one.length > 1) directory = one[0]; - var appendedImages = one[1] == 'images' ? core.material.images.images : {}; - - fs.readdir(directory, function (err, data) { - if (err) { - printe(directory + '不存在!'); - throw (directory + '不存在!'); - } - if (!(data instanceof Array)) { - printe('没有可显示的内容') - return; - } - value = value || []; - data = (transform ? data.map(transform) : data).filter(function (one) {return one;}).sort(); - var data2 = Object.keys(appendedImages); - data2 = (transform ? data2.map(transform) : data2).filter(function (one) { - return one && data.indexOf(one) < 0; - }).sort(); - - uievent.isOpen = true; - uievent.elements.div.style.display = 'block'; - uievent.mode = 'selectMaterial'; - uievent.elements.selectPoint.style.display = 'none'; - uievent.elements.yes.style.display = 'block'; - uievent.elements.title.innerText = title; - 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 = 'none'; - uievent.elements.extraBody.style.display = 'block'; - uievent.elements.body.style.overflow = "auto"; - - uievent.elements.yes.onclick = function () { - var list = Array.from(document.getElementsByClassName('materialCheckbox')).filter(function (one) { - return one.checked; - }).map(function (one) {return one.getAttribute('key'); }); - uievent.close(); - if (callback) callback(list); - } - - var _isTileset = directory.indexOf('project/tilesets') >= 0; - - // 显示每一项内容 - var html = "

"; - html += ""+ - "
"; - if (_isTileset) { - html += "警告!额外素材一旦注册成功将不可删除,否则可能会导致素材错位风险!如果你不再想用某个额外素材," - +"但又不想让它出现在素材区,可以考虑使用空气墙同名替换该额外素材文件。
" - } - data.forEach(function (one) { - var checked = value.indexOf(one) >= 0? 'checked' : ''; - var disabled = _isTileset && value.indexOf(one) >= 0 ? 'disabled' : '' - html += ` ${one}`; - // 预览图片 - if (one.endsWith('.png') || one.endsWith('.jpg') || one.endsWith('.jpeg') || one.endsWith('.gif')) { - html += ""; - html += '
'; - } - // 试听音频 - if (one.endsWith('.mp3') || one.endsWith('.ogg') || one.endsWith('.wav') || one.endsWith('.m4a') || one.endsWith('.flac')) { - html += "" - html += " 音调:"; - html += `0:00 / 0:00
- - `; - } - // 预览动画 - if (directory.indexOf('animates') >= 0) { - html += ""; - html += ""; - } - html += '
'; - }); - data2.forEach(function (one) { - var checked = value.indexOf(one) >= 0? 'checked' : ''; - var disabled = _isTileset && value.indexOf(one) >= 0 ? 'disabled' : ''; - html += ` ${one}`; - // 预览图片 - if (one.endsWith('.png') || one.endsWith('.jpg') || one.endsWith('.jpeg') || one.endsWith('.gif')) { - html += ""; - html += '

'; - } - }) - html += "

"; - html += "

如果文件未在此列表显示,请检查文件名是否合法(只能由数字字母下划线横线和点组成),后缀名是否正确。

"; - uievent.elements.extraBody.innerHTML = html; - }); - } - - uievent._selectAllMaterial = function (checked) { - Array.from(document.getElementsByClassName('materialCheckbox')).forEach(function (one) { - if (!one.disabled) one.checked = checked; - }) - } - - uievent._previewMaterialImage = function (button) { - var br = button.nextElementSibling; - var img = br.nextElementSibling; - if (br.style.display == 'none') { - button.innerText = '折叠'; - br.style.display = 'block'; - img.style.display = 'block'; - img.src = img.getAttribute('key'); - } else { - button.innerText = '预览'; - br.style.display = 'none'; - img.style.display = 'none'; - } - } - - uievent._previewMaterialImage2 = function (button) { - var br = button.nextElementSibling; - if (br.style.display == 'none') { - button.innerText = '折叠'; - br.style.display = 'block'; - br.parentElement.insertBefore(core.material.images.images[br.getAttribute('key')], br.nextElementSibling); - } else { - button.innerText = '预览'; - br.style.display = 'none'; - br.parentElement.removeChild(core.material.images.images[br.getAttribute('key')]); - } - } - - uievent._previewMaterialAudio = function (button) { - var span = button.nextElementSibling.nextElementSibling; - var br = span.nextElementSibling; - var audio = br.nextElementSibling; - var progress = audio.nextElementSibling; - if (br.style.display == 'none') { - button.innerText = '暂停'; - br.style.display = 'block'; - progress.style.display = 'block'; - span.style.display = 'inline'; - audio.play(); - } else { - button.innerText = '播放'; - br.style.display = 'none'; - progress.style.display='none'; - span.style.display = 'none'; - audio.pause(); - } - } - - uievent._previewMaterialAudio_onPitchChange = function (input) { - var audio = input.parentElement.nextElementSibling.nextElementSibling.nextElementSibling; - audio.preservesPitch = false; - audio.playbackRate = core.clamp((parseInt(input.value) || 100) / 100, 0.3, 3.0); - } - - uievent._previewMaterialAudio_onTimeUpdate = function (audio) { - var _format = function (time) { return parseInt(time/60) + ":" + core.setTwoDigits(parseInt(time) % 60); } - if (audio.duration > 0) { - audio.previousElementSibling.previousElementSibling.innerText = _format(audio.currentTime) + " / " + _format(audio.duration); - audio.nextElementSibling.setAttribute('value', audio.currentTime / audio.duration); - } - } - - uievent._previewMaterialAudio_seek = function (element, event) { - var audio = element.previousElementSibling; - var value = event.offsetX * element.max / element.offsetWidth; - element.setAttribute("value", value); - audio.currentTime = audio.duration * value; - if (audio.paused) audio.play(); - } - - var _previewMaterialAnimate = function (span, content) { - _previewMaterialAnimate_buildSounds(span, content); - - // 创建dom - if (!uievent.values.dom) { - var dom = document.createElement('span'); - dom.style.position = "relative"; - dom.style.marginLeft = "-10px"; - var canvas = document.createElement('canvas'); - canvas.width = canvas.height = core.__PIXELS__; - canvas.style.position = 'absolute'; - core.drawThumbnail(editor.currentFloorId, null, {ctx: canvas.getContext('2d')}); - dom.appendChild(canvas); - var canvas2 = document.createElement('canvas'); - canvas2.style.position = 'absolute'; - canvas2.width = canvas2.height = core.__PIXELS__; - uievent.values.ctx = canvas2.getContext('2d'); - dom.appendChild(canvas2); - var canvas3 = document.createElement('canvas'); - canvas3.width = canvas3.height = core.__PIXELS__; - dom.appendChild(canvas3); - uievent.values.dom = dom; - } - - span.appendChild(uievent.values.dom); - clearInterval(uievent.values.interval); - var frame = 0; - uievent.values.interval = setInterval(function () { - if (span.style.display == 'none') { - clearInterval(uievent.values.interval); - uievent.values.interval = null; - return; - } - core.clearMap(uievent.values.ctx); - core.maps._drawAnimateFrame(uievent.values.ctx, content, core.__PIXELS__ / 2, core.__PIXELS__ / 2, frame++); - }, 50); - } - - var _previewMaterialAnimate_buildSounds = function (span, content) { - var sounds = content.se || {}; - if (typeof sounds == 'string') sounds = {1: sounds}; - var pitch = content.pitch || {}; - - span.appendChild(document.createElement('br')); - var dom = document.createElement('span'); - dom.setAttribute('frames', content.frame); - var html = ""; - Object.keys(sounds).forEach(function (frame) { - html += "" + _previewMaterialAnimate_buildSoundRow(frame, sounds[frame], content.frame, pitch[frame]) + ""; - }); - html += ''; - html += ''; - html += "

"; - dom.innerHTML = html; - span.appendChild(dom); - _previewMaterialAnimate_awesomplete(span); - } - - var _previewMaterialAnimate_buildSoundRow = function (index, se, frames, pitch) { - var audios = Object.keys(core.material.sounds).sort().join(","); - var html = ""; - html += "第 帧:"; - html += ''; - html += ''; - html += " 音调:"; - html += ''; - html += '
'; - return html; - } - - var _previewMaterialAnimate_awesomplete = function (span) { - var inputs = span.getElementsByClassName("_audio"); - for (var i = 0; i < inputs.length; ++i) { - var input = inputs[i]; - if (!input.hasAttribute('awesomplete')) { - input.setAttribute('awesomplete', '1'); - new Awesomplete(input); - } - } - } - - uievent._previewMaterialAnimate = function (button) { - var span = button.nextElementSibling; - while (span.firstChild) span.removeChild(span.lastChild); - var filename = span.getAttribute("key"); - uievent.values.animates = uievent.values.animates || {}; - if (span.style.display == 'none') { - button.innerText = '收起'; - span.style.display = 'inline'; - if (uievent.values.animates[filename]) { - _previewMaterialAnimate(span, uievent.values.animates[filename]); - } else { - fs.readFile(filename, 'utf-8', function (e, d) { - if (e) { - alert('无法打开动画文件!'+e); return; - } - uievent.values.animates[filename] = core.loader._loadAnimate(d); - if (uievent.values.animates[filename]) { - uievent.values.animates[filename + ':raw'] = JSON.parse(d); - _previewMaterialAnimate(span, uievent.values.animates[filename]); - } - }) - } - } else { - button.innerText = '预览'; - span.style.display = 'none'; - } - } - - uievent._previewMaterialAnimate_previewSound = function (button) { - var input = button.previousElementSibling; - if (input.tagName == 'DIV') input = input.firstChild; - if (!input.value) return; - if (!uievent.values.audio) - uievent.values.audio = new Audio(); - uievent.values.audio.src = './project/sounds/' + input.value; - uievent.values.audio.preservesPitch = false; - uievent.values.audio.playbackRate = core.clamp((parseInt(button.nextElementSibling.children[0].value) || 100) / 100, 0.3, 3.0); - uievent.values.audio.play(); - } - - uievent._previewMaterialAnimate_addSound = function (button) { - var parent = button.parentElement; - var span = document.createElement("span"); - span.innerHTML = _previewMaterialAnimate_buildSoundRow(1, "", parseInt(parent.getAttribute("frames"))); - parent.insertBefore(span, button); - _previewMaterialAnimate_awesomplete(parent); - } - - uievent._previewMaterialAnimate_deleteSound = function (button) { - var element = button.parentElement; - element.parentElement.removeChild(element); - } - - uievent._previewMaterialAnimate_saveSound = function (button) { - var span = button.parentElement; - var filename = span.parentElement.getAttribute("key"); - if (!filename || !uievent.values.animates[filename]) return; - var se = {}; - var pitch = {}; - - var audios = span.getElementsByClassName("_audio"); - for (var i = 0; i < audios.length; ++i) { - var audio = audios[i]; - var select = audio.parentElement.previousElementSibling; - if (audio.value && select.tagName == 'SELECT') { - se[select.value] = audio.value; - var p = audio.parentElement.nextElementSibling.nextElementSibling.children[0]; - pitch[select.value] = core.clamp(parseInt(p.value) || 100, 30, 300); - } - } - uievent.values.animates[filename].se = se; - uievent.values.animates[filename+':raw'].se = se; - uievent.values.animates[filename].pitch = pitch; - uievent.values.animates[filename+':raw'].pitch = pitch; - fs.writeFile(filename, JSON.stringify(uievent.values.animates[filename+':raw']), 'utf-8', function (e, d) { - if (e) alert('无法修改音效文件!'+e); - else { - alert('动画音效修改成功!别忘了在全塔属性中注册音效哦!'); - } - }) - } - - // ------ 多选框 ------ // - uievent.popCheckboxSet = function (value, comments, title, callback) { - if (value == null) value = []; - if (!(value instanceof Array)) { - if (value == 0) value = []; - else value = [value]; - } - - uievent.isOpen = true; - uievent.elements.div.style.display = 'block'; - uievent.mode = 'popCheckboxSet'; - uievent.elements.selectPoint.style.display = 'none'; - uievent.elements.yes.style.display = 'block'; - uievent.elements.title.innerText = title; - 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 = 'none'; - uievent.elements.extraBody.style.display = 'block'; - uievent.elements.body.style.overflow = "auto"; - - uievent.elements.yes.onclick = function () { - var list = Array.from(document.getElementsByClassName('uieventCheckboxSet')).filter(function (one) { - return one.checked; - }).map(function (one) { - var value = one.getAttribute('key'); - if (one.getAttribute('_type') == 'number') value = parseFloat(value); - return value; - }); - uievent.close(); - if (callback) callback(list); - } - - var keys=Array.from(comments.key) - var prefixStrings=Array.from(comments.prefix) - for (var index = 0; index < value.length; index++) { - if (keys.indexOf(value[index])==-1) { - prefixStrings.push(value[index]+': ') - keys.push(value[index]) - } - } - var table = ''; - - for (var index = 0; index < keys.length; index++) { - var one = keys[index]; - if (index % 3 == 0) { - table += ''; - } - table += ``; - if (index % 3 == 2) { - table += ''; - } - } - if (keys.length % 3 != 0) table += ''; - table += '
${prefixStrings[index]}= 0? 'checked' : ''}/>
'; - - uievent.elements.extraBody.innerHTML = "

"+table+"

"; - } - - editor.constructor.prototype.uievent=uievent; - } \ No newline at end of file diff --git a/_server/editor_uievent.js b/_server/editor_uievent.js new file mode 100644 index 00000000..d19cdf84 --- /dev/null +++ b/_server/editor_uievent.js @@ -0,0 +1,1068 @@ +editor_uievent_wrapper = function (editor) { + + // ------ 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.select = document.getElementById('uieventSelect'); + 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.extraBody = document.getElementById('uieventExtraBody'); + + uievent.close = function () { + uievent.isOpen = false; + uievent.elements.div.style.display = 'none'; + if (uievent.values.interval) { + clearTimeout(uievent.values.interval); + clearInterval(uievent.values.interval); + } + uievent.values = {}; + } + uievent.elements.no.onclick = uievent.close; + + uievent.drawPreviewUI = function () { + core.setAlpha('uievent', 1); + core.clearMap('uievent'); + core.setFilter('uievent', null); + + // 绘制UI + var background = uievent.elements.select.value; + if (background == 'thumbnail') { + core.drawThumbnail(editor.currentFloorId, null, {ctx: 'uievent'}); + } + else { + core.fillRect('uievent', 0, 0, core.__PIXELS__, core.__PIXELS__, background); + } + + if (uievent.values.list instanceof Array) { + uievent.values.list.forEach(function (data) { + if (typeof data == 'string') data = { "type": "text", "text": data }; + var type = data.type; + if (type == "text") { + data.ctx = 'uievent'; + core.saveCanvas('uievent'); + core.drawTextBox(data.text, data); + core.loadCanvas('uievent'); + return; + } + else if (type == "choices") { + for (var i = 0; i < data.choices.length; i++) { + if (typeof data.choices[i] === 'string') + data.choices[i] = {"text": data.choices[i]}; + data.choices[i].text = core.replaceText(data.choices[i].text); + } + core.saveCanvas('uievent'); + core.status.event.selection = data.selected || 0; + core.drawChoices(core.replaceText(data.text), data.choices, data.width, 'uievent'); + core.status.event.selection = null; + core.loadCanvas('uievent'); + return; + } else if (type == "confirm") { + core.saveCanvas('uievent'); + core.drawConfirmBox(data.text, null, null, 'uievent'); + core.loadCanvas('uievent'); + } else if (core.ui["_uievent_" + type]) + 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.select.style.display = 'inline'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'block'; + uievent.elements.extraBody.style.display = 'none'; + uievent.elements.body.style.overflow = "hidden"; + + uievent.elements.select.innerHTML = + '' + + '' + + ''; + uievent.elements.select.onchange = function () { + uievent.drawPreviewUI(); + } + + uievent.values.list = list; + uievent.drawPreviewUI(); + } + + uievent.selectPoint = function (floorId, x, y, bigmap, callback) { + uievent.values.bigmap = bigmap; + uievent.values.size = editor.isMobile ? window.innerWidth / core.__SIZE__ : 32 * 540 / core.__PIXELS__; + + 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.select.style.display = 'none'; + uievent.elements.selectFloor.style.display = 'inline'; + uievent.elements.selectPointBox.style.display = 'block'; + uievent.elements.canvas.style.display = 'block'; + uievent.elements.extraBody.style.display = 'none'; + uievent.elements.body.style.overflow = "hidden"; + uievent.elements.yes.onclick = function () { + var floorId = uievent.values.floorId, x = uievent.values.x, y = uievent.values.y; + var multipoints = uievent.values.multipoints || []; + uievent.close(); + if (callback) { + if (multipoints.length > 0) { + callback(floorId, multipoints.map(function (one) { return one.split(',')[0]}).join(','), + multipoints.map(function (one) { return one.split(',')[1]}).join(',')); + } else { + callback(floorId, x, y); + } + } + } + + // Append children + var floors = ""; + core.floorIds.forEach(function (f) { + floors += ""; + }) + uievent.elements.selectFloor.innerHTML = floors; + // 检查多选点 + if (/^\d+(,\d+)+$/.test(x) && /^\d+(,\d+)+$/.test(y)) { + var xx = x.split(','), yy = y.split(','); + uievent.values.multipoints = []; + for (var i = 0; i < xx.length; ++i) { + uievent.values.multipoints.push(xx[i] + "," + yy[i]); + } + x = xx[xx.length - 1]; + y = yy[yy.length - 1]; + } + 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 + ')'; + // 计算size + uievent.values.boxSize = uievent.values.size * + (uievent.values.bigmap ? (core.__SIZE__ / Math.max(uievent.values.width, uievent.values.height)) : 1); + uievent.values.boxLeft = uievent.values.bigmap ? + (core.__PIXELS__ * Math.max(0, (1 - uievent.values.width / uievent.values.height) / 2)) : 0; + uievent.values.boxTop = uievent.values.bigmap ? + (core.__PIXELS__ * Math.max(0, (1 - uievent.values.height / uievent.values.width) / 2)) : 0; + + if (uievent.values.bigmap) { + uievent.elements.selectPointBox.style.left = uievent.values.boxSize * uievent.values.x + uievent.values.boxLeft + "px"; + uievent.elements.selectPointBox.style.top = uievent.values.boxSize * uievent.values.y + uievent.values.boxTop + "px"; + } else { + uievent.elements.selectPointBox.style.left = uievent.values.boxSize * (uievent.values.x - uievent.values.left) + "px"; + uievent.elements.selectPointBox.style.top = uievent.values.boxSize * (uievent.values.y - uievent.values.top) + "px"; + } + uievent.elements.selectPointBox.style.width = uievent.values.boxSize - 6 + "px"; + uievent.elements.selectPointBox.style.height = uievent.values.boxSize - 6 + "px"; + + if (redraw) { + core.setAlpha('uievent', 1); + core.clearMap('uievent'); + core.drawThumbnail(uievent.values.floorId, null, { + ctx: 'uievent', centerX: uievent.values.left + core.__HALF_SIZE__, + centerY: uievent.values.top + core.__HALF_SIZE__, all: uievent.values.bigmap + }); + uievent.values.multipoints = uievent.values.multipoints || []; + core.setTextAlign('uievent', 'right'); + for (var i = 0; i < uievent.values.multipoints.length; ++i) { + var xy = uievent.values.multipoints[i].split(","), x = parseInt(xy[0]), y = parseInt(xy[1]); + core.fillBoldText('uievent', i + 1, + 32 * (x - uievent.values.left) + 28 , 32 * (y - uievent.values.top) + 26, '#FF7F00', null, '14px Verdana'); + } + core.setTextAlign('uievent', 'left'); + } + } + + 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.values.multipoints = []; + uievent.setPoint(uievent.elements.selectFloor.value); + } + + uievent.elements.selectPointBox.onclick = function (e) { + e.preventDefault(); + e.stopPropagation(); + return false; + } + + uievent.elements.body.onclick = function (e) { + if (uievent.mode != 'selectPoint') return; + if (uievent.values.bigmap) { + uievent.values.x = core.clamp(Math.floor((e.offsetX - uievent.values.boxLeft) / uievent.values.boxSize), 0, uievent.values.width - 1); + uievent.values.y = core.clamp(Math.floor((e.offsetY - uievent.values.boxTop) / uievent.values.boxSize), 0, uievent.values.height - 1); + } else { + 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.elements.body.oncontextmenu = function (e) { + e.preventDefault(); + e.stopPropagation(); + if (uievent.mode != 'selectPoint' || uievent.values.bigmap) return; + var x = uievent.values.left + Math.floor(e.offsetX / uievent.values.size); + var y = uievent.values.top + Math.floor(e.offsetY / uievent.values.size); + uievent.values.multipoints = uievent.values.multipoints || []; + if (uievent.values.multipoints.indexOf(x+","+y) >= 0) { + uievent.values.multipoints = uievent.values.multipoints.filter(function (o) { return o != x+","+y;}) + } else { + uievent.values.multipoints.push(x+","+y); + } + uievent.values.x = x; + uievent.values.y = y; + uievent.updateSelectPoint(true); + return false; + } + + uievent.move = function (dx, dy) { + if (uievent.mode != 'selectPoint') return; + if (uievent.values.bigmap) 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); + }; + + uievent.triggerBigmap = function () { + if (uievent.mode != 'selectPoint') return; + uievent.values.bigmap = !uievent.values.bigmap; + uievent.values.multipoints = []; + uievent.setPoint(uievent.values.floorId); + }; + + (function () { + + var viewportButtons = uievent.elements.selectPointButtons; + var pressTimer = null; + for (var ii = 0, node; node = viewportButtons.children[ii]; ii++) { + if (ii == 4) { + node.onclick = uievent.triggerBigmap; + continue; + } + if (ii == 5) { + node.onclick = function () { + alert(core.copy(uievent.values.floorId) ? ('楼层ID '+uievent.values.floorId+' 已成功复制到剪切板') : '无法复制楼层ID'); + } + } + (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') 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.values.multipoints = []; + uievent.setPoint(core.floorIds[index]); + } + + uievent.onKeyDown = function (e) { + if (e.keyCode == 27) editor.uievent.close(); + if (uievent.mode == 'selectPoint') { + if (e.keyCode == 87) editor.uievent.move(0, -1) + if (e.keyCode == 65) editor.uievent.move(-1, 0) + if (e.keyCode == 83) editor.uievent.move(0, 1); + if (e.keyCode == 68) editor.uievent.move(1, 0); + } + } + + // ------ 搜索变量出现的位置,也放在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.select.style.display = 'inline'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'none'; + uievent.elements.extraBody.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.select.innerHTML = html; + uievent.elements.select.onchange = uievent.doSearchUsedFlags; + + uievent.doSearchUsedFlags(); + } + + uievent.doSearchUsedFlags = function () { + var flag = uievent.elements.select.value; + + var html = "

该变量出现的所有位置如下:

"; + uievent.elements.extraBody.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\u3040-\u30FF\u2160-\u216B\u0391-\u03C9]$/.test(obj.charAt(index + length))) return true; + } + } + + uievent._searchUsedFlags = function (flag) { + var list = []; + // 每个点的事件 + var events = ["events", "autoEvent", "changeFloor", "beforeBattle", "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 + ") 点"); + } + } + } + }); + } + // 公共事件 + for (var name in events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent) { + if (hasUsedFlags(events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent[name], flag)) + list.push("公共事件 " + name); + } + // 道具 & 装备属性 + for (var id in items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a) { + var item = items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a[id]; + // 装备属性 + if (hasUsedFlags(item.equip, flag)) { + list.push("道具 " + (item.name || id) + " 的装备属性"); + } + // 使用事件 + if (hasUsedFlags(item.useItemEvent, flag)) { + list.push("道具 " + (item.name || id) + " 的使用事件"); + } + } + // 怪物战前 & 战后 + for (var id in enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80) { + var enemy = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80[id]; + if (hasUsedFlags(enemy.beforeBattle, flag)) { + list.push("怪物 " + (enemy.name || id) + " 的战前事件"); + } + if (hasUsedFlags(enemy.afterBattle, flag)) { + list.push("怪物 " + (enemy.name || id) + " 的战后事件"); + } + } + // 图块的碰触 & 门信息 + for (var id in maps_90f36752_8815_4be8_b32b_d7fad1d0542e) { + var mapInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e[id]; + if (hasUsedFlags(mapInfo.doorInfo, flag)) + list.push("图块 " + (mapInfo.name || mapInfo.id) + " 的门信息"); + if (hasUsedFlags(mapInfo.event, flag)) + list.push("图块 " + (mapInfo.name || mapInfo.id) + " 碰触事件"); + } + // 难度 & 标题事件 & 开场剧情 & 等级提升 + if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.main.levelChoose, flag)) + list.push("难度分歧"); + if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.startCanvas, flag)) + list.push("标题事件"); + if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.startText, flag)) + list.push("开场剧情"); + if (hasUsedFlags(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.levelUp, flag)) + list.push("等级提升"); + // 全局商店 + (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData.shops || []).forEach(function (shop) { + if (hasUsedFlags(shop, flag)) list.push("商店 " + shop.id); + }); + + return list; + } + + // ------ 选择楼层 ------ // + uievent.selectFloor = function (floorId, title, callback) { + uievent.isOpen = true; + uievent.elements.div.style.display = 'block'; + uievent.mode = 'selectFloor'; + uievent.elements.selectPoint.style.display = 'none'; + uievent.elements.yes.style.display = 'block'; + uievent.elements.title.innerText = title; + uievent.elements.select.style.display = 'none'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'none'; + uievent.elements.extraBody.style.display = 'block'; + uievent.elements.body.style.overflow = "auto"; + + uievent.elements.yes.onclick = function () { + var floorId = uievent.values.floorId; + uievent.close(); + if (callback) callback(floorId); + } + + if (floorId instanceof Array) floorId = floorId[0]; + if (!floorId) floorId = editor.currentFloorId; + uievent.values.floorId = floorId; + + var html = "

"; + html += "搜索楼层:"; + html += "" + + one + '(' + floor.title + ')' + ""; + html += ""; + html += ""; + html += '
'; + }); + floorList.innerHTML = html; + } + + uievent._selectFloor_preview = function (button) { + var span = button.nextElementSibling; + while (span.firstChild) span.removeChild(span.lastChild); + var floorId = span.getAttribute('key'); + + if (span.style.display == 'none') { + button.innerText = '收起'; + span.style.display = 'inline'; + if (!uievent.values.dom) { + var canvas = document.createElement('canvas'); + canvas.style.position = 'relative'; + canvas.style.marginLeft = "-10px"; + canvas.style.marginTop = '5px'; + canvas.width = canvas.height = core.__PIXELS__; + uievent.values.dom = canvas; + uievent.values.ctx = canvas.getContext('2d'); + } + span.appendChild(uievent.values.dom); + core.clearMap(uievent.values.ctx); + core.drawThumbnail(floorId, null, {ctx: uievent.values.ctx, all: true}); + } else { + button.innerText = '预览'; + span.style.display = 'none'; + } + } + + // ------ 素材选择框 ------ // + uievent.selectMaterial = function (value, title, directory, transform, callback) { + var one = directory.split(':'); + if (one.length > 1) directory = one[0]; + var appendedImages = one[1] == 'images' ? core.material.images.images : {}; + + fs.readdir(directory, function (err, data) { + if (err) { + printe(directory + '不存在!'); + throw (directory + '不存在!'); + } + if (!(data instanceof Array)) { + printe('没有可显示的内容') + return; + } + value = value || []; + data = (transform ? data.map(transform) : data).filter(function (one) {return one;}).sort(); + var data2 = Object.keys(appendedImages); + data2 = (transform ? data2.map(transform) : data2).filter(function (one) { + return one && data.indexOf(one) < 0; + }).sort(); + + uievent.isOpen = true; + uievent.elements.div.style.display = 'block'; + uievent.mode = 'selectMaterial'; + uievent.elements.selectPoint.style.display = 'none'; + uievent.elements.yes.style.display = 'block'; + uievent.elements.title.innerText = title; + uievent.elements.select.style.display = 'none'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'none'; + uievent.elements.extraBody.style.display = 'block'; + uievent.elements.body.style.overflow = "auto"; + + uievent.elements.yes.onclick = function () { + var list = Array.from(document.getElementsByClassName('materialCheckbox')).filter(function (one) { + return one.checked; + }).map(function (one) {return one.getAttribute('key'); }); + uievent.close(); + if (callback) callback(list); + } + + var _isTileset = directory.indexOf('project/tilesets') >= 0; + + // 显示每一项内容 + var html = "

"; + html += ""+ + "
"; + if (_isTileset) { + html += "警告!额外素材一旦注册成功将不可删除,否则可能会导致素材错位风险!如果你不再想用某个额外素材," + +"但又不想让它出现在素材区,可以考虑使用空气墙同名替换该额外素材文件。
" + } + data.forEach(function (one) { + var checked = value.indexOf(one) >= 0? 'checked' : ''; + var disabled = _isTileset && value.indexOf(one) >= 0 ? 'disabled' : '' + html += ` ${one}`; + // 预览图片 + if (one.endsWith('.png') || one.endsWith('.jpg') || one.endsWith('.jpeg') || one.endsWith('.gif')) { + html += ""; + html += '
'; + } + // 试听音频 + if (one.endsWith('.mp3') || one.endsWith('.ogg') || one.endsWith('.wav') || one.endsWith('.m4a') || one.endsWith('.flac')) { + html += "" + html += " 音调:"; + html += `0:00 / 0:00
+ + `; + } + // 预览动画 + if (directory.indexOf('animates') >= 0) { + html += ""; + html += ""; + } + html += '
'; + }); + data2.forEach(function (one) { + var checked = value.indexOf(one) >= 0? 'checked' : ''; + var disabled = _isTileset && value.indexOf(one) >= 0 ? 'disabled' : ''; + html += ` ${one}`; + // 预览图片 + if (one.endsWith('.png') || one.endsWith('.jpg') || one.endsWith('.jpeg') || one.endsWith('.gif')) { + html += ""; + html += '

'; + } + }) + html += "

"; + html += "

如果文件未在此列表显示,请检查文件名是否合法(只能由数字字母下划线横线和点组成),后缀名是否正确。

"; + uievent.elements.extraBody.innerHTML = html; + }); + } + + uievent._selectAllMaterial = function (checked) { + Array.from(document.getElementsByClassName('materialCheckbox')).forEach(function (one) { + if (!one.disabled) one.checked = checked; + }) + } + + uievent._previewMaterialImage = function (button) { + var br = button.nextElementSibling; + var img = br.nextElementSibling; + if (br.style.display == 'none') { + button.innerText = '折叠'; + br.style.display = 'block'; + img.style.display = 'block'; + img.src = img.getAttribute('key'); + } else { + button.innerText = '预览'; + br.style.display = 'none'; + img.style.display = 'none'; + } + } + + uievent._previewMaterialImage2 = function (button) { + var br = button.nextElementSibling; + if (br.style.display == 'none') { + button.innerText = '折叠'; + br.style.display = 'block'; + br.parentElement.insertBefore(core.material.images.images[br.getAttribute('key')], br.nextElementSibling); + } else { + button.innerText = '预览'; + br.style.display = 'none'; + br.parentElement.removeChild(core.material.images.images[br.getAttribute('key')]); + } + } + + uievent._previewMaterialAudio = function (button) { + var span = button.nextElementSibling.nextElementSibling; + var br = span.nextElementSibling; + var audio = br.nextElementSibling; + var progress = audio.nextElementSibling; + if (br.style.display == 'none') { + button.innerText = '暂停'; + br.style.display = 'block'; + progress.style.display = 'block'; + span.style.display = 'inline'; + audio.play(); + } else { + button.innerText = '播放'; + br.style.display = 'none'; + progress.style.display='none'; + span.style.display = 'none'; + audio.pause(); + } + } + + uievent._previewMaterialAudio_onPitchChange = function (input) { + var audio = input.parentElement.nextElementSibling.nextElementSibling.nextElementSibling; + audio.preservesPitch = false; + audio.playbackRate = core.clamp((parseInt(input.value) || 100) / 100, 0.3, 3.0); + } + + uievent._previewMaterialAudio_onTimeUpdate = function (audio) { + var _format = function (time) { return parseInt(time/60) + ":" + core.setTwoDigits(parseInt(time) % 60); } + if (audio.duration > 0) { + audio.previousElementSibling.previousElementSibling.innerText = _format(audio.currentTime) + " / " + _format(audio.duration); + audio.nextElementSibling.setAttribute('value', audio.currentTime / audio.duration); + } + } + + uievent._previewMaterialAudio_seek = function (element, event) { + var audio = element.previousElementSibling; + var value = event.offsetX * element.max / element.offsetWidth; + element.setAttribute("value", value); + audio.currentTime = audio.duration * value; + if (audio.paused) audio.play(); + } + + var _previewMaterialAnimate = function (span, content) { + _previewMaterialAnimate_buildSounds(span, content); + + // 创建dom + if (!uievent.values.dom) { + var dom = document.createElement('span'); + dom.style.position = "relative"; + dom.style.marginLeft = "-10px"; + var canvas = document.createElement('canvas'); + canvas.width = canvas.height = core.__PIXELS__; + canvas.style.position = 'absolute'; + core.drawThumbnail(editor.currentFloorId, null, {ctx: canvas.getContext('2d')}); + dom.appendChild(canvas); + var canvas2 = document.createElement('canvas'); + canvas2.style.position = 'absolute'; + canvas2.width = canvas2.height = core.__PIXELS__; + uievent.values.ctx = canvas2.getContext('2d'); + dom.appendChild(canvas2); + var canvas3 = document.createElement('canvas'); + canvas3.width = canvas3.height = core.__PIXELS__; + dom.appendChild(canvas3); + uievent.values.dom = dom; + } + + span.appendChild(uievent.values.dom); + clearInterval(uievent.values.interval); + var frame = 0; + uievent.values.interval = setInterval(function () { + if (span.style.display == 'none') { + clearInterval(uievent.values.interval); + uievent.values.interval = null; + return; + } + core.clearMap(uievent.values.ctx); + core.maps._drawAnimateFrame(uievent.values.ctx, content, core.__PIXELS__ / 2, core.__PIXELS__ / 2, frame++); + }, 50); + } + + var _previewMaterialAnimate_buildSounds = function (span, content) { + var sounds = content.se || {}; + if (typeof sounds == 'string') sounds = {1: sounds}; + var pitch = content.pitch || {}; + + span.appendChild(document.createElement('br')); + var dom = document.createElement('span'); + dom.setAttribute('frames', content.frame); + var html = ""; + Object.keys(sounds).forEach(function (frame) { + html += "" + _previewMaterialAnimate_buildSoundRow(frame, sounds[frame], content.frame, pitch[frame]) + ""; + }); + html += ''; + html += ''; + html += "

"; + dom.innerHTML = html; + span.appendChild(dom); + _previewMaterialAnimate_awesomplete(span); + } + + var _previewMaterialAnimate_buildSoundRow = function (index, se, frames, pitch) { + var audios = Object.keys(core.material.sounds).sort().join(","); + var html = ""; + html += "第 帧:"; + html += ''; + html += ''; + html += " 音调:"; + html += ''; + html += '
'; + return html; + } + + var _previewMaterialAnimate_awesomplete = function (span) { + var inputs = span.getElementsByClassName("_audio"); + for (var i = 0; i < inputs.length; ++i) { + var input = inputs[i]; + if (!input.hasAttribute('awesomplete')) { + input.setAttribute('awesomplete', '1'); + new Awesomplete(input); + } + } + } + + uievent._previewMaterialAnimate = function (button) { + var span = button.nextElementSibling; + while (span.firstChild) span.removeChild(span.lastChild); + var filename = span.getAttribute("key"); + uievent.values.animates = uievent.values.animates || {}; + if (span.style.display == 'none') { + button.innerText = '收起'; + span.style.display = 'inline'; + if (uievent.values.animates[filename]) { + _previewMaterialAnimate(span, uievent.values.animates[filename]); + } else { + fs.readFile(filename, 'utf-8', function (e, d) { + if (e) { + alert('无法打开动画文件!'+e); return; + } + uievent.values.animates[filename] = core.loader._loadAnimate(d); + if (uievent.values.animates[filename]) { + uievent.values.animates[filename + ':raw'] = JSON.parse(d); + _previewMaterialAnimate(span, uievent.values.animates[filename]); + } + }) + } + } else { + button.innerText = '预览'; + span.style.display = 'none'; + } + } + + uievent._previewMaterialAnimate_previewSound = function (button) { + var input = button.previousElementSibling; + if (input.tagName == 'DIV') input = input.firstChild; + if (!input.value) return; + if (!uievent.values.audio) + uievent.values.audio = new Audio(); + uievent.values.audio.src = './project/sounds/' + input.value; + uievent.values.audio.preservesPitch = false; + uievent.values.audio.playbackRate = core.clamp((parseInt(button.nextElementSibling.children[0].value) || 100) / 100, 0.3, 3.0); + uievent.values.audio.play(); + } + + uievent._previewMaterialAnimate_addSound = function (button) { + var parent = button.parentElement; + var span = document.createElement("span"); + span.innerHTML = _previewMaterialAnimate_buildSoundRow(1, "", parseInt(parent.getAttribute("frames"))); + parent.insertBefore(span, button); + _previewMaterialAnimate_awesomplete(parent); + } + + uievent._previewMaterialAnimate_deleteSound = function (button) { + var element = button.parentElement; + element.parentElement.removeChild(element); + } + + uievent._previewMaterialAnimate_saveSound = function (button) { + var span = button.parentElement; + var filename = span.parentElement.getAttribute("key"); + if (!filename || !uievent.values.animates[filename]) return; + var se = {}; + var pitch = {}; + + var audios = span.getElementsByClassName("_audio"); + for (var i = 0; i < audios.length; ++i) { + var audio = audios[i]; + var select = audio.parentElement.previousElementSibling; + if (audio.value && select.tagName == 'SELECT') { + se[select.value] = audio.value; + var p = audio.parentElement.nextElementSibling.nextElementSibling.children[0]; + pitch[select.value] = core.clamp(parseInt(p.value) || 100, 30, 300); + } + } + uievent.values.animates[filename].se = se; + uievent.values.animates[filename+':raw'].se = se; + uievent.values.animates[filename].pitch = pitch; + uievent.values.animates[filename+':raw'].pitch = pitch; + fs.writeFile(filename, JSON.stringify(uievent.values.animates[filename+':raw']), 'utf-8', function (e, d) { + if (e) alert('无法修改音效文件!'+e); + else { + alert('动画音效修改成功!别忘了在全塔属性中注册音效哦!'); + } + }) + } + + // ------ 多选框 ------ // + uievent.popCheckboxSet = function (value, comments, title, callback) { + if (value == null) value = []; + if (!(value instanceof Array)) { + if (value == 0) value = []; + else value = [value]; + } + + uievent.isOpen = true; + uievent.elements.div.style.display = 'block'; + uievent.mode = 'popCheckboxSet'; + uievent.elements.selectPoint.style.display = 'none'; + uievent.elements.yes.style.display = 'block'; + uievent.elements.title.innerText = title; + uievent.elements.select.style.display = 'none'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'none'; + uievent.elements.extraBody.style.display = 'block'; + uievent.elements.body.style.overflow = "auto"; + + uievent.elements.yes.onclick = function () { + var list = Array.from(document.getElementsByClassName('uieventCheckboxSet')).filter(function (one) { + return one.checked; + }).map(function (one) { + var value = one.getAttribute('key'); + if (one.getAttribute('_type') == 'number') value = parseFloat(value); + return value; + }); + uievent.close(); + if (callback) callback(list); + } + + var keys=Array.from(comments.key) + var prefixStrings=Array.from(comments.prefix) + for (var index = 0; index < value.length; index++) { + if (keys.indexOf(value[index])==-1) { + prefixStrings.push(value[index]+': ') + keys.push(value[index]) + } + } + var table = ''; + + for (var index = 0; index < keys.length; index++) { + var one = keys[index]; + if (index % 3 == 0) { + table += ''; + } + table += ``; + if (index % 3 == 2) { + table += ''; + } + } + if (keys.length % 3 != 0) table += ''; + table += '
${prefixStrings[index]}= 0? 'checked' : ''}/>
'; + + uievent.elements.extraBody.innerHTML = "

"+table+"

"; + } + + uievent.previewEditorMulti = function (mode, code) { + if (mode == 'statusBar') return uievent.previewStatusBar(code); + } + + // ------ 状态栏预览 ------ // + uievent.previewStatusBar = function (code) { + if (!/^function\s*\(\)\s*{/.test(code)) return; + + uievent.isOpen = true; + uievent.elements.div.style.display = 'block'; + uievent.mode = 'previewStatusBar'; + uievent.elements.selectPoint.style.display = 'none'; + uievent.elements.yes.style.display = 'none'; + uievent.elements.title.innerText = '状态栏自绘预览'; + uievent.elements.select.style.display = 'inline'; + uievent.elements.selectFloor.style.display = 'none'; + uievent.elements.selectPointBox.style.display = 'none'; + uievent.elements.canvas.style.display = 'none'; + uievent.elements.extraBody.style.display = 'block'; + uievent.elements.body.style.overflow = "auto"; + + uievent.elements.select.innerHTML = '' + uievent.elements.select.onchange = uievent._previewStatusBar; + + // 计算在自绘状态栏中使用到的所有flag + var flags = {}; + code.replace(/flag:([a-zA-Z0-9_\u4E00-\u9FCC\u3040-\u30FF\u2160-\u216B\u0391-\u03C9]+)/g, function (s0, s1) { + flags[s1] = 0; return s0; + }); + code.replace(/(core\.)?flags.([a-zA-Z0-9_]+)/g, function (s0, s1, s2) { + if (!s1) flags[s2] = 0; return s0; + }); + code.replace(/core\.(has|get|set|add|remove)Flag\('(.*?)'/g, function (s0, s1, s2) { + flags[s2] = 0; return s0; + }); + code.replace(/core\.(has|get|set|add|remove)Flag\("(.*?)"/g, function (s0, s1, s2) { + flags[s2] = 0; return s0; + }); + + var html = ''; + html += "

注:此处预览效果与实际游戏内效果会有所出入,仅供参考,请以游戏内实际效果为准。

"; + html += "

"; + html += ""; + html += "属性设置:
" + html += "名称: 生命: 上限: 攻击: 防御: 护盾: "; + html += "魔力: 上限: 金币: 经验: 等级: "; + html += "
当前道具ID(以逗号分隔):
"; + html += "
当前装备ID(以逗号分隔):
"; + html += "
当前变量值(JSON格式):
"; + html += "

" + uievent.elements.extraBody.innerHTML = html; + + var inputs = document.querySelectorAll('#_previewStatusBarP input'); + for (var i = 0; i < inputs.length; ++i) inputs[i].style.width = '50px'; + + uievent.values.code = code; + uievent._previewStatusBar(); + } + + uievent._previewStatusBar = function () { + var domStyle = core.clone(core.domStyle); + var hero = core.clone(core.status.hero); + core.status.hero.flags.__statistics__ = true; + + var statusCanvasCtx = core.dom.statusCanvasCtx; + var enable = core.flags.statusCanvas; + + core.domStyle.showStatusBar = true; + core.flags.statusCanvas = true; + core.domStyle.isVertical = uievent.elements.select.value == 'vertical'; + + var canvas = document.getElementById('_previewStatusBarCanvas'); + var canvas2 = document.createElement('canvas'); + + document.getElementById('_previewStatusBarP').style.flexWrap = core.domStyle.isVertical ? 'wrap' : 'nowrap'; + + var values = Array.from(document.getElementById('_previewStatusBarValue').children).filter(function (one) { + return one.tagName == 'INPUT' || one.tagName == 'TEXTAREA'; + }).map(function (one) { return one.value; }); + core.status.hero.name = values[0]; + core.status.hero.hp = parseFloat(values[1]); + core.status.hero.hpmax = parseFloat(values[2]); + core.status.hero.atk = parseFloat(values[3]); + core.status.hero.def = parseFloat(values[4]); + core.status.hero.mdef = parseFloat(values[5]); + core.status.hero.mana = parseFloat(values[6]); + core.status.hero.manamax = parseFloat(values[7]); + core.status.hero.money = parseFloat(values[8]); + core.status.hero.exp = parseFloat(values[9]); + core.status.hero.lv = parseFloat(values[10]); + + values[11].split(',').forEach(function (itemId) { + if (!core.material.items[itemId]) return; + var itemCls = core.material.items[itemId].cls; + if (itemCls == 'items') return; + core.status.hero.items[itemCls][itemId] = (core.status.hero.items[itemCls][itemId]||0) + 1; + }); + core.status.hero.equipment = values[12].split(','); + try { + var flags = JSON.parse(values[13]); + for (var flag in flags) { + core.status.hero.flags[flag] = flags[flag]; + } + } catch (e) {} + + var ctx = canvas2.getContext('2d'); + + if (core.domStyle.isVertical) { + canvas.width = canvas2.width = core.__PIXELS__; + canvas.height = canvas2.height = 32*(core.values.statusCanvasRowsOnMobile||3)+9; + } else if (data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags.extendToolbar) { + canvas.width = canvas2.width = Math.round(core.__PIXELS__ * 0.31); + canvas.height = canvas2.height = core.__PIXELS__ + 3 + 38; + } else { + canvas.width = canvas2.width = Math.round(core.__PIXELS__ * 0.31); + canvas.height = canvas2.height = core.__PIXELS__; + } + + core.dom.statusCanvasCtx = ctx; + + try { + eval('(' + uievent.values.code + ')()'); + } catch (e) { + console.error(e); + } + + var toCtx = canvas.getContext('2d'); + core.fillRect(toCtx, 0, 0, canvas.width, canvas.height, 'black'); + core.drawImage(toCtx, canvas2, 0, 0); + + core.dom.statusCanvasCtx = statusCanvasCtx; + core.domStyle = domStyle; + core.flags.statusCanvas = enable; + core.status.hero = hero; + window.hero = hero; + window.flags = core.status.hero.flags; + } + + editor.constructor.prototype.uievent=uievent; +} \ No newline at end of file diff --git a/_server/table/data.comment.js b/_server/table/data.comment.js index 6a2031b9..2991876e 100644 --- a/_server/table/data.comment.js +++ b/_server/table/data.comment.js @@ -138,9 +138,9 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "equipName": { "_leaf": true, "_type": "textarea", - "_range": "(thiseval instanceof Array && thiseval.length<=6)||thiseval==null", + "_range": "(thiseval instanceof Array)||thiseval==null", "_docs": "装备孔", - "_data": "装备位名称,为不超过6个的数组,此项的顺序与equiptype数值关联;例如可写[\"武器\",\"防具\",\"首饰\"]等等。" + "_data": "装备位名称,为一个数组,此项的顺序与equiptype数值关联;例如可写[\"武器\",\"防具\",\"首饰\"]等等。" }, "startBgm": { "_leaf": true, @@ -344,7 +344,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "flags": { "_leaf": true, "_type": "textarea", - "_hide": true, "_range": "thiseval instanceof Object && !(thiseval instanceof Array)", "_data": "游戏变量" }, @@ -490,10 +489,10 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_leaf": true, "_type": "select", "_select": { - "values": [1, 2, 3, 4] + "values": [1, 2, 3, 4, 5] }, "_docs": "竖状态栏自绘行数", - "_data": "竖屏模式下,顶端状态栏canvas化后的行数。\n此项将决定竖屏的状态栏高度,如果设置则不小于1且不大于4。\n仅在statusCanvas开启时才有效" + "_data": "竖屏模式下,顶端状态栏canvas化后的行数。\n此项将决定竖屏的状态栏高度,如果设置则不小于1且不大于5。\n仅在statusCanvas开启时才有效" }, "floorChangeTime": { "_leaf": true, diff --git a/_server/table/functions.comment.js b/_server/table/functions.comment.js index f14d295a..9326bf12 100644 --- a/_server/table/functions.comment.js +++ b/_server/table/functions.comment.js @@ -192,6 +192,7 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_leaf": true, "_type": "textarea", "_lint": true, + "_preview": "statusBar", "_data": "自绘状态栏" }, "drawStatistics": { diff --git a/_server/thirdparty/caret-position.js b/_server/thirdparty/caret-position.js index 8294e99f..b6e14aa6 100644 --- a/_server/thirdparty/caret-position.js +++ b/_server/thirdparty/caret-position.js @@ -109,7 +109,7 @@ } }); if (!isInput) - style.whiteSpace = 'pre'; + style.whiteSpace = 'pre-wrap'; if (isFirefox) { // Firefox lies about the overflow property for textareas: https://bugzilla.mozilla.org/show_bug.cgi?id=984275 diff --git a/docs/sample0.png b/docs/sample0.png index 6598e611..24d6ac87 100644 Binary files a/docs/sample0.png and b/docs/sample0.png differ diff --git a/editor-mobile.html b/editor-mobile.html index 0356e7c5..5964f4c7 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -29,9 +29,9 @@
- + - + 保留楼层属性
@@ -55,9 +55,9 @@
- + - + 保留楼层属性
@@ -150,12 +150,14 @@
- + +
- + - + +
@@ -210,6 +212,7 @@ --> + @@ -241,7 +244,9 @@
+ + 语法检查 @@ -346,7 +351,7 @@
- @@ -381,8 +386,9 @@ + - +