diff --git a/_docs/api.md b/_docs/api.md index b75d25d1..737333e3 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -1222,13 +1222,16 @@ nearStair: fn() -> bool turnBlock: fn(direction?: string, x?: number, y?: number, floorId?: string) 事件转向 -getMapArray: fn(floorId?: string) -> [[number]] +getMapArray: fn(floorId?: string, noCache?: bool) -> [[number]] 生成事件层矩阵 例如:core.getMapArray('MT0'); // 生成主塔0层的事件层矩阵,隐藏的图块视为0 floorId: 地图id,不填视为当前地图 showDisable: 可选,true表示隐藏的图块也会被表示出来 返回值:事件层矩阵,注意对其阵元的访问是[y][x] +getMapNumber: fn(x: number, y: number, floorId?: string, noCache?: bool) -> number +获得事件层某个点的数字 + jumpBlock: fn(sx: number, sy: number, ex: number, ey: number, time?: number, keep?: bool, callback?: fn()) 跳跃图块;从V2.7开始不再有音效 例如:core.jumpBlock(0, 0, 0, 0); // 令地图左上角的图块原地跳跃半秒,再花半秒淡出 @@ -1358,9 +1361,12 @@ canMoveDirectlyArray: fn(locs?: [[number]]) hideFloorImage: fn(loc?: [number]|[[number]], floorId?: string, callback?: fn()) 隐藏一个楼层贴图 -extractBlocks: fn(map?: [[number]], flags?: flags) +extractBlocks: fn(map?: ?) 根据需求解析出blocks +extractBlocksForUI: fn(map?: ?, flags?: flags) +根据需求为UI解析出blocks + getBlockId: fn(x: number, y: number, floorId?: string, showDisable?: bool) -> string 判定某个点的图块id 例如:if(core.getBlockId(x1, y1) != 'greenSlime' && core.getBlockId(x2, y2) != 'redSlime') core.openDoor(x3, y3); // 一个简单的机关门事件,打败或炸掉这一对绿头怪和红头怪就开门 @@ -1370,17 +1376,22 @@ floorId: 地图id,不填视为当前地图 showDisable: 隐藏点是否不返回null,true表示不返回null 返回值:图块id,该点无图块则返回null +getBlockNumber: fn(x: number, y: number, floorId?: string, showDisable?: bool) -> number +判定某个点的图块数字 +x: 横坐标 +y: 纵坐标 +floorId: 地图id,不填视为当前地图 +showDisable: 隐藏点是否不返回null,true表示不返回null +返回值:图块数字,该点无图块则返回null + loadFloor: fn(floorId?: string, map?: ?) 从文件或存档中加载某个楼层 -generateMovableArray: fn(floorId?: string, x?: number, y?: number, direction?: string) +generateMovableArray: fn(floorId?: string) 可通行性判定 例如:core.generateMovableArray(); // 判断当前地图主角从各点能向何方向移动 floorId: 地图id,不填视为当前地图 -x: 起点横坐标,不填视为挨个判定 -y: 起点纵坐标,不填视为挨个判定 -direction: 可选,必须和坐标一起使用。填写后将只检查是否可向该方向移动并返回布尔值 -返回值:不设置坐标时为从各点可移动方向的三维数组,设置坐标但不设置方向时为该点可移动方向的一维数组,都设置时为布尔值 +返回值:从各点可移动方向的三维数组 terrainExists: fn(x: number, y: number, id?: string, floorId?: string) -> bool 某个点是否存在(指定的)地形 @@ -1401,7 +1412,7 @@ x: 横坐标 y: 纵坐标 floorId: 地图id,不填视为当前地图 -getMapBlocksObj: fn(floorId?: string, showDisable?: bool) +getMapBlocksObj: fn(floorId?: string, noCache?: bool) 以x,y的形式返回每个点的事件 removeGlobalAnimate: fn(x?: number, y?: number, name?: string) @@ -1442,10 +1453,10 @@ drawFg: fn(floorId?: string, ctx?: CanvasRenderingContext2D) floorId: 地图id,不填视为当前地图 ctx: 某画布的ctx,用于绘制缩略图,一般不需要 -getBlock: fn(x: number, y: number, floorId?: string, showDisable?: bool) -> {index: number, block: block} +getBlock: fn(x: number, y: number, floorId?: string, showDisable?: bool) -> block: block 获得某个点的block -initBlock: fn(x: number, y: number, id: string|number, addInfo?: bool, eventFloor?: ?, flags?: ?) -> block +initBlock: fn(x: number, y: number, id: string|number, addInfo?: bool, eventFloor?: ?) -> block 初始化一个图块 addGlobalAnimate: fn(block?: block) @@ -1486,13 +1497,12 @@ y: 起点纵坐标,不填视为主角当前的 direction: 移动的方向,不填视为主角面对的方向 floorId: 地图id,不填视为当前地图 -drawThumbnail: fn(floorId?: string, blocks?: [block], options?: ?, toDraw?: string|CanvasRenderingContext2D|?) +drawThumbnail: fn(floorId?: string, blocks?: [block], options?: ?) 绘制缩略图 例如:core.drawThumbnail(); // 绘制当前地图的缩略图 floorId: 地图id,不填视为当前地图 blocks: 一般不需要 options: 额外的绘制项,可选。可以增绘主角位置和朝向、采用不同于游戏中的主角行走图、增绘显伤、提供flags用于存读档 -toDraw: 要绘制到的画布名或画布的ctx或还有其他信息,如起绘坐标、绘制大小、是否绘制全图、截取中心 hideBlockByIndex: fn(index?: number, floorId?: string) 根据图块的索引来隐藏图块 @@ -1846,6 +1856,10 @@ filter: 过滤器,可选,表示data为数组或对象时拷贝哪些项或 recursion: 过滤器是否递归,可选。true表示过滤器也被递归 返回值:拷贝的结果,注意函数将原样返回 +cloneArray: fn(data?: [number]|[[number]]) -> [number]|[[number]] +深拷贝一个1D或2D数组对象 +例如:core.cloneArray(core.status.thisMap.map) + setLocalForage: fn(key: string, value?: ?, successCallback?: fn(), errorCallback?: fn()) 往数据库写入一段数据 diff --git a/_docs/personalization.md b/_docs/personalization.md index c950a2ee..2a552e91 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -260,9 +260,9 @@ this.statusBar = { 6. 显示内容的设置。在脚本编辑的updateStatusBar函数,可以对该状态栏显示内容进行设置,下面是几个例子。 ``` js // 设置其显示内容为status:speed值;需要在project/data.js中firstData的hero那里新增初始值`"speed": 0`。 -core.statusBar.speed.innerHTML = core.getStatus('speed'); +core.setStatusBarInnerHTML('speed', core.getStatus('speed')); // 设置其显示内容为flag:speed值,无需额外进行定义。 -core.statusBar.speed.innerHTML = core.getFlag('speed', 0); +core.setStatusBarInnerHTML('speed', core.getFlag('speed', 0)); ``` 总的来说不建议这样做,因为 `main.js` 和 `html` 文件不在 `project` 文件夹,会导致随样板更新迁移接档变得困难。 @@ -302,7 +302,7 @@ else { } // 设置技能栏 // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名 -core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); +core.setStatusBarInnerHTML('skill', core.getFlag('skillName', '无')); ``` ### 技能的触发 diff --git a/_docs/script.md b/_docs/script.md index 521fcf9c..c448045a 100644 --- a/_docs/script.md +++ b/_docs/script.md @@ -313,9 +313,9 @@ core.events.openShop = function (shopId, needVisited) { ```js var drawMap = core.maps.drawMap; // 先把原始函数用一个变量记录下来 -core.maps.drawMap = function (floorId, callback) { +core.maps.drawMap = function (floorId) { console.log("drawMap..."); // 控制台打出一条信息 - return drawMap.call(core.maps, floorId, callback); // 需要使用`call`来告知this是core.maps + return drawMap.call(core.maps, floorId); // 需要使用`call`来告知this是core.maps } ``` diff --git a/_server/CodeMirror/defs.js b/_server/CodeMirror/defs.js index 95efd9b0..22b340a8 100644 --- a/_server/CodeMirror/defs.js +++ b/_server/CodeMirror/defs.js @@ -1867,6 +1867,30 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "number", "!doc": "大地图视角纵向偏移量" }, + "posX": { + "!type": "number", + "!doc": "大地图视角横向基准格" + }, + "posY": { + "!type": "number", + "!doc": "大地图视角纵向基准格" + }, + "v2": { + "!type": "bool", + "!doc": "是否是新版大地图绘制方式" + }, + "threshold": { + "!type": "number", + "!doc": "新版大地图绘制方式的分界线" + }, + "extend": { + "!type": "number", + "!doc": "新版大地图模式下向每一侧额外计算的数量" + }, + "scale": { + "!type": "number", + "!doc": "缩略图的比例放缩" + }, "tempCanvas": { "!type": "CanvasRenderingContext2D", "!doc": "临时画布" @@ -1908,6 +1932,9 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "fgmaps": { "!doc": "各地图前景层" }, + "mapBlockObjs": { + "!doc": "以<位置,block>存放的各地图图块信息" + }, "boxAnimateObjs": { "!doc": "(手册和剧情文本的)帧动画对象" }, @@ -1933,6 +1960,9 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "每个点的光环缓存" }, }, + "damage": { + "!doc": "每个点的显伤信息", + }, "ctrlDown": { "!type": "bool", "!doc": "Ctrl键是否被按下" @@ -2111,9 +2141,13 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(color?: [number], time?: number, callback?: fn())" }, "updateDamage": { - "!doc": "更新地图显伤
例如:core.updateDamage(); // 更新当前地图的显伤,绘制在显伤层(废话)
floorId: 地图id,不填视为当前地图。预览地图时填写
ctx: 绘制到的画布,如果填写了就会画在该画布而不是显伤层", + "!doc": "重算并绘制地图显伤
例如:core.updateDamage(); // 更新当前地图的显伤,绘制在显伤层(废话)
floorId: 地图id,不填视为当前地图。预览地图时填写
ctx: 绘制到的画布,如果填写了就会画在该画布而不是显伤层", "!type": "fn(floorId?: string, ctx?: string|CanvasRenderingContext2D)" }, + "drawDamage": { + "!doc": "仅绘制地图显伤", + "!type": "fn(string|CanvasRenderingContext2D)" + }, "nextX": { "!doc": "获取主角面前第n格的横坐标
例如:core.closeDoor(core.nextX(), core.nextY(), 'yellowDoor', core.turnHero); // 在主角面前关上一扇黄门,然后主角顺时针旋转90°
n: 目标格与主角的距离,面前为正数,背后为负数,脚下为0,不填视为1", "!type": "fn(n?: number) -> number" @@ -2694,6 +2728,10 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!doc": "深拷贝一个对象(函数将原样返回)
例如:core.clone(core.status.hero, (name, value) => (name == 'items' || typeof value == 'number'), false); // 深拷贝主角的属性和道具
data: 待拷贝对象
filter: 过滤器,可选,表示data为数组或对象时拷贝哪些项或属性,true表示拷贝
recursion: 过滤器是否递归,可选。true表示过滤器也被递归
返回值:拷贝的结果,注意函数将原样返回", "!type": "fn(data?: ?, filter?: fn(name: string, value: ?) -> bool, recursion?: bool)" }, + "cloneArray": { + "!doc": "深拷贝一个1D或2D数组对象
例如:core.cloneArray(core.status.thisMap.map)", + "!type": "fn(data?: [number]|[[number]]) -> [number]|[[number]]" + }, "setLocalForage": { "!doc": "往数据库写入一段数据", "!type": "fn(key: string, value?: ?, successCallback?: fn(), errorCallback?: fn())" @@ -3025,8 +3063,12 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ }, "getMapArray": { "!doc": "生成事件层矩阵
例如:core.getMapArray('MT0'); // 生成主塔0层的事件层矩阵,隐藏的图块视为0
floorId: 地图id,不填视为当前地图
showDisable: 可选,true表示隐藏的图块也会被表示出来
返回值:事件层矩阵,注意对其阵元的访问是[y][x]", - "!type": "fn(floorId?: string) -> [[number]]" + "!type": "fn(floorId?: string, noCache?: bool) -> [[number]]" }, + "getMapNumber": { + "!doc": "获得事件层某个点的数字", + "!type": "fn(x: number, y: number, floorId?: string, noCache?: bool) -> number" + }, "jumpBlock": { "!doc": "跳跃图块;从V2.7开始不再有音效
例如:core.jumpBlock(0, 0, 0, 0); // 令地图左上角的图块原地跳跃半秒,再花半秒淡出
sx: 起点的横坐标
sy: 起点的纵坐标
ex: 终点的横坐标
ey: 终点的纵坐标
time: 单步和淡出用时,单位为毫秒。不填视为半秒
keep: 是否不淡出,true表示不淡出
callback: 落地或淡出后的回调函数,可选", "!type": "fn(sx: number, sy: number, ex: number, ey: number, time?: number, keep?: bool, callback?: fn())" @@ -3141,19 +3183,27 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ }, "extractBlocks": { "!doc": "根据需求解析出blocks", - "!type": "fn(map?: [[number]], flags?: flags)" + "!type": "fn(map?: ?)" + }, + "extractBlocksForUI": { + "!doc": "根据需求为UI解析出blocks", + "!type": "fn(map?: ?, flags?: ?)" }, "getBlockId": { "!doc": "判定某个点的图块id
例如:if(core.getBlockId(x1, y1) != 'greenSlime' && core.getBlockId(x2, y2) != 'redSlime') core.openDoor(x3, y3); // 一个简单的机关门事件,打败或炸掉这一对绿头怪和红头怪就开门
x: 横坐标
y: 纵坐标
floorId: 地图id,不填视为当前地图
showDisable: 隐藏点是否不返回null,true表示不返回null
返回值:图块id,该点无图块则返回null", "!type": "fn(x: number, y: number, floorId?: string, showDisable?: bool) -> string" }, + "getBlockNumber": { + "!doc": "判定某个点的图块数字
x: 横坐标
y: 纵坐标
floorId: 地图id,不填视为当前地图
showDisable: 隐藏点是否不返回null,true表示不返回null
返回值:图块数字,该点无图块则返回null", + "!type": "fn(x: number, y: number, floorId?: string, showDisable?: bool) -> number" + }, "loadFloor": { "!doc": "从文件或存档中加载某个楼层", "!type": "fn(floorId?: string, map?: ?)" }, "generateMovableArray": { - "!doc": "可通行性判定
例如:core.generateMovableArray(); // 判断当前地图主角从各点能向何方向移动
floorId: 地图id,不填视为当前地图
x: 起点横坐标,不填视为挨个判定
y: 起点纵坐标,不填视为挨个判定
direction: 可选,必须和坐标一起使用。填写后将只检查是否可向该方向移动并返回布尔值
返回值:不设置坐标时为从各点可移动方向的三维数组,设置坐标但不设置方向时为该点可移动方向的一维数组,都设置时为布尔值", - "!type": "fn(floorId?: string, x?: number, y?: number, direction?: string)" + "!doc": "可通行性判定
例如:core.generateMovableArray(); // 判断当前地图主角从各点能向何方向移动
floorId: 地图id,不填视为当前地图
返回值:从各点可移动方向的三维数组", + "!type": "fn(floorId?: string) -> [[[string]]]" }, "terrainExists": { "!doc": "某个点是否存在(指定的)地形", @@ -3173,7 +3223,7 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ }, "getMapBlocksObj": { "!doc": "以x,y的形式返回每个点的事件", - "!type": "fn(floorId?: string, showDisable?: bool)" + "!type": "fn(floorId?: string, noCache?: bool)" }, "removeGlobalAnimate": { "!doc": "删除一个或所有全局动画", @@ -3205,11 +3255,11 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ }, "getBlock": { "!doc": "获得某个点的block", - "!type": "fn(x: number, y: number, floorId?: string, showDisable?: bool) -> {index: number, block: block}" + "!type": "fn(x: number, y: number, floorId?: string, showDisable?: bool) -> block" }, "initBlock": { "!doc": "初始化一个图块", - "!type": "fn(x: number, y: number, id: string|number, addInfo?: bool, eventFloor?: ?, flags?: ?) -> block" + "!type": "fn(x: number, y: number, id: string|number, addInfo?: bool, eventFloor?: ?) -> block" }, "addGlobalAnimate": { "!doc": "添加一个全局动画", @@ -3240,8 +3290,8 @@ var terndefs_f6783a0a_522d_417e_8407_94c67b692e50 = [ "!type": "fn(x?: number, y?: number, direction?: string, floorId?: string) -> bool" }, "drawThumbnail": { - "!doc": "绘制缩略图
例如:core.drawThumbnail(); // 绘制当前地图的缩略图
floorId: 地图id,不填视为当前地图
blocks: 一般不需要
options: 额外的绘制项,可选。可以增绘主角位置和朝向、采用不同于游戏中的主角行走图、增绘显伤、提供flags用于存读档
toDraw: 要绘制到的画布名或画布的ctx或还有其他信息,如起绘坐标、绘制大小、是否绘制全图、截取中心", - "!type": "fn(floorId?: string, blocks?: [block], options?: ?, toDraw?: string|CanvasRenderingContext2D|?)" + "!doc": "绘制缩略图
例如:core.drawThumbnail(); // 绘制当前地图的缩略图
floorId: 地图id,不填视为当前地图
blocks: 一般不需要
options: 绘制信息,可选。可以增绘主角位置和朝向、采用不同于游戏中的主角行走图、增绘显伤、提供flags用于存读档,同时包含要绘制到的画布名或画布的ctx或还有其他信息,如起绘坐标、绘制大小、是否绘制全图、截取中心", + "!type": "fn(floorId?: string, blocks?: [block], options?: ?)" }, "hideBlockByIndex": { "!doc": "根据图块的索引来隐藏图块", diff --git a/_server/config.json b/_server/config.json index 0414c1bc..a2a81f0c 100644 --- a/_server/config.json +++ b/_server/config.json @@ -1 +1 @@ -{"lastUsed":[],"foldPerCol":50,"folded":false,"editorLastFloorId":"sample0","disableBlocklyReplace":false,"disableBlocklyExpandCompare":false,"shortcut":{"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0}} \ No newline at end of file +{"lastUsed":[],"foldPerCol":50,"folded":false,"editorLastFloorId":"sample0","disableBlocklyReplace":false,"disableBlocklyExpandCompare":false,"shortcut":{"48":0,"49":0,"50":0,"51":0,"52":0,"53":0,"54":0,"55":0,"56":0,"57":0},"viewportLoc":[0,0]} \ No newline at end of file diff --git a/_server/editor.js b/_server/editor.js index 6adec79d..45b1b554 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -223,13 +223,17 @@ editor.prototype.init = function (callback) { for (var one in canvases) { canvases[one].width = canvases[one].height = core.__PIXELS__; } + core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.cloneArray(core.initStatus.maps)); + var floorId = editor.config.get('editorLastFloorId', core.status.floorId); + if (core.floorIds.indexOf(floorId) < 0) floorId = core.status.floorId; - core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.clone(core.initStatus.maps)); - var lastFloorId = editor.config.get('editorLastFloorId', core.status.floorId); - if (core.floorIds.indexOf(lastFloorId) < 0) lastFloorId = core.status.floorId; - core.changeFloor(lastFloorId, null, {x: 0, y: 0, direction:"up"}, null, function () { - afterCoreReset(); - }, true); + core.status.floorId = floorId; + core.resizeMap(floorId); + core.clearMap('all'); + core.generateGroundPattern(floorId); + core.extractBlocks(floorId); + core.status.thisMap = core.status.maps[floorId]; + afterCoreReset(); }); } @@ -239,11 +243,13 @@ editor.prototype.init = function (callback) { editor.drawInitData(core.icons.icons); // 初始化绘图 editor.game.fetchMapFromCore(); + editor.pos = {x: 0, y: 0}; editor.updateMap(); editor.buildMark(); + var viewportLoc = editor.config.get('viewportLoc', []); + editor.setViewport(viewportLoc[0] || 0, viewportLoc[1] || 0); editor.drawEventBlock(); - - editor.pos = {x: 0, y: 0}; + editor.mode.loc(); editor.info = editor.ids[editor.indexs[201]]; editor.mode.enemyitem(); @@ -335,20 +341,26 @@ editor.prototype.changeFloor = function (floorId, callback) { editor.uivalues.preMapData = []; editor.uivalues.postMapData = []; editor.uifunctions._extraEvent_bindSpecialDoor_doAction(true); - core.changeFloor(floorId, null, {"x": 0, "y": 0, "direction": "up"}, null, function () { - editor.game.fetchMapFromCore(); - editor.updateMap(); - editor_mode.floor(); - editor.drawEventBlock(); - editor.viewportLoc = editor.viewportLoc || {}; - var loc = editor.viewportLoc[floorId] || [], x = loc[0] || 0, y = loc[1] || 0; - editor.setViewport(x, y); - editor.uifunctions.unhighlightSaveFloorButton(); + core.status.floorId = floorId; + core.resizeMap(floorId); + core.clearMap('all'); + core.generateGroundPattern(floorId); + core.extractBlocks(floorId); + core.status.thisMap = core.status.maps[floorId]; - editor.config.set('editorLastFloorId', floorId, function() { - if (callback) callback(); - }); + editor.game.fetchMapFromCore(); + editor.updateMap(); + editor_mode.floor(); + editor.drawEventBlock(); + + editor.viewportLoc = editor.viewportLoc || {}; + var loc = editor.viewportLoc[floorId] || [], x = loc[0] || 0, y = loc[1] || 0; + editor.setViewport(x, y); + editor.uifunctions.unhighlightSaveFloorButton(); + + editor.config.set('editorLastFloorId', floorId, function() { + if (callback) callback(); }); } @@ -445,8 +457,7 @@ editor.prototype._updateMap_bigmap = function () { bm.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__); bm.fillStyle = '#000000'; bm.fillRect(0, 0, core.__PIXELS__, core.__PIXELS__); - core.drawThumbnail(editor.currentFloorId, core.status.thisMap.blocks, null, - {ctx: bm, all: true}); + core.drawThumbnail(editor.currentFloorId, null, {ctx: bm, all: true}); var width = editor.currentFloorData.width; var height = editor.currentFloorData.height; editor.uivalues.bigmapInfo.top = core.__PIXELS__ * Math.max(0, (1 - height / width) / 2); @@ -573,6 +584,7 @@ editor.prototype.setViewport=function (x, y) { editor.viewportLoc = editor.viewportLoc || {}; editor.viewportLoc[editor.currentFloorId] = [core.bigmap.offsetX, core.bigmap.offsetY]; core.control.updateViewport(); + editor.config.set('viewportLoc', editor.viewportLoc[editor.currentFloorId]); editor.buildMark(); editor.drawPosSelection(); } diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 36e122a9..ce76e341 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -631,7 +631,6 @@ editor_blockly = function () { namesObj.allIds = ["this"].concat(core.getAllIconIds()); namesObj.allIconIds = namesObj.allIds.concat(Object.keys(core.statusBar.icons).filter(function (x) { - return core.statusBar.icons[x] instanceof Image; })); namesObj.allImages = Object.keys(core.material.images.images); diff --git a/_server/editor_datapanel.js b/_server/editor_datapanel.js index 3d6a6771..425a6a10 100644 --- a/_server/editor_datapanel.js +++ b/_server/editor_datapanel.js @@ -148,8 +148,8 @@ editor_datapanel_wrapper = function (editor) { } var width = parseInt(document.getElementById('newMapWidth').value); var height = parseInt(document.getElementById('newMapHeight').value); - if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width * height > 1000) { - printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且宽高之积不能超过1000"); + if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width > 128 || height > 128) { + printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且都不得大于128"); return; } @@ -217,8 +217,8 @@ editor_datapanel_wrapper = function (editor) { var width = parseInt(document.getElementById('newMapsWidth').value); var height = parseInt(document.getElementById('newMapsHeight').value); - if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width * height > 1000) { - printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且宽高之积不能超过1000"); + if (!core.isset(width) || !core.isset(height) || width < core.__SIZE__ || height < core.__SIZE__ || width > 128 || height > 128) { + printe("新建地图的宽高都不得小于" + core.__SIZE__ + ",且都不得大于128"); return; } editor_mode.onmode(''); diff --git a/_server/editor_ui.js b/_server/editor_ui.js index 12ae8e41..ad2f6582 100644 --- a/_server/editor_ui.js +++ b/_server/editor_ui.js @@ -375,7 +375,7 @@ editor_ui_wrapper = function (editor) { // 绘制UI var background = uievent.elements.selectBackground.value; if (background == 'thumbnail') { - core.drawThumbnail(editor.currentFloorId, null, {}, 'uievent'); + core.drawThumbnail(editor.currentFloorId, null, {ctx: 'uievent'}); } else { core.fillRect('uievent', 0, 0, core.__PIXELS__, core.__PIXELS__, background); @@ -482,11 +482,10 @@ editor_ui_wrapper = function (editor) { if (redraw) { core.setAlpha('uievent', 1); core.clearMap('uievent'); - core.drawThumbnail(uievent.values.floorId, null, null, - { - ctx: 'uievent', centerX: uievent.values.left + core.__HALF_SIZE__, - centerY: uievent.values.top + core.__HALF_SIZE__, all: uievent.values.bigmap - }); + 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) { @@ -857,7 +856,7 @@ editor_ui_wrapper = function (editor) { var canvas = document.createElement('canvas'); canvas.width = canvas.height = core.__PIXELS__; canvas.style.position = 'absolute'; - core.drawThumbnail(editor.currentFloorId, null, {}, canvas.getContext('2d')); + core.drawThumbnail(editor.currentFloorId, null, {ctx: canvas.getContext('2d')}); dom.appendChild(canvas); var canvas2 = document.createElement('canvas'); canvas2.style.position = 'absolute'; diff --git a/_server/table/plugins.comment.js b/_server/table/plugins.comment.js index e19c11ff..c9e37646 100644 --- a/_server/table/plugins.comment.js +++ b/_server/table/plugins.comment.js @@ -75,12 +75,6 @@ var plugins_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = { "_range": "typeof(thiseval)=='string' || thiseval==null", "_data": "物品分类插件" }, - "smoothCamera": { - "_leaf": true, - "_type": "textarea", - "_range": "typeof(thiseval)=='string' || thiseval==null", - "_data": "平滑移动镜头" - }, } if (obj[key]) return obj[key]; return { diff --git a/libs/actions.js b/libs/actions.js index 3ba55a3e..3b9a4923 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1211,11 +1211,11 @@ actions.prototype._clickViewMaps = function (x, y) { return; } - if (x >= per && x <= this.LAST - per && y <= per - 1 && mh > this.SIZE) { + if (x >= per && x <= this.LAST - per && y <= per - 1 && (!core.status.event.data.all && mh > this.SIZE)) { core.ui.drawMaps(index, cx, cy - 1); return; } - if (x >= per && x <= this.LAST - per && y >= this.SIZE - per && mh > this.SIZE) { + if (x >= per && x <= this.LAST - per && y >= this.SIZE - per && (!core.status.event.data.all && mh > this.SIZE)) { core.ui.drawMaps(index, cx, cy + 1); return; } @@ -2531,7 +2531,7 @@ actions.prototype._clickReplay = function (x, y) { actions.prototype._clickReplay_fromBeginning = function () { core.ui.closePanel(); - core.startGame(core.status.hard, core.getFlag('__seed__'), core.clone(core.status.route)); + core.startGame(core.status.hard, core.getFlag('__seed__'), core.cloneArray(core.status.route)); } actions.prototype._clickReplay_fromLoad = function () { diff --git a/libs/control.js b/libs/control.js index 202c2357..c2507578 100644 --- a/libs/control.js +++ b/libs/control.js @@ -143,7 +143,7 @@ control.prototype._animationFrame_globalAnimate = function (timestamp) { core.maps._drawFloorImages(core.status.floorId, core.canvas.fg, 'fg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); // Global Autotile Animate - core.status.autotileAnimateObjs.blocks.forEach(function (block) { + core.status.autotileAnimateObjs.forEach(function (block) { core.maps._drawAutotileAnimate(block, core.status.globalAnimateStatus); }); @@ -770,7 +770,7 @@ control.prototype.tryMoveDirectly = function (destX, destY) { if (this.nearHero(destX, destY)) return false; var canMoveArray = core.maps.generateMovableArray(); var dirs = [[destX,destY],[destX-1,destY,"right"],[destX,destY-1,"down"],[destX,destY+1,"up"],[destX+1,destY,"left"]]; - var canMoveDirectlyArray = core.canMoveDirectlyArray(dirs); + var canMoveDirectlyArray = core.canMoveDirectlyArray(dirs, canMoveArray); for (var i = 0; i < dirs.length; ++i) { var d = dirs[i], dx = d[0], dy = d[1], dir = d[2]; @@ -915,8 +915,13 @@ control.prototype.addGameCanvasTranslate = function (x, y) { if (id=='ui' || id=='data') continue; // UI层和data层不移动 var offsetX = x, offsetY = y; if (core.bigmap.canvas.indexOf(id)>=0) { - offsetX -= core.bigmap.offsetX; - offsetY -= core.bigmap.offsetY; + if (core.bigmap.v2) { + offsetX -= (core.bigmap.offsetX - 32 * core.bigmap.posX) + 32; + offsetY -= (core.bigmap.offsetY - 32 * core.bigmap.posY) + 32; + } else { + offsetX -= core.bigmap.offsetX; + offsetY -= core.bigmap.offsetY; + } } core.control.setGameCanvasTranslate(id, offsetX, offsetY); } @@ -924,8 +929,24 @@ control.prototype.addGameCanvasTranslate = function (x, y) { ////// 更新视野范围 ////// control.prototype.updateViewport = function() { + // 当前是否应该重绘? + if (core.bigmap.v2) { + if (core.bigmap.offsetX >= core.bigmap.posX * 32 + 32 + || core.bigmap.offsetX <= core.bigmap.posX * 32 - 32 + || core.bigmap.offsetY >= core.bigmap.posY * 32 + 32 + || core.bigmap.offsetY <= core.bigmap.posY * 32 - 32) { + core.bigmap.posX = parseInt(core.bigmap.offsetX / 32); + core.bigmap.posY = parseInt(core.bigmap.offsetY / 32); + core.redrawMap(); + } + } else { + core.bigmap.posX = core.bigmap.posY = 0; + } + var offsetX = core.bigmap.v2 ? -(core.bigmap.offsetX - 32 * core.bigmap.posX) - 32 : -core.bigmap.offsetX; + var offsetY = core.bigmap.v2 ? -(core.bigmap.offsetY - 32 * core.bigmap.posY) - 32 : -core.bigmap.offsetY; + core.bigmap.canvas.forEach(function(cn){ - core.control.setGameCanvasTranslate(cn,-core.bigmap.offsetX,-core.bigmap.offsetY); + core.control.setGameCanvasTranslate(cn, offsetX, offsetY); }); // ------ 路线 core.relocateCanvas('route', core.status.automaticRoute.offsetX - core.bigmap.offsetX, core.status.automaticRoute.offsetY - core.bigmap.offsetY); @@ -1095,65 +1116,136 @@ control.prototype._checkBlock_ambush = function (ambush) { ////// 更新全地图显伤 ////// control.prototype.updateDamage = function (floorId, ctx) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId) || core.status.gameOver) return; - if (core.status.gameOver) return; - var refreshCheckBlock = true; - if (!core.isset(ctx)) { - ctx = core.canvas.damage; - core.clearMap('damage'); - refreshCheckBlock = false; - } + if (!floorId || core.status.gameOver) return; + var onMap = ctx == null; // 没有怪物手册 if (!core.hasItem('book')) return; - core.setFont(ctx, "bold 11px Arial"); - this._updateDamage_damage(floorId, ctx); - this._updateDamage_extraDamage(floorId, ctx, refreshCheckBlock); + core.status.damage.posX = core.bigmap.posX; + core.status.damage.posY = core.bigmap.posY; + if (!onMap) { + var width = core.floors[floorId].width, height = core.floors[floorId].height; + // 地图过大的缩略图不绘制显伤 + if (width * height > (core.__SIZE__ + 2 * core.bigmap.extend) * (core.__SIZE__ + 2 * core.bigmap.extend)) return; + } + this._updateDamage_damage(floorId, onMap); + this._updateDamage_extraDamage(floorId, onMap); + this.drawDamage(ctx); } -control.prototype._updateDamage_damage = function (floorId, ctx) { - core.setTextAlign(ctx, 'left'); +control.prototype._updateDamage_damage = function (floorId, onMap) { + core.status.damage.data = []; + if (!core.flags.displayEnemyDamage && !core.flags.displayExtraDamage) return; + core.extractBlocks(floorId); core.status.maps[floorId].blocks.forEach(function (block) { var x = block.x, y = block.y; + + // v2优化,只绘制范围内的部分 + if (onMap && core.bigmap.v2) { + if (x < core.bigmap.posX - core.bigmap.extend || x > core.bigmap.posX + core.__SIZE__ + core.bigmap.extend + || y < core.bigmap.posY - core.bigmap.extend || y > core.bigmap.posY + core.__SIZE__ + core.bigmap.extend) { + return; + } + } + if (!block.disable && block.event.cls.indexOf('enemy') == 0 && block.event.displayDamage !== false) { - if (core.flags.displayEnemyDamage) { + if (core.flags.displayEnemyDamage) { var damageString = core.enemys.getDamageString(block.event.id, x, y, floorId); - var damage = damageString.damage, color = damageString.color; - core.fillBoldText(ctx, damage, 32*x+1, 32*(y+1)-1, color); - } - if (core.flags.displayCritical) { + core.status.damage.data.push({text: damageString.damage, px: 32*x+1, py: 32*(y+1)-1, color: damageString.color}); + } + if (core.flags.displayCritical) { var critical = core.enemys.nextCriticals(block.event.id, 1, x, y, floorId); critical = core.formatBigNumber((critical[0]||[])[0], true); if (critical == '???') critical = '?'; - core.fillBoldText(ctx, critical, 32*x+1, 32*(y+1)-11, '#FFFFFF'); - } + core.status.damage.data.push({text: critical, px: 32*x+1, py: 32*(y+1)-11, color: '#FFFFFF'}); + } } }); } -control.prototype._updateDamage_extraDamage = function (floorId, ctx, refresh) { - core.setTextAlign(ctx, 'center'); - if (refresh) this.updateCheckBlock(floorId); - if (core.flags.displayExtraDamage) { - var width = core.floors[floorId].width, height = core.floors[floorId].height; - for (var x=0;x0) { // 该点伤害 - damage = core.formatBigNumber(damage, true); - core.fillBoldText(ctx, damage, 32*x+16, 32*(y+1)-14, '#ffaa33'); - } - else { // 检查捕捉 - if (core.status.checkBlock.ambush[x+","+y]) { - core.fillBoldText(ctx, '!', 32*x+16, 32*(y+1)-14, '#ffaa33'); - } +control.prototype._updateDamage_extraDamage = function (floorId, onMap) { + core.status.damage.extraData = []; + if (!core.flags.displayExtraDamage) return; + + var width = core.floors[floorId].width, height = core.floors[floorId].height; + var startX = onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posX - core.bigmap.extend) : 0; + var endX = onMap && core.bigmap.v2 ? Math.min(width, core.bigmap.posX + core.__SIZE__ + core.bigmap.extend + 1) : width; + var startY = onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posY - core.bigmap.extend) : 0; + var endY = onMap && core.bigmap.v2 ? Math.min(height, core.bigmap.posY + core.__SIZE__ + core.bigmap.extend + 1) : height; + + for (var x=startX;x0) { // 该点伤害 + damage = core.formatBigNumber(damage, true); + core.status.damage.extraData.push({text: damage, px: 32*x+16, py: 32*(y+1)-14, color: '#ffaa33'}); + } + else { // 检查捕捉 + if (core.status.checkBlock.ambush[x+","+y]) { + core.status.damage.extraData.push({text: '!', px: 32*x+16, py: 32*(y+1)-14, color: '#ffaa33'}); } } } } } +////// 重绘地图显伤 ////// +control.prototype.drawDamage = function (ctx) { + if (core.status.gameOver || !core.status.damage) return; + var onMap = false; + if (ctx == null) { + ctx = core.canvas.damage; + core.clearMap('damage'); + onMap = true; + } + + if (onMap && core.bigmap.v2) { + // 检查是否需要重算... + if (Math.abs(core.bigmap.posX - core.status.damage.posX) >= core.bigmap.extend - 1 + || Math.abs(core.bigmap.posY - core.status.damage.posY) >= core.bigmap.extend - 1) { + return this.updateDamage(); + } + } + return this._drawDamage_draw(ctx, onMap); +} + +control.prototype._drawDamage_draw = function (ctx, onMap) { + if (!core.hasItem('book')) return; + // 双缓冲 + var cacheCtx = core.bigmap.cacheCanvas; + cacheCtx.canvas.width = ctx.canvas.width; + cacheCtx.canvas.height = ctx.canvas.height; + cacheCtx.clearRect(0, 0, cacheCtx.canvas.width, cacheCtx.canvas.height); + + core.setFont(cacheCtx, "bold 11px Arial"); + core.setTextAlign(cacheCtx, 'left'); + core.status.damage.data.forEach(function (one) { + var px = one.px, py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if (px < -32 * 2 || px > core.__PIXELS__ + 32 || py < -32 || py > core.__PIXELS__ + 32) + return; + } + core.fillBoldText(cacheCtx, one.text, px, py, one.color); + }); + + core.setTextAlign(cacheCtx, 'center'); + core.status.damage.extraData.forEach(function (one) { + var px = one.px, py = one.py; + if (onMap && core.bigmap.v2) { + px -= core.bigmap.posX * 32; + py -= core.bigmap.posY * 32; + if (px < -32 || px > core.__PIXELS__ + 32 || py < -32 || py > core.__PIXELS__ + 32) + return; + } + core.fillBoldText(cacheCtx, one.text, px, py, one.color); + }); + + core.drawImage(ctx, cacheCtx.canvas, 0, 0); +} + // ------ 录像相关 ------ // ////// 选择录像文件 ////// @@ -1178,7 +1270,7 @@ control.prototype.startReplay = function (list) { core.status.replay.replaying=true; core.status.replay.pausing=true; core.status.replay.speed=1.0; - core.status.replay.toReplay = core.clone(list); + core.status.replay.toReplay = core.cloneArray(list); core.status.replay.totalList = core.status.route.concat(list); core.status.replay.steps = 0; core.status.replay.save = []; @@ -1433,8 +1525,8 @@ control.prototype._replay_save = function () { if (core.status.replay.save.length == 30) core.status.replay.save.shift(); core.status.replay.save.push({"data": core.saveData(), "replay": { - "totalList": core.clone(core.status.replay.totalList), - "toReplay": core.clone(core.status.replay.toReplay), + "totalList": core.cloneArray(core.status.replay.totalList), + "toReplay": core.cloneArray(core.status.replay.toReplay), "speed": core.status.replay.speed, "steps": core.status.replay.steps }}); @@ -2541,8 +2633,12 @@ control.prototype.checkBgm = function() { ////// 清空状态栏 ////// control.prototype.clearStatusBar = function() { Object.keys(core.statusBar).forEach(function (e) { - if (core.statusBar[e].innerHTML != null) + if (core.statusBar[e].innerHTML != null) { core.statusBar[e].innerHTML = " "; + core.statusBar[e].removeAttribute('_isNumber'); + core.statusBar[e].removeAttribute('_style'); + core.statusBar[e].removeAttribute('_value'); + } }) core.statusBar.image.book.style.opacity = 0.3; if (!core.flags.equipboxButton) @@ -2856,9 +2952,9 @@ control.prototype._resize_canvas = function (obj) { core.dom.gameDraw.style.right = 0; core.dom.gameDraw.style.border = obj.border; // resize bigmap - core.bigmap.canvas.forEach(function(cn){ - core.canvas[cn].canvas.style.width = core.bigmap.width * 32 * core.domStyle.scale + "px"; - core.canvas[cn].canvas.style.height = core.bigmap.height * 32 * core.domStyle.scale + "px"; + core.bigmap.canvas.forEach(function (cn) { + core.canvas[cn].canvas.style.width = core.canvas[cn].canvas.width * core.domStyle.scale + "px"; + core.canvas[cn].canvas.style.height = core.canvas[cn].canvas.height * core.domStyle.scale + "px"; }); // resize dynamic canvas for (var name in core.dymCanvas) { diff --git a/libs/core.js b/libs/core.js index bba8f4fc..77baf55e 100644 --- a/libs/core.js +++ b/libs/core.js @@ -93,9 +93,16 @@ function core() { canvas: ["bg", "event", "event2", "fg", "damage"], offsetX: 0, // in pixel offsetY: 0, + posX: 0, // + posY: 0, width: this.__SIZE__, // map width and height height: this.__SIZE__, + v2: false, + threshold: 512, + extend: 10, + scale: 1.0, tempCanvas: null, // A temp canvas for drawing + cacheCanvas: null, // A cache canvas } this.saves = { "saveIndex": null, @@ -125,7 +132,14 @@ function core() { 'maps': null, 'bgmaps': {}, 'fgmaps': {}, - 'checkBlock': {}, // 显伤伤害 + 'mapBlockObjs': {}, + 'checkBlock': {}, // 每个点的阻激夹域信息 + 'damage': { // 每个点的显伤绘制 + 'posX': 0, + 'posY': 0, + 'data': [], + 'extraData': [], + }, 'lockControl': false, @@ -208,7 +222,7 @@ function core() { 'globalAnimateObjs': [], 'floorAnimateObjs': [], 'boxAnimateObjs': [], - 'autotileAnimateObjs': {"blocks": [], "map": null, "bgmap": null, "fgmap": null}, + 'autotileAnimateObjs': [], "globalAnimateStatus": 0, 'animateObjs': [], }; @@ -392,6 +406,7 @@ core.prototype._init_others = function () { core.material.groundCanvas.canvas.width = core.material.groundCanvas.canvas.height = 32; core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat'); core.bigmap.tempCanvas = document.createElement('canvas').getContext('2d'); + core.bigmap.cacheCanvas = document.createElement('canvas').getContext('2d'); core.loadImage("materials", 'fog', function (name, img) { core.animateFrame.weather.fog = img; }); core.loadImage("materials", "cloud", function (name, img) { core.animateFrame.weather.cloud = img; }) core.loadImage("materials", 'keyboard', function (name, img) {core.material.images.keyboard = img; }); diff --git a/libs/enemys.js b/libs/enemys.js index 978a89e7..bbd05e97 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -336,12 +336,11 @@ enemys.prototype.getCurrentEnemys = function (floorId) { floorId = floorId || core.status.floorId; var enemys = [], used = {}; core.extractBlocks(floorId); - var mapBlocks = core.status.maps[floorId].blocks; - for (var b = 0; b < mapBlocks.length; b++) { - if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') == 0) { - this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId); + core.status.maps[floorId].blocks.forEach(function (block) { + if (!block.disable && block.event.cls.indexOf('enemy') == 0) { + this._getCurrentEnemys_addEnemy(block.event.id, enemys, used, floorId); } - } + }, this); return this._getCurrentEnemys_sort(enemys); } diff --git a/libs/events.js b/libs/events.js index 92572803..b7e0a2c8 100644 --- a/libs/events.js +++ b/libs/events.js @@ -43,7 +43,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { events.prototype._startGame_start = function (hard, seed, route, callback) { console.log('开始游戏'); - core.resetGame(core.firstData.hero, hard, null, core.clone(core.initStatus.maps)); + core.resetGame(core.firstData.hero, hard, null, core.cloneArray(core.initStatus.maps)); core.setHeroLoc('x', -1); core.setHeroLoc('y', -1); @@ -335,7 +335,6 @@ events.prototype.trigger = function (x, y, callback) { var block = core.getBlock(x, y); if (block == null) return _executeCallback(); - block = block.block; // 执行该点的脚本 if (block.event.script) { @@ -363,7 +362,6 @@ events.prototype._trigger_inAction = function (x, y) { var block = core.getBlock(x, y); if (block == null) return core.doAction(); - block = block.block; // 执行该点的脚本 try { @@ -612,7 +610,7 @@ events.prototype._canGetNextItem = function (direction) { var nx = core.getHeroLoc('x') + core.utils.scan[direction].x; var ny = core.getHeroLoc('y') + core.utils.scan[direction].y; var block = core.getBlock(nx, ny); - return block != null && block.block.event.trigger == 'getItem'; + return block != null && block.event.trigger == 'getItem'; } events.prototype._getNextItem = function (direction, noRoute) { diff --git a/libs/maps.js b/libs/maps.js index 52ca529c..86bccf70 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -43,8 +43,7 @@ maps.prototype.loadFloor = function (floorId, map) { map = {"map": map}; } var content = {}; - var notCopy = ["firstArrive", "eachArrive", "parallelDo", "map", "bgmap", "fgmap", - "events", "changeFloor", "afterBattle", "afterGetItem", "afterOpenDoor", "cannotMove"]; + var notCopy = this._loadFloor_doNotCopy(); for (var name in floor) { if (notCopy.indexOf(name) == -1 && floor[name] != null) content[name] = core.clone(floor[name]); @@ -60,8 +59,15 @@ maps.prototype.loadFloor = function (floorId, map) { return content; } +maps.prototype._loadFloor_doNotCopy = function () { + return [ + "firstArrive", "eachArrive", "blocks", "parallelDo", "map", "bgmap", "fgmap", + "events", "changeFloor", "afterBattle", "afterGetItem", "afterOpenDoor", "cannotMove" + ]; +} + /// 根据需求解析出blocks -maps.prototype.extractBlocks = function (map, flags) { +maps.prototype.extractBlocks = function (map) { map = map || core.status.floorId; if (typeof map == 'string') map = (core.status.maps||{})[map]; if (!map) return; @@ -71,16 +77,16 @@ maps.prototype.extractBlocks = function (map, flags) { return; } var floorId = map.floorId; - map.blocks = this._mapIntoBlocks(this.decompressMap(map.map, floorId), core.floors[floorId], floorId, flags); + map.blocks = this._mapIntoBlocks(this.decompressMap(map.map, floorId), core.floors[floorId], floorId); } -maps.prototype._mapIntoBlocks = function (map, floor, floorId, flags) { +maps.prototype._mapIntoBlocks = function (map, floor, floorId) { var blocks = []; var mw = core.floors[floorId].width; var mh = core.floors[floorId].height; for (var i = 0; i < mh; i++) { for (var j = 0; j < mw; j++) { - var block = this.initBlock(j, i, (map[i] || [])[j], true, floor, flags); + var block = this.initBlock(j, i, (map[i] || [])[j], true, floor); if (block.id != 0 || block.event.trigger) blocks.push(block); } @@ -88,6 +94,23 @@ maps.prototype._mapIntoBlocks = function (map, floor, floorId, flags) { return blocks; } +maps.prototype.extractBlocksForUI = function (map, flags) { + if (!map || map.blocks) return; + if (map.deleted) return map.blocks = []; + var floorId = map.floorId; + var decompressed = this.decompressMap(map.map, floorId); + map.blocks = []; + var mw = core.floors[floorId].width; + var mh = core.floors[floorId].height; + for (var i = 0; i < mh; i++) { + for (var j = 0; j < mw; j++) { + var number = (decompressed[i] || [])[j] || 0; + if (!number || number == 17 || this.isMapBlockDisabled(floorId, j, i, flags)) continue; + map.blocks.push(this.initBlock(j, i, number)); + } + } +} + ////// 从ID获得数字 ////// maps.prototype.getNumberById = function (id) { id = this.getIdOfThis(id); @@ -129,11 +152,10 @@ maps.prototype.getIdOfThis = function (id) { } ////// 数字和ID的对应关系 ////// -maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor, flags) { +maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { var disable = null; if (eventFloor != null) { - if (flags == null) flags = (core.status.hero || {}).flags || {}; - disable = this.isMapBlockDisabled(eventFloor.floorId, x, y, flags); + disable = this.isMapBlockDisabled(eventFloor.floorId, x, y); } var block = {'x': x, 'y': y, 'id': id}; if (disable != null) block.disable = disable; @@ -247,14 +269,9 @@ maps.prototype.compressMap = function (mapArr, floorId) { maps.prototype._processInvalidMap = function (mapArr, width, height) { if (mapArr.length == height && mapArr[0].length == width) return mapArr; - - var allZeros = []; - for (var i = 0; i < width; ++i) { - allZeros.push(0); - } var map = []; for (var i = 0; i < height; ++i) { - map.push(core.clone(allZeros)); + map.push(Array(width).fill(0)); } for (var j = 0; j < height; ++j) { for (var i = 0; i < width; ++i) { @@ -302,14 +319,14 @@ maps.prototype.decompressMap = function (mapArr, floorId) { var mh = core.floors[floorId].height; var floorMap = this._processInvalidMap(core.floors[floorId].map, mw, mh); - if (!mapArr) return core.clone(floorMap); + if (!mapArr) return core.cloneArray(floorMap); for (var x = 0; x < mh; x++) { if (x >= mapArr.length) { mapArr.push(0); } if (mapArr[x] === 0) { - mapArr[x] = core.clone(floorMap[x]); + mapArr[x] = core.cloneArray(floorMap[x]); } else { for (var y = 0; y < mw; y++) { @@ -342,7 +359,7 @@ maps.prototype.saveMap = function (floorId) { var map = maps[floorId]; var thisFloor = this._compressFloorData(map, core.floors[floorId]); if (map.blocks) { - var mapArr = this.compressMap(this._getMapArrayFromBlocks(map.blocks, map.width, map.height), floorId); + var mapArr = this.compressMap(this._getMapArrayFromBlocks(map.blocks, map.width, map.height, true), floorId); if (mapArr != null) thisFloor.map = mapArr; } return thisFloor; @@ -350,8 +367,9 @@ maps.prototype.saveMap = function (floorId) { maps.prototype._compressFloorData = function (map, floor) { var thisFloor = {}; + var notCopy = this._loadFloor_doNotCopy(); for (var name in map) { - if (name != 'blocks') { + if (notCopy.indexOf(name) == -1) { var floorData = floor[name]; if (!core.utils.same(map[name], floorData)) { thisFloor[name] = core.clone(map[name]); @@ -379,50 +397,71 @@ maps.prototype.resizeMap = function (floorId) { if (!floorId) return; core.bigmap.width = core.floors[floorId].width; core.bigmap.height = core.floors[floorId].height; - var cwidth = core.bigmap.width * 32; - var cheight = core.bigmap.height * 32; + core.bigmap.posX = core.bigmap.posY = 0; + + core.bigmap.v2 = core.bigmap.width * core.bigmap.height > core.bigmap.threshold; + var width = core.bigmap.v2 ? core.__PIXELS__ + 64 : core.bigmap.width * 32; + var height = core.bigmap.v2 ? core.__PIXELS__ + 64 : core.bigmap.width * 32; + core.bigmap.canvas.forEach(function (cn) { - core.canvas[cn].canvas.setAttribute("width", cwidth); - core.canvas[cn].canvas.setAttribute("height", cheight); - core.canvas[cn].canvas.style.width = cwidth * core.domStyle.scale + "px"; - core.canvas[cn].canvas.style.height = cheight * core.domStyle.scale + "px"; + core.canvas[cn].canvas.setAttribute("width", width); + core.canvas[cn].canvas.setAttribute("height", height); + core.canvas[cn].canvas.style.width = width * core.domStyle.scale + "px"; + core.canvas[cn].canvas.style.height = height * core.domStyle.scale + "px"; + core.canvas[cn].translate(core.bigmap.v2 ? 32 : 0, core.bigmap.v2 ? 32 : 0); if (main.mode === 'editor' && editor.isMobile) { - core.canvas[cn].canvas.style.width = core.bigmap.width * 32 / core.__PIXELS__ * 96 + "vw"; - core.canvas[cn].canvas.style.height = core.bigmap.height * 32 / core.__PIXELS__ * 96 + "vw"; + core.canvas[cn].canvas.style.width = width / core.__PIXELS__ * 96 + "vw"; + core.canvas[cn].canvas.style.height = height / core.__PIXELS__ * 96 + "vw"; } }); } ////// 将当前地图重新变成二维数组形式 ////// -maps.prototype.getMapArray = function (floorId) { +maps.prototype.getMapArray = function (floorId, noCache) { floorId = floorId || core.status.floorId; var map = core.status.maps[floorId]; - if (!map.blocks) return map.map; - return this._getMapArrayFromBlocks(map.blocks, map.width, map.height); + if (!map.blocks || !noCache) return map.map; + return map.map = this._getMapArrayFromBlocks(map.blocks, map.width, map.height); } -maps.prototype._getMapArrayFromBlocks = function (blockArray, width, height) { +////// 获得地图上某点的数字 +maps.prototype.getMapNumber = function (x, y, floorId, noCache) { + return this.getMapArray(floorId, noCache)[y][x]; +} + +maps.prototype._updateMapArray = function (floorId, x, y) { + floorId = floorId || core.status.floorId; + var map = core.status.maps[floorId]; + if (!map.blocks) return; + if (x == null || y == null) return this.getMapArray(floorId, true); + var block = this.getBlock(x, y, floorId, true); + if (block == null || block.disable) map.map[y][x] = 0; + else map.map[y][x] = block.id; +} + +maps.prototype._getMapArrayFromBlocks = function (blockArray, width, height, showDisable) { var blocks = []; - var allzero = []; - for (var y = 0; y < width; y++) allzero.push(0); - for (var x = 0; x < height; x++) blocks.push(core.clone(allzero)); + for (var x = 0; x < height; x++) blocks.push(Array(width).fill(0)); blockArray.forEach(function (block) { - blocks[block.y][block.x] = block.id; + if (showDisable || !block.disable) + blocks[block.y][block.x] = block.id; }); return blocks; } ////// 以x,y的形式返回每个点的事件 ////// -maps.prototype.getMapBlocksObj = function (floorId, showDisable) { +maps.prototype.getMapBlocksObj = function (floorId, noCache) { floorId = floorId || core.status.floorId; + if (core.status.mapBlockObjs[floorId] && !noCache) + return core.status.mapBlockObjs[floorId]; + var obj = {}; core.extractBlocks(floorId); core.status.maps[floorId].blocks.forEach(function (block) { - if (!block.disable || showDisable) - obj[block.x + "," + block.y] = block; + obj[block.x + "," + block.y] = block; }); - return obj; + return core.status.mapBlockObjs[floorId] = obj; } ////// 将背景前景层变成二维数组的形式 ////// @@ -435,90 +474,104 @@ maps.prototype._getBgFgMapArray = function (name, floorId, noCache) { if (!noCache && core.status[name + "maps"][floorId]) return core.status[name + "maps"][floorId]; - var arr = core.clone(core.floors[floorId][name + "map"] || []); - if (main.mode == 'editor' && !(window.editor && editor.uievent && editor.uievent.isOpen)) - arr = core.clone(editor[name + "map"]) || arr; - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - arr[y] = arr[y] || []; - var flag = [floorId, x, y, name+'_disable'].join('@'); - var vFlag = [floorId, x, y, name+'_value'].join('@'); - if (core.hasFlag(flag)) arr[y][x] = 0; - else arr[y][x] = core.getFlag(vFlag, arr[y][x] || 0); - if (main.mode == 'editor') arr[y][x] = arr[y][x].idnum || arr[y][x] || 0; + var arr = (main.mode == 'editor' && !(window.editor && editor.uievent && editor.uievent.isOpen)) + ? core.cloneArray(editor[name + 'map']) : null; + if (arr == null) + arr = core.cloneArray(core.floors[floorId][name + "map"] || []); + + for (var y = 0; y < height; ++y) { + if (arr[y] == null) arr[y] = Array(width).fill(0); + } + (core.getFlag('__'+name+'v__', {})[floorId] || []).forEach(function (one) { + arr[one[1]][one[0]] = one[2] || 0; + }); + (core.getFlag('__'+name+'d__', {})[floorId] || []).forEach(function (one) { + arr[one[1]][one[0]] = 0; + }); + if (main.mode == 'editor') { + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + arr[y][x] = arr[y][x].idnum || arr[y][x] || 0; + } } } if (core.status[name + "maps"]) - core.status[name + "maps"][floorId] = core.clone(arr); + core.status[name + "maps"][floorId] = arr; return arr; } -maps.prototype.getBgMapArray = function (floorId, noCache) { - return this._getBgFgMapArray('bg', floorId, noCache); +maps.prototype.getBgMapArray = function (floorId) { + return this._getBgFgMapArray('bg', floorId); } -maps.prototype.getFgMapArray = function (floorId, noCache) { - return this._getBgFgMapArray('fg', floorId, noCache); +maps.prototype.getFgMapArray = function (floorId) { + return this._getBgFgMapArray('fg', floorId); } -maps.prototype._getBgFgNumber = function (name, x, y, floorId, noCache) { +maps.prototype._getBgFgNumber = function (name, x, y, floorId) { if (x == null) x = core.getHeroLoc('x'); if (y == null) y = core.getHeroLoc('y'); - return this._getBgFgMapArray(name, floorId, noCache)[y][x]; + return this._getBgFgMapArray(name, floorId)[y][x]; } -maps.prototype.getBgNumber = function (x, y, floorId, noCache) { - return this._getBgFgNumber('bg', x, y, floorId, noCache); +maps.prototype.getBgNumber = function (x, y, floorId) { + return this._getBgFgNumber('bg', x, y, floorId); } -maps.prototype.getFgNumber = function (x, y, floorId, noCache) { - return this._getBgFgNumber('fg', x, y, floorId, noCache); +maps.prototype.getFgNumber = function (x, y, floorId) { + return this._getBgFgNumber('fg', x, y, floorId); } // ------ 当前能否朝某方向移动,能否瞬间移动 ------ // ////// 生成全图的当前可移动信息 ////// -maps.prototype.generateMovableArray = function (floorId, x, y, direction) { +maps.prototype.generateMovableArray = function (floorId) { floorId = floorId || core.status.floorId; if (!floorId) return null; + var arrays = this._generateMovableArray_arrays(floorId); + var width = core.floors[floorId].width, height = core.floors[floorId].height; - var bgArray = this.getBgMapArray(floorId), - fgArray = this.getFgMapArray(floorId), - eventArray = this.getMapArray(floorId); - - var generate = function (x, y, direction) { - if (direction != null) { - return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, { - bgArray: bgArray, fgArray: fgArray, eventArray: eventArray - }); - } - return ["left", "down", "up", "right"].filter(function (direction) { - return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, { - bgArray: bgArray, fgArray: fgArray, eventArray: eventArray - }); - }); - } - - if (x != null && y != null) return generate(x, y, direction); var array = []; - for (var x = 0; x < width; x++) { - array[x] = []; - for (var y = 0; y < height; y++) { - array[x][y] = generate(x, y); + for (var x = 0; x < width; ++x) { + array[x] = Array(height).fill([]); + } + var v2 = floorId == core.status.floorId && core.bigmap.v2; + var startX = v2 ? Math.max(0, core.bigmap.posX - core.bigmap.extend) : 0; + var endX = v2 ? Math.min(width, core.bigmap.posX + core.__SIZE__ + core.bigmap.extend + 1) : width; + var startY = v2 ? Math.max(0, core.bigmap.posY - core.bigmap.extend) : 0; + var endY = v2 ? Math.min(height, core.bigmap.posY + core.__SIZE__ + core.bigmap.extend + 1) : height; + + for (var x = startX; x < endX; x++) { + for (var y = startY; y < endY; y++) { + array[x][y] = ["left", "down", "up", "right"].filter(function (direction) { + return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, arrays); + }); } } return array; } +maps.prototype._generateMovableArray_arrays = function (floorId) { + return { + bgArray: this.getBgMapArray(floorId), + fgArray: this.getFgMapArray(floorId), + eventArray: this.getMapArray(floorId) + }; +} + ////// 勇士能否前往某方向 ////// maps.prototype.canMoveHero = function (x, y, direction, floorId) { if (x == null) x = core.getHeroLoc('x'); if (y == null) y = core.getHeroLoc('y'); direction = direction || core.getHeroLoc('direction'); - return this.generateMovableArray(floorId, x, y, direction); + return this._canMoveHero_checkPoint(x, y, direction, floorId); } -maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, extraData) { +maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, arrays) { + floorId = floorId || core.status.floorId; + if (!floorId) return false; + arrays = arrays || this._generateMovableArray_arrays(floorId); + // 1. 检查该点 cannotMove if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction)) return false; @@ -528,19 +581,15 @@ maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, ext return false; // 2. 检查该点素材的 cannotOut 和下一个点的 cannotIn - if (this._canMoveHero_checkCannotInOut([ - extraData.bgArray[y][x], extraData.fgArray[y][x], extraData.eventArray[y][x] - ], "cannotOut", direction)) + if (this._canMoveHero_checkCannotInOut(Object.keys(arrays).map(function (name) { return arrays[name][y][x]; }), "cannotOut", direction)) return false; - if (this._canMoveHero_checkCannotInOut([ - extraData.bgArray[ny][nx], extraData.fgArray[ny][nx], extraData.eventArray[ny][nx] - ], "cannotIn", direction)) + if (this._canMoveHero_checkCannotInOut(Object.keys(arrays).map(function (name) { return arrays[name][ny][nx]; }), "cannotIn", direction)) return false; // 3. 检查是否能进将死的领域 if (floorId == core.status.floorId && !core.flags.canGoDeadZone && core.status.hero.hp <= (core.status.checkBlock.damage[nx + "," + ny]||0) - && extraData.eventArray[ny][nx] == 0) + && arrays.eventArray[ny][nx] == 0) return false; return true; @@ -563,7 +612,7 @@ maps.prototype.canMoveDirectly = function (destX, destY) { return this.canMoveDirectlyArray([[destX,destY]])[0]; } -maps.prototype.canMoveDirectlyArray = function (locs) { +maps.prototype.canMoveDirectlyArray = function (locs, canMoveArray) { var ans = [], number = locs.length; var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y'); @@ -592,7 +641,7 @@ maps.prototype.canMoveDirectlyArray = function (locs) { return ans; } - return this._canMoveDirectly_bfs(fromX, fromY, locs, number, ans); + return this._canMoveDirectly_bfs(fromX, fromY, locs, number, ans, canMoveArray); } maps.prototype._canMoveDirectly_checkGlobal = function () { @@ -611,14 +660,14 @@ maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) { var block = core.getBlock(sx, sy); if (block != null) { // 只有起点是传送点才是能无视 - return block.block.event.trigger == 'changeFloor'; + return block.event.trigger == 'changeFloor'; } return true; } -maps.prototype._canMoveDirectly_bfs = function (sx, sy, locs, number, ans) { - var canMoveArray = this.generateMovableArray(); - var blocksObj = this.getMapBlocksObj(core.status.floorId); +maps.prototype._canMoveDirectly_bfs = function (sx, sy, locs, number, ans, canMoveArray) { + canMoveArray = canMoveArray || this.generateMovableArray(); + var blocksObj = this.getMapBlocksObj(); // 滑冰 var bgMap = this.getBgMapArray(); @@ -639,7 +688,8 @@ maps.prototype._canMoveDirectly_bfs = function (sx, sy, locs, number, ans) { for (var i in ans) { if (locs[i][0] == nx && locs[i][1] == ny && ans[i] == null) { // 不可以绿点为终点 - if (blocksObj[nx + "," + ny] && blocksObj[nx + "," + ny].event.trigger) { + var block = blocksObj[nx + "," + ny]; + if (block && !block.disable && block.event.trigger) { ans[i] = -1; } else { ans[i] = visited[nindex]; @@ -660,15 +710,16 @@ maps.prototype._canMoveDirectly_bfs = function (sx, sy, locs, number, ans) { maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { var index = x + "," + y; + var block = blocksObj[index]; // 该点是否不可通行或有脚本 - if (blocksObj[index] && (blocksObj[index].event.noPass || blocksObj[index].event.script)) + if (block && !block.disable && (block.event.noPass || block.event.script)) return false; // 该点是否是绿点可触发 - if (blocksObj[index] && blocksObj[index].event.trigger) { - if (blocksObj[index].event.trigger != 'changeFloor') return false; + if (block && !block.disable && block.event.trigger) { + if (block.event.trigger != 'changeFloor') return false; var ignore = core.flags.ignoreChangeFloor; - if (blocksObj[index].event.data && blocksObj[index].event.data.ignoreChangeFloor != null) - ignore = blocksObj[index].event.data.ignoreChangeFloor; + if (block.event.data && block.event.data.ignoreChangeFloor != null) + ignore = block.event.data.ignoreChangeFloor; if (!ignore) return false; } // 是否存在阻激夹域伤害 @@ -731,7 +782,7 @@ maps.prototype._automaticRoute_deepAdd = function (x, y, blocks) { // 判定每个可通行点的损耗值,越高越应该绕路 var deepAdd = 1; var block = blocks[x+","+y]; - if (block != null){ + if (block && !block.disable) { var id = block.event.id; // 绕过亮灯 if (id == "light") deepAdd += 100; @@ -740,7 +791,7 @@ maps.prototype._automaticRoute_deepAdd = function (x, y, blocks) { // 绕过血瓶和绿宝石 if (core.hasFlag('__potionNoRouting__') && (id.endsWith("Potion") || id == 'greenGem')) deepAdd += 100; // 绕过传送点 - // if (block.block.event.trigger == 'changeFloor') deepAdd+=10; + // if (block.event.trigger == 'changeFloor') deepAdd+=10; } // 绕过存在伤害的地方 deepAdd += (core.status.checkBlock.damage[x+","+y]||0) * 100; @@ -752,50 +803,65 @@ maps.prototype._automaticRoute_deepAdd = function (x, y, blocks) { // -------- 绘制地图,各层图块,楼层贴图,Autotile -------- // ////// 绘制一个图块 ////// -maps.prototype.drawBlock = function (block, animate) { +maps.prototype.drawBlock = function (block, animate, ctx) { if (block.event.id == 'none') return; var redraw = animate != null; if (!redraw) animate = 0; var x = block.x, y = block.y; // --- 在界面外的动画不绘制 - if (redraw && block.event.animate > 1 && - (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core.__PIXELS__ + 32 - || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core.__PIXELS__ + 32 + 16)) { - return; + + // 判定是否绘制 + if (core.bigmap.v2) { + var posX = core.bigmap.posX, posY = core.bigmap.posY; + if (x < posX - 1 || y < posY - 1 || x > posX + core.__SIZE__ || y > posY + core.__SIZE__ + 1) { // +1 for 48 height + return; + } + } else { + if (redraw && block.event.animate > 1 && + (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core.__PIXELS__ + 32 + || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core.__PIXELS__ + 32 + 16)) { + return; + } } var blockInfo = this.getBlockInfo(block); if (blockInfo == null) return; if (blockInfo.cls != 'tileset') blockInfo.posX = animate % block.event.animate; if (!block.name) - this._drawBlockInfo(blockInfo, block.x, block.y); + this._drawBlockInfo(blockInfo, block.x, block.y, ctx); else - this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y); + this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y, ctx); } -maps.prototype._drawBlockInfo = function (blockInfo, x, y) { +maps.prototype._drawBlockInfo = function (blockInfo, x, y, ctx) { var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height; + var px = 32 * x - 32 * core.bigmap.posX; + var py = 32 * y - 32 * core.bigmap.posY; + if (ctx == null) ctx = 'event'; - core.clearMap('event', x * 32, y * 32, 32, 32); - core.drawImage('event', image, posX * 32, posY * height + height - 32, 32, 32, x * 32, y * 32, 32, 32); + core.clearMap(ctx, px, py, 32, 32); + core.drawImage(ctx, image, posX * 32, posY * height + height - 32, 32, 32, px, py, 32, 32); if (height > 32) { - core.clearMap('event2', x * 32, y * 32 + 32 - height, 32, height - 32) - core.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, x * 32, y * 32 + 32 - height, 32, height - 32); + core.clearMap('event2', px, py + 32 - height, 32, height - 32) + core.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, px, py + 32 - height, 32, height - 32); } } -maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y) { +maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y, ctx) { var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height; + var px = 32 * x - 32 * core.bigmap.posX; + var py = 32 * y - 32 * core.bigmap.posY; + if (ctx == null) ctx = name; - core.clearMap(name, x * 32, y * 32 + 32 - height, 32, height); + core.clearMap(ctx, px, py + 32 - height, 32, height); if (name == 'bg') { if (height > 32) { - core.clearMap('bg', x * 32, y * 32 - 32, 32, 32); - core.drawImage('bg', core.material.groundCanvas.canvas, x * 32, y * 32 - 32); + core.clearMap(ctx, px, py - 32, 32, 32); + core.drawImage(ctx, core.material.groundCanvas.canvas, px, py - 32); } - core.drawImage('bg', core.material.groundCanvas.canvas, x * 32, y * 32); + core.drawImage(ctx, core.material.groundCanvas.canvas, px, py); } - core.drawImage(name, image, posX * 32, posY * height, 32, height, x * 32, y * 32 + 32 - height, 32, height); + core.drawImage(ctx, image, posX * 32, posY * height, 32, height, px, py + 32 - height, 32, height); } ////// 生成groundPattern ////// @@ -812,12 +878,9 @@ maps.prototype.generateGroundPattern = function (floorId) { } ////// 绘制某张地图 ////// -maps.prototype.drawMap = function (floorId, callback) { +maps.prototype.drawMap = function (floorId) { floorId = floorId || core.status.floorId; - if (!floorId) { - if (callback) callback(); - return; - } + if (!floorId) return; core.clearMap('all'); this.generateGroundPattern(floorId); core.status.floorId = floorId; @@ -831,20 +894,36 @@ maps.prototype.drawMap = function (floorId, callback) { } core.drawHero(); core.updateStatusBar(); - if (callback) callback(); } -maps.prototype._drawMap_drawAll = function (floorId) { +////// 重绘某张地图 ////// +maps.prototype.redrawMap = function () { + core.bigmap.canvas.forEach(function (one) { + core.clearMap(one); + }); + this._drawMap_drawAll(null, {redraw: true}); + core.drawDamage(); +} + +maps.prototype._drawMap_drawAll = function (floorId, config) { floorId = floorId || core.status.floorId; - this.drawBg(floorId); + this.drawBg(floorId, config); this.drawEvents(floorId); - this.drawFg(floorId); + this.drawFg(floorId, config); } maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { if (blockInfo == null) return; + if (onMap && core.bigmap.v2) { + // 判定是否绘制 + var posX = core.bigmap.posX, posY = core.bigmap.posY; + if (block.x < posX - 1 || block.y < posY - 1 || block.x > posX + core.__SIZE__ || block.y > posY + core.__SIZE__ + 1) { // +1 for 48 height + return; + } + } + if (blockInfo.cls == 'autotile') { // Autotile单独处理 - this._drawAutotile(ctx, arr, block, 32, 0, 0); + this._drawAutotile(ctx, arr, block, 32, 0, 0, 0, onMap); if (onMap) this.addGlobalAnimate(block); return; } @@ -853,69 +932,155 @@ maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, on core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y + 32 - height, 32, height); return; } - this.drawBlock(block); + this.drawBlock(block, null, ctx); this.addGlobalAnimate(block); } ////// 绘制背景层 ////// -maps.prototype.drawBg = function (floorId, ctx) { +// config:绘制的参数,可包含如下项: +// redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用); +maps.prototype.drawBg = function (floorId, config) { floorId = floorId || core.status.floorId; - var onMap = ctx == null; - if (onMap) { - ctx = core.canvas.bg; - core.clearMap(ctx); + if (config == null) config = {}; + if (typeof config == 'string' || config.canvas) config = {ctx: config}; + config = Object.assign({}, config); + if (config.ctx == null) { + config.onMap = true; + config.ctx = 'bg'; + core.clearMap('bg'); core.status.floorAnimateObjs = this._getFloorImages(floorId); } - core.maps._drawBg_drawBackground(floorId, ctx); - // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 - core.maps._drawFloorImages(floorId, ctx, 'bg'); - core.maps._drawBgFgMap(floorId, ctx, 'bg', onMap); + var toDrawCtx = core.getContextByName(config.ctx); + if (!toDrawCtx) return; + + var cacheCtx = toDrawCtx; + if (config.onMap) { + cacheCtx = core.bigmap.cacheCanvas; + cacheCtx.canvas.width = toDrawCtx.canvas.width; + cacheCtx.canvas.height = toDrawCtx.canvas.height; + if (core.bigmap.v2) cacheCtx.translate(32, 32); + } + this._drawBg_draw(floorId, toDrawCtx, cacheCtx, config); + if (config.onMap) cacheCtx.translate(0, 0); } -maps.prototype._drawBg_drawBackground = function (floorId, ctx) { - var width = core.floors[floorId].width, height = core.floors[floorId].height; +maps.prototype._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) { + config.ctx = cacheCtx; + core.maps._drawBg_drawBackground(floorId, config); + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 + core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap); + core.maps._drawBgFgMap(floorId, 'bg', config); + if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + config.ctx = toDrawCtx; +} + +maps.prototype._drawBg_drawBackground = function (floorId, config) { var groundId = (core.status.maps || core.floors)[floorId].defaultGround || "ground"; var groundInfo = core.getBlockInfo(groundId); + var onMap = config.onMap; if (groundInfo != null) { - for (var i = 0; i < width; i++) { - for (var j = 0; j < height; j++) { - core.drawImage(ctx, groundInfo.image, 32 * groundInfo.posX, groundInfo.height * groundInfo.posY, 32, 32, i * 32, j * 32, 32, 32); - } - } + var start = onMap && core.bigmap.v2 ? -1 : 0; + var endX = onMap && core.bigmap.v2 ? core.__SIZE__ + 1 : core.floors[floorId].width; + var endY = onMap && core.bigmap.v2 ? core.__SIZE__ + 1 : core.floors[floorId].height; + + var patternCanvas = document.createElement('canvas'); + patternCanvas.width = patternCanvas.height = 32; + var patternCtx = patternCanvas.getContext('2d'); + core.drawImage(patternCtx, groundInfo.image, 32 * groundInfo.posX, groundInfo.height * groundInfo.posY, 32, 32, 0, 0, 32, 32) + + core.fillRect(config.ctx, 32 * start, 32 * start, 32 * (endX - start), 32 * (endY - start), patternCtx.createPattern(patternCanvas, 'repeat')); } } ////// 绘制事件层 ////// -maps.prototype.drawEvents = function (floorId, blocks, ctx) { +maps.prototype.drawEvents = function (floorId, blocks, config) { floorId = floorId || core.status.floorId; - core.extractBlocks(floorId); - if (!blocks) blocks = core.status.maps[floorId].blocks; - var arr = this._getMapArrayFromBlocks(blocks, core.floors[floorId].width, core.floors[floorId].height); - var onMap = ctx == null; - if (onMap) ctx = core.canvas.event; + if (config == null) config = {}; + if (typeof config == 'string' || config.canvas) config = {ctx: config}; + config = Object.assign({}, config); + if (config.ctx == null) { + config.onMap = true; + config.ctx = 'event'; + core.clearMap('event'); + core.clearMap('event2'); + } + var toDrawCtx = core.getContextByName(config.ctx); + if (!toDrawCtx) return; + + var cacheCtx = toDrawCtx; + if (config.onMap) { + cacheCtx = core.bigmap.cacheCanvas; + cacheCtx.canvas.width = toDrawCtx.canvas.width; + cacheCtx.canvas.height = toDrawCtx.canvas.height; + if (core.bigmap.v2) cacheCtx.translate(32, 32); + } + + var arr = null; + if (!blocks) { + core.extractBlocks(floorId); + blocks = core.status.maps[floorId].blocks; + arr = this.getMapArray(floorId, !config.redraw) + } else { + arr = this._getMapArrayFromBlocks(blocks, core.floors[floorId].width, core.floors[floorId].height); + } + blocks.filter(function (block) { + if (config.onMap && core.bigmap.v2) { + // 判定是否绘制 + var posX = core.bigmap.posX, posY = core.bigmap.posY; + if (block.x < posX - 1 || block.y < posY - 1 || block.x > posX + core.__SIZE__ || block.y > posY + core.__SIZE__ + 1) { // +1 for 48 height + return false; + } + } return block.event && !block.disable; }).forEach(function (block) { - core.maps._drawMap_drawBlockInfo(ctx, block, core.maps.getBlockInfo(block), arr, onMap); + core.maps._drawMap_drawBlockInfo(cacheCtx, block, core.maps.getBlockInfo(block), arr, config.onMap); }); - if (onMap) core.status.autotileAnimateObjs.map = core.clone(arr); + + if (config.onMap) { + core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + cacheCtx.translate(0, 0); + } } ////// 绘制前景层 ////// -maps.prototype.drawFg = function (floorId, ctx) { +// config:绘制的参数,可包含如下项: +// redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用); +maps.prototype.drawFg = function (floorId, config) { floorId = floorId || core.status.floorId; - var onMap = ctx == null; - if (onMap) { - ctx = core.canvas.fg; - core.status.floorAnimateObjs = this._getFloorImages(floorId); + if (config == null) config = {}; + if (typeof config == 'string' || config.canvas) config = {ctx: config}; + config = Object.assign({}, config); + if (config.ctx == null) { + config.onMap = true; + config.ctx = 'fg'; + core.clearMap('fg'); } - // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 - this._drawFloorImages(floorId, ctx, 'fg'); - this._drawBgFgMap(floorId, ctx, 'fg', onMap); + var toDrawCtx = core.getContextByName(config.ctx); + if (!toDrawCtx) return; + + var cacheCtx = toDrawCtx; + if (config.onMap) { + cacheCtx = core.bigmap.cacheCanvas; + cacheCtx.canvas.width = toDrawCtx.canvas.width; + cacheCtx.canvas.height = toDrawCtx.canvas.height; + if (core.bigmap.v2) cacheCtx.translate(32, 32); + } + this._drawFg_draw(floorId, toDrawCtx, cacheCtx, config); + if (config.onMap) cacheCtx.translate(0, 0); +} + +maps.prototype._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) { + config.ctx = cacheCtx; + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。 + core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap); + core.maps._drawBgFgMap(floorId, 'fg', config); + if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + config.ctx = toDrawCtx; } ////// 实际的背景/前景图块的绘制 ////// -maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { +maps.prototype._drawBgFgMap = function (floorId, name, config) { floorId = floorId || core.status.floorId; if (!floorId) return; var width = core.floors[floorId].width; @@ -924,14 +1089,20 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { if (!core.status[name + "maps"]) core.status[name + "maps"] = {}; - var arr = this._getBgFgMapArray(name, floorId, true); + var startX = config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posX - 1) : 0; + var endX = config.onMap && core.bigmap.v2 ? Math.min(width, core.bigmap.posX + core.__SIZE__ + 1) : width; + var startY = config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posY - 1) : 0; + var endY = config.onMap && core.bigmap.v2 ? Math.min(height, core.bigmap.posY + core.__SIZE__ + 2) : height; // +1 for 48 px + + var arr = this._getBgFgMapArray(name, floorId, !config.redraw); var eventArr = null; - if (name == 'fg' && onMap && this._drawBgFgMap_shouldBlurFg()) { + if (name == 'fg' && config.onMap && this._drawBgFgMap_shouldBlurFg()) { eventArr = this.getMapArray(floorId); } - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { + for (var x = startX; x < endX; x++) { + for (var y = startY; y < endY; y++) { + if (arr[y][x] == 0) continue; var block = this.initBlock(x, y, arr[y][x], true); block.name = name; var blockInfo = this.getBlockInfo(block); @@ -940,15 +1111,13 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { var blur = false, alpha; if (eventArr != null && eventArr[y][x] != 0) { blur = true; - alpha = ctx.globalAlpha; - ctx.globalAlpha = 0.6; + alpha = config.ctx.globalAlpha; + config.ctx.globalAlpha = 0.6; } - this._drawMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); - if (blur) ctx.globalAlpha = alpha; + this._drawMap_drawBlockInfo(config.ctx, block, blockInfo, arr, config.onMap); + if (blur) config.ctx.globalAlpha = alpha; } } - if (onMap) - core.status.autotileAnimateObjs[name + "map"] = core.clone(arr); } ////// 是否应当存在事件时虚化前景层 ////// @@ -957,7 +1126,7 @@ maps.prototype._drawBgFgMap_shouldBlurFg = function () { } ////// 绘制楼层贴图 ////// -maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStatus) { +maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStatus, onMap) { floorId = floorId || core.status.floorId; if (!images) images = this._getFloorImages(floorId); var redraw = currStatus != null; @@ -974,7 +1143,7 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat this._drawFloorImages_gif(image, one.x, one.y); return; } - this._drawFloorImage(ctx, name, one, image, currStatus); + this._drawFloorImage(ctx, name, one, image, currStatus, onMap); }, this); } @@ -995,25 +1164,34 @@ maps.prototype._drawFloorImages_gif = function (image, dx, dy) { return; } -maps.prototype._drawFloorImage = function (ctx, name, one, image, currStatus) { +maps.prototype._drawFloorImage = function (ctx, name, one, image, currStatus, onMap) { var height = image.height; var imageName = one.name + (one.reverse||''); var width = parseInt((one.w == null ? image.width : one.w) / (one.frame || 1)); var height = one.h == null ? image.height : one.h; var sx = (one.sx || 0) + (currStatus || 0) % (one.frame || 1) * width; var sy = one.sy || 0; + var x = one.x || 0, y = one.y || 0; + if (onMap && core.bigmap.v2) { + if (x > 32 * core.bigmap.posX + core.__PIXELS__ + 32 || x + width < 32 * core.bigmap.posX - 32 + || y > 32 * core.bigmap.posX + core.__PIXELS__ + 32 || y + height < 32 * core.bigmap.posY - 32) { + return; + } + x -= 32 * core.bigmap.posX; + y -= 32 * core.bigmap.posY; + } if (one.canvas != 'auto' && one.canvas != name) return; if (one.canvas != 'auto') { - if (currStatus != null) core.clearMap(ctx, one.x, one.y, width, height); - core.drawImage(ctx, imageName, sx, sy, width, height, one.x, one.y, width, height); + if (currStatus != null) core.clearMap(ctx, x, y, width, height); + core.drawImage(ctx, imageName, sx, sy, width, height, x, y, width, height); } else { if (name == 'bg') { - if (currStatus != null) core.clearMap(ctx, one.x, one.y + height - 32, width, 32); - core.drawImage(ctx, imageName, sx, sy + height - 32, width, 32, one.x, one.y+height - 32, width, 32); + if (currStatus != null) core.clearMap(ctx, x, y + height - 32, width, 32); + core.drawImage(ctx, imageName, sx, sy + height - 32, width, 32, x, y + height - 32, width, 32); } else if (name == 'fg') { - if (currStatus != null) core.clearMap(ctx, one.x, one.y, width, height - 32); - core.drawImage(ctx, imageName, sx, sy, width, height - 32, one.x, one.y, width, height - 32); + if (currStatus != null) core.clearMap(ctx, x, y, width, height - 32); + core.drawImage(ctx, imageName, sx, sy, width, height - 32, x, y, width, height - 32); } } } @@ -1021,7 +1199,7 @@ maps.prototype._drawFloorImage = function (ctx, name, one, image, currStatus) { ////// 绘制Autotile ////// -maps.prototype._drawAutotile = function (ctx, mapArr, block, size, left, top, status) { +maps.prototype._drawAutotile = function (ctx, mapArr, block, size, left, top, status, onMap) { var xx = block.x, yy = block.y; var autotile = core.material.images['autotile'][block.event.id]; status = status || 0; @@ -1041,27 +1219,32 @@ maps.prototype._drawAutotile = function (ctx, mapArr, block, size, left, top, st iG[_x][_y] = isGrass(xx + _x, yy + _y); })}); if(iG[-1][-1] + iG[0][-1] + iG[0][0] + iG[-1][0] == 3 && !iG[-1][-1]){ - this._drawAutotile_render(ctx, xx * size + left, yy * size + top, size, autotile, status, 16); + this._drawAutotile_render(ctx, xx * size + left, yy * size + top, size, autotile, status, 16, null, onMap); done[0] = true; } if(iG[0][-1] + iG[1][-1] + iG[1][0] + iG[0][0] == 3 && !iG[1][-1]){ - this._drawAutotile_render(ctx, xx * size + left + size/2, yy * size + top, size, autotile, status, 17); + this._drawAutotile_render(ctx, xx * size + left + size/2, yy * size + top, size, autotile, status, 17, null, onMap); done[1] = true; } if(iG[0][0] + iG[1][0] + iG[1][1] + iG[0][1] == 3 && !iG[1][1]){ - this._drawAutotile_render(ctx, xx * size + left+size/2, yy * size + top + size/2, size, autotile, status, 18); + this._drawAutotile_render(ctx, xx * size + left+size/2, yy * size + top + size/2, size, autotile, status, 18, null, onMap); done[3] = true; } if(iG[0-1][0] + iG[0][0] + iG[0][1] + iG[-1][1] == 3 && !iG[-1][1]){ - this._drawAutotile_render(ctx, xx * size + left, yy * size + top + size/2, size, autotile, status, 19); + this._drawAutotile_render(ctx, xx * size + left, yy * size + top + size/2, size, autotile, status, 19, null, onMap); done[2] = true; } var _id = iG[0][-1] + 2 * iG[-1][0] + 4 * iG[0][1] + 8 * iG[1][0]; - this._drawAutotile_render(ctx, xx * size, yy * size, size, autotile, status, _id, done); + + this._drawAutotile_render(ctx, xx * size, yy * size, size, autotile, status, _id, done, onMap); } -maps.prototype._drawAutotile_render = function(canvas, x, y, size, autotile, status, index, done) { +maps.prototype._drawAutotile_render = function(canvas, x, y, size, autotile, status, index, done, onMap) { + if (onMap) { + x -= 32 * core.bigmap.posX; + y -= 32 * core.bigmap.posY; + } var indexData = [[[96 * status, 0, 32, 32, x, y, size, size],], [[96 * status, 3 * 32, 16, 32, x, y, size / 2, size],[96 * status + 2 * 32 + 16, 3 * 32, 16, 32, x + size / 2, y, size / 2, size],], [[96 * status + 2 * 32, 32, 32, 16, x, y, size, size / 2],[96 * status + 2 * 32, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2],], @@ -1141,7 +1324,7 @@ maps.prototype._drawAutotile_drawBlockByIndex = function (ctx, dx, dy, autotileI maps.prototype._drawAutotile_getAutotileAroundId = function (currId, x, y, mapArr) { if (x < 0 || y < 0 || x >= mapArr[0].length || y >= mapArr.length) return 1; - else return core.material.autotileEdges[currId].indexOf(mapArr[y][x]) >= 0; + else return (core.material.autotileEdges[currId] || []).indexOf(mapArr[y][x]) >= 0; } maps.prototype._drawAutotile_checkAround = function (x, y, mapArr) { @@ -1174,20 +1357,27 @@ maps.prototype._drawAutotile_getAutotileIndexs = function (x, y, mapArr, indexAr maps.prototype._drawAutotileAnimate = function (block, animate) { var x = block.x, y = block.y; // ------ 界面外的动画不绘制 - if (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core.__PIXELS__ + 32 - || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core.__PIXELS__ + 32 + 16) { - return; + if (core.bigmap.v2) { + var posX = core.bigmap.posX, posY = core.bigmap.posY; + if (x < posX - 1 || y < posY - 1 || x > posX + core.__SIZE__ || y > posY + core.__SIZE__) { + return; + } + } else { + if (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + core.__PIXELS__ + 32 + || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + core.__PIXELS__ + 32 + 16) { + return; + } } var cv = block.name?core.canvas[block.name]:core.canvas.event; - cv.clearRect(32 * x, 32 * y, 32, 32); + cv.clearRect(32 * x - 32 * core.bigmap.posX, 32 * y - 32 * core.bigmap.posY, 32, 32); if (block.name) { if (block.name == 'bg') - core.drawImage('bg', core.material.groundCanvas.canvas, 32 * x, 32 * y); - this._drawAutotile(cv, core.status.autotileAnimateObjs[block.name+"map"], block, 32, 0, 0, animate); + core.drawImage('bg', core.material.groundCanvas.canvas, 32 * x - 32 * core.bigmap.posX, 32 * y - 32 * core.bigmap.posY); + this._drawAutotile(cv, this._getBgFgMapArray(block.name), block, 32, 0, 0, animate, true); } else { - this._drawAutotile(cv, core.status.autotileAnimateObjs.map, block, 32, 0, 0, animate); + this._drawAutotile(cv, this.getMapArray(), block, 32, 0, 0, animate, true); } } @@ -1228,31 +1418,54 @@ maps.prototype._makeAutotileEdges = function () { // 此函数将绘制一个缩略图,floorId为目标floorId,blocks为地图的图块(可为null使用floorId对应默认的) // options为绘制选项(可为null),包括: // heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤;flags:当前的flags(存读档时使用) -// toDraw为要绘制到的信息(可为null,或为一个画布名),包括: // ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:大小(默认416/480); // all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心) -maps.prototype.drawThumbnail = function (floorId, blocks, options, toDraw) { +maps.prototype.drawThumbnail = function (floorId, blocks, options) { floorId = floorId || core.status.floorId; if (!floorId) return; + options = options || {}; + if (typeof options == 'string' || options.canvas) options = {ctx: options}; + var ctx = options.ctx; // Step1:绘制到tempCanvas上 this._drawThumbnail_drawTempCanvas(floorId, blocks, options); + options.ctx = ctx; // Step2:从tempCanvas绘制到对应的画布上 - this._drawThumbnail_drawToTarget(floorId, toDraw); + this._drawThumbnail_drawToTarget(floorId, options); } maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) { - core.extractBlocks(floorId); - blocks = blocks || core.status.maps[floorId].blocks; - options = options || {} - var width = core.floors[floorId].width; var height = core.floors[floorId].height; // 绘制到tempCanvas上面 var tempCanvas = core.bigmap.tempCanvas; - var tempWidth = width * 32, tempHeight = height * 32; - tempCanvas.canvas.width = tempWidth; - tempCanvas.canvas.height = tempHeight; - tempCanvas.clearRect(0, 0, tempWidth, tempHeight); + + // 如果是大地图模式? + if (options.all) { + // 计算比例 + var scale = Math.max(core.__SIZE__ / width, core.__SIZE__ / height); + tempCanvas.canvas.width = width * 32 * scale; + tempCanvas.canvas.height = height * 32 * scale; + tempCanvas.scale(scale, scale); + } else if (width * height > core.bigmap.threshold) { + options.v2 = true; + tempCanvas.canvas.width = core.__PIXELS__; + tempCanvas.canvas.height = core.__PIXELS__; + var centerX = options.centerX, centerY = options.centerY; + if (centerX == null) centerX = Math.floor(width / 2); + if (centerY == null) centerY = Math.floor(height / 2); + var offsetX = core.clamp(centerX - core.__HALF_SIZE__, 0, width - core.__SIZE__), + offsetY = core.clamp(centerY - core.__HALF_SIZE__, 0, height - core.__SIZE__); + tempCanvas.translate(-32 * offsetX, -32 * offsetY); + } else { + options.v2 = false; + tempCanvas.canvas.width = width * 32; + tempCanvas.canvas.height = height * 32; + } + options.ctx = tempCanvas; + + // 地图过大的缩略图不绘制显伤 + if (width * height > (core.__SIZE__ + 2 * core.bigmap.extend) * (core.__SIZE__ + 2 * core.bigmap.extend)) + options.damage = false; // --- 暂存 flags var hasHero = core.status.hero != null, flags = null; @@ -1262,48 +1475,49 @@ maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, option core.status.hero.flags = options.flags; } - this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options, tempCanvas); + this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options); // --- 恢复 flags if (!hasHero) delete core.status.hero; else if (flags != null) core.status.hero.flags = flags; + tempCanvas.setTransform(1, 0, 0, 1, 0, 0); } -maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, options, tempCanvas) { +maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, options) { // 缩略图:背景 - this.drawBg(floorId, tempCanvas); + this.drawBg(floorId, options); // 缩略图:事件 - this.drawEvents(floorId, blocks, tempCanvas); + this.drawEvents(floorId, blocks, options); // 缩略图:勇士 if (options.heroLoc) { options.heroIcon = options.heroIcon || core.status.hero.image || 'hero.png'; options.heroIcon = core.getMappedName(options.heroIcon); var icon = core.material.icons.hero[options.heroLoc.direction]; var height = core.material.images.images[options.heroIcon].height / 4; - core.drawImage(tempCanvas, core.material.images.images[options.heroIcon], icon.stop * 32, icon.loc * height, 32, height, + core.drawImage(options.ctx, core.material.images.images[options.heroIcon], icon.stop * 32, icon.loc * height, 32, height, 32 * options.heroLoc.x, 32 * options.heroLoc.y + 32 - height, 32, height); } // 缩略图:前景 - this.drawFg(floorId, tempCanvas); + this.drawFg(floorId, options); // 缩略图:显伤 - if (options.damage) - core.control.updateDamage(floorId, tempCanvas); + if (options.damage && core.hasItem('book')) { + core.updateCheckBlock(floorId); + core.control.updateDamage(floorId, options.ctx); + } } -maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { - if (toDraw == null) return; - if (typeof toDraw == 'string' || toDraw.canvas) toDraw = {ctx: toDraw}; - var ctx = core.getContextByName(toDraw.ctx); +maps.prototype._drawThumbnail_drawToTarget = function (floorId, options) { + var ctx = core.getContextByName(options.ctx); if (ctx == null) return; - var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || core.__PIXELS__; + var x = options.x || 0, y = options.y || 0, size = options.size || core.__PIXELS__; var width = core.floors[floorId].width, height = core.floors[floorId].height; - var centerX = toDraw.centerX, centerY = toDraw.centerY; + var centerX = options.centerX, centerY = options.centerY; if (centerX == null) centerX = Math.floor(width / 2); if (centerY == null) centerY = Math.floor(height / 2); - var tempCanvas = core.bigmap.tempCanvas, tempWidth = 32 * width, tempHeight = 32 * height; + var tempCanvas = core.bigmap.tempCanvas; - // core.clearMap(ctx, x, y, size, size); - if (toDraw.all) { + if (options.all) { + var tempWidth = tempCanvas.canvas.width, tempHeight = tempCanvas.canvas.height; // 绘制全景图 if (tempWidth <= tempHeight) { var realHeight = size, realWidth = realHeight * tempWidth / tempHeight; @@ -1322,9 +1536,14 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { } else { // 只绘制可见窗口 - var offsetX = core.clamp(centerX - core.__HALF_SIZE__, 0, width - core.__SIZE__), - offsetY = core.clamp(centerY - core.__HALF_SIZE__, 0, height - core.__SIZE__); - core.drawImage(ctx, tempCanvas.canvas, offsetX * 32, offsetY * 32, core.__PIXELS__, core.__PIXELS__, x, y, size, size); + if (options.v2) { + core.drawImage(ctx, tempCanvas.canvas, 0, 0, core.__PIXELS__, core.__PIXELS__, x, y, size, size); + } else { + var offsetX = core.clamp(centerX - core.__HALF_SIZE__, 0, width - core.__SIZE__), + offsetY = core.clamp(centerY - core.__HALF_SIZE__, 0, height - core.__SIZE__); + core.drawImage(ctx, tempCanvas.canvas, offsetX * 32, offsetY * 32, core.__PIXELS__, core.__PIXELS__, x, y, size, size); + } + } } @@ -1334,21 +1553,21 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { maps.prototype.noPass = function (x, y, floorId) { var block = core.getBlock(x, y, floorId); if (block == null) return false; - return block.block.event.noPass; + return block.event.noPass; } ////// 某个点是否存在NPC ////// maps.prototype.npcExists = function (x, y, floorId) { var block = this.getBlock(x, y, floorId); if (block == null) return false; - return block.block.event.cls.indexOf('npc') == 0; + return block.event.cls.indexOf('npc') == 0; } ////// 某个点是否存在(指定的)地形 ////// maps.prototype.terrainExists = function (x, y, id, floorId) { var block = this.getBlock(x, y, floorId); if (block == null) return false; - return block.block.event.cls == 'terrains' && (id ? block.block.event.id == id : true); + return block.event.cls == 'terrains' && (id ? block.event.id == id : true); } ////// 某个点是否存在楼梯 ////// @@ -1371,7 +1590,7 @@ maps.prototype.nearStair = function () { maps.prototype.enemyExists = function (x, y, id, floorId) { var block = this.getBlock(x, y, floorId); if (block == null) return false; - return block.block.event.cls.indexOf('enemy') == 0 && (id ? block.block.event.id == id : true); + return block.event.cls.indexOf('enemy') == 0 && (id ? block.event.id == id : true); } ////// 获得某个点的block ////// @@ -1379,26 +1598,28 @@ maps.prototype.getBlock = function (x, y, floorId, showDisable) { floorId = floorId || core.status.floorId; if (!floorId) return null; core.extractBlocks(floorId); - var blocks = core.status.maps[floorId].blocks; - for (var n = 0; n < blocks.length; n++) { - if (blocks[n].x == x && blocks[n].y == y) { - if (!showDisable && blocks[n].disable) return null; - return {"index": n, "block": blocks[n]}; - } - } + var blockObjs = this.getMapBlocksObj(floorId); + var block = blockObjs[x + "," + y]; + if (block && (showDisable || !block.disable)) return block; return null; } ////// 获得某个点的blockId ////// maps.prototype.getBlockId = function (x, y, floorId, showDisable) { var block = core.getBlock(x, y, floorId, showDisable); - return block == null ? null : block.block.event.id; + return block == null ? null : block.event.id; +} + +////// 获得某个点的数字 ////// +maps.prototype.getBlockNumber = function (x, y, floorId, showDisable) { + var block = core.getBlock(x, y, floorId, showDisable); + return block == null ? null : block.id; } ////// 获得某个点的blockCls ////// maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { var block = core.getBlock(x, y, floorId, showDisable); - return block == null ? null : block.block.event.cls; + return block == null ? null : block.event.cls; } ////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 ////// @@ -1460,7 +1681,7 @@ maps.prototype.searchBlock = function (id, floorId, showDisable) { for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) { var block = core.status.maps[floorId].blocks[i]; if ((showDisable || !block.disable) && (core.matchWildcard(id, block.event.id) || core.matchRegex(id, block.event.id))) { - result.push({floorId: floorId, index: i, block: block, x: block.x, y: block.y}); + result.push({floorId: floorId, x: block.x, y: block.y, block: block}); } } return result; @@ -1474,7 +1695,6 @@ maps.prototype.showBlock = function (x, y, floorId) { if (!floorId) return; var block = core.getBlock(x, y, floorId, true); if (block == null) return; // 不存在 - block = block.block; // 本身是禁用事件,启用之 if (block.disable) { block.disable = false; @@ -1500,10 +1720,12 @@ maps.prototype.hideBlock = function (x, y, floorId) { var block = core.getBlock(x, y, floorId, true); if (block == null) return; // 不存在 - core.hideBlockByIndex(block.index, floorId); + block.disable = true; + core.setMapBlockDisabled(floorId, block.x, block.y, true); + this._updateMapArray(floorId, block.x, block.y); // 删除动画,清除地图 - this._removeBlockFromMap(floorId, block.block); + this._removeBlockFromMap(floorId, block); } ////// 根据图块的索引来隐藏图块 ////// @@ -1514,6 +1736,7 @@ maps.prototype.hideBlockByIndex = function (index, floorId) { var blocks = core.status.maps[floorId].blocks, block = blocks[index]; block.disable = true; core.setMapBlockDisabled(floorId, block.x, block.y, true); + this._updateMapArray(floorId, block.x, block.y); } ////// 一次性隐藏多个block ////// @@ -1531,11 +1754,13 @@ maps.prototype._removeBlockFromMap = function (floorId, block) { core.drawMap(); } else { var x = block.x, y = block.y; + var px = 32 * x - core.bigmap.posX * 32; + var py = 32 * y - core.bigmap.posY * 32; core.removeGlobalAnimate(x, y); - core.clearMap('event', x * 32, y * 32, 32, 32); + core.clearMap('event', px, py, 32, 32); var height = block.event.height || 32; if (height > 32) - core.clearMap('event2', x * 32, y * 32 + 32 - height, 32, height - 32); + core.clearMap('event2', px, py + 32 - height, 32, height - 32); core.updateStatusBar(); } } @@ -1545,14 +1770,15 @@ maps.prototype.removeBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; if (!floorId) return false; - var block = core.getBlock(x, y, floorId, true); - if (block == null) return false; // 不存在 - - core.removeBlockByIndex(block.index, floorId); - - // 删除动画,清除地图 - this._removeBlockFromMap(floorId, block.block); - return true; + for (var i in core.status.maps[floorId].blocks) { + var block = core.status.maps[floorId].blocks[i]; + if (block.x == x && block.y == y) { + this.removeBlockByIndex(i, floorId); + this._removeBlockFromMap(floorId, block); + return true; + } + } + return false; } ////// 根据block的索引(尽可能)删除该块 ////// @@ -1562,7 +1788,10 @@ maps.prototype.removeBlockByIndex = function (index, floorId) { core.extractBlocks(floorId); var blocks = core.status.maps[floorId].blocks, block = blocks[index]; blocks.splice(index, 1); + if (core.status.mapBlockObjs[floorId]) + delete core.status.mapBlockObjs[floorId][block.x+","+block.y]; core.setMapBlockDisabled(floorId, block.x, block.y, true); + this._updateMapArray(floorId, block.x, block.y); } ////// 一次性删除多个block ////// @@ -1587,27 +1816,30 @@ maps.prototype.hideBgFgMap = function (name, loc, floorId, callback) { ////// 设置前景/背景地图的显示状态 ////// maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) { if (type != 'show') type = 'hide'; - if (name != 'fg') name = 'bg'; + if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; floorId = floorId || core.status.floorId; if (!floorId) return; if (loc.length == 0) return; + var disabled = core.getFlag('__'+name+'d__', {}); + disabled[floorId] = disabled[floorId] || []; loc.forEach(function (t) { - var x = t[0], y = t[1]; - var flag = [floorId, x, y, name+"_disable"].join('@'); - if (type == 'hide') core.setFlag(flag, true); - else core.removeFlag(flag); + if (type == 'hide') { + disabled[floorId].push([t[0], t[1]]); + } else { + disabled[floorId] = disabled[floorId].filter(function (one) { return one[0] != t[0] || one[1] != t[1]}); + } }) + core.setFlag('__'+name+'d__', disabled); + core.status[name + "maps"][floorId] = null; if (floorId == core.status.floorId) { - core.drawMap(floorId, callback); - } - else { - if (callback) callback(); + core.drawMap(floorId); } + if (callback) callback(); } ////// 显示一个楼层贴图 ////// @@ -1637,11 +1869,9 @@ maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) { }) if (floorId == core.status.floorId) { - core.drawMap(floorId, callback); - } - else { - if (callback) callback(); + core.drawMap(floorId); } + if (callback) callback(); } ////// 改变图块 ////// @@ -1661,17 +1891,20 @@ maps.prototype.setBlock = function (number, x, y, floorId) { return; } var originBlock = core.getBlock(x, y, floorId, true); - var originEvent = originBlock == null ? null : originBlock.block.event; + var originEvent = originBlock == null ? null : originBlock.event; if (originBlock == null) { core.status.maps[floorId].blocks.push(block); + if (core.status.mapBlockObjs[floorId]) + core.status.mapBlockObjs[floorId][block.x+","+block.y] = block; core.setMapBlockDisabled(floorId, block.x, block.y, false); delete block.disable; } else { - originBlock.block.id = number; - originBlock.block.event = block.event; - block = originBlock.block; + originBlock.id = number; + originBlock.event = block.event; + block = originBlock; } + this._updateMapArray(floorId, x, y); if (floorId == core.status.floorId) { // 有任何一个是autotile直接重绘地图 if ((originEvent != null && originEvent.cls == 'autotile') || block.event.cls == 'autotile') { @@ -1706,7 +1939,7 @@ maps.prototype.animateSetBlock = function (number, x, y, floorId, time, callback var block = this.initBlock(x, y, number, true, core.floors[floorId]); // 如果原本是启用的 - if (originBlock != null && !originBlock.block.disable) { + if (originBlock != null && !originBlock.disable) { return this._animateSetBlock_originEnabled(block, number, x, y, floorId, time, callback); } @@ -1716,7 +1949,7 @@ maps.prototype.animateSetBlock = function (number, x, y, floorId, time, callback } // 如果原本存在且禁用;应当直接设置,没有动画 - if (originBlock != null && originBlock.block.disable) { + if (originBlock != null && originBlock.disable) { return this._animateSetBlock_originDisabled(number, x, y, floorId, callback); } if (callback) callback(); @@ -1823,8 +2056,10 @@ maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) { for (var one in toBlock.event) { block.event[one] = core.clone(toBlock.event[one]); } + this._updateMapArray(floorId, block.x, block.y); } - }); + }, this); + if (floorId == core.status.floorId) core.drawMap(); } ////// 改变前景背景的图块 ////// @@ -1832,19 +2067,23 @@ maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; if (!floorId || number == null || x == null || y == null) return; if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return; - if (name != 'bg' && name != 'fg') return; + if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return; + if (typeof number == 'string') { if (/^\d+$/.test(number)) number = parseInt(number); else number = core.getNumberById(number); } - var vFlag = [floorId, x, y, name + "_value"].join('@'); - core.setFlag(vFlag, number); + var values = core.getFlag('__'+name+'v__', {}); + values[floorId] = (values[floorId] || []).filter(function (one) { return one[0] != x || one[1] != y }); + values[floorId].push([x,y,number]); + core.setFlag('__'+name+'v__', values); + core.status[name + "maps"][floorId] = null; if (floorId == core.status.floorId){ core.clearMap(name); - if (name=='bg') core.drawBg(floorId); + if (name.startsWith('bg')) core.drawBg(floorId); else core.drawFg(floorId); } } @@ -1939,7 +2178,6 @@ maps.prototype._deleteDetachedBlock = function (canvases) { maps.prototype._getAndRemoveBlock = function (x, y) { var block = core.getBlock(x, y); if (block == null) return null; - block = block.block; var blockInfo = this.getBlockInfo(block); if (blockInfo == null) return; core.removeBlock(x, y); @@ -2152,7 +2390,6 @@ maps.prototype._animateBlock_getList = function (loc, type) { loc.forEach(function (t) { var block = core.getBlock(t[0], t[1], null, true); if (block == null) return; - block = block.block; var blockInfo = core.maps.getBlockInfo(block); if (blockInfo == null) { @@ -2190,11 +2427,12 @@ maps.prototype._animateBlock_drawList = function (list, opacity) { ////// 添加一个全局动画 ////// maps.prototype.addGlobalAnimate = function (block) { - if (!block.event || block.event.animate == null) return; + if (!block || !block.event) return; + this.removeGlobalAnimate(block.x, block.y, block.name); if (block.event.cls == 'autotile') { var id = block.event.id, img = core.material.images.autotile[id]; if (!img || img.width == 96) return; - core.status.autotileAnimateObjs.blocks.push(block); + core.status.autotileAnimateObjs.push(block); } else { if (!block.event.animate || block.event.animate == 1) return; @@ -2208,7 +2446,7 @@ maps.prototype.removeGlobalAnimate = function (x, y, name) { if (x == null || y == null) { core.status.globalAnimateStatus = 0; core.status.globalAnimateObjs = []; - core.status.autotileAnimateObjs = {"blocks": [], "map": null, "bgmap": null, "fgmap": null}; + core.status.autotileAnimateObjs = []; core.status.floorAnimateObjs = []; return; } @@ -2218,13 +2456,9 @@ maps.prototype.removeGlobalAnimate = function (x, y, name) { }); // 检查Autotile - if (core.status.autotileAnimateObjs.blocks) { - core.status.autotileAnimateObjs.blocks = core.status.autotileAnimateObjs.blocks.filter(function (block) { - return block.x != x || block.y != y || block.name != name; - }); - core.status.autotileAnimateObjs.map[y][x] = 0; - } - + core.status.autotileAnimateObjs = core.status.autotileAnimateObjs.filter(function (block) { + return block.x != x || block.y != y || block.name != name; + }); } ////// 绘制UI层的box动画 ////// diff --git a/libs/ui.js b/libs/ui.js index 4bae76a7..e13c6fc9 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -50,14 +50,20 @@ ui.prototype._createUIEvent = function () { ui.prototype.clearMap = function (name, x, y, width, height) { if (name == 'all') { for (var m in core.canvas) { - core.canvas[m].clearRect(0, 0, core.bigmap.width*32, core.bigmap.height*32); + core.canvas[m].clearRect(-32, -32, core.canvas[m].width+32, core.canvas[m].height+32); } core.dom.gif.innerHTML = ""; core.removeGlobalAnimate(); } else { var ctx = this.getContextByName(name); - if (ctx) ctx.clearRect(x||0, y||0, width||ctx.canvas.width, height||ctx.canvas.height); + if (ctx) { + if (x != null && y != null && width != null && height != null) { + ctx.clearRect(x, y, width, height); + } else { + ctx.clearRect(-32, -32, ctx.canvas.width + 32, ctx.canvas.height + 32); + } + } } } @@ -2274,7 +2280,7 @@ ui.prototype.drawFly = function(page) { } var size = this.PIXEL - 143; core.strokeRect('ui', 20, 100, size, size, '#FFFFFF', 2); - core.drawThumbnail(floorId, null, null, {ctx: 'ui', x: 20, y: 100, size: size}); + core.drawThumbnail(floorId, null, {ctx: 'ui', x: 20, y: 100, size: size}); } ////// 绘制中心对称飞行器 @@ -2286,8 +2292,7 @@ ui.prototype.drawCenterFly = function () { var toX = core.bigmap.width - 1 - core.getHeroLoc('x'), toY = core.bigmap.height - 1 - core.getHeroLoc('y'); this.clearUI(); core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000'); - core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.status.hero.image}, - {ctx: 'ui', centerX: toX, centerY: toY}); + core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.status.hero.image, ctx: 'ui', centerX: toX, centerY: toY}); var offsetX = core.clamp(toX - core.__HALF_SIZE__, 0, core.bigmap.width - core.__SIZE__), offsetY = core.clamp(toY - core.__HALF_SIZE__, 0, core.bigmap.height - core.__SIZE__); core.fillRect('ui', (toX - offsetX) * 32, (toY - offsetY) * 32, 32, 32, fillstyle); @@ -2306,8 +2311,7 @@ ui.prototype.drawMaps = function (index, x, y) { core.status.checkBlock.cache = {}; var data = this._drawMaps_buildData(index, x, y); core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000'); - core.drawThumbnail(data.floorId, null, {damage: data.damage}, - {ctx: 'ui', centerX: data.x, centerY: data.y, all: data.all}); + core.drawThumbnail(data.floorId, null, {damage: data.damage, ctx: 'ui', centerX: data.x, centerY: data.y, all: data.all}); core.clearMap('data'); core.setTextAlign('data', 'left'); core.setFont('data', '16px Arial'); @@ -2772,10 +2776,9 @@ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, hi if (data && data.floorId) { core.setTextAlign('ui', "center"); var map = core.maps.loadMap(data.maps, data.floorId); - core.extractBlocks(map, data.hero.flags); + core.extractBlocksForUI(map, data.hero.flags); core.drawThumbnail(data.floorId, map.blocks, { - heroLoc: data.hero.loc, heroIcon: data.hero.image, flags: data.hero.flags - }, { + heroLoc: data.hero.loc, heroIcon: data.hero.image, flags: data.hero.flags, ctx: 'ui', x: x-size/2, y: y+15, size: size, centerX: data.hero.loc.x, centerY: data.hero.loc.y }); if (core.isPlaying() && core.getFlag("hard") != data.hero.flags.hard) { diff --git a/libs/utils.js b/libs/utils.js index f3ad7131..44e1a115 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -58,6 +58,14 @@ utils.prototype._init = function () { return this.substring(0, search.length) === search; } } + if (typeof Array.prototype.fill != "function") { + Array.prototype.fill = function (value) { + for (var i = 0; i < this.length; ++i) + if (this[i] == null) + this[i] = value; + return this; + } + } } @@ -342,6 +350,16 @@ utils.prototype.clone = function (data, filter, recursion) { return data; } +////// 深拷贝1D/2D数组优化 ////// +utils.prototype.cloneArray = function (data) { + if (!(data instanceof Array)) return this.clone(data); + if (data[0] instanceof Array) { + return data.map(function (one) { return one.slice(); }); + } else { + return data.slice(); + } +} + ////// 裁剪图片 ////// utils.prototype.splitImage = function (image, width, height) { if (typeof image == "string") { @@ -660,7 +678,7 @@ utils.prototype.isset = function (val) { utils.prototype.subarray = function (a, b) { if (!(a instanceof Array) || !(b instanceof Array) || a.length < b.length) return null; - var na = core.clone(a), nb = core.clone(b); + var na = core.cloneArray(a), nb = core.cloneArray(b); while (nb.length > 0) { if (na.shift() != nb.shift()) return null; } @@ -697,11 +715,30 @@ utils.prototype.setStatusBarInnerHTML = function (name, value, css) { var length = this.strlen(value) || 1; style += 'font-size: ' + Math.min(1, 7 / length) + 'em; '; if (css) style += css; + var _isNumber = core.statusBar[name].getAttribute('_isNumber') == "1"; + var _style = core.statusBar[name].getAttribute('_style'); + var _value = core.statusBar[name].getAttribute('_value'); if (isNumber) { - core.statusBar[name].innerHTML = "" + value + ""; + if (_isNumber && _style == style) { + if (value == _value) return; + core.statusBar[name].innerText = value; + } else { + core.statusBar[name].innerHTML = "" + value + ""; + core.statusBar[name].setAttribute('_isNumber', '1'); + core.statusBar[name].setAttribute('_style', style); + } + core.statusBar[name].setAttribute('_value', value); } else { - core.statusBar[name].innerHTML = ""; - core.statusBar[name].children[0].innerText = value; + if (!_isNumber && _style == style) { + if (value == _value) return; + core.statusBar[name].children[0].innerText = value; + } else { + core.statusBar[name].innerHTML = ""; + core.statusBar[name].children[0].innerText = value; + core.statusBar[name].setAttribute('_isNumber', '0'); + core.statusBar[name].setAttribute('_style', style); + } + core.statusBar[name].setAttribute('_value', value); } } diff --git a/migration.html b/migration.html index 5f0681d8..c50d916b 100644 --- a/migration.html +++ b/migration.html @@ -483,8 +483,8 @@ function action_items(callback) { "cls": "tools", "name": "破墙镐", "text": "可以破坏勇士面前的墙", - "useItemEffect": "(function () {\n\tvar canBreak = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.block.disable) return false;\n\t\treturn block.block.event.canBreak;\n\t};\n\n\tvar success = false;\n\tvar pickaxeFourDirections = false; // 是否四方向破;如果是将其改成true\n\tif (pickaxeFourDirections) {\n\t\t// 四方向破\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBreak(nx, ny)) {\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t\tsuccess = true;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅破当前\n\t\tif (canBreak(core.nextX(), core.nextY())) {\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t\tsuccess = true;\n\t\t}\n\t}\n\n\tif (success) {\n\t\tcore.playSound('pickaxe.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\t// 无法使用\n\t\tcore.drawTip(\"当前无法使用\" + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n})();", - "canUseItemEffect": "true" + "useItemEffect": "(function () {\n\tvar canBreak = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.disable) return false;\n\t\treturn block.event.canBreak;\n\t};\n\n\tvar success = false;\n\tvar pickaxeFourDirections = false; // 是否四方向破;如果是将其改成true\n\tif (pickaxeFourDirections) {\n\t\t// 四方向破\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBreak(nx, ny)) {\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t\tsuccess = true;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅破当前\n\t\tif (canBreak(core.nextX(), core.nextY())) {\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t\tsuccess = true;\n\t\t}\n\t}\n\n\tif (success) {\n\t\tcore.playSound('pickaxe.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\t// 无法使用\n\t\tcore.drawTip(\"当前无法使用\" + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n})();", + "canUseItemEffect": "true" }, "icePickaxe": { "cls": "tools", @@ -497,8 +497,8 @@ function action_items(callback) { "cls": "tools", "name": "炸弹", "text": "可以炸掉勇士面前的怪物", - "useItemEffect": "(function () {\n\tvar canBomb = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.block.disable || block.block.event.cls.indexOf('enemy') != 0) return false;\n\t\tvar enemy = core.material.enemys[block.block.event.id];\n\t\treturn enemy && !enemy.notBomb;\n\t};\n\n\tvar bombList = []; // 炸掉的怪物坐标列表\n\tvar bombFourDirections = false; // 是否四方向可炸;如果是将其改成true。\n\tif (bombFourDirections) {\n\t\t// 四方向炸\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBomb(nx, ny)) {\n\t\t\t\tbombList.push([nx, ny]);\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅炸当前\n\t\tif (canBomb(core.nextX(), core.nextY())) {\n\t\t\tbombList.push([core.nextX(), core.nextY()]);\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t}\n\t}\n\n\tif (bombList.length > 0) {\n\t\tcore.playSound('bomb.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\tcore.drawTip('当前无法使用' + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n\n\t// 炸弹后事件\n\t// 这是一个使用炸弹也能开门的例子\n\t/*\n\tif (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在\n\t\t&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在\n\t{\n\t\tcore.insertAction([ // 插入事件\n\t\t\t{\"type\": \"openDoor\", \"loc\": [x0,y0]} // 开门\n\t\t])\n\t}\n\t*/\n})();", - "canUseItemEffect": "true" + "useItemEffect": "(function () {\n\tvar canBomb = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.disable || block.event.cls.indexOf('enemy') != 0) return false;\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\treturn enemy && !enemy.notBomb;\n\t};\n\n\tvar bombList = []; // 炸掉的怪物坐标列表\n\tvar bombFourDirections = false; // 是否四方向可炸;如果是将其改成true。\n\tif (bombFourDirections) {\n\t\t// 四方向炸\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBomb(nx, ny)) {\n\t\t\t\tbombList.push([nx, ny]);\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅炸当前\n\t\tif (canBomb(core.nextX(), core.nextY())) {\n\t\t\tbombList.push([core.nextX(), core.nextY()]);\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t}\n\t}\n\n\tif (bombList.length > 0) {\n\t\tcore.playSound('bomb.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\tcore.drawTip('当前无法使用' + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n\n\t// 炸弹后事件\n\t// 这是一个使用炸弹也能开门的例子\n\t/*\n\tif (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在\n\t\t&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在\n\t{\n\t\tcore.insertAction([ // 插入事件\n\t\t\t{\"type\": \"openDoor\", \"loc\": [x0,y0]} // 开门\n\t\t])\n\t}\n\t*/\n})();", + "canUseItemEffect": "true" }, "upFly": { "cls": "tools", @@ -518,7 +518,7 @@ function action_items(callback) { "cls": "tools", "name": "地震卷轴", "text": "可以破坏当前层的所有墙", - "useItemEffect": "(function () {\n\tvar indexes = [];\n\tfor (var index in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[index];\n\t\tif (!block.disable && block.event.canBreak) {\n\t\t\tindexes.push(index);\n\t\t}\n\t}\n\tcore.removeBlockByIndexes(indexes);\n\tcore.drawMap(core.status.floorId, function () {\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t});\n})();", + "useItemEffect": "(function () {\n\tvar indexes = [];\n\tfor (var index in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[index];\n\t\tif (!block.disable && block.event.canBreak) {\n\t\t\tindexes.push(index);\n\t\t}\n\t}\n\tcore.removeBlockByIndexes(indexes);\n\tcore.drawMap();\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n})();", "canUseItemEffect": "(function () {\n\treturn core.status.thisMap.blocks.filter(function (block) {\n\t\treturn !block.disable && block.event.canBreak;\n\t}).length > 0;\n})();" }, }; diff --git a/project/functions.js b/project/functions.js index c8172847..c857e7f8 100644 --- a/project/functions.js +++ b/project/functions.js @@ -125,6 +125,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (block.disable && core.enemys.hasSpecial(block.event.id, 23)) { block.disable = false; core.setMapBlockDisabled(floorId, block.x, block.y, false); + core.maps._updateMapArray(floorId, block.x, block.y); } }); core.control.gatherFollowers(); @@ -284,15 +285,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = return; } - // 删除该块 var guards = []; // 支援 if (x != null && y != null) { - // 检查是否是重生怪物;如果是则仅隐藏不删除 - if (core.hasSpecial(enemy.special, 23)) { - core.hideBlock(x, y); - } else { - core.removeBlock(x, y); - } guards = core.getFlag("__guards__" + x + "_" + y, []); core.removeFlag("__guards__" + x + "_" + y); } @@ -389,7 +383,18 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果事件不为空,将其插入 if (todo.length > 0) core.insertAction(todo, x, y); - core.updateStatusBar(); + + // 因为removeBlock和hideBlock都会刷新状态栏,因此移动到这里并保证刷新只执行一次,以提升效率 + if (core.getBlock(x, y) != null) { + // 检查是否是重生怪物;如果是则仅隐藏不删除 + if (core.hasSpecial(enemy.special, 23)) { + core.hideBlock(x, y); + } else { + core.removeBlock(x, y); + } + } else { + core.updateStatusBar(); + } // 如果已有事件正在处理中 if (core.status.event.id == null) @@ -1137,8 +1142,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.setStatusBarInnerHTML('fly', "飞" + core.itemCount('centerFly')); // 难度 - core.statusBar.hard.innerText = core.status.hard; - core.statusBar.hard.style.color = core.getFlag('__hardColor__', 'red'); + if (core.statusBar.hard.innerText != core.status.hard) { + core.statusBar.hard.innerText = core.status.hard; + core.statusBar.hard.style.color = core.getFlag('__hardColor__', 'red'); + } // 自定义状态栏绘制 core.drawStatusBar(); @@ -1160,6 +1167,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = type = {}, // 每个点的伤害类型 repulse = {}, // 每个点的阻击怪信息 ambush = {}; // 每个点的捕捉信息 + var betweenAttackLocs = {}; // 所有带夹击的怪物 var needCache = false; var canGoDeadZone = core.flags.canGoDeadZone; core.flags.canGoDeadZone = true; @@ -1171,6 +1179,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = y = block.y, id = block.event.id, enemy = core.material.enemys[id]; + if (block.disable) continue; type[loc] = type[loc] || {}; @@ -1266,6 +1275,18 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } + // 夹击;在这里提前计算所有可能的夹击点,具体计算逻辑在下面 + // 如果要防止夹击伤害,可以简单的将 flag:no_betweenAttack 设为true + if (enemy && core.enemys.hasSpecial(enemy.special, 16) && !core.hasFlag('no_betweenAttack')) { + for (var dir in core.utils.scan) { + var nx = x + core.utils.scan[dir].x, + ny = y + core.utils.scan[dir].y, + currloc = nx + "," + ny; + if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; + betweenAttackLocs[currloc] = true; + } + } + // 检查地图范围类技能 var specialFlag = core.getSpecialFlag(enemy); if (specialFlag & 1) needCache = true; @@ -1275,48 +1296,46 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 更新夹击伤害 // 如果要防止夹击伤害,可以简单的将 flag:no_betweenAttack 设为true - if (!core.hasFlag('no_betweenAttack')) { - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - var loc = x + "," + y; - // 夹击怪物的ID - var enemyId1 = null, - enemyId2 = null; - // 检查左右夹击 - var leftBlock = blocks[(x - 1) + "," + y], - rightBlock = blocks[(x + 1) + "," + y]; - if (leftBlock && rightBlock && leftBlock.id == rightBlock.id) { - if (core.hasSpecial(leftBlock.event.id, 16)) - enemyId1 = leftBlock.event.id; - } - // 检查上下夹击 - var topBlock = blocks[x + "," + (y - 1)], - bottomBlock = blocks[x + "," + (y + 1)]; - if (topBlock && bottomBlock && topBlock.id == bottomBlock.id) { - if (core.hasSpecial(topBlock.event.id, 16)) - enemyId2 = topBlock.event.id; - } + for (var loc in betweenAttackLocs) { + var xy = loc.split(","), + x = parseInt(xy[0]), + y = parseInt(xy[1]); + // 夹击怪物的ID + var enemyId1 = null, + enemyId2 = null; + // 检查左右夹击 + var leftBlock = blocks[(x - 1) + "," + y], + rightBlock = blocks[(x + 1) + "," + y]; + if (leftBlock && !leftBlock.disable && rightBlock && !rightBlock.disable && leftBlock.id == rightBlock.id) { + if (core.hasSpecial(leftBlock.event.id, 16)) + enemyId1 = leftBlock.event.id; + } + // 检查上下夹击 + var topBlock = blocks[x + "," + (y - 1)], + bottomBlock = blocks[x + "," + (y + 1)]; + if (topBlock && !topBlock.disable && bottomBlock && !bottomBlock.disable && topBlock.id == bottomBlock.id) { + if (core.hasSpecial(topBlock.event.id, 16)) + enemyId2 = topBlock.event.id; + } - if (enemyId1 != null || enemyId2 != null) { - var leftHp = core.status.hero.hp - (damage[loc] || 0); - if (leftHp > 1) { - // 夹击伤害值 - var value = Math.floor(leftHp / 2); - // 是否不超过怪物伤害值 - if (core.flags.betweenAttackMax) { - var enemyDamage1 = core.getDamage(enemyId1, x, y, floorId); - if (enemyDamage1 != null && enemyDamage1 < value) - value = enemyDamage1; - var enemyDamage2 = core.getDamage(enemyId2, x, y, floorId); - if (enemyDamage2 != null && enemyDamage2 < value) - value = enemyDamage2; - } - if (value > 0) { - damage[loc] = (damage[loc] || 0) + value; - type[loc] = type[loc] || {}; - type[loc]["夹击伤害"] = true; - } - } + if (enemyId1 != null || enemyId2 != null) { + var leftHp = core.status.hero.hp - (damage[loc] || 0); + if (leftHp > 1) { + // 夹击伤害值 + var value = Math.floor(leftHp / 2); + // 是否不超过怪物伤害值 + if (core.flags.betweenAttackMax) { + var enemyDamage1 = core.getDamage(enemyId1, x, y, floorId); + if (enemyDamage1 != null && enemyDamage1 < value) + value = enemyDamage1; + var enemyDamage2 = core.getDamage(enemyId2, x, y, floorId); + if (enemyDamage2 != null && enemyDamage2 < value) + value = enemyDamage2; + } + if (value > 0) { + damage[loc] = (damage[loc] || 0) + value; + type[loc] = type[loc] || {}; + type[loc]["夹击伤害"] = true; } } } @@ -1372,7 +1391,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = nowy = core.getHeroLoc('y'); var block = core.getBlock(nowx, nowy); var hasTrigger = false; - if (block != null && block.block.event.trigger == 'getItem' && + if (block != null && block.event.trigger == 'getItem' && !core.floors[core.status.floorId].afterGetItem[nowx + "," + nowy]) { hasTrigger = true; core.trigger(nowx, nowy, callback); diff --git a/project/items.js b/project/items.js index d019c23e..3227ecef 100644 --- a/project/items.js +++ b/project/items.js @@ -374,7 +374,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "tools", "name": "破墙镐", "text": "可以破坏勇士面前的墙", - "useItemEffect": "(function () {\n\tvar canBreak = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.block.disable) return false;\n\t\treturn block.block.event.canBreak;\n\t};\n\n\tvar success = false;\n\tvar pickaxeFourDirections = false; // 是否四方向破;如果是将其改成true\n\tif (pickaxeFourDirections) {\n\t\t// 四方向破\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBreak(nx, ny)) {\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t\tsuccess = true;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅破当前\n\t\tif (canBreak(core.nextX(), core.nextY())) {\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t\tsuccess = true;\n\t\t}\n\t}\n\n\tif (success) {\n\t\tcore.playSound('pickaxe.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\t// 无法使用\n\t\tcore.drawTip(\"当前无法使用\" + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n})();", + "useItemEffect": "(function () {\n\tvar canBreak = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.disable) return false;\n\t\treturn block.event.canBreak;\n\t};\n\n\tvar success = false;\n\tvar pickaxeFourDirections = false; // 是否四方向破;如果是将其改成true\n\tif (pickaxeFourDirections) {\n\t\t// 四方向破\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBreak(nx, ny)) {\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t\tsuccess = true;\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅破当前\n\t\tif (canBreak(core.nextX(), core.nextY())) {\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t\tsuccess = true;\n\t\t}\n\t}\n\n\tif (success) {\n\t\tcore.playSound('pickaxe.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\t// 无法使用\n\t\tcore.drawTip(\"当前无法使用\" + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n})();", "canUseItemEffect": "true" }, "icePickaxe": { @@ -388,7 +388,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "tools", "name": "炸弹", "text": "可以炸掉勇士面前的怪物", - "useItemEffect": "(function () {\n\tvar canBomb = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.block.disable || block.block.event.cls.indexOf('enemy') != 0) return false;\n\t\tvar enemy = core.material.enemys[block.block.event.id];\n\t\treturn enemy && !enemy.notBomb;\n\t};\n\n\tvar bombList = []; // 炸掉的怪物坐标列表\n\tvar bombFourDirections = false; // 是否四方向可炸;如果是将其改成true。\n\tif (bombFourDirections) {\n\t\t// 四方向炸\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBomb(nx, ny)) {\n\t\t\t\tbombList.push([nx, ny]);\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅炸当前\n\t\tif (canBomb(core.nextX(), core.nextY())) {\n\t\t\tbombList.push([core.nextX(), core.nextY()]);\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t}\n\t}\n\n\tif (bombList.length > 0) {\n\t\tcore.playSound('bomb.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\tcore.drawTip('当前无法使用' + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n\n\t// 炸弹后事件\n\t// 这是一个使用炸弹也能开门的例子\n\t/*\n\tif (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在\n\t\t&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在\n\t{\n\t\tcore.insertAction([ // 插入事件\n\t\t\t{\"type\": \"openDoor\", \"loc\": [x0,y0]} // 开门\n\t\t])\n\t}\n\t*/\n})();", + "useItemEffect": "(function () {\n\tvar canBomb = function (x, y) {\n\t\tvar block = core.getBlock(x, y);\n\t\tif (block == null || block.disable || block.event.cls.indexOf('enemy') != 0) return false;\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\treturn enemy && !enemy.notBomb;\n\t};\n\n\tvar bombList = []; // 炸掉的怪物坐标列表\n\tvar bombFourDirections = false; // 是否四方向可炸;如果是将其改成true。\n\tif (bombFourDirections) {\n\t\t// 四方向炸\n\t\tfor (var direction in core.utils.scan) {\n\t\t\tvar delta = core.utils.scan[direction];\n\t\t\tvar nx = core.getHeroLoc('x') + delta.x,\n\t\t\t\tny = core.getHeroLoc('y') + delta.y;\n\t\t\tif (canBomb(nx, ny)) {\n\t\t\t\tbombList.push([nx, ny]);\n\t\t\t\tcore.removeBlock(nx, ny);\n\t\t\t}\n\t\t}\n\t} else {\n\t\t// 仅炸当前\n\t\tif (canBomb(core.nextX(), core.nextY())) {\n\t\t\tbombList.push([core.nextX(), core.nextY()]);\n\t\t\tcore.removeBlock(core.nextX(), core.nextY());\n\t\t}\n\t}\n\n\tif (bombList.length > 0) {\n\t\tcore.playSound('bomb.mp3');\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t} else {\n\t\tcore.drawTip('当前无法使用' + core.material.items[itemId].name);\n\t\tcore.addItem(itemId, 1);\n\t\treturn;\n\t}\n\n\t// 炸弹后事件\n\t// 这是一个使用炸弹也能开门的例子\n\t/*\n\tif (core.status.floorId=='xxx' && core.terrainExists(x0,y0,'specialDoor') // 某个楼层,该机关门存在\n\t\t&& !core.enemyExists(x1,y1) && !core.enemyExists(x2,y2)) // 且守门的怪物都不存在\n\t{\n\t\tcore.insertAction([ // 插入事件\n\t\t\t{\"type\": \"openDoor\", \"loc\": [x0,y0]} // 开门\n\t\t])\n\t}\n\t*/\n})();", "canUseItemEffect": "true" }, "centerFly": { @@ -416,7 +416,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "cls": "tools", "name": "地震卷轴", "text": "可以破坏当前层的所有墙", - "useItemEffect": "(function () {\n\tvar indexes = [];\n\tfor (var index in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[index];\n\t\tif (!block.disable && block.event.canBreak) {\n\t\t\tindexes.push(index);\n\t\t}\n\t}\n\tcore.removeBlockByIndexes(indexes);\n\tcore.drawMap(core.status.floorId, function () {\n\t\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t});\n})();", + "useItemEffect": "(function () {\n\tvar indexes = [];\n\tfor (var index in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[index];\n\t\tif (!block.disable && block.event.canBreak) {\n\t\t\tindexes.push(index);\n\t\t}\n\t}\n\tcore.removeBlockByIndexes(indexes);\n\tcore.drawMap();\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n})();", "canUseItemEffect": "(function () {\n\treturn core.status.thisMap.blocks.filter(function (block) {\n\t\treturn !block.disable && block.event.canBreak;\n\t}).length > 0;\n})();" }, "poisonWine": { diff --git a/project/plugins.js b/project/plugins.js index 5f25ac13..95168369 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -321,7 +321,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 背景层2将会覆盖背景层 被事件层覆盖 前景层2将会覆盖前景层 // 另外 请注意加入两个新图层 会让大地图的性能降低一些 // 插件作者:ad - var __enable = false; + var __enable = true; if (!__enable) return; // 创建新图层 @@ -353,7 +353,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 背景层2(bg2) 插入事件层(event)之前(即bg与event之间) document.getElementById('mapEdit').insertBefore(bg2Canvas, document.getElementById('event')); // 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后) - document.getElementById('mapEdit').insertBefore(fg2Canvas, document.getElementById('efg')); + document.getElementById('mapEdit').insertBefore(fg2Canvas, document.getElementById('ebm')); // 原本有三个图层 从4开始添加 var num = 4; // 新增图层存入editor.dom中 @@ -364,16 +364,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = editor.dom.maps.push('bg2map', 'fg2map'); editor.dom.canvas.push('bg2', 'fg2'); - // 默认全空 - var defaultMap = []; - for (var i = 0; i < core.__SIZE__; ++i) { - var row = []; - for (var j = 0; j < core.__SIZE__; ++j) { - row.push(0); - } - defaultMap.push(row); - } - // 创建编辑器上的按钮 var createCanvasBtn = function (name) { // 电脑端创建按钮 @@ -390,7 +380,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = input.onchange = function () { editor.uifunctions.setLayerMod(value); } - editor[value] = editor[value] || defaultMap; return input; }; @@ -402,7 +391,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = input.name = 'layerMod'; input.value = value; editor.dom[id] = input; - editor[value] = editor[value] || defaultMap; return input; }; if (!editor.isMobile) { @@ -432,157 +420,54 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = parent.appendChild(input2); } } + core.maps._loadFloor_doNotCopy = function () { + return [ + "firstArrive", "eachArrive", "blocks", "parallelDo", "map", "bgmap", "fgmap", "bg2map", "fg2map", + "events", "changeFloor", "afterBattle", "afterGetItem", "afterOpenDoor", "cannotMove" + ]; + } - ////// 绘制背景层 ////// - core.maps.drawBg = function (floorId, ctx) { - floorId = floorId || core.status.floorId; - var onMap = ctx == null; - if (onMap) { - ctx = core.canvas.bg; - core.clearMap(ctx); - core.status.floorAnimateObjs = this._getFloorImages(floorId); - } - core.maps._drawBg_drawBackground(floorId, ctx); + ////// 绘制背景和前景层 ////// + core.maps._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) { + config.ctx = cacheCtx; + core.maps._drawBg_drawBackground(floorId, config); // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 - core.maps._drawFloorImages(floorId, ctx, 'bg'); - core.maps._drawBgFgMap(floorId, ctx, 'bg', onMap); - // 绘制背景层2 - core.maps._drawBgFgMap(floorId, ctx, 'bg2', onMap); - }; - - ////// 绘制前景层 ////// - core.maps.drawFg = function (floorId, ctx) { - floorId = floorId || core.status.floorId; - var onMap = ctx == null; - if (onMap) { - ctx = core.canvas.fg; - core.status.floorAnimateObjs = this._getFloorImages(floorId); + core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap); + core.maps._drawBgFgMap(floorId, 'bg', config); + if (config.onMap) { + core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + core.clearMap('bg2'); + core.clearMap(cacheCtx); } + core.maps._drawBgFgMap(floorId, 'bg2', config); + if (config.onMap) core.drawImage('bg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + config.ctx = toDrawCtx; + } + core.maps._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) { + config.ctx = cacheCtx; // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。 - this._drawFloorImages(floorId, ctx, 'fg'); - this._drawBgFgMap(floorId, ctx, 'fg', onMap); - // 绘制前景层2 - this._drawBgFgMap(floorId, ctx, 'fg2', onMap); - }; + core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap); + core.maps._drawBgFgMap(floorId, 'fg', config); + if (config.onMap) { + core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + core.clearMap('fg2'); + core.clearMap(cacheCtx); + } + core.maps._drawBgFgMap(floorId, 'fg2', config); + if (config.onMap) core.drawImage('fg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); + config.ctx = toDrawCtx; + } + /* cannotIn/cannotOut适配 start*/ - core.maps.generateMovableArray = function (floorId, x, y, direction) { - floorId = floorId || core.status.floorId; - if (!floorId) return null; - var width = core.floors[floorId].width, - height = core.floors[floorId].height; - var bgArray = this.getBgMapArray(floorId), - bg2Array = this._getBgFgMapArray('bg2', floorId), - fgArray = this.getFgMapArray(floorId), - fg2Array = this._getBgFgMapArray('fg2', floorId), - eventArray = this.getMapArray(floorId); - - var generate = function (x, y, direction) { - if (direction != null) { - return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, { - bgArray: bgArray, - fgArray: fgArray, - bg2Array: bg2Array, - fg2Array: fg2Array, - eventArray: eventArray - }); - } - return ["left", "down", "up", "right"].filter(function (direction) { - return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, { - bgArray: bgArray, - fgArray: fgArray, - bg2Array: bg2Array, - fg2Array: fg2Array, - eventArray: eventArray - }); - }); + core.maps._generateMovableArray_arrays = function (floorId) { + return { + bgArray: this.getBgMapArray(floorId), + fgArray: this.getFgMapArray(floorId), + eventArray: this.getMapArray(floorId), + bg2Array: this._getBgFgMapArray('bg2', floorId), + fg2Array: this._getBgFgMapArray('fg2', floorId) }; - - if (x != null && y != null) return generate(x, y, direction); - var array = []; - for (var x = 0; x < width; x++) { - array[x] = []; - for (var y = 0; y < height; y++) { - array[x][y] = generate(x, y); - } - } - return array; - }; - core.maps._canMoveHero_checkPoint = function (x, y, direction, floorId, extraData) { - // 1. 检查该点 cannotMove - if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction)) - return false; - - var nx = x + core.utils.scan[direction].x, - ny = y + core.utils.scan[direction].y; - if (nx < 0 || ny < 0 || nx >= core.floors[floorId].width || ny >= core.floors[floorId].height) - return false; - - // 2. 检查该点素材的 cannotOut 和下一个点的 cannotIn - if (this._canMoveHero_checkCannotInOut([ - extraData.bgArray[y][x], extraData.bg2Array[y][x], extraData.fgArray[y][x], extraData.fg2Array[y][x], extraData.eventArray[y][x] - ], "cannotOut", direction)) - return false; - if (this._canMoveHero_checkCannotInOut([ - extraData.bgArray[ny][nx], extraData.bg2Array[ny][nx], extraData.fgArray[ny][nx], extraData.fg2Array[ny][nx], extraData.eventArray[ny][nx] - ], "cannotIn", direction)) - return false; - - // 3. 检查是否能进将死的领域 - if (floorId == core.status.floorId && !core.flags.canGoDeadZone && - core.status.hero.hp <= (core.status.checkBlock.damage[nx + "," + ny] || 0) && - extraData.eventArray[ny][nx] == 0) - return false; - - return true; - }; - /* cannotIn/cannotOut适配 end*/ - // 前景层2与背景层2的隐藏与显示适配 - // 比如:可以用core.hideBgFgMap("bg2",[x, y], floorId)隐藏当前楼层的背景层2图块 - core.maps._triggerBgFgMap = function (type, name, loc, floorId, callback) { - if (type != 'show') type = 'hide'; - if (!name) name = 'bg'; - if (typeof loc[0] == 'number' && typeof loc[1] == 'number') - loc = [loc]; - floorId = floorId || core.status.floorId; - if (!floorId) return; - - if (loc.length == 0) return; - loc.forEach(function (t) { - var x = t[0], - y = t[1]; - var flag = [floorId, x, y, name + '_disable'].join('@'); - if (type == 'hide') core.setFlag(flag, true); - else core.removeFlag(flag); - }); - core.status[name + "maps"][floorId] = null; - - if (floorId == core.status.floorId) { - core.drawMap(floorId, callback); - } else { - if (callback) callback(); - } - }; - // 改变背景层2与前景层2图块 例:core.setBgFgBlock('fg2',312,core.nextX(),core.nextY()) - core.maps.setBgFgBlock = function (name, number, x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!floorId || number == null || x == null || y == null) return; - if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return; - if (name != 'bg' && name != 'fg' && name != 'bg2' && name != 'fg2') return; - if (typeof number == 'string') { - if (/^\d+$/.test(number)) number = parseInt(number); - else number = core.getNumberById(number); - } - - var vFlag = [floorId, x, y, name + "_value"].join('@'); - core.setFlag(vFlag, number); - core.status[name + "maps"][floorId] = null; - - if (floorId == core.status.floorId) { - core.clearMap(name); - if (name.startsWith('bg')) core.drawBg(floorId); - else core.drawFg(floorId); - } - }; + } }, "itemShop": function () { // 道具商店相关的插件 @@ -1373,125 +1258,5 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = return true; }, 100); -}, - "smoothCamera": function () { - // 此插件开启后,大地图的瞬间移动将开启平滑镜头移动,避免突兀感 - // 插件作者:老黄鸡 - - // 是否启用本插件,默认不启用 - var __enable = false; - if (!__enable) return; - - this.Camera = function () { - - // 下面这个变量决定本插件的开关 - // 你可以在游戏中使用core.setFlag('smoothCamera',false)来关闭本插件的功能 - // 同时也可以core.setFlag('smoothCamera',true)重新开启 - // 此项默认为true - // - this.__switchName = 'smoothCamera'; - - // 初始化成员变量 - this._cameraNeedRefresh = true; - this._nowOffsetX = 0; - this._nowOffsetY = 0; - this._targetOffsetX = 0; - this._targetOffsetY = 0; - this._currentFloorId = null; - - // 重置镜头,在楼层变更时使用 - this.resetCamera = function () { - this._targetOffsetX = core.bigmap.offsetX; - this._targetOffsetY = core.bigmap.offsetY; - this._nowOffsetX = this._targetOffsetX; - this._nowOffsetY = this._targetOffsetY; - this._cameraNeedRefresh = true; - }; - - // 设置焦点坐标,目前没有用 - this.setTarget = function (x, y) { - this._targetOffsetX = x; - this._targetOffsetY = y; - }; - - // 请求镜头更新 - this.requestCameraUpdate = function () { - this._cameraNeedRefresh = true; - }; - - // 更新焦点坐标,目前仅根据大地图偏移决定 - this.updateTargetPosition = function () { - this._targetOffsetX = core.bigmap.offsetX; - this._targetOffsetY = core.bigmap.offsetY; - }; - - // 更新额外的刷新条件,即镜头未指向焦点时 - this.updateRefreshFlag = function () { - if (this._nowOffsetX != this._targetOffsetX || this._nowOffsetY != this._targetOffsetY) { - this._cameraNeedRefresh = true; - } - }; - - // 判断是否禁止了弹性滚动 - this.canDirectMove = function () { - return !core.getFlag(this.__switchName, true); - }; - - // 更新镜头坐标 - this.updateCameraPosition = function () { - if (this._cameraNeedRefresh) { - this._cameraNeedRefresh = false; - var disX = this._targetOffsetX - this._nowOffsetX; - var disY = this._targetOffsetY - this._nowOffsetY; - if (Math.abs(disX) <= 2 && Math.abs(disY) <= 2 || this.canDirectMove()) { - this._nowOffsetX = this._targetOffsetX; - this._nowOffsetY = this._targetOffsetY; - } else { - this._nowOffsetX += disX / 10; - this._nowOffsetY += disY / 10; - } - var x = -Math.floor(this._nowOffsetX); - var y = -Math.floor(this._nowOffsetY); - core.bigmap.canvas.forEach(function (cn) { - core.control.setGameCanvasTranslate(cn, x, y); - }); - core.relocateCanvas('route', core.status.automaticRoute.offsetX + x, core.status.automaticRoute.offsetY + y); - core.setGameCanvasTranslate('hero', x + this._targetOffsetX, y + this._targetOffsetY); - } - }; - - // 更新逻辑主体 - this.update = function () { - this.updateTargetPosition(); - this.updateRefreshFlag(); - this.updateCameraPosition(); - }; - }; - - // 创建摄像机对象 - this.camera = new this.Camera(); - - // 帧事件 更新摄像机 - this.updateCameraEx = function () { - this.camera.update(); - }; - - core.control._drawHero_updateViewport = function () { - core.control.updateViewport(); - } - - // 代理原本的镜头事件 - core.control.updateViewport = function () { - core.plugin.camera.requestCameraUpdate(); - }; - - // 更变楼层的行为追加,重置镜头 - core.events.changingFloor = function (floorId, heroLoc) { - this.eventdata.changingFloor(floorId, heroLoc); - core.plugin.camera.resetCamera(); - }; - - // 注册帧事件 - core.registerAnimationFrame('smoothCameraFlash', true, this.updateCameraEx.bind(this)); } } \ No newline at end of file diff --git a/runtime.d.ts b/runtime.d.ts index 6fb09a77..acb2cf43 100644 --- a/runtime.d.ts +++ b/runtime.d.ts @@ -149,8 +149,10 @@ type gameStatus = { thisMap: ResolvedMap bgmaps: { [key: string]: number[][] } fgmaps: { [key: string]: number[][] } + mapBlockObjs: { [key: string]: any } /** 显伤伤害 */ checkBlock: {} + damage: {} lockControl: boolean @@ -230,12 +232,7 @@ type gameStatus = { globalAnimateObjs: [] floorAnimateObjs: [] boxAnimateObjs: [] - autotileAnimateObjs: { - blocks: [], - map: any - bgmap: any - fgmap: null - } + autotileAnimateObjs: [] globalAnimateStatus: number animateObjs: [] } @@ -393,13 +390,16 @@ declare class control { nearHero(x: number, y: number, n?: number): boolean /** - * 更新地图显伤 + * 重算并绘制地图显伤 * @example core.updateDamage(); // 更新当前地图的显伤,绘制在显伤层(废话) * @param floorId 地图id,不填视为当前地图。预览地图时填写 * @param ctx 绘制到的画布,如果填写了就会画在该画布而不是显伤层 */ updateDamage(floorId?: string, ctx?: CanvasRenderingContext2D): void + /** 仅重绘地图显伤 */ + drawDamage(ctx?: CanvasRenderingContext2D): void + /** * 设置主角的某个属性 * @example core.setStatus('loc', {x : 0, y : 0, direction : 'up'}); // 设置主角位置为地图左上角,脸朝上 @@ -1410,7 +1410,10 @@ declare class maps { * @param showDisable 可选,true表示隐藏的图块也会被表示出来 * @returns 事件层矩阵,注意对其阵元的访问是[y][x] */ - getMapArray(floorId?: string): number[][] + getMapArray(floorId?: string, noCache?: boolean): number[][] + + /** 判定图块的事件层数字;不存在为0 */ + getMapNumber(floorId?: string, noCache?: boolean): number /** * 生成背景层矩阵 @@ -1454,12 +1457,9 @@ declare class maps { * 可通行性判定 * @example core.generateMovableArray(); // 判断当前地图主角从各点能向何方向移动 * @param floorId 地图id,不填视为当前地图 - * @param x 起点横坐标,不填视为挨个判定 - * @param y 起点纵坐标,不填视为挨个判定 - * @param direction 可选,必须和坐标一起使用。填写后将只检查是否可向该方向移动并返回布尔值 - * @returns 不设置坐标时为从各点可移动方向的三维数组,设置坐标但不设置方向时为该点可移动方向的一维数组,都设置时为布尔值 + * @returns 从各点可移动方向的三维数组 */ - generateMovableArray(floorId?: string, x?: number, y?: number, direction?: direction): boolean | Array>> + generateMovableArray(floorId?: string): Array>> /** * 单点单朝向的可通行性判定 @@ -1529,9 +1529,8 @@ declare class maps { * @param floorId 地图id,不填视为当前地图 * @param blocks 一般不需要 * @param options 额外的绘制项,可选。可以增绘主角位置和朝向、采用不同于游戏中的主角行走图、增绘显伤、提供flags用于存读档 - * @param toDraw 要绘制到的画布名或画布的ctx或还有其他信息,如起绘坐标、绘制大小、是否绘制全图、截取中心 */ - drawThumbnail(floorId?: string, blocks?: Block[], options?: object, toDraw?: string | CanvasRenderingContext2D | object): void + drawThumbnail(floorId?: string, blocks?: Block[], options?: object): void /** * 判定某个点是否不可被踏入(不基于主角生命值和图块cannotIn属性) @@ -1554,6 +1553,9 @@ declare class maps { */ getBlockId(x: number, y: number, floorId?: string, showDisable?: boolean): string | null + /** 判定某个点的图块数字;空图块为0 */ + getBlockNumber(x: number, y: number, floorId?: string, showDisable?: boolean): number + /** * 判定某个点的图块类型 * @example if(core.getBlockCls(x1, y1) != 'enemys' && core.getBlockCls(x2, y2) != 'enemy48') core.openDoor(x3, y3); // 另一个简单的机关门事件,打败或炸掉这一对不同身高的敌人就开门 @@ -1709,6 +1711,9 @@ declare class maps { loadFloor(floorId?: string, map?: any): any /** 根据需求解析出blocks */ + extractBlocks(map?: any): void + + /** 根据需求为UI解析出blocks */ extractBlocks(map?: any, flags?: any): void /** 根据数字获得图块 */ @@ -1721,7 +1726,7 @@ declare class maps { getIdOfThis(id?: string): string /** 初始化一个图块 */ - initBlock(x?: number, y?: number, id?: string | number, addInfo?: boolean, eventFloor?: any, flags?: any): any + initBlock(x?: number, y?: number, id?: string | number, addInfo?: boolean, eventFloor?: any): any /** 压缩地图 */ compressMap(mapArr?: any, floorId?: string): any @@ -1739,7 +1744,7 @@ declare class maps { resizeMap(floorId?: string): void /** 以x,y的形式返回每个点的事件 */ - getMapBlocksObj(floorId?: string, showDisable?: any): any + getMapBlocksObj(floorId?: string, noCache?: boolean): any /** 获得某些点可否通行的信息 */ canMoveDirectlyArray(locs?: any): any @@ -1766,7 +1771,7 @@ declare class maps { enemyExists(x?: number, y?: number, id?: string, floorId?: string): boolean /** 获得某个点的block */ - getBlock(x?: number, y?: number, floorId?: string, showDisable?: boolean): any + getBlock(x?: number, y?: number, floorId?: string, showDisable?: boolean): Block /** 获得某个图块或素材的信息,包括ID,cls,图片,坐标,faceIds等等 */ getBlockInfo(block?: any): any @@ -2372,6 +2377,9 @@ declare class utils { */ clone(data?: T, filter?: (name: string, value: any) => boolean, recursion?: boolean): T + /** 深拷贝一个1D或2D的数组 */ + cloneArray(data?: Array|Array>): Array|Array> + /** * 等比例切分一张图片 * @example core.splitImage(core.material.images.images['npc48.png'], 32, 48); // 把npc48.png切分成若干32×48px的小人 @@ -2748,9 +2756,16 @@ type core = { canvas: string[], offsetX: number // in pixel offsetY: number + posX: number + posY: number width: number // map width and height height: number + v2: boolean + threshold: number + extend: number + scale: number tempCanvas: CanvasRenderingContext2D // A temp canvas for drawing + cacheCanvas: CanvasRenderingContext2D } saves: { saveIndex: number