From 476bf7149077379712fae48d4d8a88f657fbe762 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 12 Mar 2019 23:29:26 +0800 Subject: [PATCH 001/153] Fix bugs: cannotEquip & heroMoving & hideBlock --- _docs/personalization.md | 4 +++- libs/items.js | 1 + libs/maps.js | 2 +- project/functions.js | 2 +- 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/_docs/personalization.md b/_docs/personalization.md index 51ca82d2..27276ef1 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -427,10 +427,12 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { ``` js ////// 点击楼层传送器时的打开操作 ////// control.prototype.useFly = function (need) { - if (!core.status.heroStop) { + if (!core.status.heroStop || core.status.heroMoving > 0) { core.drawTip("请先停止勇士行动"); return; } + if (core.status.lockControl || core.status.event.id != null) return; + if (core.canUseItem('fly')) core.useItem('fly'); else core.drawTip("当前无法使用"+core.material.items.fly.name); } diff --git a/libs/items.js b/libs/items.js index 1834cdb3..f38f8cb3 100644 --- a/libs/items.js +++ b/libs/items.js @@ -320,6 +320,7 @@ items.prototype.loadEquip = function (equipId, callback) { var type = this.getEquipTypeById(equipId); if (type < 0) { core.drawTip("当前没有"+loadEquip.equip.type+"的空位!"); + if (core.isset(callback)) callback(); return; } diff --git a/libs/maps.js b/libs/maps.js index c1fdd3b8..89050ff4 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1377,7 +1377,7 @@ maps.prototype.hideBlock = function (x, y, floorId) { core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); } - block.disable = true; + block.block.disable = true; core.updateStatusBar(); } diff --git a/project/functions.js b/project/functions.js index f0561da5..63fd72ee 100644 --- a/project/functions.js +++ b/project/functions.js @@ -745,7 +745,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 可以在这里任意增加或编辑每个按键的行为 // 如果处于正在行走状态,则不处理 - if (!core.status.heroStop) + if (!core.status.heroStop || core.status.heroMoving > 0) return; // Alt+0~9,快捷换上套装 From 2fce7d9d68262feeddbbf3b6315c641ab93214dc Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 14 Mar 2019 02:01:19 +0800 Subject: [PATCH 002/153] maps.js V2.6 --- _server/editor.js | 5 +- index.html | 2 +- libs/control.js | 8 +- libs/enemys.js | 4 +- libs/events.js | 8 +- libs/loader.js | 2 +- libs/maps.js | 808 ++++++++++++++++++++++++---------------------- libs/ui.js | 6 +- main.js | 5 +- 9 files changed, 439 insertions(+), 409 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index f77895f1..8af331c5 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -43,9 +43,6 @@ editor.info editor.prototype.init = function (callback) { var afterCoreReset = function () { - main.editor.disableGlobalAnimate = false;//允许GlobalAnimate - // core.setHeroMoveTriggerInterval(); - editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 editor.drawInitData(core.icons.icons); // 初始化绘图 @@ -302,7 +299,7 @@ editor.prototype.updateMap = function () { core.status.thisMap.blocks = blocks; var updateMap = function () { - core.removeGlobalAnimate(null, null, true); + core.removeGlobalAnimate(); core.clearMap('bg'); core.clearMap('event'); core.clearMap('event2'); diff --git a/index.html b/index.html index 8dde6626..afa4c129 100644 --- a/index.html +++ b/index.html @@ -152,6 +152,6 @@ - + \ No newline at end of file diff --git a/libs/control.js b/libs/control.js index a9296e4a..ffddf80f 100644 --- a/libs/control.js +++ b/libs/control.js @@ -139,7 +139,7 @@ control.prototype.setRequestAnimationFrame = function () { })(obj.callback); } else { - core.maps.drawAnimateFrame(obj.animate, obj.centerX, obj.centerY, obj.index++); + core.maps._drawAnimateFrame(obj.animate, obj.centerX, obj.centerY, obj.index++); animateObjs.push(obj); } } @@ -528,7 +528,7 @@ control.prototype.moveDirectly = function (destX, destY) { control.prototype.tryMoveDirectly = function (destX, destY) { if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1) return false; - var canMoveArray = core.maps._canMoveHero_generateArray(); + var canMoveArray = core.maps.generateMovableArray(); var testMove = function (dx, dy, dir) { if (dx<0 || dx>=core.bigmap.width|| dy<0 || dy>=core.bigmap.height) return false; if (core.isset(dir) && !core.inArray(canMoveArray[dx][dy],dir)) return false; @@ -653,7 +653,7 @@ control.prototype.automaticRoute = function (destX, destY) { }}); var ans = []; - var canMoveArray = core.maps._canMoveHero_generateArray(); + var canMoveArray = core.maps.generateMovableArray(); route[startX + fw * startY] = ''; queue.queue({depth: 0, x: startX, y: startY}); @@ -695,7 +695,7 @@ control.prototype.automaticRoute = function (destX, destY) { route[nid] = direction; break; } - if (core.noPassExists(nx, ny)) + if (core.noPass(nx, ny)) continue; route[nid] = direction; diff --git a/libs/enemys.js b/libs/enemys.js index f0fc4c7a..ba2ce156 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -25,11 +25,11 @@ enemys.prototype.hasSpecial = function (special, test) { if (!core.isset(special)) return false; if (special instanceof Array) { - return special.indexOf(test)>=0; + return special.indexOf(test) >= 0; } if (typeof special == 'number') { - return special!=0 && (special%100==test||this.hasSpecial(parseInt(special/100), test)); + return special === test; } if (typeof special == 'string') { diff --git a/libs/events.js b/libs/events.js index 5ed17252..e172a3a1 100644 --- a/libs/events.js +++ b/libs/events.js @@ -542,7 +542,7 @@ events.prototype.doAction = function() { if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.setFloorImage("show", data.loc, data.floorId, function() { + core.maps.showFloorImage(data.loc, data.floorId, function() { core.events.doAction(); }) break; @@ -552,7 +552,7 @@ events.prototype.doAction = function() { if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.setFloorImage("hide", data.loc, data.floorId, function() { + core.maps.hideFloorImage(data.loc, data.floorId, function() { core.events.doAction(); }) break; @@ -562,7 +562,7 @@ events.prototype.doAction = function() { if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.setBgFgMap("show", data.name, data.loc, data.floorId, function() { + core.maps.showBgFgMap(data.name, data.loc, data.floorId, function() { core.events.doAction(); }) break; @@ -572,7 +572,7 @@ events.prototype.doAction = function() { if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.setBgFgMap("hide", data.name, data.loc, data.floorId, function() { + core.maps.hideBgFgMap(data.name, data.loc, data.floorId, function() { core.events.doAction(); }) break; diff --git a/libs/loader.js b/libs/loader.js index 7fc1f393..337c199a 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -73,7 +73,7 @@ loader.prototype._loadAutotiles = function (callback) { }); setTimeout(function () { - core.maps.makeAutotileEdges(); + core.maps._makeAutotileEdges(); }); callback(); diff --git a/libs/maps.js b/libs/maps.js index 89050ff4..3246c96d 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -327,6 +327,7 @@ maps.prototype.getMapArray = function (blockArray, width, height, checkDisable) return blocks; } +////// 以x,y的形式返回每个点的事件 ////// maps.prototype.getMapBlocksObj = function (floorId, showDisable) { floorId = floorId || core.status.floorId; var obj = {}; @@ -337,7 +338,8 @@ maps.prototype.getMapBlocksObj = function (floorId, showDisable) { return obj; } -maps.prototype.getBgFgMapArray = function (floorId, name) { +////// 将背景前景层变成二维数组的形式 ////// +maps.prototype.getBgFgMapArray = function (name, floorId) { floorId = floorId||core.status.floorId; if (!core.isset(floorId)) return []; var width = core.floors[floorId].width; @@ -351,8 +353,10 @@ maps.prototype.getBgFgMapArray = function (floorId, name) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { arr[y] = arr[y] || []; - if (core.hasFlag(name + "_" + floorId + "_" + x + "_" + y)) arr[y][x] = 0; - else arr[y][x] = core.getFlag(name + "v_" + floorId + "_" + x + "_" + y, arr[y][x] || 0); + var flag = "__"+name+"Map__"+floorId+"_"+x+"_"+y; + var vFlag = "__"+name+"Value__"+floorId+"_"+x+"_"+y; + 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; } } @@ -364,21 +368,13 @@ maps.prototype.getBgFgMapArray = function (floorId, name) { // ------ canMoveHero & canMoveDirectly ------ // -////// 勇士能否前往某方向 ////// -maps.prototype.canMoveHero = function(x,y,direction,floorId) { - if (!core.isset(x)) x = core.getHeroLoc('x'); - if (!core.isset(y)) y = core.getHeroLoc('y'); - if (!core.isset(direction)) direction = core.getHeroLoc('direction'); - return core.inArray(this._canMoveHero_generateArray(floorId, x, y), direction); -} - ////// 生成全图的当前可移动信息 ////// -maps.prototype._canMoveHero_generateArray = function (floorId, x, y) { +maps.prototype.generateMovableArray = function (floorId, x, y) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return null; var width = core.floors[floorId].width, height = core.floors[floorId].height; - var bgArray = this.getBgFgMapArray(floorId, "bg"), - fgArray = this.getBgFgMapArray(floorId, "fg"), + var bgArray = this.getBgFgMapArray('bg', floorId), + fgArray = this.getBgFgMapArray('fg', floorId), eventArray = this.getMapArray(floorId); var generate = function (x, y) { @@ -400,6 +396,14 @@ maps.prototype._canMoveHero_generateArray = function (floorId, x, y) { return array; } +////// 勇士能否前往某方向 ////// +maps.prototype.canMoveHero = function(x,y,direction,floorId) { + if (!core.isset(x)) x = core.getHeroLoc('x'); + if (!core.isset(y)) y = core.getHeroLoc('y'); + if (!core.isset(direction)) direction = core.getHeroLoc('direction'); + return core.inArray(this.generateMovableArray(floorId, x, y), direction); +} + maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, extraData) { // 1. 检查该点 cannotMove if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction)) @@ -477,7 +481,7 @@ maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) { } maps.prototype._canMoveDirectly_bfs = function (sx, sy, ex, ey) { - var canMoveArray = this._canMoveHero_generateArray(); + var canMoveArray = this.generateMovableArray(); var blocksObj = this.getMapBlocksObj(core.status.floorId); var visited=[], queue=[]; @@ -514,44 +518,7 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { // -------- Draw block, map, autotile, ... -------- // -// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 -maps.prototype.getBlockInfo = function (block) { - if (!core.isset(block)) return null; - if (typeof block == 'string') { // 参数是ID - block = this.getNumberById(block); - } - if (typeof block == 'number') { // 参数是数字 - if (block == 0) return null; - block = this.initBlock(0, 0, block, true); - } - if (!core.isset(block.event)) return null; - var id = block.event.id, cls = block.event.cls, image = null, posX = 0, posY = 0, - height = block.event.height || 32, faceIds = {}; - - if (id == 'none') return null; - else if (id == 'airwall') { - if (!core.isset(core.material.images.airwall)) return null; - image = core.material.images.airwall; - } - else if (cls == 'tileset') { - var offset = core.icons.getTilesetOffset(id); - if (offset == null) return null; - posX = offset.x; - posY = offset.y; - image = core.material.images.tilesets[offset.image]; - } - else if (cls == 'autotile') { - image = core.material.images.autotile[id]; - } - else { - image = core.material.images[cls]; - posY = core.material.icons[cls][id]; - faceIds = block.event.faceIds||{}; - } - - return {id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; -} - +////// 绘制一个图块 ////// maps.prototype.drawBlock = function (block, animate, dx, dy) { if (block.event.id == 'none') return; animate = animate || 0; @@ -599,46 +566,6 @@ maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y) { core.drawImage(name, image, posX * 32, posY * height, 32, height, x * 32, y * 32 + 32 - height, 32, height); } -////// 背景/前景图块的绘制 ////// -maps.prototype.drawBgFgMap = function (floorId, ctx, name, onMap) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - var width = core.floors[floorId].width; - var height = core.floors[floorId].height; - - if (!core.isset(core.status[name+"maps"])) - core.status[name+"maps"] = {}; - - var arr = this.getBgFgMapArray(floorId, name); - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - var block = this.initBlock(x, y, arr[y][x], true); - if (!core.isset(block.event)) continue; - block.name = name; - var blockInfo = this.getBlockInfo(block); - if (!core.isset(blockInfo)) continue; - this._drawBgFgMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); - } - } - if (onMap) - core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); -} - -maps.prototype._drawBgFgMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { - if (blockInfo.cls == 'autotile') { // Autotile单独处理 - this.drawAutotile(ctx, arr, block, 32, 0, 0); - if (onMap) core.addAutotileGlobalAnimate(block); - return; - } - if (!onMap) { - var height = blockInfo.height; - core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); - return; - } - this.drawBlock(block); - this.addGlobalAnimate(block); -} - ////// 生成groundPattern ////// maps.prototype.generateGroundPattern = function (floorId) { // 生成floorId层的groundPattern(盒子内的怪物动画) @@ -662,6 +589,7 @@ maps.prototype._getFloorImages = function (floorId) { return images; } +////// 绘制楼层贴图 ////// maps.prototype.drawFloorImages = function (floorId, ctx, name, images, animate) { floorId = floorId || core.status.floorId; if (!core.isset(images)) images = this._getFloorImages(floorId); @@ -674,7 +602,7 @@ maps.prototype.drawFloorImages = function (floorId, ctx, name, images, animate) if (redraw && frame == 1) return; // 不重绘 if (core.isset(dx) && core.isset(dy) && core.isset(image) && - !core.hasFlag("floorimg_"+floorId+"@"+dx+"@"+dy)) { + !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy)) { var width = parseInt(image.width / frame), offsetX = (animate||0)%frame*width; if (/.*\.gif/i.test(imageName) && main.mode=='play') { if (redraw) return; // 忽略gif @@ -779,6 +707,7 @@ maps.prototype._drawMap_drawBgFg = function (floorId) { this.drawFg(floorId); } +////// 绘制背景层 ////// maps.prototype.drawBg = function (floorId, ctx) { var onMap = !core.isset(ctx); if (onMap) { @@ -795,6 +724,7 @@ maps.prototype.drawBg = function (floorId, ctx) { this._drawBg_drawContent(floorId, ctx, onMap); } +////// 绘制前景层 ////// maps.prototype.drawFg = function (floorId, ctx) { var onMap = !core.isset(ctx); if (onMap) ctx = core.canvas.fg; @@ -815,6 +745,46 @@ maps.prototype._drawFg_drawContent = function (floorId, ctx, onMap) { this.drawBgFgMap(floorId, ctx, 'fg', onMap); } +////// 背景/前景图块的绘制 ////// +maps.prototype.drawBgFgMap = function (floorId, ctx, name, onMap) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; + + if (!core.isset(core.status[name+"maps"])) + core.status[name+"maps"] = {}; + + var arr = this.getBgFgMapArray(name, floorId); + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + var block = this.initBlock(x, y, arr[y][x], true); + if (!core.isset(block.event)) continue; + block.name = name; + var blockInfo = this.getBlockInfo(block); + if (!core.isset(blockInfo)) continue; + this._drawBgFgMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); + } + } + if (onMap) + core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); +} + +maps.prototype._drawBgFgMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { + if (blockInfo.cls == 'autotile') { // Autotile单独处理 + this.drawAutotile(ctx, arr, block, 32, 0, 0); + if (onMap) core.addAutotileGlobalAnimate(block); + return; + } + if (!onMap) { + var height = blockInfo.height; + core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); + return; + } + this.drawBlock(block); + this.addGlobalAnimate(block); +} + ////// 绘制Autotile ////// maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, status){ var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 @@ -837,43 +807,9 @@ maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, stat [34, 33, 28, 27] //15 bin:1111 +----+----+----+----+----+----+ ]; - var drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size){ //index为autotile的图块索引1-48 - var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6)); - status = status || 0; - status %= parseInt(autotileImg.width/96); - ctx.drawImage(autotileImg, sx + 96*status, sy, 16, 16, dx, dy, size/2, size/2); - } - var getAutotileAroundId = function(currId, x, y) { - 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; - } - var checkAround = function(x, y){ // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引 - var currId = mapArr[y][x]; - var pointBlock = []; - for(var i=0; i<4; i++){ - var bsum = 0; - var offsetx = i%2, offsety = ~~(i/2); - for(var j=0; j<4; j++){ - var mx = j%2, my = ~~(j/2); - var b = getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1); - bsum += b*(Math.pow(2, 3-j)); - } - pointBlock.push(bsum); - } - return pointBlock; - } - var getAutotileIndexs = function(x, y){ - var indexArr = []; - var pointBlocks = checkAround(x, y); - for(var i=0; i<4; i++){ - var arr = indexArrs[pointBlocks[i]] - indexArr.push(arr[3-i]); - } - return indexArr; - } // 开始绘制autotile var x = block.x, y = block.y; - var pieceIndexs = getAutotileIndexs(x, y); + var pieceIndexs = this._drawAutotile_getAutotileIndexs(x, y, mapArr, indexArrs); //修正四个边角的固定搭配 if(pieceIndexs[0] == 13){ @@ -895,12 +831,52 @@ maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, stat for(var i=0; i<4; i++){ var index = pieceIndexs[i]; var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2)); - drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size); + this._drawAutotile_drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size, status); } } +maps.prototype._drawAutotile_drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size, status) { + //index为autotile的图块索引1-48 + var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6)); + status = status || 0; + status %= parseInt(autotileImg.width/96); + ctx.drawImage(autotileImg, sx + 96*status, sy, 16, 16, dx, dy, size/2, size/2); +} + +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; +} + +maps.prototype._drawAutotile_checkAround = function(x, y, mapArr){ + // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引 + var currId = mapArr[y][x]; + var pointBlock = []; + for(var i=0; i<4; i++){ + var bsum = 0; + var offsetx = i%2, offsety = ~~(i/2); + for(var j=0; j<4; j++){ + var mx = j%2, my = ~~(j/2); + var b = this._drawAutotile_getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1, mapArr); + bsum += b*(Math.pow(2, 3-j)); + } + pointBlock.push(bsum); + } + return pointBlock; +} + +maps.prototype._drawAutotile_getAutotileIndexs = function(x, y, mapArr, indexArrs){ + var indexArr = []; + var pointBlocks = this._drawAutotile_checkAround(x, y, mapArr); + for(var i=0; i<4; i++){ + var arr = indexArrs[pointBlocks[i]] + indexArr.push(arr[3-i]); + } + return indexArr; +} + ////// 为autotile判定边界 ////// -maps.prototype.makeAutotileEdges = function () { +maps.prototype._makeAutotileEdges = function () { var autotileIds = Object.keys(core.material.images.autotile); core.material.autotileEdges = {}; @@ -932,18 +908,15 @@ maps.prototype.makeAutotileEdges = function () { }); } +// -------- xxxExists, get & set block ... -------- // + ////// 某个点是否不可通行 ////// -maps.prototype.noPassExists = function (x, y, floorId) { +maps.prototype.noPass = function (x, y, floorId) { var block = core.getBlock(x,y,floorId); if (block==null) return false; return core.isset(block.block.event.noPass) && block.block.event.noPass; } -////// 某个点是否在区域内且不可通行 ////// -maps.prototype.noPass = function (x, y) { - return x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height || this.noPassExists(x,y); -} - ////// 某个点是否存在NPC ////// maps.prototype.npcExists = function (x, y, floorId) { var block = this.getBlock(x,y,floorId); @@ -1008,6 +981,284 @@ maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { return null; } +////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 ////// +maps.prototype.getBlockInfo = function (block) { + if (!core.isset(block)) return null; + if (typeof block == 'string') { // 参数是ID + block = this.getNumberById(block); + } + if (typeof block == 'number') { // 参数是数字 + if (block == 0) return null; + block = this.initBlock(0, 0, block, true); + } + if (!core.isset(block.event)) return null; + var id = block.event.id, cls = block.event.cls, image = null, posX = 0, posY = 0, + height = block.event.height || 32, faceIds = {}; + + if (id == 'none') return null; + else if (id == 'airwall') { + if (!core.isset(core.material.images.airwall)) return null; + image = core.material.images.airwall; + } + else if (cls == 'tileset') { + var offset = core.icons.getTilesetOffset(id); + if (offset == null) return null; + posX = offset.x; + posY = offset.y; + image = core.material.images.tilesets[offset.image]; + } + else if (cls == 'autotile') { + image = core.material.images.autotile[id]; + } + else { + image = core.material.images[cls]; + posY = core.material.icons[cls][id]; + faceIds = block.event.faceIds||{}; + } + + return {id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; +} + +////// 将某个块从禁用变成启用状态 ////// +maps.prototype.showBlock = function(x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + var block = core.getBlock(x,y,floorId,true); + if (block==null) return; // 不存在 + block=block.block; + // 本身是禁用事件,启用之 + if (block.disable) { + block.disable = false; + // 在本层,添加动画 + if (floorId == core.status.floorId && core.isset(block.event)) { + core.drawBlock(block); + core.addGlobalAnimate(block); + } + core.updateStatusBar(); + } +} + +////// 只隐藏但不删除某块 ////// +maps.prototype.hideBlock = function (x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + + var block = core.getBlock(x,y,floorId,true); + if (block==null) return; // 不存在 + + // 删除动画,清除地图 + if (floorId==core.status.floorId) { + core.removeGlobalAnimate(x, y); + core.clearMap('event', x * 32, y * 32, 32, 32); + var height = 32; + if (core.isset(block.block.event)) height=block.block.event.height||32; + if (height>32) + core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + } + + block.block.disable = true; + core.updateStatusBar(); +} + +////// 将某个块从启用变成禁用状态 ////// +maps.prototype.removeBlock = function (x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + + var block = core.getBlock(x,y,floorId,true); + if (block==null) return; // 不存在 + + var index=block.index; + + // 删除动画,清除地图 + if (floorId==core.status.floorId) { + core.removeGlobalAnimate(x, y); + core.clearMap('event', x * 32, y * 32, 32, 32); + var height = 32; + if (core.isset(block.block.event)) height=block.block.event.height||32; + if (height>32) + core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + } + + // 删除Index + core.removeBlockById(index, floorId); + core.updateStatusBar(); +} + +////// 根据block的索引(尽可能)删除该块 ////// +maps.prototype.removeBlockById = function (index, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + + var blocks = core.status.maps[floorId].blocks, block = blocks[index]; + + if (this.canRemoveBlock(block, floorId)) { // 能否彻底删除该图块 + blocks.splice(index,1); + } + else { + block.disable = true; + } +} + +////// 能否彻底从地图中删除一个图块 ////// +maps.prototype.canRemoveBlock = function (block, floorId) { + var x=block.x, y=block.y; + // 检查该点是否存在事件 + if (core.floors[floorId].events[x+","+y] || core.floors[floorId].changeFloor[x+","+y]) + return false; + // 检查是否存在重生 + if (block.event && block.event.cls.indexOf('enemy')==0 && core.hasSpecial(block.event.id, 23)) + return false; + + return true; +} + +////// 一次性删除多个block ////// +maps.prototype.removeBlockByIds = function (floorId, ids) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + ids.sort(function (a,b) {return b-a}).forEach(function (id) { + core.removeBlockById(id, floorId); + }); +} + +////// 显示前景/背景地图 ////// +maps.prototype.showBgFgMap = function (name, loc, floorId, callback) { + this._triggerBgFgMap('show', name, loc, floorId, callback); +} + +////// 隐藏前景/背景地图 ////// +maps.prototype.hideBgFgMap = function (name, loc, floorId, callback) { + this._triggerBgFgMap('hide', name, loc, floorId, callback); +} + +////// 设置前景/背景地图的显示状态 ////// +maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) { + if (type!='show') type='hide'; + if (name!='fg') name='bg'; + if (typeof loc[0] == 'number' && typeof loc[1] == 'number') + loc = [loc]; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + + if (loc.length==0) return; + loc.forEach(function (t) { + var x=t[0], y=t[1]; + var flag = "__"+name+"Map__"+floorId+"_"+x+"_"+y; + 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 (core.isset(callback)) callback(); + } +} + +////// 显示一个楼层贴图 ////// +maps.prototype.showFloorImage = function (loc, floorId, callback) { + this._triggerFloorImage('show', loc, floorId, callback); +} + +////// 隐藏一个楼层贴图 ////// +maps.prototype.hideFloorImage = function (loc, floorId, callback) { + this._triggerFloorImage('hide', loc, floorId, callback); +} + +///// 设置贴图显示状态 ////// +maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) { + if (type!='show') type='hide'; + if (typeof loc[0] == 'number' && typeof loc[1] == 'number') + loc = [loc]; + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + + if (loc.length==0) return; + loc.forEach(function (t) { + var x=t[0], y=t[1]; + var flag = "__floorImg__"+floorId+"_"+x+"_"+y; + if (type == 'hide') core.setFlag(flag, true); + else core.removeFlag(flag); + }) + + if (floorId==core.status.floorId) { + core.drawMap(floorId, callback); + } + else { + if (core.isset(callback)) callback(); + } +} + +////// 改变图块 ////// +maps.prototype.setBlock = function (number, x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; + if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; + + var originBlock=core.getBlock(x,y,floorId,true); + var block = this.initBlock(x,y,number,true,core.floors[floorId]); + if (core.isset(block.event)) { + if (floorId == core.status.floorId) { + core.removeGlobalAnimate(x, y); + core.clearMap('event', x * 32, y * 32, 32, 32); + if (originBlock != null) { + var height = (originBlock.block.event||{}).height||32; + if (height>32) + core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + } + } + if (originBlock==null) { + core.status.maps[floorId].blocks.push(block); + } + else { + originBlock.block.id = number; + originBlock.block.event = block.event; + block = originBlock.block; + } + if (floorId==core.status.floorId && !block.disable) { + core.drawBlock(block); + core.addGlobalAnimate(block); + core.updateStatusBar(); + } + } +} + +////// 改变前景背景的图块 ////// +maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; + if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; + if (name!='bg' && name!='fg') return; + + var vFlag = "__"+name+"Value__"+floorId+"_"+x+"_"+y; + core.setFlag(vFlag, number); + core.status[name+"maps"][floorId] = null; + + if (floorId == core.status.floorId) + core.drawMap(floorId); +} + +////// 重置地图 ////// +maps.prototype.resetMap = function(floorId) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + if (typeof floorId == 'string') floorId = [floorId]; + var needRefresh = false; + floorId.forEach(function (t) { + core.status.maps[t] = core.maps.loadFloor(t); + if (t == core.status.floorId) needRefresh = true; + }); + if (needRefresh) this.drawMap(); + core.drawTip("地图重置成功"); +} + +// -------- moveBlock, Animate ... -------- // + maps.prototype.__moveBlockCanvas = function (image, bx, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas) { // 重绘block & 重定位 if (headCanvas != null) { @@ -1340,168 +1591,14 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { core.animateFrame.asyncId[animate] = true; } -////// 将某个块从禁用变成启用状态 ////// -maps.prototype.showBlock = function(x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - var block = core.getBlock(x,y,floorId,true); - if (block==null) return; // 不存在 - block=block.block; - // 本身是禁用事件,启用之 - if (block.disable) { - block.disable = false; - // 在本层,添加动画 - if (floorId == core.status.floorId && core.isset(block.event)) { - core.drawBlock(block); - core.addGlobalAnimate(block); - } - core.updateStatusBar(); - } -} - -////// 只隐藏但不删除某块 ////// -maps.prototype.hideBlock = function (x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - - var block = core.getBlock(x,y,floorId,true); - if (block==null) return; // 不存在 - - // 删除动画,清除地图 - if (floorId==core.status.floorId) { - core.removeGlobalAnimate(x, y); - core.clearMap('event', x * 32, y * 32, 32, 32); - var height = 32; - if (core.isset(block.block.event)) height=block.block.event.height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); - } - - block.block.disable = true; - core.updateStatusBar(); -} - -////// 将某个块从启用变成禁用状态 ////// -maps.prototype.removeBlock = function (x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - - var block = core.getBlock(x,y,floorId,true); - if (block==null) return; // 不存在 - - var index=block.index; - - // 删除动画,清除地图 - if (floorId==core.status.floorId) { - core.removeGlobalAnimate(x, y); - core.clearMap('event', x * 32, y * 32, 32, 32); - var height = 32; - if (core.isset(block.block.event)) height=block.block.event.height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); - } - - // 删除Index - core.removeBlockById(index, floorId); - core.updateStatusBar(); -} - -////// 根据block的索引删除该块 ////// -maps.prototype.removeBlockById = function (index, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - - var blocks = core.status.maps[floorId].blocks, block = blocks[index]; - var x=block.x, y=block.y; - - // 检查该点是否存在事件 - var event = core.floors[floorId].events[x+","+y]; - if (!core.isset(event)) - event = core.floors[floorId].changeFloor[x+","+y]; - - // 检查是否存在重生 - var isReborn = false; - if (core.isset(block.event) && block.event.cls.indexOf('enemy')==0 - && core.enemys.hasSpecial(core.material.enemys[block.event.id].special, 23)) - isReborn = true; - - // 不存在事件,直接删除 - if (!isReborn && !core.isset(event)) { - blocks.splice(index,1); - return; - } - block.disable = true; -} - -////// 一次性删除多个block ////// -maps.prototype.removeBlockByIds = function (floorId, ids) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - ids.sort(function (a,b) {return b-a}).forEach(function (id) { - core.removeBlockById(id, floorId); - }); -} - -////// 改变图块 ////// -maps.prototype.setBlock = function (number, x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; - - var originBlock=core.getBlock(x,y,floorId,true); - var block = core.maps.initBlock(x,y,number,true,core.floors[floorId]); - if (core.isset(block.event)) { - if (floorId == core.status.floorId) { - core.removeGlobalAnimate(x, y); - core.clearMap('event', x * 32, y * 32, 32, 32); - if (originBlock != null) { - var height = (originBlock.block.event||{}).height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); - } - } - if (originBlock==null) { - core.status.maps[floorId].blocks.push(block); - } - else { - originBlock.block.id = number; - originBlock.block.event = block.event; - block = originBlock.block; - } - if (floorId==core.status.floorId && !block.disable) { - core.drawBlock(block); - core.addGlobalAnimate(block); - core.updateStatusBar(); - } - } -} - -////// 改变图层块 ////// -maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; - if (name!='bg' && name!='fg') return; - - core.setFlag(name+"v_"+floorId+"_"+x+"_"+y, number); - core.status[name+"maps"][floorId] = null; - - if (floorId == core.status.floorId) - core.drawMap(floorId); -} - ////// 添加一个全局动画 ////// maps.prototype.addGlobalAnimate = function (b) { - if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; if (!core.isset(b.event) || !core.isset(b.event.animate) || b.event.animate==1) return; core.status.globalAnimateObjs.push(b); } ////// 添加一个Autotile全局动画 ////// maps.prototype.addAutotileGlobalAnimate = function (b) { - if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; if (!core.isset(b.event) || b.event.cls!='autotile') return; var id = b.event.id, img = core.material.images.autotile[id]; if (!core.isset(img) || img.width==96) return; @@ -1509,10 +1606,9 @@ maps.prototype.addAutotileGlobalAnimate = function (b) { } ////// 删除一个或所有全局动画 ////// -maps.prototype.removeGlobalAnimate = function (x, y, all, name) { - if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; - - if (all) { +maps.prototype.removeGlobalAnimate = function (x, y, name) { + // 没有定义xy,则全部删除 + if (!core.isset(x) || !core.isset(y)) { core.status.globalAnimateStatus = 0; core.status.globalAnimateObjs = []; core.status.autotileAnimateObjs = {"blocks": [], "map": null, "bgmap": null, "fgmap": null}; @@ -1531,8 +1627,7 @@ maps.prototype.removeGlobalAnimate = function (x, y, all, name) { } ////// 设置全局动画的显示效果 ////// -maps.prototype.setGlobalAnimate = function (speed) { - if (main.mode=='editor' && main.editor.disableGlobalAnimate) return; +maps.prototype.setGlobalAnimate = function () { core.status.globalAnimateStatus = 0; core.animateFrame.globalAnimate = true; } @@ -1547,36 +1642,6 @@ maps.prototype.drawBoxAnimate = function () { }); } -////// 绘制动画的某一帧 ////// -maps.prototype.drawAnimateFrame = function (animate, centerX, centerY, index) { - var frame = animate.frames[index]; - var ratio = animate.ratio; - frame.forEach(function (t) { - var image = animate.images[t.index]; - if (!core.isset(image)) return; - var realWidth = image.width * ratio * t.zoom / 100; - var realHeight = image.height * ratio * t.zoom / 100; - core.setAlpha('animate', t.opacity / 255); - - var cx = centerX+t.x, cy=centerY+t.y; - - if (!t.mirror && !t.angle) { - core.drawImage('animate', image, cx-realWidth/2 - core.bigmap.offsetX, cy-realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); - } - else { - core.saveCanvas('animate'); - core.canvas.animate.translate(cx,cy); - if (t.angle) - core.canvas.animate.rotate(-t.angle*Math.PI/180); - if (t.mirror) - core.canvas.animate.scale(-1,1); - core.drawImage('animate', image, -realWidth/2 - core.bigmap.offsetX, -realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); - core.loadCanvas('animate'); - } - core.setAlpha('animate', 1); - }) -} - ////// 绘制动画 ////// maps.prototype.drawAnimate = function (name, x, y, callback) { @@ -1611,6 +1676,36 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { return animateId; } +////// 绘制动画的某一帧 ////// +maps.prototype._drawAnimateFrame = function (animate, centerX, centerY, index) { + var frame = animate.frames[index]; + var ratio = animate.ratio; + frame.forEach(function (t) { + var image = animate.images[t.index]; + if (!core.isset(image)) return; + var realWidth = image.width * ratio * t.zoom / 100; + var realHeight = image.height * ratio * t.zoom / 100; + core.setAlpha('animate', t.opacity / 255); + + var cx = centerX+t.x, cy=centerY+t.y; + + if (!t.mirror && !t.angle) { + core.drawImage('animate', image, cx-realWidth/2 - core.bigmap.offsetX, cy-realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); + } + else { + core.saveCanvas('animate'); + core.canvas.animate.translate(cx,cy); + if (t.angle) + core.canvas.animate.rotate(-t.angle*Math.PI/180); + if (t.mirror) + core.canvas.animate.scale(-1,1); + core.drawImage('animate', image, -realWidth/2 - core.bigmap.offsetX, -realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); + core.loadCanvas('animate'); + } + core.setAlpha('animate', 1); + }) +} + ////// 停止动画 ////// maps.prototype.stopAnimate = function (id, doCallback) { for (var i=0;i Date: Thu, 14 Mar 2019 04:15:11 +0800 Subject: [PATCH 003/153] maps.js V2.6 --- _server/editor.js | 1 - libs/control.js | 2 +- libs/events.js | 2 +- libs/maps.js | 527 ++++++++++++++++++++-------------------------- libs/utils.js | 20 ++ 5 files changed, 252 insertions(+), 300 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index 8af331c5..a15a967b 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -306,7 +306,6 @@ editor.prototype.updateMap = function () { core.clearMap('fg'); core.maps._drawMap_drawBgFg(); core.maps._drawMap_drawEvent(); - core.setGlobalAnimate(core.values.animateSpeed); } updateMap(); diff --git a/libs/control.js b/libs/control.js index ffddf80f..c7b6d0fd 100644 --- a/libs/control.js +++ b/libs/control.js @@ -64,7 +64,7 @@ control.prototype.setRequestAnimationFrame = function () { core.status.globalAnimateStatus++; - if (core.animateFrame.globalAnimate && core.isset(core.status.floorId)) { + if (core.isset(core.status.floorId)) { // Global Animate core.status.globalAnimateObjs.forEach(function (block) { core.drawBlock(block, core.status.globalAnimateStatus % (block.event.animate||1)); diff --git a/libs/events.js b/libs/events.js index e172a3a1..8ddde54e 100644 --- a/libs/events.js +++ b/libs/events.js @@ -63,7 +63,7 @@ events.prototype._init = function () { var dir = {"up":"down","down":"up","left":"right","right":"left"}[core.getHeroLoc('direction')]; var id = data.event.id, toId = (data.event.faceIds||{})[dir]; if (core.isset(toId) && id!=toId) { - var number = core.maps.getNumberById(toId); + var number = core.icons.getNumberById(toId); if (number>0) core.setBlock(number, ex, ey); } diff --git a/libs/maps.js b/libs/maps.js index 3246c96d..9743be79 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -24,7 +24,7 @@ maps.prototype._setFloorSize = function (floorId) { core.floors[floorId].height = core.floors[floorId].height || this.DEFAULT_HEIGHT; } -// ------ 加载与存档读档 ------ // +// ------ 加载地图与地图的存档读档(压缩与解压缩) ------ // ////// 加载某个楼层(从剧本或存档中) ////// maps.prototype.loadFloor = function (floorId, map) { @@ -267,6 +267,18 @@ maps.prototype._compressFloorData = function (map, floor) { return thisFloor; } +////// 将存档中的地图信息重新读取出来 ////// +maps.prototype.loadMap = function (data, floorId) { + if (!core.isset(floorId)) { + var map = {}; + core.floorIds.forEach(function (id) { + map[id] = core.maps.loadFloor(id, data[id]); + }) + return map; + } + return this.loadFloor(floorId, data[floorId]); +} + ////// 更改地图画布的尺寸 maps.prototype.resizeMap = function(floorId) { floorId = floorId || core.status.floorId; @@ -287,18 +299,6 @@ maps.prototype.resizeMap = function(floorId) { }); } -////// 将存档中的地图信息重新读取出来 ////// -maps.prototype.loadMap = function (data, floorId) { - if (!core.isset(floorId)) { - var map = {}; - core.floorIds.forEach(function (id) { - map[id] = core.maps.loadFloor(id, data[id]); - }) - return map; - } - return this.loadFloor(floorId, data[floorId]); -} - ////// 将当前地图重新变成二维数组形式 ////// maps.prototype.getMapArray = function (blockArray, width, height, checkDisable) { if (typeof blockArray == 'string') { @@ -364,9 +364,7 @@ maps.prototype.getBgFgMapArray = function (name, floorId) { return arr; } -// ------ 地图处理 ------ // - -// ------ canMoveHero & canMoveDirectly ------ // +// ------ 当前能否朝某方向移动,能否瞬间移动 ------ // ////// 生成全图的当前可移动信息 ////// maps.prototype.generateMovableArray = function (floorId, x, y) { @@ -516,7 +514,7 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { return true; } -// -------- Draw block, map, autotile, ... -------- // +// -------- 绘制地图,各层图块,楼层贴图,Autotile -------- // ////// 绘制一个图块 ////// maps.prototype.drawBlock = function (block, animate, dx, dy) { @@ -672,7 +670,6 @@ maps.prototype.drawMap = function (floorId, callback) { core.fillRect('curtain', 0, 0, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, core.arrayToRGBA(core.status.curtainColor)); } - core.setGlobalAnimate(core.values.animateSpeed); core.drawHero(); core.updateStatusBar(); if (core.isset(callback)) @@ -690,12 +687,11 @@ maps.prototype._drawMap_drawEvent = function (floorId) { if (core.isset(block.event) && !block.disable) { if (block.event.cls == 'autotile') { core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); - core.addAutotileGlobalAnimate(block); } else { core.drawBlock(block); - core.addGlobalAnimate(block); } + core.addGlobalAnimate(block); } } core.status.autotileAnimateObjs.map = core.clone(mapArray); @@ -773,7 +769,7 @@ maps.prototype.drawBgFgMap = function (floorId, ctx, name, onMap) { maps.prototype._drawBgFgMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { if (blockInfo.cls == 'autotile') { // Autotile单独处理 this.drawAutotile(ctx, arr, block, 32, 0, 0); - if (onMap) core.addAutotileGlobalAnimate(block); + if (onMap) this.addGlobalAnimate(block); return; } if (!onMap) { @@ -908,7 +904,7 @@ maps.prototype._makeAutotileEdges = function () { }); } -// -------- xxxExists, get & set block ... -------- // +// -------- 获得某个点的图块信息 -------- // ////// 某个点是否不可通行 ////// maps.prototype.noPass = function (x, y, floorId) { @@ -992,7 +988,8 @@ maps.prototype.getBlockInfo = function (block) { block = this.initBlock(0, 0, block, true); } if (!core.isset(block.event)) return null; - var id = block.event.id, cls = block.event.cls, image = null, posX = 0, posY = 0, + var number = block.id, id = block.event.id, cls = block.event.cls, + image = null, posX = 0, posY = 0, height = block.event.height || 32, faceIds = {}; if (id == 'none') return null; @@ -1016,9 +1013,11 @@ maps.prototype.getBlockInfo = function (block) { faceIds = block.event.faceIds||{}; } - return {id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; + return {number:number, id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; } +// -------- 启用/禁用图块,楼层贴图 -------- // + ////// 将某个块从禁用变成启用状态 ////// maps.prototype.showBlock = function(x, y, floorId) { floorId = floorId || core.status.floorId; @@ -1257,51 +1256,32 @@ maps.prototype.resetMap = function(floorId) { core.drawTip("地图重置成功"); } -// -------- moveBlock, Animate ... -------- // +// -------- 移动/跳跃图块,图块的淡入淡出 -------- // -maps.prototype.__moveBlockCanvas = function (image, bx, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas) { - // 重绘block & 重定位 - if (headCanvas != null) { - core.dymCanvas[headCanvas].clearRect(0, 0, 32, height); - core.dymCanvas[headCanvas].drawImage(image, bx * 32, by * height, 32, height - 32, 0, 0, 32, height - 32); - core.relocateCanvas(headCanvas, nowX - core.bigmap.offsetX, nowY+32-height - core.bigmap.offsetY); - core.setOpacity(headCanvas, opacity); +////// 初始化独立的block canvas ////// +maps.prototype._initDetachedBlock = function (blockInfo, x, y, displayDamage) { + var headCanvas = null, bodyCanvas = '__body_'+x+"_"+y, damageCanvas = null; + // head + if (blockInfo.height > 32) { + headCanvas = "__head_"+x+"_"+y; + core.createCanvas(headCanvas, 0, 0, 32, blockInfo.height - 32, 55); } - if (bodyCanvas != null) { - core.dymCanvas[bodyCanvas].clearRect(0, 0, 32, 32); - core.dymCanvas[bodyCanvas].drawImage(image, bx * 32, by * height + height - 32, 32, 32, 0, 0, 32, 32); - core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); - core.setOpacity(bodyCanvas, opacity); - } - if (damageCanvas != null) { - core.relocateCanvas(damageCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); - core.setOpacity(damageCanvas, opacity); - } -} - -maps.prototype.__initBlockCanvas = function (block, height, x, y) { - var headCanvas = null, bodyCanvas = 'block'+x+"_"+y, damageCanvas = null; - + // body core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35); - if (height > 32) { - headCanvas = "blockHead"+x+"_"+y; - core.createCanvas(headCanvas, 0, 0, 32, height - 32, 55); - } - // 显伤 + // damage var damage = null, damageColor = null; - if ((block.event.cls == 'enemys' || block.event.cls == 'enemy48') && core.hasItem('book') - && block.event.displayDamage !== false) { - var damageString = core.enemys.getDamageString(block.event.id, x, y); + if (blockInfo.cls.indexOf('enemy')==0 && core.hasItem('book') && displayDamage) { + var damageString = core.enemys.getDamageString(blockInfo.id, x, y); damage = damageString.damage; damageColor = damageString.color; } if (damage != null) { - damageCanvas = "blockDamage"+x+"_"+y; + damageCanvas = "__damage_"+x+"_"+y; var ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); ctx.textAlign = 'left'; ctx.font = "bold 11px Arial"; core.fillBoldText(ctx, damage, 1, 31, damageColor); if (core.flags.displayCritical) { - var critical = core.enemys.nextCriticals(block.event.id); + var critical = core.enemys.nextCriticals(blockInfo.id); if (critical.length>0) critical=critical[0]; critical = core.formatBigNumber(critical[0], true); if (critical == '???') critical = '?'; @@ -1315,216 +1295,215 @@ maps.prototype.__initBlockCanvas = function (block, height, x, y) { } } +////// 移动独立的block canvas ////// +maps.prototype._moveDetachedBlock = function (blockInfo, nowX, nowY, opacity, canvases) { + var height = blockInfo.height, posX = blockInfo.posX, posY = blockInfo.posY, image = blockInfo.image; + var headCanvas = canvases.headCanvas, bodyCanvas = canvases.bodyCanvas, damageCanvas = canvases.damageCanvas; + if (headCanvas) { + core.dymCanvas[headCanvas].clearRect(0, 0, 32, height); + core.dymCanvas[headCanvas].drawImage(image, posX * 32, posY * height, 32, height - 32, 0, 0, 32, height - 32); + core.relocateCanvas(headCanvas, nowX - core.bigmap.offsetX, nowY + 32 - height - core.bigmap.offsetY); + core.setOpacity(headCanvas, opacity); + } + if (bodyCanvas) { + core.dymCanvas[bodyCanvas].clearRect(0, 0, 32, 32); + core.dymCanvas[bodyCanvas].drawImage(image, posX * 32, posY * height + height - 32, 32, 32, 0, 0, 32, 32); + core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); + core.setOpacity(bodyCanvas, opacity); + } + if (damageCanvas) { + core.relocateCanvas(damageCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY); + core.setOpacity(damageCanvas, opacity); + } +} + +////// 删除独立的block canvas ////// +maps.prototype._deleteDetachedBlock = function (canvases) { + core.deleteCanvas(canvases.headCanvas); + core.deleteCanvas(canvases.bodyCanvas); + core.deleteCanvas(canvases.damageCanvas); +} + +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); + return [block, blockInfo]; +} + ////// 显示移动某块的动画,达到{“type”:”move”}的效果 ////// maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { time = time || 500; - var floorId = core.status.floorId; - - var block = core.getBlock(x,y); - if (block==null) {// 不存在 + var blockArr = this._getAndRemoveBlock(x, y); + if (blockArr == null) { if (core.isset(callback)) callback(); return; } - var id = block.block.id; + var block = blockArr[0], blockInfo = blockArr[1]; + var moveSteps = core.utils.expandMoveSteps(steps); + var canvases = this._initDetachedBlock(blockInfo, x, y, block.event.animate !== false); + this._moveDetachedBlock(blockInfo, 32 * x, 32 * y, 1, canvases); - // 需要删除该块 - core.removeBlock(x,y); - - block=block.block; - var blockInfo = this.getBlockInfo(block); - if (blockInfo == null) { - if (core.isset(callback)) callback(); - return; + var moveInfo = { + x: x, y: y, px: 32 * x, py: 32 * y, opacity: 1, keep: keep, + moveSteps: moveSteps, step: 0, per_time: time / 16 / core.status.replay.speed } - var image = blockInfo.image, bx = blockInfo.bx, by = blockInfo.by, height = blockInfo.height, isTileset = blockInfo.isTileset, faceIds = blockInfo.faceIds; + this._moveBlock_doMove(blockInfo, canvases, moveInfo, callback); +} - // 要运行的轨迹:将steps展开 - var moveSteps=[]; - steps.forEach(function (e) { - if (typeof e=="string") { - moveSteps.push(e); - } - else { - if (!core.isset(e.value)) { - moveSteps.push(e.direction) - } - else { - for (var i=0;i core.values.animateSpeed) { + animateTime = 0; + blockInfo.posX = (blockInfo.posX + 1) % animateTotal; } } - }); - moveSteps = moveSteps.filter(function (t) { return ['up','down','left','right'].indexOf(t)>=0;}); - - var nowX=32*x, nowY=32*y, step=0; - var destX=x, destY=y; - moveSteps.forEach(function (t) { - destX += core.utils.scan[t].x; - destY += core.utils.scan[t].y; - }); - - var animateValue = core.icons._getAnimateFrames(block.event.cls, true), animateCurrent = isTileset?bx:0, animateTime = 0; - var blockCanvas = this.__initBlockCanvas(block, height, x, y); - var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; - var opacity = 1; - - core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); - - var animate=window.setInterval(function() { - - animateTime += time / 16 / core.status.replay.speed; - if (animateTime >= core.values.animateSpeed) { - animateCurrent++; - animateTime = 0; - if (animateCurrent>=animateValue) animateCurrent=0; - } - if (isTileset) animateCurrent = bx; - - // 已经移动完毕,消失 - if (moveSteps.length==0 || floorId != core.status.floorId) { - if (keep || floorId!=core.status.floorId) opacity=0; - else opacity -= 0.06; - if (opacity<=0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.deleteCanvas(headCanvas); - core.deleteCanvas(bodyCanvas); - core.deleteCanvas(damageCanvas); - // 不消失 - if (keep) { - core.setBlock(id, destX, destY, floorId); - if (floorId == core.status.floorId) - core.showBlock(destX, destY); - } - if (core.isset(callback)) callback(); - } - else { - core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); - } - } - else { - // 移动中 - var direction = moveSteps[0]; - if (step == 0) { - // 根据faceIds修改朝向 - var currid = faceIds[direction]; - if (core.isset(currid)) { - var tby = core.material.icons[block.event.cls][currid]; - if (core.isset(tby)) - by = tby; - } - } - step++; - nowX+=core.utils.scan[direction].x*2; - nowY+=core.utils.scan[direction].y*2; - // 移动 - core.maps.__moveBlockCanvas(image, animateCurrent, by, height, nowX, nowY, opacity, headCanvas, bodyCanvas, damageCanvas); - if (step==16) { - // 该移动完毕,继续 - step=0; - moveSteps.shift(); - } - } - }, time / 16 / core.status.replay.speed); + if (moveInfo.moveSteps.length!=0) + core.maps._moveBlock_moving(blockInfo, canvases, moveInfo); + else + core.maps._moveJumpBlock_finished(blockInfo, canvases, moveInfo, animate, callback); + }, moveInfo.per_time); core.animateFrame.asyncId[animate] = true; +} +maps.prototype._moveBlock_moving = function (blockInfo, canvases, moveInfo) { + var direction = moveInfo.moveSteps[0]; + if (moveInfo.step == 0) { + moveInfo.x += core.utils.scan[direction].x; + moveInfo.y += core.utils.scan[direction].y; + // 根据faceIds修改朝向 + var currid = blockInfo.faceIds[direction]; + if (core.isset(currid)) { + var posY = core.material.icons[blockInfo.cls][currid]; + if (core.isset(posY)) blockInfo.posY = posY; + } + } + moveInfo.step++; + moveInfo.px += core.utils.scan[direction].x * 2; + moveInfo.py += core.utils.scan[direction].y * 2; + this._moveDetachedBlock(blockInfo, moveInfo.px, moveInfo.py, moveInfo.opacity, canvases); + if (moveInfo.step == 16) { + moveInfo.step = 0; + moveInfo.moveSteps.shift(); + } } ////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 ////// maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { time = time || 500; - var floorId = core.status.floorId; - var block = core.getBlock(sx,sy); - if (block==null) { + var blockArr = this._getAndRemoveBlock(sx, sy); + if (blockArr == null) { if (core.isset(callback)) callback(); return; } - var id = block.block.id; + var block = blockArr[0], blockInfo = blockArr[1]; + var canvases = this._initDetachedBlock(blockInfo, sx, sy, block.event.animate !== false); + this._moveDetachedBlock(blockInfo, 32 * sx, 32 * sy, 1, canvases); - // 需要删除该块 - core.removeBlock(sx,sy); + this._jumpBlock_playSound(); - block=block.block; - var blockInfo = this.getBlockInfo(block); - if (blockInfo == null) { - if (core.isset(callback)) callback(); - return; - } - var image = blockInfo.image, bx = blockInfo.bx, by = blockInfo.by, height = blockInfo.height, isTileset = blockInfo.isTileset, faceIds = blockInfo.faceIds; - - core.playSound('jump.mp3'); - - var dx = ex-sx, dy=ey-sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); + var dx = ex - sx, dy = ey - sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); var jump_peak = 6 + distance, jump_count = jump_peak * 2; - var currx = sx, curry = sy; + var jumpInfo = { + x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, keep: keep, + jump_peak: jump_peak, jump_count: jump_count, + step: 0, per_time: time / 16 / core.status.replay.speed + }; + this._jumpBlock_doJump(blockInfo, canvases, jumpInfo, callback); +} - var drawX = function() { - return currx * 32; - } - - var drawY = function() { - var ret = curry * 32; - if(jump_count >= jump_peak){ - var n = jump_count - jump_peak; - }else{ - var n = jump_peak - jump_count; - } - return ret - (jump_peak * jump_peak - n * n) / 2; - } - - var updateJump = function() { - jump_count--; - currx = (currx * jump_count + ex) / (jump_count + 1.0); - curry = (curry * jump_count + ey) / (jump_count + 1.0); - } - - var blockCanvas = this.__initBlockCanvas(block, height, sx, sy); - var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; - var opacity = 1; - - core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); +maps.prototype._jumpBlock_playSound = function () { + core.playSound('jump.mp3'); +} +maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, callback) { var animate=window.setInterval(function() { - - if (jump_count>0 && floorId == core.status.floorId) { - updateJump(); - core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); - } - else { - if (keep || floorId != core.status.floorId) opacity=0; - else opacity -= 0.06; - if (opacity<=0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.deleteCanvas(headCanvas); - core.deleteCanvas(bodyCanvas); - core.deleteCanvas(damageCanvas); - if (keep) { - core.setBlock(id, ex, ey, floorId); - if (floorId == core.status.floorId) - core.showBlock(ex, ey); - } - if (core.isset(callback)) callback(); - } - else { - core.maps.__moveBlockCanvas(image, bx, by, height, drawX(), drawY(), opacity, headCanvas, bodyCanvas, damageCanvas); - } - } - - }, time / 16 / core.status.replay.speed); + if (jumpInfo.jump_count>0) + core.maps._jumpBlock_jumping(blockInfo, canvases, jumpInfo) + else + core.maps._moveJumpBlock_finished(blockInfo, canvases, jumpInfo, animate, callback); + }, jumpInfo.per_time); core.animateFrame.asyncId[animate] = true; } +maps.prototype._jumpBlock_updateJump = function (jumpInfo) { + jumpInfo.jump_count--; + jumpInfo.x = (jumpInfo.x * jumpInfo.jump_count + jumpInfo.ex) / (jumpInfo.jump_count + 1.0); + jumpInfo.y = (jumpInfo.y * jumpInfo.jump_count + jumpInfo.ey) / (jumpInfo.jump_count + 1.0); + jumpInfo.px = 32 * jumpInfo.x; + var delta = Math.abs(jumpInfo.jump_count - jumpInfo.jump_peak); + jumpInfo.py = 32 * jumpInfo.y - (jumpInfo.jump_peak * jumpInfo.jump_peak - delta * delta) / 2; +} + +maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) { + this._jumpBlock_updateJump(jumpInfo); + core.maps._moveDetachedBlock(blockInfo, jumpInfo.px, jumpInfo.py, jumpInfo.opacity, canvases); +} + +maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, animate, callback) { + if (info.keep) info.opacity=0; + else info.opacity -= 0.06; + if (info.opacity<=0) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + this._deleteDetachedBlock(canvases); + // 不消失 + if (info.keep) { + core.setBlock(blockInfo.number, info.x, info.y); + core.showBlock(info.x, info.y); + } + if (core.isset(callback)) callback(); + } + else { + this._moveDetachedBlock(blockInfo, info.px, info.py, info.opacity, canvases); + } +} + ////// 显示/隐藏某个块时的动画效果 ////// maps.prototype.animateBlock = function (loc,type,time,callback) { - if (type!='hide') type='show'; - + var isHide = type=='hide'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; + var list = this._animateBlock_getList(loc); + if (list.length==0) { + if (core.isset(callback)) callback(); + return; + } + this._animateBlock_drawList(list, isHide?1:0); + this._animateBlock_doAnimate(loc, list, isHide, 10 / time, callback); +} +maps.prototype._animateBlock_doAnimate = function (loc, list, isHide, delta, callback) { + var opacity = isHide?1:0; + var animate = setInterval(function () { + opacity += isHide?-delta:delta; + core.maps._animateBlock_drawList(list, opacity); + if (opacity >=1 || opacity<=0) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + list.forEach(function (t) { + core.maps._deleteDetachedBlock(t.canvases); + }); + loc.forEach(function (t) { + if (isHide) core.removeBlock(t[0],t[1]); + else core.showBlock(t[0],t[1]); + }); + if (core.isset(callback)) callback(); + } + }, 10); + + core.animateFrame.asyncId[animate] = true; +} + +maps.prototype._animateBlock_getList = function (loc) { var list = []; loc.forEach(function (t) { var block = core.getBlock(t[0],t[1],null,true); @@ -1533,76 +1512,36 @@ maps.prototype.animateBlock = function (loc,type,time,callback) { var blockInfo = core.maps.getBlockInfo(block); if (blockInfo == null) return; - var blockCanvas = core.maps.__initBlockCanvas(block, blockInfo.height, t[0], t[1]); - var headCanvas = blockCanvas.headCanvas, bodyCanvas = blockCanvas.bodyCanvas, damageCanvas = blockCanvas.damageCanvas; + var canvases = core.maps._initDetachedBlock(blockInfo, t[0], t[1], block.event.displayDamage !== false); list.push({ - 'x': t[0], 'y': t[1], 'height': blockInfo.height, - 'bx': blockInfo.bx, 'by': blockInfo.by, 'image': blockInfo.image, - 'headCanvas': headCanvas, 'bodyCanvas': bodyCanvas, 'damageCanvas': damageCanvas + 'x': t[0], 'y': t[1], 'blockInfo': blockInfo, 'canvases': canvases }); }); - - if (list.length==0) { - if (core.isset(callback)) callback(); - return; - } - - var opacity = 0; - if (type=='hide') opacity=1; - - var draw = function () { - list.forEach(function (t) { - core.maps.__moveBlockCanvas(t.image, t.bx, t.by, t.height, t.x*32, t.y*32, opacity, t.headCanvas, t.bodyCanvas, t.damageCanvas); - }) - }; - draw(); - - var per_time = 10, steps = parseInt(time / per_time), delta = 1 / steps; - var animate = setInterval(function () { - if (type=='show') opacity += delta; - else opacity -= delta; - if (opacity >=1 || opacity<=0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - list.forEach(function (t) { - core.deleteCanvas(t.headCanvas); - core.deleteCanvas(t.bodyCanvas); - core.deleteCanvas(t.damageCanvas); - }); - if (type == 'show') { - loc.forEach(function (t) { - core.showBlock(t[0],t[1],data.floorId); - }); - } - else { - loc.forEach(function (t) { - core.removeBlock(t[0],t[1],data.floorId); - }); - } - if (core.isset(callback)) callback(); - } - else { - draw(); - } - }, per_time); - - core.animateFrame.asyncId[animate] = true; + return list; } +maps.prototype._animateBlock_drawList = function (list, opacity) { + list.forEach(function (t) { + core.maps._moveDetachedBlock(t.blockInfo, t.x * 32, t.y * 32, opacity, t.canvases); + }); +} + +// ------ 全局动画控制,动画绘制 ------ // + ////// 添加一个全局动画 ////// maps.prototype.addGlobalAnimate = function (b) { - if (!core.isset(b.event) || !core.isset(b.event.animate) || b.event.animate==1) return; - core.status.globalAnimateObjs.push(b); -} - -////// 添加一个Autotile全局动画 ////// -maps.prototype.addAutotileGlobalAnimate = function (b) { - if (!core.isset(b.event) || b.event.cls!='autotile') return; - var id = b.event.id, img = core.material.images.autotile[id]; - if (!core.isset(img) || img.width==96) return; - core.status.autotileAnimateObjs.blocks.push(b); + if (!core.isset(b.event) || !core.isset(b.event.animate)) return; + if (b.event.cls == 'autotile') { + var id = b.event.id, img = core.material.images.autotile[id]; + if (!core.isset(img) || img.width==96) return; + core.status.autotileAnimateObjs.blocks.push(b); + } + else { + if (!core.isset(b.event.animate) || b.event.animate == 1) return; + core.status.globalAnimateObjs.push(b); + } } ////// 删除一个或所有全局动画 ////// @@ -1626,12 +1565,6 @@ maps.prototype.removeGlobalAnimate = function (x, y, name) { } -////// 设置全局动画的显示效果 ////// -maps.prototype.setGlobalAnimate = function () { - core.status.globalAnimateStatus = 0; - core.animateFrame.globalAnimate = true; -} - ////// 绘制UI层的box动画 ////// maps.prototype.drawBoxAnimate = function () { core.status.boxAnimateObjs.forEach(function (obj) { diff --git a/libs/utils.js b/libs/utils.js index f8a9323b..688aa8b2 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -570,6 +570,26 @@ utils.prototype.getCookie = function (name) { return match?match[2]:null; } +utils.prototype.expandMoveSteps = function (steps) { + var moveSteps=[]; + steps.forEach(function (e) { + if (typeof e=="string") { + moveSteps.push(e); + } + else { + if (!core.isset(e.value)) { + moveSteps.push(e.direction) + } + else { + for (var i=0;i Date: Thu, 14 Mar 2019 16:00:47 +0800 Subject: [PATCH 004/153] drawEvents v2.6 --- _server/editor.js | 3 +- libs/control.js | 4 +- libs/maps.js | 299 ++++++++++++++++++++++------------------------ 3 files changed, 148 insertions(+), 158 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index a15a967b..83c29c51 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -304,8 +304,7 @@ editor.prototype.updateMap = function () { core.clearMap('event'); core.clearMap('event2'); core.clearMap('fg'); - core.maps._drawMap_drawBgFg(); - core.maps._drawMap_drawEvent(); + core.maps._drawMap_drawAll(); } updateMap(); diff --git a/libs/control.js b/libs/control.js index c7b6d0fd..4996210b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -71,8 +71,8 @@ control.prototype.setRequestAnimationFrame = function () { }); // Global floor images - core.maps.drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); - core.maps.drawFloorImages(core.status.floorId, core.canvas.fg, 'fg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); + core.maps._drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); + 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) { diff --git a/libs/maps.js b/libs/maps.js index 9743be79..a7fb73a2 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -575,6 +575,151 @@ maps.prototype.generateGroundPattern = function (floorId) { // core.material.groundPattern = '#000000'; } +////// 绘制某张地图 ////// +maps.prototype.drawMap = function (floorId, callback) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) { + if (core.isset(callback)) callback(); + return; + } + core.clearMap('all'); + this.generateGroundPattern(floorId); + core.status.floorId = floorId; + core.status.thisMap = core.status.maps[floorId]; + + this._drawMap_drawAll(); + if (core.isset(core.status.curtainColor)) { + core.fillRect('curtain', 0, 0, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, + core.arrayToRGBA(core.status.curtainColor)); + } + core.drawHero(); + core.updateStatusBar(); + if (core.isset(callback)) + callback(); +} + +maps.prototype._drawMap_drawAll = function (floorId) { + floorId = floorId || core.status.floorId; + this.drawBg(floorId); + this.drawEvents(floorId); + this.drawFg(floorId); +} + +maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { + if (blockInfo == null) return; + if (blockInfo.cls == 'autotile') { // Autotile单独处理 + this.drawAutotile(ctx, arr, block, 32, 0, 0); + if (onMap) this.addGlobalAnimate(block); + return; + } + if (!onMap) { + var height = blockInfo.height; + core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); + return; + } + this.drawBlock(block); + this.addGlobalAnimate(block); +} + +////// 绘制背景层 ////// +maps.prototype.drawBg = function (floorId, ctx) { + var onMap = !core.isset(ctx); + if (onMap) { + ctx = core.canvas.bg; + core.clearMap(ctx); + } + this._drawBg_drawBackground(floorId, ctx); + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 + this._drawFloorImages(floorId, ctx, 'bg'); + this._drawBgFgMap(floorId, ctx, 'bg', onMap); +} + +maps.prototype._drawBg_drawBackground = function (floorId, ctx) { + var width = core.floors[floorId].width, height = core.floors[floorId].height; + var groundId = (core.status.maps||core.floors)[floorId].defaultGround || "ground"; + var yOffset = core.material.icons.terrains[groundId]; + if (core.isset(yOffset)) { + for (var i = 0; i < width; i++) { + for (var j = 0; j < height; j++) { + ctx.drawImage(core.material.images.terrains, 0, yOffset * 32, 32, 32, i * 32, j * 32, 32, 32); + } + } + } +} + +////// 绘制事件层 ////// +maps.prototype.drawEvents = function (floorId, blocks, ctx) { + floorId = floorId ||core.status.floorId; + if (!core.isset(blocks)) blocks = core.status.maps[floorId].blocks; + var arr = this.getMapArray(blocks, core.floors[floorId].width, core.floors[floorId].height); + var onMap = !core.isset(ctx); + if (onMap) ctx = core.canvas.event; + blocks.filter(function (block) { return block.event && !block.disable; }) + .forEach(function (block) { + core.maps._drawMap_drawBlockInfo(ctx, block, core.maps.getBlockInfo(block), arr, onMap); + }); + if (onMap) core.status.autotileAnimateObjs.map = core.clone(arr); +} + +////// 绘制前景层 ////// +maps.prototype.drawFg = function (floorId, ctx) { + var onMap = !core.isset(ctx); + if (onMap) ctx = core.canvas.fg; + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 + this._drawFloorImages(floorId, ctx, 'fg'); + this._drawBgFgMap(floorId, ctx, 'fg', onMap); +} + +////// 实际的背景/前景图块的绘制 ////// +maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + var width = core.floors[floorId].width; + var height = core.floors[floorId].height; + + if (!core.isset(core.status[name+"maps"])) + core.status[name+"maps"] = {}; + + var arr = this.getBgFgMapArray(name, floorId); + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + var block = this.initBlock(x, y, arr[y][x], true); + if (!core.isset(block.event)) continue; + block.name = name; + var blockInfo = this.getBlockInfo(block); + if (!core.isset(blockInfo)) continue; + this._drawMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); + } + } + if (onMap) + core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); +} + +////// 绘制楼层贴图 ////// +maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStatus) { + floorId = floorId || core.status.floorId; + if (!core.isset(images)) images = this._getFloorImages(floorId); + var redraw = core.isset(currStatus); + if (!redraw) core.status.floorAnimateObjs = core.clone(images); + images.forEach(function (t) { + if (typeof t == 'string') t = [0,0,t]; + var dx=parseInt(t[0]), dy=parseInt(t[1]), imageName=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); + var image = core.material.images.images[imageName]; + if (redraw && frame == 1) return; // 不重绘 + + if (core.isset(dx) && core.isset(dy) && core.isset(image) && + !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy)) { + var width = parseInt(image.width / frame), offsetX = (currStatus||0)%frame*width; + if (/.*\.gif/i.test(imageName) && main.mode=='play') { + if (redraw) return; // 忽略gif + this._drawFloorImages_gif(image, dx, dy); + return; + } + core.maps._drawFloorImage(ctx, name, t[3], image, offsetX, width, dx, dy, redraw); + } + }); +} + maps.prototype._getFloorImages = function (floorId) { floorId = floorId || core.status.floorId; var images = []; @@ -587,31 +732,6 @@ maps.prototype._getFloorImages = function (floorId) { return images; } -////// 绘制楼层贴图 ////// -maps.prototype.drawFloorImages = function (floorId, ctx, name, images, animate) { - floorId = floorId || core.status.floorId; - if (!core.isset(images)) images = this._getFloorImages(floorId); - var redraw = core.isset(animate); - if (!redraw) core.status.floorAnimateObjs = core.clone(images); - images.forEach(function (t) { - if (typeof t == 'string') t = [0,0,t]; - var dx=parseInt(t[0]), dy=parseInt(t[1]), imageName=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); - var image = core.material.images.images[imageName]; - if (redraw && frame == 1) return; // 不重绘 - - if (core.isset(dx) && core.isset(dy) && core.isset(image) && - !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy)) { - var width = parseInt(image.width / frame), offsetX = (animate||0)%frame*width; - if (/.*\.gif/i.test(imageName) && main.mode=='play') { - if (redraw) return; // 忽略gif - this._drawFloorImages_gif(image, dx, dy); - return; - } - core.maps._drawFloorImage(ctx, name, t[3], image, offsetX, width, dx, dy, redraw); - } - }); -} - maps.prototype._drawFloorImages_gif = function (image, dx, dy) { core.dom.gif.innerHTML = ""; var gif = new Image(); @@ -652,135 +772,6 @@ maps.prototype._drawFloorImage = function (ctx, name, type, image, offsetX, widt } } -////// 绘制某张地图 ////// -maps.prototype.drawMap = function (floorId, callback) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) { - if (core.isset(callback)) callback(); - return; - } - core.clearMap('all'); - this.generateGroundPattern(floorId); - core.status.floorId = floorId; - core.status.thisMap = core.status.maps[floorId]; - - this._drawMap_drawBgFg(); - this._drawMap_drawEvent(); - if (core.isset(core.status.curtainColor)) { - core.fillRect('curtain', 0, 0, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, - core.arrayToRGBA(core.status.curtainColor)); - } - core.drawHero(); - core.updateStatusBar(); - if (core.isset(callback)) - callback(); -} - -maps.prototype._drawMap_drawEvent = function (floorId) { - floorId = floorId || core.status.floorId; - var mapBlocks = core.status.maps[floorId].blocks; - - var mapArray = this.getMapArray(mapBlocks, core.bigmap.width, core.bigmap.height); - for (var b = 0; b < mapBlocks.length; b++) { - // 事件启用 - var block = mapBlocks[b]; - if (core.isset(block.event) && !block.disable) { - if (block.event.cls == 'autotile') { - core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0); - } - else { - core.drawBlock(block); - } - core.addGlobalAnimate(block); - } - } - core.status.autotileAnimateObjs.map = core.clone(mapArray); -} - -maps.prototype._drawMap_drawBgFg = function (floorId) { - floorId = floorId || core.status.floorId; - this.drawBg(floorId); - this.drawFg(floorId); -} - -////// 绘制背景层 ////// -maps.prototype.drawBg = function (floorId, ctx) { - var onMap = !core.isset(ctx); - if (onMap) { - ctx = core.canvas.bg; - core.clearMap(ctx); - var width = core.floors[floorId].width; - var height = core.floors[floorId].height; - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - core.drawImage(ctx, core.material.groundCanvas.canvas, 32*x, 32*y); - } - } - } - this._drawBg_drawContent(floorId, ctx, onMap); -} - -////// 绘制前景层 ////// -maps.prototype.drawFg = function (floorId, ctx) { - var onMap = !core.isset(ctx); - if (onMap) ctx = core.canvas.fg; - this._drawFg_drawContent(floorId, ctx, onMap); -} - -// --- 实际绘制背景层;可以调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块 -// 先绘制的会被后绘制的覆盖 -maps.prototype._drawBg_drawContent = function (floorId, ctx, onMap) { - this.drawFloorImages(floorId, ctx, 'bg'); - this.drawBgFgMap(floorId, ctx, 'bg', onMap); -} - -// --- 实际绘制前景层;可以调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块 -// 先绘制的会被后绘制的覆盖 -maps.prototype._drawFg_drawContent = function (floorId, ctx, onMap) { - this.drawFloorImages(floorId, ctx, 'fg'); - this.drawBgFgMap(floorId, ctx, 'fg', onMap); -} - -////// 背景/前景图块的绘制 ////// -maps.prototype.drawBgFgMap = function (floorId, ctx, name, onMap) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - var width = core.floors[floorId].width; - var height = core.floors[floorId].height; - - if (!core.isset(core.status[name+"maps"])) - core.status[name+"maps"] = {}; - - var arr = this.getBgFgMapArray(name, floorId); - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - var block = this.initBlock(x, y, arr[y][x], true); - if (!core.isset(block.event)) continue; - block.name = name; - var blockInfo = this.getBlockInfo(block); - if (!core.isset(blockInfo)) continue; - this._drawBgFgMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); - } - } - if (onMap) - core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); -} - -maps.prototype._drawBgFgMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { - if (blockInfo.cls == 'autotile') { // Autotile单独处理 - this.drawAutotile(ctx, arr, block, 32, 0, 0); - if (onMap) this.addGlobalAnimate(block); - return; - } - if (!onMap) { - var height = blockInfo.height; - core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); - return; - } - this.drawBlock(block); - this.addGlobalAnimate(block); -} - ////// 绘制Autotile ////// maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, status){ var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 From 70075763fb54d6100149caf1fee32ad9b4f91cc4 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 14 Mar 2019 19:27:22 +0800 Subject: [PATCH 005/153] Forward plugin & drawThumbnail --- libs/core.js | 28 +++++------ libs/maps.js | 101 ++++++++++++++++++++++++++++++++++++++ libs/ui.js | 136 +-------------------------------------------------- 3 files changed, 115 insertions(+), 150 deletions(-) diff --git a/libs/core.js b/libs/core.js index c35abc7f..a878e84c 100644 --- a/libs/core.js +++ b/libs/core.js @@ -351,7 +351,6 @@ core.prototype.init = function (coreData, callback) { }); core.loader._load(function () { - console.log(core.material); // 设置勇士高度 core.material.icons.hero.height = core.material.images.hero.height/4; // 行走图 @@ -369,6 +368,7 @@ core.prototype.init = function (coreData, callback) { }; core.plugin.__init__ = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.plugin; core.plugin.__init__(); + core._forwardFunc("plugin"); } core.showStartAnimate(); @@ -379,29 +379,25 @@ core.prototype.init = function (coreData, callback) { } core.prototype._forwardFuncs = function () { - var list = {}; for (var i = 0; i < main.loadList.length; ++i) { var name = main.loadList[i]; if (name == 'core') continue; - for (var funcname in core[name]) { - if (funcname.charAt(0) != "_" && core[name][funcname] instanceof Function) { - if (list[funcname]) { - main.log("Error forward: "+name+"."+funcname); - } - else { - list[funcname] = name; - } - } - } - } - for (var funcname in list) { - this._forwardFunc(list[funcname], funcname); + this._forwardFunc(name); } } core.prototype._forwardFunc = function (name, funcname) { + if (funcname == null) { + for (funcname in core[name]) { + if (funcname.charAt(0) != "_" && core[name][funcname] instanceof Function) { + this._forwardFunc(name, funcname); + } + } + return; + } + if (core[funcname]) { - main.log("Error in forwarding "+funcname+" from "+name+"!"); + console.error("ERROR: Cannot forward function "+funcname+" from "+name+"!"); return; } var parameterInfo = /^\s*function\s*[\w_$]*\(([\w_,$\s]*)\)\s*\{/.exec(core[name][funcname].toString()); diff --git a/libs/maps.js b/libs/maps.js index a7fb73a2..85dfa778 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -895,6 +895,107 @@ maps.prototype._makeAutotileEdges = function () { }); } +////// 绘制缩略图 ////// +// 此函数将绘制一个缩略图,floorId为目标floorId,blocks为地图的图块(可为null使用floorId对应默认的) +// options为绘制选项(可为null),包括: +// heroLoc: 勇士位置;heroIcon:勇士图标;damage:是否绘制显伤;flags:当前的flags(存读档时使用) +// toDraw为要绘制到的信息(可为null,或为一个画布名),包括: +// ctx:要绘制到的画布(名);x,y:起点横纵坐标;size:大小;all:是否绘制全图;centerX,centerY:截取中心 +maps.prototype.drawThumbnail = function (floorId, blocks, options, toDraw) { + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) return; + // Step1:绘制到tempCanvas上 + this._drawThumbnail_drawTempCanvas(floorId, blocks, options); + // Step2:从tempCanvas绘制到对应的画布上 + this._drawThumbnail_drawToTarget(floorId, toDraw); +} + +maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) { + if (!core.isset(blocks)) blocks = core.status.maps[floorId].blocks; + if (!core.isset(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); + + // --- 暂存 flags + var hasHero = core.isset(core.status.hero), flags = null; + if (options.flags) { + if (!hasHero) core.status.hero = {}; + flags = core.status.hero.flags; + core.status.hero.flags = options.flags; + } + + this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options, tempCanvas); + + // --- 恢复 flags + if (!hasHero) delete core.status.hero; + else if (flags != null) core.status.hero.flags = flags; +} + +maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, options, tempCanvas) { + // 缩略图:背景 + this.drawBg(floorId, tempCanvas); + // 缩略图:事件 + this.drawEvents(floorId, blocks, tempCanvas); + // 缩略图:勇士 + if (options.heroLoc) { + options.heroIcon = options.heroIcon || "hero.png"; + var icon = core.material.icons.hero[options.heroLoc.direction]; + var height = core.material.images.images[options.heroIcon].height/4; + tempCanvas.drawImage(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); + // 缩略图:显伤 + if (options.damage) + core.control.updateDamage(floorId, tempCanvas); +} + +maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { + if (!core.isset(toDraw)) return; + if (typeof toDraw == 'string' || toDraw.canvas) toDraw = {ctx: toDraw}; + var ctx = core.getContextByName(toDraw.ctx); + if (ctx == null) return; + var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || this.DEFAULT_PIXEL_WIDTH; + var width = core.floors[floorId].width, height = core.floors[floorId].height; + var centerX = toDraw.centerX, centerY = toDraw.centerY; + if (!core.isset(centerX)) centerX = Math.floor(width/2); + if (!core.isset(centerY)) centerY = Math.floor(height/2); + var tempCanvas = core.bigmap.tempCanvas, tempWidth = 32 * width, tempHeight = 32 * height; + + core.clearMap(ctx, x, y, size, size); + if (toDraw.all) { + // 绘制全景图 + if (tempWidth<=tempHeight) { + var realHeight = size, realWidth = realHeight * tempWidth / tempHeight; + var side = (size - realWidth) / 2; + core.fillRect(ctx, x, y, side, realHeight, '#000000'); + core.fillRect(ctx, x + size - side, y, side, realHeight); + ctx.drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, x + side, y, realWidth, realHeight); + } + else { + var realWidth = size, realHeight = realWidth * tempHeight / tempWidth; + var side = (size - realHeight) / 2; + core.fillRect(ctx, x, y, realWidth, side, '#000000'); + core.fillRect(ctx, x, y + size - side, realWidth, side); + ctx.drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, x, y + side, realWidth, realHeight); + } + } + else { + // 只绘制可见窗口 + var halfWidth = parseInt(this.DEFAULT_WIDTH / 2), halfHeight = parseInt(this.DEFAULT_HEIGHT / 2); + var offsetX = core.clamp(centerX - halfWidth, 0, width - this.DEFAULT_WIDTH), offsetY = core.clamp(centerY - halfHeight, 0, height - this.DEFAULT_HEIGHT); + ctx.drawImage(tempCanvas.canvas, offsetX * 32, offsetY * 32, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, x, y, size, size); + } +} + // -------- 获得某个点的图块信息 -------- // ////// 某个点是否不可通行 ////// diff --git a/libs/ui.js b/libs/ui.js index f208ae46..0ea67f59 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2159,140 +2159,8 @@ ui.prototype.drawSLPanel = function(index, refresh) { ////// 绘制一个缩略图 ////// ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, centerX, centerY, heroLoc, heroIcon) { - - var mw = core.floors[floorId].width; - var mh = core.floors[floorId].height; - // 绘制到tempCanvas上面 - var tempCanvas = core.bigmap.tempCanvas; - var tempWidth = mw*32, tempHeight = mh*32; - tempCanvas.canvas.width = tempWidth; - tempCanvas.canvas.height = tempHeight; - tempCanvas.clearRect(0, 0, tempWidth, tempHeight); - - // -------- 1. 绘制地板 - var groundId = (core.status.maps||core.floors)[floorId].defaultGround || "ground"; - var blockIcon = core.material.icons.terrains[groundId]; - for (var i = 0; i < mw; i++) { - for (var j = 0; j < mh; j++) { - tempCanvas.drawImage(core.material.images.terrains, 0, blockIcon * 32, 32, 32, i * 32, j * 32, 32, 32); - } - } - - var images = []; - if (core.isset((core.status.maps||core.floors)[floorId].images)) { - images = (core.status.maps||core.floors)[floorId].images; - if (typeof images == 'string') { - images = [[0, 0, images]]; - } - } - - // -------- 2. 绘制背景贴图 - images.forEach(function (t) { - if (typeof t == 'string') t = [0,0,t]; - var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); - if (core.isset(dx) && core.isset(dy) && - !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy) && - core.isset(core.material.images.images[p])) { - var image = core.material.images.images[p]; - var width = image.width / frame, height = image.height; - if (!t[3]) - tempCanvas.drawImage(image, 0, 0, width, height, dx, dy, width, height); - else if (t[3]==2) - tempCanvas.drawImage(image, 0, height-32, width, 32, dx, dy + height - 32, width, 32); - } - }) - - // -------- 3. 绘制背景图块 - core.maps.drawBgFgMap(floorId, tempCanvas, "bg"); - - // -------- 4. 绘制事件层 - var mapArray = core.maps.getMapArray(blocks,mw,mh); - for (var b in blocks) { - var block = blocks[b]; - if (core.isset(block.event) && !block.disable) { - if (block.event.cls == 'autotile') { - core.drawAutotile(tempCanvas, mapArray, block, 32, 0, 0); - } - else if (block.event.cls == 'tileset') { - var offset = core.icons.getTilesetOffset(block.event.id); - if (offset!=null) { - tempCanvas.drawImage(core.material.images.tilesets[offset.image], 32*offset.x, 32*offset.y, 32, 32, 32*block.x, 32*block.y, 32, 32); - } - } - else if (block.id==17) { - if (core.isset(core.material.images.airwall)) { - tempCanvas.drawImage(core.material.images.airwall, 32*block.x, 32*block.y); - } - } - else if (block.event.id!='none') { - var blockIcon = core.material.icons[block.event.cls][block.event.id]; - var blockImage = core.material.images[block.event.cls]; - var height = block.event.height || 32; - tempCanvas.drawImage(blockImage, 0, blockIcon * height, 32, height, 32*block.x, 32*block.y + 32 - height, 32, height); - } - } - } - // -------- 5. 绘制勇士 - if (core.isset(heroLoc)) { - if (!core.isset(core.material.images.images[heroIcon])) - heroIcon = "hero.png"; - var icon = core.material.icons.hero[heroLoc.direction]; - var height = core.material.images.images[heroIcon].height/4; - tempCanvas.drawImage(core.material.images.images[heroIcon], icon.stop * 32, icon.loc * height, 32, height, 32*heroLoc.x, 32*heroLoc.y+32-height, 32, height); - } - - // -------- 6. 绘制前景贴图 - images.forEach(function (t) { - var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); - if (core.isset(dx) && core.isset(dy) && - !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy) && - core.isset(core.material.images.images[p])) { - var image = core.material.images.images[p]; - var width = image.width / frame, height = image.height; - if (t[3]==1) - tempCanvas.drawImage(image, 0, 0, width, height, dx, dy, width, height); - else if (t[3]==2) - tempCanvas.drawImage(image, 0, 0, width, height-32, dx, dy, width, height-32); - } - }) - - // -------- 7. 绘制前景图块 - core.maps.drawBgFgMap(floorId, tempCanvas, "fg"); - - // -------- 8. 绘制显伤 - if (core.status.event.id=='viewMaps' && (core.status.event.data||{}).damage) - core.control.updateDamage(floorId, tempCanvas); - - var ctx = core.getContextByName(canvas); - if (ctx == null) return; - - // draw to canvas - core.clearMap(canvas, x, y, size, size); - if (!core.isset(centerX)) centerX=parseInt(mw/2); - if (!core.isset(centerY)) centerY=parseInt(mh/2); - - // 如果是浏览地图的全模式 - if (core.status.event.id=='viewMaps' && (core.status.event.data||{}).all) { - if (tempWidth<=tempHeight) { - var realHeight = 416, realWidth = realHeight * tempWidth / tempHeight; - var side = (416 - realWidth) / 2; - core.fillRect(canvas, 0, 0, side, realHeight, '#000000'); - core.fillRect(canvas, 416-side, 0, side, realHeight); - ctx.drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, side, 0, realWidth, realHeight); - } - else { - var realWidth = 416, realHeight = realWidth * tempHeight / tempWidth; - var side = (416 - realHeight) / 2; - core.fillRect(canvas, 0, 0, realWidth, side, '#000000'); - core.fillRect(canvas, 0, 416-side, realWidth, side); - ctx.drawImage(tempCanvas.canvas, 0, 0, tempWidth, tempHeight, 0, side, realWidth, realHeight); - } - } - else { - var offsetX = core.clamp(centerX-6, 0, mw-13), offsetY = core.clamp(centerY-6, 0, mh-13); - // offsetX~offsetX+12; offsetY~offsetY+12 - ctx.drawImage(tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, x, y, size, size); - } + core.drawThumbnail(floorId, blocks, {heroLoc: heroLoc, heroIcon: heroIcon}, + {ctx: canvas, x: x, y: y, size: size, centerX: centerX, centerY: centerY}); } ui.prototype.drawKeyBoard = function () { From d440987345f4f56b7a7c80fdf8e96097b2dd3c7c Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 14 Mar 2019 22:05:14 +0800 Subject: [PATCH 006/153] drawThumbnail & updateCheckBlock(floorId) --- libs/control.js | 33 +++++++------------- libs/events.js | 3 +- libs/items.js | 10 ++++-- libs/maps.js | 22 +++++++------ libs/ui.js | 23 ++++++++------ project/functions.js | 73 +++++++++++++++++++++++--------------------- 6 files changed, 84 insertions(+), 80 deletions(-) diff --git a/libs/control.js b/libs/control.js index 4996210b..f006e9ef 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1220,8 +1220,8 @@ control.prototype.updateFollowers = function () { } ////// 更新领域、夹击、阻击的伤害地图 ////// -control.prototype.updateCheckBlock = function() { - return this.controldata.updateCheckBlock(); +control.prototype.updateCheckBlock = function(floorId) { + return this.controldata.updateCheckBlock(floorId); } ////// 检查并执行领域、夹击、阻击事件 ////// @@ -1455,9 +1455,11 @@ control.prototype.updateDamage = function (floorId, canvas) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (core.status.gameOver) return; + var refreshCheckBlock = true; if (!core.isset(canvas)) { canvas = core.canvas.damage; core.clearMap('damage'); + refreshCheckBlock = false; } // 更新显伤 @@ -1502,37 +1504,24 @@ control.prototype.updateDamage = function (floorId, canvas) { if (core.flags.displayExtraDamage && core.isset((core.status.checkBlock||{}).damage)) { canvas.textAlign = 'center'; - // 临时改变 - var tempCheckBlock = null; - if (floorId != core.status.floorId) { - tempCheckBlock = core.clone(core.status.checkBlock); - core.status.thisMap = core.status.maps[floorId]; - core.bigmap.width = core.floors[floorId].width; - core.bigmap.height = core.floors[floorId].height; - core.updateCheckBlock(); - } + if (refreshCheckBlock) + this.updateCheckBlock(floorId); - for (var x=0;x0) { // 该点伤害 damage = core.formatBigNumber(damage, true); core.fillBoldText(canvas, damage, 32*x+16, 32*(y+1)-14, '#FF7F00'); } else { // 检查捕捉 - if ((core.status.checkBlock.ambush||[])[x+core.bigmap.width*y]) { + if ((core.status.checkBlock.ambush||[])[x+width*y]) { core.fillBoldText(canvas, '!', 32*x+16, 32*(y+1)-14, '#FF7F00'); } } } } - - if (floorId!=core.status.floorId) { - core.status.thisMap = core.status.maps[core.status.floorId]; - core.status.checkBlock = tempCheckBlock; - core.bigmap.width = core.floors[core.status.floorId].width; - core.bigmap.height = core.floors[core.status.floorId].height; - } } } diff --git a/libs/events.js b/libs/events.js index 8ddde54e..d4e549e9 100644 --- a/libs/events.js +++ b/libs/events.js @@ -2104,7 +2104,8 @@ events.prototype.tryUseItem = function(itemId) { var fillstyle = 'rgba(255,0,0,0.5)'; if (core.canUseItem('centerFly')) fillstyle = 'rgba(0,255,0,0.5)'; var toX = core.bigmap.width-1 - core.getHeroLoc('x'), toY = core.bigmap.height-1-core.getHeroLoc('y'); - core.ui.drawThumbnail(core.status.floorId, 'ui', core.status.thisMap.blocks, 0, 0, 416, toX, toY, core.status.hero.loc, core.getFlag('heroIcon', "hero.png")); + core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.getFlag('heroIcon', "hero.png")}, + {ctx: 'ui', centerX: toX, centerY: toY}); var offsetX = core.clamp(toX-6, 0, core.bigmap.width-13), offsetY = core.clamp(toY-6, 0, core.bigmap.height-13); core.fillRect('ui',(toX-offsetX)*32,(toY-offsetY)*32,32,32,fillstyle); core.status.event.data = {"x": toX, "y": toY, "posX": toX-offsetX, "posY": toY-offsetY}; diff --git a/libs/items.js b/libs/items.js index f38f8cb3..ec445a3c 100644 --- a/libs/items.js +++ b/libs/items.js @@ -81,7 +81,10 @@ items.prototype._afterUseItem = function (itemId) { if (core.status.hero.items[itemCls][itemId]<=0) delete core.status.hero.items[itemCls][itemId]; - core.status.event.ui = null; + if (!core.status.event.id) { + core.status.event.data = null; + core.status.event.ui = null; + } core.updateStatusBar(); } @@ -114,7 +117,10 @@ items.prototype.canUseItem = function (itemId) { main.log(e); } } - if (!able) core.status.event.ui = null; + if (!able) { + core.status.event.data = null; + core.status.event.ui = null; + } return able; } diff --git a/libs/maps.js b/libs/maps.js index 85dfa778..82a40107 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -339,13 +339,13 @@ maps.prototype.getMapBlocksObj = function (floorId, showDisable) { } ////// 将背景前景层变成二维数组的形式 ////// -maps.prototype.getBgFgMapArray = function (name, floorId) { +maps.prototype.getBgFgMapArray = function (name, floorId, useCache) { floorId = floorId||core.status.floorId; if (!core.isset(floorId)) return []; var width = core.floors[floorId].width; var height = core.floors[floorId].height; - if (main.mode!='editor' && core.isset(core.status[name+"maps"][floorId])) + if (useCache && core.isset(core.status[name+"maps"][floorId])) return core.status[name+"maps"][floorId]; var arr = core.clone(core.floors[floorId][name+"map"] || []); @@ -360,7 +360,8 @@ maps.prototype.getBgFgMapArray = function (name, floorId) { if(main.mode=='editor')arr[y][x]= arr[y][x].idnum || arr[y][x] || 0; } } - core.status[name+"maps"][floorId] = core.clone(arr); + if (useCache) + core.status[name+"maps"][floorId] = core.clone(arr); return arr; } @@ -371,8 +372,8 @@ maps.prototype.generateMovableArray = function (floorId, x, y) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return null; var width = core.floors[floorId].width, height = core.floors[floorId].height; - var bgArray = this.getBgFgMapArray('bg', floorId), - fgArray = this.getBgFgMapArray('fg', floorId), + var bgArray = this.getBgFgMapArray('bg', floorId, true), + fgArray = this.getBgFgMapArray('fg', floorId, true), eventArray = this.getMapArray(floorId); var generate = function (x, y) { @@ -723,8 +724,8 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat maps.prototype._getFloorImages = function (floorId) { floorId = floorId || core.status.floorId; var images = []; - if (core.isset(core.status.maps[floorId].images)) { - images = core.status.maps[floorId].images; + if (core.isset((core.status.maps||core.floors)[floorId].images)) { + images = (core.status.maps||core.floors)[floorId].images; if (typeof images == 'string') { images = [[0, 0, images]]; } @@ -898,9 +899,10 @@ maps.prototype._makeAutotileEdges = function () { ////// 绘制缩略图 ////// // 此函数将绘制一个缩略图,floorId为目标floorId,blocks为地图的图块(可为null使用floorId对应默认的) // options为绘制选项(可为null),包括: -// heroLoc: 勇士位置;heroIcon:勇士图标;damage:是否绘制显伤;flags:当前的flags(存读档时使用) +// heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤;flags:当前的flags(存读档时使用) // toDraw为要绘制到的信息(可为null,或为一个画布名),包括: -// ctx:要绘制到的画布(名);x,y:起点横纵坐标;size:大小;all:是否绘制全图;centerX,centerY:截取中心 +// ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:大小(默认416/480); +// all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心) maps.prototype.drawThumbnail = function (floorId, blocks, options, toDraw) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; @@ -945,7 +947,7 @@ maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, op this.drawEvents(floorId, blocks, tempCanvas); // 缩略图:勇士 if (options.heroLoc) { - options.heroIcon = options.heroIcon || "hero.png"; + options.heroIcon = options.heroIcon || core.getFlag("heroIcon", "hero.png"); var icon = core.material.icons.hero[options.heroLoc.direction]; var height = core.material.images.images[options.heroIcon].height/4; tempCanvas.drawImage(core.material.images.images[options.heroIcon], icon.stop * 32, icon.loc * height, 32, height, diff --git a/libs/ui.js b/libs/ui.js index 0ea67f59..d7a6f361 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1602,7 +1602,8 @@ ui.prototype.drawFly = function(page) { core.fillText('ui', '▼', 356, 247 + 96 + 7, '#FFFFFF', "17px "+globalFont); } core.strokeRect('ui', 20, 100, 273, 273, '#FFFFFF', 2); - this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 20, 100, 273); + + core.drawThumbnail(floorId, null, null, {ctx: 'ui', x: 20, y: 100, size: 273}); } ////// 绘制浏览地图界面 ////// @@ -1681,7 +1682,7 @@ ui.prototype.drawMaps = function (index, x, y) { clearTimeout(core.interval.tipAnimate); core.clearLastEvent(); core.status.checkBlock.cache = {}; - this.drawThumbnail(floorId, 'ui', core.status.maps[floorId].blocks, 0, 0, 416, x, y); + core.drawThumbnail(floorId, null, {damage: damage}, {ctx: 'ui', centerX: x, centerY: y, all: all}); // 绘图 if (core.status.event.data.paint) { @@ -2088,7 +2089,11 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 30, '#FFFFFF', "bold 17px "+globalFont); core.strokeRect('ui', (2*i+1)*u-size/2, 45, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { - core.ui.drawThumbnail(data.floorId, 'ui', core.maps.loadMap(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 45, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); + core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { + heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, flags: data.hero.flags + }, { + ctx: 'ui', x: (2*i+1)*u-size/2, y: 45, size: size, centerX: data.hero.loc.x, centerY: data.hero.loc.y + }); var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; @@ -2104,7 +2109,11 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.fillText('ui', name+id, (2*i-5)*u, 218, '#FFFFFF', "bold 17px "+globalFont); core.strokeRect('ui', (2*i-5)*u-size/2, 233, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); if (core.isset(data) && core.isset(data.floorId)) { - core.ui.drawThumbnail(data.floorId, 'ui', core.maps.loadMap(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 233, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); + core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { + heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, flags: data.hero.flags + }, { + ctx: 'ui', x: (2*i-5)*u-size/2, y: 233, size: size, centerX: data.hero.loc.x, centerY: data.hero.loc.y + }); var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; @@ -2157,12 +2166,6 @@ ui.prototype.drawSLPanel = function(index, refresh) { else drawAll(); } -////// 绘制一个缩略图 ////// -ui.prototype.drawThumbnail = function(floorId, canvas, blocks, x, y, size, centerX, centerY, heroLoc, heroIcon) { - core.drawThumbnail(floorId, blocks, {heroLoc: heroLoc, heroIcon: heroIcon}, - {ctx: canvas, x: x, y: y, size: size, centerX: centerX, centerY: centerY}); -} - ui.prototype.drawKeyBoard = function () { core.lockControl(); core.status.event.id = 'keyBoard'; diff --git a/project/functions.js b/project/functions.js index 63fd72ee..0b5234c1 100644 --- a/project/functions.js +++ b/project/functions.js @@ -191,7 +191,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 检查equipAnimate是否存在SE,如果不存在则使用默认音效 if (!core.isset((core.material.animates[equipAnimate] || {}).se)) core.playSound('attack.mp3'); - core.drawAnimate(equipAnimate, x, y); + // 强制战斗的战斗动画 + core.drawAnimate(equipAnimate, core.isset(x)?x:core.getHeroLoc('x'), core.isset(y)?y:core.getHeroLoc('y')); var damage = core.enemys.getDamage(enemyId, x, y); if (damage == null) damage = core.status.hero.hp + 1; @@ -1017,12 +1018,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 更新全地图显伤 core.updateDamage(); }, - "updateCheckBlock": function () { + "updateCheckBlock": function (floorId) { // 领域、夹击、阻击等的伤害值计算 + floorId = floorId || core.status.floorId; + if (!core.isset(floorId) || !core.isset(core.status.maps)) return; + var blocks = core.status.maps[floorId].blocks; + var width = core.floors[floorId].width, height = core.floors[floorId].height; core.status.checkBlock = {}; - if (!core.isset(core.status.thisMap)) return; - var blocks = core.status.thisMap.blocks; // Step1: 更新怪物地图 core.status.checkBlock.map = []; // 记录怪物地图 @@ -1032,29 +1035,29 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var id = block.event.id, enemy = core.material.enemys[id]; if (core.isset(enemy)) { - core.status.checkBlock.map[block.x + core.bigmap.width * block.y] = id; + core.status.checkBlock.map[block.x + width * block.y] = id; } } // 血网 if (core.isset(block.event) && !block.disable && block.event.id == 'lavaNet' && block.event.trigger == 'passNet' && !core.hasItem("shoes")) { - core.status.checkBlock.map[block.x + core.bigmap.width * block.y] = "lavaNet"; + core.status.checkBlock.map[block.x + width * block.y] = "lavaNet"; } } // Step2: 更新领域、阻击伤害 - core.status.checkBlock.damage = []; // 记录(x,y)点的伤害;(x,y)对应的值是 x+core.bigmap.width*y - for (var x = 0; x < core.bigmap.width * core.bigmap.height; x++) core.status.checkBlock.damage[x] = 0; + core.status.checkBlock.damage = []; // 记录(x,y)点的伤害;(x,y)对应的值是 x+width*y + for (var x = 0; x < width * height; x++) core.status.checkBlock.damage[x] = 0; core.status.checkBlock.ambush = []; - for (var x = 0; x < core.bigmap.width; x++) { - for (var y = 0; y < core.bigmap.height; y++) { - var id = core.status.checkBlock.map[x + core.bigmap.width * y]; + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { + var id = core.status.checkBlock.map[x + width * y]; if (core.isset(id)) { // 如果是血网,直接加上伤害值 if (id == "lavaNet") { - core.status.checkBlock.damage[x + core.bigmap.width * y] += core.values.lavaDamage || 0; + core.status.checkBlock.damage[x + width * y] += core.values.lavaDamage || 0; continue; } @@ -1073,10 +1076,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (dx == 0 && dy == 0) continue; var nx = x + dx, ny = y + dy; - if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) continue; + if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; // 如果是十字领域,则还需要满足 |dx|+|dy|<=range if (!zoneSquare && Math.abs(dx) + Math.abs(dy) > range) continue; - core.status.checkBlock.damage[nx + ny * core.bigmap.width] += enemy.value || 0; + core.status.checkBlock.damage[nx + ny * width] += enemy.value || 0; } } } @@ -1084,11 +1087,11 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果要防止激光伤害,可以直接简单的将 flag:no_laser 设为true if (core.enemys.hasSpecial(enemy.special, 24) && !core.hasFlag("no_laser")) { // 检查同行和同列,增加激光伤害值 - for (var nx = 0; nx < core.bigmap.width; nx++) { - if (nx != x) core.status.checkBlock.damage[nx + y * core.bigmap.width] += enemy.value || 0; + for (var nx = 0; nx < width; nx++) { + if (nx != x) core.status.checkBlock.damage[nx + y * width] += enemy.value || 0; } - for (var ny = 0; ny < core.bigmap.height; ny++) { - if (ny != y) core.status.checkBlock.damage[x + ny * core.bigmap.width] += enemy.value || 0; + for (var ny = 0; ny < height; ny++) { + if (ny != y) core.status.checkBlock.damage[x + ny * width] += enemy.value || 0; } } // 存在阻击 @@ -1099,8 +1102,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (dx == 0 && dy == 0) continue; var nx = x + dx, ny = y + dy; - if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height || Math.abs(dx) + Math.abs(dy) > 1) continue; - core.status.checkBlock.damage[nx + ny * core.bigmap.width] += enemy.value || 0; + if (nx < 0 || nx >= width || ny < 0 || ny >= height || Math.abs(dx) + Math.abs(dy) > 1) continue; + core.status.checkBlock.damage[nx + ny * width] += enemy.value || 0; } } } @@ -1110,10 +1113,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = for (var dir in core.utils.scan) { var nx = x + core.utils.scan[dir].x, ny = y + core.utils.scan[dir].y; - if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) continue; - if (!core.isset(core.status.checkBlock.ambush[nx + ny * core.bigmap.width])) - core.status.checkBlock.ambush[nx + ny * core.bigmap.width] = []; - core.status.checkBlock.ambush[nx + ny * core.bigmap.width].push([x, y, id, dir]); + if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; + if (!core.isset(core.status.checkBlock.ambush[nx + ny * width])) + core.status.checkBlock.ambush[nx + ny * width] = []; + core.status.checkBlock.ambush[nx + ny * width].push([x, y, id, dir]); } } } @@ -1124,14 +1127,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.checkBlock.betweenAttack = []; // 记录(x,y)点是否有夹击 // 如果要防止夹击伤害,可以简单的将 flag:no_betweenAttack 设为true if (!core.hasFlag('no_betweenAttack')) { - for (var x = 0; x < core.bigmap.width; x++) { - for (var y = 0; y < core.bigmap.height; y++) { + for (var x = 0; x < width; x++) { + for (var y = 0; y < height; y++) { // 该点是否存在夹击 var has = false; // 检测左右是否存在相同的怪物,且拥有夹击属性 - if (x > 0 && x < core.bigmap.width - 1) { - var id1 = core.status.checkBlock.map[x - 1 + core.bigmap.width * y], - id2 = core.status.checkBlock.map[x + 1 + core.bigmap.width * y]; + if (x > 0 && x < width - 1) { + var id1 = core.status.checkBlock.map[x - 1 +width * y], + id2 = core.status.checkBlock.map[x + 1 + width * y]; if (core.isset(id1) && core.isset(id2) && id1 == id2) { var enemy = core.material.enemys[id1]; if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { @@ -1140,9 +1143,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } // 检测上下是否存在相同的怪物,且拥有夹击属性 - if (y > 0 && y < core.bigmap.height - 1) { - var id1 = core.status.checkBlock.map[x + core.bigmap.width * (y - 1)], - id2 = core.status.checkBlock.map[x + core.bigmap.width * (y + 1)]; + if (y > 0 && y < height - 1) { + var id1 = core.status.checkBlock.map[x + width * (y - 1)], + id2 = core.status.checkBlock.map[x + width * (y + 1)]; if (core.isset(id1) && core.isset(id2) && id1 == id2) { var enemy = core.material.enemys[id1]; if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { @@ -1152,12 +1155,12 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 计算夹击伤害 if (has) { - core.status.checkBlock.betweenAttack[x + core.bigmap.width * y] = true; + core.status.checkBlock.betweenAttack[x + width * y] = true; // 先扣除该点领域/阻击/激光造成的伤害,再算夹击 - var leftHp = core.status.hero.hp - core.status.checkBlock.damage[x + core.bigmap.width * y]; + var leftHp = core.status.hero.hp - core.status.checkBlock.damage[x + width * y]; // 1血不夹;core.flags.betweenAttackCeil控制向上还是向下 if (leftHp > 1) - core.status.checkBlock.damage[x + core.bigmap.width * y] += Math.floor((leftHp + (core.flags.betweenAttackCeil ? 0 : 1)) / 2); + core.status.checkBlock.damage[x + width * y] += Math.floor((leftHp + (core.flags.betweenAttackCeil ? 0 : 1)) / 2); } } } From 6a22e27e09486560db9ea7fad239e572806ab0e9 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 14 Mar 2019 22:22:18 +0800 Subject: [PATCH 007/153] Adjust order --- libs/actions.js | 12 ++--- libs/enemys.js | 86 ++++++++++++++++----------------- libs/items.js | 124 ++++++++++++++++++++++++------------------------ libs/loader.js | 52 ++++++++++---------- libs/utils.js | 118 ++++++++++++++++++++++----------------------- 5 files changed, 196 insertions(+), 196 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 87bedddf..00650fe4 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -395,7 +395,7 @@ actions.prototype.ondown = function (loc) { actions.prototype._sys_ondown_paint = function (x, y, px, py) { // 画板 if (core.status.played && (core.status.event || {}).id == 'paint') { - this.ondownPaint(px, py); + this._ondownPaint(px, py); return true; } } @@ -452,7 +452,7 @@ actions.prototype.onmove = function (loc) { actions.prototype._sys_onmove_paint = function (x, y, px, py) { // 画板 if (core.status.played && (core.status.event || {}).id == 'paint') { - this.onmovePaint(px, py); + this._onmovePaint(px, py); return true; } } @@ -488,7 +488,7 @@ actions.prototype.onup = function () { actions.prototype._sys_onup_paint = function () { // 画板 if (core.status.played && (core.status.event || {}).id == 'paint') { - this.onupPaint(); + this._onupPaint(); return true; } } @@ -2327,7 +2327,7 @@ actions.prototype._keyUpCursor = function (keycode) { ////// 绘图相关 ////// -actions.prototype.ondownPaint = function (x, y) { +actions.prototype._ondownPaint = function (x, y) { x+=core.bigmap.offsetX; y+=core.bigmap.offsetY; if (!core.status.event.data.erase) { @@ -2338,7 +2338,7 @@ actions.prototype.ondownPaint = function (x, y) { core.status.event.data.y = y; } -actions.prototype.onmovePaint = function (x, y) { +actions.prototype._onmovePaint = function (x, y) { if (core.status.event.data.x==null) return; x+=core.bigmap.offsetX; y+=core.bigmap.offsetY; @@ -2353,7 +2353,7 @@ actions.prototype.onmovePaint = function (x, y) { core.status.event.data.y = y; } -actions.prototype.onupPaint = function () { +actions.prototype._onupPaint = function () { core.status.event.data.x = null; core.status.event.data.y = null; // 保存 diff --git a/libs/enemys.js b/libs/enemys.js index ba2ce156..c6ea882c 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -47,15 +47,6 @@ enemys.prototype.getSpecials = function () { return this.enemydata.getSpecials(); } -enemys.prototype._calSpecialContent = function (enemy, content) { - if (typeof content == 'string') return content; - if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - if (content instanceof Function) { - return content(enemy); - } - return ""; -} - ////// 获得所有特殊属性的名称 ////// enemys.prototype.getSpecialText = function (enemy) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; @@ -95,6 +86,15 @@ enemys.prototype.getSpecialHint = function (enemy, special) { return ""; } +enemys.prototype._calSpecialContent = function (enemy, content) { + if (typeof content == 'string') return content; + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; + if (content instanceof Function) { + return content(enemy); + } + return ""; +} + ////// 能否获胜 ////// enemys.prototype.canBattle = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; @@ -155,6 +155,40 @@ enemys.prototype.getDamageString = function (enemy, x, y, floorId) { }; } +////// 接下来N个临界值和临界减伤计算 ////// +enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { + if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; + number = number||1; + + if (this.hasSpecial(enemy.special, 10)) return []; // 模仿怪物临界 + var info = this.getDamageInfo(enemy, null, x, y, floorId); + if (info == null || this.hasSpecial(enemy.special, 3)) { // 未破防,或是坚固怪 + info = this.getEnemyInfo(enemy, null, x, y, floorId); + if (core.status.hero.atk<=info.def) { + return [[info.def+1-core.status.hero.atk,'?']]; + } + return []; + } + + // getDamageInfo直接返回数字;0伤且无负伤 + if (typeof info == 'number' || (info.damage<=0 && !core.flags.enableNegativeDamage)) { + return [[0,0]]; + } + + if (core.flags.useLoop) { + var LOOP_MAX_VALUE = 1; + if (core.status.hero.atk <= LOOP_MAX_VALUE) { + return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId); + } + else { + return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId); + } + } + else { + return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId); + } +} + enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, floorId) { var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, pre = info.damage; var list = []; @@ -225,40 +259,6 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f return list; } -////// 接下来N个临界值和临界减伤计算 ////// -enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { - if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - number = number||1; - - if (this.hasSpecial(enemy.special, 10)) return []; // 模仿怪物临界 - var info = this.getDamageInfo(enemy, null, x, y, floorId); - if (info == null || this.hasSpecial(enemy.special, 3)) { // 未破防,或是坚固怪 - info = this.getEnemyInfo(enemy, null, x, y, floorId); - if (core.status.hero.atk<=info.def) { - return [[info.def+1-core.status.hero.atk,'?']]; - } - return []; - } - - // getDamageInfo直接返回数字;0伤且无负伤 - if (typeof info == 'number' || (info.damage<=0 && !core.flags.enableNegativeDamage)) { - return [[0,0]]; - } - - if (core.flags.useLoop) { - var LOOP_MAX_VALUE = 1; - if (core.status.hero.atk <= LOOP_MAX_VALUE) { - return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId); - } - else { - return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId); - } - } - else { - return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId); - } -} - ////// N防减伤计算 ////// enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; diff --git a/libs/items.js b/libs/items.js index ec445a3c..708acd6a 100644 --- a/libs/items.js +++ b/libs/items.js @@ -61,6 +61,21 @@ items.prototype.getItemEffectTip = function(itemId) { return ""; } +////// 使用道具 ////// +items.prototype.useItem = function (itemId, noRoute, callback) { + if (!this.canUseItem(itemId)) { + if (core.isset(callback)) callback(); + return; + } + // 执行道具效果 + this._useItemEffect(itemId); + // 执行完毕 + this._afterUseItem(itemId); + // 记录路线 + if (!noRoute) core.status.route.push("item:"+itemId); + if (core.isset(callback)) callback(); +} + items.prototype._useItemEffect = function (itemId) { if (itemId in this.useItemEffect) { try { @@ -88,21 +103,6 @@ items.prototype._afterUseItem = function (itemId) { core.updateStatusBar(); } -////// 使用道具 ////// -items.prototype.useItem = function (itemId, noRoute, callback) { - if (!this.canUseItem(itemId)) { - if (core.isset(callback)) callback(); - return; - } - // 执行道具效果 - this._useItemEffect(itemId); - // 执行完毕 - this._afterUseItem(itemId); - // 记录路线 - if (!noRoute) core.status.route.push("item:"+itemId); - if (core.isset(callback)) callback(); -} - ////// 当前能否使用道具 ////// items.prototype.canUseItem = function (itemId) { // 没有道具 @@ -266,53 +266,6 @@ items.prototype.canEquip = function (equipId, hint) { return true; } -////// 实际换装的效果 ////// -items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentage) { - // 比较能力值 - var result = core.compareEquipment(equipId, unloadEquipId); - - if (isPercentage) { - for (var v in result) - core.addFlag('__'+v+'_buff__', result[v]/100); - } - else { - for (var v in result) - core.status.hero[v] += result[v]; - } -} - -items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { - var loadEquip = core.material.items[loadId] || {}, unloadEquip = core.material.items[unloadId] || {}; - if (!core.isset(loadEquip.equip)) loadEquip.equip = {}; - if (!core.isset(unloadEquip.equip)) unloadEquip.equip = {}; - - var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage; - - if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) { - this.unloadEquip(type); - this.loadEquip(loadId); - if (core.isset(callback)) callback(); - return; - } - - // --- 音效 - core.playSound('equip.mp3'); - - // --- 实际换装 - this._loadEquipEffect(loadId, unloadId, loadPercentage==null?unloadPercentage:loadPercentage); - - // --- 加减 - if (loadId) core.removeItem(loadId); - if (unloadId) core.addItem(unloadId); - core.status.hero.equipment[type] = loadId||null; - - // --- 提示 - if (loadId) core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[loadId]); - else if (unloadId) core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadId]); - - if (core.isset(callback)) callback(); -} - ////// 换上 ////// items.prototype.loadEquip = function (equipId, callback) { if (!core.isset(core.status.hero)) return null; @@ -364,6 +317,53 @@ items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) return {"atk":compareAtk,"def":compareDef,"mdef":compareMdef}; } +////// 实际换装的效果 ////// +items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentage) { + // 比较能力值 + var result = core.compareEquipment(equipId, unloadEquipId); + + if (isPercentage) { + for (var v in result) + core.addFlag('__'+v+'_buff__', result[v]/100); + } + else { + for (var v in result) + core.status.hero[v] += result[v]; + } +} + +items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { + var loadEquip = core.material.items[loadId] || {}, unloadEquip = core.material.items[unloadId] || {}; + if (!core.isset(loadEquip.equip)) loadEquip.equip = {}; + if (!core.isset(unloadEquip.equip)) unloadEquip.equip = {}; + + var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage; + + if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) { + this.unloadEquip(type); + this.loadEquip(loadId); + if (core.isset(callback)) callback(); + return; + } + + // --- 音效 + core.playSound('equip.mp3'); + + // --- 实际换装 + this._loadEquipEffect(loadId, unloadId, loadPercentage==null?unloadPercentage:loadPercentage); + + // --- 加减 + if (loadId) core.removeItem(loadId); + if (unloadId) core.addItem(unloadId); + core.status.hero.equipment[type] = loadId||null; + + // --- 提示 + if (loadId) core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[loadId]); + else if (unloadId) core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadId]); + + if (core.isset(callback)) callback(); +} + ////// 保存装备 ////// items.prototype.quickSaveEquip = function (index) { if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; diff --git a/libs/loader.js b/libs/loader.js index 337c199a..4449c64e 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -13,12 +13,12 @@ loader.prototype._init = function () { } ////// 设置加载进度条进度 ////// -loader.prototype.setStartProgressVal = function (val) { +loader.prototype._setStartProgressVal = function (val) { core.dom.startTopProgress.style.width = val + '%'; } ////// 设置加载进度条提示文字 ////// -loader.prototype.setStartLoadTipText = function (text) { +loader.prototype._setStartLoadTipText = function (text) { core.dom.startTopLoadTips.innerHTML = text; } @@ -106,10 +106,10 @@ loader.prototype.loadImages = function (names, toSave, callback) { var items = 0; for (var i=0;i0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + cnt=0; + } + lastMove=t; + cnt++; + } + else { + if (cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + cnt=0; + } + ans += core.utils._encodeRoute_encodeOne(t); + } + }); + if (cnt>0) { + ans+=lastMove.substring(0,1).toUpperCase(); + if (cnt>1) ans+=cnt; + } + return LZString.compressToBase64(ans); +} + utils.prototype._encodeRoute_id2number = function (id) { var number = core.maps.getNumberById(id); return number==0?id:number; @@ -436,34 +466,23 @@ utils.prototype._encodeRoute_encodeOne = function (t) { return ''; } -////// 加密路线 ////// -utils.prototype.encodeRoute = function (route) { - var ans="", lastMove = "", cnt=0; +////// 解密路线 ////// +utils.prototype.decodeRoute = function (route) { + if (!core.isset(route)) return route; - route.forEach(function (t) { - if (t=='up' || t=='down' || t=='left' || t=='right') { - if (t!=lastMove && cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; - cnt=0; - } - lastMove=t; - cnt++; + // 解压缩 + try { + var v = LZString.decompressFromBase64(route); + if (core.isset(v) && /^[a-zA-Z0-9+\/=:]*$/.test(v)) { + route = v; } - else { - if (cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; - cnt=0; - } - ans += core.utils._encodeRoute_encodeOne(t); - } - }); - if (cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; + } catch (e) {} + + var decodeObj = {route: route, index: 0, ans: []}; + while (decodeObj.index < decodeObj.route.length) { + this._decodeRoute_decodeOne(decodeObj, decodeObj.route.charAt(decodeObj.index++)); } - return LZString.compressToBase64(ans); + return decodeObj.ans; } utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) { @@ -518,25 +537,6 @@ utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { } } -////// 解密路线 ////// -utils.prototype.decodeRoute = function (route) { - if (!core.isset(route)) return route; - - // 解压缩 - try { - var v = LZString.decompressFromBase64(route); - if (core.isset(v) && /^[a-zA-Z0-9+\/=:]*$/.test(v)) { - route = v; - } - } catch (e) {} - - var decodeObj = {route: route, index: 0, ans: []}; - while (decodeObj.index < decodeObj.route.length) { - this._decodeRoute_decodeOne(decodeObj, decodeObj.route.charAt(decodeObj.index++)); - } - return decodeObj.ans; -} - ////// 判断某对象是否不为undefined也不会null ////// utils.prototype.isset = function (val) { if (val == undefined || val == null || (typeof val=='number' && isNaN(val))) { @@ -624,21 +624,6 @@ utils.prototype.convertBase = function (str, fromBase, toBase) { return ans; } -utils.prototype.__init_seed = function () { - var rand = new Date().getTime()%34834795 + 3534; - rand = this.__next_rand(rand); - rand = this.__next_rand(rand); - rand = this.__next_rand(rand); - core.setFlag('__seed__', rand); - core.setFlag('__rand__', rand); -} - -utils.prototype.__next_rand = function (_rand) { - _rand=(_rand%127773)*16807-~~(_rand/127773)*2836; - _rand+=_rand<0?2147483647:0; - return _rand; -} - utils.prototype.rand = function (num) { var rand = core.getFlag('__rand__'); rand = this.__next_rand(rand); @@ -672,6 +657,21 @@ utils.prototype.rand2 = function (num) { return value; } +utils.prototype.__init_seed = function () { + var rand = new Date().getTime()%34834795 + 3534; + rand = this.__next_rand(rand); + rand = this.__next_rand(rand); + rand = this.__next_rand(rand); + core.setFlag('__seed__', rand); + core.setFlag('__rand__', rand); +} + +utils.prototype.__next_rand = function (_rand) { + _rand=(_rand%127773)*16807-~~(_rand/127773)*2836; + _rand+=_rand<0?2147483647:0; + return _rand; +} + ////// 读取一个本地文件内容 ////// utils.prototype.readFile = function (success, error, readType) { From 198f59296229b45f1bddb4f8116304e641629f58 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 15 Mar 2019 16:39:40 +0800 Subject: [PATCH 008/153] drawTextBox \f 8 parameters --- _docs/event.md | 5 +++-- libs/ui.js | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 86f93c9e..700a835f 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -255,7 +255,7 @@ 从V2.5.3以后,也可以使用`\f[...]`来同时绘制一张图片。 -其基本写法是`\f[图片名,起始x像素,起始y像素]`,或者`\f[图片名,起始x像素,起始y像素,绘制宽度,绘制高度]`。 +其基本写法是`\f[img,x,y]`,或者`\f[img,x,y,w,h]`,或者`\f[img,sx,sy,sw,sh,x,y,w,h]`。 需要注意的是,这个图片是绘制在UI层上的,下一个事件执行时即会擦除;同时如果使用了\t的图标动画效果,重叠的地方也会被图标动画给覆盖掉。 @@ -263,7 +263,8 @@ "x,y": [ // 实际执行的事件列表 "\t[勇士]\b[up,hero]\f[1.png,100,100]以(100,100)为左上角绘制1.png图片", "\t[hero]\f[1.png,100,100]\f[2.png,300,300]同时绘制了两张图片", - "\f[1.png,100,100,300,300]也可以填写宽高,这样会把图片强制进行放缩到指定的宽高值" + "\f[1.png,100,100,300,300]也可以填写宽高,这样会把图片强制进行放缩到指定的宽高值", + "\f[1.png,64,64,128,128,100,100,128,128]裁剪1.png上以(64,64)开始的128x128图片,并绘制到画布的(100,100)处" ] ``` diff --git a/libs/ui.js b/libs/ui.js index d7a6f361..e5c746bb 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -686,14 +686,16 @@ ui.prototype.drawTextBox = function(content, showAll) { // drawImage content = content.replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { var ss = str.split(","); - if (ss.length!=3 && ss.length!=5) return ""; + if (ss.length!=3 && ss.length!=5 && ss.length!=9) return ""; var img = core.material.images.images[ss[0]]; if (!core.isset(img)) return ""; // 绘制 if (ss.length==3) core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2])); - else + else if (ss.length=5) core.drawImage('ui', img, 0, 0, img.width, img.height, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4])); + else if (ss.length==9) + core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4]), parseFloat(ss[5]), parseFloat(ss[6]), parseFloat(ss[7]), parseFloat(ss[8])); return ""; }); From 17240b21e44935c9493164b1f61ef0a98f078f4e Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Fri, 15 Mar 2019 16:51:00 +0800 Subject: [PATCH 009/153] drawTextBox \f 8 parameters --- libs/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui.js b/libs/ui.js index e5c746bb..c242e448 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -692,7 +692,7 @@ ui.prototype.drawTextBox = function(content, showAll) { // 绘制 if (ss.length==3) core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2])); - else if (ss.length=5) + else if (ss.length==5) core.drawImage('ui', img, 0, 0, img.width, img.height, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4])); else if (ss.length==9) core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4]), parseFloat(ss[5]), parseFloat(ss[6]), parseFloat(ss[7]), parseFloat(ss[8])); From 182194702a0544a76ca2df88973b48ed26fc8dea Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 15 Mar 2019 22:37:58 +0800 Subject: [PATCH 010/153] system events --- libs/core.js | 1 - libs/events.js | 1033 +++++++++++++++++++++++++----------------------- 2 files changed, 537 insertions(+), 497 deletions(-) diff --git a/libs/core.js b/libs/core.js index a878e84c..b314eebc 100644 --- a/libs/core.js +++ b/libs/core.js @@ -241,7 +241,6 @@ core.prototype.init = function (coreData, callback) { core.material.items = core.items.getItems(); core.material.enemys = core.enemys.getEnemys(); core.material.icons = core.icons.getIcons(); - core.material.events = core.events.getEvents(); core.platform.isOnline = location.protocol.indexOf("http")==0; if (core.platform.isOnline) { diff --git a/libs/events.js b/libs/events.js index d4e549e9..31da99ba 100644 --- a/libs/events.js +++ b/libs/events.js @@ -8,79 +8,12 @@ function events() { events.prototype._init = function () { this.eventdata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.events; this.commonEvent = events_c12a15a8_c380_4b28_8144_256cba95f760.commonEvent; - this.events = { - 'battle': function (data, callback) { - core.battle(data.event.id, data.x, data.y); - if (core.isset(callback)) - callback(); - }, - 'getItem': function (data, callback) { - core.getItem(data.event.id, 1, data.x, data.y); - if (core.isset(callback)) - callback(); - }, - 'openDoor': function (data, callback) { - core.openDoor(data.event.id, data.x, data.y, true, function () { - if (core.isset(callback)) callback(); - }); - }, - 'changeFloor': function (data, callback) { - var heroLoc = {}; - if (core.isset(data.event.data.loc)) - heroLoc = {'x': data.event.data.loc[0], 'y': data.event.data.loc[1]}; - if (core.isset(data.event.data.direction)) - heroLoc.direction = data.event.data.direction; - if (core.status.event.id!='action') core.status.event.id=null; - core.changeFloor(data.event.data.floorId, data.event.data.stair, - heroLoc, data.event.data.time, function () { - if (core.isset(callback)) callback(); - }); - }, - 'passNet': function (data, callback) { - core.events.passNet(data); - if (core.isset(callback)) - callback(); - }, - "changeLight": function (data, callback) { - core.events.changeLight(data.x, data.y); - if (core.isset(callback)) - callback(); - }, - "ski": function (data, callback) { - core.events.ski(); - if (core.isset(callback)) - callback(); - }, - "pushBox": function (data, callback) { - core.events.pushBox(data); - if (core.isset(callback)) - callback(); - }, - 'action': function (data, callback) { - var ev = core.clone(data.event.data), ex = data.x, ey = data.y; - // 检查是否需要改变朝向 - if (ex == core.nextX() && ey == core.nextY()) { - var dir = {"up":"down","down":"up","left":"right","right":"left"}[core.getHeroLoc('direction')]; - var id = data.event.id, toId = (data.event.faceIds||{})[dir]; - if (core.isset(toId) && id!=toId) { - var number = core.icons.getNumberById(toId); - if (number>0) - core.setBlock(number, ex, ey); - } - } - core.events.insertAction(ev, ex, ey, callback); - } - } -} - -////// 获得一个或所有系统事件类型 ////// -events.prototype.getEvents = function (eventName) { - if (!core.isset(eventName)) { - return this.events; - } - return this.events[eventName]; + this.systemEvents = {}; + this.actions = {}; } +// ------ 初始化,开始和结束 ------ // +/// events.prototype.initGame = function () { return this.eventdata.initGame(); } @@ -142,7 +75,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { if (core.flags.startUsingCanvas) { core.control.triggerStatusBar('hide'); core.dom.musicBtn.style.display = 'block'; - + core.insertAction(core.clone(core.firstData.startCanvas), null, null, function() { real_start(); }); @@ -340,12 +273,536 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { } +// ------ 系统事件的处理 ------ // + +////// 注册一个系统事件 ////// +// type为事件名,func为事件的处理函数,可接受(data, callback)参数 +events.prototype.registerSystemEvent = function (type, func) { + this.systemEvents[type] = func; +} + +////// 注销一个系统事件 ////// +events.prototype.unregisterSystemEvent = function (type) { + delete this.systemEvents[type]; +} + +////// 执行一个系统事件 ////// +events.prototype.doSystemEvent = function (type, data, callback) { + if (this.systemEvents[type]) this.systemEvents[type](data, callback); + else if (this["_sys_"+type]) this["_sys_"+type](data, callback); + else { + main.log("未知的系统事件: "+type+"!"); + if (callback) callback(); + } +} + +////// 触发(x,y)点的事件 ////// +events.prototype.trigger = function (x, y) { + + if (core.status.event.id == 'action') return; + + core.status.isSkiing = false; + var block = core.getBlock(x, y); + if (block != null) { + block = block.block; + if (core.isset(block.event) && core.isset(block.event.trigger)) { + var noPass = block.event.noPass, trigger = block.event.trigger; + if (noPass) { + core.clearAutomaticRouteNode(x, y); + } + if (trigger == 'ski') core.status.isSkiing = true; + + // 转换楼层能否穿透 + if (trigger=='changeFloor' && !noPass) { + var canCross = core.flags.portalWithoutTrigger; + if (core.isset(block.event.data) && core.isset(block.event.data.portalWithoutTrigger)) + canCross=block.event.data.portalWithoutTrigger; + if (canCross) { + if (core.isReplaying()) { + if (core.status.replay.toReplay[0]=='no') { + core.status.replay.toReplay.shift(); + core.status.route.push("no"); + return; + } + } + else if (core.status.automaticRoute.autoHeroMove || core.status.automaticRoute.autoStep=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; + } + core.stopHero(); + core.stopAutomaticRoute(); + + if (!core.isset(id)) id = core.getBlockId(x, y); + if (!core.isset(id)) { + if (core.isset(callback)) callback(); + return; + } + + // 非强制战斗 + if (!core.enemys.canBattle(id, x, y) && !force && !core.isset(core.status.event.id)) { + core.drawTip("你打不过此怪物!"); + core.clearContinueAutomaticRoute(); + if (core.isset(callback)) callback(); + return; + } + + if (!core.isset(core.status.event.id)) // 自动存档 + core.autosave(true); + + // ------ 支援技能 ------// + if (core.isset(x) && core.isset(y)) { + var index = x + "," + y, cache = (core.status.checkBlock.cache || {})[index] || {}, + guards = cache.guards || []; + if (guards.length>0) { + core.setFlag("__guards__"+x+"_"+y, guards); + var actions = []; + guards.forEach(function (g) { + core.push(actions, {"type": "jump", "from": [g[0],g[1]], "to": [x, y], + "time": 300, "keep": false, "async": true}); + }) + core.push(actions, [ + {"type": "waitAsync"}, + {"type": "trigger", "loc": [x,y]} + ]); + core.insertAction(actions); + return; + } + } + + core.events.afterBattle(id, x, y, callback); +} + +////// 战斗结束后触发的事件 ////// +events.prototype.afterBattle = function (enemyId, x , y,callback) { + return this.eventdata.afterBattle(enemyId,x,y,callback); +} + +events.prototype._sys_getItem = function (data, callback) { + this.getItem(data.event.id, 1, data.x, data.y, callback); +} + +////// 获得某个物品 ////// +events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { + itemNum=itemNum||1; + var itemCls = core.material.items[itemId].cls; + core.items.getItemEffect(itemId, itemNum); + core.removeBlock(itemX, itemY); + var text = '获得 ' + core.material.items[itemId].name; + if (itemNum > 1) text += "x" + itemNum; + if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); + core.drawTip(text, core.material.icons.items[itemId]); + core.updateStatusBar(); + + this.eventdata.afterGetItem(itemId, itemX, itemY, callback); +} + +////// 获得面前的物品(轻按) ////// +events.prototype.getNextItem = function() { + if (!core.status.heroStop || !core.flags.enableGentleClick) return false; + + if (!core.canMoveHero()) return false; + + var nextX = core.nextX(), nextY = core.nextY(); + var block = core.getBlock(nextX, nextY); + if (block==null) return false; + if (block.block.event.trigger=='getItem') { + core.getItem(block.block.event.id, 1, nextX, nextY); + core.status.route.push("getNext"); + return true; + } + return false; +} + +events.prototype._sys_openDoor = function (data, callback) { + this.openDoor(data.event.id, data.x, data.y, true, callback); +} + +////// 开门 ////// +events.prototype.openDoor = function (id, x, y, needKey, callback) { + if (!core.isset(id)) id = core.getBlockId(x, y); + + // 是否存在门 + if (!core.terrainExists(x, y, id) || !(id.endsWith("Door") || id.endsWith("Wall")) + || !core.isset(core.material.icons.animates[id])) { + return false; + } + if (core.status.automaticRoute.moveStepBeforeStop.length==0) { + core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); + if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; + } + + var speed = id.endsWith("Wall")?70:30; + + if (needKey && id.endsWith("Door")) { + var key = id.replace("Door", "Key"); + if (!core.hasItem(key)) { + if (key != "specialKey") + core.drawTip("你没有" + ((core.material.items[key]||{}).name||"钥匙")); + else core.drawTip("无法开启此门"); + core.clearContinueAutomaticRoute(); + return false; + } + core.autosave(true); + core.removeItem(key); + } + + // open + core.playSound("door.mp3"); + var state = 0; + var door = core.material.icons.animates[id]; + + core.lockControl(); + core.stopHero(); + core.stopAutomaticRoute(); + core.status.replay.animate=true; + core.removeGlobalAnimate(x,y); + var animate = window.setInterval(function () { + state++; + if (state == 4) { + clearInterval(animate); + core.removeBlock(x, y); + core.unLockControl(); + core.status.replay.animate=false; + core.events.afterOpenDoor(id,x,y,callback); + return; + } + core.clearMap('event', 32 * x, 32 * y, 32, 32); + core.drawImage('event', core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); + }, speed / core.status.replay.speed); + + return true; +} + +////// 开一个门后触发的事件 ////// +events.prototype.afterOpenDoor = function (doorId, x, y, callback) { + return this.eventdata.afterOpenDoor(doorId,x,y,callback); +} + +events.prototype._sys_changeFloor = function (data, callback) { + var heroLoc = {}; + if (core.isset(data.event.data.loc)) + heroLoc = {'x': data.event.data.loc[0], 'y': data.event.data.loc[1]}; + if (core.isset(data.event.data.direction)) + heroLoc.direction = data.event.data.direction; + if (core.status.event.id!='action') core.status.event.id=null; + core.changeFloor(data.event.data.floorId, data.event.data.stair, + heroLoc, data.event.data.time, callback); +} + +////// 楼层切换 ////// +events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, fromLoad) { + + floorId = floorId || core.status.floorId; + if (!core.isset(floorId)) { + if (core.isset(callback)) callback(); + return; + } + + if (floorId == ':before') { + var index=core.floorIds.indexOf(core.status.floorId); + if (index>0) floorId = core.floorIds[index-1]; + else floorId=core.status.floorId; + } + else if (floorId == ':next') { + var index=core.floorIds.indexOf(core.status.floorId); + if (index=100 && !core.isReplaying(); + + time /= 20; + core.lockControl(); + core.stopHero(); + core.stopAutomaticRoute(); + core.clearContinueAutomaticRoute(); + core.status.replay.animate=true; + core.dom.floorNameLabel.innerHTML = core.status.maps[floorId].title; + if (!core.isset(stair) && !core.isset(heroLoc)) + heroLoc = core.clone(core.status.hero.loc); + if (core.isset(stair)) { + if (!core.isset(heroLoc)) heroLoc={}; + + if (core.isset(core.status.maps[floorId][stair])) { + heroLoc.x = core.status.maps[floorId][stair][0]; + heroLoc.y = core.status.maps[floorId][stair][1]; + } + else { + var blocks = core.status.maps[floorId].blocks; + for (var i in blocks) { + if (core.isset(blocks[i].event) && !blocks[i].disable && blocks[i].event.id === stair) { + heroLoc.x = blocks[i].x; + heroLoc.y = blocks[i].y; + break; + } + } + } + if (!core.isset(heroLoc.x)) { + heroLoc.x=core.status.hero.loc.x; + heroLoc.y=core.status.hero.loc.y; + } + } + if (!core.isset(heroLoc.direction)) heroLoc.direction = core.status.hero.loc.direction; + + if (core.status.maps[floorId].canFlyTo && core.status.hero.flyRange.indexOf(floorId)<0) { + core.status.hero.flyRange.push(floorId); + core.status.hero.flyRange.sort(function (a, b) { + return core.floorIds.indexOf(a) - core.floorIds.indexOf(b); + }) + } + + window.setTimeout(function () { + + var changing = function () { + + core.events.eventdata.changingFloor(floorId, heroLoc, fromLoad); + + var changed = function () { + core.unLockControl(); + core.status.replay.animate=false; + core.events.afterChangeFloor(floorId, fromLoad); + if (core.isset(callback)) callback(); + } + if (displayAnimate) { + core.hide(core.dom.floorMsgGroup, time/4, function () { + changed(); + }); + } + else { + changed(); + } + + } + core.playSound('floor.mp3'); + if (displayAnimate) { + core.show(core.dom.floorMsgGroup, time/2, function () { + changing(); + }); + } + else { + changing(); + } + }, 25); +} + ////// 转换楼层结束的事件 ////// events.prototype.afterChangeFloor = function (floorId, fromLoad) { if (main.mode!='play') return; return this.eventdata.afterChangeFloor(floorId, fromLoad); } +events.prototype._sys_passNet = function (data, callback) { + this.passNet(data); + if (callback) callback(); +} + +////// 经过一个路障 ////// +events.prototype.passNet = function (data) { + // 有鞋子 + if (core.hasItem('shoes')) return; + if (data.event.id=='lavaNet') { + // 血网 lavaNet 移动到 checkBlock 中处理 + /* + core.status.hero.hp -= core.values.lavaDamage; + if (core.status.hero.hp<=0) { + core.status.hero.hp=0; + core.updateStatusBar(); + core.events.lose(); + return; + } + core.drawTip('经过血网,生命-'+core.values.lavaDamage); + */ + } + if (data.event.id=='poisonNet') { // 毒网 + core.setFlag('debuff', 'poison'); + core.insertAction('毒衰咒处理'); + } + else if (data.event.id=='weakNet') { // 衰网 + core.setFlag('debuff', 'weak'); + core.insertAction('毒衰咒处理'); + } + else if (data.event.id=='curseNet') { // 咒网 + core.setFlag('debuff', 'curse'); + core.insertAction('毒衰咒处理'); + } + core.updateStatusBar(); +} + +events.prototype._sys_pushBox = function (data, callback) { + this.pushBox(data); + if (callback) callback(); +} + +////// 推箱子 ////// +events.prototype.pushBox = function (data) { + if (data.event.id!='box' && data.event.id!='boxed') return; + + // 判断还能否前进,看看是否存在事件 + var direction = core.getHeroLoc('direction'), nx=data.x+core.utils.scan[direction].x, ny=data.y+core.utils.scan[direction].y; + + if (nx<0||nx>=core.bigmap.width||ny<0||ny>=core.bigmap.height) return; + + var block = core.getBlock(nx, ny, null, true); + if (block!=null && !(core.isset(block.block.event) && block.block.event.id=='flower')) + return; + + if (block==null) { + core.status.thisMap.blocks.push(core.maps.initBlock(nx, ny, 169)); + block = core.getBlock(nx, ny); + } + else { + block.block.id=170; + block.block.event=core.maps.initBlock(null,null,170).event; + } + core.drawBlock(block.block); + + if (data.event.id=='box') { + core.removeBlock(data.x, data.y); + } + else { + data.id=168; + data.event=core.maps.initBlock(null,null,168).event; + core.drawBlock(data); + } + + core.updateStatusBar(); + + core.status.replay.animate = true; + core.lockControl(); + setTimeout(function () { + core.moveHero(direction, function() { + core.status.replay.animate = false; + core.status.route.pop(); + core.events.afterPushBox(); + // 可能有阻击... + if (core.status.event.id == null) { + core.unLockControl(); + core.replay(); + } + }); + }) + +} + +////// 推箱子后的事件 ////// +events.prototype.afterPushBox = function () { + return this.eventdata.afterPushBox(); +} + +events.prototype._sys_changeLight = function (data, callback) { + core.events.changeLight(data.x, data.y); + if (callback) callback(); +} + +////// 改变亮灯(感叹号)的事件 ////// +events.prototype.changeLight = function(x, y) { + var block = core.getBlock(x, y); + if (block==null) return; + var index = block.index; + block = block.block; + if (block.event.id != 'light') return; + // 改变为dark + block.id = 166; + block.event = {'cls': 'terrains', 'id': 'darkLight', 'noPass': true}; + core.drawBlock(block); + this.afterChangeLight(x,y); +} + +////// 改变亮灯之后,可以触发的事件 ////// +events.prototype.afterChangeLight = function (x,y) { + return this.eventdata.afterChangeLight(x,y); +} + +events.prototype._sys_ski = function (data, callback) { + this.ski(); + if (callback) callback(); +} + +////// 滑冰 ////// +events.prototype.ski = function (direction) { + if (!core.isset(direction)) + direction = core.status.automaticRoute.lastDirection || core.getHeroLoc('direction'); + if (core.status.event.id!='ski') { + core.waitHeroToStop(function () { + core.status.event.id='ski'; + core.events.ski(direction); + }); + } + else { + core.moveHero(direction, function () { + if (core.status.event.id=='ski' && !core.status.isSkiing) { + core.status.event.id=null; + core.unLockControl(); + core.replay(); + } + }) + } +} + +events.prototype._sys_action = function (data, callback) { + var ev = core.clone(data.event.data), ex = data.x, ey = data.y; + // 检查是否需要改变朝向 + if (ex == core.nextX() && ey == core.nextY()) { + var dir = {"up":"down","down":"up","left":"right","right":"left"}[core.getHeroLoc('direction')]; + var id = data.event.id, toId = (data.event.faceIds||{})[dir]; + if (core.isset(toId) && id!=toId) { + var number = core.icons.getNumberById(toId); + if (number>0) + core.setBlock(number, ex, ey); + } + } + this.insertAction(ev, ex, ey, callback); +} + +// ------ 自定义事件的处理 ------ // + +////// 注册一个自定义事件 ////// +// type为事件名,func为事件的处理函数,可接受(data, x, y, prefix)参数 +// data为事件内容,x和y为当前点坐标(可为null),prefix为当前点前缀 +events.prototype.registerEvent = function (type, func) { + this.actions[type] = func; +} + +////// 注销一个自定义事件 +events.prototype.unregisterEvent = function (type) { + delete this.actions[type]; +} + +////// 执行一个自定义事件 +events.prototype.doEvent = function (data, x, y, prefix) { + var type = data.type; + if (this.actions[type]) this.actions[type](data, x, y, prefix); + else if (this["_action_"+type]) this["_action_"+type](data, x, y, prefix); + else { + core.insertAction("未知的自定义事件: "+type+"!"); + this.doAction(); + } +} + ////// 开始执行一系列自定义事件 ////// events.prototype.doEvents = function (list, x, y, callback) { if (!core.isset(list)) return; @@ -913,7 +1370,7 @@ events.prototype.doAction = function() { ]; } else { - core.material.events[block.event.trigger](block, function () { + core.doSystemEvent(block.event.trigger, block, function () { core.lockControl(); core.doAction(); }); @@ -1355,6 +1812,12 @@ events.prototype.insertAction = function (action, x, y, callback) { } } +////// 获得一个公共事件 ////// +events.prototype.getCommonEvent = function (name) { + if (!core.isset(name) || !(typeof name === 'string')) return null; + return this.commonEvent[name] || null; +} + ////// 恢复一个事件 ////// events.prototype.recoverEvents = function (data) { if (core.isset(data)) { @@ -1370,192 +1833,7 @@ events.prototype.recoverEvents = function (data) { return false; } -////// 获得一个公共事件 ////// -events.prototype.getCommonEvent = function (name) { - if (!core.isset(name) || !(typeof name === 'string')) return null; - return this.commonEvent[name] || null; -} - -////// 获得面前的物品(轻按) ////// -events.prototype.getNextItem = function() { - if (!core.status.heroStop || !core.flags.enableGentleClick) return false; - - if (!core.canMoveHero()) return false; - - var nextX = core.nextX(), nextY = core.nextY(); - var block = core.getBlock(nextX, nextY); - if (block==null) return false; - if (block.block.event.trigger=='getItem') { - core.getItem(block.block.event.id, 1, nextX, nextY); - core.status.route.push("getNext"); - return true; - } - return false; -} - -////// 获得某个物品 ////// -events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { - itemNum=itemNum||1; - var itemCls = core.material.items[itemId].cls; - core.items.getItemEffect(itemId, itemNum); - core.removeBlock(itemX, itemY); - var text = '获得 ' + core.material.items[itemId].name; - if (itemNum > 1) text += "x" + itemNum; - if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); - core.drawTip(text, core.material.icons.items[itemId]); - core.updateStatusBar(); - - this.eventdata.afterGetItem(itemId, itemX, itemY, callback); -} - -////// 开门 ////// -events.prototype.openDoor = function (id, x, y, needKey, callback) { - if (!core.isset(id)) id = core.getBlockId(x, y); - - // 是否存在门 - if (!core.terrainExists(x, y, id) || !(id.endsWith("Door") || id.endsWith("Wall")) - || !core.isset(core.material.icons.animates[id])) { - return false; - } - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); - if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - - var speed = id.endsWith("Wall")?70:30; - - if (needKey && id.endsWith("Door")) { - var key = id.replace("Door", "Key"); - if (!core.hasItem(key)) { - if (key != "specialKey") - core.drawTip("你没有" + ((core.material.items[key]||{}).name||"钥匙")); - else core.drawTip("无法开启此门"); - core.clearContinueAutomaticRoute(); - return false; - } - core.autosave(true); - core.removeItem(key); - } - - // open - core.playSound("door.mp3"); - var state = 0; - var door = core.material.icons.animates[id]; - - core.lockControl(); - core.stopHero(); - core.stopAutomaticRoute(); - core.status.replay.animate=true; - core.removeGlobalAnimate(x,y); - var animate = window.setInterval(function () { - state++; - if (state == 4) { - clearInterval(animate); - core.removeBlock(x, y); - core.unLockControl(); - core.status.replay.animate=false; - core.events.afterOpenDoor(id,x,y,callback); - return; - } - core.clearMap('event', 32 * x, 32 * y, 32, 32); - core.drawImage('event', core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); - }, speed / core.status.replay.speed); - - return true; -} - -////// 战斗 ////// -events.prototype.battle = function (id, x, y, force, callback) { - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); - if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - core.stopHero(); - core.stopAutomaticRoute(); - - if (!core.isset(id)) id = core.getBlockId(x, y); - if (!core.isset(id)) { - if (core.isset(callback)) callback(); - return; - } - - // 非强制战斗 - if (!core.enemys.canBattle(id, x, y) && !force && !core.isset(core.status.event.id)) { - core.drawTip("你打不过此怪物!"); - core.clearContinueAutomaticRoute(); - if (core.isset(callback)) callback(); - return; - } - - if (!core.isset(core.status.event.id)) // 自动存档 - core.autosave(true); - - // ------ 支援技能 ------// - if (core.isset(x) && core.isset(y)) { - var index = x + "," + y, cache = (core.status.checkBlock.cache || {})[index] || {}, - guards = cache.guards || []; - if (guards.length>0) { - core.setFlag("__guards__"+x+"_"+y, guards); - var actions = []; - guards.forEach(function (g) { - core.push(actions, {"type": "jump", "from": [g[0],g[1]], "to": [x, y], - "time": 300, "keep": false, "async": true}); - }) - core.push(actions, [ - {"type": "waitAsync"}, - {"type": "trigger", "loc": [x,y]} - ]); - core.insertAction(actions); - return; - } - } - - core.events.afterBattle(id, x, y, callback); -} - -////// 触发(x,y)点的事件 ////// -events.prototype.trigger = function (x, y) { - - if (core.status.event.id == 'action') return; - - core.status.isSkiing = false; - var block = core.getBlock(x, y); - if (block != null) { - block = block.block; - if (core.isset(block.event) && core.isset(block.event.trigger)) { - var noPass = block.event.noPass, trigger = block.event.trigger; - if (noPass) { - core.clearAutomaticRouteNode(x, y); - } - if (trigger == 'ski') core.status.isSkiing = true; - - // 转换楼层能否穿透 - if (trigger=='changeFloor' && !noPass) { - var canCross = core.flags.portalWithoutTrigger; - if (core.isset(block.event.data) && core.isset(block.event.data.portalWithoutTrigger)) - canCross=block.event.data.portalWithoutTrigger; - if (canCross) { - if (core.isReplaying()) { - if (core.status.replay.toReplay[0]=='no') { - core.status.replay.toReplay.shift(); - core.status.route.push("no"); - return; - } - } - else if (core.status.automaticRoute.autoHeroMove || core.status.automaticRoute.autoStep0) floorId = core.floorIds[index-1]; - else floorId=core.status.floorId; - } - else if (floorId == ':next') { - var index=core.floorIds.indexOf(core.status.floorId); - if (index=100 && !core.isReplaying(); - - time /= 20; - core.lockControl(); - core.stopHero(); - core.stopAutomaticRoute(); - core.clearContinueAutomaticRoute(); - core.status.replay.animate=true; - core.dom.floorNameLabel.innerHTML = core.status.maps[floorId].title; - if (!core.isset(stair) && !core.isset(heroLoc)) - heroLoc = core.clone(core.status.hero.loc); - if (core.isset(stair)) { - if (!core.isset(heroLoc)) heroLoc={}; - - if (core.isset(core.status.maps[floorId][stair])) { - heroLoc.x = core.status.maps[floorId][stair][0]; - heroLoc.y = core.status.maps[floorId][stair][1]; - } - else { - var blocks = core.status.maps[floorId].blocks; - for (var i in blocks) { - if (core.isset(blocks[i].event) && !blocks[i].disable && blocks[i].event.id === stair) { - heroLoc.x = blocks[i].x; - heroLoc.y = blocks[i].y; - break; - } - } - } - if (!core.isset(heroLoc.x)) { - heroLoc.x=core.status.hero.loc.x; - heroLoc.y=core.status.hero.loc.y; - } - } - if (!core.isset(heroLoc.direction)) heroLoc.direction = core.status.hero.loc.direction; - - if (core.status.maps[floorId].canFlyTo && core.status.hero.flyRange.indexOf(floorId)<0) { - core.status.hero.flyRange.push(floorId); - core.status.hero.flyRange.sort(function (a, b) { - return core.floorIds.indexOf(a) - core.floorIds.indexOf(b); - }) - } - - window.setTimeout(function () { - - var changing = function () { - - core.events.eventdata.changingFloor(floorId, heroLoc, fromLoad); - - var changed = function () { - core.unLockControl(); - core.status.replay.animate=false; - core.events.afterChangeFloor(floorId, fromLoad); - if (core.isset(callback)) callback(); - } - if (displayAnimate) { - core.hide(core.dom.floorMsgGroup, time/4, function () { - changed(); - }); - } - else { - changed(); - } - - } - core.playSound('floor.mp3'); - if (displayAnimate) { - core.show(core.dom.floorMsgGroup, time/2, function () { - changing(); - }); - } - else { - changing(); - } - }, 25); -} - ////// 显示图片 ////// events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, time, callback) { dw /= 100; @@ -2122,144 +2301,6 @@ events.prototype.addPoint = function (enemy) { return this.eventdata.addPoint(enemy); } -////// 战斗结束后触发的事件 ////// -events.prototype.afterBattle = function (enemyId,x,y,callback) { - return this.eventdata.afterBattle(enemyId,x,y,callback); -} - -////// 开一个门后触发的事件 ////// -events.prototype.afterOpenDoor = function (doorId,x,y,callback) { - return this.eventdata.afterOpenDoor(doorId,x,y,callback); -} - -////// 经过一个路障 ////// -events.prototype.passNet = function (data) { - // 有鞋子 - if (core.hasItem('shoes')) return; - if (data.event.id=='lavaNet') { // 血网 - // 在checkBlock中进行处理 - /* - core.status.hero.hp -= core.values.lavaDamage; - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose(); - return; - } - */ - // core.drawTip('经过血网,生命-'+core.values.lavaDamage); - } - if (data.event.id=='poisonNet') { // 毒网 - core.setFlag('debuff', 'poison'); - core.insertAction('毒衰咒处理'); - } - else if (data.event.id=='weakNet') { // 衰网 - core.setFlag('debuff', 'weak'); - core.insertAction('毒衰咒处理'); - } - else if (data.event.id=='curseNet') { // 咒网 - core.setFlag('debuff', 'curse'); - core.insertAction('毒衰咒处理'); - } - core.updateStatusBar(); -} - -////// 改变亮灯(感叹号)的事件 ////// -events.prototype.changeLight = function(x, y) { - var block = core.getBlock(x, y); - if (block==null) return; - var index = block.index; - block = block.block; - if (block.event.id != 'light') return; - // 改变为dark - block.id = 166; - block.event = {'cls': 'terrains', 'id': 'darkLight', 'noPass': true}; - core.drawBlock(block); - this.afterChangeLight(x,y); -} - -////// 改变亮灯之后,可以触发的事件 ////// -events.prototype.afterChangeLight = function (x,y) { - return this.eventdata.afterChangeLight(x,y); -} - -////// 滑冰 ////// -events.prototype.ski = function (direction) { - if (!core.isset(direction)) - direction = core.status.automaticRoute.lastDirection || core.getHeroLoc('direction'); - if (core.status.event.id!='ski') { - core.waitHeroToStop(function () { - core.status.event.id='ski'; - core.events.ski(direction); - }); - } - else { - core.moveHero(direction, function () { - if (core.status.event.id=='ski' && !core.status.isSkiing) { - core.status.event.id=null; - core.unLockControl(); - core.replay(); - } - }) - } -} - -////// 推箱子 ////// -events.prototype.pushBox = function (data) { - if (data.event.id!='box' && data.event.id!='boxed') return; - - // 判断还能否前进,看看是否存在事件 - var direction = core.getHeroLoc('direction'), nx=data.x+core.utils.scan[direction].x, ny=data.y+core.utils.scan[direction].y; - - if (nx<0||nx>=core.bigmap.width||ny<0||ny>=core.bigmap.height) return; - - var block = core.getBlock(nx, ny, null, true); - if (block!=null && !(core.isset(block.block.event) && block.block.event.id=='flower')) - return; - - if (block==null) { - core.status.thisMap.blocks.push(core.maps.initBlock(nx, ny, 169)); - block = core.getBlock(nx, ny); - } - else { - block.block.id=170; - block.block.event=core.maps.initBlock(null,null,170).event; - } - core.drawBlock(block.block); - - if (data.event.id=='box') { - core.removeBlock(data.x, data.y); - } - else { - data.id=168; - data.event=core.maps.initBlock(null,null,168).event; - core.drawBlock(data); - } - - core.updateStatusBar(); - - core.status.replay.animate = true; - core.lockControl(); - setTimeout(function () { - core.moveHero(direction, function() { - core.status.replay.animate = false; - core.status.route.pop(); - core.events.afterPushBox(); - // 可能有阻击... - if (core.status.event.id == null) { - core.unLockControl(); - core.replay(); - } - }); - }) - -} - -////// 推箱子后的事件 ////// -events.prototype.afterPushBox = function () { - return this.eventdata.afterPushBox(); -} - ////// 使用炸弹/圣锤后的事件 ////// events.prototype.afterUseBomb = function () { return this.eventdata.afterUseBomb(); From dd12ebb04da36d6a04b2b6f5c49d9cbfc7357218 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 15 Mar 2019 23:19:33 +0800 Subject: [PATCH 011/153] init, start & gameover --- _docs/personalization.md | 2 +- libs/control.js | 2 +- libs/events.js | 341 +++++++++++++++++---------------------- libs/ui.js | 4 +- project/functions.js | 2 +- 5 files changed, 151 insertions(+), 200 deletions(-) diff --git a/_docs/personalization.md b/_docs/personalization.md index 27276ef1..4831d9b5 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -974,7 +974,7 @@ this.getAchievements = function () { - **`flag:textAttribute`**, **`flag:globalAttribute`**, **`flag:globalFlags`**: 当前的剧情文本属性,当前的全局属性,当前的全局开关。 - **`flag:cannotMoveDirectly`**, **`flag:clickMove`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。 - **`flag:hideStatusBar`**, **`flag:showToolbox`**: 是否隐藏状态栏,是否显示工具栏。 -- **`flag:debug`**, **`flag:consoleOpened`**: 当前是否开启了调试模式,是否开启了控制台。 +- **`flag:debug`**, **`flag:__consoleOpened__`**: 当前是否开启了调试模式,是否开启了控制台。 - **`flag:__seed__`**, **`flag:__rand__`**: 伪随机数生成种子和当前的状态 ========================================================================================== diff --git a/libs/control.js b/libs/control.js index f006e9ef..34e65e69 100644 --- a/libs/control.js +++ b/libs/control.js @@ -297,7 +297,7 @@ control.prototype.setRequestAnimationFrame = function () { // 检查控制台状态 if (core.utils.consoleOpened()) { - core.setFlag('consoleOpened', true); + core.setFlag('__consoleOpened__', true); } window.requestAnimationFrame(draw); diff --git a/libs/events.js b/libs/events.js index 31da99ba..33f1a0ad 100644 --- a/libs/events.js +++ b/libs/events.js @@ -13,103 +13,84 @@ events.prototype._init = function () { } // ------ 初始化,开始和结束 ------ // -/// + +/// 初始化游戏 events.prototype.initGame = function () { return this.eventdata.initGame(); } ////// 游戏开始事件 ////// events.prototype.startGame = function (hard, seed, route, callback) { - main.dom.levelChooseButtons.style.display='none'; main.dom.startButtonGroup.style.display='none'; - var start = function () { - console.log('开始游戏'); - core.resetStatus(core.firstData.hero, hard, null, null, core.initStatus.maps); - var nowLoc = core.clone(core.getHeroLoc()); - core.setHeroLoc('x', -1); - core.setHeroLoc('y', -1); - - if (core.isset(seed)) { - core.setFlag('__seed__', seed); - core.setFlag('__rand__', seed); - } - else core.utils.__init_seed(); - - core.clearMap('all'); - core.deleteAllCanvas(); - core.clearStatusBar(); - - var post_start = function () { - core.ui.closePanel(); - - core.control.triggerStatusBar('show'); - core.dom.musicBtn.style.display = 'none'; - - core.changeFloor(core.firstData.floorId, null, nowLoc, null, function() { - if (core.isset(callback)) callback(); - }); - - setTimeout(function () { - // Upload - var formData = new FormData(); - formData.append('type', 'people'); - formData.append('name', core.firstData.name); - formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); - formData.append('hard', core.encodeBase64(core.status.hard)); - formData.append('hardCode', core.getFlag('hard', 0)); - formData.append('base64', 1); - - core.utils.http("POST", "/games/upload.php", formData); - }) - } - - var real_start = function () { - core.insertAction(core.clone(core.firstData.startText), null, null, function() { - post_start(); - }); - } - - if (core.flags.startUsingCanvas) { - core.control.triggerStatusBar('hide'); - core.dom.musicBtn.style.display = 'block'; - - core.insertAction(core.clone(core.firstData.startCanvas), null, null, function() { - real_start(); - }); - } - else { - core.events.setInitData(hard); - real_start(); - } - - if (core.isset(route)) { - core.startReplay(route); - } - - } - if (main.mode!='play') return; - if (core.flags.startUsingCanvas) { + // 无动画的开始游戏 + if (core.flags.startUsingCanvas || core.isset(route)) { core.dom.startPanel.style.display = 'none'; - start(); - return; - } - - if (core.isset(route)) { - core.dom.startPanel.style.display = 'none'; - start(); + this._startGame_start(hard, seed, route, callback); } else { - core.hideStartAnimate(function() { - start(); - }) + core.hideStartAnimate(function () { + core.events._startGame_start(hard, seed, route, callback); + }); } } +events.prototype._startGame_start = function (hard, seed, route, callback) { + console.log('开始游戏'); + core.resetStatus(core.firstData.hero, hard, null, null, core.initStatus.maps); + var nowLoc = core.clone(core.getHeroLoc()); + core.setHeroLoc('x', -1); + core.setHeroLoc('y', -1); + + if (core.isset(seed)) { + core.setFlag('__seed__', seed); + core.setFlag('__rand__', seed); + } + else core.utils.__init_seed(); + + core.clearMap('all'); + core.deleteAllCanvas(); + core.clearStatusBar(); + + var todo = []; + if (core.flags.startUsingCanvas) { + core.control.triggerStatusBar('hide'); + core.dom.musicBtn.style.display = 'block'; + core.push(todo, core.firstData.startCanvas); + } + core.push(todo, core.firstData.startText); + this.insertAction(todo, null, null, function () { + core.events._startGame_afterStart(nowLoc, callback); + }); + + if (core.isset(route)) core.startReplay(route); +} + +events.prototype._startGame_afterStart = function (nowLoc, callback) { + core.ui.closePanel(); + core.control.triggerStatusBar('show'); + core.dom.musicBtn.style.display = 'none'; + core.changeFloor(core.firstData.floorId, null, nowLoc, null, callback); + this._startGame_upload(); +} + +events.prototype._startGame_upload = function () { + // Upload + var formData = new FormData(); + formData.append('type', 'people'); + formData.append('name', core.firstData.name); + formData.append('version', core.firstData.version); + formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('hard', core.encodeBase64(core.status.hard)); + formData.append('hardCode', core.getFlag('hard', 0)); + formData.append('base64', 1); + + core.utils.http("POST", "/games/upload.php", formData); +} + ////// 不同难度分别设置初始属性 ////// events.prototype.setInitData = function (hard) { return this.eventdata.setInitData(hard); @@ -129,7 +110,6 @@ events.prototype.lose = function (reason) { ////// 游戏结束 ////// events.prototype.gameOver = function (ending, fromReplay, norank) { - core.clearMap('all'); core.deleteAllCanvas(); core.dom.gif2.innerHTML = ""; @@ -141,136 +121,107 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { ending += "[比赛]"; } - var askRate = function () { - if (!core.isset(ending)) { - core.restart(); - return; - } + var reason = null; + if (fromReplay) reason = "录像回放完毕!"; + else if (core.hasFlag("debug")) reason = "\t[系统提示]调试模式下无法上传成绩"; + else if (core.hasFlag("__consoleOpened__")) reason = "\t[系统提示]本存档开启过控制台,无法上传成绩"; - core.ui.closePanel(); - core.ui.drawConfirmBox("恭喜通关本塔,你想进行评分吗?", function () { - if (core.platform.isPC) { - window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); - core.restart(); - } - else { - window.location.href = "/score.php?name="+core.firstData.name+"&num=10"; - } - }, function () { - core.restart(); - }); + if (reason != null) + core.drawText(reason, core.restart); + else + this._gameOver_confirmUpload(ending, norank); +} +events.prototype._gameOver_confirmUpload = function (ending, norank) { + core.ui.closePanel(); + + if (!core.isset(ending)) { + this._gameOver_confirmDownload(ending); + return; } + core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () { + var username = main.isCompetition?"":prompt("请输入你的ID:", core.getCookie('id')||""); + core.events._gameOver_doUpload(username, ending, norank); + }, function () { + if (main.isCompetition) + core.events._gameOver_confirmDownload(ending); + else + core.events._gameOver_doUpload(null, ending, norank); + }) +} - // 下载录像 - var confirmDownload = function () { +events.prototype._gameOver_doUpload = function (username, ending, norank) { + var hp = core.status.hero.hp; + if (!core.isset(username)) hp = 1; + core.ui.closePanel(); + // upload + var formData = new FormData(); + formData.append('type', 'score'); + formData.append('name', core.firstData.name); + formData.append('version', core.firstData.version); + formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('hard', core.encodeBase64(core.status.hard)); + formData.append('username', core.encodeBase64(username||"")); + formData.append('ending', core.encodeBase64(ending)); + formData.append('lv', core.status.hero.lv); + formData.append('hp', Math.min(hp, Math.pow(2, 63))); + formData.append('atk', core.status.hero.atk); + formData.append('def', core.status.hero.def); + formData.append('mdef', core.status.hero.mdef); + formData.append('money', core.status.hero.money); + formData.append('experience', core.status.hero.experience); + formData.append('steps', core.status.hero.steps); + formData.append('norank', norank||0); + formData.append('seed', core.getFlag('__seed__')); + formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); + formData.append('route', core.encodeRoute(core.status.route)); + formData.append('base64', 1); - core.ui.closePanel(); - core.ui.drawConfirmBox("你想下载录像吗?", function () { - var obj = { - 'name': core.firstData.name, - 'version': core.firstData.version, - 'hard': core.status.hard, - 'seed': core.getFlag('__seed__'), - 'route': core.encodeRoute(core.status.route) - } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); - // core.restart(); - askRate(); - }, function () { - // core.restart(); - askRate(); - }) + if (main.isCompetition) + core.http("POST", "/games/competition/upload.php", formData); + else + core.http("POST", "/games/upload.php", formData); - } + setTimeout(function() { + core.events._gameOver_confirmDownload(ending); + }, 200); +} - // 上传成绩 - var confirmUpload = function () { - - core.ui.closePanel(); - - if (!core.isset(ending)) { - confirmDownload(); - return; +events.prototype._gameOver_confirmDownload = function (ending) { + core.ui.closePanel(); + core.ui.drawConfirmBox("你想下载录像吗?", function () { + var obj = { + 'name': core.firstData.name, + 'version': core.firstData.version, + 'hard': core.status.hard, + 'seed': core.getFlag('__seed__'), + 'route': core.encodeRoute(core.status.route) } + core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); + core.events._gameOver_askRate(ending); + }, function () { + core.events._gameOver_askRate(ending); + }); +} - var doUpload = function(username) { - var hp = core.status.hero.hp; - if (username==undefined) hp = 1; - core.ui.closePanel(); - // upload - var formData = new FormData(); - formData.append('type', 'score'); - formData.append('name', core.firstData.name); - formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); - formData.append('hard', core.encodeBase64(core.status.hard)); - formData.append('username', core.encodeBase64(username||"")); - formData.append('ending', core.encodeBase64(ending)); - formData.append('lv', core.status.hero.lv); - formData.append('hp', Math.min(hp, Math.pow(2, 63))); - formData.append('atk', core.status.hero.atk); - formData.append('def', core.status.hero.def); - formData.append('mdef', core.status.hero.mdef); - formData.append('money', core.status.hero.money); - formData.append('experience', core.status.hero.experience); - formData.append('steps', core.status.hero.steps); - formData.append('norank', norank||0); - formData.append('seed', core.getFlag('__seed__')); - formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); - formData.append('route', core.encodeRoute(core.status.route)); - formData.append('base64', 1); - - if (main.isCompetition) - core.http("POST", "/games/competition/upload.php", formData); - else - core.http("POST", "/games/upload.php", formData); - - setTimeout(function() { - confirmDownload(); - }, 150); - } - - core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () { - if (main.isCompetition) { - doUpload(""); - } - else { - doUpload(prompt("请输入你的ID:", core.getCookie('id')||"")); - } - }, function () { - if (main.isCompetition) - confirmDownload(); - else - doUpload(undefined); - }) - +events.prototype._gameOver_askRate = function (ending) { + if (!core.isset(ending)) { + core.restart(); return; } - if (fromReplay) { - core.drawText("录像回放完毕!", function () { + core.ui.closePanel(); + core.ui.drawConfirmBox("恭喜通关本塔,你想进行评分吗?", function () { + if (core.platform.isPC) { + window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); core.restart(); - }); - } - else { - - if (core.hasFlag('debug')) { - core.drawText("\t[系统提示]调试模式下无法上传成绩", function () { - core.restart(); - }) - } - else if (core.hasFlag('consoleOpened')) { - core.drawText("\t[系统提示]本存档开启过控制台,无法上传成绩", function () { - core.restart(); - }) } else { - confirmUpload(); + window.location.href = "/score.php?name="+core.firstData.name+"&num=10"; } - - } - + }, function () { + core.restart(); + }); } // ------ 系统事件的处理 ------ // diff --git a/libs/ui.js b/libs/ui.js index c242e448..c00865ab 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2100,7 +2100,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; core.fillText('ui', v, (2*i+1)*u, 60+size, '#FFD700', '10px '+globalFont); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 73+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF'); + core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 73+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF'); } else { core.fillRect('ui', (2*i+1)*u-size/2, 45, size, size, '#333333', 2); @@ -2120,7 +2120,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); if (v.length+v2.length<=21) v+=v2; core.fillText('ui', v, (2*i-5)*u, 248+size, '#FFD700', '10px '+globalFont); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 261+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF', '10px '+globalFont); + core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 261+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF', '10px '+globalFont); } else { core.fillRect('ui', (2*i-5)*u-size/2, 233, size, size, '#333333', 2); diff --git a/project/functions.js b/project/functions.js index 0b5234c1..dead2159 100644 --- a/project/functions.js +++ b/project/functions.js @@ -62,7 +62,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 游戏获胜事件 core.ui.closePanel(); var replaying = core.isReplaying(); - core.stopReplay(); + if (replaying) core.stopReplay(); core.waitHeroToStop(function() { core.clearMap('all'); // 清空全地图 core.deleteAllCanvas(); // 删除所有创建的画布 From 0c4b1ad77a6ca37240bff0b47ef4cb041f25e6ba Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 02:11:28 +0800 Subject: [PATCH 012/153] system events --- _docs/personalization.md | 2 +- _server/blockly/MotaAction.g4 | 4 +- _server/data.comment.js | 2 +- _server/functions.comment.js | 4 +- libs/control.js | 26 +- libs/events.js | 496 ++++++++++++++++------------------ libs/maps.js | 39 +++ libs/ui.js | 12 +- libs/utils.js | 2 +- project/data.js | 2 +- project/functions.js | 118 ++++---- 11 files changed, 370 insertions(+), 337 deletions(-) diff --git a/_docs/personalization.md b/_docs/personalization.md index 4831d9b5..c83c7eaa 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -427,7 +427,7 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { ``` js ////// 点击楼层传送器时的打开操作 ////// control.prototype.useFly = function (need) { - if (!core.status.heroStop || core.status.heroMoving > 0) { + if (core.isMoving()) { core.drawTip("请先停止勇士行动"); return; } diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index df4cf03e..bd5e3f4a 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -200,7 +200,7 @@ var loc = ', "loc": ['+Number_0+', '+Number_1+']'; if (Stair_List_0!=='loc')loc = ', "stair": "'+Stair_List_0+'"'; DirectionEx_List_0 = DirectionEx_List_0 && (', "direction": "'+DirectionEx_List_0+'"'); Int_0 = (Int_0!=='') ?(', "time": '+Int_0):''; -Bool_0 = Bool_0 ?'':(', "portalWithoutTrigger": false'); +Bool_0 = Bool_0 ?'':(', "ignoreChangeFloor": false'); var code = '{"floorId": "'+toFloorId+'"'+loc+DirectionEx_List_0+Int_0+Bool_0+' }\n'; return code; */; @@ -2006,7 +2006,7 @@ ActionParser.prototype.parse = function (obj,type) { if (!this.isset(obj.time)) obj.time=500; return MotaActionBlocks['changeFloor_m'].xmlText([ obj.floorType||'floorId',obj.floorId,obj.stair||'loc',obj.loc[0],obj.loc[1],obj.direction, - obj.time,!this.isset(obj.portalWithoutTrigger) + obj.time,!this.isset(obj.ignoreChangeFloor) ]); case 'level': diff --git a/_server/data.comment.js b/_server/data.comment.js index 4b6d6156..bad2978f 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -636,7 +636,7 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "寻路算法是否经过血瓶;如果该项为false,则寻路算法会自动尽量绕过血瓶" }, - "portalWithoutTrigger": { + "ignoreChangeFloor": { "_leaf": true, "_type": "checkbox", "_bool": "bool", diff --git a/_server/functions.comment.js b/_server/functions.comment.js index 89181b22..8e961da5 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -43,11 +43,11 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_lint": true, "_data": "转换楼层结束的事件\n此函数会在整个楼层切换完全结束后执行" }, - "addPoint": { + "beforeBattle": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "加点事件" + "_data": "战斗前发生的事件" }, "afterBattle": { "_leaf": true, diff --git a/libs/control.js b/libs/control.js index 34e65e69..a3e706f5 100644 --- a/libs/control.js +++ b/libs/control.js @@ -486,6 +486,16 @@ control.prototype.stopAutomaticRoute = function () { core.deleteCanvas('route'); } +control.prototype.saveAndStopAutomaticRoute = function () { + var automaticRoute = core.status.automaticRoute; + if (automaticRoute.moveStepBeforeStop.length == 0) { + automaticRoute.moveStepBeforeStop = automaticRoute.autoStepRoutes.slice(automaticRoute.autoStep - 1); + if (automaticRoute.moveStepBeforeStop.length>=1) + automaticRoute.moveStepBeforeStop[0].step -= automaticRoute.movedStep; + } + this.stopAutomaticRoute(); +} + ////// 继续剩下的自动寻路操作 ////// control.prototype.continueAutomaticRoute = function () { // 此函数只应由events.afterOpenDoor和events.afterBattle调用 @@ -500,9 +510,10 @@ control.prototype.continueAutomaticRoute = function () { } ////// 清空剩下的自动寻路列表 ////// -control.prototype.clearContinueAutomaticRoute = function () { +control.prototype.clearContinueAutomaticRoute = function (callback) { core.deleteCanvas('route'); core.status.automaticRoute.moveStepBeforeStop=[]; + if (callback) callback(); } ////// 瞬间移动 ////// @@ -724,6 +735,11 @@ control.prototype.fillPosWithPoint = function (pos) { core.fillRect('ui', pos.x*32+12,pos.y*32+12,8,8, '#bfbfbf'); } +// 当前是否正在移动 +control.prototype.isMoving = function () { + return !core.status.heroStop || core.status.heroMoving > 0; +} + ////// 设置勇士的自动行走路线 ////// control.prototype.setAutoHeroMove = function (steps) { steps=steps||core.status.automaticRoute.autoStepRoutes; @@ -781,7 +797,7 @@ control.prototype.moveAction = function (callback) { core.status.automaticRoute.moveStepBeforeStop = []; core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); if (canMove) // 非箭头:触发 - core.trigger(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y); + core.events._trigger(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y); core.drawHero(direction, x, y); if (core.status.automaticRoute.moveStepBeforeStop.length==0) { @@ -822,11 +838,11 @@ control.prototype.moveAction = function (callback) { if (block!=null && block.block.event.trigger=='getItem' && !core.isset(core.floors[core.status.floorId].afterGetItem[nowx+","+nowy])) { hasTrigger = true; - core.trigger(nowx, nowy); + core.events._trigger(nowx, nowy); } core.checkBlock(); if (!hasTrigger && !core.status.gameOver) - core.trigger(nowx, nowy); + core.events._trigger(nowx, nowy); if (core.isset(callback)) callback(); }); } @@ -2023,7 +2039,7 @@ control.prototype.checkStatus = function (name, need, item) { core.drawTip("你没有" + core.material.items[name].name); return false; } - if (!core.status.heroStop) { + if (core.isMoving()) { core.drawTip("请先停止勇士行动"); return false; } diff --git a/libs/events.js b/libs/events.js index 33f1a0ad..7ef4ef98 100644 --- a/libs/events.js +++ b/libs/events.js @@ -50,6 +50,7 @@ events.prototype._startGame_start = function (hard, seed, route, callback) { core.setFlag('__rand__', seed); } else core.utils.__init_seed(); + this.setInitData(); core.clearMap('all'); core.deleteAllCanvas(); @@ -92,8 +93,8 @@ events.prototype._startGame_upload = function () { } ////// 不同难度分别设置初始属性 ////// -events.prototype.setInitData = function (hard) { - return this.eventdata.setInitData(hard); +events.prototype.setInitData = function () { + return this.eventdata.setInitData(); } ////// 游戏获胜事件 ////// @@ -248,47 +249,49 @@ events.prototype.doSystemEvent = function (type, data, callback) { } ////// 触发(x,y)点的事件 ////// -events.prototype.trigger = function (x, y) { - +events.prototype._trigger = function (x, y) { + // 如果正在自定义事件中,忽略 if (core.status.event.id == 'action') return; core.status.isSkiing = false; var block = core.getBlock(x, y); - if (block != null) { - block = block.block; - if (core.isset(block.event) && core.isset(block.event.trigger)) { - var noPass = block.event.noPass, trigger = block.event.trigger; - if (noPass) { - core.clearAutomaticRouteNode(x, y); - } - if (trigger == 'ski') core.status.isSkiing = true; + if (block == null) return; + block = block.block; + if (core.isset(block.event) && core.isset(block.event.trigger)) { + var noPass = block.event.noPass, trigger = block.event.trigger; + if (noPass) core.clearAutomaticRouteNode(x, y); + if (trigger == 'ski') core.status.isSkiing = true; - // 转换楼层能否穿透 - if (trigger=='changeFloor' && !noPass) { - var canCross = core.flags.portalWithoutTrigger; - if (core.isset(block.event.data) && core.isset(block.event.data.portalWithoutTrigger)) - canCross=block.event.data.portalWithoutTrigger; - if (canCross) { - if (core.isReplaying()) { - if (core.status.replay.toReplay[0]=='no') { - core.status.replay.toReplay.shift(); - core.status.route.push("no"); - return; - } - } - else if (core.status.automaticRoute.autoHeroMove || core.status.automaticRoute.autoStep=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - core.stopHero(); - core.stopAutomaticRoute(); - - if (!core.isset(id)) id = core.getBlockId(x, y); - if (!core.isset(id)) { - if (core.isset(callback)) callback(); - return; - } - + core.saveAndStopAutomaticRoute(); + id = id || core.getBlockId(x, y); + if (!core.isset(id)) return core.clearContinueAutomaticRoute(callback); // 非强制战斗 if (!core.enemys.canBattle(id, x, y) && !force && !core.isset(core.status.event.id)) { core.drawTip("你打不过此怪物!"); - core.clearContinueAutomaticRoute(); - if (core.isset(callback)) callback(); - return; + return core.clearContinueAutomaticRoute(callback); } + // 自动存档 + if (!core.isset(core.status.event.id)) core.autosave(true); + // 战前事件 + if (!this.beforeBattle(id, x, y)) + return core.clearContinueAutomaticRoute(callback); + // 战后事件 + this.afterBattle(id, x, y, callback); +} - if (!core.isset(core.status.event.id)) // 自动存档 - core.autosave(true); - - // ------ 支援技能 ------// - if (core.isset(x) && core.isset(y)) { - var index = x + "," + y, cache = (core.status.checkBlock.cache || {})[index] || {}, - guards = cache.guards || []; - if (guards.length>0) { - core.setFlag("__guards__"+x+"_"+y, guards); - var actions = []; - guards.forEach(function (g) { - core.push(actions, {"type": "jump", "from": [g[0],g[1]], "to": [x, y], - "time": 300, "keep": false, "async": true}); - }) - core.push(actions, [ - {"type": "waitAsync"}, - {"type": "trigger", "loc": [x,y]} - ]); - core.insertAction(actions); - return; - } - } - - core.events.afterBattle(id, x, y, callback); +////// 战斗前触发的事件 ////// +events.prototype.beforeBattle = function (enemyId, x, y) { + return this.eventdata.beforeBattle(enemyId, x, y) } ////// 战斗结束后触发的事件 ////// events.prototype.afterBattle = function (enemyId, x , y,callback) { - return this.eventdata.afterBattle(enemyId,x,y,callback); + return this.eventdata.afterBattle(enemyId, x, y, callback); +} + +events.prototype._sys_openDoor = function (data, callback) { + this.openDoor(data.event.id, data.x, data.y, true, callback); +} + +////// 开门 ////// +events.prototype.openDoor = function (id, x, y, needKey, callback) { + id = id || core.getBlockId(x, y); + core.saveAndStopAutomaticRoute(); + if (!this._openDoor_check(id, x, y, needKey)) return false; + core.playSound("door.mp3"); + this._openDoor_animate(id, x, y, callback); + return true; +} + +events.prototype._openDoor_check = function (id, x, y, needKey) { + // 是否存在门或暗墙 + if (!core.terrainExists(x, y, id) || !(id.endsWith("Door") || id.endsWith("Wall")) + || !core.isset(core.material.icons.animates[id])) { + core.clearContinueAutomaticRoute(); + return false; + } + + if (needKey && id.endsWith("Door")) { + var key = id.replace("Door", "Key"); + if (!core.hasItem(key)) { + if (key != "specialKey") + core.drawTip("你没有" + ((core.material.items[key]||{}).name||"钥匙")); + else core.drawTip("无法开启此门"); + core.clearContinueAutomaticRoute(); + return false; + } + core.autosave(true); + core.removeItem(key); + } + return true; +} + +events.prototype._openDoor_animate = function (id, x, y, callback) { + var door = core.material.icons.animates[id]; + var speed = id.endsWith("Door") ? 30 : 70; + + core.lockControl(); + core.status.replay.animate = true; + var state = 0; + var animate = window.setInterval(function () { + state++; + if (state == 4) { + clearInterval(animate); + core.removeBlock(x, y); + core.unLockControl(); + core.status.replay.animate = false; + core.events.afterOpenDoor(id, x, y, callback); + return; + } + core.clearMap('event', 32 * x, 32 * y, 32, 32); + core.drawImage('event', core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); + }, speed / core.status.replay.speed); +} + +////// 开一个门后触发的事件 ////// +events.prototype.afterOpenDoor = function (doorId, x, y, callback) { + return this.eventdata.afterOpenDoor(doorId,x,y,callback); } events.prototype._sys_getItem = function (data, callback) { @@ -355,7 +397,7 @@ events.prototype._sys_getItem = function (data, callback) { ////// 获得某个物品 ////// events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { - itemNum=itemNum||1; + itemNum = itemNum || 1; var itemCls = core.material.items[itemId].cls; core.items.getItemEffect(itemId, itemNum); core.removeBlock(itemX, itemY); @@ -370,106 +412,57 @@ events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { ////// 获得面前的物品(轻按) ////// events.prototype.getNextItem = function() { - if (!core.status.heroStop || !core.flags.enableGentleClick) return false; - - if (!core.canMoveHero()) return false; + if (core.isMoving() || !core.canMoveHero() || !core.flags.enableGentleClick) return false; var nextX = core.nextX(), nextY = core.nextY(); var block = core.getBlock(nextX, nextY); if (block==null) return false; if (block.block.event.trigger=='getItem') { - core.getItem(block.block.event.id, 1, nextX, nextY); core.status.route.push("getNext"); + this.getItem(block.block.event.id, 1, nextX, nextY); return true; } return false; } -events.prototype._sys_openDoor = function (data, callback) { - this.openDoor(data.event.id, data.x, data.y, true, callback); -} - -////// 开门 ////// -events.prototype.openDoor = function (id, x, y, needKey, callback) { - if (!core.isset(id)) id = core.getBlockId(x, y); - - // 是否存在门 - if (!core.terrainExists(x, y, id) || !(id.endsWith("Door") || id.endsWith("Wall")) - || !core.isset(core.material.icons.animates[id])) { - return false; - } - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.status.automaticRoute.moveStepBeforeStop=core.status.automaticRoute.autoStepRoutes.slice(core.status.automaticRoute.autoStep-1,core.status.automaticRoute.autoStepRoutes.length); - if (core.status.automaticRoute.moveStepBeforeStop.length>=1)core.status.automaticRoute.moveStepBeforeStop[0].step-=core.status.automaticRoute.movedStep; - } - - var speed = id.endsWith("Wall")?70:30; - - if (needKey && id.endsWith("Door")) { - var key = id.replace("Door", "Key"); - if (!core.hasItem(key)) { - if (key != "specialKey") - core.drawTip("你没有" + ((core.material.items[key]||{}).name||"钥匙")); - else core.drawTip("无法开启此门"); - core.clearContinueAutomaticRoute(); - return false; - } - core.autosave(true); - core.removeItem(key); - } - - // open - core.playSound("door.mp3"); - var state = 0; - var door = core.material.icons.animates[id]; - - core.lockControl(); - core.stopHero(); - core.stopAutomaticRoute(); - core.status.replay.animate=true; - core.removeGlobalAnimate(x,y); - var animate = window.setInterval(function () { - state++; - if (state == 4) { - clearInterval(animate); - core.removeBlock(x, y); - core.unLockControl(); - core.status.replay.animate=false; - core.events.afterOpenDoor(id,x,y,callback); - return; - } - core.clearMap('event', 32 * x, 32 * y, 32, 32); - core.drawImage('event', core.material.images.animates, 32 * state, 32 * door, 32, 32, 32 * x, 32 * y, 32, 32); - }, speed / core.status.replay.speed); - - return true; -} - -////// 开一个门后触发的事件 ////// -events.prototype.afterOpenDoor = function (doorId, x, y, callback) { - return this.eventdata.afterOpenDoor(doorId,x,y,callback); -} - events.prototype._sys_changeFloor = function (data, callback) { + data = data.event.data; var heroLoc = {}; - if (core.isset(data.event.data.loc)) - heroLoc = {'x': data.event.data.loc[0], 'y': data.event.data.loc[1]}; - if (core.isset(data.event.data.direction)) - heroLoc.direction = data.event.data.direction; + if (core.isset(data.loc)) + heroLoc = {'x': data.loc[0], 'y': data.loc[1]}; + if (core.isset(data.direction)) + heroLoc.direction = data.direction; if (core.status.event.id!='action') core.status.event.id=null; - core.changeFloor(data.event.data.floorId, data.event.data.stair, - heroLoc, data.event.data.time, callback); + core.changeFloor(data.floorId, data.stair, heroLoc, data.time, callback); } ////// 楼层切换 ////// events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback, fromLoad) { - - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) { - if (core.isset(callback)) callback(); + var info = this._changeFloor_getInfo(floorId, stair, heroLoc, time); + if (info == null) { + if (callback) callback(); return; } + info.fromLoad = fromLoad; + floorId = info.floorId; + core.dom.floorNameLabel.innerHTML = core.status.maps[floorId].title; + core.lockControl(); + core.stopAutomaticRoute(); + core.clearContinueAutomaticRoute(); + core.status.replay.animate=true; + + if (core.status.maps[floorId].canFlyTo && core.status.hero.flyRange.indexOf(floorId)<0) { + core.status.hero.flyRange.push(floorId); + core.status.hero.flyRange.sort(function (a, b) { + return core.floorIds.indexOf(a) - core.floorIds.indexOf(b); + }) + } + this._changeFloor_beforeChange(info, callback); +} + +events.prototype._changeFloor_getInfo = function (floorId, stair, heroLoc, time) { + floorId = floorId || core.status.floorId; if (floorId == ':before') { var index=core.floorIds.indexOf(core.status.floorId); if (index>0) floorId = core.floorIds[index-1]; @@ -480,24 +473,29 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback if (index=100 && !core.isReplaying(); - + if (time<100) time = 0; time /= 20; - core.lockControl(); - core.stopHero(); - core.stopAutomaticRoute(); - core.clearContinueAutomaticRoute(); - core.status.replay.animate=true; - core.dom.floorNameLabel.innerHTML = core.status.maps[floorId].title; - if (!core.isset(stair) && !core.isset(heroLoc)) + + return { + floorId: floorId, + time: time, + heroLoc: core.clone(this._changeFloor_getHeroLoc(floorId, stair, heroLoc)) + }; +} + +events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) { + if (!core.isset(heroLoc)) heroLoc = core.clone(core.status.hero.loc); if (core.isset(stair)) { - if (!core.isset(heroLoc)) heroLoc={}; - + // 检查该层地图的 upFloor & downFloor if (core.isset(core.status.maps[floorId][stair])) { heroLoc.x = core.status.maps[floorId][stair][0]; heroLoc.y = core.status.maps[floorId][stair][1]; @@ -505,59 +503,55 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback else { var blocks = core.status.maps[floorId].blocks; for (var i in blocks) { - if (core.isset(blocks[i].event) && !blocks[i].disable && blocks[i].event.id === stair) { + if (!blocks[i].disable && blocks[i].event.id === stair) { heroLoc.x = blocks[i].x; heroLoc.y = blocks[i].y; break; } } } - if (!core.isset(heroLoc.x)) { - heroLoc.x=core.status.hero.loc.x; - heroLoc.y=core.status.hero.loc.y; - } - } - if (!core.isset(heroLoc.direction)) heroLoc.direction = core.status.hero.loc.direction; - - if (core.status.maps[floorId].canFlyTo && core.status.hero.flyRange.indexOf(floorId)<0) { - core.status.hero.flyRange.push(floorId); - core.status.hero.flyRange.sort(function (a, b) { - return core.floorIds.indexOf(a) - core.floorIds.indexOf(b); - }) } + ['x', 'y', 'direction'].forEach(function (name) { + if (!core.isset(heroLoc[name])) + heroLoc[name] = core.getHeroLoc(name); + }); + return heroLoc; +} +events.prototype._changeFloor_beforeChange = function (info, callback) { + core.playSound('floor.mp3'); + // 需要 setTimeout 执行,不然会出错 window.setTimeout(function () { - - var changing = function () { - - core.events.eventdata.changingFloor(floorId, heroLoc, fromLoad); - - var changed = function () { - core.unLockControl(); - core.status.replay.animate=false; - core.events.afterChangeFloor(floorId, fromLoad); - if (core.isset(callback)) callback(); - } - if (displayAnimate) { - core.hide(core.dom.floorMsgGroup, time/4, function () { - changed(); - }); - } - else { - changed(); - } - - } - core.playSound('floor.mp3'); - if (displayAnimate) { - core.show(core.dom.floorMsgGroup, time/2, function () { - changing(); + if (info.time == 0) + core.events._changeFloor_changing(info, callback); + else + core.show(core.dom.floorMsgGroup, info.time / 2, function () { + core.events._changeFloor_changing(info, callback); }); - } - else { - changing(); - } - }, 25); + }, 25) +} + +events.prototype._changeFloor_changing = function (info, callback) { + this.changingFloor(info.floorId, info.heroLoc, info.fromLoad); + + if (info.time == 0) + this._changeFloor_afterChange(info, callback); + else + core.hide(core.dom.floorMsgGroup, info.time / 4, function () { + core.events._changeFloor_afterChange(info, callback); + }); +} + +events.prototype._changeFloor_afterChange = function (info, callback) { + core.unLockControl(); + core.status.replay.animate=false; + core.events.afterChangeFloor(info.floorId, info.fromLoad); + + if (callback) callback(); +} + +events.prototype.changingFloor = function (floorId, heroLoc, fromLoad) { + this.eventdata.changingFloor(floorId, heroLoc, fromLoad); } ////// 转换楼层结束的事件 ////// @@ -566,6 +560,16 @@ events.prototype.afterChangeFloor = function (floorId, fromLoad) { return this.eventdata.afterChangeFloor(floorId, fromLoad); } +////// 是否到达过某个楼层 ////// +events.prototype.hasVisitedFloor = function (floorId) { + return core.getFlag("__visited__")[floorId] || false; +} + +////// 到达某楼层 ////// +events.prototype.visitFloor = function (floorId) { + core.getFlag("__visited__")[floorId] = true; +} + events.prototype._sys_passNet = function (data, callback) { this.passNet(data); if (callback) callback(); @@ -573,21 +577,8 @@ events.prototype._sys_passNet = function (data, callback) { ////// 经过一个路障 ////// events.prototype.passNet = function (data) { - // 有鞋子 if (core.hasItem('shoes')) return; - if (data.event.id=='lavaNet') { - // 血网 lavaNet 移动到 checkBlock 中处理 - /* - core.status.hero.hp -= core.values.lavaDamage; - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose(); - return; - } - core.drawTip('经过血网,生命-'+core.values.lavaDamage); - */ - } + // 血网 lavaNet 移动到 checkBlock 中处理 if (data.event.id=='poisonNet') { // 毒网 core.setFlag('debuff', 'poison'); core.insertAction('毒衰咒处理'); @@ -613,35 +604,26 @@ events.prototype.pushBox = function (data) { if (data.event.id!='box' && data.event.id!='boxed') return; // 判断还能否前进,看看是否存在事件 - var direction = core.getHeroLoc('direction'), nx=data.x+core.utils.scan[direction].x, ny=data.y+core.utils.scan[direction].y; + var direction = core.getHeroLoc('direction'), + nx = data.x + core.utils.scan[direction].x, ny = data.y + core.utils.scan[direction].y; - if (nx<0||nx>=core.bigmap.width||ny<0||ny>=core.bigmap.height) return; + // 检测能否推上去 + if (!core.canMoveHero() || !core.canMoveHero(data.x, data.y, direction)) return; + var nextId = core.getBlockId(nx, ny); + if (nextId != null && nextId != 'flower') return; - var block = core.getBlock(nx, ny, null, true); - if (block!=null && !(core.isset(block.block.event) && block.block.event.id=='flower')) - return; + core.setBlock(nextId==null?169:170, nx, ny); - if (block==null) { - core.status.thisMap.blocks.push(core.maps.initBlock(nx, ny, 169)); - block = core.getBlock(nx, ny); - } - else { - block.block.id=170; - block.block.event=core.maps.initBlock(null,null,170).event; - } - core.drawBlock(block.block); - - if (data.event.id=='box') { + if (data.event.id=='box') core.removeBlock(data.x, data.y); - } - else { - data.id=168; - data.event=core.maps.initBlock(null,null,168).event; - core.drawBlock(data); - } + else + core.setBlock(168, data.x, data.y); core.updateStatusBar(); + this._pushBox_moveHero(direction); +} +events.prototype._pushBox_moveHero = function (direction) { core.status.replay.animate = true; core.lockControl(); setTimeout(function () { @@ -655,8 +637,7 @@ events.prototype.pushBox = function (data) { core.replay(); } }); - }) - + }); } ////// 推箱子后的事件 ////// @@ -665,21 +646,14 @@ events.prototype.afterPushBox = function () { } events.prototype._sys_changeLight = function (data, callback) { - core.events.changeLight(data.x, data.y); + core.events.changeLight(data.event.id, data.x, data.y); if (callback) callback(); } ////// 改变亮灯(感叹号)的事件 ////// -events.prototype.changeLight = function(x, y) { - var block = core.getBlock(x, y); - if (block==null) return; - var index = block.index; - block = block.block; - if (block.event.id != 'light') return; - // 改变为dark - block.id = 166; - block.event = {'cls': 'terrains', 'id': 'darkLight', 'noPass': true}; - core.drawBlock(block); +events.prototype.changeLight = function(id, x, y) { + if (id != null && id != 'light') return; + core.setBlock(core.getNumberById('darkLight'), x, y); this.afterChangeLight(x,y); } diff --git a/libs/maps.js b/libs/maps.js index 82a40107..1d516e2b 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1110,6 +1110,25 @@ maps.prototype.getBlockInfo = function (block) { return {number:number, id:id, cls:cls, image:image, posX:posX, posY:posY, height:height, faceIds:faceIds}; } +////// 搜索某个图块出现的所有位置 ////// +maps.prototype.searchBlock = function (id, floorId, showDisable) { + if (typeof id == 'number') id = this.initBlock(0, 0, id).event.id; + floorId = floorId || core.status.floorId; + var result = []; + if (floorId instanceof Array) { + floorId.forEach(function (floorId) { + result = result.concat(core.searchBlock(id, floorId, showDisable)); + }); + return result; + } + for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) { + var block = core.status.maps[floorId].blocks[i]; + if (block.event.id == id && (showDisable || !block.disable)) + result.push({floorId: floorId, index: i, block: block}); + } + return result; +} + // -------- 启用/禁用图块,楼层贴图 -------- // ////// 将某个块从禁用变成启用状态 ////// @@ -1215,6 +1234,26 @@ maps.prototype.removeBlockByIds = function (floorId, ids) { }); } +////// 将地图中所有某个图块替换成另一个图块 ////// +maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) { + floorId = floorId || core.status.floorId; + if (floorId instanceof Array) { + floorId.forEach(function (floorId) { + core.replaceBlock(fromNumber, toNumber, floorId); + }); + return; + } + var toBlock = this.initBlock(0, 0, toNumber, true); + core.status.maps[floorId].blocks.forEach(function (block) { + if (block.id == fromNumber) { + block.id = toNumber; + for (var one in toBlock.event) { + block.event[one] = core.clone(toBlock.event[one]); + } + } + }); +} + ////// 显示前景/背景地图 ////// maps.prototype.showBgFgMap = function (name, loc, floorId, callback) { this._triggerBgFgMap('show', name, loc, floorId, callback); diff --git a/libs/ui.js b/libs/ui.js index c00865ab..9a1d4b47 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -352,13 +352,11 @@ ui.prototype.getTitleAndIcon = function (content) { var number = core.maps.getNumberById(v); if (number>0) { var block = core.maps.initBlock(0,0,number,true); - if (core.isset(block.event)) { - var cls = block.event.cls; - image = core.material.images[cls]; - icon = core.material.icons[cls][v]; - iconHeight = block.event.height; - animate = block.event.animate; - } + var cls = block.event.cls; + image = core.material.images[cls]; + icon = core.material.icons[cls][v]; + iconHeight = block.event.height; + animate = block.event.animate; } }; diff --git a/libs/utils.js b/libs/utils.js index 22fa2a90..ee12e6f9 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -1003,7 +1003,7 @@ utils.prototype._export = function (floorIds) { // check monster x.forEach(function (t) { var block = core.maps.initBlock(null, null, t); - if (core.isset(block.event) && block.event.cls.indexOf("enemy")==0) { + if (block.event.cls.indexOf("enemy")==0) { monsterMap[t] = block.event.id; } }) diff --git a/project/data.js b/project/data.js index 5802ae43..cfecf74f 100644 --- a/project/data.js +++ b/project/data.js @@ -393,7 +393,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "displayExtraDamage": true, "enableGentleClick": true, "potionWhileRouting": false, - "portalWithoutTrigger": true, + "ignoreChangeFloor": true, "canGoDeadZone": false, "enableMoveDirectly": true, "enableDisabledShop": true, diff --git a/project/functions.js b/project/functions.js index dead2159..4c8f9f6f 100644 --- a/project/functions.js +++ b/project/functions.js @@ -32,22 +32,22 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.material.items.shield5.cls = 'equips'; } }, - "setInitData": function (hard) { + "setInitData": function () { // 不同难度分别设置初始属性 - if (hard == 'Easy') { // 简单难度 + if (core.status.hard == 'Easy') { // 简单难度 core.setFlag('hard', 1); // 可以用flag:hard来获得当前难度 // 可以在此设置一些初始福利,比如设置初始生命值可以调用: // core.setStatus("hp", 10000); // 赠送一把黄钥匙可以调用 // core.setItem("yellowKey", 1); } - if (hard == 'Normal') { // 普通难度 + if (core.status.hard == 'Normal') { // 普通难度 core.setFlag('hard', 2); // 可以用flag:hard来获得当前难度 } - if (hard == 'Hard') { // 困难难度 + if (core.status.hard == 'Hard') { // 困难难度 core.setFlag('hard', 3); // 可以用flag:hard来获得当前难度 } - if (hard == 'Hell') { // 噩梦难度 + if (core.status.hard == 'Hell') { // 噩梦难度 core.setFlag('hard', 4); // 可以用flag:hard来获得当前难度 } @@ -55,6 +55,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = ["atk", "def", "mdef"].forEach(function (name) { core.setFlag("__" + name + "_buff__", 1); }); + // 设置已经到过的楼层 + core.setFlag("__visited__", {}); core.events.afterLoadData(); }, @@ -150,33 +152,50 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 转换楼层结束的事件;此函数会在整个楼层切换完全结束后再执行 // floorId是切换到的楼层;fromLoad若为true则代表是从读档行为造成的楼层切换 - // 如果是读档,则进行检查 + // 如果是读档,则进行检查(是否需要恢复事件) if (fromLoad) { core.events.recoverEvents(core.getFlag("__events__")); core.removeFlag("__events__"); - } - else { + } else { // 每次抵达楼层执行的事件 core.insertAction(core.floors[floorId].eachArrive); // 首次抵达楼层时执行的事件(后插入,先执行) - var visited = core.getFlag("__visited__", []); - if (visited.indexOf(floorId)===-1) { + if (!core.hasVisitedFloor(floorId)) { core.insertAction(core.floors[floorId].firstArrive); - visited.push(floorId); - core.setFlag("__visited__", visited); + core.visitFloor(floorId); } } }, - "addPoint": function (enemy) { - // 加点事件 - var point = enemy.point; - if (!core.flags.enableAddPoint || !core.isset(point) || point<=0) return []; + "beforeBattle": function (enemyId, x, y) { + // 战斗前触发的事件,可以加上一些战前特效(详见下面支援的例子) + // 此函数在“检测能否战斗和自动存档”【之后】执行。如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。 + // 返回true则将继续战斗,返回false将不再战斗。 - // 加点,返回一个choices事件 - // ----- 从V2.5.4开始,移动到“公共事件-加点事件”中 - core.setFlag('point', point); // 设置flag:point - return core.getCommonEvent('加点事件'); + // ------ 支援技能 ------ // + if (core.isset(x) && core.isset(y)) { + var index = x + "," + y, + cache = (core.status.checkBlock.cache || {})[index] || {}, + guards = cache.guards || []; + // 如果存在支援怪 + if (guards.length > 0) { + // 记录flag,当前要参与支援的怪物 + core.setFlag("__guards__" + x + "_" + y, guards); + var actions = []; + // 增加支援的特效动画(图块跳跃) + guards.forEach(function (g) { + core.push(actions, { "type": "jump", "from": [g[0], g[1]], "to": [x, y], "time": 300, "keep": false, "async": true }); + }); + core.push(actions, [ + { "type": "waitAsync" }, // 等待所有异步事件执行完毕 + { "type": "trigger", "loc": [x, y] } // 重要!重新触发本点事件(即重新触发战斗) + ]); + core.insertAction(actions); + return false; + } + } + + return true; }, "afterBattle": function (enemyId, x, y, callback) { // 战斗结束后触发的事件 @@ -192,7 +211,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (!core.isset((core.material.animates[equipAnimate] || {}).se)) core.playSound('attack.mp3'); // 强制战斗的战斗动画 - core.drawAnimate(equipAnimate, core.isset(x)?x:core.getHeroLoc('x'), core.isset(y)?y:core.getHeroLoc('y')); + core.drawAnimate(equipAnimate, core.isset(x) ? x : core.getHeroLoc('x'), core.isset(y) ? y : core.getHeroLoc('y')); var damage = core.enemys.getDamage(enemyId, x, y); if (damage == null) damage = core.status.hero.hp + 1; @@ -220,26 +239,24 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 获得金币和经验 - var money = enemy.money; - guards.forEach(function (g) { - money += core.material.enemys[g[2]].money; - }); + var money = guards.reduce(function (curr, g) { + return curr + core.material.enemys[g[2]].money; + }, enemy.money); if (core.hasItem('coin')) money *= 2; if (core.hasFlag('curse')) money = 0; core.status.hero.money += money; core.status.hero.statistics.money += money; - var experience = enemy.experience; - guards.forEach(function (g) { - experience += core.material.enemys[g[2]].experience; - }) + + var experience = guards.reduce(function (curr, g) { + return curr + core.material.enemys[g[2]].experience; + }, enemy.experience); if (core.hasFlag('curse')) experience = 0; core.status.hero.experience += experience; core.status.hero.statistics.experience += experience; + var hint = "打败 " + enemy.name; - if (core.flags.enableMoney) - hint += ",金币+" + money; - if (core.flags.enableExperience) - hint += ",经验+" + experience; + if (core.flags.enableMoney) hint += ",金币+" + money; + if (core.flags.enableExperience) hint += ",经验+" + experience; core.drawTip(hint); // 事件的处理 @@ -263,7 +280,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 仇恨属性:减半 if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) { - core.setFlag('hatred', parseInt(core.getFlag('hatred', 0) / 2)); + core.setFlag('hatred', Math.floor(core.getFlag('hatred', 0) / 2)); } // 自爆 if (core.enemys.hasSpecial(special, 19)) { @@ -327,43 +344,42 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.isset(callback)) callback(); }, - "afterOpenDoor": function(doorId,x,y,callback) { + "afterOpenDoor": function (doorId, x, y, callback) { // 开一个门后触发的事件 - + var todo = []; if (core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterOpenDoor[x+","+y]; + var event = core.floors[core.status.floorId].afterOpenDoor[x + "," + y]; if (core.isset(event)) { core.unshift(todo, event); } } - if (todo.length>0) { - core.events.insertAction(todo,x,y); + if (todo.length > 0) { + core.events.insertAction(todo, x, y); } if (core.status.event.id == null) { core.continueAutomaticRoute(); - } - else { + } else { core.clearContinueAutomaticRoute(); } if (core.isset(callback)) callback(); }, - "afterGetItem": function(itemId,x,y,callback) { + "afterGetItem": function (itemId, x, y, callback) { // 获得一个道具后触发的事件 core.playSound('item.mp3'); var todo = []; if (core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterGetItem[x+","+y]; + var event = core.floors[core.status.floorId].afterGetItem[x + "," + y]; if (core.isset(event)) { core.unshift(todo, event); } } - if (todo.length>0) { - core.events.insertAction(todo,x,y); + if (todo.length > 0) { + core.events.insertAction(todo, x, y); } if (core.isset(callback)) callback(); @@ -374,17 +390,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = }, "afterPushBox": function () { // 推箱子后的事件 - - var noBoxLeft = function () { - // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false - for (var i=0;i Date: Sat, 16 Mar 2019 02:30:22 +0800 Subject: [PATCH 013/153] Remove core.isset(block.event) --- libs/events.js | 6 +-- libs/maps.js | 101 ++++++++++++++++++------------------------- libs/ui.js | 3 +- project/functions.js | 9 ++-- project/items.js | 14 +++--- 5 files changed, 58 insertions(+), 75 deletions(-) diff --git a/libs/events.js b/libs/events.js index 7ef4ef98..2631afec 100644 --- a/libs/events.js +++ b/libs/events.js @@ -257,7 +257,7 @@ events.prototype._trigger = function (x, y) { var block = core.getBlock(x, y); if (block == null) return; block = block.block; - if (core.isset(block.event) && core.isset(block.event.trigger)) { + if (block.event.trigger) { var noPass = block.event.noPass, trigger = block.event.trigger; if (noPass) core.clearAutomaticRouteNode(x, y); if (trigger == 'ski') core.status.isSkiing = true; @@ -1283,7 +1283,7 @@ events.prototype.doAction = function() { var block=core.getBlock(toX, toY); if (block!=null) { block = block.block; - if (core.isset(block.event) && core.isset(block.event.trigger)) { + if (block.event.trigger) { core.status.event.data.x=block.x; core.status.event.data.y=block.y; core.status.event.data.list = [ @@ -1661,7 +1661,7 @@ events.prototype.doAction = function() { var block=core.getBlock(x,y); // 重新获得事件 if (block!=null) { block = block.block; - if (core.isset(block.event) && block.event.trigger=='action') { + if (block.event.trigger=='action') { core.status.event.data.list = [ {"todo": core.clone(block.event.data), "total": core.clone(block.event.data), "condition": "false"} ]; diff --git a/libs/maps.js b/libs/maps.js index 1d516e2b..22c42747 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -51,8 +51,7 @@ maps.prototype._mapIntoBlocks = function (map,floor,floorId){ 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); - if (core.isset(block.event)) blocks.push(block); + blocks.push(this.initBlock(j, i, (map[i]||[])[j], true, floor)); } } return blocks; @@ -87,6 +86,7 @@ maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { if (id==17) block.event = {"cls": "terrains", "id": "airwall", "noPass": true}; else if (id in this.blocksInfo) block.event = JSON.parse(JSON.stringify(this.blocksInfo[id])); else if (core.icons.getTilesetOffset(id)) block.event = {"cls": "tileset", "id": "X"+id, "noPass": true}; + else block.event = {'cls': 'terrains', 'id': 'none', 'noPass': false}; if (addInfo) this._addInfo(block); if (eventFloor) { @@ -100,33 +100,28 @@ maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { ////// 添加一些信息到block上 ////// maps.prototype._addInfo = function (block) { - if (core.isset(block.event)) { - if (block.event.cls.indexOf("enemy")==0 && !core.isset(block.event.trigger)) { - block.event.trigger = 'battle'; - } - if (block.event.cls == 'items' && !core.isset(block.event.trigger)) { - block.event.trigger = 'getItem'; - } - if (!core.isset(block.event.noPass)) { - if (block.event.cls != 'items') { - block.event.noPass = true; - } - } - if (!core.isset(block.event.animate)) { - block.event.animate = core.icons._getAnimateFrames(block.event.cls, false); - } - block.event.height = 32; - if (block.event.cls == 'enemy48' || block.event.cls == 'npc48') - block.event.height = 48; + if (block.event.cls.indexOf("enemy")==0 && !core.isset(block.event.trigger)) { + block.event.trigger = 'battle'; } + if (block.event.cls == 'items' && !core.isset(block.event.trigger)) { + block.event.trigger = 'getItem'; + } + if (!core.isset(block.event.noPass)) { + if (block.event.cls != 'items') { + block.event.noPass = true; + } + } + if (!core.isset(block.event.animate)) { + block.event.animate = core.icons._getAnimateFrames(block.event.cls, false); + } + block.event.height = 32; + if (block.event.cls == 'enemy48' || block.event.cls == 'npc48') + block.event.height = 48; } ////// 向该楼层添加剧本的自定义事件 ////// maps.prototype._addEvent = function (block, x, y, event) { if (!core.isset(event)) return; - if (!core.isset(block.event)) { // 本身是空地? - block.event = {'cls': 'terrains', 'id': 'none', 'noPass': false}; - } // event是字符串或数组? if (typeof event == "string") { event = {"data": [event]}; @@ -685,7 +680,6 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var block = this.initBlock(x, y, arr[y][x], true); - if (!core.isset(block.event)) continue; block.name = name; var blockInfo = this.getBlockInfo(block); if (!core.isset(blockInfo)) continue; @@ -1058,17 +1052,13 @@ maps.prototype.getBlock = function (x, y, floorId, showDisable) { ////// 获得某个点的blockId ////// maps.prototype.getBlockId = function (x, y, floorId, showDisable) { var block = core.getBlock(x, y, floorId, showDisable); - if (block == null) return null; - if (core.isset(block.block.event)) return block.block.event.id; - return null; + return block == null ? null : block.block.event.id; } ////// 获得某个点的blockCls ////// maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { var block = core.getBlock(x, y, floorId, showDisable); - if (block == null) return null; - if (core.isset(block.block.event)) return block.block.event.cls; - return null; + return block == null ? null : block.block.event.cls; } ////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 ////// @@ -1081,7 +1071,6 @@ maps.prototype.getBlockInfo = function (block) { if (block == 0) return null; block = this.initBlock(0, 0, block, true); } - if (!core.isset(block.event)) return null; var number = block.id, id = block.event.id, cls = block.event.cls, image = null, posX = 0, posY = 0, height = block.event.height || 32, faceIds = {}; @@ -1142,7 +1131,7 @@ maps.prototype.showBlock = function(x, y, floorId) { if (block.disable) { block.disable = false; // 在本层,添加动画 - if (floorId == core.status.floorId && core.isset(block.event)) { + if (floorId == core.status.floorId) { core.drawBlock(block); core.addGlobalAnimate(block); } @@ -1162,8 +1151,7 @@ maps.prototype.hideBlock = function (x, y, floorId) { if (floorId==core.status.floorId) { core.removeGlobalAnimate(x, y); core.clearMap('event', x * 32, y * 32, 32, 32); - var height = 32; - if (core.isset(block.block.event)) height=block.block.event.height||32; + var height = block.block.event.height || 32; if (height>32) core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); } @@ -1186,8 +1174,7 @@ maps.prototype.removeBlock = function (x, y, floorId) { if (floorId==core.status.floorId) { core.removeGlobalAnimate(x, y); core.clearMap('event', x * 32, y * 32, 32, 32); - var height = 32; - if (core.isset(block.block.event)) height=block.block.event.height||32; + var height = block.block.event.height||32; if (height>32) core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); } @@ -1333,30 +1320,28 @@ maps.prototype.setBlock = function (number, x, y, floorId) { var originBlock=core.getBlock(x,y,floorId,true); var block = this.initBlock(x,y,number,true,core.floors[floorId]); - if (core.isset(block.event)) { - if (floorId == core.status.floorId) { - core.removeGlobalAnimate(x, y); - core.clearMap('event', x * 32, y * 32, 32, 32); - if (originBlock != null) { - var height = (originBlock.block.event||{}).height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); - } - } - if (originBlock==null) { - core.status.maps[floorId].blocks.push(block); - } - else { - originBlock.block.id = number; - originBlock.block.event = block.event; - block = originBlock.block; - } - if (floorId==core.status.floorId && !block.disable) { - core.drawBlock(block); - core.addGlobalAnimate(block); - core.updateStatusBar(); + if (floorId == core.status.floorId) { + core.removeGlobalAnimate(x, y); + core.clearMap('event', x * 32, y * 32, 32, 32); + if (originBlock != null) { + var height = (originBlock.block.event||{}).height||32; + if (height>32) + core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); } } + if (originBlock==null) { + core.status.maps[floorId].blocks.push(block); + } + else { + originBlock.block.id = number; + originBlock.block.event = block.event; + block = originBlock.block; + } + if (floorId==core.status.floorId && !block.disable) { + core.drawBlock(block); + core.addGlobalAnimate(block); + core.updateStatusBar(); + } } ////// 改变前景背景的图块 ////// diff --git a/libs/ui.js b/libs/ui.js index 9a1d4b47..b5bdfe4e 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2283,8 +2283,7 @@ ui.prototype.drawStatistics = function () { if (floor.cannotViewMap && floorId!=core.status.floorId) return; blocks.forEach(function (block) { - if (!core.isset(block.event) || block.disable) - return; + if (block.disable) return; var event = block.event; if (event.cls.indexOf("enemy")==0) { var enemyId = event.id, enemy = core.material.enemys[enemyId]; diff --git a/project/functions.js b/project/functions.js index 4c8f9f6f..024e425c 100644 --- a/project/functions.js +++ b/project/functions.js @@ -109,8 +109,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 检查重生怪并重置 if (!fromLoad) { core.status.maps[floorId].blocks.forEach(function(block) { - if (block.disable && core.isset(block.event) && block.event.cls.indexOf('enemy')==0 && - core.enemys.hasSpecial(core.material.enemys[block.event.id].special, 23)) { + if (block.disable && core.enemys.hasSpecial(block.event.id, 23)) { block.disable = false; } }); @@ -523,7 +522,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (!core.isset(cache)) { // 没有该点的缓存,则遍历每个图块 core.status.maps[floorId].blocks.forEach(function (block) { - if (core.isset(block.event) && !block.disable) { + if (!block.disable) { // 获得该图块的ID var id = block.event.id, enemy = core.material.enemys[id]; @@ -1037,7 +1036,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.status.checkBlock.map = []; // 记录怪物地图 for (var n = 0; n < blocks.length; n++) { var block = blocks[n]; - if (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy') == 0) { + if (!block.disable && block.event.cls.indexOf('enemy') == 0) { var id = block.event.id, enemy = core.material.enemys[id]; if (core.isset(enemy)) { @@ -1045,7 +1044,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } // 血网 - if (core.isset(block.event) && !block.disable && + if (!block.disable && block.event.id == 'lavaNet' && block.event.trigger == 'passNet' && !core.hasItem("shoes")) { core.status.checkBlock.map[block.x + width * block.y] = "lavaNet"; } diff --git a/project/items.js b/project/items.js index 793296cb..1abd9db9 100644 --- a/project/items.js +++ b/project/items.js @@ -390,16 +390,16 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "canUseItemEffect": { "book": "true", "fly": "(function () {\n\treturn core.status.hero.flyRange.indexOf(core.status.floorId)>=0 && (core.status.maps[core.status.floorId]||{}).canFlyTo;\n})();", - "pickaxe": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", - "icePickaxe": "(function() {\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.ui = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();", - "bomb": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", - "hammer": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", - "earthquake": "(function () {\n\tvar able=false;\n\tvar ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable &&\n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", + "pickaxe": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "icePickaxe": "(function() {\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.ui = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();", + "bomb": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "hammer": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "earthquake": "(function () {\n\tvar able=false;\n\tvar ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable &&\n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", "centerFly": "(function () {\n\tvar toX = core.bigmap.width-1-core.getHeroLoc('x'), toY = core.bigmap.height-1-core.getHeroLoc('y');\n\tvar id = core.getBlockId(toX, toY);\n\treturn id == null;\n})();", "upFly": "(function() {\n\tvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\n\tif (index=0 && toX=0 && toY0) {\n\t\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\t\tvar mw = core.floors[toId].width, mh = core.floors[toId].height;\n\t\tif (toX>=0 && toX=0 && toY0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", - "bigKey": "(function() {\n\tvar able=false, ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", + "snow": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.event.id == 'lava' && core.nearHero(block.x, block.y)) {\n\t\t\tif (core.flags.snowFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", + "bigKey": "(function() {\n\tvar able=false, ids = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.event.id == 'yellowDoor') {\n\t\t\tids.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\table=true;\n\t}\n\treturn able;\n})();", "poisonWine": "core.hasFlag('poison');", "weakWine": "core.hasFlag('weak');", "curseWine": "core.hasFlag('curse');", From 32e760e9e6a3c9c15617965726f59920596f4889 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 03:03:02 +0800 Subject: [PATCH 014/153] remove flyRange --- _server/data.comment.js | 6 ------ _server/editor_mode.js | 1 - libs/actions.js | 41 ++++++++++++++++++++++++++++++----------- libs/control.js | 5 ++--- libs/events.js | 6 ------ libs/maps.js | 4 +++- libs/ui.js | 8 +++----- project/data.js | 1 - project/items.js | 4 ++-- 9 files changed, 40 insertions(+), 36 deletions(-) diff --git a/_server/data.comment.js b/_server/data.comment.js index bad2978f..c4ad3175 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -253,12 +253,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } } }, - "flyRange": { - "_leaf": true, - "_type": "textarea", - "_range": "thiseval instanceof Array", - "_data": "初始可飞的楼层;一般留空数组即可" - }, "loc": { "_type": "object", diff --git a/_server/editor_mode.js b/_server/editor_mode.js index 15950e8e..d23f4abe 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -339,7 +339,6 @@ editor_mode = function (editor) { editor_mode.prototype.indent = function (field) { var num = '\t'; if (field.indexOf("['main']") === 0) return 0; - if (field.indexOf("['flyRange']") !== -1) return 0; if (field === "['special']") return 0; return num; } diff --git a/libs/actions.js b/libs/actions.js index 00650fe4..7d5cba93 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -660,8 +660,8 @@ actions.prototype._sys_onmousewheel = function (direct) { // 楼层飞行器 if (core.status.lockControl && core.status.event.id == 'fly') { - if (direct==1) core.ui.drawFly(core.status.event.data+1); - if (direct==-1) core.ui.drawFly(core.status.event.data-1); + if (direct==1) core.ui.drawFly(this._getNextFlyFloor(1)); + if (direct==-1) core.ui.drawFly(this._getNextFlyFloor(-1)); return; } @@ -990,25 +990,44 @@ actions.prototype._clickBookDetail = function () { ////// 楼层传送器界面时的点击操作 ////// actions.prototype._clickFly = function(x,y) { - if ((x==10 || x==11) && y==9) core.ui.drawFly(core.status.event.data-1); - if ((x==10 || x==11) && y==5) core.ui.drawFly(core.status.event.data+1); - if ((x==10 || x==11) && y==10) core.ui.drawFly(core.status.event.data-10); - if ((x==10 || x==11) && y==4) core.ui.drawFly(core.status.event.data+10); + if ((x==10 || x==11) && y==9) core.ui.drawFly(this._getNextFlyFloor(-1)); + if ((x==10 || x==11) && y==5) core.ui.drawFly(this._getNextFlyFloor(1)); + if ((x==10 || x==11) && y==10) core.ui.drawFly(this._getNextFlyFloor(-10)); + if ((x==10 || x==11) && y==4) core.ui.drawFly(this._getNextFlyFloor(10)); if (x>=5 && x<=7 && y==12) core.ui.closePanel(); if (x>=0 && x<=9 && y>=3 && y<=11) - core.control.flyTo(core.status.hero.flyRange[core.status.event.data]); + core.control.flyTo(core.floorIds[core.status.event.data]); return; } ////// 楼层传送器界面时,按下某个键的操作 ////// actions.prototype._keyDownFly = function (keycode) { - if (keycode==37) core.ui.drawFly(core.status.event.data-10); - else if (keycode==38) core.ui.drawFly(core.status.event.data+1); - else if (keycode==39) core.ui.drawFly(core.status.event.data+10); - else if (keycode==40) core.ui.drawFly(core.status.event.data-1); + if (keycode==37) core.ui.drawFly(this._getNextFlyFloor(-10)); + else if (keycode==38) core.ui.drawFly(this._getNextFlyFloor(1)); + else if (keycode==39) core.ui.drawFly(this._getNextFlyFloor(10)); + else if (keycode==40) core.ui.drawFly(this._getNextFlyFloor(-1)); return; } +actions.prototype._getNextFlyFloor = function (delta, index) { + if (!core.isset(index)) index = core.status.event.data; + if (delta == 0) return index; + var sign = Math.sign(delta); + delta = Math.abs(delta); + var ans = index; + while (true) { + index += sign; + if (index < 0 || index >= core.floorIds.length) break; + var floorId = core.floorIds[index]; + if (core.status.maps[floorId].canFlyTo && core.hasVisitedFloor(floorId)) { + delta--; + ans = index; + } + if (delta == 0) break; + } + return ans; +} + ////// 楼层传送器界面时,放开某个键的操作 ////// actions.prototype._keyUpFly = function (keycode) { if (keycode==71 || keycode==27 || keycode==88) diff --git a/libs/control.js b/libs/control.js index a3e706f5..c44f8a70 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1912,9 +1912,8 @@ control.prototype.replay = function () { } else if (action.indexOf("fly:")==0) { var floorId=action.substring(4); - var toIndex=core.status.hero.flyRange.indexOf(floorId); - var nowIndex=core.status.hero.flyRange.indexOf(core.status.floorId); - if (core.hasItem('fly') && toIndex>=0 && nowIndex>=0) { + var toIndex=core.floorIds.indexOf(floorId); + if (core.hasItem('fly')) { core.ui.drawFly(toIndex); setTimeout(function () { if (!core.control.flyTo(floorId, function () {core.replay()})) { diff --git a/libs/events.js b/libs/events.js index 2631afec..3048b431 100644 --- a/libs/events.js +++ b/libs/events.js @@ -452,12 +452,6 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback core.clearContinueAutomaticRoute(); core.status.replay.animate=true; - if (core.status.maps[floorId].canFlyTo && core.status.hero.flyRange.indexOf(floorId)<0) { - core.status.hero.flyRange.push(floorId); - core.status.hero.flyRange.sort(function (a, b) { - return core.floorIds.indexOf(a) - core.floorIds.indexOf(b); - }) - } this._changeFloor_beforeChange(info, callback); } diff --git a/libs/maps.js b/libs/maps.js index 22c42747..5d7eb87e 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -51,7 +51,9 @@ maps.prototype._mapIntoBlocks = function (map,floor,floorId){ var mh = core.floors[floorId].height; for (var i = 0; i < mh; i++) { for (var j = 0; j < mw; j++) { - blocks.push(this.initBlock(j, i, (map[i]||[])[j], true, floor)); + var block = this.initBlock(j, i, (map[i]||[])[j], true, floor); + if (block.id != 0 || block.event.trigger) + blocks.push(block); } } return blocks; diff --git a/libs/ui.js b/libs/ui.js index b5bdfe4e..d055aada 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1575,11 +1575,9 @@ ui.prototype.drawBookDetail = function (index) { ////// 绘制楼层传送器 ////// ui.prototype.drawFly = function(page) { - if (page<0) page=0; - if (page>=core.status.hero.flyRange.length) page=core.status.hero.flyRange.length-1; core.status.event.data = page; - var floorId = core.status.hero.flyRange[page]; + var floorId = core.floorIds[page]; var title = core.status.maps[floorId].title; core.clearMap('ui'); @@ -1591,12 +1589,12 @@ ui.prototype.drawFly = function(page) { core.fillText('ui', '楼层跳跃', 208, 60, '#FFFFFF', "bold 28px "+globalFont); core.fillText('ui', '返回游戏', 208, 403, '#FFFFFF', "bold 15px "+globalFont) core.fillText('ui', title, 356, 247, '#FFFFFF', "bold 19px "+globalFont); - if (page0) { + if (core.actions._getNextFlyFloor(-1) != page) { core.fillText('ui', '▼', 356, 247 + 64, '#FFFFFF', "17px "+globalFont); core.fillText('ui', '▼', 356, 247 + 96, '#FFFFFF', "17px "+globalFont); core.fillText('ui', '▼', 356, 247 + 96 + 7, '#FFFFFF', "17px "+globalFont); diff --git a/project/data.js b/project/data.js index cfecf74f..4affc3ea 100644 --- a/project/data.js +++ b/project/data.js @@ -95,7 +95,6 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "tools": {}, "equips": {} }, - "flyRange": [], "loc": { "direction": "up", "x": 6, diff --git a/project/items.js b/project/items.js index 1abd9db9..1c464161 100644 --- a/project/items.js +++ b/project/items.js @@ -360,7 +360,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = }, "useItemEffect": { "book": "core.ui.drawBook(0);", - "fly": "core.ui.drawFly(core.status.hero.flyRange.indexOf(core.status.floorId));", + "fly": "core.ui.drawFly(core.floorIds.indexOf(core.status.floorId));", "earthquake": "core.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});", "pickaxe": "core.playSound('pickaxe.mp3');\ncore.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});", "icePickaxe": "core.removeBlockByIds(core.status.floorId, core.status.event.ui);\ncore.drawMap(core.status.floorId, function () {\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n});", @@ -389,7 +389,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = }, "canUseItemEffect": { "book": "true", - "fly": "(function () {\n\treturn core.status.hero.flyRange.indexOf(core.status.floorId)>=0 && (core.status.maps[core.status.floorId]||{}).canFlyTo;\n})();", + "fly": "(function () {\n\treturn core.status.maps[core.status.floorId].canFlyTo;\n})();", "pickaxe": "(function() {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && core.nearHero(block.x, block.y) && \n\t\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t\t// 四个方向\n\t\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse id2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\telse if (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", "icePickaxe": "(function() {\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\t\tcore.status.event.ui = [i];\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n})();", "bomb": "(function () {\n\tvar ids = [], id2s = [];\n\tfor (var i in core.status.thisMap.blocks) {\n\t\tvar block = core.status.thisMap.blocks[i];\n\t\tif (!block.disable && block.event.cls.indexOf('enemy')==0 && core.nearHero(block.x, block.y)) {\n\t\t\tvar enemy = core.material.enemys[block.event.id];\n\t\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\t\tids.push(i);\n\t\t\telse\n\t\t\t\tid2s.push(i);\n\t\t}\n\t}\n\tif (ids.length>0) {\n\t\tcore.status.event.ui = ids;\n\t\treturn true;\n\t}\n\tif (id2s.length==1) {\n\t\tcore.status.event.ui = id2s;\n\t\treturn true;\n\t}\n\treturn false;\n})();", From 2233da20c671e410664cd77301d26c82df5ec4e0 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 17:47:37 +0800 Subject: [PATCH 015/153] doAction V2.6 --- libs/actions.js | 4 +- libs/events.js | 1788 ++++++++++++++++++++++------------------------- 2 files changed, 831 insertions(+), 961 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 7d5cba93..6b0313a4 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -707,7 +707,7 @@ actions.prototype._sys_keyDownCtrl = function () { if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length==0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; - core.events.doAction(); + core.doAction(); } return true; } @@ -742,7 +742,7 @@ actions.prototype._sys_longClick_lockControl = function (x, y) { if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length == 0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; - core.events.doAction(); + core.doAction(); return true; } } diff --git a/libs/events.js b/libs/events.js index 3048b431..f5a8f265 100644 --- a/libs/events.js +++ b/libs/events.js @@ -718,7 +718,7 @@ events.prototype.doEvent = function (data, x, y, prefix) { else if (this["_action_"+type]) this["_action_"+type](data, x, y, prefix); else { core.insertAction("未知的自定义事件: "+type+"!"); - this.doAction(); + core.doAction(); } } @@ -728,29 +728,49 @@ events.prototype.doEvents = function (list, x, y, callback) { if (!(list instanceof Array)) { list = [list]; } - - core.status.event = {'id': 'action', 'data': { - 'list': [ - {"todo": core.clone(list), "total": core.clone(list), "condition": "false"} - ], 'x': x, 'y': y, 'callback': callback - }} - + this.setEvents(list, x, y, callback); // 停止勇士 core.waitHeroToStop(function() { core.lockControl(); - core.events.doAction(); + core.doAction(); }); } +events.prototype.setEvents = function (list, x, y, callback) { + var data = core.status.event.data || {}; + if (core.isset(list)) + data.list = [{todo: core.clone(list), total: core.clone(list), condition: "false"}]; + if (core.isset(x)) data.x = x; + if (core.isset(y)) data.y = y; + if (core.isset(callback)) data.callback = callback; + core.status.event = {id: 'action', data: data}; +} + ////// 执行当前自定义事件列表中的下一个事件 ////// events.prototype.doAction = function() { // 清空boxAnimate和UI层 core.status.boxAnimateObjs = []; clearInterval(core.status.event.interval); core.status.event.interval = null; - core.clearLastEvent(); + // 判定是否执行完毕 + if (this._doAction_finishEvents()) return; + // 当前点坐标和前缀 + var x = core.status.event.data.x, y = core.status.event.data.y; + var prefix = [core.status.floorId||"f", core.isset(x)?x:"x", core.isset(y)?y:"y"].join("@"); + var current = core.status.event.data.list[0]; + if (this._popEvents(current, prefix)) return; + // 当前要执行的事件 + var data = current.todo.shift(); + core.status.event.data.current = data; + if (typeof data == "string") + data = {"type": "text", "text": data}; + core.status.event.data.type = data.type; + this.doEvent(data, x, y, prefix); + return; +} +events.prototype._doAction_finishEvents = function () { // 事件处理完毕 if (core.status.event.data.list.length==0) { var callback = core.status.event.data.callback; @@ -758,955 +778,23 @@ events.prototype.doAction = function() { if (core.isset(callback)) callback(); core.replay(); - return; + return true; } + return false; +} - var x=core.status.event.data.x, y=core.status.event.data.y; - var prefix = [core.status.floorId||"f", core.isset(x)?x:"x", core.isset(y)?y:"y"].join("@"); - - var current = core.status.event.data.list[0]; +events.prototype._popEvents = function (current, prefix) { if (current.todo.length == 0) { // current list is empty if (core.calValue(current.condition, prefix)) { // check condition current.todo = core.clone(current.total); } else { - core.status.event.data.list.shift(); // remove stackc + core.status.event.data.list.shift(); // remove stack } - this.doAction(); - return; + core.doAction(); + return true; } - var data = current.todo.shift(); - core.status.event.data.current = data; - - // 不同种类的事件 - - // 如果是文字:显示 - if (typeof data == "string") { - core.status.event.data.type='text'; - // 如果是正在回放中,不显示 - if (core.isReplaying()) - core.events.doAction(); - else - core.ui.drawTextBox(data); - return; - } - core.status.event.data.type=data.type; - switch (data.type) { - case "text": // 文字/对话 - if (core.isReplaying()) - core.events.doAction(); - else - core.ui.drawTextBox(data.text, data.showAll); - break; - case "autoText": - if (core.isReplaying()) - core.events.doAction(); - else { - core.ui.drawTextBox(data.text); - setTimeout(function () { - core.events.doAction(); - }, data.time || 3000); - } - break; - case "scrollText": // 滚动剧情文本 - if (core.isReplaying()) - core.events.doAction(); - else { - var content = core.replaceText(data.text); - var time = data.time || 5000; - if (data.async) { - core.ui.drawScrollText(content, time); - core.events.doAction(); - } - else { - core.ui.drawScrollText(content, time, function() { - core.events.doAction(); - }); - } - } - break; - case "comment": - this.doAction(); - break; - case "setText": // 设置文本状态 - ["position", "offset", "bold", "titlefont", "textfont", "time"].forEach(function (t) { - if (core.isset(data[t])) core.status.textAttribute[t]=data[t]; - }); - ["background", "title", "text"].forEach(function (t) { - if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length>=3) { - if (data[t].length==3) data[t].push(1); - core.status.textAttribute[t]=data[t]; - } - if (t=='background' && core.isset(data[t])) { - var img = core.material.images.images[data[t]]; - if (core.isset(img) && img.width==192 && img.height==128) { - core.status.textAttribute[t]=data[t]; - } - } - }); - core.setFlag('textAttribute', core.status.textAttribute); - core.events.doAction(); - break; - case "tip": - core.drawTip(core.replaceText(data.text)); - core.events.doAction(); - break; - case "show": // 显示 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - if (core.isset(data.time) && data.time>0 && (!core.isset(data.floorId) || data.floorId==core.status.floorId)) { - if (data.async) { - core.animateBlock(data.loc, 'show', data.time); - this.doAction(); - } - else { - core.animateBlock(data.loc,'show', data.time, function () { - core.events.doAction(); - }); - } - } - else { - data.loc.forEach(function (t) { - core.showBlock(t[0],t[1],data.floorId); - }) - this.doAction(); - } - break; - case "hide": // 消失 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - if (core.isset(data.time) && data.time>0 && (!core.isset(data.floorId) || data.floorId==core.status.floorId)) { - data.loc.forEach(function (t) { - core.hideBlock(t[0],t[1],data.floorId); - }); - if (data.async) { - core.animateBlock(data.loc, 'hide', data.time); - this.doAction(); - } - else { - core.animateBlock(data.loc,'hide', data.time, function () { - core.events.doAction(); - }); - } - } - else { - data.loc.forEach(function (t) { - core.removeBlock(t[0],t[1],data.floorId) - }) - this.doAction(); - } - break; - case "setBlock": // 设置某图块 - { - if (core.isset(data.loc)) { - x=core.calValue(data.loc[0], prefix); - y=core.calValue(data.loc[1], prefix); - } - core.setBlock(data.number, x, y, data.floorId); - this.doAction(); - break; - } - case "showFloorImg": // 显示贴图 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.showFloorImage(data.loc, data.floorId, function() { - core.events.doAction(); - }) - break; - case "hideFloorImg": // 隐藏贴图 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.hideFloorImage(data.loc, data.floorId, function() { - core.events.doAction(); - }) - break; - case "showBgFgMap": // 显示图层块 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.showBgFgMap(data.name, data.loc, data.floorId, function() { - core.events.doAction(); - }) - break; - case "hideBgFgMap": // 隐藏图层块 - if (!core.isset(data.loc)) - data.loc = [x,y]; - if ((typeof data.loc[0] == 'number' || typeof data.loc[0] == 'string') - && (typeof data.loc[1] == 'number' || typeof data.loc[1] == 'string')) - data.loc = [[core.calValue(data.loc[0], prefix), core.calValue(data.loc[1], prefix)]]; - core.maps.hideBgFgMap(data.name, data.loc, data.floorId, function() { - core.events.doAction(); - }) - break; - case "setBgFgBlock": // 设置图层块 - { - if (core.isset(data.loc)) { - x=core.calValue(data.loc[0], prefix); - y=core.calValue(data.loc[1], prefix); - } - core.setBgFgBlock(data.name, data.number, x, y, data.floorId); - this.doAction(); - break; - } - case "follow": // 跟随 - if (core.isset(core.material.images.images[data.name]) - && core.material.images.images[data.name].width==128) { - if (!core.isset(core.status.hero.followers)) - core.status.hero.followers = []; - core.status.hero.followers.push({"img": data.name}); - core.control.gatherFollowers(); - core.clearMap('hero'); - core.drawHero(); - } - this.doAction(); - break; - case "unfollow": // 取消跟随 - if (core.isset(core.status.hero.followers)) { - var remove = false; - if (!core.isset(data.name) && core.status.hero.followers.length>0) { - core.status.hero.followers = []; - remove=true; - } - if (core.isset(data.name)) { - for (var i=0;icore.itemCount(itemId)) // 效果 - core.getItem(itemId,value-core.itemCount(itemId)); - else core.setItem(itemId, value); - } - // flag - if (data.name.indexOf("flag:")==0) { - core.setFlag(data.name.substring(5), value); - } - // switch - if (data.name.indexOf("switch:")==0) { - core.setFlag((prefix||"global")+"@"+data.name.substring(7), value); - } - } - catch (e) {main.log(e)} - core.updateStatusBar(); - this.doAction(); - break; - case "setFloor": - core.status.maps[data.floorId||core.status.floorId][data.name] = core.calValue(data.value, prefix); - core.updateStatusBar(); - this.doAction(); - break; - case "setGlobalAttribute": - if (typeof data.value == 'string') { - if ((data.value.charAt(0)=='"' && data.value.charAt(data.value.length-1)=='"') - || (data.value.charAt(0)=="'" && data.value.charAt(data.value.length-1)=="'")) - data.value = data.value.substring(1, data.value.length-1); - // --- 检查 [] - if (data.value.charAt(0) == '[' && data.value.charAt(data.value.length-1)==']') - data.value = eval(data.value); - } - core.status.globalAttribute[data.name] = data.value; - core.control.updateGlobalAttribute(data.name); - core.setFlag('globalAttribute', core.status.globalAttribute); - this.doAction(); - break; - case "setGlobalValue": - core.values[data.name] = data.value; - this.doAction(); - break; - case "setGlobalFlag": - { - var flags = core.getFlag("globalFlags", {}); - flags[data.name] = data.value; - core.flags[data.name] = data.value; - core.setFlag("globalFlags", flags); - core.resize(); - this.doAction(); - break; - } - case "setHeroIcon": - { - this.setHeroIcon(data.name); - this.doAction(); - break; - } - case "input": - { - var value; - if (core.isReplaying()) { - var action = core.status.replay.toReplay.shift(); - if (action.indexOf("input:")==0 ) { - value=parseInt(action.substring(6)); - } - else { - core.stopReplay(); - core.drawTip("录像文件出错"); - return; - } - } - else { - core.interval.onDownInterval = 'tmp'; - value = prompt(core.replaceText(data.text)); - } - value = Math.abs(parseInt(value)||0); - core.status.route.push("input:"+value); - core.setFlag("input", value); - this.doAction(); - } - break; - case "input2": - { - var value; - if (core.isReplaying()) { - var action = core.status.replay.toReplay.shift(); - try { - if (action.indexOf("input2:")!=0) throw new Error("Input2 Error. Current action: "+action); - value = core.decodeBase64(action.substring(7)); - } - catch (e) { - main.log(e); - core.stopReplay(); - core.drawTip("录像文件出错"); - return; - } - } - else { - core.interval.onDownInterval = 'tmp'; - value = prompt(core.replaceText(data.text)); - if (!core.isset(value)) value=""; - } - core.status.route.push("input2:"+core.encodeBase64(value)); - core.setFlag("input", value); - this.doAction(); - } - break; - case "if": // 条件判断 - if (core.calValue(data.condition, prefix)) - core.events.insertAction(data["true"]) - else - core.events.insertAction(data["false"]) - this.doAction(); - break; - case "switch": // 条件选择 - var key = core.calValue(data.condition, prefix) - for (var i = 0; i < data.caseList.length; i++) { - if (data.caseList[i]["case"]=="default" || core.calValue(data.caseList[i]["case"], prefix) == key) { - core.events.insertAction(data.caseList[i].action); - break; - } - } - this.doAction(); - break; - case "choices": // 提供选项 - if (core.isReplaying()) { - if (core.status.replay.toReplay.length==0) { // 回放完毕 - core.status.replay.replaying=false; - core.drawTip("录像回放完毕"); - } - else { - var action = core.status.replay.toReplay.shift(), index; - if (action == 'turn') action = core.status.replay.toReplay.shift(); - if (action.indexOf("choices:")==0 && ((index=parseInt(action.substring(8)))>=0) && index=1000000) { - core.setFlag('type', 1); - var px = parseInt((value-1000000)/1000), py = value%1000; - core.setFlag('px', px); - core.setFlag('py', py); - core.setFlag('x', parseInt(px/32)); - core.setFlag('y', parseInt(py/32)); - } - else if (value>=10000) { - core.setFlag('type', 1); - var x = parseInt((value-10000)/100), y = value%100; - core.setFlag('px', 32*x+16); - core.setFlag('py', 32*y+16); - core.setFlag('x', x); - core.setFlag('y', y); - } - else { - core.setFlag('type', 0); - core.setFlag('keycode', value); - } - core.events.doAction(); - } - else { - core.stopReplay(); - core.drawTip("录像文件出错"); - } - } - break; - case "waitAsync": // 等待所有异步事件执行完毕 - { - var test = window.setInterval(function () { - if (Object.keys(core.animateFrame.asyncId).length==0) { - clearInterval(test); - core.events.doAction(); - } - }, 50); - break; - } - case "revisit": // 立刻重新执行该事件 - { - var block=core.getBlock(x,y); // 重新获得事件 - if (block!=null) { - block = block.block; - if (block.event.trigger=='action') { - core.status.event.data.list = [ - {"todo": core.clone(block.event.data), "total": core.clone(block.event.data), "condition": "false"} - ]; - } - } - this.doAction(); - break; - } - case "callBook": // 呼出怪物手册 - if (core.isReplaying() || !core.hasItem('book')) { - this.doAction(); - } - else { - var e = core.clone(core.status.event.data); - core.ui.closePanel(); - core.openBook(); - core.status.event.interval = e; - } - break; - case "callSave": // 呼出存档页面 - if (core.isReplaying() || core.hasFlag("__events__")) { - core.removeFlag("__events__"); - this.doAction(); - } - else { - var e = core.clone(core.status.event.data); - core.ui.closePanel(); - core.save(); - core.status.event.interval = e; - } - break; - case "callLoad": // 呼出读档页面 - if (core.isReplaying()) { - this.doAction(); - } - else { - var e = core.clone(core.status.event.data); - core.ui.closePanel(); - core.load(); - core.status.event.interval = e; - } - break; - case "exit": // 立刻结束事件 - core.status.event.data.list = []; - core.events.doAction(); - break; - default: - core.status.event.data.type='text'; - core.ui.drawTextBox("\t[警告]出错啦!\n"+data.type+" 事件不被支持..."); - } - return; + return false; } ////// 往当前事件列表之前添加一个或多个事件 ////// @@ -1715,25 +803,21 @@ events.prototype.insertAction = function (action, x, y, callback) { // ------ 判定commonEvent var commonEvent = this.getCommonEvent(action); - if (core.isset(commonEvent) && commonEvent instanceof Array) { - action = commonEvent; - } + if (commonEvent instanceof Array) action = commonEvent; if (!core.isset(action)) return; if (core.status.event.id != 'action') { this.doEvents(action, x, y, callback); } else { - core.unshift(core.status.event.data.list[0].todo, action) - if (core.isset(x)) core.status.event.data.x=x; - if (core.isset(y)) core.status.event.data.y=y; - if (core.isset(callback)) core.status.event.data.callback=callback; + core.unshift(core.status.event.data.list[0].todo, action); + this.setEvents(null, x, y, callback); } } ////// 获得一个公共事件 ////// events.prototype.getCommonEvent = function (name) { - if (!core.isset(name) || !(typeof name === 'string')) return null; + if (!core.isset(name) || typeof name !== 'string') return null; return this.commonEvent[name] || null; } @@ -1752,7 +836,793 @@ events.prototype.recoverEvents = function (data) { return false; } -// ------ 样板自带的自定义事件处理 ------ // +// ------ 样板提供的的自定义事件 ------ // + +events.prototype.__action_checkReplaying = function () { + if (core.isReplaying()) { + core.doAction(); + return true; + } + return false; +} + +events.prototype.__action_getLoc = function (loc, x, y, prefix) { + if (loc) { + x = core.calValue(loc[0], prefix); + y = core.calValue(loc[1], prefix); + } + return [x,y]; +} + +events.prototype.__action_getHeroLoc = function (loc, prefix) { + return this.__action_getLoc(loc, core.getHeroLoc('x'), core.getHeroLoc('y'), prefix); +} + +events.prototype.__action_getLoc2D = function (loc, x, y, prefix) { + if (!(loc && loc[0] instanceof Array)) + loc = [this.__action_getLoc(data.loc, x, y, prefix)]; + return loc; +} + +events.prototype.__action_doAsyncFunc = function (isAsync, func) { + var parameters = Array.prototype.slice.call(arguments, 2); + if (isAsync) { + func.apply(this, parameters); + core.doAction(); + } + else { + func.apply(this, parameters.concat(core.doAction)); + } +} + +events.prototype._action_text = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + core.ui.drawTextBox(data.text, data.showAll); +} + +events.prototype._action_autoText = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + core.ui.drawTextBox(data.text); + setTimeout(core.doAction, data.time || 3000); +} + +events.prototype._action_scrollText = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + this.__action_doAsyncFunc(data.async, core.ui.drawScrollText, data.text, data.time || 5000); +} + +events.prototype._action_comment = function (data, x, y, prefix) { + core.doAction(); +} + +events.prototype._action_setText = function (data, x, y, prefix) { + ["position", "offset", "bold", "titlefont", "textfont", "time"].forEach(function (t) { + if (core.isset(data[t])) core.status.textAttribute[t]=data[t]; + }); + ["background", "title", "text"].forEach(function (t) { + if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length>=3) { + if (data[t].length==3) data[t].push(1); + core.status.textAttribute[t]=data[t]; + } + if (t=='background' && core.isset(data[t])) { + var img = core.material.images.images[data[t]]; + if (core.isset(img) && img.width==192 && img.height==128) { + core.status.textAttribute[t]=data[t]; + } + } + }); + core.setFlag('textAttribute', core.status.textAttribute); + core.doAction(); +} + +events.prototype._action_tip = function (data, x, y, prefix) { + core.drawTip(core.replaceText(data.text)); + core.doAction(); +} + +events.prototype._action_show = function (data, x, y, prefix) { + data.loc = this.__action_getLoc2D(data.loc, x, y, prefix); + if (data.time>0 && !(data.floorId && data.floorId != core.status.floorId)) { + this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, 'show', data.time); + } + else { + data.loc.forEach(function (t) { + core.showBlock(t[0], t[1], data.floorId); + }); + core.doAction(); + } +} + +events.prototype._action_hide = function (data, x, y, prefix) { + data.loc = this.__action_getLoc2D(data.loc, x, y, prefix); + if (data.time>0 && !(data.floorId && data.floorId != core.status.floorId)) { + data.loc.forEach(function (t) { + core.hideBlock(t[0], t[1], data.floorId); + }); + this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, 'hide', data.time); + } + else { + data.loc.forEach(function (t) { + core.removeBlock(t[0],t[1],data.floorId) + }); + core.doAction(); + } +} + +events.prototype._action_setBlock = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + core.setBlock(data.number, loc[0], loc[1], data.floorId); + core.doAction(); +} + +events.prototype._action_showFloorImg = function (data, x, y, prefix) { + core.maps.showFloorImage(this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction); +} + +events.prototype._action_hideFloorImg = function (data, x, y, prefix) { + core.maps.hideFloorImage(this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction); +} + +events.prototype._action_showBgFgMap = function (data, x, y, prefix) { + core.maps.showBgFgMap(data.name, this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction) +} + +events.prototype._action_hideBgFgMap = function (data, x, y, prefix) { + core.maps.hideBgFgMap(data.name, this.__action_getLoc2D(data.loc, x, y, prefix), data.floorId, core.doAction); +} + +events.prototype._action_setBgFgBlock = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + core.setBgFgBlock(data.name, data.number, loc[0], loc[1], data.floorId); + core.doAction(); +} + +events.prototype._action_follow = function (data, x, y, prefix) { + this.follow(data.name); + core.doAction(); +} + +events.prototype._action_unfollow = function (data, x, y, prefix) { + this.unfollow(data.name); + core.doAction(); +} + +events.prototype._action_animate = function (data, x, y, prefix) { + if (data.loc == 'hero') data.loc = [core.getHeroLoc('x'), core.getHeroLoc('y')]; + else data.loc = this.__action_getLoc(data.loc, x, y, prefix); + this.__action_doAsyncFunc(data.async, core.drawAnimate, data.name, data.loc[0], data.loc[1]); +} + +events.prototype._action_move = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + this.__action_doAsyncFunc(data.async, core.moveBlock, loc[0], loc[1], data.steps, data.time, data.keep); +} + +events.prototype._action_moveHero = function (data, x, y, prefix) { + this.__action_doAsyncFunc(data.async, core.eventMoveHero, data.steps, data.time); +} + +events.prototype._action_jump = function (data, x, y, prefix) { + var from = this.__action_getLoc(data.from, x, y, prefix), + to = this.__action_getLoc(data.to, x, y, prefix); + this.__action_doAsyncFunc(data.async, core.jumpBlock, from[0], from[1], to[0], to[1], data.time, data.keep); +} + +events.prototype._action_jumpHero = function (data, x, y, prefix) { + var loc = this.__action_getHeroLoc(data.loc, prefix); + this.__action_doAsyncFunc(data.async, core.jumpHero, loc[0], loc[1], data.time); +} + +events.prototype._action_changeFloor = function (data, x, y, prefix) { + var loc = this.__action_getHeroLoc(data.loc, prefix); + var heroLoc = {x: loc[0], y: loc[1], direction: data.direction}; + core.changeFloor(data.floorId || core.status.floorId, null, heroLoc, data.time, function() { + core.lockControl(); + core.doAction(); + }); +} + +events.prototype._action_changePos = function (data, x, y, prefix) { + core.clearMap('hero'); + var loc = this.__action_getHeroLoc(data.loc, prefix); + core.setHeroLoc('x', loc[0]); + core.setHeroLoc('y', loc[1]); + if (data.direction) core.setHeroLoc('direction', data.direction); + core.drawHero(); + core.doAction(); +} + +events.prototype._action_showImage = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, 0, 0, prefix); + if (core.isReplaying()) data.time = 0; + var image = core.material.images.images[data.image]; + if (!core.isset(image)) return core.doAction(); + this.__action_doAsyncFunc(data.async || data.time == 0, this.showImage, + data.code, image, loc[0], loc[1], data.dw, data.dh, data.opacity, data.time); +} + +events.prototype._action_showTextImage = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, 0, 0, prefix); + if (core.isReplaying()) data.time = 0; + this.__action_doAsyncFunc(data.async || data.time == 0, this.showImage, + data.code, this.textImage(data.text), loc[0], loc[1], 100, 100, data.opacity, data.time); +} + +events.prototype._action_hideImage = function (data, x, y, prefix) { + if (core.isReplaying()) data.time = 0; + this.__action_doAsyncFunc(data.async || data.time == 0, this.hideImage, data.code, data.time); +} + +events.prototype._action_showGif = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, 0, 0, prefix); + this.showGif(data.name, loc[0], loc[1]); + core.doAction(); +} + +events.prototype._action_moveImage = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + this.__action_doAsyncFunc(data.async, this.moveImage, data.code, data.to, data.opacity, data.time); +} + +events.prototype._action_setFg = function (data, x, y, prefix) { + if (data.async) { + core.setFg(data.color, data.time); + core.setFlag('__color__', data.color || null); + core.doAction(); + } + else { + core.setFg(data.color, data.time, function() { + core.setFlag('__color__', data.color || null); + core.doAction(); + }); + } +} + +events.prototype._action_screenFlash = function (data, x, y, prefix) { + this.__action_doAsyncFunc(data.async, core.screenFlash, data.color, data.time, data.times); +} + +events.prototype._action_setWeather = function (data, x, y, prefix) { + core.setWeather(data.name, data.level); + if (data.name == 'rain' || data.name == 'snow' || data.name == 'fog') + core.setFlag('__weather__', [data.name, data.level]); + else core.removeFlag('__weather__'); + core.doAction(); +} + +events.prototype._action_openDoor = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + var floorId = data.floorId || core.status.floorId; + if (floorId == core.status.floorId) { + var _callback = function () { + core.lockControl(); + core.doAction(); + } + if (!core.openDoor(null, loc[0], loc[1], data.needKey, _callback)) + _callback(); + } + else { + core.removeBlock(loc[0], loc[1], floorId); + core.doAction(); + } +} + +events.prototype._action_useItem = function (data, x, y, prefix) { + // 考虑到可能覆盖楼传事件的问题,这里不对fly进行检查。 + if (data.id != 'book' && core.canUseItem(data.id)) { + core.useItem(data.id, true, core.doAction); + } + else { + core.drawTip("当前无法使用"+((core.material.items[data.id]||{}).name||"未知道具")); + core.doAction(); + } +} + +events.prototype._action_openShop = function (data, x, y, prefix) { + if (core.isReplaying()) { // 正在播放录像,简单将visited置为true + core.status.shops[data.id].visited = true; + this.setEvents([]); + core.doAction(); + } + else + this.openShop(data.id); +} + +events.prototype._action_disableShop = function (data, x, y, prefix) { + this.disableQuickShop(data.id); + core.doAction(); +} + +events.prototype._action_battle = function (data, x, y, prefix) { + this.battle(data.id, null, null, true, core.doAction); +} + +events.prototype._action_trigger = function (data, x, y, prefix) { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + var block = core.getBlock(loc[0], loc[1]); + if (block != null && block.block.event.trigger) { + block = block.block; + this.setEvents([], block.x, block.y); + if (block.event.trigger == 'action') + this.setEvents(block.event.data); + else { + core.doSystemEvent(block.event.trigger, block, function () { + core.lockControl(); + core.doAction(); + }); + return; + } + } + core.doAction(); +} + +events.prototype._action_insert = function (data, x, y, prefix) { + if (core.isset(data.name)) { // 公共事件 + core.insertAction(this.getCommonEvent(data.name)); + } + else { + var loc = this.__action_getLoc(data.loc, x, y, prefix); + var floorId = data.floorId || core.status.floorId; + var event = core.floors[floorId].events[loc[0]+","+loc[1]]; + if (core.isset(event)) { + if (core.isset(event.data)) event = event.data; + this.insertAction(event); + } + } + core.doAction(); +} + +events.prototype._action_playBgm = function (data, x, y, prefix) { + core.playBgm(data.name); + core.doAction(); +} + +events.prototype._action_pauseBgm = function (data, x, y, prefix) { + core.pauseBgm(); + core.doAction(); +} + +events.prototype._action_resumeBgm = function (data, x, y, prefix) { + core.resumeBgm(); + core.doAction(); +} + +events.prototype._action_loadBgm = function (data, x, y, prefix) { + core.loadBgm(data.name); + core.doAction(); +} + +events.prototype._action_freeBgm = function (data, x, y, prefix) { + core.freeBgm(data.name); + core.doAction(); +} + +events.prototype._action_playSound = function (data, x, y, prefix) { + core.playSound(data.name); + core.doAction(); +} + +events.prototype._action_stopSound = function (data, x, y, prefix) { + core.stopSound(); + core.doAction(); +} + +events.prototype._action_setVolume = function (data, x, y, prefix) { + data.value = core.clamp(parseInt(data.value)/100, 0, 1); + core.setFlag("__volume__", data.value); + this.__action_doAsyncFunc(data.async, this.setVolume, data.value, data.time || 0); +} + +events.prototype._action_setValue = function (data, x, y, prefix) { + this.setValue(data.name, data.value, prefix); + core.doAction(); +} + +events.prototype._action_setValue2 = function (data, x, y, prefix) { + this.setValue2(data.name, data.value, prefix); + core.doAction(); +} + +events.prototype._action_setFloor = function (data, x, y, prefix) { + this.setFloorInfo(data.name, data.value, data.floorId, prefix); + core.doAction(); +} + +events.prototype._action_setGlobalAttribute = function (data, x, y, prefix) { + this.setGlobalAttribute(data.name, data.value); + core.doAction(); +} + +events.prototype._action_setGlobalValue = function (data, x, y, prefix) { + core.values[data.name] = data.value; + core.doAction(); +} + +events.prototype._action_setGlobalFlag = function (data, x, y, prefix) { + this.setGlobalFlag(data.name, data.value); + core.doAction(); +} + +events.prototype._action_setHeroIcon = function (data, x, y, prefix) { + this.setHeroIcon(data.name); + core.doAction(); +} + +events.prototype._action_input = function (data, x, y, prefix) { + var value = this.__action_getInput(data.text, false); + if (value == null) return; + value = Math.abs(parseInt(value)||0); + core.status.route.push("input:" + value); + core.setFlag("input", value); + core.doAction(); +} + +events.prototype._action_input2 = function (data, x, y, prefix) { + var value = this.__action_getInput(data.text, true); + if (value == null) return; + core.status.route.push("input2:" + core.encodeBase64(value)); + core.setFlag("input", value); + core.doAction(); +} + +events.prototype.__action_getInput = function (hint, isText) { + var value, prefix = isText?"input2:":"input:"; + if (core.isReplaying()) { + var action = core.status.replay.toReplay.shift(); + try { + if (action.indexOf(prefix)!=0) + throw new Error("录像文件出错!当前需要一个 "+prefix+" 项,实际为 "+action); + if (isText) value = core.decodeBase64(action.substring(7)); + else value = parseInt(action.substring(6)); + } + catch (e) { + main.log(e); + core.stopReplay(); + core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type":"exit"}]); + core.doAction(); + return null; + } + } + else { + core.interval.onDownInterval = 'tmp'; + value = prompt(core.replaceText(hint)); + if (!core.isset(value)) value=""; + } + return value; +} + +events.prototype._action_if = function (data, x, y, prefix) { + if (core.calValue(data.condition, prefix)) + core.events.insertAction(data["true"]) + else + core.events.insertAction(data["false"]) + core.doAction(); +} + +events.prototype._action_switch = function (data, x, y, prefix) { + var key = core.calValue(data.condition, prefix) + for (var i = 0; i < data.caseList.length; i++) { + var condition = data.caseList[i]["case"]; + if (condition == "default" || core.calValue(condition, prefix) == key) { + this.insertAction(data.caseList[i].action); + break; + } + } + core.doAction(); +} + +events.prototype._action_choices = function (data, x, y, prefix) { + if (core.isReplaying()) { + var action = core.status.replay.toReplay.shift(), index; + // --- 忽略可能的turn事件 + if (action == 'turn') action = core.status.replay.toReplay.shift(); + if (action.indexOf("choices:")==0 && ((index=parseInt(action.substring(8)))>=0) && index= 1000000) { + core.setFlag('type', 1); + var px = parseInt((value - 1000000) / 1000), py = value % 1000; + core.setFlag('px', px); + core.setFlag('py', py); + core.setFlag('x', parseInt(px / 32)); + core.setFlag('y', parseInt(py / 32)); + } + else if (value >= 10000) { + core.setFlag('type', 1); + var x = parseInt((value - 10000) / 100), y = value % 100; + core.setFlag('px', 32 * x + 16); + core.setFlag('py', 32 * y + 16); + core.setFlag('x', x); + core.setFlag('y', y); + } + else if (value > 0) { + core.setFlag('type', 0); + core.setFlag('keycode', value); + } +} + +events.prototype._action_waitAsync = function (data, x, y, prefix) { + var test = window.setInterval(function () { + if (Object.keys(core.animateFrame.asyncId).length == 0) { + clearInterval(test); + core.doAction(); + } + }, 50); +} + +events.prototype._action_revisit = function (data, x, y, prefix) { + var block = core.getBlock(x, y); + if (block != null && block.block.event.trigger == 'action') + this.setEvents(block.block.event.data); + core.doAction(); +} + +events.prototype._action_callBook = function (data, x, y, prefix) { + if (core.isReplaying() || !core.hasItem('book')) { + core.doAction(); + } + else { + var e = core.clone(core.status.event.data); + core.ui.closePanel(); + core.openBook(); + core.status.event.interval = e; + } +} + +events.prototype._action_callSave = function (data, x, y, prefix) { + if (core.isReplaying() || core.hasFlag("__events__")) { + core.removeFlag("__events__"); + core.doAction(); + } + else { + var e = core.clone(core.status.event.data); + core.ui.closePanel(); + core.save(); + core.status.event.interval = e; + } +} + +events.prototype._action_callLoad = function (data, x, y, prefix) { + if (this.__action_checkReplaying()) return; + var e = core.clone(core.status.event.data); + core.ui.closePanel(); + core.load(); + core.status.event.interval = e; +} + +events.prototype._action_exit = function (data, x, y, prefix) { + this.setEvents([]); + core.doAction(); +} + +// ------ 样板提供的的自定义事件 END ------ // + +events.prototype.follow = function (name) { + core.status.hero.followers = core.status.hero.followers || []; + if (core.isset(core.material.images.images[name]) + && core.material.images.images[name].width==128) { + core.status.hero.followers.push({"img": name}); + core.control.gatherFollowers(); + core.clearMap('hero'); + core.drawHero(); + } +} + +events.prototype.unfollow = function (name) { + core.status.hero.followers = core.status.hero.followers || []; + if (!core.isset(name)) { + core.status.heroMoving.followers = []; + } + else { + for (var i = 0; i < core.status.hero.followers.length; i++) { + if (core.status.hero.followers[i].img == name) { + core.status.hero.followers.splice(i, 1); + break; + } + } + } + core.control.gatherFollowers(); + core.clearMap('hero'); + core.drawHero(); +} + +events.prototype.showGif = function (name, x, y) { + var image = core.material.images.images[name]; + if (image) { + var gif = new Image(); + gif.src = image.src; + gif.style.position = 'absolute'; + gif.style.left = x * core.domStyle.scale + "px"; + gif.style.top = y * core.domStyle.scale + "px"; + gif.style.width = image.width * core.domStyle.scale + "px"; + gif.style.height = image.height * core.domStyle.scale + "px"; + core.dom.gif2.appendChild(gif); + } + else { + core.dom.gif2.innerHTML = ""; + } +} + +events.prototype.setValue = function (name, value, prefix, add) { + var value = core.calValue(value, prefix); + if (add) value += core.calValue(name, prefix); + this._setValue_setStatus(name, value); + this._setValue_setItem(name, value); + this._setValue_setFlag(name, value); + this._setValue_setSwitch(name, value); + core.updateStatusBar(); +} + +events.prototype._setValue_setStatus = function (name, value) { + if (name.indexOf("status:") !== 0) return; + core.setStatus(name.substring(7), value); + if (core.status.hero.hp <= 0) { + core.status.hero.hp = 0; + core.updateStatusBar(); + core.events.lose(); + } +} + +events.prototype._setValue_setItem = function (name, value) { + if (name.indexOf("item:") !== 0) return; + var itemId = name.substring(5), count = core.itemCount(itemId); + if (value > count) core.getItem(itemId, value - count); + else core.setItem(itemId, value); +} + +events.prototype._setValue_setFlag = function (name, value) { + if (name.indexOf("flag:") !== 0) return; + core.setFlag(name.substring(5), value); +} + +events.prototype._setValue_setSwitch = function (name, value, prefix) { + if (name.indexOf("switch:") !==0 ) return; + core.setFlag((prefix||"f@x@y")+"@"+data.name.substring(7), value); +} + +events.prototype.setValue2 = function (name, value, prefix) { + this.setValue(name, value, prefix, true); +} + +events.prototype.setFloorInfo = function (name, value, floorId, prefix) { + floorId = floorId || data.floorId; + core.status.maps[floorId][name] = core.calValue(value, prefix); + core.updateStatusBar(); +} + +events.prototype.setGlobalAttribute = function (name, value) { + if (typeof value == 'string') { + if ((value.charAt(0)=='"' && value.charAt(value.length-1)=='"') + || (value.charAt(0)=="'" && value.charAt(value.length-1)=="'")) + value = value.substring(1, value.length-1); + // --- 检查 [] + if (value.charAt(0) == '[' && value.charAt(value.length-1)==']') + value = eval(value); + } + core.status.globalAttribute[name] = value; + core.control.updateGlobalAttribute(name); + core.setFlag('globalAttribute', core.status.globalAttribute); +} + +events.prototype.setGlobalFlag = function (name, value) { + var flags = core.getFlag("globalFlags", {}); + flags[name] = value; + core.flags[name] = value; + core.setFlag("globalFlags", flags); + core.resize(); +} events.prototype.setFloorName = function (floorId) { floorId = floorId || core.status.floorId; From fb7bf4780405b8ab003542e667e9091d88435e45 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 17:51:10 +0800 Subject: [PATCH 016/153] remove sample1.js event list --- project/floors/sample1.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/project/floors/sample1.js b/project/floors/sample1.js index 50b9e828..95d4ca75 100644 --- a/project/floors/sample1.js +++ b/project/floors/sample1.js @@ -39,9 +39,6 @@ main.floors.sample1= "4,10": [ "\t[样板提示]本层楼将会对各类事件进行介绍。", "左边是一个仿50层的陷阱做法,上方是商店、快捷商店的使用方法,右上是一个典型的杀怪开门的例子,右下是各类可能的NPC事件。", - "本样板目前支持的事件列表大致有:\ntext: 显示一段文字(比如你现在正在看到的)\ntip: 左上角显示提示\nshow: 使一个事件有效(可见、可被交互)\nhide: 使一个事件失效(不可见、不可被交互)\ntrigger: 触发另一个地点的事件\nanimate: 显示动画\nbattle: 强制和某怪物战斗\nopenDoor: 无需钥匙开门(例如机关门、暗墙)", - "openShop: 打开一个全局商店\ndisableShop: 禁用一个全局商店\nchangeFloor: 传送勇士到某层某位置\nchangePos: 传送勇士到当层某位置;转向\nshowImage: 显示图片\nsetFg: 更改画面色调\nsetWeather: 更改天气\nmove: 移动事件效果\nmoveHero: 移动勇士效果\nplayBgm: 播放某个背景音乐\npauseBgm: 暂停背景音乐\nresumeBgm: 恢复背景音乐的播放\nplaySound: 播放某个音频", - "if: 条件判断\nchoices: 提供选项\nsetValue: 设置勇士属性道具,或某个变量/flag\nupdate: 更新状态栏和地图显伤\nwin: 获得胜利(游戏通关)\nlose: 游戏失败\nsleep: 等待多少毫秒\nexit: 立刻结束当前事件\nrevisit: 立刻结束事件并重新触发\nfunction: 自定义JS脚本\n\n更多支持的事件还在编写中,欢迎您宝贵的意见。", "有关各事件的样例,可参见本层一些NPC的写法。\n所有事件样例本层都有介绍。\n\n一个自定义事件处理完后,需要调用{\"type\": \"hide\"}该事件才不会再次出现。", { "type": "hide" From b3b395c9aab3e8b06b362a673b652119b40339d7 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 19:37:41 +0800 Subject: [PATCH 017/153] setStatusBarInnerHTML --- libs/control.js | 3 +- libs/events.js | 39 ++++++----------------- libs/maps.js | 25 +++++++-------- libs/utils.js | 21 +++++++++++++ project/functions.js | 75 +++++++++++++++++++++++--------------------- 5 files changed, 83 insertions(+), 80 deletions(-) diff --git a/libs/control.js b/libs/control.js index c44f8a70..c408c0df 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2812,8 +2812,7 @@ control.prototype.checkBgm = function() { ////// 清空状态栏 ////// control.prototype.clearStatusBar = function() { Object.keys(core.statusBar).forEach(function (e) { - if (core.isset(core.statusBar[e].innerHTML)) - core.statusBar[e].innerHTML = " "; + core.statusBar[e].innerHTML = ""; }) core.statusBar.image.book.style.opacity = 0.3; if (!core.flags.equipboxButton) { diff --git a/libs/events.js b/libs/events.js index f5a8f265..b4ff5a19 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1509,6 +1509,9 @@ events.prototype._action_exit = function (data, x, y, prefix) { // ------ 样板提供的的自定义事件 END ------ // +// ------ 一些事件的具体执行过程 ------ // + +////// 跟随 ////// events.prototype.follow = function (name) { core.status.hero.followers = core.status.hero.followers || []; if (core.isset(core.material.images.images[name]) @@ -1520,6 +1523,7 @@ events.prototype.follow = function (name) { } } +////// 取消跟随 ////// events.prototype.unfollow = function (name) { core.status.hero.followers = core.status.hero.followers || []; if (!core.isset(name)) { @@ -1538,6 +1542,7 @@ events.prototype.unfollow = function (name) { core.drawHero(); } +////// 绘制或取消一张gif图片 ////// events.prototype.showGif = function (name, x, y) { var image = core.material.images.images[name]; if (image) { @@ -1555,6 +1560,7 @@ events.prototype.showGif = function (name, x, y) { } } +////// 数值操作 ////// events.prototype.setValue = function (name, value, prefix, add) { var value = core.calValue(value, prefix); if (add) value += core.calValue(name, prefix); @@ -1592,16 +1598,19 @@ events.prototype._setValue_setSwitch = function (name, value, prefix) { core.setFlag((prefix||"f@x@y")+"@"+data.name.substring(7), value); } +////// 数值增减 ////// events.prototype.setValue2 = function (name, value, prefix) { this.setValue(name, value, prefix, true); } +////// 设置楼层属性 ////// events.prototype.setFloorInfo = function (name, value, floorId, prefix) { floorId = floorId || data.floorId; core.status.maps[floorId][name] = core.calValue(value, prefix); core.updateStatusBar(); } +////// 设置全塔属性 ////// events.prototype.setGlobalAttribute = function (name, value) { if (typeof value == 'string') { if ((value.charAt(0)=='"' && value.charAt(value.length-1)=='"') @@ -1616,6 +1625,7 @@ events.prototype.setGlobalAttribute = function (name, value) { core.setFlag('globalAttribute', core.status.globalAttribute); } +////// 设置全局开关 ////// events.prototype.setGlobalFlag = function (name, value) { var flags = core.getFlag("globalFlags", {}); flags[name] = value; @@ -1624,30 +1634,6 @@ events.prototype.setGlobalFlag = function (name, value) { core.resize(); } -events.prototype.setFloorName = function (floorId) { - floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - // 根据文字判断是否斜体 - var floorName = core.status.maps[floorId].name || ""; - if (typeof floorName == 'number') floorName = ""+floorName; - if (!core.isset(floorName) || floorName=="") floorName=" " - if (core.statusBar.floor.innerHTML == floorName) return; - core.statusBar.floor.innerHTML = floorName; - if (/^[+-]?\d+$/.test(floorName)) { - core.statusBar.floor.style.fontStyle = 'italic'; - core.statusBar.floor.style.fontSize = '1.1em'; - } - else { - core.statusBar.floor.style.fontStyle = 'normal'; - if (floorName.length<=5) - core.statusBar.floor.style.fontSize = '1.1em'; - else if (floorName.length==6) - core.statusBar.floor.style.fontSize = '0.9em'; - else - core.statusBar.floor.style.fontSize = '0.7em'; - } -} - ////// 显示图片 ////// events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, time, callback) { dw /= 100; @@ -2085,11 +2071,6 @@ events.prototype.tryUseItem = function(itemId) { else core.drawTip("当前无法使用"+core.material.items[itemId].name); } -////// 加点事件 ////// -events.prototype.addPoint = function (enemy) { - return this.eventdata.addPoint(enemy); -} - ////// 使用炸弹/圣锤后的事件 ////// events.prototype.afterUseBomb = function () { return this.eventdata.afterUseBomb(); diff --git a/libs/maps.js b/libs/maps.js index 5d7eb87e..509e6d96 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -515,16 +515,15 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { // -------- 绘制地图,各层图块,楼层贴图,Autotile -------- // ////// 绘制一个图块 ////// -maps.prototype.drawBlock = function (block, animate, dx, dy) { +maps.prototype.drawBlock = function (block, animate) { if (block.event.id == 'none') return; - animate = animate || 0; - dx = dx || 0; - dy = dy || 0; + var redraw = core.isset(animate); + if (!redraw) animate = 0; var x = block.x, y = block.y; // --- 在界面外的动画不绘制 - if (animate > 1 && block.event.animate > 1 && - (32*x + dx < core.bigmap.offsetX - 64 || 32*x + dx > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 - || 32*y + dy < core.bigmap.offsetY - 64 || 32*y + dy > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { + if (redraw && block.event.animate > 1 && + (32*x < core.bigmap.offsetX - 64 || 32*x > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 + || 32*y < core.bigmap.offsetY - 64 || 32*y > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { return; } @@ -532,19 +531,19 @@ maps.prototype.drawBlock = function (block, animate, dx, dy) { if (blockInfo == null) return; if (blockInfo.cls != 'tileset') blockInfo.posX = animate % block.event.animate; if (!core.isset(block.name)) - this._drawBlockInfo(blockInfo, block.x, block.y, dx, dy); + this._drawBlockInfo(blockInfo, block.x, block.y); else this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y); } -maps.prototype._drawBlockInfo = function (blockInfo, x, y, dx, dy) { +maps.prototype._drawBlockInfo = function (blockInfo, x, y) { var image = blockInfo.image, posX = blockInfo.posX, posY = blockInfo.posY, height = blockInfo.height; - core.clearMap('event', x * 32 + dx, y * 32 + dy, 32, 32); - core.drawImage('event', image, posX * 32, posY * height + height - 32, 32, 32, x * 32 + dx, y * 32 + dy, 32, 32); + 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); if (height>32) { - core.clearMap('event2', x * 32 + dx, y * 32 + 32 - height + dy, 32, height - 32) - core.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, x * 32 + dx, y * 32 + 32 - height + dy, 32, 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); } } diff --git a/libs/utils.js b/libs/utils.js index ee12e6f9..7a1b9456 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -590,6 +590,27 @@ utils.prototype.expandMoveSteps = function (steps) { return moveSteps; } +////// 设置statusBar的innerHTML,会自动斜体和放缩,也可以增加自定义css ////// +utils.prototype.setStatusBarInnerHTML = function (name, value, css) { + if (typeof value == 'number') value = this.formatBigNumber(value); + // 判定是否斜体 + var italic = /^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test(value); + var style = 'font-style: ' + (italic?'italic':'normal') + '; '; + // 判定是否需要缩放 + var length = this.strlen(value) || 1; + style += 'font-size: ' + Math.min(1, 7/length) + 'em; '; + if (core.isset(css)) style += css; + core.statusBar[name].innerHTML = "" + value + ""; +} + +utils.prototype.strlen = function (str) { + var count = 0; + for (var i = 0, len = str.length; i < len; i++) { + count += str.charCodeAt(i) < 256 ? 1 : 2; + } + return count; +}; + ////// Base64加密 ////// utils.prototype.encodeBase64 = function (str) { return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { diff --git a/project/functions.js b/project/functions.js index 024e425c..ce86cf72 100644 --- a/project/functions.js +++ b/project/functions.js @@ -946,18 +946,14 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } // 设置楼层名 - core.events.setFloorName(); + if (core.status.floorId) { + core.setStatusBarInnerHTML('floor', core.status.maps[core.status.floorId].name); + } // 设置勇士名字和图标 - core.statusBar.name.innerHTML = core.getStatus('name'); - + core.setStatusBarInnerHTML('name', core.getStatus('name')); // 设置等级名称 - var lvName = core.getLvName(); - core.statusBar.lv.innerHTML = lvName; - // 检测是不是纯数字;如果带中文等需要取消斜体(不然很难看的!) - if (/^[+-]?\d+$/.test(lvName)) - core.statusBar.lv.style.fontStyle = 'italic'; - else core.statusBar.lv.style.fontStyle = 'normal'; + core.setStatusBarInnerHTML('lv', core.getLvName()); // 设置生命上限、生命值、攻防魔防金币和经验值 var statusList = ['hpmax', 'hp', 'mana', 'atk', 'def', 'mdef', 'money', 'experience']; @@ -965,24 +961,24 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 向下取整 if (core.isset(core.status.hero[item])) core.status.hero[item] = Math.floor(core.status.hero[item]); - // 大数据格式化; - core.statusBar[item].innerHTML = core.formatBigNumber(core.getRealStatus(item)); + // 大数据格式化 + core.setStatusBarInnerHTML(item, core.getRealStatus(item)); }); // 设置魔力值 if (core.flags.enableMana) { // 也可以使用flag:manaMax来表示最大魔力值;详见文档-个性化-技能塔的支持 // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); - // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); + // core.setStatusBarInnerHTML('mana', core.status.hero.mana + "/" + core.getFlag('manaMax', 10)); } // 设置技能栏 if (core.flags.enableSkill) { // 可以用flag:skill表示当前开启的技能类型,flag:skillName显示技能名;详见文档-个性化-技能塔的支持 - core.statusBar.skill.innerHTML = core.getFlag('skillName', '无'); + core.setStatusBarInnerHTML('skill', core.getFlag('skillName', '无')); } // 可以在这里添加自己额外的状态栏信息,比如想攻击显示 +0.5 可以这么写: - // if (core.hasFlag('halfAtk')) core.statusBar.atk.innerHTML += "+0.5"; + // if (core.hasFlag('halfAtk')) core.setStatusBarInnerHTML('atk', core.statusBar.atk.innerText + "+0.5"); // 如果是自定义添加的状态栏,也需要在这里进行设置显示的数值 @@ -990,32 +986,32 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (core.flags.enableLevelUp && core.status.hero.lv < core.firstData.levelUp.length) { var need = core.calValue(core.firstData.levelUp[core.status.hero.lv].need); if (core.flags.levelUpLeftMode) - core.statusBar.up.innerHTML = core.formatBigNumber(need - core.getStatus('experience')) || " "; + core.setStatusBarInnerHTML('up', core.formatBigNumber(need - core.getStatus('experience')) || ""); else - core.statusBar.up.innerHTML = core.formatBigNumber(need) || " "; - } else core.statusBar.up.innerHTML = " "; + core.setStatusBarInnerHTML('up', core.formatBigNumber(need) || ""); + } else core.setStatusBarInnerHTML('up', ""); // 钥匙 var keys = ['yellowKey', 'blueKey', 'redKey']; keys.forEach(function (key) { - core.statusBar[key].innerHTML = core.setTwoDigits(core.status.hero.items.keys[key]); + core.setStatusBarInnerHTML(key, core.setTwoDigits(core.itemCount(key))); }); // 毒衰咒 if (core.flags.enableDebuff) { - core.statusBar.poison.innerHTML = core.hasFlag('poison') ? "毒" : ""; - core.statusBar.weak.innerHTML = core.hasFlag('weak') ? "衰" : ""; - core.statusBar.curse.innerHTML = core.hasFlag('curse') ? "咒" : ""; + core.setStatusBarInnerHTML('poison', core.hasFlag('poison') ? "毒" : ""); + core.setStatusBarInnerHTML('weak', core.hasFlag('weak') ? "衰" : ""); + core.setStatusBarInnerHTML('curse', core.hasFlag('curse') ? "咒" : ""); } // 破炸飞 if (core.flags.enablePZF) { - core.statusBar.pickaxe.innerHTML = "破" + core.itemCount('pickaxe'); - core.statusBar.bomb.innerHTML = "炸" + core.itemCount('bomb'); - core.statusBar.fly.innerHTML = "飞" + core.itemCount('centerFly'); + core.setStatusBarInnerHTML('pickaxe', "破" + core.itemCount('pickaxe')); + core.setStatusBarInnerHTML('bomb', "炸" + core.itemCount('bomb')); + core.setStatusBarInnerHTML('fly', "飞" + core.itemCount('centerFly')); } // 难度 core.statusBar.hard.innerHTML = core.status.hard; - // 状态栏绘制 + // 自定义状态栏绘制 core.drawStatusBar(); // 更新阻激夹域的伤害值 @@ -1195,30 +1191,37 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = }, "ui": { "drawStatusBar": function () { + // 自定义绘制状态栏,需要开启状态栏canvas化 + // 如果是非状态栏canvas化,直接返回 if (!core.flags.statusCanvas) return; - var canvas = core.dom.statusCanvas, ctx = canvas.getContext('2d'); + var canvas = core.dom.statusCanvas, + ctx = canvas.getContext('2d'); // 清空状态栏 ctx.clearRect(0, 0, canvas.width, canvas.height); // 如果是隐藏状态栏模式,直接返回 if (!core.domStyle.showStatusBar) return; - + // 作为样板,只绘制楼层、生命、攻击、防御、魔防、金币、钥匙这七个内容 // 需要其他的请自行进行修改;横竖屏都需要进行适配绘制。 // (可以使用Chrome浏览器开控制台来模拟手机上的竖屏模式的显示效果,具体方式自行百度) // 横屏模式下的画布大小是 129*416 // 竖屏模式下的画布大小是 416*(32*rows+9) 其中rows为状态栏行数,即全塔属性中statusCanvasRowsOnMobile值 // 可以使用 core.domStyle.isVertical 来判定当前是否是竖屏模式 - + ctx.fillStyle = core.status.globalAttribute.statusBarColor || core.initStatus.globalAttribute.statusBarColor; ctx.font = 'italic bold 18px Verdana'; - + // 距离左侧边框6像素,上侧边框9像素,行距约为39像素 - var leftOffset = 6, topOffset = 9, lineHeight = 39; + var leftOffset = 6, + topOffset = 9, + lineHeight = 39; if (core.domStyle.isVertical) { // 竖屏模式,行高32像素 - leftOffset = 6; topOffset = 6; lineHeight = 32; + leftOffset = 6; + topOffset = 6; + lineHeight = 32; } - + var toDraw = ["floor", "hp", "atk", "def", "mdef", "money"]; for (var index = 0; index < toDraw.length; index++) { // 绘制下一个数据 @@ -1226,9 +1229,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 图片大小25x25 ctx.drawImage(core.statusBar.icons[name], leftOffset, topOffset, 25, 25); // 文字内容 - var text = (core.statusBar[name]||{}).innerText || " "; + var text = (core.statusBar[name] || {}).innerText || " "; // 斜体判定:如果不是纯数字和字母,斜体会非常难看,需要取消 - if (!/^[-+_.a-zA-Z0-9]*$/.test(text)) ctx.font = 'bold 18px Verdana'; + if (!/^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test(text)) + ctx.font = 'bold 18px Verdana'; // 绘制文字 ctx.fillText(text, leftOffset + 36, topOffset + 20); ctx.font = 'italic bold 18px Verdana'; @@ -1240,8 +1244,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = leftOffset = 6; topOffset += lineHeight; } - } - else { + } else { // 横屏模式 topOffset += lineHeight; } From 8144ca8d17c23c5328cf161eb67ddf923e06d78e Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 22:50:02 +0800 Subject: [PATCH 018/153] events.js V2.6 --- libs/control.js | 14 ++ libs/events.js | 406 +++++++++++++++--------------------------------- libs/ui.js | 83 ++++++++++ libs/utils.js | 2 +- styles.css | 1 - 5 files changed, 219 insertions(+), 287 deletions(-) diff --git a/libs/control.js b/libs/control.js index c408c0df..9d3f9ab1 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1080,6 +1080,20 @@ control.prototype.setGameCanvasTranslate = function(canvas,x,y){ } }; +////// 加减画布偏移 +control.prototype.addGameCanvasTranslate = function (x, y) { + for(var ii=0,canvas;canvas=core.dom.gameCanvas[ii];ii++){ + var id = canvas.getAttribute('id'); + 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; + } + core.control.setGameCanvasTranslate(id, offsetX, offsetY); + } +} + ////// 更新视野范围 ////// control.prototype.updateViewport = function() { core.bigmap.canvas.forEach(function(cn){ diff --git a/libs/events.js b/libs/events.js index b4ff5a19..3bda1f7b 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1045,7 +1045,7 @@ events.prototype._action_showTextImage = function (data, x, y, prefix) { var loc = this.__action_getLoc(data.loc, 0, 0, prefix); if (core.isReplaying()) data.time = 0; this.__action_doAsyncFunc(data.async || data.time == 0, this.showImage, - data.code, this.textImage(data.text), loc[0], loc[1], 100, 100, data.opacity, data.time); + data.code, core.ui.textImage(data.text), loc[0], loc[1], 100, 100, data.opacity, data.time); } events.prototype._action_hideImage = function (data, x, y, prefix) { @@ -1640,252 +1640,161 @@ events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, ti dh /= 100; x = core.calValue(x) || 0; y = core.calValue(y) || 0; + if (typeof image == 'string') image = core.material.images.images[image]; + if (!image) { + if (callback) callback(); + return; + } var zIndex = code + 100; time = time || 0; var name = "image"+ zIndex; var ctx = core.createCanvas(name, x, y, image.width * dw, image.height * dh, zIndex); - ctx.drawImage(image, 0, 0, image.width * dw, image.height * dh); - if (time == 0) + if (time == 0) { core.setOpacity(name, opacityVal); - else { - var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; - var opacity = 0; - core.setOpacity(name, 0); - var animate = setInterval(function () { - opacity += per_add; - core.setOpacity(name, opacity); - if (opacity >= opacityVal) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.setOpacity(name, opacityVal); - if (core.isset(callback)) callback(); - } - }, per_time); - - core.animateFrame.asyncId[animate] = true; + if (callback) callback(); + return; } + core.setOpacity(name, 0); + this.moveImage(code, null, opacityVal, time, callback); } ////// 隐藏图片 ////// events.prototype.hideImage = function (code, time, callback) { time = time || 0; - var name = "image"+ (code+100); - if (!core.isset(core.dymCanvas[name])) { - if (core.isset(callback)) callback(); + var name = "image" + (code + 100); + if (time == 0 || !core.dymCanvas[name]) { + core.deleteCanvas(name); + if (callback) callback(); return; } - if (time == 0) + this.moveImage(code, null, 0, time, function () { core.deleteCanvas(name); - else { - var opacityVal = parseFloat(core.dymCanvas[name].canvas.style.opacity); - var per_time = 10, steps = parseInt(time / per_time), per_add = opacityVal / steps; - var animate = setInterval(function () { - opacityVal -= per_add; - core.setOpacity(name, opacityVal); - if (opacityVal < 0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.deleteCanvas(name); - if (core.isset(callback)) callback(); - } - }, per_time); - - core.animateFrame.asyncId[animate] = true; - } -} - -////// 文本图片化 ////// -events.prototype.textImage = function (content) { - content = content || ""; - - // 获得颜色的盒子等信息 - var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; - var textfont = textAttribute.textfont || 16; - var offset = textAttribute.offset || 15; - var textColor = core.arrayToRGBA(textAttribute.text); - - var font = textfont+"px "+core.status.globalAttribute.font; - if (textAttribute.bold) font = "bold "+font; - var contents = core.splitLines('ui', content), lines = contents.length; - - // 计算总高度,按1.4倍行距计算 - var width = 416, height = textfont * 1.4 * lines; - var tempCanvas = core.bigmap.tempCanvas; - tempCanvas.canvas.width = width; - tempCanvas.canvas.height = height; - tempCanvas.clearRect(0, 0, width, height); - tempCanvas.font = font; - tempCanvas.fillStyle = textColor; - - // 全部绘制 - var currH = textfont; - for (var i = 0; i < lines; ++i) { - var text = contents[i]; - tempCanvas.fillText(text, offset, currH); - currH += 1.4 * textfont; - } - - return tempCanvas.canvas; + if (callback) callback(); + }); } ////// 移动图片 ////// events.prototype.moveImage = function (code, to, opacityVal, time, callback) { time = time || 1000; - + to = to || []; var name = "image"+ (code+100); - if (!core.isset(core.dymCanvas[name])) { - if (core.isset(callback)) callback(); + if (!core.dymCanvas[name]) { + if (callback) callback(); return; } - var fromX = parseFloat(core.dymCanvas[name].canvas.getAttribute("_left")), - fromY = parseFloat(core.dymCanvas[name].canvas.getAttribute("_top")), - preX = fromX, preY = fromY, toX = fromX, toY = fromY; + var getOrDefault = function (a, b) { + a = core.calValue(a); + return core.isset(a) ? a : b; + } + var canvas = core.dymCanvas[name].canvas; + var fromX = parseFloat(canvas.getAttribute("_left")), + fromY = parseFloat(canvas.getAttribute("_top")), + toX = getOrDefault(to[0], fromX), toY = getOrDefault(to[1], fromY); - if (core.isset(to)) { - toX = core.calValue(to[0]); - toY = core.calValue(to[1]); - if (!core.isset(toX)) toX = fromX; - if (!core.isset(toY)) toY = fromY; - } + var opacity = parseFloat(canvas.style.opacity), toOpacity = getOrDefault(opacityVal, opacity); - var step = 0; - var per_time = 10, steps = parseInt(time / per_time); - var preOpac = parseFloat(core.dymCanvas[name].canvas.style.opacity), opacStep = 0; - if (core.isset(opacityVal)) { - opacityVal = core.calValue(opacityVal); - opacStep = (opacityVal - preOpac) / steps; - } - - var moveStep = function () { - preOpac += opacStep; - core.setOpacity(name, preOpac); - preX = parseInt(fromX + (toX-fromX)*step/steps); - preY = parseInt(fromY + (toY-fromY)*step/steps); - core.relocateCanvas(name, preX, preY); - } + this._moveImage_moving(name, { + fromX: fromX, fromY: fromY, toX: toX, toY: toY, opacity: opacity, toOpacity: toOpacity, time: time + }, callback) +} + +events.prototype._moveImage_moving = function(name, moveInfo, callback) { + var per_time = 10, step = 0, steps = parseInt(moveInfo.time / 10); + var fromX = moveInfo.fromX, fromY = moveInfo.fromY, toX = moveInfo.toX, toY = moveInfo.toY, + opacity = moveInfo.opacity, toOpacity = moveInfo.toOpacity; + var currX = fromX, currY = fromY, currOpacity = opacity; var animate = setInterval(function () { step++; - moveStep(); + currOpacity = opacity + (toOpacity-opacity)*step/steps; + currX = parseInt(fromX + (toX-fromX)*step/steps); + currY = parseInt(fromY + (toY-fromY)*step/steps); + core.setOpacity(name, currOpacity); + core.relocateCanvas(name, currX, currY); if (step == steps) { - if (core.isset(opacityVal)) - core.setOpacity(name, opacityVal); + core.setOpacity(name, toOpacity); delete core.animateFrame.asyncId[animate]; clearInterval(animate); - if (core.isset(callback)) callback(); + if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[animate] = true; } ////// 淡入淡出音乐 ////// events.prototype.setVolume = function (value, time, callback) { - var set = function (value) { core.musicStatus.volume = value; - if (core.isset(core.musicStatus.playingBgm)) { + if (core.musicStatus.playingBgm) core.material.bgms[core.musicStatus.playingBgm].volume = value; - } - // core.musicStatus.gainNode.gain.value = value; } - if (!core.isset(time) || time<100) { set(value); - if (core.isset(callback)) callback(); + if (callback) callback(); return; } - var currVolume = core.musicStatus.volume; var per_time = 10, step = 0, steps = parseInt(time / per_time); var fade = setInterval(function () { step++; - var nowVolume = currVolume+(value-currVolume)*step/steps; - set(nowVolume); + set(currVolume+(value-currVolume)*step/steps); if (step>=steps) { delete core.animateFrame.asyncId[fade]; clearInterval(fade); - if (core.isset(callback)) - callback(); + if (callback) callback(); } }, per_time); - core.animateFrame.asyncId[fade] = true; } ////// 画面震动 ////// events.prototype.vibrate = function(time, callback) { - if (core.isReplaying()) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } - - // core.status.replay.animate=true; - - var addGameCanvasTranslate=function(x,y){ - for(var ii=0,canvas;canvas=core.dom.gameCanvas[ii];ii++){ - var id = canvas.getAttribute('id'); - if (id=='ui' || id=='data') continue; - var offsetX = x, offsetY = y; - if (core.bigmap.canvas.indexOf(id)>=0) { - offsetX-=core.bigmap.offsetX; - offsetY-=core.bigmap.offsetY; - } - core.control.setGameCanvasTranslate(id, offsetX, offsetY); - } - } - if (!core.isset(time) || time<1000) time=1000; - - var shake_duration = time*3/50; - var shake_speed = 5; - var shake_power = 5; - var shake_direction = 1; - var shake = 0; - - var update = function() { - if(shake_duration >= 1 || shake != 0){ - var delta = (shake_power * shake_speed * shake_direction) / 10.0; - if(shake_duration <= 1 && shake * (shake + delta) < 0){ - shake = 0; - }else{ - shake += delta; - } - if(shake > shake_power * 2){ - shake_direction = -1; - } - if(shake < - shake_power * 2){ - shake_direction = 1; - } - if(shake_duration >= 1){ - shake_duration -= 1 - } - } - } - + // --- 将time调整为500的倍数(上整),不然会出错 + time = Math.ceil(time / 500) * 500; + var shakeInfo = { duration: time * 3 / 50, speed: 5, power: 5, direction: 1, shake: 0 }; var animate=setInterval(function(){ - update(); - addGameCanvasTranslate(shake, 0); - if(shake_duration===0) { + core.events._vibrate_update(shakeInfo); + core.control.addGameCanvasTranslate(shakeInfo.shake, 0); + if(shakeInfo.duration===0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - // core.status.replay.animate=false; - if (core.isset(callback)) callback(); + if (callback) callback(); } - }, 50/3); + }, 50 / 3); core.animateFrame.asyncId[animate] = true; } +events.prototype._vibrate_update = function (shakeInfo) { + if(shakeInfo.duration >= 1 || shakeInfo.shake != 0){ + var delta = (shakeInfo.power * shakeInfo.speed * shakeInfo.direction) / 10.0; + if(shakeInfo.duration <= 1 && shakeInfo.shake * (shakeInfo.shake + delta) < 0){ + shakeInfo.shake = 0; + }else{ + shakeInfo.shake += delta; + } + if(shakeInfo.shake > shakeInfo.power * 2){ + shakeInfo.direction = -1; + } + if(shakeInfo.shake < - shakeInfo.power * 2){ + shakeInfo.direction = 1; + } + if(shakeInfo.duration >= 1){ + shakeInfo.duration -= 1 + } + } +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function(shopId, needVisited) { var shop = core.status.shops[shopId]; shop.times = shop.times || 0; - if (shop.commonTimes) - shop.times = core.getFlag('commonTimes', 0); - shop.visited = shop.visited || false; - + if (shop.commonTimes) shop.times = core.getFlag('commonTimes', 0); if (needVisited && !shop.visited) { if (!core.flags.enableDisabledShop) { if (shop.times==0) core.drawTip("该商店尚未开启"); @@ -1897,85 +1806,30 @@ events.prototype.openShop = function(shopId, needVisited) { } } else shop.visited = true; - - var selection = core.status.event.selection; - var actions = []; - if (core.isset(core.status.event.data) && core.isset(core.status.event.data.actions)) - actions=core.status.event.data.actions; - var fromList; - if (core.isset(core.status.event.data) && core.isset(core.status.event.data.fromList)) - fromList = core.status.event.data.fromList; - - core.ui.closePanel(); - core.lockControl(); - // core.status.event = {'id': 'shop', 'data': {'id': shopId, 'shop': shop}}; - core.status.event.id = 'shop'; - core.status.event.data = {'id': shopId, 'shop': shop, 'actions': actions, 'fromList': fromList}; - core.status.event.selection = selection; - - // 拼词 - var content = "\t["+shop.name+","+shop.icon+"]"; - var times = shop.times, need=core.calValue(shop.need, null, null, times); - - content += core.replaceText(shop.text, need, times); - - var use = shop.use=='experience'?'经验':'金币'; - - var choices = []; - for (var i=0;i core.getStatus(use)) { + core.drawTip("你的"+(use=='money'?"金币":"经验")+"不足"); return false; } - - var money = core.getStatus('money'), experience = core.getStatus('experience'); - var times = shop.times, need = core.calValue(shop.need, null, null, times); - var use = shop.use; - var use_text = use=='money'?"金币":"经验"; - - var choice = shop.choices[index]; - if (core.isset(choice.need)) - need = core.calValue(choice.need, null, null, times); - - if (need > eval(use)) { - core.drawTip("你的"+use_text+"不足"); - return false; - } - core.status.event.selection = index; core.status.event.data.actions.push(index); - - eval(use+'-='+need); - core.setStatus('money', money); - core.setStatus('experience', experience); - - // 更新属性 - choice.effect.split(";").forEach(function (t) { - core.doEffect(t, need, times); - }); + core.setStatus(use, core.getStatus(use) - need); + core.doEffect(choice.effect, need, times); core.updateStatusBar(); shop.times++; - if (shop.commonTimes) - core.setFlag('commonTimes', shop.times); - core.events.openShop(shop.id); + if (shop.commonTimes) core.setFlag('commonTimes', shop.times); + this.openShop(shop.id); return true; } @@ -2003,69 +1857,51 @@ events.prototype.canUseQuickShop = function(shopId) { ////// 设置角色行走图 ////// events.prototype.setHeroIcon = function (name, noDraw) { - if (core.isset(core.material.images.images[name]) && core.material.images.images[name].width==128) { - core.setFlag("heroIcon", name); - core.material.images.hero.onload = function () { - core.material.icons.hero.height = core.material.images.images[name].height/4; - core.control.updateHeroIcon(name); - if (!noDraw) core.drawHero(); - } - core.material.images.hero.src = core.material.images.images[name].src; + var img = core.material.images.images[name]; + if (!img || img.width != 128) return; + core.setFlag("heroIcon", name); + core.material.images.hero.onload = function () { + core.material.icons.hero.height = img.height/4; + core.control.updateHeroIcon(name); + if (!noDraw) core.drawHero(); } + core.material.images.hero.src = img.src; } ////// 检查升级事件 ////// events.prototype.checkLvUp = function () { - var check = function () { - if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) - || core.status.hero.lv>=core.firstData.levelUp.length) return null; - // 计算下一个所需要的数值 - var next = (core.firstData.levelUp[core.status.hero.lv]||{}); - var need = core.calValue(next.need); - if (!core.isset(need)) return null; - if (core.status.hero.experience>=need) { - // 升级 - core.status.hero.lv++; - if (next.clear) core.status.hero.experience -= need; - return next.action||[]; - } - return null; - } var actions = []; while (true) { - var next = check(); + var next = this._checkLvUp_check(); if (next == null) break; actions = actions.concat(next); } if (actions.length>0) core.insertAction(actions); } +events.prototype._checkLvUp_check = function () { + if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) + || core.status.hero.lv>=core.firstData.levelUp.length) return null; + // 计算下一个所需要的数值 + var next = (core.firstData.levelUp[core.status.hero.lv]||{}); + var need = core.calValue(next.need); + if (!core.isset(need)) return null; + if (core.status.hero.experience>=need) { + // 升级 + core.status.hero.lv++; + if (next.clear) core.status.hero.experience -= need; + return next.action||[]; + } + return null; +} + ////// 尝试使用道具 ////// events.prototype.tryUseItem = function(itemId) { core.ui.closePanel(); - if (itemId=='book') { - core.openBook(false); - return; - } - if (itemId=='fly') { - core.useFly(false); - return; - } - if (itemId=='centerFly') { - core.lockControl(); - core.status.event.id = 'centerFly'; - var fillstyle = 'rgba(255,0,0,0.5)'; - if (core.canUseItem('centerFly')) fillstyle = 'rgba(0,255,0,0.5)'; - var toX = core.bigmap.width-1 - core.getHeroLoc('x'), toY = core.bigmap.height-1-core.getHeroLoc('y'); - core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.getFlag('heroIcon', "hero.png")}, - {ctx: 'ui', centerX: toX, centerY: toY}); - var offsetX = core.clamp(toX-6, 0, core.bigmap.width-13), offsetY = core.clamp(toY-6, 0, core.bigmap.height-13); - core.fillRect('ui',(toX-offsetX)*32,(toY-offsetY)*32,32,32,fillstyle); - core.status.event.data = {"x": toX, "y": toY, "posX": toX-offsetX, "posY": toY-offsetY}; - core.drawTip("请确认当前中心对称飞行器的位置"); - return; - } + if (itemId=='book') return core.openBook(false); + if (itemId=='fly') return core.useFly(false); + if (itemId=='centerFly') return core.ui.drawCenterFly(); if (core.canUseItem(itemId))core.useItem(itemId); else core.drawTip("当前无法使用"+core.material.items[itemId].name); diff --git a/libs/ui.js b/libs/ui.js index d055aada..2761d85f 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -8,6 +8,10 @@ function ui() { this._init(); + this.DEFAULT_WIDTH = 13; + this.DEFAULT_HEIGHT = 13; + this.DEFAULT_PIXEL_WIDTH = this.DEFAULT_WIDTH * 32; + this.DEFAULT_PIXEL_HEIGHT = this.DEFAULT_HEIGHT * 32; } // 初始化UI @@ -1042,6 +1046,40 @@ ui.prototype.drawChoices = function(content, choices) { return; } +////// 文本图片化 ////// +ui.prototype.textImage = function (content) { + content = content || ""; + + // 获得颜色的盒子等信息 + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + var textfont = textAttribute.textfont || 16; + var offset = textAttribute.offset || 15; + var textColor = core.arrayToRGBA(textAttribute.text); + + var font = textfont+"px "+core.status.globalAttribute.font; + if (textAttribute.bold) font = "bold "+font; + var contents = core.splitLines('ui', content), lines = contents.length; + + // 计算总高度,按1.4倍行距计算 + var width = 416, height = textfont * 1.4 * lines; + var tempCanvas = core.bigmap.tempCanvas; + tempCanvas.canvas.width = width; + tempCanvas.canvas.height = height; + tempCanvas.clearRect(0, 0, width, height); + tempCanvas.font = font; + tempCanvas.fillStyle = textColor; + + // 全部绘制 + var currH = textfont; + for (var i = 0; i < lines; ++i) { + var text = contents[i]; + tempCanvas.fillText(text, offset, currH); + currH += 1.4 * textfont; + } + + return tempCanvas.canvas; +} + ////// 绘制一个确认/取消的警告页面 ////// ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { core.lockControl(); @@ -1604,6 +1642,51 @@ ui.prototype.drawFly = function(page) { core.drawThumbnail(floorId, null, null, {ctx: 'ui', x: 20, y: 100, size: 273}); } +////// 绘制中心对称飞行器 +ui.prototype.drawCenterFly = function () { + core.lockControl(); + core.status.event.id = 'centerFly'; + var fillstyle = 'rgba(255,0,0,0.5)'; + if (core.canUseItem('centerFly')) fillstyle = 'rgba(0,255,0,0.5)'; + var toX = core.bigmap.width - 1 - core.getHeroLoc('x'), toY = core.bigmap.height - 1 - core.getHeroLoc('y'); + core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.getFlag('heroIcon', "hero.png")}, + {ctx: 'ui', centerX: toX, centerY: toY}); + var midX = Math.floor(this.DEFAULT_WIDTH / 2), midY = Math.floor(this.DEFAULT_HEIGHT / 2); + var offsetX = core.clamp(toX - midX, 0, core.bigmap.width - this.DEFAULT_WIDTH), + offsetY = core.clamp(toY - midY, 0, core.bigmap.height - this.DEFAULT_HEIGHT); + core.fillRect('ui', (toX - offsetX) * 32, (toY - offsetY) * 32, 32, 32, fillstyle); + core.status.event.data = {"x": toX, "y": toY, "posX": toX - offsetX, "posY": toY - offsetY}; + core.drawTip("请确认当前中心对称飞行器的位置"); + return; +} + +////// 绘制全局商店 +ui.prototype.drawShop = function (shopId) { + var shop = core.status.shops[shopId]; + var actions = [], fromList = (core.status.event.data||{}).fromList, selection = core.status.event.selection; + if (core.status.event.data && core.status.event.data.actions) actions=core.status.event.data.actions; + + core.ui.closePanel(); + core.lockControl(); + core.status.event.id = 'shop'; + core.status.event.data = {'id': shopId, 'shop': shop, 'actions': actions, 'fromList': fromList}; + core.status.event.selection = selection; + + var times = shop.times, need=core.calValue(shop.need, null, null, times); + var content = "\t["+shop.name+","+shop.icon+"]" + core.replaceText(shop.text, need, times); + var use = shop.use=='experience'?'经验':'金币'; + var choices = []; + for (var i=0;i" + value + ""; + core.statusBar[name].innerHTML = "" + value + ""; } utils.prototype.strlen = function (str) { diff --git a/styles.css b/styles.css index 9f36a7d1..da593b91 100644 --- a/styles.css +++ b/styles.css @@ -194,7 +194,6 @@ max-height: 1.6em; } #statusBar span{ - color: white; font: bold italic 1.1em Verdana; } #statusBar p { From 02934cad46a3bd444707cf20cd6c9ff3e16e6ca9 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 16 Mar 2019 22:58:57 +0800 Subject: [PATCH 019/153] Reformat code --- libs/actions.js | 1070 +++++++++++++++++++++--------------------- libs/core.js | 67 ++- libs/data.js | 4 +- libs/enemys.js | 102 ++-- libs/events.js | 292 ++++++------ libs/icons.js | 10 +- libs/items.js | 86 ++-- libs/loader.js | 34 +- libs/utils.js | 467 +++++++++--------- project/functions.js | 2 +- 10 files changed, 1104 insertions(+), 1030 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 6b0313a4..f08502e9 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -84,7 +84,9 @@ actions.prototype.registerAction = function (action, name, func, priority) { ////// 注销一个用户交互行为 ////// actions.prototype.unregisterAction = function (action, name) { if (!this.actions[action]) return; - this.actions[action] = this.actions[action].filter(function (x) { return x.name != name; }); + this.actions[action] = this.actions[action].filter(function (x) { + return x.name != name; + }); } ////// 执行一个用户交互行为 ////// @@ -99,8 +101,8 @@ actions.prototype.doRegisteredAction = function (action) { } actions.prototype.checkReplaying = function () { - if (core.isReplaying()&&core.status.event.id!='save' - &&(core.status.event.id||"").indexOf('book')!=0&&core.status.event.id!='viewMaps') + if (core.isReplaying() && core.status.event.id != 'save' + && (core.status.event.id || "").indexOf('book') != 0 && core.status.event.id != 'viewMaps') return true; return false; } @@ -116,70 +118,70 @@ actions.prototype.onkeyDown = function (e) { } actions.prototype._sys_onkeyDown = function (e) { - if (!core.isset(core.status.holdingKeys))core.status.holdingKeys=[]; - var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] - if(isArrow && !core.status.lockControl){ - for(var ii =0;ii=49 && e.keyCode<=51) - core.setReplaySpeed(e.keyCode-48); - else if (e.keyCode==52) + else if (e.keyCode >= 49 && e.keyCode <= 51) + core.setReplaySpeed(e.keyCode - 48); + else if (e.keyCode == 52) core.setReplaySpeed(6); - else if (e.keyCode==53) + else if (e.keyCode == 53) core.setReplaySpeed(12); - else if (e.keyCode==54) + else if (e.keyCode == 54) core.setReplaySpeed(24); return true; } } actions.prototype._sys_onkeyUp = function (e) { - var isArrow={37:true,38:true,39:true,40:true}[e.keyCode] - if(isArrow && !core.status.lockControl){ - for(var ii =0;ii0) { - var pos={'x':x,'y':y}; - var pos0=core.status.stepPostfix[core.status.stepPostfix.length-1]; - var directionDistance=[pos.y-pos0.y,pos0.x-pos.x,pos0.y-pos.y,pos.x-pos0.x]; - var max=0,index=4; - for(var ii=0;ii<4;ii++){ - if(directionDistance[ii]>max){ - index=ii; - max=directionDistance[ii]; + if ((core.status.stepPostfix || []).length > 0) { + var pos = {'x': x, 'y': y}; + var pos0 = core.status.stepPostfix[core.status.stepPostfix.length - 1]; + var directionDistance = [pos.y - pos0.y, pos0.x - pos.x, pos0.y - pos.y, pos.x - pos0.x]; + var max = 0, index = 4; + for (var ii = 0; ii < 4; ii++) { + if (directionDistance[ii] > max) { + index = ii; + max = directionDistance[ii]; } } - pos=[{'x':0,'y':1},{'x':-1,'y':0},{'x':0,'y':-1},{'x':1,'y':0},false][index] - if(pos){ - pos.x+=pos0.x; - pos.y+=pos0.y; + pos = [{'x': 0, 'y': 1}, {'x': -1, 'y': 0}, {'x': 0, 'y': -1}, {'x': 1, 'y': 0}, false][index] + if (pos) { + pos.x += pos0.x; + pos.y += pos0.y; core.status.stepPostfix.push(pos); core.fillPosWithPoint(pos); } @@ -499,31 +503,35 @@ actions.prototype._sys_onup = function () { clearInterval(core.interval.onDownInterval); core.interval.onDownInterval = null; - if ((core.status.stepPostfix||[]).length == 0) return false; + if ((core.status.stepPostfix || []).length == 0) return false; var stepPostfix = []; - var direction={'0':{'1':'down','-1':'up'},'-1':{'0':'left'},'1':{'0':'right'}}; - for(var ii=1;ii=1000) { + if (!core.status.lockControl && stepPostfix.length == 0 && core.status.downTime != null && new Date() - core.status.downTime >= 1000) { this.longClick(posx, posy); } else { //posx,posy是寻路的目标点,stepPostfix是后续的移动 - this.onclick(posx,posy,stepPostfix); + this.onclick(posx, posy, stepPostfix); } - core.status.downTime=null; + core.status.downTime = null; return true; } @@ -545,7 +553,7 @@ actions.prototype.getClickLoc = function (x, y) { var left = core.dom.gameGroup.offsetLeft + statusBar.x; var top = core.dom.gameGroup.offsetTop + statusBar.y; - var loc={'x': x - left, 'y': y - top, 'size': size}; + var loc = {'x': x - left, 'y': y - top, 'size': size}; return loc; } @@ -562,72 +570,72 @@ actions.prototype._sys_onclick_lockControl = function (x, y) { this._clickCenterFly(x, y); break; case 'book': - this._clickBook(x,y); + this._clickBook(x, y); break; case 'book-detail': - this._clickBookDetail(x,y); + this._clickBookDetail(x, y); break; case 'fly': - this._clickFly(x,y); + this._clickFly(x, y); break; case 'viewMaps': - this._clickViewMaps(x,y); + this._clickViewMaps(x, y); break; case 'switchs': - this._clickSwitchs(x,y); + this._clickSwitchs(x, y); break; case 'settings': - this._clickSettings(x,y); + this._clickSettings(x, y); break; case 'shop': - this._clickShop(x,y); + this._clickShop(x, y); break; case 'selectShop': - this._clickQuickShop(x,y); + this._clickQuickShop(x, y); break; case 'equipbox': - this._clickEquipbox(x,y); + this._clickEquipbox(x, y); break; case 'toolbox': - this._clickToolbox(x,y); + this._clickToolbox(x, y); break; case 'save': case 'load': case 'replayLoad': - this._clickSL(x,y); + this._clickSL(x, y); break; case 'confirmBox': - this._clickConfirmBox(x,y); + this._clickConfirmBox(x, y); break; case 'keyBoard': - this._clickKeyBoard(x,y); + this._clickKeyBoard(x, y); break; case 'action': - this._clickAction(x,y); + this._clickAction(x, y); break; case 'text': core.drawText(); break; case 'syncSave': - this._clickSyncSave(x,y); + this._clickSyncSave(x, y); break; case 'syncSelect': - this._clickSyncSelect(x,y); + this._clickSyncSelect(x, y); break; case 'localSaveSelect': - this._clickLocalSaveSelect(x,y); + this._clickLocalSaveSelect(x, y); break; case 'storageRemove': - this._clickStorageRemove(x,y); + this._clickStorageRemove(x, y); break; case 'cursor': - this._clickCursor(x,y); + this._clickCursor(x, y); break; case 'replay': - this._clickReplay(x,y); + this._clickReplay(x, y); break; case 'gameInfo': - this._clickGameInfo(x,y); + this._clickGameInfo(x, y); break; case 'about': case 'help': @@ -639,7 +647,7 @@ actions.prototype._sys_onclick_lockControl = function (x, y) { actions.prototype._sys_onclick = function (x, y, stepPostfix) { // 寻路 - core.setAutomaticRoute(x+parseInt(core.bigmap.offsetX/32), y+parseInt(core.bigmap.offsetY/32), stepPostfix); + core.setAutomaticRoute(x + parseInt(core.bigmap.offsetX / 32), y + parseInt(core.bigmap.offsetY / 32), stepPostfix); return true; } @@ -653,36 +661,36 @@ actions.prototype._sys_onmousewheel = function (direct) { if (this.checkReplaying()) { // 滚轮控制速度 - if (direct==1) core.speedUpReplay(); - if (direct==-1) core.speedDownReplay(); + if (direct == 1) core.speedUpReplay(); + if (direct == -1) core.speedDownReplay(); return; } // 楼层飞行器 if (core.status.lockControl && core.status.event.id == 'fly') { - if (direct==1) core.ui.drawFly(this._getNextFlyFloor(1)); - if (direct==-1) core.ui.drawFly(this._getNextFlyFloor(-1)); + if (direct == 1) core.ui.drawFly(this._getNextFlyFloor(1)); + if (direct == -1) core.ui.drawFly(this._getNextFlyFloor(-1)); return; } // 怪物手册 if (core.status.lockControl && core.status.event.id == 'book') { - if (direct==1) core.ui.drawBook(core.status.event.data - 6); - if (direct==-1) core.ui.drawBook(core.status.event.data + 6); + if (direct == 1) core.ui.drawBook(core.status.event.data - 6); + if (direct == -1) core.ui.drawBook(core.status.event.data + 6); return; } // 存读档 if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) { - if (direct==1) core.ui.drawSLPanel(core.status.event.data - 10); - if (direct==-1) core.ui.drawSLPanel(core.status.event.data + 10); + if (direct == 1) core.ui.drawSLPanel(core.status.event.data - 10); + if (direct == -1) core.ui.drawSLPanel(core.status.event.data + 10); return; } // 浏览地图 if (core.status.lockControl && core.status.event.id == 'viewMaps') { - if (direct==1) this._clickViewMaps(6,3); - if (direct==-1) this._clickViewMaps(6,9); + if (direct == 1) this._clickViewMaps(6, 3); + if (direct == -1) this._clickViewMaps(6, 9); return; } @@ -694,17 +702,17 @@ actions.prototype.keyDownCtrl = function () { } actions.prototype._sys_keyDownCtrl = function () { - if (core.status.event.id=='text') { + if (core.status.event.id == 'text') { core.drawText(); return true; } - if (core.status.event.id=='action' && core.status.event.data.type=='text') { + if (core.status.event.id == 'action' && core.status.event.data.type == 'text') { core.doAction(); return true; } - if (core.status.event.id=='action' && core.status.event.data.type=='sleep' + if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' && !core.status.event.data.current.noSkip) { - if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length==0) { + if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length == 0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.doAction(); @@ -765,34 +773,34 @@ actions.prototype._sys_longClick = function (x, y, fromEvent) { // 数字键快速选择选项 actions.prototype._selectChoices = function (length, keycode, callback) { var topIndex = 6 - parseInt((length - 1) / 2); - if (keycode==13 || keycode==32 || keycode==67) { - callback(6, topIndex+core.status.event.selection); + if (keycode == 13 || keycode == 32 || keycode == 67) { + callback(6, topIndex + core.status.event.selection); } - if (keycode>=49 && keycode<=57) { - var index = keycode-49; + if (keycode >= 49 && keycode <= 57) { + var index = keycode - 49; if (index < length) { - callback(6, topIndex+index); + callback(6, topIndex + index); } } } // 上下键调整选项 actions.prototype._keyDownChoices = function (keycode) { - if (keycode==38) { + if (keycode == 38) { core.status.event.selection--; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } - if (keycode==40) { + if (keycode == 40) { core.status.event.selection++; core.ui.drawChoices(core.status.event.ui.text, core.status.event.ui.choices); } } ////// 点击中心对称飞行器时 -actions.prototype._clickCenterFly = function(x, y) { +actions.prototype._clickCenterFly = function (x, y) { var posX = core.status.event.data.posX, posY = core.status.event.data.posY; core.ui.closePanel(); - if (x==posX&& y==posY) { + if (x == posX && y == posY) { if (core.canUseItem('centerFly')) { core.useItem('centerFly'); } @@ -804,7 +812,7 @@ actions.prototype._clickCenterFly = function(x, y) { actions.prototype._keyUpCenterFly = function (keycode) { core.ui.closePanel(); - if (keycode==51 || keycode==13 || keycode==32 || keycode==67) { + if (keycode == 51 || keycode == 13 || keycode == 32 || keycode == 67) { if (core.canUseItem('centerFly')) { core.useItem('centerFly'); } @@ -815,7 +823,7 @@ actions.prototype._keyUpCenterFly = function (keycode) { } ////// 点击确认框时 ////// -actions.prototype._clickConfirmBox = function (x,y) { +actions.prototype._clickConfirmBox = function (x, y) { if ((x == 4 || x == 5) && y == 7 && core.isset(core.status.event.data.yes)) core.status.event.data.yes(); if ((x == 7 || x == 8) && y == 7 && core.isset(core.status.event.data.no)) @@ -824,26 +832,26 @@ actions.prototype._clickConfirmBox = function (x,y) { ////// 键盘操作确认框时 ////// actions.prototype._keyUpConfirmBox = function (keycode) { - if (keycode==37) { - core.status.event.selection=0; + if (keycode == 37) { + core.status.event.selection = 0; core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); return; } - if (keycode==39) { - core.status.event.selection=1; + if (keycode == 39) { + core.status.event.selection = 1; core.ui.drawConfirmBox(core.status.event.ui, core.status.event.data.yes, core.status.event.data.no); return; } - if (keycode==13 || keycode==32 || keycode==67) { - if (core.status.event.selection==0 && core.isset(core.status.event.data.yes)) { - core.status.event.selection=null; + if (keycode == 13 || keycode == 32 || keycode == 67) { + if (core.status.event.selection == 0 && core.isset(core.status.event.data.yes)) { + core.status.event.selection = null; core.status.event.data.yes(); return; } - if (core.status.event.selection==1 && core.isset(core.status.event.data.no)) { - core.status.event.selection=null; + if (core.status.event.selection == 1 && core.isset(core.status.event.data.no)) { + core.status.event.selection = null; core.status.event.data.no(); return; } @@ -851,11 +859,11 @@ actions.prototype._keyUpConfirmBox = function (keycode) { } ////// 自定义事件时的点击操作 ////// -actions.prototype._clickAction = function (x,y) { - if (core.status.event.data.type=='text') { +actions.prototype._clickAction = function (x, y) { + if (core.status.event.data.type == 'text') { // 打字机效果显示全部文字 - if (core.status.event.interval!=null) { + if (core.status.event.interval != null) { core.insertAction({"type": "text", "text": core.status.event.ui, "showAll": true}); } @@ -864,17 +872,17 @@ actions.prototype._clickAction = function (x,y) { return; } - if (core.status.event.data.type=='choices') { + if (core.status.event.data.type == 'choices') { // 选项 var data = core.status.event.data.current; var choices = data.choices; - if (choices.length==0) return; + if (choices.length == 0) return; if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { // 选择 - core.status.route.push("choices:"+(y-topIndex)); - core.insertAction(choices[y-topIndex].action); + core.status.route.push("choices:" + (y - topIndex)); + core.insertAction(choices[y - topIndex].action); core.doAction(); } } @@ -883,39 +891,39 @@ actions.prototype._clickAction = function (x,y) { ////// 自定义事件时,按下某个键的操作 ////// actions.prototype._keyDownAction = function (keycode) { - if (core.status.event.data.type=='choices') { + if (core.status.event.data.type == 'choices') { this._keyDownChoices(keycode); } } ////// 自定义事件时,放开某个键的操作 ////// actions.prototype._keyUpAction = function (keycode) { - if (core.status.event.data.type=='text' && (keycode==13 || keycode==32 || keycode==67)) { + if (core.status.event.data.type == 'text' && (keycode == 13 || keycode == 32 || keycode == 67)) { // 打字机效果显示全部文字 - if (core.status.event.interval!=null) { + if (core.status.event.interval != null) { core.insertAction({"type": "text", "text": core.status.event.ui, "showAll": true}); } core.doAction(); return; } - if (core.status.event.data.type=='wait') { + if (core.status.event.data.type == 'wait') { core.setFlag('type', 0); core.setFlag('keycode', keycode); - core.status.route.push("input:"+keycode); + core.status.route.push("input:" + keycode); core.doAction(); return; } - if (core.status.event.data.type=='choices') { + if (core.status.event.data.type == 'choices') { var data = core.status.event.data.current; var choices = data.choices; - if (choices.length>0) { + if (choices.length > 0) { this._selectChoices(choices.length, keycode, this._clickAction); } } } ////// 怪物手册界面的点击操作 ////// -actions.prototype._clickBook = function(x,y) { +actions.prototype._clickBook = function (x, y) { // 上一页 if ((x == 3 || x == 4) && y == 12) { core.ui.drawBook(core.status.event.data - 6); @@ -927,7 +935,7 @@ actions.prototype._clickBook = function(x,y) { return; } // 返回 - if (x>=10 && x<=12 && y==12) { + if (x >= 10 && x <= 12 && y == 12) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -940,9 +948,9 @@ actions.prototype._clickBook = function(x,y) { } // 怪物信息 var data = core.status.event.data; - if (core.isset(data) && y<12) { - var page=parseInt(data/6); - var index=6*page+parseInt(y/2); + if (core.isset(data) && y < 12) { + var page = parseInt(data / 6); + var index = 6 * page + parseInt(y / 2); core.ui.drawBook(index); core.ui.drawBookDetail(index); } @@ -951,18 +959,18 @@ actions.prototype._clickBook = function(x,y) { ////// 怪物手册界面时,按下某个键的操作 ////// actions.prototype._keyDownBook = function (keycode) { - if (keycode==37) core.ui.drawBook(core.status.event.data-6); - if (keycode==38) core.ui.drawBook(core.status.event.data-1); - if (keycode==39) core.ui.drawBook(core.status.event.data+6); - if (keycode==40) core.ui.drawBook(core.status.event.data+1); - if (keycode==33) core.ui.drawBook(core.status.event.data-6); - if (keycode==34) core.ui.drawBook(core.status.event.data+6); + if (keycode == 37) core.ui.drawBook(core.status.event.data - 6); + if (keycode == 38) core.ui.drawBook(core.status.event.data - 1); + if (keycode == 39) core.ui.drawBook(core.status.event.data + 6); + if (keycode == 40) core.ui.drawBook(core.status.event.data + 1); + if (keycode == 33) core.ui.drawBook(core.status.event.data - 6); + if (keycode == 34) core.ui.drawBook(core.status.event.data + 6); return; } ////// 怪物手册界面时,放开某个键的操作 ////// actions.prototype._keyUpBook = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -973,10 +981,10 @@ actions.prototype._keyUpBook = function (keycode) { else core.ui.closePanel(); return; } - if (keycode==13 || keycode==32 || keycode==67) { - var data=core.status.event.data; + if (keycode == 13 || keycode == 32 || keycode == 67) { + var data = core.status.event.data; if (core.isset(data)) { - this._clickBook(6, 2*(data%6)); + this._clickBook(6, 2 * (data % 6)); } return; } @@ -989,23 +997,23 @@ actions.prototype._clickBookDetail = function () { } ////// 楼层传送器界面时的点击操作 ////// -actions.prototype._clickFly = function(x,y) { - if ((x==10 || x==11) && y==9) core.ui.drawFly(this._getNextFlyFloor(-1)); - if ((x==10 || x==11) && y==5) core.ui.drawFly(this._getNextFlyFloor(1)); - if ((x==10 || x==11) && y==10) core.ui.drawFly(this._getNextFlyFloor(-10)); - if ((x==10 || x==11) && y==4) core.ui.drawFly(this._getNextFlyFloor(10)); - if (x>=5 && x<=7 && y==12) core.ui.closePanel(); - if (x>=0 && x<=9 && y>=3 && y<=11) +actions.prototype._clickFly = function (x, y) { + if ((x == 10 || x == 11) && y == 9) core.ui.drawFly(this._getNextFlyFloor(-1)); + if ((x == 10 || x == 11) && y == 5) core.ui.drawFly(this._getNextFlyFloor(1)); + if ((x == 10 || x == 11) && y == 10) core.ui.drawFly(this._getNextFlyFloor(-10)); + if ((x == 10 || x == 11) && y == 4) core.ui.drawFly(this._getNextFlyFloor(10)); + if (x >= 5 && x <= 7 && y == 12) core.ui.closePanel(); + if (x >= 0 && x <= 9 && y >= 3 && y <= 11) core.control.flyTo(core.floorIds[core.status.event.data]); return; } ////// 楼层传送器界面时,按下某个键的操作 ////// actions.prototype._keyDownFly = function (keycode) { - if (keycode==37) core.ui.drawFly(this._getNextFlyFloor(-10)); - else if (keycode==38) core.ui.drawFly(this._getNextFlyFloor(1)); - else if (keycode==39) core.ui.drawFly(this._getNextFlyFloor(10)); - else if (keycode==40) core.ui.drawFly(this._getNextFlyFloor(-1)); + if (keycode == 37) core.ui.drawFly(this._getNextFlyFloor(-10)); + else if (keycode == 38) core.ui.drawFly(this._getNextFlyFloor(1)); + else if (keycode == 39) core.ui.drawFly(this._getNextFlyFloor(10)); + else if (keycode == 40) core.ui.drawFly(this._getNextFlyFloor(-1)); return; } @@ -1030,15 +1038,15 @@ actions.prototype._getNextFlyFloor = function (delta, index) { ////// 楼层传送器界面时,放开某个键的操作 ////// actions.prototype._keyUpFly = function (keycode) { - if (keycode==71 || keycode==27 || keycode==88) + if (keycode == 71 || keycode == 27 || keycode == 88) core.ui.closePanel(); - if (keycode==13 || keycode==32 || keycode==67) - this._clickFly(5,5); + if (keycode == 13 || keycode == 32 || keycode == 67) + this._clickFly(5, 5); return; } ////// 查看地图界面时的点击操作 ////// -actions.prototype._clickViewMaps = function (x,y) { +actions.prototype._clickViewMaps = function (x, y) { if (!core.isset(core.status.event.data)) { core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId)); return; @@ -1049,54 +1057,54 @@ actions.prototype._clickViewMaps = function (x,y) { var cx = core.status.event.data.x, cy = core.status.event.data.y; var floorId = core.floorIds[index], mw = core.floors[floorId].width, mh = core.floors[floorId].height; - if (x==0 && y==0) { + if (x == 0 && y == 0) { core.status.event.data.damage = !core.status.event.data.damage; core.ui.drawMaps(index, cx, cy); return; } - if (x==0 && y==12) { + if (x == 0 && y == 12) { core.status.event.data.paint = !core.status.event.data.paint; core.ui.drawMaps(index, cx, cy); return; } - if (x==12 && y==0) { + if (x == 12 && y == 0) { core.status.event.data.all = !core.status.event.data.all; core.ui.drawMaps(index, cx, cy); return; } - if (x>=2 && x<=10 && y<=1 && mh>13) { - core.ui.drawMaps(index, cx, cy-1); + if (x >= 2 && x <= 10 && y <= 1 && mh > 13) { + core.ui.drawMaps(index, cx, cy - 1); return; } - if (x>=2 && x<=10 && y>=11 && mh>13) { - core.ui.drawMaps(index, cx, cy+1); + if (x >= 2 && x <= 10 && y >= 11 && mh > 13) { + core.ui.drawMaps(index, cx, cy + 1); return; } - if (x<=1 && y>=2 && y<=10) { - core.ui.drawMaps(index, cx-1, cy); + if (x <= 1 && y >= 2 && y <= 10) { + core.ui.drawMaps(index, cx - 1, cy); return; } - if (x>=11 && y>=2 && y<=10) { - core.ui.drawMaps(index, cx+1, cy); + if (x >= 11 && y >= 2 && y <= 10) { + core.ui.drawMaps(index, cx + 1, cy); return; } - if(y<=4 && (mh==13 || (x>=2 && x<=10))) { + if (y <= 4 && (mh == 13 || (x >= 2 && x <= 10))) { index++; - while (index=8 && (mh==13 || (x>=2 && x<=10))) { + else if (y >= 8 && (mh == 13 || (x >= 2 && x <= 10))) { index--; - while (index>=0 && index!=now && core.status.maps[core.floorIds[index]].cannotViewMap) + while (index >= 0 && index != now && core.status.maps[core.floorIds[index]].cannotViewMap) index--; - if (index>=0) + if (index >= 0) core.ui.drawMaps(index); } - else if (x>=2 && x<=10 && y>=5 && y<=7) { + else if (x >= 2 && x <= 10 && y >= 5 && y <= 7) { core.clearMap('data'); core.ui.closePanel(); } @@ -1108,12 +1116,12 @@ actions.prototype._keyDownViewMaps = function (keycode) { var floorId = core.floorIds[core.status.event.data.index], mh = core.floors[floorId].height; - if (keycode==38||keycode==33) this._clickViewMaps(6, 3); - if (keycode==40||keycode==34) this._clickViewMaps(6, 9); - if (keycode==87 && mh>13) this._clickViewMaps(6,0); - if (keycode==65) this._clickViewMaps(0,6); - if (keycode==83 && mh>13) this._clickViewMaps(6,12); - if (keycode==68) this._clickViewMaps(12,6); + if (keycode == 38 || keycode == 33) this._clickViewMaps(6, 3); + if (keycode == 40 || keycode == 34) this._clickViewMaps(6, 9); + if (keycode == 87 && mh > 13) this._clickViewMaps(6, 0); + if (keycode == 65) this._clickViewMaps(0, 6); + if (keycode == 83 && mh > 13) this._clickViewMaps(6, 12); + if (keycode == 68) this._clickViewMaps(12, 6); return; } @@ -1124,27 +1132,27 @@ actions.prototype._keyUpViewMaps = function (keycode) { return; } - if (keycode==27 || keycode==13 || keycode==32 || (!core.isReplaying() && keycode==67)) { + if (keycode == 27 || keycode == 13 || keycode == 32 || (!core.isReplaying() && keycode == 67)) { core.clearMap('data'); core.ui.closePanel(); return; } - if (keycode==86) { + if (keycode == 86) { core.status.event.data.damage = !core.status.event.data.damage; core.ui.drawMaps(core.status.event.data); return; } - if (keycode==90) { + if (keycode == 90) { core.status.event.data.all = !core.status.event.data.all; core.ui.drawMaps(core.status.event.data); return; } - if (keycode==77) { + if (keycode == 77) { core.status.event.data.paint = !core.status.event.data.paint; core.ui.drawMaps(core.status.event.data); return; } - if (keycode==88 || (core.isReplaying() && keycode==67)) { + if (keycode == 88 || (core.isReplaying() && keycode == 67)) { if (core.isReplaying()) { core.bookReplay(); } else { @@ -1156,16 +1164,16 @@ actions.prototype._keyUpViewMaps = function (keycode) { } ////// 商店界面时的点击操作 ////// -actions.prototype._clickShop = function(x,y) { +actions.prototype._clickShop = function (x, y) { var shop = core.status.event.data.shop; var choices = shop.choices; if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(choices.length / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { + return core.events._useShop(shop, y - topIndex); } // 离开 - else if (y==topIndex+choices.length) { + else if (y == topIndex + choices.length) { core.events._exitShop(); } else return false; @@ -1175,56 +1183,60 @@ actions.prototype._clickShop = function(x,y) { ////// 商店界面时,放开某个键的操作 ////// actions.prototype._keyUpShop = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { core.events._exitShop(); return; } - this._selectChoices(core.status.event.data.shop.choices.length+1, keycode, this._clickShop); + this._selectChoices(core.status.event.data.shop.choices.length + 1, keycode, this._clickShop); return; } ////// 快捷商店界面时的点击操作 ////// -actions.prototype._clickQuickShop = function(x, y) { - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); +actions.prototype._clickQuickShop = function (x, y) { + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); if (x >= 5 && x <= 7) { var topIndex = 6 - parseInt(keys.length / 2); - if (y>=topIndex && y= topIndex && y < topIndex + keys.length) { var reason = core.events.canUseQuickShop(keys[y - topIndex]); if (!core.flags.enableDisabledShop && core.isset(reason)) { core.drawText(reason); return; } core.events.openShop(keys[y - topIndex], true); - if (core.status.event.id=='shop') + if (core.status.event.id == 'shop') core.status.event.data.fromList = true; } // 离开 - else if (y==topIndex+keys.length) + else if (y == topIndex + keys.length) core.ui.closePanel(); } } ////// 快捷商店界面时,放开某个键的操作 ////// actions.prototype._keyUpQuickShop = function (keycode) { - if (keycode==27 || keycode==75 || keycode==88 || keycode==86) { + if (keycode == 27 || keycode == 75 || keycode == 88 || keycode == 86) { core.ui.closePanel(); return; } - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); - this._selectChoices(keys.length+1, keycode, this._clickQuickShop); + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); + this._selectChoices(keys.length + 1, keycode, this._clickQuickShop); return; } ////// 工具栏界面时的点击操作 ////// -actions.prototype._clickToolbox = function(x,y) { +actions.prototype._clickToolbox = function (x, y) { // 装备栏 - if (x>=10 && x<=12 && y==0) { + if (x >= 10 && x <= 12 && y == 0) { core.ui.closePanel(); core.openEquipbox(); return; } // 返回 - if (x>=10 && x<=12 && y==12) { + if (x >= 10 && x <= 12 && y == 12) { core.ui.closePanel(); return; } @@ -1232,54 +1244,55 @@ actions.prototype._clickToolbox = function(x,y) { var constantsPage = core.status.event.data.constantsPage; // 上一页 if (x == 3 || x == 4) { - if (y == 7 && toolsPage>1) { + if (y == 7 && toolsPage > 1) { core.status.event.data.toolsPage--; core.ui.drawToolbox(core.status.event.selection); } - if (y == 12 && constantsPage>1) { + if (y == 12 && constantsPage > 1) { core.status.event.data.toolsPage--; core.ui.drawToolbox(core.status.event.selection); } } // 下一页 if (x == 8 || x == 9) { - if (y == 7 && toolsPage=0) + if (index >= 0) this._clickToolboxIndex(index); } ////// 选择工具栏界面中某个Index后的操作 ////// -actions.prototype._clickToolboxIndex = function(index) { +actions.prototype._clickToolboxIndex = function (index) { var items = null; var select; - if (index<12) { - select = index + 12 * (core.status.event.data.toolsPage-1); + if (index < 12) { + select = index + 12 * (core.status.event.data.toolsPage - 1); items = Object.keys(core.status.hero.items.tools).sort(); } else { - select = index%12 + 12 * (core.status.event.data.constantsPage-1); + select = index % 12 + 12 * (core.status.event.data.constantsPage - 1); items = Object.keys(core.status.hero.items.constants).sort(); } - if (items==null) return; - if (select>=items.length) return; - var itemId=items[select]; - if (itemId==core.status.event.data.selectId) { + if (items == null) return; + if (select >= items.length) return; + var itemId = items[select]; + if (itemId == core.status.event.data.selectId) { core.events.tryUseItem(itemId); } else { @@ -1296,79 +1309,79 @@ actions.prototype._keyDownToolbox = function (keycode) { var index = core.status.event.selection; var toolsPage = core.status.event.data.toolsPage; var constantsPage = core.status.event.data.constantsPage; - var toolsTotalPage = Math.ceil(tools.length/12); - var constantsTotalPage = Math.ceil(constants.length/12); - var toolsLastIndex = toolsPage 1) { core.status.event.data.toolsPage--; index = 11; } else return; // 第一页不向前翻 } - else if (index==12) { + else if (index == 12) { if (constantsPage == 1) { - if (toolsTotalPage==0) return; + if (toolsTotalPage == 0) return; core.status.event.data.toolsPage = toolsTotalPage; - index = (tools.length+11)%12; + index = (tools.length + 11) % 12; } else { core.status.event.data.constantsPage--; index = 23; } } - else index -= 1 ; + else index -= 1; this._clickToolboxIndex(index); return; } - if (keycode==38) { // up - if (index>=12&&index<=17) { // 进入tools - if (toolsTotalPage==0) return; - if (toolsLastIndex>=6) index = Math.min(toolsLastIndex, index-6); - else index = Math.min(toolsLastIndex, index-12); + if (keycode == 38) { // up + if (index >= 12 && index <= 17) { // 进入tools + if (toolsTotalPage == 0) return; + if (toolsLastIndex >= 6) index = Math.min(toolsLastIndex, index - 6); + else index = Math.min(toolsLastIndex, index - 12); } - else if (index<6) return; // 第一行没有向上 + else if (index < 6) return; // 第一行没有向上 else index -= 6; this._clickToolboxIndex(index); return; } - if (keycode==39) { // right - if (toolsPage 5) nextIndex = Math.min(toolsLastIndex, index + 6); - else index+=6; + else index += 6; } - if (nextIndex==null && index<=11) { + if (nextIndex == null && index <= 11) { if (constantsTotalPage == 0) return; - nextIndex = Math.min(index+6, constantsLastIndex); + nextIndex = Math.min(index + 6, constantsLastIndex); } - if (nextIndex==null && index<=17) { - if (constantsLastIndex > 17) nextIndex = Math.min(constantsLastIndex, index+6); + if (nextIndex == null && index <= 17) { + if (constantsLastIndex > 17) nextIndex = Math.min(constantsLastIndex, index + 6); } - if (nextIndex!=null) { + if (nextIndex != null) { this._clickToolboxIndex(nextIndex); } return; @@ -1377,33 +1390,33 @@ actions.prototype._keyDownToolbox = function (keycode) { ////// 工具栏界面时,放开某个键的操作 ////// actions.prototype._keyUpToolbox = function (keycode) { - if (keycode==81){ + if (keycode == 81) { core.ui.closePanel(); core.openEquipbox(); return; } - if (keycode==84 || keycode==27 || keycode==88) { + if (keycode == 84 || keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } if (!core.isset(core.status.event.data)) return; - if (keycode==13 || keycode==32 || keycode==67) { + if (keycode == 13 || keycode == 32 || keycode == 67) { this._clickToolboxIndex(core.status.event.selection); return; } } ////// 装备栏界面时的点击操作 ////// -actions.prototype._clickEquipbox = function(x,y) { +actions.prototype._clickEquipbox = function (x, y) { // 道具栏 - if (x>=10 && x<=12 && y==0) { + if (x >= 10 && x <= 12 && y == 0) { core.ui.closePanel(); core.openToolbox(); return; } // 返回 - if (x>=10 && x<=12 && y==12) { + if (x >= 10 && x <= 12 && y == 12) { core.ui.closePanel(); return; } @@ -1413,7 +1426,7 @@ actions.prototype._clickEquipbox = function(x,y) { // 上一页 if ((x == 3 || x == 4) && y == 12) { - if (page>1) { + if (page > 1) { core.status.event.data.page--; core.ui.drawEquipbox(core.status.event.selection); } @@ -1421,44 +1434,44 @@ actions.prototype._clickEquipbox = function(x,y) { } // 下一页 if ((x == 8 || x == 9) && y == 12) { - var lastPage = Math.ceil(Object.keys(core.status.hero.items.equips).length/12); - if (page=0) { - if (index<12) index = parseInt(index/2); + if (index >= 0) { + if (index < 12) index = parseInt(index / 2); this._clickEquipboxIndex(index); } } ////// 选择装备栏界面中某个Index后的操作 ////// -actions.prototype._clickEquipboxIndex = function(index) { - if (index<6) { - if (index>=core.status.globalAttribute.equipName.length) return; - if (index==core.status.event.selection && core.isset(core.status.hero.equipment[index])) { +actions.prototype._clickEquipboxIndex = function (index) { + if (index < 6) { + if (index >= core.status.globalAttribute.equipName.length) return; + if (index == core.status.event.selection && core.isset(core.status.hero.equipment[index])) { core.unloadEquip(index); - core.status.route.push("unEquip:"+index); + core.status.route.push("unEquip:" + index); } } - else if (index>=12) { - var equips = Object.keys(core.status.hero.items.equips||{}).sort(); - if (index==core.status.event.selection) { - var equipId = equips[index-12 + (core.status.event.data.page-1)*12]; + else if (index >= 12) { + var equips = Object.keys(core.status.hero.items.equips || {}).sort(); + if (index == core.status.event.selection) { + var equipId = equips[index - 12 + (core.status.event.data.page - 1) * 12]; core.loadEquip(equipId); - core.status.route.push("equip:"+equipId); + core.status.route.push("equip:" + equipId); } - } + } core.ui.drawEquipbox(index); } @@ -1470,12 +1483,12 @@ actions.prototype._keyDownEquipbox = function (keycode) { var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); var index = core.status.event.selection; var page = core.status.event.data.page; - var totalPage = Math.ceil(ownEquipment.length/12); - var totalLastIndex = 12+(page 1) { core.status.event.data.page--; index = 23; @@ -1488,47 +1501,47 @@ actions.prototype._keyDownEquipbox = function (keycode) { this._clickEquipboxIndex(index); return; } - if (keycode==38) { // up - if (index<3) return; - else if (index<6) index -= 3; + if (keycode == 38) { // up + if (index < 3) return; + else if (index < 6) index -= 3; else if (index < 18) { - index = parseInt((index-12)/2); - if (equipCapacity>3) index = Math.min(equipCapacity-1, index + 3); - else index = Math.min(equipCapacity-1, index); + index = parseInt((index - 12) / 2); + if (equipCapacity > 3) index = Math.min(equipCapacity - 1, index + 3); + else index = Math.min(equipCapacity - 1, index); } else index -= 6; this._clickEquipboxIndex(index); return; } - if (keycode==39) { // right - if (page3) index = Math.min(index+3, equipCapacity-1); + if (keycode == 40) { // down + if (index < 3) { + if (equipCapacity > 3) index = Math.min(index + 3, equipCapacity - 1); else { if (totalPage == 0) return; - index = Math.min(2*index+1+12, totalLastIndex); + index = Math.min(2 * index + 1 + 12, totalLastIndex); } } else if (index < 6) { if (totalPage == 0) return; - index = Math.min(2*(index-3)+1+12, totalLastIndex); + index = Math.min(2 * (index - 3) + 1 + 12, totalLastIndex); } else if (index < 18) - index = Math.min(index+6, totalLastIndex); + index = Math.min(index + 6, totalLastIndex); else return; this._clickEquipboxIndex(index); return; @@ -1537,45 +1550,45 @@ actions.prototype._keyDownEquipbox = function (keycode) { ////// 装备栏界面时,放开某个键的操作 ////// actions.prototype._keyUpEquipbox = function (keycode, altKey) { - if (altKey && keycode>=48 && keycode<=57) { - core.items.quickSaveEquip(keycode-48); + if (altKey && keycode >= 48 && keycode <= 57) { + core.items.quickSaveEquip(keycode - 48); return; } - if (keycode==84){ + if (keycode == 84) { core.ui.closePanel(); core.openToolbox(); return; } - if (keycode==81 || keycode==27 || keycode==88) { + if (keycode == 81 || keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } if (!core.isset(core.status.event.data.selectId)) return; - if (keycode==13 || keycode==32 || keycode==67) { + if (keycode == 13 || keycode == 32 || keycode == 67) { this._clickEquipboxIndex(core.status.event.selection); return; } } ////// 存读档界面时的点击操作 ////// -actions.prototype._clickSL = function(x,y) { +actions.prototype._clickSL = function (x, y) { - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; + var index = core.status.event.data; + var page = parseInt(index / 10), offset = index % 10; // 上一页 if ((x == 3 || x == 4) && y == 12) { - core.ui.drawSLPanel(10*(page-1)+offset); + core.ui.drawSLPanel(10 * (page - 1) + offset); return; } // 下一页 if ((x == 8 || x == 9) && y == 12) { - core.ui.drawSLPanel(10*(page+1)+offset); + core.ui.drawSLPanel(10 * (page + 1) + offset); return; } // 返回 - if (x>=10 && x<=12 && y==12) { + if (x >= 10 && x <= 12 && y == 12) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -1586,42 +1599,42 @@ actions.prototype._clickSL = function(x,y) { return; } // 删除 - if (x>=0 && x<=2 && y==12) { + if (x >= 0 && x <= 2 && y == 12) { - if (core.status.event.id=='save') { - core.status.event.selection=!core.status.event.selection; + if (core.status.event.id == 'save') { + core.status.event.selection = !core.status.event.selection; core.ui.drawSLPanel(index); } else { - var index = parseInt(prompt("请输入读档编号"))||0; - if (index>0) { + var index = parseInt(prompt("请输入读档编号")) || 0; + if (index > 0) { core.doSL(index, core.status.event.id); } } return; } - var id=null; - if (y>=1 && y<=4) { - if (x>=1 && x<=3) id = "autoSave"; - if (x>=5 && x<=7) id = 5*page+1; - if (x>=9 && x<=11) id = 5*page+2; + var id = null; + if (y >= 1 && y <= 4) { + if (x >= 1 && x <= 3) id = "autoSave"; + if (x >= 5 && x <= 7) id = 5 * page + 1; + if (x >= 9 && x <= 11) id = 5 * page + 2; } - if (y>=7 && y<=10) { - if (x>=1 && x<=3) id = 5*page+3; - if (x>=5 && x<=7) id = 5*page+4; - if (x>=9 && x<=11) id = 5*page+5; + if (y >= 7 && y <= 10) { + if (x >= 1 && x <= 3) id = 5 * page + 3; + if (x >= 5 && x <= 7) id = 5 * page + 4; + if (x >= 9 && x <= 11) id = 5 * page + 5; } - if (id!=null) { - if (core.status.event.selection) { + if (id != null) { + if (core.status.event.selection) { if (id == 'autoSave') { core.drawTip("无法删除自动存档!"); } else { // core.removeLocalStorage("save"+id); - core.removeLocalForage("save"+id, function() { + core.removeLocalForage("save" + id, function () { core.ui.drawSLPanel(index, true); - }, function() { + }, function () { core.drawTip("无法删除存档!"); }) } @@ -1633,53 +1646,53 @@ actions.prototype._clickSL = function(x,y) { } ////// 存读档界面时,按下某个键的操作 ////// -actions.prototype._keyDownSL = function(keycode) { +actions.prototype._keyDownSL = function (keycode) { - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; + var index = core.status.event.data; + var page = parseInt(index / 10), offset = index % 10; - if (keycode==37) { // left - if (offset==0) { - core.ui.drawSLPanel(10*(page-1) + 5); + if (keycode == 37) { // left + if (offset == 0) { + core.ui.drawSLPanel(10 * (page - 1) + 5); } else { core.ui.drawSLPanel(index - 1); } return; } - if (keycode==38) { // up - if (offset<3) { - core.ui.drawSLPanel(10*(page-1) + offset + 3); + if (keycode == 38) { // up + if (offset < 3) { + core.ui.drawSLPanel(10 * (page - 1) + offset + 3); } else { core.ui.drawSLPanel(index - 3); } return; } - if (keycode==39) { // right - if (offset==5) { - core.ui.drawSLPanel(10*(page+1)+1); + if (keycode == 39) { // right + if (offset == 5) { + core.ui.drawSLPanel(10 * (page + 1) + 1); } else { core.ui.drawSLPanel(index + 1); } return; } - if (keycode==40) { // down - if (offset>=3) { - core.ui.drawSLPanel(10*(page+1) + offset - 3); + if (keycode == 40) { // down + if (offset >= 3) { + core.ui.drawSLPanel(10 * (page + 1) + offset - 3); } else { core.ui.drawSLPanel(index + 3); } return; } - if (keycode==33) { // PAGEUP - core.ui.drawSLPanel(10*(page-1) + offset); + if (keycode == 33) { // PAGEUP + core.ui.drawSLPanel(10 * (page - 1) + offset); return; } - if (keycode==34) { // PAGEDOWN - core.ui.drawSLPanel(10*(page+1) + offset); + if (keycode == 34) { // PAGEDOWN + core.ui.drawSLPanel(10 * (page + 1) + offset); return; } } @@ -1687,10 +1700,10 @@ actions.prototype._keyDownSL = function(keycode) { ////// 存读档界面时,放开某个键的操作 ////// actions.prototype._keyUpSL = function (keycode) { - var index=core.status.event.data; - var page = parseInt(index/10), offset=index%10; + var index = core.status.event.data; + var page = parseInt(index / 10), offset = index % 10; - if (keycode==27 || keycode==88 || (core.status.event.id == 'save' && keycode==83) || (core.status.event.id == 'load' && keycode==68)) { + if (keycode == 27 || keycode == 88 || (core.status.event.id == 'save' && keycode == 83) || (core.status.event.id == 'load' && keycode == 68)) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -1700,32 +1713,32 @@ actions.prototype._keyUpSL = function (keycode) { } return; } - if (keycode==13 || keycode==32 || keycode==67) { - if (offset==0) { + if (keycode == 13 || keycode == 32 || keycode == 67) { + if (offset == 0) { core.doSL("autoSave", core.status.event.id); } else { - core.doSL(5*page+offset, core.status.event.id); + core.doSL(5 * page + offset, core.status.event.id); } return; } - if (keycode==69 && core.status.event.id == 'load') { // E - var index = parseInt(prompt("请输入读档编号"))||0; - if (index>0) { + if (keycode == 69 && core.status.event.id == 'load') { // E + var index = parseInt(prompt("请输入读档编号")) || 0; + if (index > 0) { core.doSL(index, core.status.event.id); } return; } - if (keycode==46) { - if (offset==0) { + if (keycode == 46) { + if (offset == 0) { core.drawTip("无法删除自动存档!"); } else { // core.removeLocalStorage("save"+(5*page+offset)); // core.ui.drawSLPanel(index); - core.removeLocalForage("save"+(5*page+offset), function() { + core.removeLocalForage("save" + (5 * page + offset), function () { core.ui.drawSLPanel(index, true); - }, function() { + }, function () { core.drawTip("无法删除存档!"); }) } @@ -1733,12 +1746,12 @@ actions.prototype._keyUpSL = function (keycode) { } ////// 系统设置界面时的点击操作 ////// -actions.prototype._clickSwitchs = function (x,y) { - if (x<5 || x>7) return; +actions.prototype._clickSwitchs = function (x, y) { + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { + var selection = y - topIndex; switch (selection) { case 0: core.triggerBgm(); @@ -1750,25 +1763,25 @@ actions.prototype._clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 2: - core.flags.displayEnemyDamage=!core.flags.displayEnemyDamage; + core.flags.displayEnemyDamage = !core.flags.displayEnemyDamage; core.updateDamage(); core.setLocalStorage('enemyDamage', core.flags.displayEnemyDamage); core.ui.drawSwitchs(); break; case 3: - core.flags.displayCritical=!core.flags.displayCritical; + core.flags.displayCritical = !core.flags.displayCritical; core.updateDamage(); core.setLocalStorage('critical', core.flags.displayCritical); core.ui.drawSwitchs(); break; case 4: - core.flags.displayExtraDamage=!core.flags.displayExtraDamage; + core.flags.displayExtraDamage = !core.flags.displayExtraDamage; core.updateDamage(); core.setLocalStorage('extraDamage', core.flags.displayExtraDamage); core.ui.drawSwitchs(); break; case 5: - core.platform.useLocalForage=!core.platform.useLocalForage; + core.platform.useLocalForage = !core.platform.useLocalForage; core.setLocalStorage('useLocalForage', core.platform.useLocalForage); core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; @@ -1786,7 +1799,7 @@ actions.prototype._clickSwitchs = function (x,y) { core.ui.drawSwitchs(); break; case 8: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSettings(); break; } @@ -1795,8 +1808,8 @@ actions.prototype._clickSwitchs = function (x,y) { ////// 系统设置界面时,放开某个键的操作 ////// actions.prototype._keyUpSwitchs = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=0; + if (keycode == 27 || keycode == 88) { + core.status.event.selection = 0; core.ui.drawSettings(); return; } @@ -1804,16 +1817,16 @@ actions.prototype._keyUpSwitchs = function (keycode) { } ////// 系统菜单栏界面时的点击事件 ////// -actions.prototype._clickSettings = function (x,y) { - if (x<5 || x>7) return; +actions.prototype._clickSettings = function (x, y) { + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { + var selection = y - topIndex; switch (selection) { case 0: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSwitchs(); break; case 1: @@ -1828,20 +1841,20 @@ actions.prototype._clickSettings = function (x,y) { core.ui.drawPaint(); break; case 4: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSyncSave(); break; case 5: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawGameInfo(); break; case 6: - core.status.event.selection=1; + core.status.event.selection = 1; core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () { core.ui.closePanel(); core.restart(); }, function () { - core.status.event.selection=3; + core.status.event.selection = 3; core.ui.drawSettings(); }); break; @@ -1855,7 +1868,7 @@ actions.prototype._clickSettings = function (x,y) { ////// 系统菜单栏界面时,放开某个键的操作 ////// actions.prototype._keyUpSettings = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } @@ -1863,32 +1876,32 @@ actions.prototype._keyUpSettings = function (keycode) { } ////// 同步存档界面时的点击操作 ////// -actions.prototype._clickSyncSave = function (x,y) { - if (x<5 || x>7) return; +actions.prototype._clickSyncSave = function (x, y) { + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { + var selection = y - topIndex; switch (selection) { case 0: // core.syncSave("save"); - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSyncSelect(); break; case 1: core.syncLoad(); break; case 2: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawLocalSaveSelect(); break; case 3: core.readFile(function (obj) { - if (obj.name!=core.firstData.name) { + if (obj.name != core.firstData.name) { alert("存档和游戏不一致!"); return; } - if (obj.version!=core.firstData.version) { + if (obj.version != core.firstData.version) { alert("游戏版本不一致!"); return; } @@ -1896,30 +1909,30 @@ actions.prototype._clickSyncSave = function (x,y) { alert("无效的存档!"); return; } - var data=obj.data; + var data = obj.data; if (data instanceof Array) { core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () { - for (var i=1;i<=5*(main.savePages||30);i++) { - if (i<=data.length) { - core.setLocalForage("save"+i, data[i-1]); + for (var i = 1; i <= 5 * (main.savePages || 30); i++) { + if (i <= data.length) { + core.setLocalForage("save" + i, data[i - 1]); } else { if (core.saves.ids[i]) - core.removeLocalForage("save"+i); + core.removeLocalForage("save" + i); } } core.ui.closePanel(); core.drawText("读取成功!\n你的本地所有存档均已被覆盖。"); }, function () { - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSyncSave(); }) } else { // core.setLocalStorage("save"+core.saves.saveIndex, data); - core.setLocalForage("save"+core.saves.saveIndex, data, function() { - core.drawText("同步成功!\n单存档已覆盖至存档"+core.saves.saveIndex); + core.setLocalForage("save" + core.saves.saveIndex, data, function () { + core.drawText("同步成功!\n单存档已覆盖至存档" + core.saves.saveIndex); }) } }, function () { @@ -1927,7 +1940,7 @@ actions.prototype._clickSyncSave = function (x,y) { }); break; case 4: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawReplay(); break; case 5: @@ -1935,7 +1948,7 @@ actions.prototype._clickSyncSave = function (x,y) { core.drawText("\t[系统提示]调试模式下无法下载录像"); break; } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify({ + core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5route", JSON.stringify({ 'name': core.firstData.name, 'hard': core.status.hard, 'seed': core.getFlag('__seed__'), @@ -1943,11 +1956,11 @@ actions.prototype._clickSyncSave = function (x,y) { })); break; case 6: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawStorageRemove(); break; case 7: - core.status.event.selection=4; + core.status.event.selection = 4; core.ui.drawSettings(); break; @@ -1958,8 +1971,8 @@ actions.prototype._clickSyncSave = function (x,y) { ////// 同步存档界面时,放开某个键的操作 ////// actions.prototype._keyUpSyncSave = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=2; + if (keycode == 27 || keycode == 88) { + core.status.event.selection = 2; core.ui.drawSettings(); return; } @@ -1968,11 +1981,11 @@ actions.prototype._keyUpSyncSave = function (keycode) { ////// 同步存档选择界面时的点击操作 ////// actions.prototype._clickSyncSelect = function (x, y) { - if (x<5 || x>7) return; + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; switch (selection) { case 0: @@ -1982,7 +1995,7 @@ actions.prototype._clickSyncSelect = function (x, y) { core.syncSave(); break; case 2: - core.status.event.selection=0; + core.status.event.selection = 0; core.ui.drawSyncSave(); break; } @@ -1991,8 +2004,8 @@ actions.prototype._clickSyncSelect = function (x, y) { ////// 同步存档选择界面时,放开某个键的操作 ////// actions.prototype._keyUpSyncSelect = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=0; + if (keycode == 27 || keycode == 88) { + core.status.event.selection = 0; core.ui.drawSettings(); return; } @@ -2000,36 +2013,36 @@ actions.prototype._keyUpSyncSelect = function (keycode) { } ////// 存档下载界面时的点击操作 ////// -actions.prototype._clickLocalSaveSelect = function (x,y) { - if (x<5 || x>7) return; +actions.prototype._clickLocalSaveSelect = function (x, y) { + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; - if (selection<2) { - core.control.getSaves(selection==0?null:core.saves.saveIndex, function(saves) { + if (selection < 2) { + core.control.getSaves(selection == 0 ? null : core.saves.saveIndex, function (saves) { if (core.isset(saves)) { var content = { "name": core.firstData.name, "version": core.firstData.version, "data": saves } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5save", JSON.stringify(content)); + core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5save", JSON.stringify(content)); } }) } } - core.status.event.selection=2; + core.status.event.selection = 2; core.ui.drawSyncSave(); } ////// 存档下载界面时,放开某个键的操作 ////// actions.prototype._keyUpLocalSaveSelect = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=0; + if (keycode == 27 || keycode == 88) { + core.status.event.selection = 0; core.ui.drawSettings(); return; } @@ -2038,12 +2051,12 @@ actions.prototype._keyUpLocalSaveSelect = function (keycode) { ////// 存档删除界面时的点击操作 ////// actions.prototype._clickStorageRemove = function (x, y) { - if (x<5 || x>7) return; + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; switch (selection) { case 0: @@ -2067,10 +2080,10 @@ actions.prototype._clickStorageRemove = function (x, y) { if (core.platform.useLocalForage) { core.ui.drawWaiting("正在清空,请稍后..."); Object.keys(core.saves.ids).forEach(function (v) { - if (v!=0) - core.removeLocalForage("save"+v); + if (v != 0) + core.removeLocalForage("save" + v); }); - core.removeLocalForage("autoSave", function() { + core.removeLocalForage("autoSave", function () { core.saves.autosave.data = null; core.saves.autosave.updated = false; core.ui.closePanel(); @@ -2081,8 +2094,8 @@ actions.prototype._clickStorageRemove = function (x, y) { } else { Object.keys(core.saves.ids).forEach(function (v) { - if (v!=0) - core.removeLocalStorage("save"+v); + if (v != 0) + core.removeLocalStorage("save" + v); }); core.removeLocalStorage("autoSave"); core.saves.autosave.data = null; @@ -2093,7 +2106,7 @@ actions.prototype._clickStorageRemove = function (x, y) { } break; case 2: - core.status.event.selection=6; + core.status.event.selection = 6; core.ui.drawSyncSave(); break; } @@ -2102,8 +2115,8 @@ actions.prototype._clickStorageRemove = function (x, y) { ////// 存档删除界面时,放开某个键的操作 ////// actions.prototype._keyUpStorageRemove = function (keycode) { - if (keycode==27 || keycode==88) { - core.status.event.selection=5; + if (keycode == 27 || keycode == 88) { + core.status.event.selection = 5; core.ui.drawSyncSave(); return; } @@ -2112,30 +2125,28 @@ actions.prototype._keyUpStorageRemove = function (keycode) { ////// 回放选择界面时的点击操作 ////// actions.prototype._clickReplay = function (x, y) { - if (x<5 || x>7) return; + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; switch (selection) { - case 0: - { - core.ui.closePanel(); - core.startGame(core.status.hard, core.getFlag('__seed__'), core.clone(core.status.route)); - break; - } - case 1: - { - core.status.event.id = 'replayLoad'; - core.status.event.selection = null; - core.ui.clearLastEvent(); - var saveIndex = core.saves.saveIndex; - var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; - core.ui.drawSLPanel(10*page+offset); - break; - } + case 0: { + core.ui.closePanel(); + core.startGame(core.status.hard, core.getFlag('__seed__'), core.clone(core.status.route)); + break; + } + case 1: { + core.status.event.id = 'replayLoad'; + core.status.event.selection = null; + core.ui.clearLastEvent(); + var saveIndex = core.saves.saveIndex; + var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page; + core.ui.drawSLPanel(10 * page + offset); + break; + } case 2: core.chooseReplayFile(); break; @@ -2144,7 +2155,7 @@ actions.prototype._clickReplay = function (x, y) { core.drawText("\t[系统提示]调试模式下无法下载录像"); break; } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify({ + core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5route", JSON.stringify({ 'name': core.firstData.name, 'hard': core.status.hard, 'seed': core.getFlag('__seed__'), @@ -2161,7 +2172,7 @@ actions.prototype._clickReplay = function (x, y) { ////// 回放选择界面时,放开某个键的操作 ////// actions.prototype._keyUpReplay = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } @@ -2170,12 +2181,12 @@ actions.prototype._keyUpReplay = function (keycode) { ////// 游戏信息界面时的点击操作 ////// actions.prototype._clickGameInfo = function (x, y) { - if (x<5 || x>7) return; + if (x < 5 || x > 7) return; var choices = core.status.event.ui.choices; var topIndex = 6 - parseInt((choices.length - 1) / 2); - if (y>=topIndex && y= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; switch (selection) { case 0: @@ -2190,11 +2201,11 @@ actions.prototype._clickGameInfo = function (x, y) { break; case 2: if (core.platform.isPC) { - window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); + window.open("/score.php?name=" + core.firstData.name + "&num=10", "_blank"); } else { if (confirm("即将离开本塔,跳转至本塔评论页面,确认?")) { - window.location.href = "/score.php?name="+core.firstData.name+"&num=10"; + window.location.href = "/score.php?name=" + core.firstData.name + "&num=10"; } } break; @@ -2206,12 +2217,12 @@ actions.prototype._clickGameInfo = function (x, y) { break; case 5: if (core.platform.isPC) - window.open(core.firstData.name+".zip"); + window.open(core.firstData.name + ".zip"); else - window.location.href = core.firstData.name+".zip"; + window.location.href = core.firstData.name + ".zip"; break; case 6: - core.status.event.selection=5; + core.status.event.selection = 5; core.ui.drawSettings(); break; } @@ -2220,7 +2231,7 @@ actions.prototype._clickGameInfo = function (x, y) { ////// 游戏信息界面时,放开某个键的操作 ////// actions.prototype._keyUpGameInfo = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } @@ -2229,102 +2240,103 @@ actions.prototype._keyUpGameInfo = function (keycode) { ////// “虚拟键盘”界面时的点击操作 ////// actions.prototype._clickKeyBoard = function (x, y) { - if (y==3 && x>=1 && x<=11) { + if (y == 3 && x >= 1 && x <= 11) { core.ui.closePanel(); - core.keyUp(112+x-1); // F1-F12: 112-122 + core.keyUp(112 + x - 1); // F1-F12: 112-122 } - if (y==3 && x==12) { + if (y == 3 && x == 12) { var val = prompt(); - if (val!=null) { + if (val != null) { try { eval(val); } - catch (e) {} + catch (e) { + } } } - if (y==4 && x>=1 && x<=10) { + if (y == 4 && x >= 1 && x <= 10) { core.ui.closePanel(); - core.keyUp(x==10?48:48+x); // 1-9: 49-57; 0: 48 + core.keyUp(x == 10 ? 48 : 48 + x); // 1-9: 49-57; 0: 48 } // 字母 var lines = [ - ["Q","W","E","R","T","Y","U","I","O","P"], - ["A","S","D","F","G","H","J","K","L"], - ["Z","X","C","V","B","N","M"], + ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"], + ["A", "S", "D", "F", "G", "H", "J", "K", "L"], + ["Z", "X", "C", "V", "B", "N", "M"], ]; - if (y==5 && x>=1 && x<=10) { + if (y == 5 && x >= 1 && x <= 10) { core.ui.closePanel(); - core.keyUp(lines[0][x-1].charCodeAt(0)); + core.keyUp(lines[0][x - 1].charCodeAt(0)); } - if (y==6 && x>=1 && x<=9) { + if (y == 6 && x >= 1 && x <= 9) { core.ui.closePanel(); - core.keyUp(lines[1][x-1].charCodeAt(0)); + core.keyUp(lines[1][x - 1].charCodeAt(0)); } - if (y==7 && x>=1 && x<=7) { + if (y == 7 && x >= 1 && x <= 7) { core.ui.closePanel(); - core.keyUp(lines[2][x-1].charCodeAt(0)); + core.keyUp(lines[2][x - 1].charCodeAt(0)); } - if (y==8 && x>=1 && x<=11) { + if (y == 8 && x >= 1 && x <= 11) { core.ui.closePanel(); - if (x==1) core.keyUp(189); // - - if (x==2) core.keyUp(187); // = - if (x==3) core.keyUp(219); // [ - if (x==4) core.keyUp(221); // ] - if (x==5) core.keyUp(220); // \ - if (x==6) core.keyUp(186); // ; - if (x==7) core.keyUp(222); // ' - if (x==8) core.keyUp(188); // , - if (x==9) core.keyUp(190); // . - if (x==10) core.keyUp(191); // / - if (x==11) core.keyUp(192); // ` + if (x == 1) core.keyUp(189); // - + if (x == 2) core.keyUp(187); // = + if (x == 3) core.keyUp(219); // [ + if (x == 4) core.keyUp(221); // ] + if (x == 5) core.keyUp(220); // \ + if (x == 6) core.keyUp(186); // ; + if (x == 7) core.keyUp(222); // ' + if (x == 8) core.keyUp(188); // , + if (x == 9) core.keyUp(190); // . + if (x == 10) core.keyUp(191); // / + if (x == 11) core.keyUp(192); // ` } - if (y==9 && x>=1 && x<=10) { + if (y == 9 && x >= 1 && x <= 10) { core.ui.closePanel(); - if (x==1) core.keyUp(27); // ESC - if (x==2) core.keyUp(9); // TAB - if (x==3) core.keyUp(20); // CAPS - if (x==4) core.keyUp(16); // SHIFT - if (x==5) core.keyUp(17); // CTRL - if (x==6) core.keyUp(18); // ALT - if (x==7) core.keyUp(32); // SPACE - if (x==8) core.keyUp(8); // BACKSPACE - if (x==9) core.keyUp(13); // ENTER - if (x==10) core.keyUp(46); // DEL + if (x == 1) core.keyUp(27); // ESC + if (x == 2) core.keyUp(9); // TAB + if (x == 3) core.keyUp(20); // CAPS + if (x == 4) core.keyUp(16); // SHIFT + if (x == 5) core.keyUp(17); // CTRL + if (x == 6) core.keyUp(18); // ALT + if (x == 7) core.keyUp(32); // SPACE + if (x == 8) core.keyUp(8); // BACKSPACE + if (x == 9) core.keyUp(13); // ENTER + if (x == 10) core.keyUp(46); // DEL } - if (y==10 && x>=9 && x<=11) + if (y == 10 && x >= 9 && x <= 11) core.ui.closePanel(); } ////// 光标界面时的点击操作 ////// -actions.prototype._clickCursor = function (x,y) { - if (x==core.status.automaticRoute.cursorX && y==core.status.automaticRoute.cursorY) { +actions.prototype._clickCursor = function (x, y) { + if (x == core.status.automaticRoute.cursorX && y == core.status.automaticRoute.cursorY) { core.ui.closePanel(); - core.onclick(x,y,[]); + core.onclick(x, y, []); return; } - core.status.automaticRoute.cursorX=x; - core.status.automaticRoute.cursorY=y; + core.status.automaticRoute.cursorX = x; + core.status.automaticRoute.cursorY = y; core.ui.drawCursor(); } ////// 光标界面时,按下某个键的操作 ////// actions.prototype._keyDownCursor = function (keycode) { - if (keycode==37) { // left + if (keycode == 37) { // left core.status.automaticRoute.cursorX--; core.ui.drawCursor(); return; } - if (keycode==38) { // up + if (keycode == 38) { // up core.status.automaticRoute.cursorY--; core.ui.drawCursor(); return; } - if (keycode==39) { // right + if (keycode == 39) { // right core.status.automaticRoute.cursorX++; core.ui.drawCursor(); return; } - if (keycode==40) { // down + if (keycode == 40) { // down core.status.automaticRoute.cursorY++; core.ui.drawCursor(); return; @@ -2333,11 +2345,11 @@ actions.prototype._keyDownCursor = function (keycode) { ////// 光标界面时,放开某个键的操作 ////// actions.prototype._keyUpCursor = function (keycode) { - if (keycode==27 || keycode==88) { + if (keycode == 27 || keycode == 88) { core.ui.closePanel(); return; } - if (keycode==13 || keycode==32 || keycode==67 || keycode==69) { + if (keycode == 13 || keycode == 32 || keycode == 67 || keycode == 69) { core.ui.closePanel(); core.onclick(core.status.automaticRoute.cursorX, core.status.automaticRoute.cursorY, []); return; @@ -2347,8 +2359,8 @@ actions.prototype._keyUpCursor = function (keycode) { ////// 绘图相关 ////// actions.prototype._ondownPaint = function (x, y) { - x+=core.bigmap.offsetX; - y+=core.bigmap.offsetY; + x += core.bigmap.offsetX; + y += core.bigmap.offsetY; if (!core.status.event.data.erase) { core.dymCanvas.paint.beginPath(); core.dymCanvas.paint.moveTo(x, y); @@ -2358,14 +2370,14 @@ actions.prototype._ondownPaint = function (x, y) { } actions.prototype._onmovePaint = function (x, y) { - if (core.status.event.data.x==null) return; - x+=core.bigmap.offsetX; - y+=core.bigmap.offsetY; + if (core.status.event.data.x == null) return; + x += core.bigmap.offsetX; + y += core.bigmap.offsetY; if (core.status.event.data.erase) { - core.clearMap('paint', x-10, y-10, 20, 20); + core.clearMap('paint', x - 10, y - 10, 20, 20); return; } - var midx = (core.status.event.data.x+x)/2, midy = (core.status.event.data.y+y)/2; + var midx = (core.status.event.data.x + x) / 2, midy = (core.status.event.data.y + y) / 2; core.dymCanvas.paint.quadraticCurveTo(midx, midy, x, y); core.dymCanvas.paint.stroke(); core.status.event.data.x = x; @@ -2384,7 +2396,7 @@ actions.prototype.setPaintMode = function (mode) { else if (mode == 'erase') core.status.event.data.erase = true; else return; - core.drawTip("进入"+(core.status.event.data.erase?"擦除":"绘图")+"模式"); + core.drawTip("进入" + (core.status.event.data.erase ? "擦除" : "绘图") + "模式"); } actions.prototype.clearPaint = function () { @@ -2399,7 +2411,7 @@ actions.prototype.savePaint = function () { if (core.isset(core.paint[floorId])) data[floorId] = lzw_decode(core.paint[floorId]); } - core.download(core.firstData.name+".h5paint", JSON.stringify({ + core.download(core.firstData.name + ".h5paint", JSON.stringify({ 'name': core.firstData.name, 'paint': data })); @@ -2407,7 +2419,7 @@ actions.prototype.savePaint = function () { actions.prototype.loadPaint = function () { core.readFile(function (obj) { - if (obj.name!=core.firstData.name) { + if (obj.name != core.firstData.name) { alert("绘图文件和游戏不一致!"); return; } @@ -2424,7 +2436,7 @@ actions.prototype.loadPaint = function () { core.clearMap('paint'); var value = core.paint[core.status.floorId]; if (core.isset(value)) value = lzw_decode(value).split(","); - core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); + core.utils.decodeCanvas(value, 32 * core.bigmap.width, 32 * core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); core.drawTip("读取绘图文件成功"); @@ -2441,7 +2453,7 @@ actions.prototype.exitPaint = function () { } actions.prototype._keyUpPaint = function (keycode) { - if (keycode==27 || keycode==88 || keycode==77 || keycode==13 || keycode==32 || keycode==67) { + if (keycode == 27 || keycode == 88 || keycode == 77 || keycode == 13 || keycode == 32 || keycode == 67) { this.exitPaint(); return; } diff --git a/libs/core.js b/libs/core.js index b314eebc..a61b6f6a 100644 --- a/libs/core.js +++ b/libs/core.js @@ -172,9 +172,9 @@ function core() { 'textAttribute': { 'position': "center", "offset": 0, - "title": [255,215,0,1], - "background": [0,0,0,0.85], - "text": [255,255,255,1], + "title": [255, 215, 0, 1], + "background": [0, 0, 0, 0.85], + "text": [255, 255, 255, 1], "titlefont": 22, "textfont": 16, "bold": false, @@ -242,7 +242,7 @@ core.prototype.init = function (coreData, callback) { core.material.enemys = core.enemys.getEnemys(); core.material.icons = core.icons.getIcons(); - core.platform.isOnline = location.protocol.indexOf("http")==0; + core.platform.isOnline = location.protocol.indexOf("http") == 0; if (core.platform.isOnline) { window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; try { @@ -256,10 +256,10 @@ core.prototype.init = function (coreData, callback) { } ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"].forEach(function (t) { - if (navigator.userAgent.indexOf(t)>=0) { - if (t=='iPhone' || t=='iPad' || t=='iPod') core.platform.isIOS = true; - if (t=='Android') core.platform.isAndroid=true; - core.platform.isPC=false; + if (navigator.userAgent.indexOf(t) >= 0) { + if (t == 'iPhone' || t == 'iPad' || t == 'iPod') core.platform.isIOS = true; + if (t == 'Android') core.platform.isAndroid = true; + core.platform.isPC = false; } }); @@ -270,8 +270,8 @@ core.prototype.init = function (coreData, callback) { core.platform.supportCopy = false; } - var chrome=/Chrome\/(\d+)\./i.exec(navigator.userAgent); - if (core.isset(chrome) && parseInt(chrome[1])>=50) + var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent); + if (core.isset(chrome) && parseInt(chrome[1]) >= 50) core.platform.isChrome = true; core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent); core.platform.isQQ = /QQ/i.test(navigator.userAgent); @@ -279,26 +279,41 @@ core.prototype.init = function (coreData, callback) { core.platform.useLocalForage = core.getLocalStorage('useLocalForage', !core.platform.isIOS); if (core.platform.useLocalForage) { try { - core.setLocalForage("__test__", lzw_encode("__test__"), function() { + core.setLocalForage("__test__", lzw_encode("__test__"), function () { try { - core.getLocalForage("__test__", null, function(data) { + core.getLocalForage("__test__", null, function (data) { try { - if (lzw_decode(data)!="__test__") { + if (lzw_decode(data) != "__test__") { console.log("localForage unsupported!"); - core.platform.useLocalForage=false; + core.platform.useLocalForage = false; } else { console.log("localForage supported!") core.removeLocalForage("__test__"); } } - catch (e) {main.log(e); core.platform.useLocalForage=false;} - }, function(e) {main.log(e); core.platform.useLocalForage=false;}) + catch (e) { + main.log(e); + core.platform.useLocalForage = false; + } + }, function (e) { + main.log(e); + core.platform.useLocalForage = false; + }) } - catch (e) {main.log(e); core.platform.useLocalForage=false;} - }, function(e) {main.log(e); core.platform.useLocalForage=false;}) + catch (e) { + main.log(e); + core.platform.useLocalForage = false; + } + }, function (e) { + main.log(e); + core.platform.useLocalForage = false; + }) + } + catch (e) { + main.log(e); + core.platform.useLocalForage = false; } - catch (e) {main.log(e); core.platform.useLocalForage=false;} } core.platform.extendKeyboard = core.getLocalStorage("extendKeyboard", false); @@ -316,7 +331,7 @@ core.prototype.init = function (coreData, callback) { // 先从存储中读取BGM状态 core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true); - if (!core.platform.isPC && (navigator.connection||{}).type!='wifi') + if (!core.platform.isPC && (navigator.connection || {}).type != 'wifi') core.musicStatus.bgmStatus = false; core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); @@ -336,7 +351,7 @@ core.prototype.init = function (coreData, callback) { core.animateFrame.weather.fog.src = "project/images/fog.png"; core.material.images.keyboard = new Image(); - core.material.images.keyboard.onerror = function () { + core.material.images.keyboard.onerror = function () { core.material.images.keyboard = null; } core.material.images.keyboard.src = "project/images/keyboard.png"; @@ -351,14 +366,14 @@ core.prototype.init = function (coreData, callback) { core.loader._load(function () { // 设置勇士高度 - core.material.icons.hero.height = core.material.images.hero.height/4; + core.material.icons.hero.height = core.material.images.hero.height / 4; // 行走图 core.control.updateHeroIcon(); core.initStatus.maps = core.maps.initMaps(core.floorIds); core.setRequestAnimationFrame(); - if (main.mode=='play') + if (main.mode == 'play') core.events.initGame(); if (core.isset(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins)) { @@ -396,13 +411,13 @@ core.prototype._forwardFunc = function (name, funcname) { } if (core[funcname]) { - console.error("ERROR: Cannot forward function "+funcname+" from "+name+"!"); + console.error("ERROR: Cannot forward function " + funcname + " from " + name + "!"); return; } var parameterInfo = /^\s*function\s*[\w_$]*\(([\w_,$\s]*)\)\s*\{/.exec(core[name][funcname].toString()); - var parameters = (parameterInfo==null?"":parameterInfo[1]).replace(/\s*/g, '').replace(/,/g, ', '); + var parameters = (parameterInfo == null ? "" : parameterInfo[1]).replace(/\s*/g, '').replace(/,/g, ', '); // core[funcname] = new Function(parameters, "return core."+name+"."+funcname+"("+parameters+");"); - eval("core."+funcname+" = function ("+parameters+") {\n\treturn core."+name+"."+funcname+"("+parameters+");\n}"); + eval("core." + funcname + " = function (" + parameters + ") {\n\treturn core." + name + "." + funcname + "(" + parameters + ");\n}"); } /** diff --git a/libs/data.js b/libs/data.js index b11f91cf..e833cf37 100644 --- a/libs/data.js +++ b/libs/data.js @@ -4,13 +4,13 @@ function data() { this._init(); } -data.prototype._init = function() { +data.prototype._init = function () { this.firstData = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.firstData; this.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values; this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags; //delete(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d); } -data.prototype.getFirstData = function() { +data.prototype.getFirstData = function () { return core.clone(this.firstData); } \ No newline at end of file diff --git a/libs/enemys.js b/libs/enemys.js index c6ea882c..35d11e09 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -8,8 +8,10 @@ function enemys() { enemys.prototype._init = function () { this.enemys = enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80; this.enemydata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.enemys; - if (main.mode=='play') { - this.enemydata.hasSpecial = function (a, b) {return core.enemys.hasSpecial(a, b)}; + if (main.mode == 'play') { + this.enemydata.hasSpecial = function (a, b) { + return core.enemys.hasSpecial(a, b) + }; for (var enemyId in this.enemys) { this.enemys[enemyId].id = enemyId; } @@ -54,9 +56,9 @@ enemys.prototype.getSpecialText = function (enemy) { var special = enemy.special; var text = []; - var specials=this.getSpecials(); + var specials = this.getSpecials(); if (core.isset(specials)) { - for (var i=0;inextInfo.damage) { + if (nextInfo == null || (typeof nextInfo == 'number')) break; + if (pre > nextInfo.damage) { pre = nextInfo.damage; - list.push([atk-hero_atk, info.damage-nextInfo.damage]); - if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; - if (list.length>=number) break; + list.push([atk - hero_atk, info.damage - nextInfo.damage]); + if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break; + if (list.length >= number) break; } } - if (list.length==0) list.push([0,0]); + if (list.length == 0) list.push([0, 0]); return list; } @@ -211,51 +213,51 @@ enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, var list = []; var calNext = function (currAtk, maxAtk) { var start = Math.floor(currAtk), end = Math.floor(maxAtk); - if (start>end) return null; + if (start > end) return null; - while (startnextInfo.damage) end = mid; - else start = mid+1; + if (pre > nextInfo.damage) end = mid; + else start = mid + 1; } var nextInfo = core.enemys.getDamageInfo(enemy, {"atk": start}, x, y, floorId); - return nextInfo==null||(typeof nextInfo == 'number')||nextInfo.damage>=pre?null:[start,nextInfo.damage]; + return nextInfo == null || (typeof nextInfo == 'number') || nextInfo.damage >= pre ? null : [start, nextInfo.damage]; } var currAtk = hero_atk; while (true) { - var next = calNext(currAtk+1, mon_hp+mon_def, pre); + var next = calNext(currAtk + 1, mon_hp + mon_def, pre); if (next == null) break; currAtk = next[0]; pre = next[1]; - list.push([currAtk-hero_atk, info.damage-pre]); - if (pre<=0 && !core.flags.enableNegativeDamage) break; - if (list.length>=number) break; + list.push([currAtk - hero_atk, info.damage - pre]); + if (pre <= 0 && !core.flags.enableNegativeDamage) break; + if (list.length >= number) break; } - if (list.length==0) list.push([0,0]); + if (list.length == 0) list.push([0, 0]); return list; } enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, floorId) { var mon_hp = info.mon_hp, hero_atk = core.status.hero.atk, mon_def = info.mon_def, turn = info.turn; var list = [], pre = null; - for (var t = turn-1;t>=1;t--) { - var nextAtk = Math.ceil(mon_hp/t) + mon_def; + for (var t = turn - 1; t >= 1; t--) { + var nextAtk = Math.ceil(mon_hp / t) + mon_def; // 装备提升比例的计算临界 nextAtk = Math.ceil(nextAtk / core.getFlag('__atk_buff__', 1)); - if (nextAtk<=hero_atk) break; - if (nextAtk!=pre) { + if (nextAtk <= hero_atk) break; + if (nextAtk != pre) { var nextInfo = this.getDamageInfo(enemy, {"atk": nextAtk}, x, y, floorId); - if (nextInfo==null || (typeof nextInfo == 'number')) break; - list.push([nextAtk-hero_atk,Math.floor(info.damage-nextInfo.damage)]); - if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; + if (nextInfo == null || (typeof nextInfo == 'number')) break; + list.push([nextAtk - hero_atk, Math.floor(info.damage - nextInfo.damage)]); + if (nextInfo.damage <= 0 && !core.flags.enableNegativeDamage) break; pre = nextAtk; } - if (list.length>=number) + if (list.length >= number) break; } - if (list.length==0) list.push([0,0]); + if (list.length == 0) list.push([0, 0]); return list; } @@ -265,7 +267,7 @@ enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) { k = k || 1; var nowDamage = this.calDamage(enemy, null, x, y, floorId); var nextDamage = this.calDamage(enemy, {"def": core.status.hero.def + k}, x, y, floorId); - if (nowDamage == null || nextDamage ==null) return "???"; + if (nowDamage == null || nextDamage == null) return "???"; return nowDamage - nextDamage; } @@ -275,7 +277,7 @@ enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) { } ////// 获得战斗伤害信息(实际伤害计算函数) ////// -enemys.prototype.getDamageInfo = function(enemy, hero, x, y, floorId) { +enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) { // 移动到了脚本编辑 - getDamageInfo中 if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; return this.enemydata.getDamageInfo(enemy, hero, x, y, floorId); @@ -298,12 +300,12 @@ enemys.prototype.updateEnemys = function () { ////// 获得当前楼层的怪物列表 ////// enemys.prototype.getCurrentEnemys = function (floorId) { - floorId=floorId||core.status.floorId; + floorId = floorId || core.status.floorId; var enemys = [], used = {}; var mapBlocks = core.status.maps[floorId].blocks; for (var b = 0; b < mapBlocks.length; b++) { if (core.isset(mapBlocks[b].event) && !mapBlocks[b].disable - && mapBlocks[b].event.cls.indexOf('enemy')==0) { + && mapBlocks[b].event.cls.indexOf('enemy') == 0) { this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId); } } @@ -324,15 +326,15 @@ enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) { enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, floorId) { var enemy = this._getCurrentEnemys_getEnemy(enemyId); - if (enemy==null || used[enemy.id]) return; + if (enemy == null || used[enemy.id]) return; var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId); var specialText = core.enemys.getSpecialText(enemy); - if (specialText.length>=3) specialText = "多属性..."; + if (specialText.length >= 3) specialText = "多属性..."; else specialText = specialText.join(" "); var critical = this.nextCriticals(enemy, 1, null, null, floorId); - if (critical.length>0) critical=critical[0]; + if (critical.length > 0) critical = critical[0]; var e = core.clone(enemy); for (var x in enemyInfo) { @@ -342,7 +344,7 @@ enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, f e.damage = this.getDamage(enemy, null, null, floorId); e.critical = critical[0]; e.criticalDamage = critical[1]; - e.defDamage = this.getDefDamage(enemy,1,null,null,floorId); + e.defDamage = this.getDefDamage(enemy, 1, null, null, floorId); enemys.push(e); used[enemy.id] = true; } diff --git a/libs/events.js b/libs/events.js index 3bda1f7b..4dae39cf 100644 --- a/libs/events.js +++ b/libs/events.js @@ -21,10 +21,10 @@ events.prototype.initGame = function () { ////// 游戏开始事件 ////// events.prototype.startGame = function (hard, seed, route, callback) { - main.dom.levelChooseButtons.style.display='none'; - main.dom.startButtonGroup.style.display='none'; + main.dom.levelChooseButtons.style.display = 'none'; + main.dom.startButtonGroup.style.display = 'none'; - if (main.mode!='play') return; + if (main.mode != 'play') return; // 无动画的开始游戏 if (core.flags.startUsingCanvas || core.isset(route)) { @@ -84,7 +84,7 @@ events.prototype._startGame_upload = function () { formData.append('type', 'people'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); formData.append('hard', core.encodeBase64(core.status.hard)); formData.append('hardCode', core.getFlag('hard', 0)); formData.append('base64', 1); @@ -141,7 +141,7 @@ events.prototype._gameOver_confirmUpload = function (ending, norank) { return; } core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () { - var username = main.isCompetition?"":prompt("请输入你的ID:", core.getCookie('id')||""); + var username = main.isCompetition ? "" : prompt("请输入你的ID:", core.getCookie('id') || ""); core.events._gameOver_doUpload(username, ending, norank); }, function () { if (main.isCompetition) @@ -160,9 +160,9 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { formData.append('type', 'score'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); formData.append('hard', core.encodeBase64(core.status.hard)); - formData.append('username', core.encodeBase64(username||"")); + formData.append('username', core.encodeBase64(username || "")); formData.append('ending', core.encodeBase64(ending)); formData.append('lv', core.status.hero.lv); formData.append('hp', Math.min(hp, Math.pow(2, 63))); @@ -172,9 +172,9 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { formData.append('money', core.status.hero.money); formData.append('experience', core.status.hero.experience); formData.append('steps', core.status.hero.steps); - formData.append('norank', norank||0); + formData.append('norank', norank || 0); formData.append('seed', core.getFlag('__seed__')); - formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); + formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime / 1000)); formData.append('route', core.encodeRoute(core.status.route)); formData.append('base64', 1); @@ -183,7 +183,7 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { else core.http("POST", "/games/upload.php", formData); - setTimeout(function() { + setTimeout(function () { core.events._gameOver_confirmDownload(ending); }, 200); } @@ -198,7 +198,7 @@ events.prototype._gameOver_confirmDownload = function (ending) { 'seed': core.getFlag('__seed__'), 'route': core.encodeRoute(core.status.route) } - core.download(core.firstData.name+"_"+core.formatDate2(new Date())+".h5route", JSON.stringify(obj)); + core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5route", JSON.stringify(obj)); core.events._gameOver_askRate(ending); }, function () { core.events._gameOver_askRate(ending); @@ -214,11 +214,11 @@ events.prototype._gameOver_askRate = function (ending) { core.ui.closePanel(); core.ui.drawConfirmBox("恭喜通关本塔,你想进行评分吗?", function () { if (core.platform.isPC) { - window.open("/score.php?name="+core.firstData.name+"&num=10", "_blank"); + window.open("/score.php?name=" + core.firstData.name + "&num=10", "_blank"); core.restart(); } else { - window.location.href = "/score.php?name="+core.firstData.name+"&num=10"; + window.location.href = "/score.php?name=" + core.firstData.name + "&num=10"; } }, function () { core.restart(); @@ -241,9 +241,9 @@ events.prototype.unregisterSystemEvent = function (type) { ////// 执行一个系统事件 ////// events.prototype.doSystemEvent = function (type, data, callback) { if (this.systemEvents[type]) this.systemEvents[type](data, callback); - else if (this["_sys_"+type]) this["_sys_"+type](data, callback); + else if (this["_sys_" + type]) this["_sys_" + type](data, callback); else { - main.log("未知的系统事件: "+type+"!"); + main.log("未知的系统事件: " + type + "!"); if (callback) callback(); } } @@ -263,7 +263,7 @@ events.prototype._trigger = function (x, y) { if (trigger == 'ski') core.status.isSkiing = true; // 转换楼层能否穿透 - if (trigger=='changeFloor' && !noPass && this._trigger_ignoreChangeFloor(block)) + if (trigger == 'changeFloor' && !noPass && this._trigger_ignoreChangeFloor(block)) return; core.status.automaticRoute.moveDirectly = false; this.doSystemEvent(trigger, block, function () { @@ -276,17 +276,17 @@ events.prototype._trigger = function (x, y) { events.prototype._trigger_ignoreChangeFloor = function (block) { var able = core.flags.ignoreChangeFloor; if (core.isset(block.event.data) && core.isset(block.event.data.ignoreChangeFloor)) - able=block.event.data.ignoreChangeFloor; + able = block.event.data.ignoreChangeFloor; if (able) { if (core.isReplaying()) { - if (core.status.replay.toReplay[0]=='no') { + if (core.status.replay.toReplay[0] == 'no') { core.status.replay.toReplay.shift(); core.status.route.push("no"); return true; } } else if (core.status.automaticRoute.autoHeroMove - || core.status.automaticRoute.autoStep0) floorId = core.floorIds[index-1]; - else floorId=core.status.floorId; + var index = core.floorIds.indexOf(core.status.floorId); + if (index > 0) floorId = core.floorIds[index - 1]; + else floorId = core.status.floorId; } else if (floorId == ':next') { - var index=core.floorIds.indexOf(core.status.floorId); - if (index0) + if (number > 0) core.setBlock(number, ex, ey); } } @@ -715,9 +715,9 @@ events.prototype.unregisterEvent = function (type) { events.prototype.doEvent = function (data, x, y, prefix) { var type = data.type; if (this.actions[type]) this.actions[type](data, x, y, prefix); - else if (this["_action_"+type]) this["_action_"+type](data, x, y, prefix); + else if (this["_action_" + type]) this["_action_" + type](data, x, y, prefix); else { - core.insertAction("未知的自定义事件: "+type+"!"); + core.insertAction("未知的自定义事件: " + type + "!"); core.doAction(); } } @@ -730,7 +730,7 @@ events.prototype.doEvents = function (list, x, y, callback) { } this.setEvents(list, x, y, callback); // 停止勇士 - core.waitHeroToStop(function() { + core.waitHeroToStop(function () { core.lockControl(); core.doAction(); }); @@ -747,7 +747,7 @@ events.prototype.setEvents = function (list, x, y, callback) { } ////// 执行当前自定义事件列表中的下一个事件 ////// -events.prototype.doAction = function() { +events.prototype.doAction = function () { // 清空boxAnimate和UI层 core.status.boxAnimateObjs = []; clearInterval(core.status.event.interval); @@ -757,7 +757,7 @@ events.prototype.doAction = function() { if (this._doAction_finishEvents()) return; // 当前点坐标和前缀 var x = core.status.event.data.x, y = core.status.event.data.y; - var prefix = [core.status.floorId||"f", core.isset(x)?x:"x", core.isset(y)?y:"y"].join("@"); + var prefix = [core.status.floorId || "f", core.isset(x) ? x : "x", core.isset(y) ? y : "y"].join("@"); var current = core.status.event.data.list[0]; if (this._popEvents(current, prefix)) return; // 当前要执行的事件 @@ -772,7 +772,7 @@ events.prototype.doAction = function() { events.prototype._doAction_finishEvents = function () { // 事件处理完毕 - if (core.status.event.data.list.length==0) { + if (core.status.event.data.list.length == 0) { var callback = core.status.event.data.callback; core.ui.closePanel(); if (core.isset(callback)) @@ -851,7 +851,7 @@ events.prototype.__action_getLoc = function (loc, x, y, prefix) { x = core.calValue(loc[0], prefix); y = core.calValue(loc[1], prefix); } - return [x,y]; + return [x, y]; } events.prototype.__action_getHeroLoc = function (loc, prefix) { @@ -897,17 +897,17 @@ events.prototype._action_comment = function (data, x, y, prefix) { events.prototype._action_setText = function (data, x, y, prefix) { ["position", "offset", "bold", "titlefont", "textfont", "time"].forEach(function (t) { - if (core.isset(data[t])) core.status.textAttribute[t]=data[t]; + if (core.isset(data[t])) core.status.textAttribute[t] = data[t]; }); ["background", "title", "text"].forEach(function (t) { - if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length>=3) { - if (data[t].length==3) data[t].push(1); - core.status.textAttribute[t]=data[t]; + if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length >= 3) { + if (data[t].length == 3) data[t].push(1); + core.status.textAttribute[t] = data[t]; } - if (t=='background' && core.isset(data[t])) { + if (t == 'background' && core.isset(data[t])) { var img = core.material.images.images[data[t]]; - if (core.isset(img) && img.width==192 && img.height==128) { - core.status.textAttribute[t]=data[t]; + if (core.isset(img) && img.width == 192 && img.height == 128) { + core.status.textAttribute[t] = data[t]; } } }); @@ -922,7 +922,7 @@ events.prototype._action_tip = function (data, x, y, prefix) { events.prototype._action_show = function (data, x, y, prefix) { data.loc = this.__action_getLoc2D(data.loc, x, y, prefix); - if (data.time>0 && !(data.floorId && data.floorId != core.status.floorId)) { + if (data.time > 0 && !(data.floorId && data.floorId != core.status.floorId)) { this.__action_doAsyncFunc(data.async, core.animateBlock, data.loc, 'show', data.time); } else { @@ -935,7 +935,7 @@ events.prototype._action_show = function (data, x, y, prefix) { events.prototype._action_hide = function (data, x, y, prefix) { data.loc = this.__action_getLoc2D(data.loc, x, y, prefix); - if (data.time>0 && !(data.floorId && data.floorId != core.status.floorId)) { + if (data.time > 0 && !(data.floorId && data.floorId != core.status.floorId)) { data.loc.forEach(function (t) { core.hideBlock(t[0], t[1], data.floorId); }); @@ -943,7 +943,7 @@ events.prototype._action_hide = function (data, x, y, prefix) { } else { data.loc.forEach(function (t) { - core.removeBlock(t[0],t[1],data.floorId) + core.removeBlock(t[0], t[1], data.floorId) }); core.doAction(); } @@ -1016,7 +1016,7 @@ events.prototype._action_jumpHero = function (data, x, y, prefix) { events.prototype._action_changeFloor = function (data, x, y, prefix) { var loc = this.__action_getHeroLoc(data.loc, prefix); var heroLoc = {x: loc[0], y: loc[1], direction: data.direction}; - core.changeFloor(data.floorId || core.status.floorId, null, heroLoc, data.time, function() { + core.changeFloor(data.floorId || core.status.floorId, null, heroLoc, data.time, function () { core.lockControl(); core.doAction(); }); @@ -1071,7 +1071,7 @@ events.prototype._action_setFg = function (data, x, y, prefix) { core.doAction(); } else { - core.setFg(data.color, data.time, function() { + core.setFg(data.color, data.time, function () { core.setFlag('__color__', data.color || null); core.doAction(); }); @@ -1113,7 +1113,7 @@ events.prototype._action_useItem = function (data, x, y, prefix) { core.useItem(data.id, true, core.doAction); } else { - core.drawTip("当前无法使用"+((core.material.items[data.id]||{}).name||"未知道具")); + core.drawTip("当前无法使用" + ((core.material.items[data.id] || {}).name || "未知道具")); core.doAction(); } } @@ -1163,7 +1163,7 @@ events.prototype._action_insert = function (data, x, y, prefix) { else { var loc = this.__action_getLoc(data.loc, x, y, prefix); var floorId = data.floorId || core.status.floorId; - var event = core.floors[floorId].events[loc[0]+","+loc[1]]; + var event = core.floors[floorId].events[loc[0] + "," + loc[1]]; if (core.isset(event)) { if (core.isset(event.data)) event = event.data; this.insertAction(event); @@ -1208,7 +1208,7 @@ events.prototype._action_stopSound = function (data, x, y, prefix) { } events.prototype._action_setVolume = function (data, x, y, prefix) { - data.value = core.clamp(parseInt(data.value)/100, 0, 1); + data.value = core.clamp(parseInt(data.value) / 100, 0, 1); core.setFlag("__volume__", data.value); this.__action_doAsyncFunc(data.async, this.setVolume, data.value, data.time || 0); } @@ -1251,7 +1251,7 @@ events.prototype._action_setHeroIcon = function (data, x, y, prefix) { events.prototype._action_input = function (data, x, y, prefix) { var value = this.__action_getInput(data.text, false); if (value == null) return; - value = Math.abs(parseInt(value)||0); + value = Math.abs(parseInt(value) || 0); core.status.route.push("input:" + value); core.setFlag("input", value); core.doAction(); @@ -1266,19 +1266,19 @@ events.prototype._action_input2 = function (data, x, y, prefix) { } events.prototype.__action_getInput = function (hint, isText) { - var value, prefix = isText?"input2:":"input:"; + var value, prefix = isText ? "input2:" : "input:"; if (core.isReplaying()) { var action = core.status.replay.toReplay.shift(); try { - if (action.indexOf(prefix)!=0) - throw new Error("录像文件出错!当前需要一个 "+prefix+" 项,实际为 "+action); + if (action.indexOf(prefix) != 0) + throw new Error("录像文件出错!当前需要一个 " + prefix + " 项,实际为 " + action); if (isText) value = core.decodeBase64(action.substring(7)); else value = parseInt(action.substring(6)); } catch (e) { main.log(e); core.stopReplay(); - core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type":"exit"}]); + core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type": "exit"}]); core.doAction(); return null; } @@ -1286,7 +1286,7 @@ events.prototype.__action_getInput = function (hint, isText) { else { core.interval.onDownInterval = 'tmp'; value = prompt(core.replaceText(hint)); - if (!core.isset(value)) value=""; + if (!core.isset(value)) value = ""; } return value; } @@ -1316,18 +1316,18 @@ events.prototype._action_choices = function (data, x, y, prefix) { var action = core.status.replay.toReplay.shift(), index; // --- 忽略可能的turn事件 if (action == 'turn') action = core.status.replay.toReplay.shift(); - if (action.indexOf("choices:")==0 && ((index=parseInt(action.substring(8)))>=0) && index= 0) && index < data.choices.length) { + core.status.event.selection = index; setTimeout(function () { - core.status.route.push("choices:"+index); + core.status.route.push("choices:" + index); core.insertAction(data.choices[index].action); core.doAction(); }, 750 / Math.max(1, core.status.replay.speed)) } else { - main.log("录像文件出错!当前需要一个 choices: 项,实际为 "+action); + main.log("录像文件出错!当前需要一个 choices: 项,实际为 " + action); core.stopReplay(); - core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type":"exit"}]); + core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type": "exit"}]); core.doAction(); return; } @@ -1370,8 +1370,8 @@ events.prototype._action_lose = function (data, x, y, prefix) { events.prototype._action_function = function (data, x, y, prefix) { var func = data["function"]; try { - if (typeof func == "string" && func.indexOf("function")==0) { - eval('('+func+')()'); + if (typeof func == "string" && func.indexOf("function") == 0) { + eval('(' + func + ')()'); } } catch (e) { main.log(e); @@ -1406,24 +1406,24 @@ events.prototype._action_vibrate = function (data, x, y, prefix) { } events.prototype._action_sleep = function (data, x, y, prefix) { - core.timeout.sleepTimeout = setTimeout(function() { + core.timeout.sleepTimeout = setTimeout(function () { core.timeout.sleepTimeout = null; core.doAction(); - }, core.isReplaying()?Math.min(data.time, 20):data.time); + }, core.isReplaying() ? Math.min(data.time, 20) : data.time); } events.prototype._action_wait = function (data, x, y, prefix) { if (core.isReplaying()) { var code = core.status.replay.toReplay.shift(); - if (code.indexOf("input:")==0) { + if (code.indexOf("input:") == 0) { var value = parseInt(code.substring(6)); - core.status.route.push("input:"+value); + core.status.route.push("input:" + value); this.__action_wait_getValue(value); } else { - main.log("录像文件出错!当前需要一个 input: 项,实际为 "+code); + main.log("录像文件出错!当前需要一个 input: 项,实际为 " + code); core.stopReplay(); - core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type":"exit"}]); + core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type": "exit"}]); } core.doAction(); return; @@ -1515,7 +1515,7 @@ events.prototype._action_exit = function (data, x, y, prefix) { events.prototype.follow = function (name) { core.status.hero.followers = core.status.hero.followers || []; if (core.isset(core.material.images.images[name]) - && core.material.images.images[name].width==128) { + && core.material.images.images[name].width == 128) { core.status.hero.followers.push({"img": name}); core.control.gatherFollowers(); core.clearMap('hero'); @@ -1594,8 +1594,8 @@ events.prototype._setValue_setFlag = function (name, value) { } events.prototype._setValue_setSwitch = function (name, value, prefix) { - if (name.indexOf("switch:") !==0 ) return; - core.setFlag((prefix||"f@x@y")+"@"+data.name.substring(7), value); + if (name.indexOf("switch:") !== 0) return; + core.setFlag((prefix || "f@x@y") + "@" + data.name.substring(7), value); } ////// 数值增减 ////// @@ -1613,11 +1613,11 @@ events.prototype.setFloorInfo = function (name, value, floorId, prefix) { ////// 设置全塔属性 ////// events.prototype.setGlobalAttribute = function (name, value) { if (typeof value == 'string') { - if ((value.charAt(0)=='"' && value.charAt(value.length-1)=='"') - || (value.charAt(0)=="'" && value.charAt(value.length-1)=="'")) - value = value.substring(1, value.length-1); + if ((value.charAt(0) == '"' && value.charAt(value.length - 1) == '"') + || (value.charAt(0) == "'" && value.charAt(value.length - 1) == "'")) + value = value.substring(1, value.length - 1); // --- 检查 [] - if (value.charAt(0) == '[' && value.charAt(value.length-1)==']') + if (value.charAt(0) == '[' && value.charAt(value.length - 1) == ']') value = eval(value); } core.status.globalAttribute[name] = value; @@ -1647,7 +1647,7 @@ events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, ti } var zIndex = code + 100; time = time || 0; - var name = "image"+ zIndex; + var name = "image" + zIndex; var ctx = core.createCanvas(name, x, y, image.width * dw, image.height * dh, zIndex); ctx.drawImage(image, 0, 0, image.width * dw, image.height * dh); if (time == 0) { @@ -1678,7 +1678,7 @@ events.prototype.hideImage = function (code, time, callback) { events.prototype.moveImage = function (code, to, opacityVal, time, callback) { time = time || 1000; to = to || []; - var name = "image"+ (code+100); + var name = "image" + (code + 100); if (!core.dymCanvas[name]) { if (callback) callback(); return; @@ -1699,16 +1699,16 @@ events.prototype.moveImage = function (code, to, opacityVal, time, callback) { }, callback) } -events.prototype._moveImage_moving = function(name, moveInfo, callback) { +events.prototype._moveImage_moving = function (name, moveInfo, callback) { var per_time = 10, step = 0, steps = parseInt(moveInfo.time / 10); var fromX = moveInfo.fromX, fromY = moveInfo.fromY, toX = moveInfo.toX, toY = moveInfo.toY, opacity = moveInfo.opacity, toOpacity = moveInfo.toOpacity; var currX = fromX, currY = fromY, currOpacity = opacity; var animate = setInterval(function () { step++; - currOpacity = opacity + (toOpacity-opacity)*step/steps; - currX = parseInt(fromX + (toX-fromX)*step/steps); - currY = parseInt(fromY + (toY-fromY)*step/steps); + currOpacity = opacity + (toOpacity - opacity) * step / steps; + currX = parseInt(fromX + (toX - fromX) * step / steps); + currY = parseInt(fromY + (toY - fromY) * step / steps); core.setOpacity(name, currOpacity); core.relocateCanvas(name, currX, currY); if (step == steps) { @@ -1728,7 +1728,7 @@ events.prototype.setVolume = function (value, time, callback) { if (core.musicStatus.playingBgm) core.material.bgms[core.musicStatus.playingBgm].volume = value; } - if (!core.isset(time) || time<100) { + if (!core.isset(time) || time < 100) { set(value); if (callback) callback(); return; @@ -1737,8 +1737,8 @@ events.prototype.setVolume = function (value, time, callback) { var per_time = 10, step = 0, steps = parseInt(time / per_time); var fade = setInterval(function () { step++; - set(currVolume+(value-currVolume)*step/steps); - if (step>=steps) { + set(currVolume + (value - currVolume) * step / steps); + if (step >= steps) { delete core.animateFrame.asyncId[fade]; clearInterval(fade); if (callback) callback(); @@ -1748,19 +1748,19 @@ events.prototype.setVolume = function (value, time, callback) { } ////// 画面震动 ////// -events.prototype.vibrate = function(time, callback) { +events.prototype.vibrate = function (time, callback) { if (core.isReplaying()) { if (callback) callback(); return; } - if (!core.isset(time) || time<1000) time=1000; + if (!core.isset(time) || time < 1000) time = 1000; // --- 将time调整为500的倍数(上整),不然会出错 time = Math.ceil(time / 500) * 500; - var shakeInfo = { duration: time * 3 / 50, speed: 5, power: 5, direction: 1, shake: 0 }; - var animate=setInterval(function(){ + var shakeInfo = {duration: time * 3 / 50, speed: 5, power: 5, direction: 1, shake: 0}; + var animate = setInterval(function () { core.events._vibrate_update(shakeInfo); core.control.addGameCanvasTranslate(shakeInfo.shake, 0); - if(shakeInfo.duration===0) { + if (shakeInfo.duration === 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); if (callback) callback(); @@ -1771,33 +1771,33 @@ events.prototype.vibrate = function(time, callback) { } events.prototype._vibrate_update = function (shakeInfo) { - if(shakeInfo.duration >= 1 || shakeInfo.shake != 0){ + if (shakeInfo.duration >= 1 || shakeInfo.shake != 0) { var delta = (shakeInfo.power * shakeInfo.speed * shakeInfo.direction) / 10.0; - if(shakeInfo.duration <= 1 && shakeInfo.shake * (shakeInfo.shake + delta) < 0){ + if (shakeInfo.duration <= 1 && shakeInfo.shake * (shakeInfo.shake + delta) < 0) { shakeInfo.shake = 0; - }else{ + } else { shakeInfo.shake += delta; } - if(shakeInfo.shake > shakeInfo.power * 2){ + if (shakeInfo.shake > shakeInfo.power * 2) { shakeInfo.direction = -1; } - if(shakeInfo.shake < - shakeInfo.power * 2){ + if (shakeInfo.shake < -shakeInfo.power * 2) { shakeInfo.direction = 1; } - if(shakeInfo.duration >= 1){ + if (shakeInfo.duration >= 1) { shakeInfo.duration -= 1 } } } ////// 打开一个全局商店 ////// -events.prototype.openShop = function(shopId, needVisited) { +events.prototype.openShop = function (shopId, needVisited) { var shop = core.status.shops[shopId]; shop.times = shop.times || 0; if (shop.commonTimes) shop.times = core.getFlag('commonTimes', 0); if (needVisited && !shop.visited) { if (!core.flags.enableDisabledShop) { - if (shop.times==0) core.drawTip("该商店尚未开启"); + if (shop.times == 0) core.drawTip("该商店尚未开启"); else core.drawTip("该商店已失效"); return; } @@ -1817,9 +1817,9 @@ events.prototype._useShop = function (shop, index) { return false; } var use = shop.use, choice = shop.choices[index]; - var times = shop.times, need = core.calValue(choice.need||shop.need, null, null, times); + var times = shop.times, need = core.calValue(choice.need || shop.need, null, null, times); if (need > core.getStatus(use)) { - core.drawTip("你的"+(use=='money'?"金币":"经验")+"不足"); + core.drawTip("你的" + (use == 'money' ? "金币" : "经验") + "不足"); return false; } core.status.event.selection = index; @@ -1834,8 +1834,8 @@ events.prototype._useShop = function (shop, index) { } events.prototype._exitShop = function () { - if (core.status.event.data.actions.length>0) { - core.status.route.push("shop:"+core.status.event.data.id+":"+core.status.event.data.actions.join("")); + if (core.status.event.data.actions.length > 0) { + core.status.route.push("shop:" + core.status.event.data.id + ":" + core.status.event.data.actions.join("")); } core.status.event.data.actions = []; core.status.boxAnimateObjs = []; @@ -1851,7 +1851,7 @@ events.prototype.disableQuickShop = function (shopId) { } ////// 能否使用快捷商店 ////// -events.prototype.canUseQuickShop = function(shopId) { +events.prototype.canUseQuickShop = function (shopId) { return this.eventdata.canUseQuickShop(shopId); } @@ -1861,7 +1861,7 @@ events.prototype.setHeroIcon = function (name, noDraw) { if (!img || img.width != 128) return; core.setFlag("heroIcon", name); core.material.images.hero.onload = function () { - core.material.icons.hero.height = img.height/4; + core.material.icons.hero.height = img.height / 4; core.control.updateHeroIcon(name); if (!noDraw) core.drawHero(); } @@ -1876,35 +1876,35 @@ events.prototype.checkLvUp = function () { if (next == null) break; actions = actions.concat(next); } - if (actions.length>0) core.insertAction(actions); + if (actions.length > 0) core.insertAction(actions); } events.prototype._checkLvUp_check = function () { if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) - || core.status.hero.lv>=core.firstData.levelUp.length) return null; + || core.status.hero.lv >= core.firstData.levelUp.length) return null; // 计算下一个所需要的数值 - var next = (core.firstData.levelUp[core.status.hero.lv]||{}); + var next = (core.firstData.levelUp[core.status.hero.lv] || {}); var need = core.calValue(next.need); if (!core.isset(need)) return null; - if (core.status.hero.experience>=need) { + if (core.status.hero.experience >= need) { // 升级 core.status.hero.lv++; if (next.clear) core.status.hero.experience -= need; - return next.action||[]; + return next.action || []; } return null; } ////// 尝试使用道具 ////// -events.prototype.tryUseItem = function(itemId) { +events.prototype.tryUseItem = function (itemId) { core.ui.closePanel(); - if (itemId=='book') return core.openBook(false); - if (itemId=='fly') return core.useFly(false); - if (itemId=='centerFly') return core.ui.drawCenterFly(); + if (itemId == 'book') return core.openBook(false); + if (itemId == 'fly') return core.useFly(false); + if (itemId == 'centerFly') return core.ui.drawCenterFly(); - if (core.canUseItem(itemId))core.useItem(itemId); - else core.drawTip("当前无法使用"+core.material.items[itemId].name); + if (core.canUseItem(itemId)) core.useItem(itemId); + else core.drawTip("当前无法使用" + core.material.items[itemId].name); } ////// 使用炸弹/圣锤后的事件 ////// @@ -1929,9 +1929,9 @@ events.prototype.uploadCurrent = function (username) { formData.append('type', 'score'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC?"PC":core.platform.isAndroid?"Android":core.platform.isIOS?"iOS":""); + formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); formData.append('hard', core.encodeBase64(core.status.hard)); - formData.append('username', core.encodeBase64(username||"current")); + formData.append('username', core.encodeBase64(username || "current")); formData.append('lv', core.status.hero.lv); formData.append('hp', Math.min(core.status.hero.hp, Math.pow(2, 63))); formData.append('atk', core.status.hero.atk); @@ -1941,7 +1941,7 @@ events.prototype.uploadCurrent = function (username) { formData.append('experience', core.status.hero.experience); formData.append('steps', core.status.hero.steps); formData.append('seed', core.getFlag('__seed__')); - formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime/1000)); + formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime / 1000)); formData.append('route', core.encodeRoute(core.status.route)); formData.append('deler', 'current'); formData.append('base64', 1); diff --git a/libs/icons.js b/libs/icons.js index db33f828..12b78828 100644 --- a/libs/icons.js +++ b/libs/icons.js @@ -26,14 +26,14 @@ icons.prototype.getClsFromId = function (id) { } icons.prototype._getAnimateFrames = function (cls, useOriginValue) { - if (cls=='enemys' || cls=='npcs') { + if (cls == 'enemys' || cls == 'npcs') { return 2; } if (cls == 'animates' || cls == 'enemy48') { return 4; } if (cls == 'npc48') { - return useOriginValue? 4 : 1; + return useOriginValue ? 4 : 1; } return 1; } @@ -55,9 +55,9 @@ icons.prototype.getTilesetOffset = function (id) { for (var i in core.tilesets) { var imgName = core.tilesets[i]; var img = core.material.images.tilesets[imgName]; - var width = Math.floor(img.width/32), height = Math.floor(img.height/32); - if (id>=startOffset && id= startOffset && id < startOffset + width * height) { + var x = (id - startOffset) % width, y = parseInt((id - startOffset) / width); return {"image": imgName, "x": x, "y": y}; } startOffset += this.tilesetStartOffset; diff --git a/libs/items.js b/libs/items.js index 708acd6a..ce3ee753 100644 --- a/libs/items.js +++ b/libs/items.js @@ -22,7 +22,7 @@ items.prototype.getItems = function () { } ////// “即捡即用类”道具的使用效果 ////// -items.prototype.getItemEffect = function(itemId, itemNum) { +items.prototype.getItemEffect = function (itemId, itemNum) { var itemCls = core.material.items[itemId].cls; // 消耗品 if (itemCls === 'items') { @@ -44,14 +44,14 @@ items.prototype.getItemEffect = function(itemId, itemNum) { } ////// “即捡即用类”道具的文字提示 ////// -items.prototype.getItemEffectTip = function(itemId) { +items.prototype.getItemEffectTip = function (itemId) { var itemCls = core.material.items[itemId].cls; // 消耗品 if (itemCls === 'items') { var ratio = parseInt(core.status.thisMap.item_ratio) || 1; if (itemId in this.itemEffectTip) { try { - return eval(this.itemEffectTip[itemId])||""; + return eval(this.itemEffectTip[itemId]) || ""; } catch (e) { main.log(e); return ""; @@ -72,7 +72,7 @@ items.prototype.useItem = function (itemId, noRoute, callback) { // 执行完毕 this._afterUseItem(itemId); // 记录路线 - if (!noRoute) core.status.route.push("item:"+itemId); + if (!noRoute) core.status.route.push("item:" + itemId); if (core.isset(callback)) callback(); } @@ -91,9 +91,9 @@ items.prototype._useItemEffect = function (itemId) { items.prototype._afterUseItem = function (itemId) { // 道具使用完毕:删除 var itemCls = core.material.items[itemId].cls; - if (itemCls=='tools') + if (itemCls == 'tools') core.status.hero.items[itemCls][itemId]--; - if (core.status.hero.items[itemCls][itemId]<=0) + if (core.status.hero.items[itemCls][itemId] <= 0) delete core.status.hero.items[itemCls][itemId]; if (!core.status.event.id) { @@ -130,8 +130,8 @@ items.prototype.itemCount = function (itemId) { if (!core.isset(core.status.hero)) return 0; if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0; var itemCls = core.material.items[itemId].cls; - if (itemCls=="items") return 0; - return core.status.hero.items[itemCls][itemId]||0; + if (itemCls == "items") return 0; + return core.status.hero.items[itemCls][itemId] || 0; } ////// 是否存在某个物品 ////// @@ -144,9 +144,9 @@ items.prototype.hasEquip = function (itemId) { if (!core.isset(core.status.hero)) return null; if (!core.isset(itemId)) return null; - if (!core.isset((core.material.items[itemId]||{}).equip)) return null; + if (!core.isset((core.material.items[itemId] || {}).equip)) return null; - for (var i in core.status.hero.equipment||[]) + for (var i in core.status.hero.equipment || []) if (core.status.hero.equipment[i] == itemId) return true; return false @@ -155,7 +155,7 @@ items.prototype.hasEquip = function (itemId) { ////// 获得某个装备类型的当前装备 ////// items.prototype.getEquip = function (equipType) { if (!core.isset(core.status.hero)) return null; - return (core.status.hero.equipment||[])[equipType]||null; + return (core.status.hero.equipment || [])[equipType] || null; } ////// 设置某个物品的个数 ////// @@ -169,7 +169,7 @@ items.prototype.setItem = function (itemId, itemNum) { } core.status.hero.items[itemCls][itemId] = itemNum; if (core.status.hero.items[itemCls][itemId] <= 0) { - if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; else core.status.hero.items[itemCls][itemId] = 0; } core.updateStatusBar(); @@ -181,9 +181,9 @@ items.prototype.removeItem = function (itemId, itemNum) { if (!core.isset(itemNum)) itemNum = 1; if (!core.hasItem(itemId)) return false; var itemCls = core.material.items[itemId].cls; - core.status.hero.items[itemCls][itemId]-=itemNum; + core.status.hero.items[itemCls][itemId] -= itemNum; if (core.status.hero.items[itemCls][itemId] <= 0) { - if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; else core.status.hero.items[itemCls][itemId] = 0; } core.updateStatusBar(); @@ -206,11 +206,11 @@ items.prototype.addItem = function (itemId, itemNum) { } core.status.hero.items[itemCls][itemId] += itemNum; if (core.status.hero.items[itemCls][itemId] <= 0) { - if (itemCls!='keys') delete core.status.hero.items[itemCls][itemId]; + if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; else core.status.hero.items[itemCls][itemId] = 0; } // 永久道具只能有一个 - if (itemCls == 'constants' && core.status.hero.items[itemCls][itemId]>1) + if (itemCls == 'constants' && core.status.hero.items[itemCls][itemId] > 1) core.status.hero.items[itemCls][itemId] = 1; core.updateStatusBar(); } @@ -227,7 +227,7 @@ items.prototype.getEquipTypeById = function (equipId) { items.prototype.getEquipTypeByName = function (name) { var names = core.status.globalAttribute.equipName; for (var i = 0; i < names.length; ++i) { - if (names[i] === name && !core.isset((core.status.hero.equipment||[])[i])) { + if (names[i] === name && !core.isset((core.status.hero.equipment || [])[i])) { return i; } } @@ -237,7 +237,7 @@ items.prototype.getEquipTypeByName = function (name) { // 当前能否撞上某装备 items.prototype.canEquip = function (equipId, hint) { // 装备是否合法 - var equip = core.material.items[equipId]||{}; + var equip = core.material.items[equipId] || {}; if (!core.isset(equip.equip)) { if (hint) core.drawTip("不合法的装备!"); return false; @@ -245,16 +245,16 @@ items.prototype.canEquip = function (equipId, hint) { // 是否拥有该装备 if (!core.hasItem(equipId) && !core.hasEquip(equipId)) { - if (hint) core.drawTip("你当前没有"+equip.name+",无法换装"); + if (hint) core.drawTip("你当前没有" + equip.name + ",无法换装"); return false; } // 可装备条件 var condition = this.equipCondition[equipId]; - if (core.isset(condition) && condition.length>0) { + if (core.isset(condition) && condition.length > 0) { try { if (!eval(condition)) { - if (hint) core.drawTip("当前不可换上"+equip.name); + if (hint) core.drawTip("当前不可换上" + equip.name); return false; } } @@ -278,7 +278,7 @@ items.prototype.loadEquip = function (equipId, callback) { var loadEquip = core.material.items[equipId] || {}; var type = this.getEquipTypeById(equipId); if (type < 0) { - core.drawTip("当前没有"+loadEquip.equip.type+"的空位!"); + core.drawTip("当前没有" + loadEquip.equip.type + "的空位!"); if (core.isset(callback)) callback(); return; } @@ -304,17 +304,17 @@ items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) var compareAtk = 0, compareDef = 0, compareMdef = 0; if (core.isset(compareEquipId)) { var compareEquip = core.material.items[compareEquipId]; - compareAtk += (compareEquip.equip||{}).atk || 0; - compareDef += (compareEquip.equip||{}).def || 0; - compareMdef += (compareEquip.equip||{}).mdef || 0; + compareAtk += (compareEquip.equip || {}).atk || 0; + compareDef += (compareEquip.equip || {}).def || 0; + compareMdef += (compareEquip.equip || {}).mdef || 0; } if (core.isset(beComparedEquipId)) { var beComparedEquip = core.material.items[beComparedEquipId]; - compareAtk -= (beComparedEquip.equip||{}).atk || 0; - compareDef -= (beComparedEquip.equip||{}).def || 0; - compareMdef -= (beComparedEquip.equip||{}).mdef || 0; + compareAtk -= (beComparedEquip.equip || {}).atk || 0; + compareDef -= (beComparedEquip.equip || {}).def || 0; + compareMdef -= (beComparedEquip.equip || {}).mdef || 0; } - return {"atk":compareAtk,"def":compareDef,"mdef":compareMdef}; + return {"atk": compareAtk, "def": compareDef, "mdef": compareMdef}; } ////// 实际换装的效果 ////// @@ -324,7 +324,7 @@ items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentag if (isPercentage) { for (var v in result) - core.addFlag('__'+v+'_buff__', result[v]/100); + core.addFlag('__' + v + '_buff__', result[v] / 100); } else { for (var v in result) @@ -350,16 +350,16 @@ items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { core.playSound('equip.mp3'); // --- 实际换装 - this._loadEquipEffect(loadId, unloadId, loadPercentage==null?unloadPercentage:loadPercentage); + this._loadEquipEffect(loadId, unloadId, loadPercentage == null ? unloadPercentage : loadPercentage); // --- 加减 if (loadId) core.removeItem(loadId); if (unloadId) core.addItem(unloadId); - core.status.hero.equipment[type] = loadId||null; + core.status.hero.equipment[type] = loadId || null; // --- 提示 - if (loadId) core.drawTip("已装备上"+loadEquip.name, core.material.icons.items[loadId]); - else if (unloadId) core.drawTip("已卸下"+unloadEquip.name, core.material.icons.items[unloadId]); + if (loadId) core.drawTip("已装备上" + loadEquip.name, core.material.icons.items[loadId]); + else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, core.material.icons.items[unloadId]); if (core.isset(callback)) callback(); } @@ -370,38 +370,38 @@ items.prototype.quickSaveEquip = function (index) { var saveEquips = core.getFlag("saveEquips", []); saveEquips[index] = core.clone(core.status.hero.equipment); core.setFlag("saveEquips", saveEquips); - core.drawTip("已保存"+index+"号套装"); + core.drawTip("已保存" + index + "号套装"); } ////// 读取装备 ////// items.prototype.quickLoadEquip = function (index) { var current = core.getFlag("saveEquips", [])[index]; if (!core.isset(current)) { - core.drawTip(index+"号套装不存在"); + core.drawTip(index + "号套装不存在"); return; } // 检查所有的装备 var equipSize = core.status.globalAttribute.equipName.length; - for (var i=0;i 32*32*3000) { - console.warn("警告!"+imgName+"上的图块素材个数大于3000!"); + if (img.width * img.height > 32 * 32 * 3000) { + console.warn("警告!" + imgName + "上的图块素材个数大于3000!"); } } callback(); @@ -99,12 +99,12 @@ loader.prototype._loadTilesets = function (callback) { } loader.prototype.loadImages = function (names, toSave, callback) { - if (!core.isset(names) || names.length==0) { + if (!core.isset(names) || names.length == 0) { if (core.isset(callback)) callback(); return; } var items = 0; - for (var i=0;i=0) { + if (index >= 0) { core.musicStatus.cachedBgms.splice(index, 1); } else { @@ -267,7 +267,9 @@ loader.prototype._preloadBgm = function (bgm) { loader.prototype.freeBgm = function (name) { if (!core.isset(core.material.bgms[name])) return; // 从cachedBgms中删除 - core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) {return t!=name; }); + core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) { + return t != name; + }); // 清掉缓存 core.material.bgms[name].removeAttribute("src"); core.material.bgms[name].load(); diff --git a/libs/utils.js b/libs/utils.js index 969cb745..9cb77897 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -18,7 +18,7 @@ function utils() { utils.prototype._init = function () { // 定义Object.assign if (typeof Object.assign != "function") { - Object.assign = function(target, varArgs) { // .length of function is 2 + Object.assign = function (target, varArgs) { // .length of function is 2 if (target == null) { // TypeError if undefined or null throw new TypeError('Cannot convert undefined or null to object'); } @@ -41,7 +41,7 @@ utils.prototype._init = function () { }; } if (typeof String.prototype.endsWith != "function") { - String.prototype.endsWith = function(search, this_len) { + String.prototype.endsWith = function (search, this_len) { if (this_len === undefined || this_len > this.length) { this_len = this.length; } @@ -63,10 +63,10 @@ utils.prototype.replaceText = function (text, need, times) { utils.prototype.calValue = function (value, prefix, need, times) { if (!core.isset(value)) return value; if (typeof value === 'string') { - value=value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')"); - value=value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')"); - value=value.replace(/flag:([\w\d_]+)/g, "core.getFlag('$1', 0)"); - value=value.replace(/switch:([\w\d_]+)/g, "core.getFlag('"+(prefix||"global")+"@$1', 0)"); + value = value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')"); + value = value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')"); + value = value.replace(/flag:([\w\d_]+)/g, "core.getFlag('$1', 0)"); + value = value.replace(/switch:([\w\d_]+)/g, "core.getFlag('" + (prefix || "global") + "@$1', 0)"); return eval(value); } if (value instanceof Function) { @@ -76,27 +76,27 @@ utils.prototype.calValue = function (value, prefix, need, times) { } ////// 字符串自动换行的分割 ////// -utils.prototype.splitLines = function(canvas, text, maxLength, font) { +utils.prototype.splitLines = function (canvas, text, maxLength, font) { if (core.isset(font)) core.setFont(canvas, font); var contents = []; var last = 0; - for (var i=0;imaxLength) { + if (core.isset(maxLength) && width > maxLength) { contents.push(text.substring(last, i)); - last=i; + last = i; } } } @@ -105,7 +105,7 @@ utils.prototype.splitLines = function(canvas, text, maxLength, font) { } ////// 向某个数组前插入另一个数组或元素 ////// -utils.prototype.unshift = function (a,b) { +utils.prototype.unshift = function (a, b) { if (!(a instanceof Array) || !core.isset(b)) return; if (b instanceof Array) { core.clone(b).reverse().forEach(function (e) { @@ -117,7 +117,7 @@ utils.prototype.unshift = function (a,b) { } ////// 向某个数组后插入另一个数组或元素 ////// -utils.prototype.push = function (a,b) { +utils.prototype.push = function (a, b) { if (!(a instanceof Array) || !core.isset(b)) return; if (b instanceof Array) { core.clone(b).forEach(function (e) { @@ -129,21 +129,21 @@ utils.prototype.push = function (a,b) { } ////// 设置本地存储 ////// -utils.prototype.setLocalStorage = function(key, value) { +utils.prototype.setLocalStorage = function (key, value) { try { if (!core.isset(value)) { this.removeLocalStorage(key); return; } - var str = JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function(chr) { + var str = JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function (chr) { return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) }); var compressed = lzw_encode(str); // test if we can save to localStorage localStorage.setItem("__tmp__", compressed); - if (lzw_decode(localStorage.getItem("__tmp__"))==str) { + if (lzw_decode(localStorage.getItem("__tmp__")) == str) { localStorage.setItem(core.firstData.name + "_" + key, compressed); } else { @@ -169,29 +169,33 @@ utils.prototype.decompress = function (value) { if (core.isset(output) && output.length > 0) return JSON.parse(output); } - catch (e) {} + catch (e) { + } try { var output = LZString.decompress(value); if (core.isset(output) && output.length > 0) return JSON.parse(output); } - catch (e) {} + catch (e) { + } try { return JSON.parse(value); } - catch (e) {main.log(e);} + catch (e) { + main.log(e); + } return null; } ////// 获得本地存储 ////// -utils.prototype.getLocalStorage = function(key, defaultValue) { - var res = this.decompress(localStorage.getItem(core.firstData.name+"_"+key)); - return res==null?defaultValue:res; +utils.prototype.getLocalStorage = function (key, defaultValue) { + var res = this.decompress(localStorage.getItem(core.firstData.name + "_" + key)); + return res == null ? defaultValue : res; } ////// 移除本地存储 ////// utils.prototype.removeLocalStorage = function (key) { - localStorage.removeItem(core.firstData.name+"_"+key); + localStorage.removeItem(core.firstData.name + "_" + key); if (key == 'autoSave') delete core.saves.ids[0]; else if (/^save\d+$/.test(key)) delete core.saves.ids[parseInt(key.substring(4))]; } @@ -214,10 +218,10 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal } // Save to localforage - var compressed = lzw_encode(JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function(chr) { + var compressed = lzw_encode(JSON.stringify(value).replace(/[\u007F-\uFFFF]/g, function (chr) { return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) })); - localforage.setItem(core.firstData.name+"_"+key, compressed, function (err) { + localforage.setItem(core.firstData.name + "_" + key, compressed, function (err) { if (core.isset(err)) { if (core.isset(errorCallback)) errorCallback(err); } @@ -232,14 +236,14 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal utils.prototype.getLocalForage = function (key, defaultValue, successCallback, errorCallback) { if (!core.platform.useLocalForage) { - var value=this.getLocalStorage(key, defaultValue); + var value = this.getLocalStorage(key, defaultValue); if (core.isset(successCallback)) { successCallback(value); } return; } - localforage.getItem(core.firstData.name+"_"+key, function (err, value) { + localforage.getItem(core.firstData.name + "_" + key, function (err, value) { if (core.isset(err)) { if (core.isset(errorCallback)) errorCallback(err); } @@ -247,7 +251,7 @@ utils.prototype.getLocalForage = function (key, defaultValue, successCallback, e if (!core.isset(successCallback)) return; if (core.isset(value)) { var res = core.utils.decompress(value); - successCallback(res==null?defaultValue:res); + successCallback(res == null ? defaultValue : res); return; } successCallback(defaultValue); @@ -263,7 +267,7 @@ utils.prototype.removeLocalForage = function (key, successCallback, errorCallbac return; } - localforage.removeItem(core.firstData.name+"_"+key, function (err) { + localforage.removeItem(core.firstData.name + "_" + key, function (err) { if (core.isset(err)) { if (core.isset(errorCallback)) errorCallback(err); } @@ -280,13 +284,13 @@ utils.prototype.clone = function (data) { if (!core.isset(data)) return data; // date if (data instanceof Date) { - var copy=new Date(); + var copy = new Date(); copy.setTime(data.getTime()); return copy; } // array if (data instanceof Array) { - var copy=[]; + var copy = []; // for (var i=0;i=one.val) { - var v = x/one.val; - return c + v.toFixed(Math.max(0, Math.floor(3-Math.log10(v+1)))) + one.c; + if (x >= one.val) { + var v = x / one.val; + return c + v.toFixed(Math.max(0, Math.floor(3 - Math.log10(v + 1)))) + one.c; } } else { - if (x>=10*one.val) { - var v = x/one.val; - return c + v.toFixed(Math.max(0, Math.floor(4-Math.log10(v+1)))) + one.c; + if (x >= 10 * one.val) { + var v = x / one.val; + return c + v.toFixed(Math.max(0, Math.floor(4 - Math.log10(v + 1)))) + one.c; } } } - return c+x; + return c + x; } ////// 数组转RGB ////// utils.prototype.arrayToRGB = function (color) { - var nowR = this.clamp(parseInt(color[0]),0,255), nowG = this.clamp(parseInt(color[1]),0,255), - nowB = this.clamp(parseInt(color[2]),0,255); - return "#"+((1<<24)+(nowR<<16)+(nowG<<8)+nowB).toString(16).slice(1); + var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255), + nowB = this.clamp(parseInt(color[2]), 0, 255); + return "#" + ((1 << 24) + (nowR << 16) + (nowG << 8) + nowB).toString(16).slice(1); } utils.prototype.arrayToRGBA = function (color) { - if (!this.isset(color[3])) color[3]=1; - var nowR = this.clamp(parseInt(color[0]),0,255), nowG = this.clamp(parseInt(color[1]),0,255), - nowB = this.clamp(parseInt(color[2]),0,255), nowA = this.clamp(parseFloat(color[3]),0,1); - return "rgba("+nowR+","+nowG+","+nowB+","+nowA+")"; + if (!this.isset(color[3])) color[3] = 1; + var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255), + nowB = this.clamp(parseInt(color[2]), 0, 255), nowA = this.clamp(parseFloat(color[3]), 0, 1); + return "rgba(" + nowR + "," + nowG + "," + nowB + "," + nowA + ")"; } ////// 加密路线 ////// utils.prototype.encodeRoute = function (route) { - var ans="", lastMove = "", cnt=0; + var ans = "", lastMove = "", cnt = 0; route.forEach(function (t) { - if (t=='up' || t=='down' || t=='left' || t=='right') { - if (t!=lastMove && cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; - cnt=0; + if (t == 'up' || t == 'down' || t == 'left' || t == 'right') { + if (t != lastMove && cnt > 0) { + ans += lastMove.substring(0, 1).toUpperCase(); + if (cnt > 1) ans += cnt; + cnt = 0; } - lastMove=t; + lastMove = t; cnt++; } else { - if (cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; - cnt=0; + if (cnt > 0) { + ans += lastMove.substring(0, 1).toUpperCase(); + if (cnt > 1) ans += cnt; + cnt = 0; } ans += core.utils._encodeRoute_encodeOne(t); } }); - if (cnt>0) { - ans+=lastMove.substring(0,1).toUpperCase(); - if (cnt>1) ans+=cnt; + if (cnt > 0) { + ans += lastMove.substring(0, 1).toUpperCase(); + if (cnt > 1) ans += cnt; } return LZString.compressToBase64(ans); } utils.prototype._encodeRoute_id2number = function (id) { var number = core.maps.getNumberById(id); - return number==0?id:number; + return number == 0 ? id : number; } utils.prototype._encodeRoute_encodeOne = function (t) { - if (t.indexOf('item:')==0) - return "I"+this._encodeRoute_id2number(t.substring(5))+":"; - else if (t.indexOf('unEquip:')==0) - return "u"+t.substring(8); - else if (t.indexOf('equip:')==0) - return "e"+this._encodeRoute_id2number(t.substring(6))+":"; - else if (t.indexOf('fly:')==0) - return "F"+t.substring(4)+":"; - else if (t.indexOf('choices:')==0) - return "C"+t.substring(8); - else if (t.indexOf('shop:')==0) - return "S"+t.substring(5); - else if (t=='turn') + if (t.indexOf('item:') == 0) + return "I" + this._encodeRoute_id2number(t.substring(5)) + ":"; + else if (t.indexOf('unEquip:') == 0) + return "u" + t.substring(8); + else if (t.indexOf('equip:') == 0) + return "e" + this._encodeRoute_id2number(t.substring(6)) + ":"; + else if (t.indexOf('fly:') == 0) + return "F" + t.substring(4) + ":"; + else if (t.indexOf('choices:') == 0) + return "C" + t.substring(8); + else if (t.indexOf('shop:') == 0) + return "S" + t.substring(5); + else if (t == 'turn') return 'T'; - else if (t.indexOf('turn:')==0) - return "t"+t.substring(5).substring(0,1).toUpperCase()+":"; - else if (t=='getNext') + else if (t.indexOf('turn:') == 0) + return "t" + t.substring(5).substring(0, 1).toUpperCase() + ":"; + else if (t == 'getNext') return 'G'; - else if (t.indexOf('input:')==0) - return "P"+t.substring(6); - else if (t.indexOf('input2:')==0) - return "Q"+t.substring(7)+":"; - else if (t=='no') + else if (t.indexOf('input:') == 0) + return "P" + t.substring(6); + else if (t.indexOf('input2:') == 0) + return "Q" + t.substring(7) + ":"; + else if (t == 'no') return 'N'; - else if (t.indexOf('move:')==0) - return "M"+t.substring(5); - else if (t.indexOf('key:')==0) - return 'K'+t.substring(4); - else if (t.indexOf('random:')==0) - return 'X'+t.substring(7); + else if (t.indexOf('move:') == 0) + return "M" + t.substring(5); + else if (t.indexOf('key:') == 0) + return 'K' + t.substring(4); + else if (t.indexOf('random:') == 0) + return 'X' + t.substring(7); return ''; } @@ -476,7 +480,8 @@ utils.prototype.decodeRoute = function (route) { if (core.isset(v) && /^[a-zA-Z0-9+\/=:]*$/.test(v)) { route = v; } - } catch (e) {} + } catch (e) { + } var decodeObj = {route: route, index: 0, ans: []}; while (decodeObj.index < decodeObj.route.length) { @@ -486,18 +491,18 @@ utils.prototype.decodeRoute = function (route) { } utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) { - var num=""; - while (decodeObj.index0) { + var na = core.clone(a), nb = core.clone(b); + while (nb.length > 0) { if (na.shift() != nb.shift()) return null; } return na; } utils.prototype.inArray = function (array, element) { - return this.isset(array) && (array instanceof Array) && array.indexOf(element)>=0; + return this.isset(array) && (array instanceof Array) && array.indexOf(element) >= 0; } utils.prototype.clamp = function (x, a, b) { - var min=Math.min(a, b), max=Math.max(a, b); - return Math.min(Math.max(x||0, min), max); + var min = Math.min(a, b), max = Math.max(a, b); + return Math.min(Math.max(x || 0, min), max); } utils.prototype.getCookie = function (name) { var match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)')); - return match?match[2]:null; + return match ? match[2] : null; } utils.prototype.expandMoveSteps = function (steps) { - var moveSteps=[]; + var moveSteps = []; steps.forEach(function (e) { - if (typeof e=="string") { + if (typeof e == "string") { moveSteps.push(e); } else { @@ -581,7 +622,7 @@ utils.prototype.expandMoveSteps = function (steps) { moveSteps.push(e.direction) } else { - for (var i=0;i\/?]*$/.test(value); - var style = 'font-style: ' + (italic?'italic':'normal') + '; '; + var style = 'font-style: ' + (italic ? 'italic' : 'normal') + '; '; // 判定是否需要缩放 var length = this.strlen(value) || 1; - style += 'font-size: ' + Math.min(1, 7/length) + 'em; '; + style += 'font-size: ' + Math.min(1, 7 / length) + 'em; '; if (core.isset(css)) style += css; core.statusBar[name].innerHTML = "" + value + ""; } @@ -620,7 +661,7 @@ utils.prototype.encodeBase64 = function (str) { ////// Base64解密 ////// utils.prototype.decodeBase64 = function (str) { - return decodeURIComponent(atob(str).split('').map(function(c) { + return decodeURIComponent(atob(str).split('').map(function (c) { return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2); }).join('')); } @@ -628,19 +669,19 @@ utils.prototype.decodeBase64 = function (str) { ////// 任意进制转换 ////// utils.prototype.convertBase = function (str, fromBase, toBase) { var map = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ~`!@#$%^&*()_-+={}[]\\|:;<>,.?/"; - if (fromBase==toBase) return str; - var len = str.length, ans=""; + if (fromBase == toBase) return str; + var len = str.length, ans = ""; var t = []; - for (var i=0;i0) { - for (var i=len; i>=1; i--) { - t[i-1]+=t[i]%toBase*fromBase; - t[i]=parseInt(t[i]/toBase); + for (var i = 0; i < len; i++) t[i] = map.indexOf(str.charAt(i)); + t[len] = 0; + while (len > 0) { + for (var i = len; i >= 1; i--) { + t[i - 1] += t[i] % toBase * fromBase; + t[i] = parseInt(t[i] / toBase); } - ans+=map.charAt(t[0]%toBase); - t[0]=parseInt(t[0]/toBase); - while (len>0 && t[len-1]==0) len--; + ans += map.charAt(t[0] % toBase); + t[0] = parseInt(t[0] / toBase); + while (len > 0 && t[len - 1] == 0) len--; } return ans; } @@ -649,21 +690,21 @@ utils.prototype.rand = function (num) { var rand = core.getFlag('__rand__'); rand = this.__next_rand(rand); core.setFlag('__rand__', rand); - var ans = rand/2147483647; - if (core.isset(num) && num>0) - return Math.floor(ans*num); + var ans = rand / 2147483647; + if (core.isset(num) && num > 0) + return Math.floor(ans * num); return ans; } ////// 生成随机数(录像方法) ////// utils.prototype.rand2 = function (num) { - num = num||2147483648; + num = num || 2147483648; var value; if (core.isReplaying()) { var action = core.status.replay.toReplay.shift(); - if (action.indexOf("random:")==0 ) { - value=parseInt(action.substring(7)); + if (action.indexOf("random:") == 0) { + value = parseInt(action.substring(7)); } else { core.stopReplay(); @@ -672,14 +713,14 @@ utils.prototype.rand2 = function (num) { } } else { - value = Math.floor(Math.random()*num); + value = Math.floor(Math.random() * num); } - core.status.route.push("random:"+value); + core.status.route.push("random:" + value); return value; } utils.prototype.__init_seed = function () { - var rand = new Date().getTime()%34834795 + 3534; + var rand = new Date().getTime() % 34834795 + 3534; rand = this.__next_rand(rand); rand = this.__next_rand(rand); rand = this.__next_rand(rand); @@ -688,8 +729,8 @@ utils.prototype.__init_seed = function () { } utils.prototype.__next_rand = function (_rand) { - _rand=(_rand%127773)*16807-~~(_rand/127773)*2836; - _rand+=_rand<0?2147483647:0; + _rand = (_rand % 127773) * 16807 - ~~(_rand / 127773) * 2836; + _rand += _rand < 0 ? 2147483647 : 0; return _rand; } @@ -712,24 +753,24 @@ utils.prototype.readFile = function (success, error, readType) { } // Step 1: 如果不支持FileReader,直接不支持 - if (core.platform.fileReader==null) { + if (core.platform.fileReader == null) { alert("当前浏览器不支持FileReader!"); if (core.isset(error)) error(); return; } - if (core.platform.fileInput==null) { + if (core.platform.fileInput == null) { core.platform.fileInput = document.createElement("input"); core.platform.fileInput.style.opacity = 0; core.platform.fileInput.type = 'file'; core.platform.fileInput.onchange = function () { var files = core.platform.fileInput.files; - if (files.length==0) { + if (files.length == 0) { if (core.isset(core.platform.errorCallback)) core.platform.errorCallback(); return; } - if(!readType)core.platform.fileReader.readAsText(core.platform.fileInput.files[0]); + if (!readType) core.platform.fileReader.readAsText(core.platform.fileInput.files[0]); else core.platform.fileReader.readAsDataURL(core.platform.fileInput.files[0]); core.platform.fileInput.value = ''; } @@ -740,14 +781,14 @@ utils.prototype.readFile = function (success, error, readType) { ////// 读取文件完毕 ////// utils.prototype.readFileContent = function (content) { - var obj=null; - if(content.slice(0,4)==='data'){ + var obj = null; + if (content.slice(0, 4) === 'data') { if (core.isset(core.platform.successCallback)) core.platform.successCallback(content); return; } try { - obj=JSON.parse(content); + obj = JSON.parse(content); if (core.isset(obj)) { if (core.isset(core.platform.successCallback)) core.platform.successCallback(obj); @@ -807,14 +848,14 @@ utils.prototype.download = function (filename, content) { alert("你当前使用的是Safari浏览器,不支持直接下载文件。\n即将打开一个新窗口为应下载内容,请自行全选复制然后创建空白文件并粘贴。"); var blob = new Blob([content], {type: 'text/plain;charset=utf-8'}); var href = window.URL.createObjectURL(blob); - var opened=window.open(href, "_blank"); + var opened = window.open(href, "_blank"); window.URL.revokeObjectURL(href); return; } // Step 4: 下载 var blob = new Blob([content], {type: 'text/plain;charset=utf-8'}); - if(window.navigator.msSaveOrOpenBlob) { + if (window.navigator.msSaveOrOpenBlob) { window.navigator.msSaveBlob(blob, filename); } else { @@ -868,7 +909,7 @@ utils.prototype.copy = function (data) { ////// 动画显示某对象 ////// utils.prototype.show = function (obj, speed, callback) { obj.style.display = 'block'; - if (!core.isset(speed) && main.mode!='play') { + if (!core.isset(speed) && main.mode != 'play') { obj.style.opacity = 1; if (core.isset(callback)) callback(); return; @@ -889,7 +930,7 @@ utils.prototype.show = function (obj, speed, callback) { ////// 动画使某对象消失 ////// utils.prototype.hide = function (obj, speed, callback) { - if (!core.isset(speed) || main.mode!='play'){ + if (!core.isset(speed) || main.mode != 'play') { obj.style.display = 'none'; if (core.isset(callback)) callback(); return; @@ -918,16 +959,16 @@ utils.prototype.encodeCanvas = function (ctx) { ctx.imageSmoothingEnabled = false; var imgData = ctx.getImageData(0, 0, width, height); - for (var i=0;i threshold - || window.outerHeight - zoom*window.innerHeight > threshold; + var zoom = Math.min(window.outerWidth / window.innerWidth, window.outerHeight / window.innerHeight); + return window.outerWidth - zoom * window.innerWidth > threshold + || window.outerHeight - zoom * window.innerHeight > threshold; } utils.prototype.hashCode = function (obj) { @@ -977,8 +1018,8 @@ utils.prototype.hashCode = function (obj) { var hash = 0, i, chr; if (obj.length === 0) return hash; for (i = 0; i < obj.length; i++) { - chr = obj.charCodeAt(i); - hash = ((hash << 5) - hash) + chr; + chr = obj.charCodeAt(i); + hash = ((hash << 5) - hash) + chr; hash |= 0; } return hash; @@ -1011,20 +1052,20 @@ utils.prototype.same = function (a, b) { utils.prototype._export = function (floorIds) { if (!core.isset(floorIds)) floorIds = [core.status.floorId]; - else if (floorIds=='all') floorIds = core.clone(core.floorIds); + else if (floorIds == 'all') floorIds = core.clone(core.floorIds); else if (typeof floorIds == 'string') floorIds = [floorIds]; var monsterMap = {}; // map - var content = floorIds.length+"\n13 13\n\n"; + var content = floorIds.length + "\n13 13\n\n"; floorIds.forEach(function (floorId) { var arr = core.maps.getMapArray(core.status.maps[floorId].blocks, 13, 13); content += arr.map(function (x) { // check monster x.forEach(function (t) { var block = core.maps.initBlock(null, null, t); - if (block.event.cls.indexOf("enemy")==0) { + if (block.event.cls.indexOf("enemy") == 0) { monsterMap[t] = block.event.id; } }) @@ -1034,7 +1075,9 @@ utils.prototype._export = function (floorIds) { // values content += ["redJewel", "blueJewel", "greenJewel", "redPotion", "bluePotion", - "yellowPotion", "greenPotion", "sword1", "shield1"].map(function (x) {return core.values[x]}).join(" ") + "\n\n"; + "yellowPotion", "greenPotion", "sword1", "shield1"].map(function (x) { + return core.values[x] + }).join(" ") + "\n\n"; // monster content += Object.keys(monsterMap).length + "\n"; @@ -1059,26 +1102,26 @@ utils.prototype.http = function (type, url, formData, success, error, mimeType, xhr.overrideMimeType(mimeType); if (core.isset(responseType)) xhr.responseType = responseType; - xhr.onload = function(e) { - if (xhr.status==200) { + xhr.onload = function (e) { + if (xhr.status == 200) { if (core.isset(success)) { success(xhr.response); } } else { if (core.isset(error)) - error("HTTP "+xhr.status); + error("HTTP " + xhr.status); } }; xhr.onabort = function () { if (core.isset(error)) error("Abort"); } - xhr.ontimeout = function() { + xhr.ontimeout = function () { if (core.isset(error)) error("Timeout"); } - xhr.onerror = function() { + xhr.onerror = function () { if (core.isset(error)) error("Error on Connection"); } @@ -1096,8 +1139,8 @@ function lzw_encode(s) { var currChar; var phrase = data[0]; var code = 256; - for (var i=1; i 1 ? dict[phrase] : phrase.charCodeAt(0)); dict[phrase + currChar] = code; code++; - phrase=currChar; + phrase = currChar; } } out.push(phrase.length > 1 ? dict[phrase] : phrase.charCodeAt(0)); - for (var i=0; i Date: Sat, 16 Mar 2019 23:10:29 +0800 Subject: [PATCH 020/153] Reformat maps --- libs/maps.js | 532 ++++++++++++++++++++++++++------------------------- 1 file changed, 271 insertions(+), 261 deletions(-) diff --git a/libs/maps.js b/libs/maps.js index 509e6d96..5ff2c705 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -8,7 +8,7 @@ function maps() { this.DEFAULT_PIXEL_HEIGHT = this.DEFAULT_HEIGHT * 32; } -maps.prototype._init = function() { +maps.prototype._init = function () { this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e; //delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e); } @@ -39,19 +39,19 @@ maps.prototype.loadFloor = function (floorId, map) { if (core.isset(map[e])) content[e] = core.clone(map[e]); else content[e] = core.clone(floor[e]); }); - map=this.decompressMap(map.map, floorId); + map = this.decompressMap(map.map, floorId); // 事件处理 - content['blocks'] = this._mapIntoBlocks(map,floor,floorId); + content['blocks'] = this._mapIntoBlocks(map, floor, floorId); return content; } -maps.prototype._mapIntoBlocks = function (map,floor,floorId){ +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); + var block = this.initBlock(j, i, (map[i] || [])[j], true, floor); if (block.id != 0 || block.event.trigger) blocks.push(block); } @@ -62,8 +62,8 @@ maps.prototype._mapIntoBlocks = function (map,floor,floorId){ ////// 从ID获得数字 ////// maps.prototype.getNumberById = function (id) { for (var number in this.blocksInfo) { - if ((this.blocksInfo[number]||{}).id == id) - return parseInt(number)||0; + if ((this.blocksInfo[number] || {}).id == id) + return parseInt(number) || 0; } // tilesets if (/^X\d+$/.test(id)) { @@ -77,23 +77,23 @@ maps.prototype.getNumberById = function (id) { ////// 数字和ID的对应关系 ////// maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { - var disable=null; - id = ""+(id||0); + var disable = null; + id = "" + (id || 0); if (id.endsWith(":f")) disable = true; if (id.endsWith(":t")) disable = false; - id=parseInt(id); + id = parseInt(id); var block = {'x': x, 'y': y, 'id': id}; - if (disable!=null) block.disable = disable; + if (disable != null) block.disable = disable; - if (id==17) block.event = {"cls": "terrains", "id": "airwall", "noPass": true}; + if (id == 17) block.event = {"cls": "terrains", "id": "airwall", "noPass": true}; else if (id in this.blocksInfo) block.event = JSON.parse(JSON.stringify(this.blocksInfo[id])); - else if (core.icons.getTilesetOffset(id)) block.event = {"cls": "tileset", "id": "X"+id, "noPass": true}; + else if (core.icons.getTilesetOffset(id)) block.event = {"cls": "tileset", "id": "X" + id, "noPass": true}; else block.event = {'cls': 'terrains', 'id': 'none', 'noPass': false}; if (addInfo) this._addInfo(block); if (eventFloor) { - this._addEvent(block, x, y, (eventFloor.events||{})[x+","+y]); - var changeFloor = (eventFloor.changeFloor||{})[x+","+y]; + this._addEvent(block, x, y, (eventFloor.events || {})[x + "," + y]); + var changeFloor = (eventFloor.changeFloor || {})[x + "," + y]; if (changeFloor) this._addEvent(block, x, y, {"trigger": "changeFloor", "data": changeFloor}); } if (main.mode == 'editor') delete block.disable; @@ -102,7 +102,7 @@ maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { ////// 添加一些信息到block上 ////// maps.prototype._addInfo = function (block) { - if (block.event.cls.indexOf("enemy")==0 && !core.isset(block.event.trigger)) { + if (block.event.cls.indexOf("enemy") == 0 && !core.isset(block.event.trigger)) { block.event.trigger = 'battle'; } if (block.event.cls == 'items' && !core.isset(block.event.trigger)) { @@ -136,7 +136,7 @@ maps.prototype._addEvent = function (block, x, y, event) { // 覆盖enable if (!core.isset(block.disable) && core.isset(event.enable)) { - block.disable=!event.enable; + block.disable = !event.enable; } // 覆盖animate if (event.animate === false) { @@ -144,8 +144,8 @@ maps.prototype._addEvent = function (block, x, y, event) { } // 覆盖所有属性 for (var key in event) { - if (key!="enable" && key!="animate" && core.isset(event[key])) { - block.event[key]=core.clone(event[key]); + if (key != "enable" && key != "animate" && core.isset(event[key])) { + block.event[key] = core.clone(event[key]); } } // 给无trigger的增加trigger:action @@ -157,7 +157,7 @@ maps.prototype._addEvent = function (block, x, y, event) { ////// 初始化所有地图 ////// maps.prototype.initMaps = function (floorIds) { var maps = {}; - for (var i=0;i0) return false; + if (core.status.checkBlock.damage[sx + core.bigmap.width * sy] > 0) return false; var id = core.getBlockId(sx, sy); if (id != null) { // 楼梯或者传送点才能无视 - if (["upFloor","downFloor","portal","upPortal","downPortal","leftPortal","rightPortal"].indexOf(id)>=0) + if (["upFloor", "downFloor", "portal", "upPortal", "downPortal", "leftPortal", "rightPortal"].indexOf(id) >= 0) return true; return false; } @@ -480,18 +480,18 @@ maps.prototype._canMoveDirectly_bfs = function (sx, sy, ex, ey) { var canMoveArray = this.generateMovableArray(); var blocksObj = this.getMapBlocksObj(core.status.floorId); - var visited=[], queue=[]; - visited[sx+","+sy]=0; - queue.push(sx+","+sy); + var visited = [], queue = []; + visited[sx + "," + sy] = 0; + queue.push(sx + "," + sy); - while (queue.length>0) { - var now=queue.shift().split(","), x=parseInt(now[0]), y=parseInt(now[1]); + while (queue.length > 0) { + var now = queue.shift().split(","), x = parseInt(now[0]), y = parseInt(now[1]); for (var direction in core.utils.scan) { if (!core.inArray(canMoveArray[x][y], direction)) continue; - var nx=x+core.utils.scan[direction].x, ny=y+core.utils.scan[direction].y, nindex = nx+","+ny; + var nx = x + core.utils.scan[direction].x, ny = y + core.utils.scan[direction].y, nindex = nx + "," + ny; if (visited[nindex]) continue; if (!this._canMoveDirectly_checkNextPoint(blocksObj, nx, ny)) continue; - visited[nindex] = visited[now]+1; + visited[nindex] = visited[now] + 1; if (nx == ex && ny == ey) return visited[nindex]; queue.push(nindex); } @@ -505,9 +505,9 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { // 该点是否有事件 if (blocksObj[index]) return false; // 是否存在阻激夹域伤害 - if (core.status.checkBlock.damage[x+core.bigmap.width*y]>0) return false; + if (core.status.checkBlock.damage[x + core.bigmap.width * y] > 0) return false; // 是否存在捕捉 - if (core.status.checkBlock.ambush[x+core.bigmap.width*y]) return false; + if (core.status.checkBlock.ambush[x + core.bigmap.width * y]) return false; return true; } @@ -522,8 +522,8 @@ maps.prototype.drawBlock = function (block, animate) { var x = block.x, y = block.y; // --- 在界面外的动画不绘制 if (redraw && block.event.animate > 1 && - (32*x < core.bigmap.offsetX - 64 || 32*x > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 - || 32*y < core.bigmap.offsetY - 64 || 32*y > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { + (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 + || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { return; } @@ -541,9 +541,9 @@ maps.prototype._drawBlockInfo = function (blockInfo, x, y) { 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); - if (height>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.drawImage('event2', image, posX * 32, posY * height, 32, height - 32, x * 32, y * 32 + 32 - height, 32, height - 32); } } @@ -552,7 +552,7 @@ maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y) { core.clearMap(name, x * 32, y * 32 + 32 - height, 32, height); if (name == 'bg') { - if (height>32) { + 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); } @@ -564,9 +564,9 @@ maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y) { ////// 生成groundPattern ////// maps.prototype.generateGroundPattern = function (floorId) { // 生成floorId层的groundPattern(盒子内的怪物动画) - var groundId = ((core.status.maps||core.floors)[floorId||core.status.floorId]||{}).defaultGround || "ground"; + var groundId = ((core.status.maps || core.floors)[floorId || core.status.floorId] || {}).defaultGround || "ground"; core.material.groundCanvas.clearRect(0, 0, 32, 32); - core.material.groundCanvas.drawImage(core.material.images.terrains, 0, 32*core.material.icons.terrains[groundId], 32, 32, 0, 0, 32, 32); + core.material.groundCanvas.drawImage(core.material.images.terrains, 0, 32 * core.material.icons.terrains[groundId], 32, 32, 0, 0, 32, 32); core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat'); // 如果需要用纯色可以直接将下面代码改成改成 // core.material.groundPattern = '#000000'; @@ -633,7 +633,7 @@ maps.prototype.drawBg = function (floorId, ctx) { maps.prototype._drawBg_drawBackground = function (floorId, ctx) { var width = core.floors[floorId].width, height = core.floors[floorId].height; - var groundId = (core.status.maps||core.floors)[floorId].defaultGround || "ground"; + var groundId = (core.status.maps || core.floors)[floorId].defaultGround || "ground"; var yOffset = core.material.icons.terrains[groundId]; if (core.isset(yOffset)) { for (var i = 0; i < width; i++) { @@ -646,12 +646,14 @@ maps.prototype._drawBg_drawBackground = function (floorId, ctx) { ////// 绘制事件层 ////// maps.prototype.drawEvents = function (floorId, blocks, ctx) { - floorId = floorId ||core.status.floorId; + floorId = floorId || core.status.floorId; if (!core.isset(blocks)) blocks = core.status.maps[floorId].blocks; var arr = this.getMapArray(blocks, core.floors[floorId].width, core.floors[floorId].height); var onMap = !core.isset(ctx); if (onMap) ctx = core.canvas.event; - blocks.filter(function (block) { return block.event && !block.disable; }) + blocks.filter(function (block) { + return block.event && !block.disable; + }) .forEach(function (block) { core.maps._drawMap_drawBlockInfo(ctx, block, core.maps.getBlockInfo(block), arr, onMap); }); @@ -674,8 +676,8 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { var width = core.floors[floorId].width; var height = core.floors[floorId].height; - if (!core.isset(core.status[name+"maps"])) - core.status[name+"maps"] = {}; + if (!core.isset(core.status[name + "maps"])) + core.status[name + "maps"] = {}; var arr = this.getBgFgMapArray(name, floorId); for (var x = 0; x < width; x++) { @@ -688,7 +690,7 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { } } if (onMap) - core.status.autotileAnimateObjs[name+"map"] = core.clone(arr); + core.status.autotileAnimateObjs[name + "map"] = core.clone(arr); } ////// 绘制楼层贴图 ////// @@ -698,15 +700,15 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat var redraw = core.isset(currStatus); if (!redraw) core.status.floorAnimateObjs = core.clone(images); images.forEach(function (t) { - if (typeof t == 'string') t = [0,0,t]; - var dx=parseInt(t[0]), dy=parseInt(t[1]), imageName=t[2], frame = core.clamp(parseInt(t[4]), 1, 8); + if (typeof t == 'string') t = [0, 0, t]; + var dx = parseInt(t[0]), dy = parseInt(t[1]), imageName = t[2], frame = core.clamp(parseInt(t[4]), 1, 8); var image = core.material.images.images[imageName]; if (redraw && frame == 1) return; // 不重绘 if (core.isset(dx) && core.isset(dy) && core.isset(image) && - !core.hasFlag("__floorImg__"+floorId+"_"+dx+"_"+dy)) { - var width = parseInt(image.width / frame), offsetX = (currStatus||0)%frame*width; - if (/.*\.gif/i.test(imageName) && main.mode=='play') { + !core.hasFlag("__floorImg__" + floorId + "_" + dx + "_" + dy)) { + var width = parseInt(image.width / frame), offsetX = (currStatus || 0) % frame * width; + if (/.*\.gif/i.test(imageName) && main.mode == 'play') { if (redraw) return; // 忽略gif this._drawFloorImages_gif(image, dx, dy); return; @@ -719,8 +721,8 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat maps.prototype._getFloorImages = function (floorId) { floorId = floorId || core.status.floorId; var images = []; - if (core.isset((core.status.maps||core.floors)[floorId].images)) { - images = (core.status.maps||core.floors)[floorId].images; + if (core.isset((core.status.maps || core.floors)[floorId].images)) { + images = (core.status.maps || core.floors)[floorId].images; if (typeof images == 'string') { images = [[0, 0, images]]; } @@ -733,10 +735,10 @@ maps.prototype._drawFloorImages_gif = function (image, dx, dy) { var gif = new Image(); gif.src = image.src; gif.style.position = 'absolute'; - gif.style.left = (dx*core.domStyle.scale)+"px"; - gif.style.top = (dy*core.domStyle.scale)+"px"; - gif.style.width = image.width*core.domStyle.scale+"px"; - gif.style.height = image.height*core.domStyle.scale+"px"; + gif.style.left = (dx * core.domStyle.scale) + "px"; + gif.style.top = (dy * core.domStyle.scale) + "px"; + gif.style.width = image.width * core.domStyle.scale + "px"; + gif.style.height = image.height * core.domStyle.scale + "px"; core.dom.gif.appendChild(gif); return; } @@ -751,42 +753,42 @@ maps.prototype._drawFloorImage = function (ctx, name, type, image, offsetX, widt if (name != 'bg') return; return _draw(); } - if (type==1) { + if (type == 1) { if (name != 'fg') return; return _draw(); } - if (type==2) { + if (type == 2) { if (name == 'bg') { if (redraw) core.clearMap(ctx, dx, dy + height - 32, width, 32); - core.drawImage('bg', image, offsetX, height-32, width, 32, dx, dy + height - 32, width, 32); + core.drawImage('bg', image, offsetX, height - 32, width, 32, dx, dy + height - 32, width, 32); } else if (name == 'fg') { - if (redraw) core.clearMap(ctx, dx, dy, width, height-32); - core.drawImage('fg', image, offsetX, 0, width, height-32, dx, dy, width, height-32); + if (redraw) core.clearMap(ctx, dx, dy, width, height - 32); + core.drawImage('fg', image, offsetX, 0, width, height - 32, dx, dy, width, height - 32); } return; } } ////// 绘制Autotile ////// -maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, status){ +maps.prototype.drawAutotile = function (ctx, mapArr, block, size, left, top, status) { var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 // +----+----+----+----+----+----+ - [10, 9, 4, 3 ], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 | - [10, 9, 4, 13], //1 bin:0001 +----+----+----+----+----+----+ - [10, 9, 18, 3 ], //2 bin:0010 | 7 | 8 | 9 | 10 | 11 | 12 | - [10, 9, 16, 15], //3 bin:0011 +----+----+----+----+----+----+ - [10, 43, 4, 3 ], //4 bin:0100 | 13 | 14 | 15 | 16 | 17 | 18 | - [10, 31, 4, 25], //5 bin:0101 +----+----+----+----+----+----+ - [10, 7, 2, 3 ], //6 bin:0110 | 19 | 20 | 21 | 22 | 23 | 24 | - [10, 31, 16, 5 ], //7 bin:0111 +----+----+----+----+----+----+ - [48, 9, 4, 3 ], //8 bin:1000 | 25 | 26 | 27 | 28 | 29 | 30 | - [ 8, 9, 4, 1 ], //9 bin:1001 +----+----+----+----+----+----+ - [36, 9, 30, 3 ], //10 bin:1010 | 31 | 32 | 33 | 34 | 35 | 36 | - [36, 9, 6, 15], //11 bin:1011 +----+----+----+----+----+----+ - [46, 45, 4, 3 ], //12 bin:1100 | 37 | 38 | 39 | 40 | 41 | 42 | - [46, 11, 4, 25], //13 bin:1101 +----+----+----+----+----+----+ - [12, 45, 30, 3 ], //14 bin:1110 | 43 | 44 | 45 | 46 | 47 | 48 | + [10, 9, 4, 3], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 | + [10, 9, 4, 13], //1 bin:0001 +----+----+----+----+----+----+ + [10, 9, 18, 3], //2 bin:0010 | 7 | 8 | 9 | 10 | 11 | 12 | + [10, 9, 16, 15], //3 bin:0011 +----+----+----+----+----+----+ + [10, 43, 4, 3], //4 bin:0100 | 13 | 14 | 15 | 16 | 17 | 18 | + [10, 31, 4, 25], //5 bin:0101 +----+----+----+----+----+----+ + [10, 7, 2, 3], //6 bin:0110 | 19 | 20 | 21 | 22 | 23 | 24 | + [10, 31, 16, 5], //7 bin:0111 +----+----+----+----+----+----+ + [48, 9, 4, 3], //8 bin:1000 | 25 | 26 | 27 | 28 | 29 | 30 | + [8, 9, 4, 1], //9 bin:1001 +----+----+----+----+----+----+ + [36, 9, 30, 3], //10 bin:1010 | 31 | 32 | 33 | 34 | 35 | 36 | + [36, 9, 6, 15], //11 bin:1011 +----+----+----+----+----+----+ + [46, 45, 4, 3], //12 bin:1100 | 37 | 38 | 39 | 40 | 41 | 42 | + [46, 11, 4, 25], //13 bin:1101 +----+----+----+----+----+----+ + [12, 45, 30, 3], //14 bin:1110 | 43 | 44 | 45 | 46 | 47 | 48 | [34, 33, 28, 27] //15 bin:1111 +----+----+----+----+----+----+ ]; @@ -795,65 +797,65 @@ maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top, stat var pieceIndexs = this._drawAutotile_getAutotileIndexs(x, y, mapArr, indexArrs); //修正四个边角的固定搭配 - if(pieceIndexs[0] == 13){ - if(pieceIndexs[1] == 16) pieceIndexs[1] = 14; - if(pieceIndexs[2] == 31) pieceIndexs[2] = 19; + if (pieceIndexs[0] == 13) { + if (pieceIndexs[1] == 16) pieceIndexs[1] = 14; + if (pieceIndexs[2] == 31) pieceIndexs[2] = 19; } - if(pieceIndexs[1] == 18){ - if(pieceIndexs[0] == 15) pieceIndexs[0] = 17; - if(pieceIndexs[3] == 36) pieceIndexs[3] = 24; + if (pieceIndexs[1] == 18) { + if (pieceIndexs[0] == 15) pieceIndexs[0] = 17; + if (pieceIndexs[3] == 36) pieceIndexs[3] = 24; } - if(pieceIndexs[2] == 43){ - if(pieceIndexs[0] == 25) pieceIndexs[0] = 37; - if(pieceIndexs[3] == 46) pieceIndexs[3] = 44; + if (pieceIndexs[2] == 43) { + if (pieceIndexs[0] == 25) pieceIndexs[0] = 37; + if (pieceIndexs[3] == 46) pieceIndexs[3] = 44; } - if(pieceIndexs[3] == 48){ - if(pieceIndexs[1] == 30) pieceIndexs[1] = 42; - if(pieceIndexs[2] == 45) pieceIndexs[2] = 47; + if (pieceIndexs[3] == 48) { + if (pieceIndexs[1] == 30) pieceIndexs[1] = 42; + if (pieceIndexs[2] == 45) pieceIndexs[2] = 47; } - for(var i=0; i<4; i++){ + for (var i = 0; i < 4; i++) { var index = pieceIndexs[i]; - var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2)); - this._drawAutotile_drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size, status); + var dx = x * size + size / 2 * (i % 2), dy = y * size + size / 2 * (~~(i / 2)); + this._drawAutotile_drawBlockByIndex(ctx, dx + left, dy + top, core.material.images['autotile'][block.event.id], index, size, status); } } -maps.prototype._drawAutotile_drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size, status) { +maps.prototype._drawAutotile_drawBlockByIndex = function (ctx, dx, dy, autotileImg, index, size, status) { //index为autotile的图块索引1-48 - var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6)); + var sx = 16 * ((index - 1) % 6), sy = 16 * (~~((index - 1) / 6)); status = status || 0; - status %= parseInt(autotileImg.width/96); - ctx.drawImage(autotileImg, sx + 96*status, sy, 16, 16, dx, dy, size/2, size/2); + status %= parseInt(autotileImg.width / 96); + ctx.drawImage(autotileImg, sx + 96 * status, sy, 16, 16, dx, dy, size / 2, size / 2); } -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; +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; } -maps.prototype._drawAutotile_checkAround = function(x, y, mapArr){ +maps.prototype._drawAutotile_checkAround = function (x, y, mapArr) { // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引 var currId = mapArr[y][x]; var pointBlock = []; - for(var i=0; i<4; i++){ + for (var i = 0; i < 4; i++) { var bsum = 0; - var offsetx = i%2, offsety = ~~(i/2); - for(var j=0; j<4; j++){ - var mx = j%2, my = ~~(j/2); - var b = this._drawAutotile_getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1, mapArr); - bsum += b*(Math.pow(2, 3-j)); + var offsetx = i % 2, offsety = ~~(i / 2); + for (var j = 0; j < 4; j++) { + var mx = j % 2, my = ~~(j / 2); + var b = this._drawAutotile_getAutotileAroundId(currId, x + offsetx + mx - 1, y + offsety + my - 1, mapArr); + bsum += b * (Math.pow(2, 3 - j)); } pointBlock.push(bsum); } return pointBlock; } -maps.prototype._drawAutotile_getAutotileIndexs = function(x, y, mapArr, indexArrs){ +maps.prototype._drawAutotile_getAutotileIndexs = function (x, y, mapArr, indexArrs) { var indexArr = []; var pointBlocks = this._drawAutotile_checkAround(x, y, mapArr); - for(var i=0; i<4; i++){ + for (var i = 0; i < 4; i++) { var arr = indexArrs[pointBlocks[i]] - indexArr.push(arr[3-i]); + indexArr.push(arr[3 - i]); } return indexArr; } @@ -874,15 +876,15 @@ maps.prototype._makeAutotileEdges = function () { var n = core.maps.getNumberById(t); core.material.autotileEdges[n] = [n]; - ctx.clearRect(0,0,32,32); + ctx.clearRect(0, 0, 32, 32); ctx.drawImage(core.material.images.autotile[t], 0, 0, 32, 32, 0, 0, 32, 32); var data = canvas.toDataURL("image/png"); autotileIds.forEach(function (t2) { - if (t==t2) return; + if (t == t2) return; var n2 = core.maps.getNumberById(t2); - ctx.clearRect(0,0,32,32); + ctx.clearRect(0, 0, 32, 32); ctx.drawImage(core.material.images.autotile[t2], 32, 0, 32, 32, 0, 0, 32, 32); if (data == canvas.toDataURL("image/png")) { core.material.autotileEdges[n].push(n2); @@ -944,9 +946,9 @@ maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, op if (options.heroLoc) { options.heroIcon = options.heroIcon || core.getFlag("heroIcon", "hero.png"); var icon = core.material.icons.hero[options.heroLoc.direction]; - var height = core.material.images.images[options.heroIcon].height/4; + var height = core.material.images.images[options.heroIcon].height / 4; tempCanvas.drawImage(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); + 32 * options.heroLoc.x, 32 * options.heroLoc.y + 32 - height, 32, height); } // 缩略图:前景 this.drawFg(floorId, tempCanvas); @@ -963,14 +965,14 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || this.DEFAULT_PIXEL_WIDTH; var width = core.floors[floorId].width, height = core.floors[floorId].height; var centerX = toDraw.centerX, centerY = toDraw.centerY; - if (!core.isset(centerX)) centerX = Math.floor(width/2); - if (!core.isset(centerY)) centerY = Math.floor(height/2); + if (!core.isset(centerX)) centerX = Math.floor(width / 2); + if (!core.isset(centerY)) centerY = Math.floor(height / 2); var tempCanvas = core.bigmap.tempCanvas, tempWidth = 32 * width, tempHeight = 32 * height; core.clearMap(ctx, x, y, size, size); if (toDraw.all) { // 绘制全景图 - if (tempWidth<=tempHeight) { + if (tempWidth <= tempHeight) { var realHeight = size, realWidth = realHeight * tempWidth / tempHeight; var side = (size - realWidth) / 2; core.fillRect(ctx, x, y, side, realHeight, '#000000'); @@ -988,7 +990,8 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { else { // 只绘制可见窗口 var halfWidth = parseInt(this.DEFAULT_WIDTH / 2), halfHeight = parseInt(this.DEFAULT_HEIGHT / 2); - var offsetX = core.clamp(centerX - halfWidth, 0, width - this.DEFAULT_WIDTH), offsetY = core.clamp(centerY - halfHeight, 0, height - this.DEFAULT_HEIGHT); + var offsetX = core.clamp(centerX - halfWidth, 0, width - this.DEFAULT_WIDTH), + offsetY = core.clamp(centerY - halfHeight, 0, height - this.DEFAULT_HEIGHT); ctx.drawImage(tempCanvas.canvas, offsetX * 32, offsetY * 32, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, x, y, size, size); } } @@ -997,43 +1000,43 @@ 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; + var block = core.getBlock(x, y, floorId); + if (block == null) return false; return core.isset(block.block.event.noPass) && block.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; + var block = this.getBlock(x, y, floorId); + if (block == null) return false; + return block.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' && (core.isset(id)?block.block.event.id==id:true); + var block = this.getBlock(x, y, floorId); + if (block == null) return false; + return block.block.event.cls == 'terrains' && (core.isset(id) ? block.block.event.id == id : true); } ////// 某个点是否存在楼梯 ////// maps.prototype.stairExists = function (x, y, floorId) { - var block = this.getBlock(x,y,floorId); - if (block==null) return false; - return block.block.event.cls=='terrains' && (block.block.event.id=='upFloor' || block.block.event.id=='downFloor'); + var block = this.getBlock(x, y, floorId); + if (block == null) return false; + return block.block.event.cls == 'terrains' && (block.block.event.id == 'upFloor' || block.block.event.id == 'downFloor'); } ////// 当前位置是否在楼梯边 ////// -maps.prototype.nearStair = function() { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - return this.stairExists(x,y) || this.stairExists(x-1,y) || this.stairExists(x,y-1) || this.stairExists(x+1,y) || this.stairExists(x,y+1); +maps.prototype.nearStair = function () { + var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'); + return this.stairExists(x, y) || this.stairExists(x - 1, y) || this.stairExists(x, y - 1) || this.stairExists(x + 1, y) || this.stairExists(x, y + 1); } ////// 某个点是否存在(指定的)怪物 ////// -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 && (core.isset(id)?block.block.event.id==id:true); +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 && (core.isset(id) ? block.block.event.id == id : true); } ////// 获得某个点的block ////// @@ -1041,8 +1044,8 @@ maps.prototype.getBlock = function (x, y, floorId, showDisable) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return null; var blocks = core.status.maps[floorId].blocks; - for (var n=0;n32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + if (height > 32) + core.clearMap('event2', x * 32, y * 32 + 32 - height, 32, height - 32); } block.block.disable = true; @@ -1166,18 +1169,18 @@ maps.prototype.removeBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - var block = core.getBlock(x,y,floorId,true); - if (block==null) return; // 不存在 + var block = core.getBlock(x, y, floorId, true); + if (block == null) return; // 不存在 - var index=block.index; + var index = block.index; // 删除动画,清除地图 - if (floorId==core.status.floorId) { + if (floorId == core.status.floorId) { core.removeGlobalAnimate(x, y); core.clearMap('event', x * 32, y * 32, 32, 32); - var height = block.block.event.height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + var height = block.block.event.height || 32; + if (height > 32) + core.clearMap('event2', x * 32, y * 32 + 32 - height, 32, height - 32); } // 删除Index @@ -1193,7 +1196,7 @@ maps.prototype.removeBlockById = function (index, floorId) { var blocks = core.status.maps[floorId].blocks, block = blocks[index]; if (this.canRemoveBlock(block, floorId)) { // 能否彻底删除该图块 - blocks.splice(index,1); + blocks.splice(index, 1); } else { block.disable = true; @@ -1202,12 +1205,12 @@ maps.prototype.removeBlockById = function (index, floorId) { ////// 能否彻底从地图中删除一个图块 ////// maps.prototype.canRemoveBlock = function (block, floorId) { - var x=block.x, y=block.y; + var x = block.x, y = block.y; // 检查该点是否存在事件 - if (core.floors[floorId].events[x+","+y] || core.floors[floorId].changeFloor[x+","+y]) + if (core.floors[floorId].events[x + "," + y] || core.floors[floorId].changeFloor[x + "," + y]) return false; // 检查是否存在重生 - if (block.event && block.event.cls.indexOf('enemy')==0 && core.hasSpecial(block.event.id, 23)) + if (block.event && block.event.cls.indexOf('enemy') == 0 && core.hasSpecial(block.event.id, 23)) return false; return true; @@ -1217,7 +1220,9 @@ maps.prototype.canRemoveBlock = function (block, floorId) { maps.prototype.removeBlockByIds = function (floorId, ids) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - ids.sort(function (a,b) {return b-a}).forEach(function (id) { + ids.sort(function (a, b) { + return b - a + }).forEach(function (id) { core.removeBlockById(id, floorId); }); } @@ -1254,23 +1259,23 @@ 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 (type != 'show') type = 'hide'; + if (name != 'fg') name = 'bg'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - if (loc.length==0) return; + if (loc.length == 0) return; loc.forEach(function (t) { - var x=t[0], y=t[1]; - var flag = "__"+name+"Map__"+floorId+"_"+x+"_"+y; + var x = t[0], y = t[1]; + var flag = "__" + name + "Map__" + floorId + "_" + x + "_" + y; if (type == 'hide') core.setFlag(flag, true); else core.removeFlag(flag); }) - core.status[name+"maps"][floorId]=null; + core.status[name + "maps"][floorId] = null; - if (floorId==core.status.floorId) { + if (floorId == core.status.floorId) { core.drawMap(floorId, callback); } else { @@ -1290,21 +1295,21 @@ maps.prototype.hideFloorImage = function (loc, floorId, callback) { ///// 设置贴图显示状态 ////// maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) { - if (type!='show') type='hide'; + if (type != 'show') type = 'hide'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; - if (loc.length==0) return; + if (loc.length == 0) return; loc.forEach(function (t) { - var x=t[0], y=t[1]; - var flag = "__floorImg__"+floorId+"_"+x+"_"+y; + var x = t[0], y = t[1]; + var flag = "__floorImg__" + floorId + "_" + x + "_" + y; if (type == 'hide') core.setFlag(flag, true); else core.removeFlag(flag); }) - if (floorId==core.status.floorId) { + if (floorId == core.status.floorId) { core.drawMap(floorId, callback); } else { @@ -1317,20 +1322,20 @@ maps.prototype.setBlock = function (number, x, y, floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; + if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return; - var originBlock=core.getBlock(x,y,floorId,true); - var block = this.initBlock(x,y,number,true,core.floors[floorId]); + var originBlock = core.getBlock(x, y, floorId, true); + var block = this.initBlock(x, y, number, true, core.floors[floorId]); if (floorId == core.status.floorId) { core.removeGlobalAnimate(x, y); core.clearMap('event', x * 32, y * 32, 32, 32); if (originBlock != null) { - var height = (originBlock.block.event||{}).height||32; - if (height>32) - core.clearMap('event2', x * 32, y * 32 +32-height, 32, height-32); + var height = (originBlock.block.event || {}).height || 32; + if (height > 32) + core.clearMap('event2', x * 32, y * 32 + 32 - height, 32, height - 32); } } - if (originBlock==null) { + if (originBlock == null) { core.status.maps[floorId].blocks.push(block); } else { @@ -1338,7 +1343,7 @@ maps.prototype.setBlock = function (number, x, y, floorId) { originBlock.block.event = block.event; block = originBlock.block; } - if (floorId==core.status.floorId && !block.disable) { + if (floorId == core.status.floorId && !block.disable) { core.drawBlock(block); core.addGlobalAnimate(block); core.updateStatusBar(); @@ -1350,19 +1355,19 @@ maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; - if (x<0 || x>=core.floors[floorId].width || y<0 || y>=core.floors[floorId].height) return; - if (name!='bg' && name!='fg') return; + if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return; + if (name != 'bg' && name != 'fg') return; - var vFlag = "__"+name+"Value__"+floorId+"_"+x+"_"+y; + var vFlag = "__" + name + "Value__" + floorId + "_" + x + "_" + y; core.setFlag(vFlag, number); - core.status[name+"maps"][floorId] = null; + core.status[name + "maps"][floorId] = null; if (floorId == core.status.floorId) core.drawMap(floorId); } ////// 重置地图 ////// -maps.prototype.resetMap = function(floorId) { +maps.prototype.resetMap = function (floorId) { floorId = floorId || core.status.floorId; if (!core.isset(floorId)) return; if (typeof floorId == 'string') floorId = [floorId]; @@ -1379,29 +1384,30 @@ maps.prototype.resetMap = function(floorId) { ////// 初始化独立的block canvas ////// maps.prototype._initDetachedBlock = function (blockInfo, x, y, displayDamage) { - var headCanvas = null, bodyCanvas = '__body_'+x+"_"+y, damageCanvas = null; + var headCanvas = null, bodyCanvas = '__body_' + x + "_" + y, damageCanvas = null; // head if (blockInfo.height > 32) { - headCanvas = "__head_"+x+"_"+y; + headCanvas = "__head_" + x + "_" + y; core.createCanvas(headCanvas, 0, 0, 32, blockInfo.height - 32, 55); } // body core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35); // damage var damage = null, damageColor = null; - if (blockInfo.cls.indexOf('enemy')==0 && core.hasItem('book') && displayDamage) { + if (blockInfo.cls.indexOf('enemy') == 0 && core.hasItem('book') && displayDamage) { var damageString = core.enemys.getDamageString(blockInfo.id, x, y); - damage = damageString.damage; damageColor = damageString.color; + damage = damageString.damage; + damageColor = damageString.color; } if (damage != null) { - damageCanvas = "__damage_"+x+"_"+y; + damageCanvas = "__damage_" + x + "_" + y; var ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65); ctx.textAlign = 'left'; ctx.font = "bold 11px Arial"; core.fillBoldText(ctx, damage, 1, 31, damageColor); if (core.flags.displayCritical) { var critical = core.enemys.nextCriticals(blockInfo.id); - if (critical.length>0) critical=critical[0]; + if (critical.length > 0) critical = critical[0]; critical = core.formatBigNumber(critical[0], true); if (critical == '???') critical = '?'; core.fillBoldText(ctx, critical, 1, 21, '#FFFFFF'); @@ -1444,17 +1450,17 @@ 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 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); + core.removeBlock(x, y); return [block, blockInfo]; } ////// 显示移动某块的动画,达到{“type”:”move”}的效果 ////// -maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) { +maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) { time = time || 500; var blockArr = this._getAndRemoveBlock(x, y); if (blockArr == null) { @@ -1483,7 +1489,7 @@ maps.prototype._moveBlock_doMove = function (blockInfo, canvases, moveInfo, call blockInfo.posX = (blockInfo.posX + 1) % animateTotal; } } - if (moveInfo.moveSteps.length!=0) + if (moveInfo.moveSteps.length != 0) core.maps._moveBlock_moving(blockInfo, canvases, moveInfo); else core.maps._moveJumpBlock_finished(blockInfo, canvases, moveInfo, animate, callback); @@ -1515,7 +1521,7 @@ maps.prototype._moveBlock_moving = function (blockInfo, canvases, moveInfo) { } ////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 ////// -maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) { +maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) { time = time || 500; var blockArr = this._getAndRemoveBlock(sx, sy); if (blockArr == null) { @@ -1543,8 +1549,8 @@ maps.prototype._jumpBlock_playSound = function () { } maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, callback) { - var animate=window.setInterval(function() { - if (jumpInfo.jump_count>0) + var animate = window.setInterval(function () { + if (jumpInfo.jump_count > 0) core.maps._jumpBlock_jumping(blockInfo, canvases, jumpInfo) else core.maps._moveJumpBlock_finished(blockInfo, canvases, jumpInfo, animate, callback); @@ -1568,9 +1574,9 @@ maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) { } maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, animate, callback) { - if (info.keep) info.opacity=0; + if (info.keep) info.opacity = 0; else info.opacity -= 0.06; - if (info.opacity<=0) { + if (info.opacity <= 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); this._deleteDetachedBlock(canvases); @@ -1587,33 +1593,33 @@ maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, an } ////// 显示/隐藏某个块时的动画效果 ////// -maps.prototype.animateBlock = function (loc,type,time,callback) { - var isHide = type=='hide'; +maps.prototype.animateBlock = function (loc, type, time, callback) { + var isHide = type == 'hide'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; var list = this._animateBlock_getList(loc); - if (list.length==0) { + if (list.length == 0) { if (core.isset(callback)) callback(); return; } - this._animateBlock_drawList(list, isHide?1:0); + this._animateBlock_drawList(list, isHide ? 1 : 0); this._animateBlock_doAnimate(loc, list, isHide, 10 / time, callback); } maps.prototype._animateBlock_doAnimate = function (loc, list, isHide, delta, callback) { - var opacity = isHide?1:0; + var opacity = isHide ? 1 : 0; var animate = setInterval(function () { - opacity += isHide?-delta:delta; + opacity += isHide ? -delta : delta; core.maps._animateBlock_drawList(list, opacity); - if (opacity >=1 || opacity<=0) { + if (opacity >= 1 || opacity <= 0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); list.forEach(function (t) { core.maps._deleteDetachedBlock(t.canvases); }); loc.forEach(function (t) { - if (isHide) core.removeBlock(t[0],t[1]); - else core.showBlock(t[0],t[1]); + if (isHide) core.removeBlock(t[0], t[1]); + else core.showBlock(t[0], t[1]); }); if (core.isset(callback)) callback(); } @@ -1625,9 +1631,9 @@ maps.prototype._animateBlock_doAnimate = function (loc, list, isHide, delta, cal maps.prototype._animateBlock_getList = function (loc) { var list = []; loc.forEach(function (t) { - var block = core.getBlock(t[0],t[1],null,true); - if (block==null) return; - block=block.block; + 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) return; @@ -1654,7 +1660,7 @@ maps.prototype.addGlobalAnimate = function (b) { if (!core.isset(b.event) || !core.isset(b.event.animate)) return; if (b.event.cls == 'autotile') { var id = b.event.id, img = core.material.images.autotile[id]; - if (!core.isset(img) || img.width==96) return; + if (!core.isset(img) || img.width == 96) return; core.status.autotileAnimateObjs.blocks.push(b); } else { @@ -1674,11 +1680,15 @@ maps.prototype.removeGlobalAnimate = function (x, y, name) { return; } - core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(function (block) {return block.x!=x || block.y!=y || block.name!=name;}); + core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(function (block) { + return block.x != x || block.y != y || block.name != name; + }); // 检查Autotile if (core.isset(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.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; } @@ -1710,7 +1720,7 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { } // 开始绘制 - var animate = core.material.animates[name], centerX = 32*x+16, centerY = 32*y+16; + var animate = core.material.animates[name], centerX = 32 * x + 16, centerY = 32 * y + 16; // 播放音效 core.playSound(animate.se); @@ -1739,19 +1749,19 @@ maps.prototype._drawAnimateFrame = function (animate, centerX, centerY, index) { var realHeight = image.height * ratio * t.zoom / 100; core.setAlpha('animate', t.opacity / 255); - var cx = centerX+t.x, cy=centerY+t.y; + var cx = centerX + t.x, cy = centerY + t.y; if (!t.mirror && !t.angle) { - core.drawImage('animate', image, cx-realWidth/2 - core.bigmap.offsetX, cy-realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); + core.drawImage('animate', image, cx - realWidth / 2 - core.bigmap.offsetX, cy - realHeight / 2 - core.bigmap.offsetY, realWidth, realHeight); } else { core.saveCanvas('animate'); - core.canvas.animate.translate(cx,cy); + core.canvas.animate.translate(cx, cy); if (t.angle) - core.canvas.animate.rotate(-t.angle*Math.PI/180); + core.canvas.animate.rotate(-t.angle * Math.PI / 180); if (t.mirror) - core.canvas.animate.scale(-1,1); - core.drawImage('animate', image, -realWidth/2 - core.bigmap.offsetX, -realHeight/2 - core.bigmap.offsetY, realWidth, realHeight); + core.canvas.animate.scale(-1, 1); + core.drawImage('animate', image, -realWidth / 2 - core.bigmap.offsetX, -realHeight / 2 - core.bigmap.offsetY, realWidth, realHeight); core.loadCanvas('animate'); } core.setAlpha('animate', 1); @@ -1760,13 +1770,13 @@ maps.prototype._drawAnimateFrame = function (animate, centerX, centerY, index) { ////// 停止动画 ////// maps.prototype.stopAnimate = function (id, doCallback) { - for (var i=0;i Date: Sat, 16 Mar 2019 23:30:38 +0800 Subject: [PATCH 021/153] core.__SIZE__ --- libs/core.js | 3 +++ libs/maps.js | 36 +++++++++++++++--------------------- libs/ui.js | 9 ++------- 3 files changed, 20 insertions(+), 28 deletions(-) diff --git a/libs/core.js b/libs/core.js index a61b6f6a..01eb1390 100644 --- a/libs/core.js +++ b/libs/core.js @@ -5,6 +5,9 @@ "use strict"; function core() { + this.__SIZE__ = 13; + this.__PIXELS__ = this.__SIZE__ * 32; + this.__HALF_SIZE__ = Math.floor(this.__SIZE__ / 2); this.material = { 'animates': {}, 'images': {}, diff --git a/libs/maps.js b/libs/maps.js index 5ff2c705..af75d570 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -2,10 +2,6 @@ function maps() { this._init(); - this.DEFAULT_WIDTH = 13; - this.DEFAULT_HEIGHT = 13; - this.DEFAULT_PIXEL_WIDTH = this.DEFAULT_WIDTH * 32; - this.DEFAULT_PIXEL_HEIGHT = this.DEFAULT_HEIGHT * 32; } maps.prototype._init = function () { @@ -20,8 +16,8 @@ maps.prototype._setFloorSize = function (floorId) { }); return; } - core.floors[floorId].width = core.floors[floorId].width || this.DEFAULT_WIDTH; - core.floors[floorId].height = core.floors[floorId].height || this.DEFAULT_HEIGHT; + core.floors[floorId].width = core.floors[floorId].width || core.__SIZE__; + core.floors[floorId].height = core.floors[floorId].height || core.__SIZE__; } // ------ 加载地图与地图的存档读档(压缩与解压缩) ------ // @@ -290,8 +286,8 @@ maps.prototype.resizeMap = function (floorId) { core.canvas[cn].canvas.style.width = cwidth * core.domStyle.scale + "px"; core.canvas[cn].canvas.style.height = cheight * core.domStyle.scale + "px"; if (main.mode === 'editor' && editor.isMobile) { - core.canvas[cn].canvas.style.width = core.bigmap.width * 32 / core.maps.DEFAULT_PIXEL_WIDTH * 96 + "vw"; - core.canvas[cn].canvas.style.height = core.bigmap.height * 32 / core.maps.DEFAULT_PIXEL_HEIGHT * 96 + "vw"; + 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"; } }); } @@ -522,8 +518,8 @@ maps.prototype.drawBlock = function (block, animate) { var x = block.x, y = block.y; // --- 在界面外的动画不绘制 if (redraw && block.event.animate > 1 && - (32 * x < core.bigmap.offsetX - 64 || 32 * x > core.bigmap.offsetX + this.DEFAULT_PIXEL_WIDTH + 32 - || 32 * y < core.bigmap.offsetY - 64 || 32 * y > core.bigmap.offsetY + this.DEFAULT_PIXEL_HEIGHT + 32 + 16)) { + (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; } @@ -586,7 +582,7 @@ maps.prototype.drawMap = function (floorId, callback) { this._drawMap_drawAll(); if (core.isset(core.status.curtainColor)) { - core.fillRect('curtain', 0, 0, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, + core.fillRect('curtain', 0, 0, core.__PIXELS__, core.__PIXELS__, core.arrayToRGBA(core.status.curtainColor)); } core.drawHero(); @@ -611,7 +607,7 @@ maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, on } if (!onMap) { var height = blockInfo.height; - core.drawImage(ctx, blockInfo.image, 32 * blockInfo.posX, height * blockInfo.posY, 32, height, 32 * block.x, 32 * block.y, 32, height); + 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); @@ -653,10 +649,9 @@ maps.prototype.drawEvents = function (floorId, blocks, ctx) { if (onMap) ctx = core.canvas.event; blocks.filter(function (block) { return block.event && !block.disable; - }) - .forEach(function (block) { - core.maps._drawMap_drawBlockInfo(ctx, block, core.maps.getBlockInfo(block), arr, onMap); - }); + }).forEach(function (block) { + core.maps._drawMap_drawBlockInfo(ctx, block, core.maps.getBlockInfo(block), arr, onMap); + }); if (onMap) core.status.autotileAnimateObjs.map = core.clone(arr); } @@ -962,7 +957,7 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { if (typeof toDraw == 'string' || toDraw.canvas) toDraw = {ctx: toDraw}; var ctx = core.getContextByName(toDraw.ctx); if (ctx == null) return; - var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || this.DEFAULT_PIXEL_WIDTH; + var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || core.__PIXELS__; var width = core.floors[floorId].width, height = core.floors[floorId].height; var centerX = toDraw.centerX, centerY = toDraw.centerY; if (!core.isset(centerX)) centerX = Math.floor(width / 2); @@ -989,10 +984,9 @@ maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { } else { // 只绘制可见窗口 - var halfWidth = parseInt(this.DEFAULT_WIDTH / 2), halfHeight = parseInt(this.DEFAULT_HEIGHT / 2); - var offsetX = core.clamp(centerX - halfWidth, 0, width - this.DEFAULT_WIDTH), - offsetY = core.clamp(centerY - halfHeight, 0, height - this.DEFAULT_HEIGHT); - ctx.drawImage(tempCanvas.canvas, offsetX * 32, offsetY * 32, this.DEFAULT_PIXEL_WIDTH, this.DEFAULT_PIXEL_HEIGHT, x, y, size, size); + var offsetX = core.clamp(centerX - core.__HALF_SIZE__, 0, width - core.__SIZE__), + offsetY = core.clamp(centerY - core.__HALF_SIZE__, 0, height - core.__SIZE__); + ctx.drawImage(tempCanvas.canvas, offsetX * 32, offsetY * 32, core.__PIXELS__, core.__PIXELS__, x, y, size, size); } } diff --git a/libs/ui.js b/libs/ui.js index 2761d85f..d69ac735 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -8,10 +8,6 @@ function ui() { this._init(); - this.DEFAULT_WIDTH = 13; - this.DEFAULT_HEIGHT = 13; - this.DEFAULT_PIXEL_WIDTH = this.DEFAULT_WIDTH * 32; - this.DEFAULT_PIXEL_HEIGHT = this.DEFAULT_HEIGHT * 32; } // 初始化UI @@ -1651,9 +1647,8 @@ ui.prototype.drawCenterFly = function () { var toX = core.bigmap.width - 1 - core.getHeroLoc('x'), toY = core.bigmap.height - 1 - core.getHeroLoc('y'); core.drawThumbnail(null, null, {heroLoc: core.status.hero.loc, heroIcon: core.getFlag('heroIcon', "hero.png")}, {ctx: 'ui', centerX: toX, centerY: toY}); - var midX = Math.floor(this.DEFAULT_WIDTH / 2), midY = Math.floor(this.DEFAULT_HEIGHT / 2); - var offsetX = core.clamp(toX - midX, 0, core.bigmap.width - this.DEFAULT_WIDTH), - offsetY = core.clamp(toY - midY, 0, core.bigmap.height - this.DEFAULT_HEIGHT); + 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); core.status.event.data = {"x": toX, "y": toY, "posX": toX - offsetX, "posY": toY - offsetY}; core.drawTip("请确认当前中心对称飞行器的位置"); From 415267fc25a8946bd86974c24707b06f5af8bce2 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 17 Mar 2019 01:33:40 +0800 Subject: [PATCH 022/153] Remove isset --- libs/actions.js | 54 ++++++------- libs/core.js | 14 ++-- libs/enemys.js | 25 +++--- libs/events.js | 103 ++++++++++++------------- libs/items.js | 79 +++++++------------ libs/loader.js | 16 ++-- libs/maps.js | 179 +++++++++++++++++++++---------------------- libs/utils.js | 155 ++++++++++++++++--------------------- project/functions.js | 116 ++++++++++++---------------- 9 files changed, 331 insertions(+), 410 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index f08502e9..045cac89 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -92,7 +92,7 @@ actions.prototype.unregisterAction = function (action, name) { ////// 执行一个用户交互行为 ////// actions.prototype.doRegisteredAction = function (action) { var actions = this.actions[action]; - if (!core.isset(actions)) return false; + if (!actions) return false; for (var i = 0; i < actions.length; ++i) { if (actions[i].func.apply(this, Array.prototype.slice.call(arguments, 1))) return true; @@ -118,7 +118,7 @@ actions.prototype.onkeyDown = function (e) { } actions.prototype._sys_onkeyDown = function (e) { - if (!core.isset(core.status.holdingKeys)) core.status.holdingKeys = []; + core.status.holdingKeys = core.status.holdingKeys || [] var isArrow = {37: true, 38: true, 39: true, 40: true}[e.keyCode] if (isArrow && !core.status.lockControl) { for (var ii = 0; ii < core.status.holdingKeys.length; ii++) { @@ -382,7 +382,7 @@ actions.prototype._sys_keyUp = function (keyCode, altKey) { if (!core.status.played) return true; this.actionsdata.onKeyUp(keyCode, altKey); - if (core.isset(core.status.automaticRoute) && core.status.automaticRoute.autoHeroMove) { + if (core.status.automaticRoute && core.status.automaticRoute.autoHeroMove) { core.stopAutomaticRoute(); } core.stopHero(); @@ -712,7 +712,7 @@ actions.prototype._sys_keyDownCtrl = function () { } if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' && !core.status.event.data.current.noSkip) { - if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length == 0) { + if (core.timeout.sleepTimeout && Object.keys(core.animateFrame.asyncId).length == 0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.doAction(); @@ -747,7 +747,7 @@ actions.prototype._sys_longClick_lockControl = function (x, y) { // 长按可以跳过等待事件 if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' && !core.status.event.data.current.noSkip) { - if (core.isset(core.timeout.sleepTimeout) && Object.keys(core.animateFrame.asyncId).length == 0) { + if (core.timeout.sleepTimeout && Object.keys(core.animateFrame.asyncId).length == 0) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.doAction(); @@ -824,9 +824,9 @@ actions.prototype._keyUpCenterFly = function (keycode) { ////// 点击确认框时 ////// actions.prototype._clickConfirmBox = function (x, y) { - if ((x == 4 || x == 5) && y == 7 && core.isset(core.status.event.data.yes)) + if ((x == 4 || x == 5) && y == 7 && core.status.event.data.yes) core.status.event.data.yes(); - if ((x == 7 || x == 8) && y == 7 && core.isset(core.status.event.data.no)) + if ((x == 7 || x == 8) && y == 7 && core.status.event.data.no) core.status.event.data.no(); } @@ -845,12 +845,12 @@ actions.prototype._keyUpConfirmBox = function (keycode) { } if (keycode == 13 || keycode == 32 || keycode == 67) { - if (core.status.event.selection == 0 && core.isset(core.status.event.data.yes)) { + if (core.status.event.selection == 0 && core.status.event.data.yes) { core.status.event.selection = null; core.status.event.data.yes(); return; } - if (core.status.event.selection == 1 && core.isset(core.status.event.data.no)) { + if (core.status.event.selection == 1 && core.status.event.data.no) { core.status.event.selection = null; core.status.event.data.no(); return; @@ -948,7 +948,7 @@ actions.prototype._clickBook = function (x, y) { } // 怪物信息 var data = core.status.event.data; - if (core.isset(data) && y < 12) { + if (data != null && y < 12) { var page = parseInt(data / 6); var index = 6 * page + parseInt(y / 2); core.ui.drawBook(index); @@ -983,7 +983,7 @@ actions.prototype._keyUpBook = function (keycode) { } if (keycode == 13 || keycode == 32 || keycode == 67) { var data = core.status.event.data; - if (core.isset(data)) { + if (data != null) { this._clickBook(6, 2 * (data % 6)); } return; @@ -1018,7 +1018,7 @@ actions.prototype._keyDownFly = function (keycode) { } actions.prototype._getNextFlyFloor = function (delta, index) { - if (!core.isset(index)) index = core.status.event.data; + if (index == null) index = core.status.event.data; if (delta == 0) return index; var sign = Math.sign(delta); delta = Math.abs(delta); @@ -1047,7 +1047,7 @@ actions.prototype._keyUpFly = function (keycode) { ////// 查看地图界面时的点击操作 ////// actions.prototype._clickViewMaps = function (x, y) { - if (!core.isset(core.status.event.data)) { + if (core.status.event.data == null) { core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId)); return; } @@ -1112,7 +1112,7 @@ actions.prototype._clickViewMaps = function (x, y) { ////// 查看地图界面时,按下某个键的操作 ////// actions.prototype._keyDownViewMaps = function (keycode) { - if (!core.isset(core.status.event.data)) return; + if (core.status.event.data == null) return; var floorId = core.floorIds[core.status.event.data.index], mh = core.floors[floorId].height; @@ -1127,7 +1127,7 @@ actions.prototype._keyDownViewMaps = function (keycode) { ////// 查看地图界面时,放开某个键的操作 ////// actions.prototype._keyUpViewMaps = function (keycode) { - if (!core.isset(core.status.event.data)) { + if (core.status.event.data == null) { core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId)); return; } @@ -1200,7 +1200,7 @@ actions.prototype._clickQuickShop = function (x, y) { var topIndex = 6 - parseInt(keys.length / 2); if (y >= topIndex && y < topIndex + keys.length) { var reason = core.events.canUseQuickShop(keys[y - topIndex]); - if (!core.flags.enableDisabledShop && core.isset(reason)) { + if (!core.flags.enableDisabledShop && reason) { core.drawText(reason); return; } @@ -1302,7 +1302,7 @@ actions.prototype._clickToolboxIndex = function (index) { ////// 工具栏界面时,按下某个键的操作 ////// actions.prototype._keyDownToolbox = function (keycode) { - if (!core.isset(core.status.event.data)) return; + if (core.status.event.data == null) return; var tools = Object.keys(core.status.hero.items.tools).sort(); var constants = Object.keys(core.status.hero.items.constants).sort(); @@ -1399,7 +1399,7 @@ actions.prototype._keyUpToolbox = function (keycode) { core.ui.closePanel(); return; } - if (!core.isset(core.status.event.data)) return; + if (core.status.event.data == null) return; if (keycode == 13 || keycode == 32 || keycode == 67) { this._clickToolboxIndex(core.status.event.selection); @@ -1459,7 +1459,7 @@ actions.prototype._clickEquipbox = function (x, y) { actions.prototype._clickEquipboxIndex = function (index) { if (index < 6) { if (index >= core.status.globalAttribute.equipName.length) return; - if (index == core.status.event.selection && core.isset(core.status.hero.equipment[index])) { + if (index == core.status.event.selection && core.status.hero.equipment[index]) { core.unloadEquip(index); core.status.route.push("unEquip:" + index); } @@ -1477,7 +1477,7 @@ actions.prototype._clickEquipboxIndex = function (index) { ////// 装备栏界面时,按下某个键的操作 ////// actions.prototype._keyDownEquipbox = function (keycode) { - if (!core.isset(core.status.event.data)) return; + if (core.status.event.data != null) return; var equipCapacity = core.status.globalAttribute.equipName.length; var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); @@ -1563,7 +1563,7 @@ actions.prototype._keyUpEquipbox = function (keycode, altKey) { core.ui.closePanel(); return; } - if (!core.isset(core.status.event.data.selectId)) return; + if (!core.status.event.data.selectId) return; if (keycode == 13 || keycode == 32 || keycode == 67) { this._clickEquipboxIndex(core.status.event.selection); @@ -1905,7 +1905,7 @@ actions.prototype._clickSyncSave = function (x, y) { alert("游戏版本不一致!"); return; } - if (!core.isset(obj.data)) { + if (!obj.data) { alert("无效的存档!"); return; } @@ -2023,7 +2023,7 @@ actions.prototype._clickLocalSaveSelect = function (x, y) { var selection = y - topIndex; if (selection < 2) { core.control.getSaves(selection == 0 ? null : core.saves.saveIndex, function (saves) { - if (core.isset(saves)) { + if (saves) { var content = { "name": core.firstData.name, "version": core.firstData.version, @@ -2408,7 +2408,7 @@ actions.prototype.clearPaint = function () { actions.prototype.savePaint = function () { var data = {}; for (var floorId in core.paint) { - if (core.isset(core.paint[floorId])) + if (core.paint[floorId]) data[floorId] = lzw_decode(core.paint[floorId]); } core.download(core.firstData.name + ".h5paint", JSON.stringify({ @@ -2423,19 +2423,19 @@ actions.prototype.loadPaint = function () { alert("绘图文件和游戏不一致!"); return; } - if (!core.isset(obj.paint)) { + if (!obj.paint) { alert("无效的绘图文件!"); return; } core.paint = {}; for (var floorId in obj.paint) { - if (core.isset(obj.paint[floorId])) + if (obj.paint[floorId]) core.paint[floorId] = lzw_encode(obj.paint[floorId]); } core.clearMap('paint'); var value = core.paint[core.status.floorId]; - if (core.isset(value)) value = lzw_decode(value).split(","); + if (value) value = lzw_decode(value).split(","); core.utils.decodeCanvas(value, 32 * core.bigmap.width, 32 * core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); diff --git a/libs/core.js b/libs/core.js index 01eb1390..b0a0072a 100644 --- a/libs/core.js +++ b/libs/core.js @@ -93,8 +93,8 @@ function core() { canvas: ["bg", "event", "event2", "fg", "damage"], offsetX: 0, // in pixel offsetY: 0, - width: 13, // map width and height - height: 13, + width: this.__SIZE__, // map width and height + height: this.__SIZE__, tempCanvas: null, // A temp canvas for drawing } this.paint = {}; @@ -229,7 +229,7 @@ core.prototype.init = function (coreData, callback) { if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false; - if (core.isset(core.firstData.shops)) { + if (core.firstData.shops) { core.firstData.shops.forEach(function (t) { core.initStatus.shops[t.id] = t; }) @@ -274,7 +274,7 @@ core.prototype.init = function (coreData, callback) { } var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent); - if (core.isset(chrome) && parseInt(chrome[1]) >= 50) + if (chrome && parseInt(chrome[1]) >= 50) core.platform.isChrome = true; core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent); core.platform.isQQ = /QQ/i.test(navigator.userAgent); @@ -327,7 +327,7 @@ core.prototype.init = function (coreData, callback) { core.readFileContent(core.platform.fileReader.result); }; core.platform.fileReader.onerror = function () { - if (core.isset(core.platform.errorCallback)) + if (core.platform.errorCallback) core.platform.errorCallback(); } } @@ -379,7 +379,7 @@ core.prototype.init = function (coreData, callback) { if (main.mode == 'play') core.events.initGame(); - if (core.isset(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins)) { + if (functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins) { core.plugin = new function () { this.__renderFrameFuncs = []; }; @@ -390,7 +390,7 @@ core.prototype.init = function (coreData, callback) { core.showStartAnimate(); - if (core.isset(callback)) callback(); + if (callback) callback(); }); } diff --git a/libs/enemys.js b/libs/enemys.js index 35d11e09..02554f28 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -24,7 +24,7 @@ enemys.prototype.getEnemys = function () { ////// 判断是否含有某特殊属性 ////// enemys.prototype.hasSpecial = function (special, test) { - if (!core.isset(special)) return false; + if (special == null) return false; if (special instanceof Array) { return special.indexOf(test) >= 0; @@ -38,7 +38,7 @@ enemys.prototype.hasSpecial = function (special, test) { return this.hasSpecial(core.material.enemys[special], test); } - if (core.isset(special.special)) { + if (special.special != null) { return this.hasSpecial(special.special, test); } @@ -52,12 +52,12 @@ enemys.prototype.getSpecials = function () { ////// 获得所有特殊属性的名称 ////// enemys.prototype.getSpecialText = function (enemy) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - if (!core.isset(enemy)) return []; + if (!enemy) return []; var special = enemy.special; var text = []; var specials = this.getSpecials(); - if (core.isset(specials)) { + if (specials) { for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(special, specials[i][0])) text.push(this._calSpecialContent(enemy, specials[i][1])); @@ -70,8 +70,8 @@ enemys.prototype.getSpecialText = function (enemy) { enemys.prototype.getSpecialHint = function (enemy, special) { var specials = this.getSpecials(); - if (!core.isset(special)) { - if (!core.isset(specials)) return []; + if (special == null) { + if (specials == null) return []; var hints = []; for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(enemy, specials[i][0])) @@ -80,7 +80,7 @@ enemys.prototype.getSpecialHint = function (enemy, special) { return hints; } - if (!core.isset(specials)) return ""; + if (specials == null) return ""; for (var i = 0; i < specials.length; i++) { if (special == specials[i][0]) return this._calSpecialContent(enemy, specials[i][1]) + ":" + this._calSpecialContent(enemy, specials[i][2]); @@ -304,8 +304,7 @@ enemys.prototype.getCurrentEnemys = function (floorId) { var enemys = [], used = {}; var mapBlocks = core.status.maps[floorId].blocks; for (var b = 0; b < mapBlocks.length; b++) { - if (core.isset(mapBlocks[b].event) && !mapBlocks[b].disable - && mapBlocks[b].event.cls.indexOf('enemy') == 0) { + if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') == 0) { this._getCurrentEnemys_addEnemy(mapBlocks[b].event.id, enemys, used, floorId); } } @@ -314,14 +313,10 @@ enemys.prototype.getCurrentEnemys = function (floorId) { enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) { var enemy = core.material.enemys[enemyId]; - if (!core.isset(enemy)) return null; + if (!enemy) return null; // 检查displayIdInBook - var tmpId = enemy.displayIdInBook; - if (core.isset(core.material.enemys[tmpId])) { - enemy = core.material.enemys[tmpId]; - } - return enemy; + return core.material.enemys[enemy.displayIdInBook] || enemy; } enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, floorId) { diff --git a/libs/events.js b/libs/events.js index 4dae39cf..abd55412 100644 --- a/libs/events.js +++ b/libs/events.js @@ -27,7 +27,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { if (main.mode != 'play') return; // 无动画的开始游戏 - if (core.flags.startUsingCanvas || core.isset(route)) { + if (core.flags.startUsingCanvas || route != null) { core.dom.startPanel.style.display = 'none'; this._startGame_start(hard, seed, route, callback); } @@ -45,7 +45,7 @@ events.prototype._startGame_start = function (hard, seed, route, callback) { core.setHeroLoc('x', -1); core.setHeroLoc('y', -1); - if (core.isset(seed)) { + if (seed != null) { core.setFlag('__seed__', seed); core.setFlag('__rand__', seed); } @@ -67,7 +67,7 @@ events.prototype._startGame_start = function (hard, seed, route, callback) { core.events._startGame_afterStart(nowLoc, callback); }); - if (core.isset(route)) core.startReplay(route); + if (route != null) core.startReplay(route); } events.prototype._startGame_afterStart = function (nowLoc, callback) { @@ -117,7 +117,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { core.setWeather(); core.ui.closePanel(); - if (main.isCompetition && core.isset(ending)) { + if (main.isCompetition && ending != null) { if (ending == "") ending = "恭喜通关"; ending += "[比赛]"; } @@ -136,7 +136,7 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { events.prototype._gameOver_confirmUpload = function (ending, norank) { core.ui.closePanel(); - if (!core.isset(ending)) { + if (ending == null) { this._gameOver_confirmDownload(ending); return; } @@ -153,7 +153,7 @@ events.prototype._gameOver_confirmUpload = function (ending, norank) { events.prototype._gameOver_doUpload = function (username, ending, norank) { var hp = core.status.hero.hp; - if (!core.isset(username)) hp = 1; + if (username == null) hp = 1; core.ui.closePanel(); // upload var formData = new FormData(); @@ -206,7 +206,7 @@ events.prototype._gameOver_confirmDownload = function (ending) { } events.prototype._gameOver_askRate = function (ending) { - if (!core.isset(ending)) { + if (ending == null) { core.restart(); return; } @@ -275,7 +275,7 @@ events.prototype._trigger = function (x, y) { events.prototype._trigger_ignoreChangeFloor = function (block) { var able = core.flags.ignoreChangeFloor; - if (core.isset(block.event.data) && core.isset(block.event.data.ignoreChangeFloor)) + if (block.event.data && block.event.data.ignoreChangeFloor != null) able = block.event.data.ignoreChangeFloor; if (able) { if (core.isReplaying()) { @@ -302,14 +302,14 @@ events.prototype._sys_battle = function (data, callback) { events.prototype.battle = function (id, x, y, force, callback) { core.saveAndStopAutomaticRoute(); id = id || core.getBlockId(x, y); - if (!core.isset(id)) return core.clearContinueAutomaticRoute(callback); + if (!id) return core.clearContinueAutomaticRoute(callback); // 非强制战斗 - if (!core.enemys.canBattle(id, x, y) && !force && !core.isset(core.status.event.id)) { + if (!core.enemys.canBattle(id, x, y) && !force && !core.status.event.id) { core.drawTip("你打不过此怪物!"); return core.clearContinueAutomaticRoute(callback); } // 自动存档 - if (!core.isset(core.status.event.id)) core.autosave(true); + if (!core.status.event.id) core.autosave(true); // 战前事件 if (!this.beforeBattle(id, x, y)) return core.clearContinueAutomaticRoute(callback); @@ -344,7 +344,7 @@ events.prototype.openDoor = function (id, x, y, needKey, callback) { events.prototype._openDoor_check = function (id, x, y, needKey) { // 是否存在门或暗墙 if (!core.terrainExists(x, y, id) || !(id.endsWith("Door") || id.endsWith("Wall")) - || !core.isset(core.material.icons.animates[id])) { + || !core.material.icons.animates[id]) { core.clearContinueAutomaticRoute(); return false; } @@ -428,10 +428,8 @@ events.prototype.getNextItem = function () { events.prototype._sys_changeFloor = function (data, callback) { data = data.event.data; var heroLoc = {}; - if (core.isset(data.loc)) - heroLoc = {'x': data.loc[0], 'y': data.loc[1]}; - if (core.isset(data.direction)) - heroLoc.direction = data.direction; + if (data.loc) heroLoc = {'x': data.loc[0], 'y': data.loc[1]}; + if (data.direction) heroLoc.direction = data.direction; if (core.status.event.id != 'action') core.status.event.id = null; core.changeFloor(data.floorId, data.stair, heroLoc, data.time, callback); } @@ -473,8 +471,8 @@ events.prototype._changeFloor_getInfo = function (floorId, stair, heroLoc, time) } if (main.mode != 'play' || core.isReplaying()) time = 0; - if (!core.isset(time)) time = core.values.floorChangeTime; - if (!core.isset(time)) time = 800; + if (time == null) time = core.values.floorChangeTime; + if (time == null) time = 800; if (time < 100) time = 0; time /= 20; @@ -486,11 +484,11 @@ events.prototype._changeFloor_getInfo = function (floorId, stair, heroLoc, time) } events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) { - if (!core.isset(heroLoc)) + if (!heroLoc) heroLoc = core.clone(core.status.hero.loc); - if (core.isset(stair)) { + if (stair) { // 检查该层地图的 upFloor & downFloor - if (core.isset(core.status.maps[floorId][stair])) { + if (core.status.maps[floorId][stair]) { heroLoc.x = core.status.maps[floorId][stair][0]; heroLoc.y = core.status.maps[floorId][stair][1]; } @@ -506,7 +504,7 @@ events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) { } } ['x', 'y', 'direction'].forEach(function (name) { - if (!core.isset(heroLoc[name])) + if (!heroLoc[name]) heroLoc[name] = core.getHeroLoc(name); }); return heroLoc; @@ -663,7 +661,7 @@ events.prototype._sys_ski = function (data, callback) { ////// 滑冰 ////// events.prototype.ski = function (direction) { - if (!core.isset(direction)) + if (!direction) direction = core.status.automaticRoute.lastDirection || core.getHeroLoc('direction'); if (core.status.event.id != 'ski') { core.waitHeroToStop(function () { @@ -688,7 +686,7 @@ events.prototype._sys_action = function (data, callback) { if (ex == core.nextX() && ey == core.nextY()) { var dir = {"up": "down", "down": "up", "left": "right", "right": "left"}[core.getHeroLoc('direction')]; var id = data.event.id, toId = (data.event.faceIds || {})[dir]; - if (core.isset(toId) && id != toId) { + if (toId && id != toId) { var number = core.icons.getNumberById(toId); if (number > 0) core.setBlock(number, ex, ey); @@ -724,7 +722,7 @@ events.prototype.doEvent = function (data, x, y, prefix) { ////// 开始执行一系列自定义事件 ////// events.prototype.doEvents = function (list, x, y, callback) { - if (!core.isset(list)) return; + if (!list) return; if (!(list instanceof Array)) { list = [list]; } @@ -738,11 +736,11 @@ events.prototype.doEvents = function (list, x, y, callback) { events.prototype.setEvents = function (list, x, y, callback) { var data = core.status.event.data || {}; - if (core.isset(list)) + if (list) data.list = [{todo: core.clone(list), total: core.clone(list), condition: "false"}]; - if (core.isset(x)) data.x = x; - if (core.isset(y)) data.y = y; - if (core.isset(callback)) data.callback = callback; + if (x != null) data.x = x; + if (y != null) data.y = y; + if (callback) data.callback = callback; core.status.event = {id: 'action', data: data}; } @@ -757,7 +755,7 @@ events.prototype.doAction = function () { if (this._doAction_finishEvents()) return; // 当前点坐标和前缀 var x = core.status.event.data.x, y = core.status.event.data.y; - var prefix = [core.status.floorId || "f", core.isset(x) ? x : "x", core.isset(y) ? y : "y"].join("@"); + var prefix = [core.status.floorId || "f", x != null ? x : "x", y != null ? y : "y"].join("@"); var current = core.status.event.data.list[0]; if (this._popEvents(current, prefix)) return; // 当前要执行的事件 @@ -775,8 +773,7 @@ events.prototype._doAction_finishEvents = function () { if (core.status.event.data.list.length == 0) { var callback = core.status.event.data.callback; core.ui.closePanel(); - if (core.isset(callback)) - callback(); + if (callback) callback(); core.replay(); return true; } @@ -804,7 +801,7 @@ events.prototype.insertAction = function (action, x, y, callback) { // ------ 判定commonEvent var commonEvent = this.getCommonEvent(action); if (commonEvent instanceof Array) action = commonEvent; - if (!core.isset(action)) return; + if (!action) return; if (core.status.event.id != 'action') { this.doEvents(action, x, y, callback); @@ -817,13 +814,13 @@ events.prototype.insertAction = function (action, x, y, callback) { ////// 获得一个公共事件 ////// events.prototype.getCommonEvent = function (name) { - if (!core.isset(name) || typeof name !== 'string') return null; + if (!name || typeof name !== 'string') return null; return this.commonEvent[name] || null; } ////// 恢复一个事件 ////// events.prototype.recoverEvents = function (data) { - if (core.isset(data)) { + if (data) { core.ui.closePanel(); core.lockControl(); core.status.event.id = 'action'; @@ -897,16 +894,16 @@ events.prototype._action_comment = function (data, x, y, prefix) { events.prototype._action_setText = function (data, x, y, prefix) { ["position", "offset", "bold", "titlefont", "textfont", "time"].forEach(function (t) { - if (core.isset(data[t])) core.status.textAttribute[t] = data[t]; + if (data[t] != null) core.status.textAttribute[t] = data[t]; }); ["background", "title", "text"].forEach(function (t) { - if (core.isset(data[t]) && (data[t] instanceof Array) && data[t].length >= 3) { + if ((data[t] instanceof Array) && data[t].length >= 3) { if (data[t].length == 3) data[t].push(1); core.status.textAttribute[t] = data[t]; } - if (t == 'background' && core.isset(data[t])) { + if (t == 'background') { var img = core.material.images.images[data[t]]; - if (core.isset(img) && img.width == 192 && img.height == 128) { + if (img && img.width == 192 && img.height == 128) { core.status.textAttribute[t] = data[t]; } } @@ -1035,10 +1032,8 @@ events.prototype._action_changePos = function (data, x, y, prefix) { events.prototype._action_showImage = function (data, x, y, prefix) { var loc = this.__action_getLoc(data.loc, 0, 0, prefix); if (core.isReplaying()) data.time = 0; - var image = core.material.images.images[data.image]; - if (!core.isset(image)) return core.doAction(); this.__action_doAsyncFunc(data.async || data.time == 0, this.showImage, - data.code, image, loc[0], loc[1], data.dw, data.dh, data.opacity, data.time); + data.code, data.image, loc[0], loc[1], data.dw, data.dh, data.opacity, data.time); } events.prototype._action_showTextImage = function (data, x, y, prefix) { @@ -1157,17 +1152,14 @@ events.prototype._action_trigger = function (data, x, y, prefix) { } events.prototype._action_insert = function (data, x, y, prefix) { - if (core.isset(data.name)) { // 公共事件 + if (data.name) { // 公共事件 core.insertAction(this.getCommonEvent(data.name)); } else { var loc = this.__action_getLoc(data.loc, x, y, prefix); var floorId = data.floorId || core.status.floorId; var event = core.floors[floorId].events[loc[0] + "," + loc[1]]; - if (core.isset(event)) { - if (core.isset(event.data)) event = event.data; - this.insertAction(event); - } + if (event) this.insertAction(event.data || event); } core.doAction(); } @@ -1285,8 +1277,7 @@ events.prototype.__action_getInput = function (hint, isText) { } else { core.interval.onDownInterval = 'tmp'; - value = prompt(core.replaceText(hint)); - if (!core.isset(value)) value = ""; + value = prompt(core.replaceText(hint)) || ""; } return value; } @@ -1514,7 +1505,7 @@ events.prototype._action_exit = function (data, x, y, prefix) { ////// 跟随 ////// events.prototype.follow = function (name) { core.status.hero.followers = core.status.hero.followers || []; - if (core.isset(core.material.images.images[name]) + if (core.material.images.images[name] && core.material.images.images[name].width == 128) { core.status.hero.followers.push({"img": name}); core.control.gatherFollowers(); @@ -1526,7 +1517,7 @@ events.prototype.follow = function (name) { ////// 取消跟随 ////// events.prototype.unfollow = function (name) { core.status.hero.followers = core.status.hero.followers || []; - if (!core.isset(name)) { + if (!name) { core.status.heroMoving.followers = []; } else { @@ -1685,7 +1676,7 @@ events.prototype.moveImage = function (code, to, opacityVal, time, callback) { } var getOrDefault = function (a, b) { a = core.calValue(a); - return core.isset(a) ? a : b; + return a != null ? a : b; } var canvas = core.dymCanvas[name].canvas; var fromX = parseFloat(canvas.getAttribute("_left")), @@ -1728,7 +1719,7 @@ events.prototype.setVolume = function (value, time, callback) { if (core.musicStatus.playingBgm) core.material.bgms[core.musicStatus.playingBgm].volume = value; } - if (!core.isset(time) || time < 100) { + if (!time || time < 100) { set(value); if (callback) callback(); return; @@ -1753,7 +1744,7 @@ events.prototype.vibrate = function (time, callback) { if (callback) callback(); return; } - if (!core.isset(time) || time < 1000) time = 1000; + if (!time || time < 1000) time = 1000; // --- 将time调整为500的倍数(上整),不然会出错 time = Math.ceil(time / 500) * 500; var shakeInfo = {duration: time * 3 / 50, speed: 5, power: 5, direction: 1, shake: 0}; @@ -1880,12 +1871,12 @@ events.prototype.checkLvUp = function () { } events.prototype._checkLvUp_check = function () { - if (!core.flags.enableLevelUp || !core.isset(core.firstData.levelUp) + if (!core.flags.enableLevelUp || !core.firstData.levelUp || core.status.hero.lv >= core.firstData.levelUp.length) return null; // 计算下一个所需要的数值 var next = (core.firstData.levelUp[core.status.hero.lv] || {}); var need = core.calValue(next.need); - if (!core.isset(need)) return null; + if (need == null) return null; if (core.status.hero.experience >= need) { // 升级 core.status.hero.lv++; diff --git a/libs/items.js b/libs/items.js index ce3ee753..097ff627 100644 --- a/libs/items.js +++ b/libs/items.js @@ -64,7 +64,7 @@ items.prototype.getItemEffectTip = function (itemId) { ////// 使用道具 ////// items.prototype.useItem = function (itemId, noRoute, callback) { if (!this.canUseItem(itemId)) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } // 执行道具效果 @@ -73,7 +73,7 @@ items.prototype.useItem = function (itemId, noRoute, callback) { this._afterUseItem(itemId); // 记录路线 if (!noRoute) core.status.route.push("item:" + itemId); - if (core.isset(callback)) callback(); + if (callback) callback(); } items.prototype._useItemEffect = function (itemId) { @@ -127,8 +127,7 @@ items.prototype.canUseItem = function (itemId) { ////// 获得某个物品的个数 ////// items.prototype.itemCount = function (itemId) { - if (!core.isset(core.status.hero)) return 0; - if (!core.isset(itemId) || !core.isset(core.material.items[itemId])) return 0; + if (!core.material.items[itemId]) return 0; var itemCls = core.material.items[itemId].cls; if (itemCls == "items") return 0; return core.status.hero.items[itemCls][itemId] || 0; @@ -141,12 +140,9 @@ items.prototype.hasItem = function (itemId) { ////// 是否装备某件装备 ////// items.prototype.hasEquip = function (itemId) { - if (!core.isset(core.status.hero)) return null; + if (!(core.material.items[itemId] || {}).equip) return null; - if (!core.isset(itemId)) return null; - if (!core.isset((core.material.items[itemId] || {}).equip)) return null; - - for (var i in core.status.hero.equipment || []) + for (var i in core.status.hero.equipment) if (core.status.hero.equipment[i] == itemId) return true; return false @@ -154,19 +150,15 @@ items.prototype.hasEquip = function (itemId) { ////// 获得某个装备类型的当前装备 ////// items.prototype.getEquip = function (equipType) { - if (!core.isset(core.status.hero)) return null; - return (core.status.hero.equipment || [])[equipType] || null; + return core.status.hero.equipment[equipType] || null; } ////// 设置某个物品的个数 ////// items.prototype.setItem = function (itemId, itemNum) { - if (!core.isset(core.status.hero)) return null; itemNum = itemNum || 0; var itemCls = core.material.items[itemId].cls; if (itemCls == 'items') return; - if (!core.isset(core.status.hero.items[itemCls])) { - core.status.hero.items[itemCls] = {}; - } + core.status.hero.items[itemCls][itemId] = itemNum; if (core.status.hero.items[itemCls][itemId] <= 0) { if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; @@ -177,8 +169,7 @@ items.prototype.setItem = function (itemId, itemNum) { ////// 删除某个物品 ////// items.prototype.removeItem = function (itemId, itemNum) { - if (!core.isset(core.status.hero)) return null; - if (!core.isset(itemNum)) itemNum = 1; + if (itemNum == null) itemNum = 1; if (!core.hasItem(itemId)) return false; var itemCls = core.material.items[itemId].cls; core.status.hero.items[itemCls][itemId] -= itemNum; @@ -192,16 +183,11 @@ items.prototype.removeItem = function (itemId, itemNum) { ////// 增加某个物品的个数 ////// items.prototype.addItem = function (itemId, itemNum) { - if (!core.isset(core.status.hero)) return null; - if (!core.isset(itemNum)) itemNum = 1; + if (itemNum == null) itemNum = 1; var itemData = core.material.items[itemId]; var itemCls = itemData.cls; if (itemCls == 'items') return; - if (!core.isset(core.status.hero.items[itemCls])) { - core.status.hero.items[itemCls] = {}; - core.status.hero.items[itemCls][itemId] = 0; - } - else if (!core.isset(core.status.hero.items[itemCls][itemId])) { + if (core.status.hero.items[itemCls][itemId] == null) { core.status.hero.items[itemCls][itemId] = 0; } core.status.hero.items[itemCls][itemId] += itemNum; @@ -227,7 +213,7 @@ items.prototype.getEquipTypeById = function (equipId) { items.prototype.getEquipTypeByName = function (name) { var names = core.status.globalAttribute.equipName; for (var i = 0; i < names.length; ++i) { - if (names[i] === name && !core.isset((core.status.hero.equipment || [])[i])) { + if (names[i] === name && !core.status.hero.equipment[i]) { return i; } } @@ -238,7 +224,7 @@ items.prototype.getEquipTypeByName = function (name) { items.prototype.canEquip = function (equipId, hint) { // 装备是否合法 var equip = core.material.items[equipId] || {}; - if (!core.isset(equip.equip)) { + if (!equip.equip) { if (hint) core.drawTip("不合法的装备!"); return false; } @@ -251,7 +237,7 @@ items.prototype.canEquip = function (equipId, hint) { // 可装备条件 var condition = this.equipCondition[equipId]; - if (core.isset(condition) && condition.length > 0) { + if (condition) { try { if (!eval(condition)) { if (hint) core.drawTip("当前不可换上" + equip.name); @@ -268,10 +254,8 @@ items.prototype.canEquip = function (equipId, hint) { ////// 换上 ////// items.prototype.loadEquip = function (equipId, callback) { - if (!core.isset(core.status.hero)) return null; - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; if (!this.canEquip(equipId, true)) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } @@ -279,7 +263,7 @@ items.prototype.loadEquip = function (equipId, callback) { var type = this.getEquipTypeById(equipId); if (type < 0) { core.drawTip("当前没有" + loadEquip.equip.type + "的空位!"); - if (core.isset(callback)) callback(); + if (callback) callback(); return; } @@ -288,12 +272,9 @@ items.prototype.loadEquip = function (equipId, callback) { ////// 卸下 ////// items.prototype.unloadEquip = function (equipType, callback) { - if (!core.isset(core.status.hero)) return null; - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - var unloadEquipId = core.status.hero.equipment[equipType]; - if (!core.isset(unloadEquipId)) { - if (core.isset(callback)) callback(); + if (!unloadEquipId) { + if (callback) callback(); return; } @@ -302,13 +283,13 @@ items.prototype.unloadEquip = function (equipType, callback) { items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) { var compareAtk = 0, compareDef = 0, compareMdef = 0; - if (core.isset(compareEquipId)) { + if (compareEquipId) { var compareEquip = core.material.items[compareEquipId]; compareAtk += (compareEquip.equip || {}).atk || 0; compareDef += (compareEquip.equip || {}).def || 0; compareMdef += (compareEquip.equip || {}).mdef || 0; } - if (core.isset(beComparedEquipId)) { + if (beComparedEquipId) { var beComparedEquip = core.material.items[beComparedEquipId]; compareAtk -= (beComparedEquip.equip || {}).atk || 0; compareDef -= (beComparedEquip.equip || {}).def || 0; @@ -334,15 +315,15 @@ items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentag items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { var loadEquip = core.material.items[loadId] || {}, unloadEquip = core.material.items[unloadId] || {}; - if (!core.isset(loadEquip.equip)) loadEquip.equip = {}; - if (!core.isset(unloadEquip.equip)) unloadEquip.equip = {}; + loadEquip.equip = loadEquip.equip || {}; + unloadEquip.equip = unloadEquip.equip || {} var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage; if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) { this.unloadEquip(type); this.loadEquip(loadId); - if (core.isset(callback)) callback(); + if (callback) callback(); return; } @@ -361,12 +342,11 @@ items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { if (loadId) core.drawTip("已装备上" + loadEquip.name, core.material.icons.items[loadId]); else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, core.material.icons.items[unloadId]); - if (core.isset(callback)) callback(); + if (callback) callback(); } ////// 保存装备 ////// items.prototype.quickSaveEquip = function (index) { - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; var saveEquips = core.getFlag("saveEquips", []); saveEquips[index] = core.clone(core.status.hero.equipment); core.setFlag("saveEquips", saveEquips); @@ -376,7 +356,7 @@ items.prototype.quickSaveEquip = function (index) { ////// 读取装备 ////// items.prototype.quickLoadEquip = function (index) { var current = core.getFlag("saveEquips", [])[index]; - if (!core.isset(current)) { + if (!current) { core.drawTip(index + "号套装不存在"); return; } @@ -384,21 +364,20 @@ items.prototype.quickLoadEquip = function (index) { var equipSize = core.status.globalAttribute.equipName.length; for (var i = 0; i < equipSize; i++) { var v = current[i]; - if (core.isset(v) && !this.canEquip(v, true)) + if (v && !this.canEquip(v, true)) return; } // 快速换装 - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; for (var i = 0; i < equipSize; i++) { - var now = core.status.hero.equipment[i] || null; - if (now != null) { + var now = core.status.hero.equipment[i]; + if (now) { this.unloadEquip(i); core.status.route.push("unEquip:" + i); } } for (var i = 0; i < equipSize; i++) { - var to = current[i] || null; - if (to != null) { + var to = current[i]; + if (to) { this.loadEquip(to); core.status.route.push("equip:" + to); } diff --git a/libs/loader.js b/libs/loader.js index 60e81804..5613c33d 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -42,7 +42,7 @@ loader.prototype._loadIcons = function () { for (var key in core.statusBar.icons) { if (typeof core.statusBar.icons[key] == 'number') { core.statusBar.icons[key] = images[core.statusBar.icons[key]]; - if (core.isset(core.statusBar.image[key])) + if (core.statusBar.image[key] != null) core.statusBar.image[key].src = core.statusBar.icons[key].src; } } @@ -82,7 +82,7 @@ loader.prototype._loadAutotiles = function (callback) { loader.prototype._loadTilesets = function (callback) { core.material.images.tilesets = {}; - if (!core.isset(core.tilesets)) core.tilesets = []; + core.tilesets = core.tilesets || []; core.loader.loadImages(core.clone(core.tilesets), core.material.images.tilesets, function () { // 检查宽高是32倍数,如果出错在控制台报错 for (var imgName in core.material.images.tilesets) { @@ -99,8 +99,8 @@ loader.prototype._loadTilesets = function (callback) { } loader.prototype.loadImages = function (names, toSave, callback) { - if (!core.isset(names) || names.length == 0) { - if (core.isset(callback)) callback(); + if (!names || names.length == 0) { + if (callback) callback(); return; } var items = 0; @@ -111,7 +111,7 @@ loader.prototype.loadImages = function (names, toSave, callback) { items++; core.loader._setStartProgressVal(items * (100 / names.length)); if (items == names.length) { - if (core.isset(callback)) callback(); + if (callback) callback(); } }) } @@ -144,7 +144,7 @@ loader.prototype._loadAnimates = function () { data.images = []; data.images_rev = []; content.bitmaps.forEach(function (t2) { - if (!core.isset(t2) || t2 == "") { + if (!t2) { data.images.push(null); } else { @@ -238,7 +238,7 @@ loader.prototype.loadOneSound = function (name) { } loader.prototype.loadBgm = function (name) { - if (!core.isset(core.material.bgms[name])) return; + if (!core.material.bgms[name]) return; // 如果没开启音乐,则不预加载 if (!core.musicStatus.bgmStatus) return; // 是否已经预加载过 @@ -265,7 +265,7 @@ loader.prototype._preloadBgm = function (bgm) { } loader.prototype.freeBgm = function (name) { - if (!core.isset(core.material.bgms[name])) return; + if (!core.material.bgms[name]) return; // 从cachedBgms中删除 core.musicStatus.cachedBgms = core.musicStatus.cachedBgms.filter(function (t) { return t != name; diff --git a/libs/maps.js b/libs/maps.js index af75d570..38ffd862 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -10,7 +10,7 @@ maps.prototype._init = function () { } maps.prototype._setFloorSize = function (floorId) { - if (!core.isset(floorId)) { + if (!floorId) { core.floorIds.forEach(function (floorId) { core.maps._setFloorSize(floorId); }); @@ -25,14 +25,14 @@ maps.prototype._setFloorSize = function (floorId) { ////// 加载某个楼层(从剧本或存档中) ////// maps.prototype.loadFloor = function (floorId, map) { var floor = core.floors[floorId]; - if (!core.isset(map)) map = floor.map; + if (!map) map = floor.map; if (map instanceof Array) { map = {"map": map}; } var content = {}; ["floorId", "title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "cannotMoveDirectly", "color", "weather", "defaultGround", "images", "item_ratio", "upFloor", "bgm", "downFloor", "underGround"].forEach(function (e) { - if (core.isset(map[e])) content[e] = core.clone(map[e]); + if (map[e] != null) content[e] = core.clone(map[e]); else content[e] = core.clone(floor[e]); }); map = this.decompressMap(map.map, floorId); @@ -98,18 +98,18 @@ maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) { ////// 添加一些信息到block上 ////// maps.prototype._addInfo = function (block) { - if (block.event.cls.indexOf("enemy") == 0 && !core.isset(block.event.trigger)) { + if (block.event.cls.indexOf("enemy") == 0 && !block.event.trigger) { block.event.trigger = 'battle'; } - if (block.event.cls == 'items' && !core.isset(block.event.trigger)) { + if (block.event.cls == 'items' && !block.event.trigger) { block.event.trigger = 'getItem'; } - if (!core.isset(block.event.noPass)) { + if (block.event.noPass == null) { if (block.event.cls != 'items') { block.event.noPass = true; } } - if (!core.isset(block.event.animate)) { + if (block.event.animate == null) { block.event.animate = core.icons._getAnimateFrames(block.event.cls, false); } block.event.height = 32; @@ -119,7 +119,7 @@ maps.prototype._addInfo = function (block) { ////// 向该楼层添加剧本的自定义事件 ////// maps.prototype._addEvent = function (block, x, y, event) { - if (!core.isset(event)) return; + if (!event) return; // event是字符串或数组? if (typeof event == "string") { event = {"data": [event]}; @@ -127,11 +127,10 @@ maps.prototype._addEvent = function (block, x, y, event) { else if (event instanceof Array) { event = {"data": event}; } - if (!core.isset(event.data)) - event.data = []; + event.data = event.data || []; // 覆盖enable - if (!core.isset(block.disable) && core.isset(event.enable)) { + if (block.disable == null && event.enable != null) { block.disable = !event.enable; } // 覆盖animate @@ -140,12 +139,12 @@ maps.prototype._addEvent = function (block, x, y, event) { } // 覆盖所有属性 for (var key in event) { - if (key != "enable" && key != "animate" && core.isset(event[key])) { + if (key != "enable" && key != "animate" && event[key] != null) { block.event[key] = core.clone(event[key]); } } // 给无trigger的增加trigger:action - if (!core.isset(block.event.trigger)) { + if (!block.event.trigger) { block.event.trigger = 'action'; } } @@ -167,12 +166,12 @@ maps.prototype._initFloorMap = function (floorId) { var mh = core.floors[floorId].height; for (var x = 0; x < mh; x++) { - if (!core.isset(map[x])) map[x] = []; + if (map[x] == null) map[x] = []; for (var y = 0; y < mw; y++) { - if (!core.isset(map[x][y])) map[x][y] = 0; + if (map[x][y] == null) map[x][y] = 0; // check "disable" var event = core.floors[floorId].events[y + "," + x]; - if (core.isset(event) && event.enable === false && main.mode == 'play') { + if (event && event.enable === false && main.mode == 'play') { map[x][y] += ":f"; } } @@ -208,7 +207,7 @@ maps.prototype.compressMap = function (mapArr, floorId) { ////// 解压缩地图 maps.prototype.decompressMap = function (mapArr, floorId) { var floorMap = this._initFloorMap(floorId); - if (!core.isset(mapArr)) return floorMap; + if (!mapArr) return floorMap; var mw = core.floors[floorId].width; var mh = core.floors[floorId].height; @@ -230,7 +229,7 @@ maps.prototype.decompressMap = function (mapArr, floorId) { ////// 将当前地图重新变成数字,以便于存档 ////// maps.prototype.saveMap = function (floorId) { var maps = core.status.maps; - if (!core.isset(floorId)) { + if (!floorId) { var map = {}; for (var id in maps) { map[id] = this.saveMap(id); @@ -262,7 +261,7 @@ maps.prototype._compressFloorData = function (map, floor) { ////// 将存档中的地图信息重新读取出来 ////// maps.prototype.loadMap = function (data, floorId) { - if (!core.isset(floorId)) { + if (!floorId) { var map = {}; core.floorIds.forEach(function (id) { map[id] = core.maps.loadFloor(id, data[id]); @@ -275,7 +274,7 @@ maps.prototype.loadMap = function (data, floorId) { ////// 更改地图画布的尺寸 maps.prototype.resizeMap = function (floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; core.bigmap.width = core.floors[floorId].width; core.bigmap.height = core.floors[floorId].height; var cwidth = core.bigmap.width * 32; @@ -334,11 +333,11 @@ maps.prototype.getMapBlocksObj = function (floorId, showDisable) { ////// 将背景前景层变成二维数组的形式 ////// maps.prototype.getBgFgMapArray = function (name, floorId, useCache) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return []; + if (!floorId) return []; var width = core.floors[floorId].width; var height = core.floors[floorId].height; - if (useCache && core.isset(core.status[name + "maps"][floorId])) + if (useCache && core.status[name + "maps"][floorId]) return core.status[name + "maps"][floorId]; var arr = core.clone(core.floors[floorId][name + "map"] || []); @@ -363,7 +362,7 @@ maps.prototype.getBgFgMapArray = function (name, floorId, useCache) { ////// 生成全图的当前可移动信息 ////// maps.prototype.generateMovableArray = function (floorId, x, y) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return null; + if (!floorId) return null; var width = core.floors[floorId].width, height = core.floors[floorId].height; var bgArray = this.getBgFgMapArray('bg', floorId, true), fgArray = this.getBgFgMapArray('fg', floorId, true), @@ -377,7 +376,7 @@ maps.prototype.generateMovableArray = function (floorId, x, y) { }); } - if (core.isset(x) && core.isset(y)) return generate(x, y); + if (x != null && y != null) return generate(x, y); var array = []; for (var x = 0; x < width; x++) { array[x] = []; @@ -390,9 +389,9 @@ maps.prototype.generateMovableArray = function (floorId, x, y) { ////// 勇士能否前往某方向 ////// maps.prototype.canMoveHero = function (x, y, direction, floorId) { - if (!core.isset(x)) x = core.getHeroLoc('x'); - if (!core.isset(y)) y = core.getHeroLoc('y'); - if (!core.isset(direction)) direction = core.getHeroLoc('direction'); + if (x == null) x = core.getHeroLoc('x'); + if (y == null) y = core.getHeroLoc('y'); + direction = direction || core.getHeroLoc('direction'); return core.inArray(this.generateMovableArray(floorId, x, y), direction); } @@ -513,7 +512,7 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { ////// 绘制一个图块 ////// maps.prototype.drawBlock = function (block, animate) { if (block.event.id == 'none') return; - var redraw = core.isset(animate); + var redraw = animate != null; if (!redraw) animate = 0; var x = block.x, y = block.y; // --- 在界面外的动画不绘制 @@ -526,7 +525,7 @@ maps.prototype.drawBlock = function (block, animate) { var blockInfo = this.getBlockInfo(block); if (blockInfo == null) return; if (blockInfo.cls != 'tileset') blockInfo.posX = animate % block.event.animate; - if (!core.isset(block.name)) + if (!block.name) this._drawBlockInfo(blockInfo, block.x, block.y); else this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y); @@ -571,8 +570,8 @@ maps.prototype.generateGroundPattern = function (floorId) { ////// 绘制某张地图 ////// maps.prototype.drawMap = function (floorId, callback) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) { - if (core.isset(callback)) callback(); + if (!floorId) { + if (callback) callback(); return; } core.clearMap('all'); @@ -581,14 +580,13 @@ maps.prototype.drawMap = function (floorId, callback) { core.status.thisMap = core.status.maps[floorId]; this._drawMap_drawAll(); - if (core.isset(core.status.curtainColor)) { + if (core.status.curtainColor) { core.fillRect('curtain', 0, 0, core.__PIXELS__, core.__PIXELS__, core.arrayToRGBA(core.status.curtainColor)); } core.drawHero(); core.updateStatusBar(); - if (core.isset(callback)) - callback(); + if (callback) callback(); } maps.prototype._drawMap_drawAll = function (floorId) { @@ -616,7 +614,7 @@ maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, on ////// 绘制背景层 ////// maps.prototype.drawBg = function (floorId, ctx) { - var onMap = !core.isset(ctx); + var onMap = ctx == null; if (onMap) { ctx = core.canvas.bg; core.clearMap(ctx); @@ -631,7 +629,7 @@ maps.prototype._drawBg_drawBackground = function (floorId, ctx) { var width = core.floors[floorId].width, height = core.floors[floorId].height; var groundId = (core.status.maps || core.floors)[floorId].defaultGround || "ground"; var yOffset = core.material.icons.terrains[groundId]; - if (core.isset(yOffset)) { + if (yOffset != null) { for (var i = 0; i < width; i++) { for (var j = 0; j < height; j++) { ctx.drawImage(core.material.images.terrains, 0, yOffset * 32, 32, 32, i * 32, j * 32, 32, 32); @@ -643,9 +641,9 @@ maps.prototype._drawBg_drawBackground = function (floorId, ctx) { ////// 绘制事件层 ////// maps.prototype.drawEvents = function (floorId, blocks, ctx) { floorId = floorId || core.status.floorId; - if (!core.isset(blocks)) blocks = core.status.maps[floorId].blocks; + if (!blocks) blocks = core.status.maps[floorId].blocks; var arr = this.getMapArray(blocks, core.floors[floorId].width, core.floors[floorId].height); - var onMap = !core.isset(ctx); + var onMap = ctx == null; if (onMap) ctx = core.canvas.event; blocks.filter(function (block) { return block.event && !block.disable; @@ -657,7 +655,7 @@ maps.prototype.drawEvents = function (floorId, blocks, ctx) { ////// 绘制前景层 ////// maps.prototype.drawFg = function (floorId, ctx) { - var onMap = !core.isset(ctx); + var onMap = ctx == null; if (onMap) ctx = core.canvas.fg; // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 this._drawFloorImages(floorId, ctx, 'fg'); @@ -667,11 +665,11 @@ maps.prototype.drawFg = function (floorId, ctx) { ////// 实际的背景/前景图块的绘制 ////// maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; var width = core.floors[floorId].width; var height = core.floors[floorId].height; - if (!core.isset(core.status[name + "maps"])) + if (!core.status[name + "maps"]) core.status[name + "maps"] = {}; var arr = this.getBgFgMapArray(name, floorId); @@ -680,7 +678,7 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { var block = this.initBlock(x, y, arr[y][x], true); block.name = name; var blockInfo = this.getBlockInfo(block); - if (!core.isset(blockInfo)) continue; + if (!blockInfo) continue; this._drawMap_drawBlockInfo(ctx, block, blockInfo, arr, onMap); } } @@ -691,8 +689,8 @@ maps.prototype._drawBgFgMap = function (floorId, ctx, name, onMap) { ////// 绘制楼层贴图 ////// maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStatus) { floorId = floorId || core.status.floorId; - if (!core.isset(images)) images = this._getFloorImages(floorId); - var redraw = core.isset(currStatus); + if (!images) images = this._getFloorImages(floorId); + var redraw = currStatus != null; if (!redraw) core.status.floorAnimateObjs = core.clone(images); images.forEach(function (t) { if (typeof t == 'string') t = [0, 0, t]; @@ -700,7 +698,7 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat var image = core.material.images.images[imageName]; if (redraw && frame == 1) return; // 不重绘 - if (core.isset(dx) && core.isset(dy) && core.isset(image) && + if (core.isset(dx) && core.isset(dy) && image && !core.hasFlag("__floorImg__" + floorId + "_" + dx + "_" + dy)) { var width = parseInt(image.width / frame), offsetX = (currStatus || 0) % frame * width; if (/.*\.gif/i.test(imageName) && main.mode == 'play') { @@ -716,7 +714,7 @@ maps.prototype._drawFloorImages = function (floorId, ctx, name, images, currStat maps.prototype._getFloorImages = function (floorId) { floorId = floorId || core.status.floorId; var images = []; - if (core.isset((core.status.maps || core.floors)[floorId].images)) { + if ((core.status.maps || core.floors)[floorId].images) { images = (core.status.maps || core.floors)[floorId].images; if (typeof images == 'string') { images = [[0, 0, images]]; @@ -897,7 +895,7 @@ maps.prototype._makeAutotileEdges = function () { // all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心) maps.prototype.drawThumbnail = function (floorId, blocks, options, toDraw) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; // Step1:绘制到tempCanvas上 this._drawThumbnail_drawTempCanvas(floorId, blocks, options); // Step2:从tempCanvas绘制到对应的画布上 @@ -905,8 +903,8 @@ maps.prototype.drawThumbnail = function (floorId, blocks, options, toDraw) { } maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) { - if (!core.isset(blocks)) blocks = core.status.maps[floorId].blocks; - if (!core.isset(options)) options = {}; + blocks = blocks || core.status.maps[floorId].blocks; + options = options || {} var width = core.floors[floorId].width; var height = core.floors[floorId].height; @@ -918,7 +916,7 @@ maps.prototype._drawThumbnail_drawTempCanvas = function (floorId, blocks, option tempCanvas.clearRect(0, 0, tempWidth, tempHeight); // --- 暂存 flags - var hasHero = core.isset(core.status.hero), flags = null; + var hasHero = core.status.hero != null, flags = null; if (options.flags) { if (!hasHero) core.status.hero = {}; flags = core.status.hero.flags; @@ -953,15 +951,15 @@ maps.prototype._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, op } maps.prototype._drawThumbnail_drawToTarget = function (floorId, toDraw) { - if (!core.isset(toDraw)) return; + if (toDraw == null) return; if (typeof toDraw == 'string' || toDraw.canvas) toDraw = {ctx: toDraw}; var ctx = core.getContextByName(toDraw.ctx); if (ctx == null) return; var x = toDraw.x || 0, y = toDraw.y || 0, size = toDraw.size || core.__PIXELS__; var width = core.floors[floorId].width, height = core.floors[floorId].height; var centerX = toDraw.centerX, centerY = toDraw.centerY; - if (!core.isset(centerX)) centerX = Math.floor(width / 2); - if (!core.isset(centerY)) centerY = Math.floor(height / 2); + 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; core.clearMap(ctx, x, y, size, size); @@ -996,7 +994,7 @@ 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 core.isset(block.block.event.noPass) && block.block.event.noPass; + return block.block.event.noPass; } ////// 某个点是否存在NPC ////// @@ -1010,7 +1008,7 @@ maps.prototype.npcExists = function (x, y, floorId) { 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' && (core.isset(id) ? block.block.event.id == id : true); + return block.block.event.cls == 'terrains' && (id ? block.block.event.id == id : true); } ////// 某个点是否存在楼梯 ////// @@ -1030,16 +1028,16 @@ 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 && (core.isset(id) ? block.block.event.id == id : true); + return block.block.event.cls.indexOf('enemy') == 0 && (id ? block.block.event.id == id : true); } ////// 获得某个点的block ////// maps.prototype.getBlock = function (x, y, floorId, showDisable) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return null; + if (!floorId) return null; var blocks = core.status.maps[floorId].blocks; for (var n = 0; n < blocks.length; n++) { - if (blocks[n].x == x && blocks[n].y == y && core.isset(blocks[n].event)) { + if (blocks[n].x == x && blocks[n].y == y) { if (!showDisable && blocks[n].disable) return null; return {"index": n, "block": blocks[n]}; } @@ -1061,7 +1059,7 @@ maps.prototype.getBlockCls = function (x, y, floorId, showDisable) { ////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 ////// maps.prototype.getBlockInfo = function (block) { - if (!core.isset(block)) return null; + if (!block) return null; if (typeof block == 'string') { // 参数是ID block = this.getNumberById(block); } @@ -1075,7 +1073,7 @@ maps.prototype.getBlockInfo = function (block) { if (id == 'none') return null; else if (id == 'airwall') { - if (!core.isset(core.material.images.airwall)) return null; + if (!core.material.images.airwall) return null; image = core.material.images.airwall; } else if (cls == 'tileset') { @@ -1121,7 +1119,7 @@ maps.prototype.searchBlock = function (id, floorId, showDisable) { ////// 将某个块从禁用变成启用状态 ////// maps.prototype.showBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; var block = core.getBlock(x, y, floorId, true); if (block == null) return; // 不存在 block = block.block; @@ -1140,7 +1138,7 @@ maps.prototype.showBlock = function (x, y, floorId) { ////// 只隐藏但不删除某块 ////// maps.prototype.hideBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; var block = core.getBlock(x, y, floorId, true); if (block == null) return; // 不存在 @@ -1161,7 +1159,7 @@ maps.prototype.hideBlock = function (x, y, floorId) { ////// 将某个块从启用变成禁用状态 ////// maps.prototype.removeBlock = function (x, y, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; var block = core.getBlock(x, y, floorId, true); if (block == null) return; // 不存在 @@ -1185,7 +1183,7 @@ maps.prototype.removeBlock = function (x, y, floorId) { ////// 根据block的索引(尽可能)删除该块 ////// maps.prototype.removeBlockById = function (index, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; var blocks = core.status.maps[floorId].blocks, block = blocks[index]; @@ -1213,7 +1211,7 @@ maps.prototype.canRemoveBlock = function (block, floorId) { ////// 一次性删除多个block ////// maps.prototype.removeBlockByIds = function (floorId, ids) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; ids.sort(function (a, b) { return b - a }).forEach(function (id) { @@ -1258,7 +1256,7 @@ maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) { if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; if (loc.length == 0) return; loc.forEach(function (t) { @@ -1273,7 +1271,7 @@ maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) { core.drawMap(floorId, callback); } else { - if (core.isset(callback)) callback(); + if (callback) callback(); } } @@ -1293,7 +1291,7 @@ maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) { if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; if (loc.length == 0) return; loc.forEach(function (t) { @@ -1307,15 +1305,14 @@ maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) { core.drawMap(floorId, callback); } else { - if (core.isset(callback)) callback(); + if (callback) callback(); } } ////// 改变图块 ////// maps.prototype.setBlock = function (number, x, y, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; + 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; var originBlock = core.getBlock(x, y, floorId, true); @@ -1347,8 +1344,7 @@ maps.prototype.setBlock = function (number, x, y, floorId) { ////// 改变前景背景的图块 ////// maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; - if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return; + 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; @@ -1363,7 +1359,7 @@ maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { ////// 重置地图 ////// maps.prototype.resetMap = function (floorId) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!floorId) return; if (typeof floorId == 'string') floorId = [floorId]; var needRefresh = false; floorId.forEach(function (t) { @@ -1458,7 +1454,7 @@ maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) { time = time || 500; var blockArr = this._getAndRemoveBlock(x, y); if (blockArr == null) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } var block = blockArr[0], blockInfo = blockArr[1]; @@ -1499,9 +1495,9 @@ maps.prototype._moveBlock_moving = function (blockInfo, canvases, moveInfo) { moveInfo.y += core.utils.scan[direction].y; // 根据faceIds修改朝向 var currid = blockInfo.faceIds[direction]; - if (core.isset(currid)) { + if (currid) { var posY = core.material.icons[blockInfo.cls][currid]; - if (core.isset(posY)) blockInfo.posY = posY; + if (posY != null) blockInfo.posY = posY; } } moveInfo.step++; @@ -1519,7 +1515,7 @@ maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) { time = time || 500; var blockArr = this._getAndRemoveBlock(sx, sy); if (blockArr == null) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } var block = blockArr[0], blockInfo = blockArr[1]; @@ -1579,7 +1575,7 @@ maps.prototype._moveJumpBlock_finished = function (blockInfo, canvases, info, an core.setBlock(blockInfo.number, info.x, info.y); core.showBlock(info.x, info.y); } - if (core.isset(callback)) callback(); + if (callback) callback(); } else { this._moveDetachedBlock(blockInfo, info.px, info.py, info.opacity, canvases); @@ -1593,7 +1589,7 @@ maps.prototype.animateBlock = function (loc, type, time, callback) { loc = [loc]; var list = this._animateBlock_getList(loc); if (list.length == 0) { - if (core.isset(callback)) callback(); + if (callback) callback(); return; } this._animateBlock_drawList(list, isHide ? 1 : 0); @@ -1615,7 +1611,7 @@ maps.prototype._animateBlock_doAnimate = function (loc, list, isHide, delta, cal if (isHide) core.removeBlock(t[0], t[1]); else core.showBlock(t[0], t[1]); }); - if (core.isset(callback)) callback(); + if (callback) callback(); } }, 10); @@ -1651,14 +1647,14 @@ maps.prototype._animateBlock_drawList = function (list, opacity) { ////// 添加一个全局动画 ////// maps.prototype.addGlobalAnimate = function (b) { - if (!core.isset(b.event) || !core.isset(b.event.animate)) return; + if (!b.event || b.event.animate == null) return; if (b.event.cls == 'autotile') { var id = b.event.id, img = core.material.images.autotile[id]; - if (!core.isset(img) || img.width == 96) return; + if (!img || img.width == 96) return; core.status.autotileAnimateObjs.blocks.push(b); } else { - if (!core.isset(b.event.animate) || b.event.animate == 1) return; + if (!b.event.animate || b.event.animate == 1) return; core.status.globalAnimateObjs.push(b); } } @@ -1666,7 +1662,7 @@ maps.prototype.addGlobalAnimate = function (b) { ////// 删除一个或所有全局动画 ////// maps.prototype.removeGlobalAnimate = function (x, y, name) { // 没有定义xy,则全部删除 - if (!core.isset(x) || !core.isset(y)) { + if (x == null || y == null) { core.status.globalAnimateStatus = 0; core.status.globalAnimateObjs = []; core.status.autotileAnimateObjs = {"blocks": [], "map": null, "bgmap": null, "fgmap": null}; @@ -1679,7 +1675,7 @@ maps.prototype.removeGlobalAnimate = function (x, y, name) { }); // 检查Autotile - if (core.isset(core.status.autotileAnimateObjs.blocks)) { + 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; }); @@ -1703,13 +1699,13 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { // 正在播放录像:不显示动画 if (core.isReplaying()) { - if (core.isset(callback)) callback(); + if (callback) callback(); return -1; } // 检测动画是否存在 - if (!core.isset(core.material.animates[name]) || !core.isset(x) || !core.isset(y)) { - if (core.isset(callback)) callback(); + if (!core.material.animates[name] || x == null || y == null) { + if (callback) callback(); return -1; } @@ -1738,7 +1734,7 @@ maps.prototype._drawAnimateFrame = function (animate, centerX, centerY, index) { var ratio = animate.ratio; frame.forEach(function (t) { var image = animate.images[t.index]; - if (!core.isset(image)) return; + if (!image) return; var realWidth = image.width * ratio * t.zoom / 100; var realHeight = image.height * ratio * t.zoom / 100; core.setAlpha('animate', t.opacity / 255); @@ -1771,8 +1767,7 @@ maps.prototype.stopAnimate = function (id, doCallback) { if (doCallback) { (function (callback) { setTimeout(function () { - if (core.isset(callback)) - callback(); + if (callback) callback(); }); })(obj.callback); } diff --git a/libs/utils.js b/libs/utils.js index 9cb77897..3c574036 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -61,7 +61,7 @@ utils.prototype.replaceText = function (text, need, times) { ////// 计算表达式的值 ////// utils.prototype.calValue = function (value, prefix, need, times) { - if (!core.isset(value)) return value; + if (!core.isset(value)) return null; if (typeof value === 'string') { value = value.replace(/status:([\w\d_]+)/g, "core.getStatus('$1')"); value = value.replace(/item:([\w\d_]+)/g, "core.itemCount('$1')"); @@ -77,7 +77,7 @@ utils.prototype.calValue = function (value, prefix, need, times) { ////// 字符串自动换行的分割 ////// utils.prototype.splitLines = function (canvas, text, maxLength, font) { - if (core.isset(font)) core.setFont(canvas, font); + if (font) core.setFont(canvas, font); var contents = []; var last = 0; @@ -94,7 +94,7 @@ utils.prototype.splitLines = function (canvas, text, maxLength, font) { else { var toAdd = text.substring(last, i + 1); var width = core.calWidth(canvas, toAdd); - if (core.isset(maxLength) && width > maxLength) { + if (maxLength && width > maxLength) { contents.push(text.substring(last, i)); last = i; } @@ -106,7 +106,7 @@ utils.prototype.splitLines = function (canvas, text, maxLength, font) { ////// 向某个数组前插入另一个数组或元素 ////// utils.prototype.unshift = function (a, b) { - if (!(a instanceof Array) || !core.isset(b)) return; + if (!(a instanceof Array) || b == null) return; if (b instanceof Array) { core.clone(b).reverse().forEach(function (e) { a.unshift(e); @@ -118,7 +118,7 @@ utils.prototype.unshift = function (a, b) { ////// 向某个数组后插入另一个数组或元素 ////// utils.prototype.push = function (a, b) { - if (!(a instanceof Array) || !core.isset(b)) return; + if (!(a instanceof Array) || b == null) return; if (b instanceof Array) { core.clone(b).forEach(function (e) { a.push(e); @@ -131,7 +131,7 @@ utils.prototype.push = function (a, b) { ////// 设置本地存储 ////// utils.prototype.setLocalStorage = function (key, value) { try { - if (!core.isset(value)) { + if (value == null) { this.removeLocalStorage(key); return; } @@ -166,15 +166,13 @@ utils.prototype.setLocalStorage = function (key, value) { utils.prototype.decompress = function (value) { try { var output = lzw_decode(value); - if (core.isset(output) && output.length > 0) - return JSON.parse(output); + if (output) return JSON.parse(output); } catch (e) { } try { var output = LZString.decompress(value); - if (core.isset(output) && output.length > 0) - return JSON.parse(output); + if (output) return JSON.parse(output); } catch (e) { } @@ -204,15 +202,15 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal if (!core.platform.useLocalForage) { if (this.setLocalStorage(key, value)) { - if (core.isset(successCallback)) successCallback(); + if (successCallback) successCallback(); } else { - if (core.isset(errorCallback)) errorCallback(); + if (errorCallback) errorCallback(); } return; } - if (!core.isset(value)) { + if (value == null) { this.removeLocalForage(key); return; } @@ -222,13 +220,13 @@ utils.prototype.setLocalForage = function (key, value, successCallback, errorCal return "\\u" + ("0000" + chr.charCodeAt(0).toString(16)).substr(-4) })); localforage.setItem(core.firstData.name + "_" + key, compressed, function (err) { - if (core.isset(err)) { - if (core.isset(errorCallback)) errorCallback(err); + if (err) { + if (errorCallback) errorCallback(err); } else { if (key == 'autoSave') core.saves.ids[0] = true; else if (/^save\d+$/.test(key)) core.saves.ids[parseInt(key.substring(4))] = true; - if (core.isset(successCallback)) successCallback(); + if (successCallback) successCallback(); } }); } @@ -237,19 +235,17 @@ utils.prototype.getLocalForage = function (key, defaultValue, successCallback, e if (!core.platform.useLocalForage) { var value = this.getLocalStorage(key, defaultValue); - if (core.isset(successCallback)) { - successCallback(value); - } + if (successCallback) successCallback(value); return; } localforage.getItem(core.firstData.name + "_" + key, function (err, value) { - if (core.isset(err)) { - if (core.isset(errorCallback)) errorCallback(err); + if (err) { + if (errorCallback) errorCallback(err); } else { - if (!core.isset(successCallback)) return; - if (core.isset(value)) { + if (!successCallback) return; + if (value != null) { var res = core.utils.decompress(value); successCallback(res == null ? defaultValue : res); return; @@ -263,25 +259,25 @@ utils.prototype.removeLocalForage = function (key, successCallback, errorCallbac if (!core.platform.useLocalForage) { this.removeLocalStorage(key); - if (core.isset(successCallback)) successCallback(); + if (successCallback) successCallback(); return; } localforage.removeItem(core.firstData.name + "_" + key, function (err) { - if (core.isset(err)) { - if (core.isset(errorCallback)) errorCallback(err); + if (err) { + if (errorCallback) errorCallback(err); } else { if (key == 'autoSave') delete core.saves.ids[0]; else if (/^save\d+$/.test(key)) delete core.saves.ids[parseInt(key.substring(4))]; - if (core.isset(successCallback)) successCallback(); + if (successCallback) successCallback(); } }) } ////// 深拷贝一个对象 ////// utils.prototype.clone = function (data) { - if (!core.isset(data)) return data; + if (!core.isset(data)) return null; // date if (data instanceof Date) { var copy = new Date(); @@ -334,14 +330,14 @@ utils.prototype.cropImage = function (image, size) { ////// 格式化时间为字符串 ////// utils.prototype.formatDate = function (date) { - if (!core.isset(date)) return ""; + if (!date) date = new Date(); return "" + date.getFullYear() + "-" + core.setTwoDigits(date.getMonth() + 1) + "-" + core.setTwoDigits(date.getDate()) + " " + core.setTwoDigits(date.getHours()) + ":" + core.setTwoDigits(date.getMinutes()) + ":" + core.setTwoDigits(date.getSeconds()); } ////// 格式化时间为最简字符串 ////// utils.prototype.formatDate2 = function (date) { - if (!core.isset(date)) return ""; + if (!date) date = new Date(); return "" + date.getFullYear() + core.setTwoDigits(date.getMonth() + 1) + core.setTwoDigits(date.getDate()) + core.setTwoDigits(date.getHours()) + core.setTwoDigits(date.getMinutes()) + core.setTwoDigits(date.getSeconds()); } @@ -395,7 +391,7 @@ utils.prototype.arrayToRGB = function (color) { } utils.prototype.arrayToRGBA = function (color) { - if (!this.isset(color[3])) color[3] = 1; + if (color[3] == null) color[3] = 1; var nowR = this.clamp(parseInt(color[0]), 0, 255), nowG = this.clamp(parseInt(color[1]), 0, 255), nowB = this.clamp(parseInt(color[2]), 0, 255), nowA = this.clamp(parseFloat(color[3]), 0, 1); return "rgba(" + nowR + "," + nowG + "," + nowB + "," + nowA + ")"; @@ -472,12 +468,12 @@ utils.prototype._encodeRoute_encodeOne = function (t) { ////// 解密路线 ////// utils.prototype.decodeRoute = function (route) { - if (!core.isset(route)) return route; + if (!route) return route; // 解压缩 try { var v = LZString.decompressFromBase64(route); - if (core.isset(v) && /^[a-zA-Z0-9+\/=:]*$/.test(v)) { + if (/^[a-zA-Z0-9+\/=:]*$/.test(v)) { route = v; } } catch (e) { @@ -496,7 +492,7 @@ utils.prototype._decodeRoute_getNumber = function (decodeObj, noparse) { num += decodeObj.route.charAt(decodeObj.index++); } if (num.length == 0) num = "1"; - return core.isset(noparse) ? num : parseInt(num); + return noparse ? num : parseInt(num); } utils.prototype._decodeRoute_getString = function (decodeObj) { @@ -511,7 +507,7 @@ utils.prototype._decodeRoute_getString = function (decodeObj) { utils.prototype._decodeRoute_number2id = function (number) { if (/^\d+$/.test(number)) { var info = core.maps.blocksInfo[number]; - if (core.isset(info)) return info.id; + if (info) return info.id; } return number; } @@ -578,17 +574,14 @@ utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { } } -////// 判断某对象是否不为undefined也不会null ////// +////// 判断某对象是否不为null也不为NaN ////// utils.prototype.isset = function (val) { - if (val == undefined || val == null || (typeof val == 'number' && isNaN(val))) { - return false; - } - return true + return val != null && !(typeof val == 'number' && isNaN(val)); } ////// 获得子数组 ////// utils.prototype.subarray = function (a, b) { - if (!core.isset(a) || !core.isset(b) || !(a instanceof Array) || !(b instanceof Array) || a.length < b.length) + if (!(a instanceof Array) || !(b instanceof Array) || a.length < b.length) return null; var na = core.clone(a), nb = core.clone(b); while (nb.length > 0) { @@ -598,7 +591,7 @@ utils.prototype.subarray = function (a, b) { } utils.prototype.inArray = function (array, element) { - return this.isset(array) && (array instanceof Array) && array.indexOf(element) >= 0; + return (array instanceof Array) && array.indexOf(element) >= 0; } utils.prototype.clamp = function (x, a, b) { @@ -618,7 +611,7 @@ utils.prototype.expandMoveSteps = function (steps) { moveSteps.push(e); } else { - if (!core.isset(e.value)) { + if (e.value == null) { moveSteps.push(e.direction) } else { @@ -640,7 +633,7 @@ utils.prototype.setStatusBarInnerHTML = function (name, value, css) { // 判定是否需要缩放 var length = this.strlen(value) || 1; style += 'font-size: ' + Math.min(1, 7 / length) + 'em; '; - if (core.isset(css)) style += css; + if (css) style += css; core.statusBar[name].innerHTML = "" + value + ""; } @@ -691,7 +684,7 @@ utils.prototype.rand = function (num) { rand = this.__next_rand(rand); core.setFlag('__rand__', rand); var ans = rand / 2147483647; - if (core.isset(num) && num > 0) + if (num && num > 0) return Math.floor(ans * num); return ans; } @@ -740,7 +733,7 @@ utils.prototype.readFile = function (success, error, readType) { core.platform.successCallback = success; core.platform.errorCallback = error; - if (core.isset(window.jsinterface)) { + if (window.jsinterface) { window.jsinterface.readFile(); return; } @@ -748,14 +741,14 @@ utils.prototype.readFile = function (success, error, readType) { // step 0: 不为http/https,直接不支持 if (!core.platform.isOnline) { alert("离线状态下不支持文件读取!"); - if (core.isset(error)) error(); + if (error) error(); return; } // Step 1: 如果不支持FileReader,直接不支持 if (core.platform.fileReader == null) { alert("当前浏览器不支持FileReader!"); - if (core.isset(error)) error(); + if (error) error(); return; } @@ -766,7 +759,7 @@ utils.prototype.readFile = function (success, error, readType) { core.platform.fileInput.onchange = function () { var files = core.platform.fileInput.files; if (files.length == 0) { - if (core.isset(core.platform.errorCallback)) + if (core.platform.errorCallback) core.platform.errorCallback(); return; } @@ -783,14 +776,14 @@ utils.prototype.readFile = function (success, error, readType) { utils.prototype.readFileContent = function (content) { var obj = null; if (content.slice(0, 4) === 'data') { - if (core.isset(core.platform.successCallback)) + if (core.platform.successCallback) core.platform.successCallback(content); return; } try { obj = JSON.parse(content); - if (core.isset(obj)) { - if (core.isset(core.platform.successCallback)) + if (obj) { + if (core.platform.successCallback) core.platform.successCallback(obj); return; } @@ -801,14 +794,14 @@ utils.prototype.readFileContent = function (content) { } alert("不是有效的JSON文件!"); - if (core.isset(core.platform.errorCallback)) + if (core.platform.errorCallback) core.platform.errorCallback(); } ////// 下载文件到本地 ////// utils.prototype.download = function (filename, content) { - if (core.isset(window.jsinterface)) { + if (window.jsinterface) { window.jsinterface.download(filename, content); return; } @@ -873,8 +866,8 @@ utils.prototype.download = function (filename, content) { ////// 复制一段内容到剪切板 ////// utils.prototype.copy = function (data) { - if (core.isset(window.jsinterface)) { - window.jsinterface.copy(filename, content); + if (window.jsinterface) { + window.jsinterface.copy(data); return true; } @@ -909,9 +902,9 @@ utils.prototype.copy = function (data) { ////// 动画显示某对象 ////// utils.prototype.show = function (obj, speed, callback) { obj.style.display = 'block'; - if (!core.isset(speed) && main.mode != 'play') { + if (!speed && main.mode != 'play') { obj.style.opacity = 1; - if (core.isset(callback)) callback(); + if (callback) callback(); return; } obj.style.opacity = 0; @@ -921,18 +914,16 @@ utils.prototype.show = function (obj, speed, callback) { obj.style.opacity = opacityVal; if (opacityVal > 1) { clearInterval(showAnimate); - if (core.isset(callback)) { - callback(); - } + if (callback) callback(); } }, speed); } ////// 动画使某对象消失 ////// utils.prototype.hide = function (obj, speed, callback) { - if (!core.isset(speed) || main.mode != 'play') { + if (!speed || main.mode != 'play') { obj.style.display = 'none'; - if (core.isset(callback)) callback(); + if (callback) callback(); return; } obj.style.opacity = 1; @@ -943,9 +934,7 @@ utils.prototype.hide = function (obj, speed, callback) { if (opacityVal < 0) { obj.style.display = 'none'; clearInterval(hideAnimate); - if (core.isset(callback)) { - callback(); - } + if (callback) callback(); } }, speed); } @@ -984,7 +973,7 @@ utils.prototype.decodeCanvas = function (arr, width, height) { tempCanvas.canvas.height = height; tempCanvas.clearRect(0, 0, width, height); - if (!core.isset(arr)) return null; + if (!arr) return null; // to byte array var curr = 0, list = []; arr.forEach(function (x) { @@ -1028,8 +1017,8 @@ utils.prototype.hashCode = function (obj) { } utils.prototype.same = function (a, b) { - if (!core.isset(a) && !core.isset(b)) return true; - if (!core.isset(a) || !core.isset(b)) return false; + if (a == null && b == null) return true; + if (a == null || b == null) return false; if (a === b) return true; if (a instanceof Array && b instanceof Array) { if (a.length != b.length) return false; @@ -1051,14 +1040,14 @@ utils.prototype.same = function (a, b) { } utils.prototype._export = function (floorIds) { - if (!core.isset(floorIds)) floorIds = [core.status.floorId]; + if (!floorIds) floorIds = [core.status.floorId]; else if (floorIds == 'all') floorIds = core.clone(core.floorIds); else if (typeof floorIds == 'string') floorIds = [floorIds]; var monsterMap = {}; // map - var content = floorIds.length + "\n13 13\n\n"; + var content = floorIds.length + "\n" + core.__SIZE__ + " " + core.__SIZE__ + "\n\n"; floorIds.forEach(function (floorId) { var arr = core.maps.getMapArray(core.status.maps[floorId].blocks, 13, 13); content += arr.map(function (x) { @@ -1098,34 +1087,26 @@ utils.prototype._export = function (floorIds) { utils.prototype.http = function (type, url, formData, success, error, mimeType, responseType) { var xhr = new XMLHttpRequest(); xhr.open(type, url, true); - if (core.isset(mimeType)) - xhr.overrideMimeType(mimeType); - if (core.isset(responseType)) - xhr.responseType = responseType; + if (mimeType) xhr.overrideMimeType(mimeType); + if (responseType) xhr.responseType = responseType; xhr.onload = function (e) { if (xhr.status == 200) { - if (core.isset(success)) { - success(xhr.response); - } + if (success) success(xhr.response); } else { - if (core.isset(error)) - error("HTTP " + xhr.status); + if (error) error("HTTP " + xhr.status); } }; xhr.onabort = function () { - if (core.isset(error)) - error("Abort"); + if (error) error("Abort"); } xhr.ontimeout = function () { - if (core.isset(error)) - error("Timeout"); + if (error) error("Timeout"); } xhr.onerror = function () { - if (core.isset(error)) - error("Error on Connection"); + if (error) error("Error on Connection"); } - if (core.isset(formData)) + if (formData) xhr.send(formData); else xhr.send(); } diff --git a/project/functions.js b/project/functions.js index bce959c7..18d5cc6d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -122,25 +122,23 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.drawMap(floorId); // 切换楼层BGM - if (core.isset(core.status.maps[floorId].bgm)) { + if (core.status.maps[floorId].bgm) { var bgm = core.status.maps[floorId].bgm; if (bgm instanceof Array) bgm = bgm[0]; core.playBgm(bgm); } // 更改画面色调 var color = core.getFlag('__color__', null); - if (!core.isset(color) && core.isset(core.status.maps[floorId].color)) + if (!color && core.status.maps[floorId].color) color = core.status.maps[floorId].color; core.clearMap('curtain'); core.status.curtainColor = color; - if (core.isset(color)) { - core.fillRect('curtain',0,0,416,416,core.arrayToRGBA(color)); - } + if (color) core.fillRect('curtain', 0, 0, core.__SIZE__, core.__SIZE__, core.arrayToRGBA(color)); // 更改天气 var weather = core.getFlag('__weather__', null); - if (!core.isset(weather) && core.isset(core.status.maps[floorId].weather)) + if (!weather && core.status.maps[floorId].weather) weather = core.status.maps[floorId].weather; - if (core.isset(weather)) + if (weather) core.setWeather(weather[0], weather[1]); else core.setWeather(); @@ -172,7 +170,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 返回true则将继续战斗,返回false将不再战斗。 // ------ 支援技能 ------ // - if (core.isset(x) && core.isset(y)) { + if (x != null && y != null) { var index = x + "," + y, cache = (core.status.checkBlock.cache || {})[index] || {}, guards = cache.guards || []; @@ -204,13 +202,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 播放战斗音效和动画 var equipAnimate = 'hand', equipId = (core.status.hero.equipment || [])[0]; - if (core.isset(equipId) && core.isset((core.material.items[equipId].equip || {}).animate)) + if (equipId && (core.material.items[equipId].equip || {}).animate) equipAnimate = core.material.items[equipId].equip.animate; // 检查equipAnimate是否存在SE,如果不存在则使用默认音效 - if (!core.isset((core.material.animates[equipAnimate] || {}).se)) + if (!(core.material.animates[equipAnimate] || {}).se) core.playSound('attack.mp3'); // 强制战斗的战斗动画 - core.drawAnimate(equipAnimate, core.isset(x) ? x : core.getHeroLoc('x'), core.isset(y) ? y : core.getHeroLoc('y')); + core.drawAnimate(equipAnimate, x != null ? x : core.getHeroLoc('x'), y != null ? y : core.getHeroLoc('y')); var damage = core.enemys.getDamage(enemyId, x, y); if (damage == null) damage = core.status.hero.hp + 1; @@ -231,7 +229,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 删除该块 var guards = []; // 支援 - if (core.isset(x) && core.isset(y)) { + if (x != null && y != null) { core.removeBlock(x, y); guards = core.getFlag("__guards__" + x + "_" + y, []); core.removeFlag("__guards__" + x + "_" + y); @@ -310,15 +308,13 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果有加点 var point = core.material.enemys[enemyId].point; - if (core.flags.enableAddPoint && core.isset(point) && point > 0) { + if (core.flags.enableAddPoint && point > 0) { core.push(todo, [{ "type": "setValue", "name": "flag:point", "value": point }]); core.push(todo, [{ "type": "insert", "name": "加点事件" }]); } - // 如果该点存在,且有事件 -- V2.5.4 以后阻击怪也可以有战后事件了 - if (core.isset(x) && core.isset(y)) { - core.push(todo, core.floors[core.status.floorId].afterBattle[x + "," + y]); - } + // 如果该点存在事件 -- V2.5.4 以后阻击怪也可以有战后事件了 + core.push(todo, core.floors[core.status.floorId].afterBattle[x + "," + y]); // 在这里增加其他的自定义事件需求 /* @@ -330,58 +326,44 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = */ // 如果事件不为空,将其插入 - if (todo.length > 0) { - core.events.insertAction(todo, x, y); - } + if (todo.length > 0) core.insertAction(todo, x, y); // 如果已有事件正在处理中 - if (core.status.event.id == null) { + if (core.status.event.id == null) core.continueAutomaticRoute(); - } else { + else core.clearContinueAutomaticRoute(); - } - if (core.isset(callback)) callback(); + + if (callback) callback(); }, "afterOpenDoor": function (doorId, x, y, callback) { // 开一个门后触发的事件 var todo = []; - if (core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterOpenDoor[x + "," + y]; - if (core.isset(event)) { - core.unshift(todo, event); - } - } + var event = core.floors[core.status.floorId].afterOpenDoor[x + "," + y]; + if (event) core.unshift(todo, event); - if (todo.length > 0) { - core.events.insertAction(todo, x, y); - } + if (todo.length > 0) core.insertAction(todo, x, y); - if (core.status.event.id == null) { + if (core.status.event.id == null) core.continueAutomaticRoute(); - } else { + else core.clearContinueAutomaticRoute(); - } - if (core.isset(callback)) callback(); + + if (callback) callback(); }, "afterGetItem": function (itemId, x, y, callback) { // 获得一个道具后触发的事件 core.playSound('item.mp3'); var todo = []; - if (core.isset(x) && core.isset(y)) { - var event = core.floors[core.status.floorId].afterGetItem[x + "," + y]; - if (core.isset(event)) { - core.unshift(todo, event); - } - } + var event = core.floors[core.status.floorId].afterGetItem[x + "," + y]; + if (event) core.unshift(todo, event); - if (todo.length > 0) { - core.events.insertAction(todo, x, y); - } + if (todo.length > 0) core.insertAction(todo, x, y); - if (core.isset(callback)) callback(); + if (callback) callback(); }, "afterChangeLight": function(x,y) { // 改变亮灯之后,可以触发的事件 @@ -516,10 +498,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // ------ 支援 ------ var guards = []; // 检查光环缓存 - if (!core.isset(core.status.checkBlock.cache)) core.status.checkBlock.cache = {}; - var index = core.isset(x) && core.isset(y) ? (x + "," + y) : "floor"; + if (!core.status.checkBlock.cache) core.status.checkBlock.cache = {}; + var index = x != null && y != null ? (x + "," + y) : "floor"; var cache = core.status.checkBlock.cache[index]; - if (!core.isset(cache)) { + if (!cache) { // 没有该点的缓存,则遍历每个图块 core.status.maps[floorId].blocks.forEach(function (block) { if (!block.disable) { @@ -527,7 +509,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var id = block.event.id, enemy = core.material.enemys[id]; // 检查是不是怪物,且是否拥有该特殊属性 - if (core.isset(enemy) && core.hasSpecial(enemy.special, 25)) { + if (enemy && core.hasSpecial(enemy.special, 25)) { // 检查是否可叠加 if (enemy.add || cnt == 0) { hp_buff += enemy.value || 0; @@ -537,10 +519,10 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } // 检查【支援】技能 - if (core.isset(enemy) && core.hasSpecial(enemy.special, 26) && + if (enemy && core.hasSpecial(enemy.special, 26) && // 检查支援条件,坐标存在,距离为1,且不能是自己 // 其他类型的支援怪,比如十字之类的话.... 看着做是一样的 - core.isset(x) && core.isset(y) && Math.abs(block.x - x) <= 1 && Math.abs(block.y - y) <= 1 && !(x == block.x && y == block.y)) { + x != null && y != null && Math.abs(block.x - x) <= 1 && Math.abs(block.y - y) <= 1 && !(x == block.x && y == block.y)) { // 记录怪物的x,y,ID guards.push([block.x, block.y, id]); } @@ -959,8 +941,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var statusList = ['hpmax', 'hp', 'mana', 'atk', 'def', 'mdef', 'money', 'experience']; statusList.forEach(function (item) { // 向下取整 - if (core.isset(core.status.hero[item])) - core.status.hero[item] = Math.floor(core.status.hero[item]); + core.status.hero[item] = Math.floor(core.status.hero[item]); // 大数据格式化 core.setStatusBarInnerHTML(item, core.getRealStatus(item)); }); @@ -1022,7 +1003,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = "updateCheckBlock": function (floorId) { // 领域、夹击、阻击等的伤害值计算 floorId = floorId || core.status.floorId; - if (!core.isset(floorId) || !core.isset(core.status.maps)) return; + if (!floorId || !core.status.maps) return; + var blocks = core.status.maps[floorId].blocks; var width = core.floors[floorId].width, height = core.floors[floorId].height; @@ -1035,9 +1017,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (!block.disable && block.event.cls.indexOf('enemy') == 0) { var id = block.event.id, enemy = core.material.enemys[id]; - if (core.isset(enemy)) { - core.status.checkBlock.map[block.x + width * block.y] = id; - } + if (enemy) core.status.checkBlock.map[block.x + width * block.y] = id; } // 血网 if (!block.disable && @@ -1054,7 +1034,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var id = core.status.checkBlock.map[x + width * y]; - if (core.isset(id)) { + if (id) { // 如果是血网,直接加上伤害值 if (id == "lavaNet") { @@ -1070,7 +1050,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var range = enemy.range || 1; // 是否是九宫格领域 var zoneSquare = false; - if (core.isset(enemy.zoneSquare)) zoneSquare = enemy.zoneSquare; + if (enemy.zoneSquare != null) zoneSquare = enemy.zoneSquare; // 在范围内进行搜索,增加领域伤害值 for (var dx = -range; dx <= range; dx++) { for (var dy = -range; dy <= range; dy++) { @@ -1115,7 +1095,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var nx = x + core.utils.scan[dir].x, ny = y + core.utils.scan[dir].y; if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; - if (!core.isset(core.status.checkBlock.ambush[nx + ny * width])) + if (!core.status.checkBlock.ambush[nx + ny * width]) core.status.checkBlock.ambush[nx + ny * width] = []; core.status.checkBlock.ambush[nx + ny * width].push([x, y, id, dir]); } @@ -1136,9 +1116,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (x > 0 && x < width - 1) { var id1 = core.status.checkBlock.map[x - 1 +width * y], id2 = core.status.checkBlock.map[x + 1 + width * y]; - if (core.isset(id1) && core.isset(id2) && id1 == id2) { + if (id1 != null && id2 != null && id1 == id2) { var enemy = core.material.enemys[id1]; - if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { + if (enemy && core.enemys.hasSpecial(enemy.special, 16)) { has = true; } } @@ -1147,9 +1127,9 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (y > 0 && y < height - 1) { var id1 = core.status.checkBlock.map[x + width * (y - 1)], id2 = core.status.checkBlock.map[x + width * (y + 1)]; - if (core.isset(id1) && core.isset(id2) && id1 == id2) { + if (id1 != null && id2 != null && id1 == id2) { var enemy = core.material.enemys[id1]; - if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 16)) { + if (enemy && core.enemys.hasSpecial(enemy.special, 16)) { has = true; } } @@ -1308,7 +1288,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = if (!core.isPlaying()) return; // 执行当前楼层的并行事件处理 - if (core.isset(core.status.floorId)) { + if (core.status.floorId) { try { eval(core.floors[core.status.floorId].parallelDo); } catch (e) { @@ -1377,7 +1357,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.clearMap(name); // 绘制色调层,默认不透明度 - if (!core.isset(color)) color = 0.9; + if (color == null) color = 0.9; ctx.fillStyle = "rgba(0,0,0,"+color+")"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); From e71080429733da57d7a51687435f07d6d3364e3b Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 17 Mar 2019 01:54:58 +0800 Subject: [PATCH 023/153] editor __SIZE__ --- _server/editor.js | 54 +++++++++++++++++++++--------------------- _server/editor_file.js | 12 ++++++---- _server/editor_mode.js | 8 +++---- 3 files changed, 38 insertions(+), 36 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index 83c29c51..384191d3 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -195,7 +195,7 @@ editor.prototype.fetchMapFromCore = function(){ editor.map = mapArray.map(function (v) { return v.map(function (v) { var x = parseInt(v), y = editor.indexs[x]; - if (!core.isset(y)) { + if (y == null) { printe("素材数字"+x+"未定义。是不是忘了注册,或者接档时没有覆盖icons.js和maps.js?"); y = [0]; } @@ -213,7 +213,7 @@ editor.prototype.fetchMapFromCore = function(){ editor[name]=mapArray.map(function (v) { return v.map(function (v) { var x = parseInt(v), y = editor.indexs[x]; - if (!core.isset(y)) { + if (y == null) { printe("素材数字"+x+"未定义。是不是忘了注册,或者接档时没有覆盖icons.js和maps.js?"); y = [0]; } @@ -242,7 +242,7 @@ editor.prototype.changeFloor = function (floorId, callback) { editor.updateMap(); editor_mode.floor(); editor.drawEventBlock(); - if (core.isset(callback)) callback(); + if (callback) callback(); }); } @@ -251,22 +251,22 @@ editor.prototype.changeFloor = function (floorId, callback) { editor.prototype.drawEventBlock = function () { var fg=document.getElementById('efg').getContext('2d'); - fg.clearRect(0, 0, 416, 416); - for (var i=0;i<13;i++) { - for (var j=0;j<13;j++) { + fg.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__); + for (var i=0;i'; colNum += tpl; } arrColMark.innerHTML = '' + colNum + ''; mapColMark.innerHTML = '' + colNum + ''; var rowNum = ' '; - for (var i = 0; i < 13; i++) { + for (var i = 0; i < core.__SIZE__; i++) { var tpl = '' + (i+offsetY) + '
'; rowNum += tpl; } @@ -522,29 +522,29 @@ editor.prototype.buildMark = function(){ } var buildMark_mobile = function (offsetX,offsetY) { var colNum = ' '; - for (var i = 0; i < 13; i++) { - var tpl = '' + (' '+i).slice(-2).replace(' ',' ') + '
'; + for (var i = 0; i < core.__SIZE__; i++) { + var tpl = '' + (' '+i).slice(-2).replace(' ',' ') + '
'; colNum += tpl; } arrColMark.innerHTML = '' + colNum + ''; //mapColMark.innerHTML = '' + colNum + ''; var rowNum = ' '; - for (var i = 0; i < 13; i++) { - var tpl = '' + (' '+i).slice(-2).replace(' ',' ') + '
'; + for (var i = 0; i < core.__SIZE__; i++) { + var tpl = '' + (' '+i).slice(-2).replace(' ',' ') + '
'; rowNum += tpl; } arrRowMark.innerHTML = rowNum; //mapRowMark.innerHTML = rowNum; //===== var colNum = ' '; - for (var i = 0; i < 13; i++) { - var tpl = '
' + (' '+(i+offsetX)).slice(-2).replace(' ',' ') + '
'; + for (var i = 0; i < core.__SIZE__; i++) { + var tpl = '
' + (' '+(i+offsetX)).slice(-2).replace(' ',' ') + '
'; colNum += tpl; } mapColMark.innerHTML = '
' + colNum + '
'; var rowNum = ' '; - for (var i = 0; i < 13; i++) { - var tpl = '
' + (' '+(i+offsetY)).slice(-2).replace(' ',' ') + '
'; + for (var i = 0; i < core.__SIZE__; i++) { + var tpl = '
' + (' '+(i+offsetY)).slice(-2).replace(' ',' ') + '
'; rowNum += tpl; } mapRowMark.innerHTML = rowNum; @@ -657,7 +657,7 @@ editor.prototype.listen = function () { editor.loc = { 'x': scrollLeft + xx - mid.offsetLeft - mapEdit.offsetLeft, 'y': scrollTop + yy - mid.offsetTop - mapEdit.offsetTop, - 'size': editor.isMobile?(32*innerWidth*0.96/416):32 + 'size': editor.isMobile?(32*innerWidth*0.96/core.__PIXELS__):32 }; return editor.loc; }//返回可用的组件内坐标 @@ -685,7 +685,7 @@ editor.prototype.listen = function () { } holdingPath = 0; stepPostfix = []; - uc.clearRect(0, 0, 416, 416); + uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__); }//用于鼠标移出canvas时的自动清除状态 eui.oncontextmenu=function(e){e.preventDefault()} @@ -807,7 +807,7 @@ editor.prototype.listen = function () { editor.updateMap(); holdingPath = 0; stepPostfix = []; - uc.clearRect(0, 0, 416, 416); + uc.clearRect(0, 0, core.__PIXELS__, core.__PIXELS__); } } diff --git a/_server/editor_file.js b/_server/editor_file.js index 6094be7a..ffc860ab 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -154,7 +154,7 @@ editor_file = function (editor, callback) { cannotMove: {} }; Object.keys(editor.currentFloorData).forEach(function (t) { - if (!core.isset(editor.currentFloorData[t])) + if (editor.currentFloorData[t] == null) delete editor.currentFloorData[t]; }) editor.currentFloorData.map = "new"; @@ -216,7 +216,7 @@ editor_file = function (editor, callback) { cannotMove: {} }; Object.keys(data).forEach(function (t) { - if (!core.isset(data[t])) + if (data[t] == null) delete data[t]; else { if (t=='map') { @@ -278,7 +278,7 @@ editor_file = function (editor, callback) { // get id num var id = c+idnum; - if (image=='terrains' && core.isset(terrainsId[y])) { + if (image=='terrains' && terrainsId[y] != null) { id=terrainsId[y]; } else { @@ -999,8 +999,10 @@ editor_file = function (editor, callback) { if (file == 'floorloc') { actionList.forEach(function (value) { // 检测null/undefined - if (!core.isset(value[2]))value[2]=undefined; - eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2])); + if (value[2]==null) + eval("delete editor.currentFloorData" + value[1]); + else + eval("editor.currentFloorData" + value[1] + '=' + JSON.stringify(value[2])); }); editor_file.saveFloorFile(callback); return; diff --git a/_server/editor_mode.js b/_server/editor_mode.js index d23f4abe..cbb63f17 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -608,8 +608,8 @@ editor_mode = function (editor) { } var width = parseInt(document.getElementById('newMapWidth').value); var height = parseInt(document.getElementById('newMapHeight').value); - if (!core.isset(width) || !core.isset(height) || width<13 || height<13 || width*height>1000) { - printe("新建地图的宽高都不得小于13,且宽高之积不能超过1000"); + if (!core.isset(width) || !core.isset(height) || width1000) { + printe("新建地图的宽高都不得小于"+core.__SIZE__+",且宽高之积不能超过1000"); return; } @@ -673,8 +673,8 @@ editor_mode = function (editor) { var width = parseInt(document.getElementById('newMapsWidth').value); var height = parseInt(document.getElementById('newMapsHeight').value); - if (!core.isset(width) || !core.isset(height) || width<13 || height<13 || width*height>1000) { - printe("新建地图的宽高都不得小于13,且宽高之积不能超过1000"); + if (!core.isset(width) || !core.isset(height) || width1000) { + printe("新建地图的宽高都不得小于"+core.__SIZE__+",且宽高之积不能超过1000"); return; } editor_mode.onmode(''); From 83fb359179e88a8199c401fac499be8d8f3c1e28 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 17 Mar 2019 02:07:06 +0800 Subject: [PATCH 024/153] Fix diff' --- _server/css/editor.css | 1 - _server/editor.js | 2 +- libs/utils.js | 4 ++-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/_server/css/editor.css b/_server/css/editor.css index 8126b33c..b37149bb 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -148,7 +148,6 @@ body { height: 180px; left: 0; bottom: 0; - border-top: 1px solid #ccc; padding: 10px 5px; margin-left: 8px;; box-sizing: border-box; diff --git a/_server/editor.js b/_server/editor.js index 384191d3..e88f264d 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -721,7 +721,7 @@ editor.prototype.listen = function () { mouseOutCheck = 2; setTimeout(clear1); e.stopPropagation(); - uc.clearRect(0, 0, 416, 416); + uc.clearRect(0, 0, core.__SIZE__, core.__SIZE__); var loc = eToLoc(e); var pos = locToPos(loc,true); stepPostfix = []; diff --git a/libs/utils.js b/libs/utils.js index 3c574036..8e4bdfc1 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -792,7 +792,7 @@ utils.prototype.readFileContent = function (content) { main.log(e); alert(e); } - alert("不是有效的JSON文件!"); + // alert("不是有效的JSON文件!"); if (core.platform.errorCallback) core.platform.errorCallback(); @@ -1049,7 +1049,7 @@ utils.prototype._export = function (floorIds) { // map var content = floorIds.length + "\n" + core.__SIZE__ + " " + core.__SIZE__ + "\n\n"; floorIds.forEach(function (floorId) { - var arr = core.maps.getMapArray(core.status.maps[floorId].blocks, 13, 13); + var arr = core.maps.getMapArray(core.status.maps[floorId].blocks); content += arr.map(function (x) { // check monster x.forEach(function (t) { From e945a81ccd9572a8d3e2ca86f8bd57d76bb9e43b Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 17 Mar 2019 16:23:55 +0800 Subject: [PATCH 025/153] registerAnimationFrame --- libs/control.js | 522 +++++++++++++++++++++++------------------------- libs/core.js | 6 +- libs/events.js | 2 +- libs/maps.js | 20 ++ libs/ui.js | 8 +- 5 files changed, 281 insertions(+), 277 deletions(-) diff --git a/libs/control.js b/libs/control.js index 9d3f9ab1..4490b3db 100644 --- a/libs/control.js +++ b/libs/control.js @@ -12,11 +12,60 @@ function control() { control.prototype._init = function () { this.controldata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.control; + this.renderFrameFuncs = []; + // --- 注册系统的animationFrame + this.registerAnimationFrame("_totalTime", false, this._animationFrame_totalTime); + this.registerAnimationFrame("_autoSave", true, this._animationFrame_autoSave); + this.registerAnimationFrame("_globalAnimate", true, this._animationFrame_globalAnimate); + this.registerAnimationFrame("_selector", false, this._animationFrame_selector); + this.registerAnimationFrame("_animate", true, this._animationFrame_animate); + this.registerAnimationFrame("_heroMoving", true, this._animationFrame_heroMoving); + this.registerAnimationFrame("_weather", true, this._animationFrame_weather); + this.registerAnimationFrame("_parallelDo", false, this._animationFrame_parallelDo); + this.registerAnimationFrame("_checkConsoleOpened", true, this._animationFrame_checkConsoleOpened); +} + +////// 注册一个 animationFrame ////// +// name:名称,可用来作为注销使用;needPlaying:是否只在游戏运行时才执行(在标题界面不执行) +// func:要执行的函数,或插件中的函数名;可接受timestamp(从页面加载完毕到当前所经过的时间)作为参数 +control.prototype.registerAnimationFrame = function (name, needPlaying, func) { + this.unregisterAnimationFrame(name); + this.renderFrameFuncs.push({name: name, needPlaying: needPlaying, func: func}); +} + +////// 注销一个 animationFrame ////// +control.prototype.unregisterAnimationFrame = function (name) { + this.renderFrameFuncs = this.renderFrameFuncs.filter(function (x) { return x.name!=name; }); } ////// 设置requestAnimationFrame ////// -control.prototype.setRequestAnimationFrame = function () { +control.prototype._setRequestAnimationFrame = function () { + this._checkRequestAnimationFrame(); + core.animateFrame.totalTime = Math.max(core.animateFrame.totalTime, core.getLocalStorage('totalTime', 0)); + var loop = function (timestamp) { + core.control.renderFrameFuncs.forEach(function (b) { + if (b.func) { + try { + if (core.isPlaying() || !b.needPlaying) { + if (b.func instanceof Function) + b.func(timestamp); + else if (typeof b.func == 'string') + core.plugin[b.func](timestamp); + } + } + catch (e) { + main.log(e); + main.log("ERROR in requestAnimationFrame["+b.name+"]:已自动注销该项。"); + core.unregisterAnimationFrame(b.name); + } + } + }) + window.requestAnimationFrame(loop); + } + window.requestAnimationFrame(loop); +} +control.prototype._checkRequestAnimationFrame = function () { (function() { var lastTime = 0; var vendors = ['webkit', 'moz']; @@ -43,268 +92,201 @@ control.prototype.setRequestAnimationFrame = function () { }; } }()); - - core.animateFrame.totalTime = Math.max(core.animateFrame.totalTime, core.getLocalStorage('totalTime', 0)); - - var draw = function(timestamp) { - - core.animateFrame.totalTime += timestamp - core.animateFrame.totalTimeStart; - core.animateFrame.totalTimeStart = timestamp; - - // move time - if (core.isPlaying() && core.isset(core.status) && core.isset(core.status.hero) - && core.isset(core.status.hero.statistics)) { - core.status.hero.statistics.totalTime = core.animateFrame.totalTime; - core.status.hero.statistics.currTime += timestamp-(core.status.hero.statistics.start||timestamp); - core.status.hero.statistics.start=timestamp; - } - - // Global Animate - if (timestamp - core.animateFrame.globalTime > core.values.animateSpeed && core.isPlaying()) { - - core.status.globalAnimateStatus++; - - if (core.isset(core.status.floorId)) { - // Global Animate - core.status.globalAnimateObjs.forEach(function (block) { - core.drawBlock(block, core.status.globalAnimateStatus % (block.event.animate||1)); - }); - - // Global floor images - core.maps._drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); - 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) { - // ------ 界面外的动画不绘制 - if (block.x * 32 < core.bigmap.offsetX - 64 || block.x * 32 > core.bigmap.offsetX + 416 + 32 - || block.y * 32 < core.bigmap.offsetY - 64 || block.y * 32 > core.bigmap.offsetY + 416 + 32 + 16) { - return; - } - - var cv = core.isset(block.name)?core.canvas[block.name]:core.canvas.event; - cv.clearRect(block.x * 32, block.y * 32, 32, 32); - if (core.isset(block.name)) { - if (block.name == 'bg') { - core.drawImage('bg', core.material.groundCanvas.canvas, block.x * 32, block.y * 32); - } - core.drawAutotile(cv, core.status.autotileAnimateObjs[block.name+"map"], block, 32, 0, 0, core.status.globalAnimateStatus); - } - else { - core.drawAutotile(cv, core.status.autotileAnimateObjs.map, block, 32, 0, 0, core.status.globalAnimateStatus); - } - }); - } - - // Box animate - core.drawBoxAnimate(); - core.animateFrame.globalTime = timestamp; - } - - // AutosaveTime - if (timestamp - core.saves.autosave.time > 5000 && core.isPlaying()) { - core.control.checkAutosave(); - core.saves.autosave.time = timestamp; - } - - // selectorTime - if (timestamp-core.animateFrame.selectorTime>20 && core.isset(core.dymCanvas.selector)) { - var opacity = parseFloat(core.dymCanvas.selector.canvas.style.opacity); - if (core.animateFrame.selectorUp) - opacity += 0.02; - else - opacity -= 0.02; - if (opacity > 0.95 || opacity < 0.55) - core.animateFrame.selectorUp = !core.animateFrame.selectorUp; - core.setOpacity("selector", opacity); - core.animateFrame.selectorTime = timestamp; - } - - // Animate - if (timestamp-core.animateFrame.animateTime>50 && core.isset(core.status.animateObjs) && core.status.animateObjs.length>0) { - core.clearMap('animate'); - // 更新帧 - var animateObjs = []; - for (var i=0;i0) { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); - - // 200ms换腿? - if (timestamp - core.animateFrame.moveTime > (core.values.moveSpeed||100)) { - core.animateFrame.leftLeg = !core.animateFrame.leftLeg; - core.animateFrame.moveTime = timestamp; - } - core.drawHero(direction, x, y, core.animateFrame.leftLeg?'leftFoot':'rightFoot', 4*core.status.heroMoving); - /* - if (core.status.heroMoving<=4) { - core.drawHero(direction, x, y, 'leftFoot', 4*core.status.heroMoving); - } - else if (core.status.heroMoving<=8) { - core.drawHero(direction, x, y, 'rightFoot', 4*core.status.heroMoving); - } - */ - } - - // weather - if (core.isPlaying() && timestamp-core.animateFrame.weather.time>30 && core.isset(core.dymCanvas.weather)) { - var ctx = core.dymCanvas.weather; - - var ox = core.bigmap.offsetX, oy = core.bigmap.offsetY; - - if (core.animateFrame.weather.type == 'rain' && core.animateFrame.weather.level > 0) { - core.clearMap('weather'); - ctx.strokeStyle = 'rgba(174,194,224,0.8)'; - ctx.lineWidth = 1; - ctx.lineCap = 'round'; - - core.animateFrame.weather.nodes.forEach(function (p) { - ctx.beginPath(); - ctx.moveTo(p.x-ox, p.y-oy); - ctx.lineTo(p.x + p.l * p.xs - ox, p.y + p.l * p.ys - oy); - ctx.stroke(); - - p.x += p.xs; - p.y += p.ys; - if (p.x > core.bigmap.width*32 || p.y > core.bigmap.height*32) { - p.x = Math.random() * core.bigmap.width*32; - p.y = -10; - } - - }) - - ctx.fill(); - - } - else if (core.animateFrame.weather.type == 'snow' && core.animateFrame.weather.level > 0) { - - core.clearMap('weather'); - ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; - ctx.beginPath(); - - if (!core.isset(core.animateFrame.weather.data)) - core.animateFrame.weather.data = 0; - core.animateFrame.weather.data += 0.01; - - var angle = core.animateFrame.weather.data; - core.animateFrame.weather.nodes.forEach(function (p) { - ctx.moveTo(p.x - ox, p.y - oy); - ctx.arc(p.x - ox, p.y - oy, p.r, 0, Math.PI * 2, true); - - // update - p.x += Math.sin(angle) * 2; - p.y += Math.cos(angle + p.d) + 1 + p.r / 2; - - if (p.x > core.bigmap.width*32 + 5 || p.x < -5 || p.y > core.bigmap.height*32) { - if (Math.random() > 1 / 3) { - p.x = Math.random() * core.bigmap.width*32; - p.y = -10; - } - else { - if (Math.sin(angle) > 0) { - p.x = -5; - p.y = Math.random() * core.bigmap.height*32; - } - else { - p.x = core.bigmap.width*32 + 5; - p.y = Math.random() * core.bigmap.height*32; - } - } - } - - }) - - ctx.fill(); - - } - else if (core.animateFrame.weather.type == 'fog' && core.animateFrame.weather.level > 0) { - core.clearMap('weather'); - if (core.animateFrame.weather.fog) { - var w = 416, h = 416; - core.setAlpha('weather', 0.5); - core.animateFrame.weather.nodes.forEach(function (p) { - ctx.drawImage(core.animateFrame.weather.fog, p.x - ox, p.y - oy, w, h); - - p.x += p.xs; - p.y += p.ys; - if (p.x > core.bigmap.width*32 - w/2) { - p.x = core.bigmap.width*32 - w/2 - 1; - p.xs = -p.xs; - } - if (p.x < -w/2) { - p.x = -w/2+1; - p.xs = -p.xs; - } - if (p.y > core.bigmap.height*32 - h/2) { - p.y = core.bigmap.height*32 - h/2 - 1; - p.ys = -p.ys; - } - if (p.y < -h/2) { - p.y = -h/2+1; - p.ys = -p.ys; - } - }) - core.setAlpha('weather',1); - } - - } - core.animateFrame.weather.time = timestamp; - - } - - // 执行用户的并行事件处理内容 - functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.parallelDo(timestamp); - - if (core.isPlaying()) { - // 执行插件中的每帧函数 - var renderFrameFuncs = core.plugin.__renderFrameFuncs || []; - renderFrameFuncs.forEach(function (t) { - try { - if (t instanceof Function) { - t(timestamp); - } - else if (typeof t == 'string') { - if (core.plugin[t]) - core.plugin[t](timestamp); - } - } - catch (e) { - main.log(e); - } - }); - } - - // 检查控制台状态 - if (core.utils.consoleOpened()) { - core.setFlag('__consoleOpened__', true); - } - - window.requestAnimationFrame(draw); - } - window.requestAnimationFrame(draw); } +control.prototype._animationFrame_totalTime = function (timestamp) { + core.animateFrame.totalTime += timestamp - core.animateFrame.totalTimeStart; + core.animateFrame.totalTimeStart = timestamp; + if (core.isPlaying()) { + core.status.hero.statistics.totalTime = core.animateFrame.totalTime; + core.status.hero.statistics.currTime += timestamp-(core.status.hero.statistics.start||timestamp); + core.status.hero.statistics.start = timestamp; + } +} + +control.prototype._animationFrame_autoSave = function (timestamp) { + if (timestamp - core.saves.autosave.time <= 5000) return; + core.control.checkAutosave(); + core.saves.autosave.time = timestamp; +} + +control.prototype._animationFrame_globalAnimate = function (timestamp) { + if (timestamp - core.animateFrame.globalTime <= core.values.animateSpeed) return; + core.status.globalAnimateStatus++; + if (core.status.floorId) { + // Global Animate + core.status.globalAnimateObjs.forEach(function (block) { + core.drawBlock(block, core.status.globalAnimateStatus % (block.event.animate||1)); + }); + + // Global floor images + core.maps._drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs||[], core.status.globalAnimateStatus); + 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.maps._drawAutotileAnimate(block, core.status.globalAnimateStatus); + }); + } + // Box animate + core.drawBoxAnimate(); + core.animateFrame.globalTime = timestamp; +} + +control.prototype._animationFrame_selector = function (timestamp) { + if (timestamp - core.animateFrame.selectorTime <= 20 || !core.dymCanvas._selector) return; + var opacity = parseFloat(core.dymCanvas._selector.canvas.style.opacity); + if (core.animateFrame.selectorUp) + opacity += 0.02; + else + opacity -= 0.02; + if (opacity > 0.95 || opacity < 0.55) + core.animateFrame.selectorUp = !core.animateFrame.selectorUp; + core.setOpacity("_selector", opacity); + core.animateFrame.selectorTime = timestamp; +} + +control.prototype._animationFrame_animate = function (timestamp) { + if (timestamp - core.animateFrame.animateTime < 50 || !core.status.animateObjs || core.status.animateObjs.length == 0) return; + core.clearMap('animate'); + // 更新帧 + var animateObjs = []; + for (var i=0;i (core.values.moveSpeed||100)) { + core.animateFrame.leftLeg = !core.animateFrame.leftLeg; + core.animateFrame.moveTime = timestamp; + } + core.drawHero(direction, x, y, core.animateFrame.leftLeg?'leftFoot':'rightFoot', 4*core.status.heroMoving); +} + +control.prototype._animationFrame_weather = function (timestamp) { + var weather = core.animateFrame.weather; + if (timestamp - weather.time <= 30 || weather.level <= 0 || !core.dymCanvas.weather) return; + core.control["_animationFrame_weather_"+weather.type](); + weather.time = timestamp; +} + +control.prototype._animationFrame_weather_rain = function () { + var ctx = core.dymCanvas.weather, ox = core.bigmap.offsetX, oy = core.bigmap.offsetY; + core.clearMap('weather'); + ctx.strokeStyle = 'rgba(174,194,224,0.8)'; + ctx.lineWidth = 1; + ctx.lineCap = 'round'; + + core.animateFrame.weather.nodes.forEach(function (p) { + ctx.beginPath(); + ctx.moveTo(p.x-ox, p.y-oy); + ctx.lineTo(p.x + p.l * p.xs - ox, p.y + p.l * p.ys - oy); + ctx.stroke(); + + p.x += p.xs; + p.y += p.ys; + if (p.x > core.bigmap.width * 32 || p.y > core.bigmap.height * 32) { + p.x = Math.random() * core.bigmap.width * 32; + p.y = -10; + } + + }); + + ctx.fill(); +} + +control.prototype._animationFrame_weather_snow = function () { + var ctx = core.dymCanvas.weather, ox = core.bigmap.offsetX, oy = core.bigmap.offsetY; + core.clearMap('weather'); + ctx.fillStyle = "rgba(255, 255, 255, 0.8)"; + ctx.beginPath(); + core.animateFrame.weather.data = core.animateFrame.weather.data || 0; + core.animateFrame.weather.data += 0.01; + + var angle = core.animateFrame.weather.data; + core.animateFrame.weather.nodes.forEach(function (p) { + ctx.moveTo(p.x - ox, p.y - oy); + ctx.arc(p.x - ox, p.y - oy, p.r, 0, Math.PI * 2, true); + // update + p.x += Math.sin(angle) * 2; + p.y += Math.cos(angle + p.d) + 1 + p.r / 2; + if (p.x > core.bigmap.width*32 + 5 || p.x < -5 || p.y > core.bigmap.height*32) { + if (Math.random() > 1 / 3) { + p.x = Math.random() * core.bigmap.width*32; + p.y = -10; + } + else { + if (Math.sin(angle) > 0) + p.x = -5; + else + p.x = core.bigmap.width*32 + 5; + p.y = Math.random() * core.bigmap.height*32; + } + } + }); + ctx.fill(); +} + +control.prototype._animationFrame_weather_fog = function () { + var ctx = core.dymCanvas.weather, ox = core.bigmap.offsetX, oy = core.bigmap.offsetY; + core.clearMap('weather'); + if (core.animateFrame.weather.fog) { + var w = core.__PIXELS__, h = core.__PIXELS__; + core.setAlpha('weather', 0.5); + core.animateFrame.weather.nodes.forEach(function (p) { + ctx.drawImage(core.animateFrame.weather.fog, p.x - ox, p.y - oy, w, h); + p.x += p.xs; + p.y += p.ys; + if (p.x > core.bigmap.width*32 - w/2) { + p.x = core.bigmap.width*32 - w/2 - 1; + p.xs = -p.xs; + } + if (p.x < -w/2) { + p.x = -w/2+1; + p.xs = -p.xs; + } + if (p.y > core.bigmap.height*32 - h/2) { + p.y = core.bigmap.height*32 - h/2 - 1; + p.ys = -p.ys; + } + if (p.y < -h/2) { + p.y = -h/2+1; + p.ys = -p.ys; + } + }); + core.setAlpha('weather',1); + } +} + +control.prototype._animationFrame_parallelDo = function (timestamp) { + functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.parallelDo(timestamp); +} + +control.prototype._animationFrame_checkConsoleOpened = function (timestamp) { + if (core.consoleOpened()) core.setFlag('__consoleOpened__', true); +} + + ////// 显示游戏开始界面 ////// control.prototype.showStartAnimate = function (noAnimate, callback) { core.dom.startPanel.style.opacity=1; @@ -355,6 +337,10 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { } +control.prototype._showStartAnimate_resetDom = function () { + +} + ////// 隐藏游戏开始界面 ////// control.prototype.hideStartAnimate = function (callback) { var opacityVal = 1; @@ -371,7 +357,13 @@ control.prototype.hideStartAnimate = function (callback) { ////// 游戏是否已经开始 ////// control.prototype.isPlaying = function() { - return core.isset(core.status.played) && core.status.played; + return core.status.played; +} + +////// 重新开始游戏;此函数将回到标题页面 ////// +control.prototype.restart = function() { + this.showStartAnimate(); + core.playBgm(main.startBgm); } ////// 清除游戏状态和数据 ////// @@ -453,12 +445,6 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value core.dom.musicBtn.style.display = 'none'; } -////// 重新开始游戏;此函数将回到标题页面 ////// -control.prototype.restart = function(noAnimate) { - this.showStartAnimate(noAnimate); - core.playBgm(main.startBgm); -} - /////////////////////// 寻路算法 & 人物行走控制 /////////////////////// diff --git a/libs/core.js b/libs/core.js index b0a0072a..06a30eea 100644 --- a/libs/core.js +++ b/libs/core.js @@ -374,15 +374,13 @@ core.prototype.init = function (coreData, callback) { core.control.updateHeroIcon(); core.initStatus.maps = core.maps.initMaps(core.floorIds); - core.setRequestAnimationFrame(); + core.control._setRequestAnimationFrame(); if (main.mode == 'play') core.events.initGame(); if (functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins) { - core.plugin = new function () { - this.__renderFrameFuncs = []; - }; + core.plugin = new function () {}; core.plugin.__init__ = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.plugin; core.plugin.__init__(); core._forwardFunc("plugin"); diff --git a/libs/events.js b/libs/events.js index abd55412..13915ac9 100644 --- a/libs/events.js +++ b/libs/events.js @@ -504,7 +504,7 @@ events.prototype._changeFloor_getHeroLoc = function (floorId, stair, heroLoc) { } } ['x', 'y', 'direction'].forEach(function (name) { - if (!heroLoc[name]) + if (heroLoc[name] == null) heroLoc[name] = core.getHeroLoc(name); }); return heroLoc; diff --git a/libs/maps.js b/libs/maps.js index 38ffd862..cdc9cd52 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -853,6 +853,26 @@ maps.prototype._drawAutotile_getAutotileIndexs = function (x, y, mapArr, indexAr return indexArr; } +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; + } + + var cv = block.name?core.canvas[block.name]:core.canvas.event; + cv.clearRect(32 * x, 32 * y, 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); + } + else { + this.drawAutotile(cv, core.status.autotileAnimateObjs.map, block, 32, 0, 0, animate); + } +} + ////// 为autotile判定边界 ////// maps.prototype._makeAutotileEdges = function () { var autotileIds = Object.keys(core.material.images.autotile); diff --git a/libs/ui.js b/libs/ui.js index d69ac735..6b381798 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -239,8 +239,8 @@ ui.prototype.closePanel = function () { ////// 一般清除事件 ////// ui.prototype.clearLastEvent = function () { - if (core.isset(core.dymCanvas.selector)) - core.deleteCanvas("selector"); + if (core.isset(core.dymCanvas._selector)) + core.deleteCanvas("_selector"); core.clearMap('ui'); core.setAlpha('ui', 1); } @@ -409,8 +409,8 @@ ui.prototype.getTitleAndIcon = function (content) { // 绘制选择光标 ui.prototype.drawWindowSelector = function(background,x,y,w,h) { w = Math.round(w), h = Math.round(h); - var dstImage = core.ui.createCanvas("selector", x, y, w, h, 165); - core.setOpacity("selector", 0.8); + var dstImage = core.ui.createCanvas("_selector", x, y, w, h, 165); + core.setOpacity("_selector", 0.8); // back dstImage.drawImage(background, 130, 66, 28, 28, 2, 2,w-4,h-4); // corner From 147da1b443e6c1a79c931c857acfd8d7820e29c3 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 17 Mar 2019 18:00:00 +0800 Subject: [PATCH 026/153] resetGame & core.init --- _server/editor.js | 2 +- _server/functions.comment.js | 5 +- libs/control.js | 113 ++++--------------- libs/core.js | 204 ++++++++++++++--------------------- libs/data.js | 4 - libs/events.js | 7 +- libs/items.js | 29 +++++ project/functions.js | 67 +++++++----- 8 files changed, 176 insertions(+), 255 deletions(-) diff --git a/_server/editor.js b/_server/editor.js index e88f264d..bd1524f3 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -90,7 +90,7 @@ editor.prototype.init = function (callback) { editor.file = editor_file; editor_mode = editor_mode(editor); editor.mode = editor_mode; - core.resetStatus(core.firstData.hero, null, core.firstData.floorId, null, core.initStatus.maps); + core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.initStatus.maps); core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function () { afterCoreReset(); }, true); diff --git a/_server/functions.comment.js b/_server/functions.comment.js index 8e961da5..bf25ed95 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -4,14 +4,13 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "object", "_data": { "events": { - "_type": "object", "_data": { - "initGame": { + "resetGame": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "游戏开始前的一些初始化操作" + "_data": "重置整个游戏" }, "setInitData": { "_leaf": true, diff --git a/libs/control.js b/libs/control.js index 4490b3db..570f9946 100644 --- a/libs/control.js +++ b/libs/control.js @@ -25,6 +25,8 @@ control.prototype._init = function () { this.registerAnimationFrame("_checkConsoleOpened", true, this._animationFrame_checkConsoleOpened); } +// ------ requestAnimationFrame 相关 ------ // + ////// 注册一个 animationFrame ////// // name:名称,可用来作为注销使用;needPlaying:是否只在游戏运行时才执行(在标题界面不执行) // func:要执行的函数,或插件中的函数名;可接受timestamp(从页面加载完毕到当前所经过的时间)作为参数 @@ -286,9 +288,19 @@ control.prototype._animationFrame_checkConsoleOpened = function (timestamp) { if (core.consoleOpened()) core.setFlag('__consoleOpened__', true); } +// ------ 标题界面的处理 ------ // ////// 显示游戏开始界面 ////// control.prototype.showStartAnimate = function (noAnimate, callback) { + this._showStartAnimate_resetDom(); + if (core.flags.startUsingCanvas || noAnimate) + return this._showStartAnimate_finished(core.flags.startUsingCanvas, callback); + core.hide(core.dom.startTop, 20, function () { + core.control._showStartAnimate_finished(false, callback); + }); +} + +control.prototype._showStartAnimate_resetDom = function () { core.dom.startPanel.style.opacity=1; core.dom.startPanel.style.display="block"; core.dom.startTop.style.opacity=1; @@ -300,59 +312,21 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { core.clearStatus(); core.clearMap('all'); core.deleteAllCanvas(); - core.dom.musicBtn.style.display = 'block'; - // 重置音量 core.events.setVolume(1, 0); - - if (core.flags.startUsingCanvas) { - core.dom.startTop.style.display = 'none'; - core.dom.startButtonGroup.style.display = 'block'; - core.events.startGame(''); - if (core.isset(callback)) callback(); - return; - } - - if(noAnimate) { - core.dom.startTop.style.display = 'none'; - // core.playGame(); - core.dom.startButtonGroup.style.display = 'block'; - if (core.isset(callback)) callback(); - } - else { - var opacityVal = 1; - var startAnimate = window.setInterval(function () { - opacityVal -= 0.03; - if (opacityVal < 0) { - clearInterval(startAnimate); - core.dom.startTop.style.display = 'none'; - // core.playGame(); - core.dom.startButtonGroup.style.display = 'block'; - if (core.isset(callback)) callback(); - } - core.dom.startTop.style.opacity = opacityVal; - }, 20); - } - } -control.prototype._showStartAnimate_resetDom = function () { - +control.prototype._showStartAnimate_finished = function (start, callback) { + core.dom.startTop.style.display = 'none'; + core.dom.startButtonGroup.style.display = 'block'; + if (start) core.startGame(); + if (callback) callback(); } ////// 隐藏游戏开始界面 ////// control.prototype.hideStartAnimate = function (callback) { - var opacityVal = 1; - var startAnimate = window.setInterval(function () { - opacityVal -= 0.03; - if (opacityVal < 0) { - clearInterval(startAnimate); - core.dom.startPanel.style.display = 'none'; - if (core.isset(callback)) callback(); - } - core.dom.startPanel.style.opacity = opacityVal; - }, 20); + core.hide(core.dom.startPanel, 20, callback); } ////// 游戏是否已经开始 ////// @@ -381,31 +355,9 @@ control.prototype.clearStatus = function() { core.clearStatusBar(); core.deleteAllCanvas(); core.status.played = false; - core.events.setHeroIcon('hero.png', true); } -////// 重置游戏状态和初始数据 ////// -control.prototype.resetStatus = function(hero, hard, floorId, route, maps, values) { - - var totalTime = core.animateFrame.totalTime; - - // 清除游戏数据 - core.clearStatus(); - - // 初始化status - core.status = core.clone(core.initStatus); - core.status.played = true; - // 初始化maps - core.status.floorId = floorId; - core.status.maps = core.clone(maps); - // 初始化怪物 - core.material.enemys = core.enemys.getEnemys(); - core.material.items = core.items.getItems(); - // 初始化人物属性 - core.status.hero = core.clone(hero); - // 初始化人物图标 - core.events.setHeroIcon(core.getFlag('heroIcon', 'hero.png'), true); - // 统计数据 +control.prototype._initStatistics = function (totalTime) { if (!core.isset(core.status.hero.statistics)) core.status.hero.statistics = { 'totalTime': totalTime, @@ -420,29 +372,6 @@ control.prototype.resetStatus = function(hero, hard, floorId, route, maps, value 'moveDirectly': 0, 'ignoreSteps': 0, } - core.status.hero.statistics.totalTime = core.animateFrame.totalTime = - Math.max(core.status.hero.statistics.totalTime, core.animateFrame.totalTime); - core.status.hero.statistics.start = null; - - core.status.hard = hard; - // 初始化路线 - if (core.isset(route)) - core.status.route = route; - - if (core.isset(values)) - core.values = core.clone(values); - else core.values = core.clone(core.data.values); - - core.flags = core.clone(core.data.flags); - var systemFlags = core.getFlag("globalFlags", {}); - for (var key in systemFlags) - core.flags[key] = systemFlags[key]; - - core.events.initGame(); - core.resize(); - this.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); - this.triggerStatusBar(core.getFlag('hideStatusBar', false)?'hide':'show', core.getFlag("showToolbox")); - core.dom.musicBtn.style.display = 'none'; } @@ -2466,8 +2395,8 @@ control.prototype.saveData = function() { ////// 从本地读档 ////// control.prototype.loadData = function (data, callback) { - core.resetStatus(data.hero, data.hard, data.floorId, core.decodeRoute(data.route), core.maps.loadMap(data.maps), - data.values); + core.resetGame(data.hero, data.hard, data.floorId, core.maps.loadMap(data.maps), data.values); + core.status.route = core.decodeRoute(data.route); // load shop times for (var shop in core.status.shops) { diff --git a/libs/core.js b/libs/core.js index 06a30eea..c64b7c71 100644 --- a/libs/core.js +++ b/libs/core.js @@ -216,48 +216,58 @@ function core() { ////// 初始化 ////// core.prototype.init = function (coreData, callback) { this._forwardFuncs(); - - for (var key in coreData) { + for (var key in coreData) core[key] = coreData[key]; - } + this._init_flags(); + this._init_platform(); + this._init_others(); + + core.loader._load(function () { + core._afterLoadResources(callback); + }); +} + +core.prototype._init_flags = function () { core.flags = core.clone(core.data.flags); core.values = core.clone(core.data.values); - core.firstData = core.data.getFirstData(); + core.firstData = core.clone(core.data.firstData); - if (!core.flags.enableExperience) - core.flags.enableLevelUp = false; - if (!core.flags.enableLevelUp) - core.flags.levelUpLeftMode = false; - - if (core.firstData.shops) { - core.firstData.shops.forEach(function (t) { - core.initStatus.shops[t.id] = t; - }) - } - - core.maps._setFloorSize(); + if (!core.flags.enableExperience) core.flags.enableLevelUp = false; + if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false; + if (core.flags.equipboxButton) core.flags.equipment = true; + core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); + core.flags.displayCritical = core.getLocalStorage('critical', core.flags.displayCritical); + core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', core.flags.displayExtraDamage); core.dom.versionLabel.innerHTML = core.firstData.version; core.dom.logoLabel.innerHTML = core.firstData.title; document.title = core.firstData.title + " - HTML5魔塔"; document.getElementById("startLogo").innerHTML = core.firstData.title; - core.material.items = core.items.getItems(); + (core.firstData.shops||[]).forEach(function (t) { core.initStatus.shops[t.id] = t; }); + core.maps._setFloorSize(); + // 初始化地图 + core.initStatus.maps = core.maps.initMaps(core.floorIds); + // 初始化怪物、道具等 core.material.enemys = core.enemys.getEnemys(); + core.material.items = core.items.getItems(); + core.items._resetItems(); core.material.icons = core.icons.getIcons(); +} +core.prototype._init_platform = function () { core.platform.isOnline = location.protocol.indexOf("http") == 0; - if (core.platform.isOnline) { - window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; - try { - core.musicStatus.audioContext = new window.AudioContext(); - core.musicStatus.gainNode = core.musicStatus.audioContext.createGain(); - core.musicStatus.gainNode.connect(core.musicStatus.audioContext.destination); - } catch (e) { - console.log("该浏览器不支持AudioContext"); - core.musicStatus.audioContext = null; - } + if (!core.platform.isOnline) alert("请勿直接打开html文件!使用启动服务或者APP进行离线游戏。"); + window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; + try { + core.musicStatus.audioContext = new window.AudioContext(); + core.musicStatus.gainNode = core.musicStatus.audioContext.createGain(); + core.musicStatus.gainNode.connect(core.musicStatus.audioContext.destination); + } catch (e) { + console.log("该浏览器不支持AudioContext"); + core.musicStatus.audioContext = null; } - + core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true); + core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); ["Android", "iPhone", "SymbianOS", "Windows Phone", "iPad", "iPod"].forEach(function (t) { if (navigator.userAgent.indexOf(t) >= 0) { if (t == 'iPhone' || t == 'iPad' || t == 'iPod') core.platform.isIOS = true; @@ -265,21 +275,32 @@ core.prototype.init = function (coreData, callback) { core.platform.isPC = false; } }); - - try { - core.platform.supportCopy = document.queryCommandSupported("copy"); - } - catch (e) { - core.platform.supportCopy = false; - } - + core.platform.supportCopy = document.queryCommandSupported || document.queryCommandSupported("copy"); var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent); - if (chrome && parseInt(chrome[1]) >= 50) - core.platform.isChrome = true; + if (chrome && parseInt(chrome[1]) >= 50) core.platform.isChrome = true; core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent); core.platform.isQQ = /QQ/i.test(navigator.userAgent); core.platform.isWeChat = /MicroMessenger/i.test(navigator.userAgent); + this._init_checkLocalForage(); + core.platform.extendKeyboard = core.getLocalStorage("extendKeyboard", false); + if (window.FileReader) { + core.platform.fileReader = new FileReader(); + core.platform.fileReader.onload = function () { + core.readFileContent(core.platform.fileReader.result); + }; + core.platform.fileReader.onerror = function () { + if (core.platform.errorCallback) + core.platform.errorCallback(); + } + } +} + +core.prototype._init_checkLocalForage = function () { core.platform.useLocalForage = core.getLocalStorage('useLocalForage', !core.platform.isIOS); + var _error = function (e) { + main.log(e); + core.platform.useLocalForage = false; + }; if (core.platform.useLocalForage) { try { core.setLocalForage("__test__", lzw_encode("__test__"), function () { @@ -291,106 +312,43 @@ core.prototype.init = function (coreData, callback) { core.platform.useLocalForage = false; } else { - console.log("localForage supported!") + console.log("localForage supported!"); core.removeLocalForage("__test__"); } } - catch (e) { - main.log(e); - core.platform.useLocalForage = false; - } - }, function (e) { - main.log(e); - core.platform.useLocalForage = false; - }) + catch (e) {_error(e);} + }, _error) } - catch (e) { - main.log(e); - core.platform.useLocalForage = false; - } - }, function (e) { - main.log(e); - core.platform.useLocalForage = false; - }) - } - catch (e) { - main.log(e); - core.platform.useLocalForage = false; + catch (e) {_error(e);} + }, _error) } + catch (e) {_error(e);} } +} - core.platform.extendKeyboard = core.getLocalStorage("extendKeyboard", false); - - if (window.FileReader) { - core.platform.fileReader = new FileReader(); - core.platform.fileReader.onload = function () { - core.readFileContent(core.platform.fileReader.result); - }; - core.platform.fileReader.onerror = function () { - if (core.platform.errorCallback) - core.platform.errorCallback(); - } - } - - // 先从存储中读取BGM状态 - core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true); - if (!core.platform.isPC && (navigator.connection || {}).type != 'wifi') - core.musicStatus.bgmStatus = false; - core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); - - // switchs - core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); - core.flags.displayCritical = core.getLocalStorage('critical', core.flags.displayCritical); - core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', core.flags.displayExtraDamage); - +core.prototype._init_others = function () { + // 一些额外的东西 core.material.groundCanvas = document.createElement('canvas').getContext('2d'); core.material.groundCanvas.canvas.width = core.material.groundCanvas.canvas.height = 32; core.material.groundPattern = core.material.groundCanvas.createPattern(core.material.groundCanvas.canvas, 'repeat'); - - core.animateFrame.weather.fog = new Image(); - core.animateFrame.weather.fog.onerror = function () { - core.animateFrame.weather.fog = null; - } - core.animateFrame.weather.fog.src = "project/images/fog.png"; - - core.material.images.keyboard = new Image(); - core.material.images.keyboard.onerror = function () { - core.material.images.keyboard = null; - } - core.material.images.keyboard.src = "project/images/keyboard.png"; - core.bigmap.tempCanvas = document.createElement('canvas').getContext('2d'); - - ////// 记录所有的存档编号!!! ////// + core.loadImage('fog', function (name, img) { core.animateFrame.weather.fog = img; }); + core.loadImage('keyboard', function (name, img) {core.material.images.keyboard = img; }); + // 记录存档编号 core.saves.saveIndex = core.getLocalStorage('saveIndex', 1); - core.control.getSaveIndexes(function (indexes) { - core.saves.ids = indexes; - }); + core.control.getSaveIndexes(function (indexes) { core.saves.ids = indexes; }); +} - core.loader._load(function () { - // 设置勇士高度 - core.material.icons.hero.height = core.material.images.hero.height / 4; - // 行走图 - core.control.updateHeroIcon(); +core.prototype._afterLoadResources = function (callback) { + core.control._setRequestAnimationFrame(); - core.initStatus.maps = core.maps.initMaps(core.floorIds); - core.control._setRequestAnimationFrame(); + core.plugin = new function () {}; + core.plugin.__init__ = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.plugin; + core.plugin.__init__(); + core._forwardFunc("plugin"); - if (main.mode == 'play') - core.events.initGame(); - - if (functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins) { - core.plugin = new function () {}; - core.plugin.__init__ = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.plugin; - core.plugin.__init__(); - core._forwardFunc("plugin"); - } - - core.showStartAnimate(); - - if (callback) callback(); - - }); + core.showStartAnimate(); + if (callback) callback(); } core.prototype._forwardFuncs = function () { diff --git a/libs/data.js b/libs/data.js index e833cf37..684e71cb 100644 --- a/libs/data.js +++ b/libs/data.js @@ -9,8 +9,4 @@ data.prototype._init = function () { this.values = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.values; this.flags = data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d.flags; //delete(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d); -} - -data.prototype.getFirstData = function () { - return core.clone(this.firstData); } \ No newline at end of file diff --git a/libs/events.js b/libs/events.js index 13915ac9..31ad3d27 100644 --- a/libs/events.js +++ b/libs/events.js @@ -15,14 +15,15 @@ events.prototype._init = function () { // ------ 初始化,开始和结束 ------ // /// 初始化游戏 -events.prototype.initGame = function () { - return this.eventdata.initGame(); +events.prototype.resetGame = function (hero, hard, floorId, maps, values) { + return this.eventdata.resetGame(hero, hard, floorId, maps, values); } ////// 游戏开始事件 ////// events.prototype.startGame = function (hard, seed, route, callback) { main.dom.levelChooseButtons.style.display = 'none'; main.dom.startButtonGroup.style.display = 'none'; + hard = hard || ""; if (main.mode != 'play') return; @@ -40,7 +41,7 @@ events.prototype.startGame = function (hard, seed, route, callback) { events.prototype._startGame_start = function (hard, seed, route, callback) { console.log('开始游戏'); - core.resetStatus(core.firstData.hero, hard, null, null, core.initStatus.maps); + core.resetGame(core.firstData.hero, hard, null, core.initStatus.maps); var nowLoc = core.clone(core.getHeroLoc()); core.setHeroLoc('x', -1); core.setHeroLoc('y', -1); diff --git a/libs/items.js b/libs/items.js index 097ff627..ace9bb3b 100644 --- a/libs/items.js +++ b/libs/items.js @@ -21,6 +21,35 @@ items.prototype.getItems = function () { return core.clone(this.items); } +items.prototype._resetItems = function () { + // 只有运行时才能执行此函数! + if (main.mode != 'play') return; + + // 根据flag来对道具进行修改 + if (core.flags.bigKeyIsBox) { + core.material.items.bigKey.cls = 'items'; + core.material.items.bigKey.name = '钥匙盒'; + } + if (core.flags.pickaxeFourDirections) + core.material.items.pickaxe.text = "可以破坏勇士四周的墙"; + if (core.flags.bombFourDirections) + core.material.items.bomb.text = "可以炸掉勇士四周的怪物"; + if (core.flags.snowFourDirections) + core.material.items.bomb.text = "可以将四周的熔岩变成平地"; + if (core.flags.equipment) { + core.material.items.sword1.cls = 'equips'; + core.material.items.sword2.cls = 'equips'; + core.material.items.sword3.cls = 'equips'; + core.material.items.sword4.cls = 'equips'; + core.material.items.sword5.cls = 'equips'; + core.material.items.shield1.cls = 'equips'; + core.material.items.shield2.cls = 'equips'; + core.material.items.shield3.cls = 'equips'; + core.material.items.shield4.cls = 'equips'; + core.material.items.shield5.cls = 'equips'; + } +} + ////// “即捡即用类”道具的使用效果 ////// items.prototype.getItemEffect = function (itemId, itemNum) { var itemCls = core.material.items[itemId].cls; diff --git a/project/functions.js b/project/functions.js index 18d5cc6d..514993d1 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1,36 +1,45 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = { "events": { - "initGame": function() { - // 游戏开始前的一些初始化操作 + "resetGame": function (hero, hard, floorId, maps, values) { + // 重置整个游戏;此函数将在游戏开始时,或者每次读档时最先被调用 + // hero:勇士信息;hard:难度;floorId:当前楼层ID;maps:地图信息;values:全局数值信息 - // 根据flag来对道具进行修改 - if (core.flags.bigKeyIsBox) - core.material.items.bigKey = {'cls': 'items', 'name': '钥匙盒'}; - // 面前的墙?四周的墙? - if (core.flags.pickaxeFourDirections) - core.material.items.pickaxe.text = "可以破坏勇士四周的墙"; - if (core.flags.bombFourDirections) - core.material.items.bomb.text = "可以炸掉勇士四周的怪物"; - if (core.flags.snowFourDirections) - core.material.items.bomb.text = "可以将四周的熔岩变成平地"; - // 是否启用装备栏 - if (core.flags.equipboxButton) { - core.statusBar.image.fly.src = core.statusBar.icons.equipbox.src; - core.flags.equipment = true; - } - if (core.flags.equipment) { - core.material.items.sword1.cls = 'equips'; - core.material.items.sword2.cls = 'equips'; - core.material.items.sword3.cls = 'equips'; - core.material.items.sword4.cls = 'equips'; - core.material.items.sword5.cls = 'equips'; - core.material.items.shield1.cls = 'equips'; - core.material.items.shield2.cls = 'equips'; - core.material.items.shield3.cls = 'equips'; - core.material.items.shield4.cls = 'equips'; - core.material.items.shield5.cls = 'equips'; - } + // 清除游戏数据 + core.clearStatus(); + // 初始化status + core.status = core.clone(core.initStatus); + core.status.played = true; + // 初始化人物,图标,统计信息 + core.status.hero = core.clone(hero); + core.events.setHeroIcon(core.getFlag('heroIcon', 'hero.png'), true); + core.control._initStatistics(core.animateFrame.totalTime); + core.status.hero.statistics.totalTime = core.animateFrame.totalTime = + Math.max(core.status.hero.statistics.totalTime, core.animateFrame.totalTime); + core.status.hero.statistics.start = null; + // 初始难度 + core.status.hard = hard || ""; + // 初始化地图 + core.status.floorId = floorId; + core.status.maps = core.clone(maps); + // 初始化怪物和道具 + core.material.enemys = core.enemys.getEnemys(); + core.material.items = core.items.getItems(); + core.items._resetItems(); + // 初始化全局数值和全局开关 + core.values = core.clone(core.data.values); + for (var key in values || {}) + core.values[key] = values[key]; + core.flags = core.clone(core.data.flags); + var globalFlags = core.getFlag("globalFlags", {}); + for (var key in globalFlags) + core.flags[key] = globalFlags[key]; + // 初始化界面,状态栏等 + core.resize(); + core.updateGlobalAttribute(Object.keys(core.status.globalAttribute)); + core.triggerStatusBar(core.hasFlag('hideStatusBar') ? 'hide' : 'show', core.hasFlag('showToolbox')); + // 隐藏右下角的音乐按钮 + core.dom.musicBtn.style.display = 'none'; }, "setInitData": function () { // 不同难度分别设置初始属性 From ac8faed0f375ca7efc3ce651fa9b5ed63832f516 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 17 Mar 2019 18:54:11 +0800 Subject: [PATCH 027/153] _canMoveDirectly_checkStartPoint changeFloor --- libs/maps.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libs/maps.js b/libs/maps.js index cdc9cd52..de5b1d82 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -461,12 +461,10 @@ maps.prototype._canMoveDirectly_checkGlobal = function () { maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) { if (core.status.checkBlock.damage[sx + core.bigmap.width * sy] > 0) return false; - var id = core.getBlockId(sx, sy); - if (id != null) { - // 楼梯或者传送点才能无视 - if (["upFloor", "downFloor", "portal", "upPortal", "downPortal", "leftPortal", "rightPortal"].indexOf(id) >= 0) - return true; - return false; + var block = core.getBlock(sx, sy); + if (block != null) { + // 只有起点是传送点才是能无视 + return block.block.event.trigger == 'changeFloor'; } return true; } From ef5aa25047e36cceab0216779a297098d7a96890 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 00:01:18 +0800 Subject: [PATCH 028/153] automaticRoute & autoMove --- _docs/personalization.md | 2 +- _server/functions.comment.js | 11 +- libs/actions.js | 3 +- libs/control.js | 334 +++++++++++++---------------------- libs/items.js | 4 +- libs/maps.js | 69 ++++++++ libs/ui.js | 2 +- project/functions.js | 67 +++++-- 8 files changed, 251 insertions(+), 241 deletions(-) diff --git a/_docs/personalization.md b/_docs/personalization.md index c83c7eaa..f960eed9 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -972,7 +972,7 @@ this.getAchievements = function () { - **`flag:__color__`**, **`flag:__weather__`**, **`flag:__volume__`**: 当前的画面色调、天气和音量。 - **`flag:__events__`**: 当前保存的事件列表,读档时会恢复(适用于在事件中存档) - **`flag:textAttribute`**, **`flag:globalAttribute`**, **`flag:globalFlags`**: 当前的剧情文本属性,当前的全局属性,当前的全局开关。 -- **`flag:cannotMoveDirectly`**, **`flag:clickMove`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。 +- **`flag:cannotMoveDirectly`**, **`flag:__noClickMove__`**: 当前是否不允许瞬间移动,当前用户是否开启了单击瞬移。 - **`flag:hideStatusBar`**, **`flag:showToolbox`**: 是否隐藏状态栏,是否显示工具栏。 - **`flag:debug`**, **`flag:__consoleOpened__`**: 当前是否开启了调试模式,是否开启了控制台。 - **`flag:__seed__`**, **`flag:__rand__`**: 伪随机数生成种子和当前的状态 diff --git a/_server/functions.comment.js b/_server/functions.comment.js index bf25ed95..af73b831 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -105,7 +105,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } }, "enemys": { - "_type": "object", "_data": { "getSpecials": { @@ -135,7 +134,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } }, "actions": { - "_type": "object", "_data": { "onKeyUp": { @@ -147,7 +145,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } }, "control": { - "_type": "object", "_data": { "flyTo": { @@ -173,11 +170,16 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_lint": true, "_data": "勇士每走一步的操作" + }, + "moveDirectly": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "瞬间移动" } } }, "ui": { - "_type": "object", "_data": { "drawStatusBar": { @@ -201,7 +203,6 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = } }, "plugins": { - "_type": "object", "_data": { "parallelDo": { diff --git a/libs/actions.js b/libs/actions.js index 045cac89..c7e5fc70 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1789,7 +1789,8 @@ actions.prototype._clickSwitchs = function (x, y) { core.ui.drawSwitchs(); break; case 6: - core.setFlag('clickMove', !core.getFlag('clickMove', true)); + if (core.hasFlag('__noClickMove__')) core.removeFlag('__noClickMove__'); + else core.setFlag('__noClickMove__', true); core.ui.drawSwitchs(); break; case 7: diff --git a/libs/control.js b/libs/control.js index 570f9946..ad816cdc 100644 --- a/libs/control.js +++ b/libs/control.js @@ -374,20 +374,16 @@ control.prototype._initStatistics = function (totalTime) { } } - -/////////////////////// 寻路算法 & 人物行走控制 /////////////////////// +// ------ 自动寻路,人物行走 ------ // ////// 清除自动寻路路线 ////// control.prototype.clearAutomaticRouteNode = function (x, y) { - if (core.status.event.id==null) - core.clearMap('route', x * 32 + 5 - core.status.automaticRoute.offsetX, y * 32 + 5 - core.status.automaticRoute.offsetY, 27, 27); + core.clearMap('route', x * 32 + 5 - core.status.automaticRoute.offsetX, y * 32 + 5 - core.status.automaticRoute.offsetY, 27, 27); } ////// 停止自动寻路操作 ////// control.prototype.stopAutomaticRoute = function () { - if (!core.status.played) { - return; - } + if (!core.status.played) return; core.status.automaticRoute.autoHeroMove = false; core.status.automaticRoute.autoStep = 0; core.status.automaticRoute.destStep = 0; @@ -401,6 +397,7 @@ control.prototype.stopAutomaticRoute = function () { core.deleteCanvas('route'); } +////// 保存剩下的寻路,并停止 ////// control.prototype.saveAndStopAutomaticRoute = function () { var automaticRoute = core.status.automaticRoute; if (automaticRoute.moveStepBeforeStop.length == 0) { @@ -431,52 +428,33 @@ control.prototype.clearContinueAutomaticRoute = function (callback) { if (callback) callback(); } -////// 瞬间移动 ////// -control.prototype.moveDirectly = function (destX, destY) { - var ignoreSteps = core.canMoveDirectly(destX, destY); - if (ignoreSteps>=0) { - core.clearMap('hero'); - var lastDirection = core.status.route[core.status.route.length-1]; - if (['left', 'right', 'up', 'down'].indexOf(lastDirection)>=0) - core.setHeroLoc('direction', lastDirection); - core.setHeroLoc('x', destX); - core.setHeroLoc('y', destY); - core.drawHero(); - core.status.route.push("move:"+destX+":"+destY); - core.status.hero.statistics.moveDirectly++; - core.status.hero.statistics.ignoreSteps+=ignoreSteps; - return true; - } - return false; -} - -////// 尝试瞬间移动 ////// -control.prototype.tryMoveDirectly = function (destX, destY) { - if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1) - return false; - var canMoveArray = core.maps.generateMovableArray(); - var testMove = function (dx, dy, dir) { - if (dx<0 || dx>=core.bigmap.width|| dy<0 || dy>=core.bigmap.height) return false; - if (core.isset(dir) && !core.inArray(canMoveArray[dx][dy],dir)) return false; - if (core.control.moveDirectly(dx, dy)) { - if (core.isset(dir)) core.moveHero(dir, function() {}); - return true; - } - return false; - } - return testMove(destX,destY) || testMove(destX-1, destY, "right") || testMove(destX,destY-1,"down") - || testMove(destX,destY+1,"up") || testMove(destX+1,destY,"left"); +////// 显示离散的寻路点 ////// +control.prototype.fillPosWithPoint = function (pos) { + core.fillRect('ui', pos.x*32+12,pos.y*32+12,8,8, '#bfbfbf'); } ////// 设置自动寻路路线 ////// control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { - if (!core.status.played || core.status.lockControl) { - return; - } - // 正在寻路中 + if (!core.status.played || core.status.lockControl) return; + if (this._setAutomaticRoute_isMoving(destX, destY)) return; + if (this._setAutomaticRoute_isTurning(destX, destY, stepPostfix)) return; + if (this._setAutomaticRoute_clickMoveDirectly(destX, destY, stepPostfix)) return; + // 找寻自动寻路路线 + var moveStep = core.automaticRoute(destX, destY).concat(stepPostfix); + if (moveStep.length == 0) return core.deleteCanvas('route'); + core.status.automaticRoute.destX=destX; + core.status.automaticRoute.destY=destY; + this._setAutomaticRoute_drawRoute(moveStep); + this._setAutomaticRoute_setAutoSteps(moveStep); + // 立刻移动 + core.setAutoHeroMove(); +} + +control.prototype._setAutomaticRoute_isMoving = function (destX, destY) { if (core.status.automaticRoute.autoHeroMove) { var lastX = core.status.automaticRoute.destX, lastY=core.status.automaticRoute.destY; core.stopAutomaticRoute(); + // 双击瞬移 if (lastX==destX && lastY==destY) { core.status.automaticRoute.moveDirectly = true; setTimeout(function () { @@ -486,8 +464,12 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { core.status.automaticRoute.moveDirectly = false; }, core.values.moveSpeed || 100); } - return; + return true; } + return false; +} + +control.prototype._setAutomaticRoute_isTurning = function (destX, destY, stepPostfix) { if (destX == core.status.hero.loc.x && destY == core.status.hero.loc.y && stepPostfix.length==0) { if (core.timeout.turnHeroTimeout==null) { core.timeout.turnHeroTimeout = setTimeout(function() { @@ -501,27 +483,23 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { core.timeout.turnHeroTimeout = null; core.getNextItem(); } - return; + return true; } + if (core.timeout.turnHeroTimeout!=null) return true; + return false; +} - if (core.timeout.turnHeroTimeout!=null) return; - +control.prototype._setAutomaticRoute_clickMoveDirectly = function (destX, destY, stepPostfix) { // 单击瞬间移动 if (core.status.heroStop && core.status.heroMoving==0) { - if (stepPostfix.length<=1 && core.getFlag('clickMove', true) && core.control.tryMoveDirectly(destX, destY)) - return; + if (stepPostfix.length<=1 && !core.hasFlag('__noClickMove__') && core.control.tryMoveDirectly(destX, destY)) + return true; } + return false; +} - var moveStep = core.automaticRoute(destX, destY).concat(stepPostfix); - if (moveStep.length == 0) { - core.deleteCanvas('route'); - return; - } - - core.status.automaticRoute.destX=destX; - core.status.automaticRoute.destY=destY; - - // 计算绘制区域的宽高 +control.prototype._setAutomaticRoute_drawRoute = function (moveStep) { + // 计算绘制区域的宽高,并尽可能小的创建route层 var sx = core.bigmap.width * 32, sy = core.bigmap.height * 32, dx = 0, dy = 0; moveStep.forEach(function (t) { sx = Math.min(sx, t.x * 32); dx = Math.max(dx, t.x * 32); @@ -547,7 +525,9 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { ctx.stroke(); } } +} +control.prototype._setAutomaticRoute_setAutoSteps = function (moveStep) { // 路线转autoStepRoutes var step = 0, currStep = null; moveStep.forEach(function (t) { @@ -556,111 +536,17 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { step++; else { core.status.automaticRoute.autoStepRoutes.push({'direction': currStep, 'step': step}); - step = 1; + step = 1; } currStep = dir; }); core.status.automaticRoute.autoStepRoutes.push({'direction': currStep, 'step': step}); - - // 立刻移动 - core.setAutoHeroMove(); -} - -////// 自动寻路算法,找寻最优路径 ////// -control.prototype.automaticRoute = function (destX, destY) { - var fw = core.bigmap.width, fh = core.bigmap.height; - var startX = core.getHeroLoc('x'); - var startY = core.getHeroLoc('y'); - if (destX == startX && destY == startY) return []; - - var route = []; - var queue = new PriorityQueue({comparator: function (a,b) { - return a.depth - b.depth; - }}); - var ans = []; - - var canMoveArray = core.maps.generateMovableArray(); - - route[startX + fw * startY] = ''; - queue.queue({depth: 0, x: startX, y: startY}); - while (queue.length!=0) { - var curr = queue.dequeue(); - var deep = curr.depth, nowX = curr.x, nowY = curr.y; - - for (var direction in core.utils.scan) { - if (!core.inArray(canMoveArray[nowX][nowY], direction)) - continue; - - var nx = nowX + core.utils.scan[direction].x; - var ny = nowY + core.utils.scan[direction].y; - if (nx<0 || nx>=fw || ny<0 || ny>=fh) continue; - - var nid = nx + fw * ny; - - if (core.isset(route[nid])) continue; - - var deepAdd=1; - var nextId, nextBlock = core.getBlock(nx,ny); - if (nextBlock!=null){ - nextId = nextBlock.block.event.id; - // 绕过亮灯(因为只有一次通行机会很宝贵) - if(nextId == "light") deepAdd=100; - // 绕过路障 - // if (nextId.substring(nextId.length-3)=="Net") deepAdd=core.values.lavaDamage*10; - // 绕过血瓶 - if (!core.flags.potionWhileRouting && nextId.substring(nextId.length-6)=="Potion") deepAdd+=20; - // 绕过传送点 - if (nextBlock.block.event.trigger == 'changeFloor') deepAdd+=10; - } - deepAdd+=core.status.checkBlock.damage[nid]*10; - // 绕过捕捉 - if ((core.status.checkBlock.ambush||[])[nid]) - deepAdd += 10000; - - if (nx == destX && ny == destY) { - route[nid] = direction; - break; - } - if (core.noPass(nx, ny)) - continue; - - route[nid] = direction; - queue.queue({depth: deep+deepAdd, x: nx, y: ny}); - } - if (core.isset(route[destX + fw * destY])) break; - } - if (!core.isset(route[destX + fw * destY])) { - return []; - } - - var nowX = destX, nowY = destY; - while (nowX != startX || nowY != startY) { - var dir = route[nowX + fw * nowY]; - ans.push({'direction': dir, 'x': nowX, 'y': nowY}); - nowX -= core.utils.scan[dir].x; - nowY -= core.utils.scan[dir].y; - } - - ans.reverse(); - return ans; -} - -////// 显示离散的寻路点 ////// -control.prototype.fillPosWithPoint = function (pos) { - core.fillRect('ui', pos.x*32+12,pos.y*32+12,8,8, '#bfbfbf'); -} - -// 当前是否正在移动 -control.prototype.isMoving = function () { - return !core.status.heroStop || core.status.heroMoving > 0; } ////// 设置勇士的自动行走路线 ////// control.prototype.setAutoHeroMove = function (steps) { steps=steps||core.status.automaticRoute.autoStepRoutes; - if (steps.length == 0) { - return; - } + if (steps.length == 0) return; core.status.automaticRoute.autoStepRoutes=steps; core.status.automaticRoute.autoHeroMove = true; core.status.automaticRoute.autoStep = 1; @@ -670,35 +556,30 @@ control.prototype.setAutoHeroMove = function (steps) { ////// 设置行走的效果动画 ////// control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { - if (core.status.heroMoving>0) { - return; - } + if (core.status.heroMoving > 0) return; core.status.heroMoving=1; var toAdd = 1; - if (core.status.replay.speed>3) - toAdd = 2; - if (core.status.replay.speed>6) - toAdd = 4; - if (core.status.replay.speed>12) - toAdd = 8; + if (core.status.replay.speed>3) toAdd = 2; + if (core.status.replay.speed>6) toAdd = 4; + if (core.status.replay.speed>12) toAdd = 8; core.interval.heroMoveInterval = window.setInterval(function () { core.status.heroMoving+=toAdd; if (core.status.heroMoving>=8) { - core.setHeroLoc('x', x+core.utils.scan[direction].x, true); - core.setHeroLoc('y', y+core.utils.scan[direction].y, true); - core.control.updateFollowers(); - core.moveOneStep(); - core.clearMap('hero'); - core.drawHero(direction); clearInterval(core.interval.heroMoveInterval); core.status.heroMoving = 0; - if (core.isset(callback)) callback(); + core.moveOneStep(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y); + if (callback) callback(); } }, (core.values.moveSpeed||100) / 8 * toAdd / core.status.replay.speed); } +////// 每移动一格后执行的事件 ////// +control.prototype.moveOneStep = function(x, y) { + return this.controldata.moveOneStep(x, y); +} + ////// 实际每一步的行走过程 ////// control.prototype.moveAction = function (callback) { if (core.status.heroMoving>0) return; @@ -763,22 +644,6 @@ control.prototype.moveAction = function (callback) { } } -////// 转向 ////// -control.prototype.turnHero = function(direction) { - if (core.isset(direction)) { - core.setHeroLoc('direction', direction); - core.drawHero(); - core.status.route.push("turn:"+direction); - return; - } - if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; - else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; - else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; - else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; - core.drawHero(); - core.status.route.push("turn"); -} - ////// 让勇士开始移动 ////// control.prototype.moveHero = function (direction, callback) { // 如果正在移动,直接return @@ -822,6 +687,51 @@ control.prototype.moveHero = function (direction, callback) { } } +////// 当前是否正在移动 ////// +control.prototype.isMoving = function () { + return !core.status.heroStop || core.status.heroMoving > 0; +} + +////// 停止勇士的一切行动,等待勇士行动结束后,再执行callback ////// +control.prototype.waitHeroToStop = function(callback) { + var lastDirection = core.status.automaticRoute.lastDirection; + core.stopAutomaticRoute(); + core.clearContinueAutomaticRoute(); + if (core.isset(callback)) { + core.status.replay.animate=true; + core.lockControl(); + core.status.automaticRoute.moveDirectly = false; + setTimeout(function(){ + core.status.replay.animate=false; + if (core.isset(lastDirection)) + core.setHeroLoc('direction', lastDirection); + core.drawHero(); + callback(); + }, 30); + } +} + +////// 停止勇士的移动状态 ////// +control.prototype.stopHero = function () { + core.status.heroStop = true; +} + +////// 转向 ////// +control.prototype.turnHero = function(direction) { + if (core.isset(direction)) { + core.setHeroLoc('direction', direction); + core.drawHero(); + core.status.route.push("turn:"+direction); + return; + } + if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; + else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; + else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; + else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; + core.drawHero(); + core.status.route.push("turn"); +} + /////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// control.prototype.eventMoveHero = function(steps, time, callback) { time = time || core.values.moveSpeed || 100; @@ -949,33 +859,27 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { core.animateFrame.asyncId[animate] = true; } -////// 每移动一格后执行的事件 ////// -control.prototype.moveOneStep = function() { - return this.controldata.moveOneStep(); +////// 瞬间移动 ////// +control.prototype.moveDirectly = function (destX, destY) { + return this.controldata.moveDirectly(destX, destY); } -////// 停止勇士的一切行动,等待勇士行动结束后,再执行callback ////// -control.prototype.waitHeroToStop = function(callback) { - var lastDirection = core.status.automaticRoute.lastDirection; - core.stopAutomaticRoute(); - core.clearContinueAutomaticRoute(); - if (core.isset(callback)) { - core.status.replay.animate=true; - core.lockControl(); - core.status.automaticRoute.moveDirectly = false; - setTimeout(function(){ - core.status.replay.animate=false; - if (core.isset(lastDirection)) - core.setHeroLoc('direction', lastDirection); - core.drawHero(); - callback(); - }, 30); +////// 尝试瞬间移动 ////// +control.prototype.tryMoveDirectly = function (destX, destY) { + if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1) + return false; + var canMoveArray = core.maps.generateMovableArray(); + var testMove = function (dx, dy, dir) { + if (dx<0 || dx>=core.bigmap.width|| dy<0 || dy>=core.bigmap.height) return false; + if (core.isset(dir) && !core.inArray(canMoveArray[dx][dy],dir)) return false; + if (core.control.moveDirectly(dx, dy)) { + if (core.isset(dir)) core.moveHero(dir, function() {}); + return true; + } + return false; } -} - -////// 停止勇士的移动状态 ////// -control.prototype.stopHero = function () { - core.status.heroStop = true; + return testMove(destX,destY) || testMove(destX-1, destY, "right") || testMove(destX,destY-1,"down") + || testMove(destX,destY+1,"up") || testMove(destX+1,destY,"left"); } ////// 设置画布偏移 @@ -1038,7 +942,7 @@ control.prototype.drawHero = function (direction, x, y, status, offset) { core.clearAutomaticRouteNode(x+dx, y+dy); - core.clearMap('hero', x * 32 - core.bigmap.offsetX - 32, y * 32 - core.bigmap.offsetY - 32, 96, 96); + core.clearMap('hero', x * 32 - core.bigmap.offsetX - 32, y * 32 - core.bigmap.offsetY - 64, 96, 128); var heroIconArr = core.material.icons.hero; var drawObjs = []; diff --git a/libs/items.js b/libs/items.js index ace9bb3b..e61c23f9 100644 --- a/libs/items.js +++ b/libs/items.js @@ -156,7 +156,7 @@ items.prototype.canUseItem = function (itemId) { ////// 获得某个物品的个数 ////// items.prototype.itemCount = function (itemId) { - if (!core.material.items[itemId]) return 0; + if (!core.material.items[itemId] || !core.isPlaying()) return 0; var itemCls = core.material.items[itemId].cls; if (itemCls == "items") return 0; return core.status.hero.items[itemCls][itemId] || 0; @@ -169,7 +169,7 @@ items.prototype.hasItem = function (itemId) { ////// 是否装备某件装备 ////// items.prototype.hasEquip = function (itemId) { - if (!(core.material.items[itemId] || {}).equip) return null; + if (!(core.material.items[itemId] || {}).equip || !core.isPlaying()) return null; for (var i in core.status.hero.equipment) if (core.status.hero.equipment[i] == itemId) diff --git a/libs/maps.js b/libs/maps.js index de5b1d82..50fb037c 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -505,6 +505,75 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { return true; } +////// 自动寻路找寻最优路径 ////// +maps.prototype.automaticRoute = function (destX, destY) { + var startX = core.getHeroLoc('x'), startY = core.getHeroLoc('y'); + if (destX == startX && destY == startY) return []; + // BFS找寻最短路径 + var route = this._automaticRoute_bfs(startX, startY, destX, destY); + if (route[destX+","+destY] == null) return []; + // 路径数组转换 + var ans = [], nowX = destX, nowY = destY; + while (nowX != startX || nowY != startY) { + var dir = route[nowX + "," + nowY]; + ans.push({'direction': dir, 'x': nowX, 'y': nowY}); + nowX -= core.utils.scan[dir].x; + nowY -= core.utils.scan[dir].y; + } + ans.reverse(); + return ans; +} + +maps.prototype._automaticRoute_bfs = function (startX, startY, destX, destY) { + var route = {}, canMoveArray = this.generateMovableArray(); + // 使用优先队列 + var queue = new PriorityQueue({comparator: function (a,b) { return a.depth - b.depth; }}); + route[startX + "," + startY] = ''; + queue.queue({depth: 0, x: startX, y: startY}); + while (queue.length!=0) { + var curr = queue.dequeue(), deep = curr.depth, nowX = curr.x, nowY = curr.y; + for (var direction in core.utils.scan) { + if (!core.inArray(canMoveArray[nowX][nowY], direction)) continue; + var nx = nowX + core.utils.scan[direction].x; + var ny = nowY + core.utils.scan[direction].y; + if (nx<0 || nx>=core.bigmap.width || ny<0 || ny>=core.bigmap.height || route[nx+","+ny] != null) continue; + // 重点 + if (nx == destX && ny == destY) { + route[nx+","+ny] = direction; + break; + } + // 不可通行 + if (core.noPass(nx, ny)) continue; + route[nx+","+ny] = direction; + queue.queue({depth: deep + this._automaticRoute_deepAdd(nx, ny), x: nx, y: ny}); + } + if (route[destX+","+destY] != null) break; + } + return route; +} + +maps.prototype._automaticRoute_deepAdd = function (x, y) { + // 判定每个可通行点的损耗值,越高越应该绕路 + var deepAdd = 1; + var block = core.getBlock(x,y); + if (block != null){ + var id = block.block.event.id; + // 绕过亮灯 + if (id == "light") deepAdd += 100; + // 绕过路障 + if (id.endsWith("Net")) deepAdd += 100; + // 绕过血瓶 + if (!core.flags.potionWhileRouting && id.endsWith("Potion")) deepAdd += 100; + // 绕过传送点 + // if (nextBlock.block.event.trigger == 'changeFloor') deepAdd+=10; + } + // 绕过存在伤害的地方 + deepAdd += core.status.checkBlock.damage[x+","+y] * 100; + // 绕过捕捉 + if ((core.status.checkBlock.ambush||[])[x+","+y]) deepAdd += 1000; + return deepAdd; +} + // -------- 绘制地图,各层图块,楼层贴图,Autotile -------- // ////// 绘制一个图块 ////// diff --git a/libs/ui.js b/libs/ui.js index 6b381798..f7c437f8 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1155,7 +1155,7 @@ ui.prototype.drawSwitchs = function() { "临界显伤: "+(core.flags.displayCritical ? "[ON]" : "[OFF]"), "领域显伤: "+(core.flags.displayExtraDamage ? "[ON]" : "[OFF]"), "新版存档: "+(core.platform.useLocalForage ? "[ON]":"[OFF]"), - "单击瞬移: "+(core.getFlag('clickMove', true) ? "[ON]":"[OFF]"), + "单击瞬移: "+(!core.hasFlag("__noClickMove__") ? "[ON]":"[OFF]"), "拓展键盘: "+(core.platform.extendKeyboard ? "[ON]":"[OFF]"), "返回主菜单" ]; diff --git a/project/functions.js b/project/functions.js index 514993d1..d95259e8 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1156,26 +1156,61 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } } }, - "moveOneStep": function () { - // 勇士每走一步后执行的操作 - core.status.hero.steps++; - // 中毒状态:扣血 - if (core.hasFlag('poison')) { - core.status.hero.statistics.poisonDamage += core.values.poisonDamage; - core.status.hero.hp -= core.values.poisonDamage; - if (core.status.hero.hp<=0) { - core.status.hero.hp=0; - core.updateStatusBar(); - core.events.lose(); - return; - } - core.updateStatusBar(); - } - // 备注:瞬间移动不会执行该函数。如果要控制能否瞬间移动有三种方法: + "moveOneStep": function (x, y) { + // 勇士每走一步后执行的操作,x,y为要移动到的坐标。 + // 这个函数执行在“刚走完”的时候,即还没有检查该点的事件和领域伤害等。 + // 请注意:瞬间移动不会执行该函数。如果要控制能否瞬间移动有三种方法: // 1. 将全塔属性中的cannotMoveDirectly这个开关勾上,即可在全塔中全程禁止使用瞬移。 // 2, 将楼层属性中的cannotMoveDirectly这个开关勾上,即禁止在该层楼使用瞬移。 // 3. 将flag:cannotMoveDirectly置为true,即可使用flag控制在某段剧情范围内禁止瞬移。 + // 设置当前坐标,增加步数 + core.setHeroLoc('x', x, true); + core.setHeroLoc('y', y, true); + core.status.hero.steps++; + // 更新跟随者状态,并绘制 + core.updateFollowers(); + core.drawHero(); + // 检查中毒状态的扣血和死亡 + if (core.hasFlag('poison')) { + core.status.hero.statistics.poisonDamage += core.values.poisonDamage; + core.status.hero.hp -= core.values.poisonDamage; + if (core.status.hero.hp <= 0) { + core.status.hero.hp = 0; + core.updateStatusBar(); + core.events.lose(); + return; + } + } + // 如需强行终止行走可以在这里条件判定: + // core.stopAutomaticRoute(); + + core.updateStatusBar(); +}, + "moveDirectly": function (x, y) { + // 瞬间移动;x,y为要瞬间移动的点 + // 返回true代表成功瞬移,false代表没有成功瞬移 + + // 判定能否瞬移到该点 + var ignoreSteps = core.canMoveDirectly(x, y); + if (ignoreSteps >= 0) { + core.clearMap('hero'); + // 获得勇士最后的朝向 + var lastDirection = core.status.route[core.status.route.length - 1]; + if (['left', 'right', 'up', 'down'].indexOf(lastDirection) >= 0) + core.setHeroLoc('direction', lastDirection); + // 设置坐标,并绘制 + core.setHeroLoc('x', x); + core.setHeroLoc('y', y); + core.drawHero(); + // 记录录像 + core.status.route.push("move:" + x + ":" + y); + // 统计信息 + core.status.hero.statistics.moveDirectly++; + core.status.hero.statistics.ignoreSteps += ignoreSteps; + return true; + } + return false; } }, "ui": { From 6041236a0b2c19f3264a9107af4199f3db1b5e6f Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 01:32:49 +0800 Subject: [PATCH 029/153] MoveAction, moveHero, drawHero --- libs/control.js | 471 ++++++++++++++++-------------------------------- libs/events.js | 148 ++++++++++++++- 2 files changed, 299 insertions(+), 320 deletions(-) diff --git a/libs/control.js b/libs/control.js index ad816cdc..2924c3ff 100644 --- a/libs/control.js +++ b/libs/control.js @@ -555,7 +555,7 @@ control.prototype.setAutoHeroMove = function (steps) { } ////// 设置行走的效果动画 ////// -control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { +control.prototype.setHeroMoveInterval = function (callback) { if (core.status.heroMoving > 0) return; core.status.heroMoving=1; @@ -569,7 +569,7 @@ control.prototype.setHeroMoveInterval = function (direction, x, y, callback) { if (core.status.heroMoving>=8) { clearInterval(core.interval.heroMoveInterval); core.status.heroMoving = 0; - core.moveOneStep(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y); + core.moveOneStep(core.nextX(), core.nextY()); if (callback) callback(); } }, (core.values.moveSpeed||100) / 8 * toAdd / core.status.replay.speed); @@ -583,64 +583,70 @@ control.prototype.moveOneStep = function(x, y) { ////// 实际每一步的行走过程 ////// control.prototype.moveAction = function (callback) { if (core.status.heroMoving>0) return; - var direction = core.getHeroLoc('direction'); - var x = core.getHeroLoc('x'); - var y = core.getHeroLoc('y'); - var noPass = core.noPass(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y), canMove = core.canMoveHero(); - if (noPass || !canMove) { + var noPass = core.noPass(core.nextX(), core.nextY()), canMove = core.canMoveHero(); + // 下一个点如果不能走 + if (noPass || !canMove) return this._moveAction_noPass(canMove, callback); + this._moveAction_moving(callback); +} + +control.prototype._moveAction_noPass = function (canMove, callback) { + if (core.status.event.id!='ski') + core.status.route.push(core.getHeroLoc('direction')); + core.status.automaticRoute.moveStepBeforeStop = []; + core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); + if (canMove) core.trigger(core.nextX(), core.nextY()); + core.drawHero(); + + if (core.status.automaticRoute.moveStepBeforeStop.length==0) { + core.clearContinueAutomaticRoute(); + core.stopAutomaticRoute(); + } + if (callback) callback(); +} + +control.prototype._moveAction_moving = function (callback) { + core.setHeroMoveInterval(function () { + var direction = core.getHeroLoc('direction'); + core.control._moveAction_popAutomaticRoute(); if (core.status.event.id!='ski') core.status.route.push(direction); - core.status.automaticRoute.moveStepBeforeStop = []; - core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); - if (canMove) // 非箭头:触发 - core.events._trigger(x + core.utils.scan[direction].x, y + core.utils.scan[direction].y); - core.drawHero(direction, x, y); - if (core.status.automaticRoute.moveStepBeforeStop.length==0) { - core.clearContinueAutomaticRoute(); - core.stopAutomaticRoute(); + // 无事件的道具(如血瓶)需要优先于阻激夹域判定 + var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y'); + var block = core.getBlock(nowx,nowy); + var hasTrigger = false; + if (block!=null && block.block.event.trigger=='getItem' && + !core.floors[core.status.floorId].afterGetItem[nowx+","+nowy]) { + hasTrigger = true; + core.trigger(nowx, nowy); } - if (core.isset(callback)) - callback(); - } - else { - core.setHeroMoveInterval(direction, x, y, function () { - if (core.status.automaticRoute.autoHeroMove) { - core.status.automaticRoute.movedStep++; - core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); - if (core.status.automaticRoute.destStep == core.status.automaticRoute.movedStep) { - if (core.status.automaticRoute.autoStep == core.status.automaticRoute.autoStepRoutes.length) { - core.clearContinueAutomaticRoute(); - core.stopAutomaticRoute(); - } - else { - core.status.automaticRoute.movedStep = 0; - core.status.automaticRoute.destStep = core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].step; - core.setHeroLoc('direction', core.status.automaticRoute.autoStepRoutes[core.status.automaticRoute.autoStep].direction); - core.status.automaticRoute.autoStep++; - } - } - } - else if (core.status.heroStop) { - core.drawHero(); - } - if (core.status.event.id!='ski') - core.status.route.push(direction); + // 执行该点的阻激夹域事件 + core.checkBlock(); + // 执行该点事件 + if (!hasTrigger) + core.trigger(nowx, nowy); + if (callback) callback(); + }); +} - // 检查是不是无事件的道具 - var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y'); - var block = core.getBlock(nowx,nowy); - var hasTrigger = false; - if (block!=null && block.block.event.trigger=='getItem' && - !core.isset(core.floors[core.status.floorId].afterGetItem[nowx+","+nowy])) { - hasTrigger = true; - core.events._trigger(nowx, nowy); +control.prototype._moveAction_popAutomaticRoute = function () { + var automaticRoute = core.status.automaticRoute; + // 检查自动寻路是否被弹出 + if (automaticRoute.autoHeroMove) { + automaticRoute.movedStep++; + automaticRoute.lastDirection = core.getHeroLoc('direction'); + if (automaticRoute.destStep == automaticRoute.movedStep) { + if (automaticRoute.autoStep == automaticRoute.autoStepRoutes.length) { + core.clearContinueAutomaticRoute(); + core.stopAutomaticRoute(); } - core.checkBlock(); - if (!hasTrigger && !core.status.gameOver) - core.events._trigger(nowx, nowy); - if (core.isset(callback)) callback(); - }); + else { + automaticRoute.movedStep = 0; + automaticRoute.destStep = automaticRoute.autoStepRoutes[automaticRoute.autoStep].step; + core.setHeroLoc('direction', automaticRoute.autoStepRoutes[automaticRoute.autoStep].direction); + core.status.automaticRoute.autoStep++; + } + } } } @@ -650,41 +656,34 @@ control.prototype.moveHero = function (direction, callback) { if (core.status.heroMoving!=0) return; if (core.isset(direction)) core.setHeroLoc('direction', direction); - if (!core.isset(callback)) { // 如果不存在回调函数,则使用heroMoveTrigger - core.status.heroStop = false; - core.status.automaticRoute.moveDirectly = false; - var doAction = function () { - if (!core.status.heroStop) { - if (core.hasFlag('debug') && core.status.ctrlDown) { - if (core.status.heroMoving!=0) return; - // 检测是否穿出去 - direction = core.getHeroLoc('direction'); - var nx = core.getHeroLoc('x') + core.utils.scan[direction].x, ny=core.getHeroLoc('y') + core.utils.scan[direction].y; - if (nx<0 || nx>=core.bigmap.width || ny<0 || ny>=core.bigmap.height) return; + if (callback) return this.moveAction(callback); + this._moveHero_moving(); +} - core.status.heroMoving=-1; - core.eventMoveHero([direction], 100, function () { - core.status.heroMoving=0; - doAction(); - }); - } - else { - core.moveAction(); - setTimeout(doAction, 50); - } +control.prototype._moveHero_moving = function () { + // ------ 我已经看不懂这个函数了,反正好用就行23333333 + core.status.heroStop = false; + core.status.automaticRoute.moveDirectly = false; + var move = function () { + if (!core.status.heroStop) { + if (core.hasFlag('debug') && core.status.ctrlDown) { + if (core.status.heroMoving!=0) return; + // 检测是否穿出去 + if (!core.insideMap(1)) return; + core.status.heroMoving=-1; + core.eventMoveHero([core.getHeroLoc('direction')], core.values.moveSpeed, function () { + core.status.heroMoving=0; + move(); + }); } else { - core.stopHero(); + core.moveAction(); + setTimeout(move, 50); } } - doAction(); - } - else { // 否则,只向某个方向移动一步,然后调用callback - core.moveAction(function () { - callback(); - }) } + move(); } ////// 当前是否正在移动 ////// @@ -697,7 +696,7 @@ control.prototype.waitHeroToStop = function(callback) { var lastDirection = core.status.automaticRoute.lastDirection; core.stopAutomaticRoute(); core.clearContinueAutomaticRoute(); - if (core.isset(callback)) { + if (callback) { core.status.replay.animate=true; core.lockControl(); core.status.automaticRoute.moveDirectly = false; @@ -718,147 +717,18 @@ control.prototype.stopHero = function () { ////// 转向 ////// control.prototype.turnHero = function(direction) { - if (core.isset(direction)) { + if (direction) { core.setHeroLoc('direction', direction); core.drawHero(); core.status.route.push("turn:"+direction); return; } - if (core.status.hero.loc.direction == 'up') core.status.hero.loc.direction = 'right'; - else if (core.status.hero.loc.direction == 'right') core.status.hero.loc.direction = 'down'; - else if (core.status.hero.loc.direction == 'down') core.status.hero.loc.direction = 'left'; - else if (core.status.hero.loc.direction == 'left') core.status.hero.loc.direction = 'up'; + var dirs = {'up':'right','right':'down','down':'left','left':'up'}; + core.setHeroLoc('direction', dirs[core.getHeroLoc('direction')]); core.drawHero(); core.status.route.push("turn"); } -/////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// -control.prototype.eventMoveHero = function(steps, time, callback) { - time = time || core.values.moveSpeed || 100; - - // 要运行的轨迹:将steps展开 - var moveSteps=[]; - steps.forEach(function (e) { - if (typeof e=="string") { - moveSteps.push(e); - } - else { - if (!core.isset(e.value)) { - moveSteps.push(e.direction) - } - else { - for (var i=0;i=0;}); - - var step=0; - - var animate=window.setInterval(function() { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - if (moveSteps.length==0) { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.drawHero(null, x, y); - if (core.isset(callback)) callback(); - } - else { - var direction = moveSteps[0]; - - // ------ 前进/后退 - var o = direction == 'backward' ? -1 : 1; - if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); - - core.setHeroLoc('direction', direction); - step++; - if (step <= 4) { - core.drawHero(direction, x, y, 'leftFoot', 4 * o * step); - } - else if (step <= 8) { - core.drawHero(direction, x, y, 'rightFoot', 4 * o * step); - } - if (step == 8) { - step = 0; - core.setHeroLoc('x', x + o * core.utils.scan[direction].x, true); - core.setHeroLoc('y', y + o * core.utils.scan[direction].y, true); - core.control.updateFollowers(); - moveSteps.shift(); - } - } - }, time / 8 / core.status.replay.speed); - - core.animateFrame.asyncId[animate] = true; -} - -////// 勇士跳跃事件 ////// -control.prototype.jumpHero = function (ex, ey, time, callback) { - var sx=core.status.hero.loc.x, sy=core.status.hero.loc.y; - if (!core.isset(ex)) ex=sx; - if (!core.isset(ey)) ey=sy; - - time = time || 500; - - core.playSound('jump.mp3'); - - var dx = ex-sx, dy=ey-sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); - var jump_peak = 6 + distance, jump_count = jump_peak * 2; - var currx = sx, curry = sy; - - var heroIcon = core.material.icons.hero[core.getHeroLoc('direction')]; - var status = 'stop'; - var height = core.material.icons.hero.height; - - var drawX = function() { - return currx * 32; - } - var drawY = function() { - var ret = curry * 32; - if(jump_count >= jump_peak){ - var n = jump_count - jump_peak; - }else{ - var n = jump_peak - jump_count; - } - return ret - (jump_peak * jump_peak - n * n) / 2; - } - var updateJump = function() { - jump_count--; - currx = (currx * jump_count + ex) / (jump_count + 1.0); - curry = (curry * jump_count + ey) / (jump_count + 1.0); - } - - if (core.isset(core.status.hero.followers) && core.status.hero.followers.length>0) - core.clearMap('hero'); - - var animate=window.setInterval(function() { - - if (jump_count>0) { - core.clearMap('hero', drawX()-core.bigmap.offsetX, drawY()-height+32-core.bigmap.offsetY, 32, height); - updateJump(); - var nowx = drawX(), nowy = drawY(); - core.bigmap.offsetX = core.clamp(nowx - 32*6, 0, 32*core.bigmap.width-416); - core.bigmap.offsetY = core.clamp(nowy - 32*6, 0, 32*core.bigmap.height-416); - core.control.updateViewport(); - core.drawImage('hero', core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, - nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); - } - else { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.setHeroLoc('x', ex); - core.setHeroLoc('y', ey); - core.drawHero(); - if (core.isset(callback)) callback(); - } - - }, time / 16 / core.status.replay.speed); - - core.animateFrame.asyncId[animate] = true; -} - ////// 瞬间移动 ////// control.prototype.moveDirectly = function (destX, destY) { return this.controldata.moveDirectly(destX, destY); @@ -866,14 +736,13 @@ control.prototype.moveDirectly = function (destX, destY) { ////// 尝试瞬间移动 ////// control.prototype.tryMoveDirectly = function (destX, destY) { - if (Math.abs(core.getHeroLoc('x')-destX)+Math.abs(core.getHeroLoc('y')-destY)<=1) - return false; + if (this.nearHero(destX, destY)) return false; var canMoveArray = core.maps.generateMovableArray(); var testMove = function (dx, dy, dir) { if (dx<0 || dx>=core.bigmap.width|| dy<0 || dy>=core.bigmap.height) return false; - if (core.isset(dir) && !core.inArray(canMoveArray[dx][dy],dir)) return false; + if (dir && !core.inArray(canMoveArray[dx][dy],dir)) return false; if (core.control.moveDirectly(dx, dy)) { - if (core.isset(dir)) core.moveHero(dir, function() {}); + if (dir) core.moveHero(dir, function() {}); return true; } return false; @@ -882,6 +751,59 @@ control.prototype.tryMoveDirectly = function (destX, destY) { || testMove(destX,destY+1,"up") || testMove(destX+1,destY,"left"); } +////// 绘制勇士 ////// +control.prototype.drawHero = function (direction, x, y, status, offset) { + if (!core.isPlaying() || !core.status.floorId) return; + if (x == null) x = core.getHeroLoc('x'); + if (y == null) y = core.getHeroLoc('y'); + status = status || 'stop'; + direction = direction || core.getHeroLoc('direction'); + offset = offset || 0; + var way = core.utils.scan[direction]; + var dx = way.x, dy = way.y, offsetX = dx * offset, offsetY = dy * offset; + core.bigmap.offsetX = core.clamp((x - 6) * 32 + offsetX, 0, 32*core.bigmap.width-core.__PIXELS__); + core.bigmap.offsetY = core.clamp((y - 6) * 32 + offsetY, 0, 32*core.bigmap.height-core.__PIXELS__); + core.clearAutomaticRouteNode(x+dx, y+dy); + core.clearMap('hero'); + + this._drawHero_getDrawObjs(direction, x, y, status, offset).forEach(function (block) { + core.drawImage('hero', block.img, block.heroIcon[block.status]*32, + block.heroIcon.loc * block.height, 32, block.height, + block.posx, block.posy+32-block.height, 32, block.height); + }); + + core.control.updateViewport(); +} + +control.prototype._drawHero_getDrawObjs = function (direction, x, y, status, offset) { + var heroIconArr = core.material.icons.hero, drawObjs = [], index = 0; + drawObjs.push({ + "img": core.material.images.hero, + "height": core.material.icons.hero.height, + "heroIcon": heroIconArr[direction], + "posx": x * 32 - core.bigmap.offsetX + core.utils.scan[direction].x * offset, + "posy": y * 32 - core.bigmap.offsetY + core.utils.scan[direction].y * offset, + "status": status, + "index": index++, + }); + (core.status.hero.followers||[]).forEach(function (t) { + drawObjs.push({ + "img": t.img, + "height": t.img.height/4, + "heroIcon": heroIconArr[t.direction], + "posx": 32*t.x - core.bigmap.offsetX + (t.stop?0:core.utils.scan[t.direction].x*offset), + "posy": 32*t.y - core.bigmap.offsetY + (t.stop?0:core.utils.scan[t.direction].y*offset), + "status": t.stop?"stop":status, + "index": index++ + }); + }); + return drawObjs.sort(function(a, b) { + return a.posy==b.posy?b.index-a.index:a.posy-b.posy; + }); +} + +// ------ 画布、位置、阻激夹域等 ------ // + ////// 设置画布偏移 control.prototype.setGameCanvasTranslate = function(canvas,x,y){ var c=core.dom.gameCanvas[canvas]; @@ -922,73 +844,6 @@ control.prototype.updateViewport = function() { core.relocateCanvas('route', core.status.automaticRoute.offsetX - core.bigmap.offsetX, core.status.automaticRoute.offsetY - core.bigmap.offsetY); } -////// 绘制勇士 ////// -control.prototype.drawHero = function (direction, x, y, status, offset) { - - if (!core.isPlaying()) return; - - if (!core.isset(x)) x = core.getHeroLoc('x'); - if (!core.isset(y)) y = core.getHeroLoc('y'); - status = status || 'stop'; - direction = direction || core.getHeroLoc('direction'); - offset = offset || 0; - var way = core.utils.scan[direction]; - var offsetX = way.x*offset; - var offsetY = way.y*offset; - var dx=offsetX==0?0:offsetX/Math.abs(offsetX), dy=offsetY==0?0:offsetY/Math.abs(offsetY); - - core.bigmap.offsetX = core.clamp((x - 6) * 32 + offsetX, 0, 32*core.bigmap.width-416); - core.bigmap.offsetY = core.clamp((y - 6) * 32 + offsetY, 0, 32*core.bigmap.height-416); - - core.clearAutomaticRouteNode(x+dx, y+dy); - - core.clearMap('hero', x * 32 - core.bigmap.offsetX - 32, y * 32 - core.bigmap.offsetY - 64, 96, 128); - - var heroIconArr = core.material.icons.hero; - var drawObjs = []; - // add hero - drawObjs.push({ - "img": core.material.images.hero, - "height": core.material.icons.hero.height, - "heroIcon": heroIconArr[direction], - "posx": x * 32 - core.bigmap.offsetX + offsetX, - "posy": y * 32 - core.bigmap.offsetY + offsetY, - "status": status, - "index": 0, - }); - - // Add other followers - if (core.isset(core.status.hero.followers)) { - var index=1; - core.status.hero.followers.forEach(function (t) { - core.clearMap('hero', 32*t.x-core.bigmap.offsetX-32, 32*t.y-core.bigmap.offsetY-32, 96, 96); - if (core.isset(core.material.images.images[t.img])) { - drawObjs.push({ - "img": core.material.images.images[t.img], - "height": core.material.images.images[t.img].height/4, - "heroIcon": heroIconArr[t.direction], - "posx": 32*t.x - core.bigmap.offsetX + (t.stop?0:core.utils.scan[t.direction].x*offset), - "posy": 32*t.y - core.bigmap.offsetY + (t.stop?0:core.utils.scan[t.direction].y*offset), - "status": t.stop?"stop":status, - "index": index++ - }); - } - }); - } - - drawObjs.sort(function (a, b) { - return a.posy==b.posy?b.index-a.index:a.posy-b.posy; - }); - - drawObjs.forEach(function (block) { - core.drawImage('hero', block.img, block.heroIcon[block.status]*32, - block.heroIcon.loc * block.height, 32, block.height, - block.posx, block.posy+32-block.height, 32, block.height); - }); - - core.control.updateViewport(); -} - ////// 设置勇士的位置 ////// control.prototype.setHeroLoc = function (itemName, itemVal, noGather) { core.status.hero.loc[itemName] = itemVal; @@ -1018,11 +873,18 @@ control.prototype.nearHero = function (x, y) { return Math.abs(x-core.getHeroLoc('x'))+Math.abs(y-core.getHeroLoc('y'))<=1; } +////// 判定下一个点是否在界面外 ////// +control.prototype.insideMap = function (n) { + n = n || 0; + var x = n==0?core.getHeroLoc('x'):core.nextX(n), + y = n==0?core.getHeroLoc('y'):core.nextY(n); + return x>=0 && x < core.bigmap.width && y >= 0 && y < core.bigmap.height; +} + ////// 聚集跟随者 ////// control.prototype.gatherFollowers = function () { - if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return; var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), dir=core.getHeroLoc('direction'); - core.status.hero.followers.forEach(function (t) { + (core.status.hero.followers||[]).forEach(function (t) { t.x = x; t.y = y; t.stop = true; @@ -1032,8 +894,7 @@ control.prototype.gatherFollowers = function () { ////// 更新跟随者坐标 ////// control.prototype.updateFollowers = function () { - if (!core.isset(core.status.hero.followers) || core.status.hero.followers.length==0) return; - core.status.hero.followers.forEach(function (t) { + (core.status.hero.followers||[]).forEach(function (t) { if (!t.stop) { t.x += core.utils.scan[t.direction].x; t.y += core.utils.scan[t.direction].y; @@ -1041,30 +902,16 @@ control.prototype.updateFollowers = function () { }) var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y'); - core.status.hero.followers.forEach(function (t) { - if (t.x == nowx && t.y == nowy) { - t.stop = true; - } - else { - var dx = nowx-t.x, dy = nowy-t.y; - if (dx==-1) { - t.stop=false; - t.direction='left'; - } - else if (dx==1) { - t.stop=false; - t.direction='right'; - } - else if (dy==-1) { - t.stop=false; - t.direction='up'; - } - else if (dy==1) { - t.stop=false; - t.direction='down'; + (core.status.hero.followers||[]).forEach(function (t) { + t.stop = true; + var dx = nowx - t.x, dy = nowy - t.y; + for (var dir in core.utils.scan) { + if (core.utils.scan[dir].x == dx && core.utils.scan[dir].y == dy) { + t.stop = false; + t.direction = dir; } } - nowx=t.x; nowy=t.y; + nowx = t.x; nowy = t.y; }) } diff --git a/libs/events.js b/libs/events.js index 31ad3d27..475c3530 100644 --- a/libs/events.js +++ b/libs/events.js @@ -250,9 +250,14 @@ events.prototype.doSystemEvent = function (type, data, callback) { } ////// 触发(x,y)点的事件 ////// -events.prototype._trigger = function (x, y) { - // 如果正在自定义事件中,忽略 - if (core.status.event.id == 'action') return; +events.prototype.trigger = function (x, y) { + // 如果已经死亡,忽略 + if (core.status.gameOver) return; + // 如果正在自定义事件中,则插入 + if (core.status.event.id == 'action') { + core.insertAction({"type": "trigger", "loc": [x, y]}); + return; + } core.status.isSkiing = false; var block = core.getBlock(x, y); @@ -798,6 +803,7 @@ events.prototype._popEvents = function (current, prefix) { ////// 往当前事件列表之前添加一个或多个事件 ////// events.prototype.insertAction = function (action, x, y, callback) { if (core.hasFlag("__statistics__")) return; + if (core.status.gameOver) return; // ------ 判定commonEvent var commonEvent = this.getCommonEvent(action); @@ -1508,8 +1514,8 @@ events.prototype.follow = function (name) { core.status.hero.followers = core.status.hero.followers || []; if (core.material.images.images[name] && core.material.images.images[name].width == 128) { - core.status.hero.followers.push({"img": name}); - core.control.gatherFollowers(); + core.status.hero.followers.push({"name": name, "img": core.material.images.images[name]}); + core.gatherFollowers(); core.clearMap('hero'); core.drawHero(); } @@ -1519,17 +1525,17 @@ events.prototype.follow = function (name) { events.prototype.unfollow = function (name) { core.status.hero.followers = core.status.hero.followers || []; if (!name) { - core.status.heroMoving.followers = []; + core.status.hero.followers = []; } else { for (var i = 0; i < core.status.hero.followers.length; i++) { - if (core.status.hero.followers[i].img == name) { + if (core.status.hero.followers[i].name == name) { core.status.hero.followers.splice(i, 1); break; } } } - core.control.gatherFollowers(); + core.gatherFollowers(); core.clearMap('hero'); core.drawHero(); } @@ -1782,6 +1788,132 @@ events.prototype._vibrate_update = function (shakeInfo) { } } +/////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// +control.prototype.eventMoveHero = function(steps, time, callback) { + time = time || core.values.moveSpeed || 100; + + // 要运行的轨迹:将steps展开 + var moveSteps=[]; + steps.forEach(function (e) { + if (typeof e=="string") { + moveSteps.push(e); + } + else { + if (!core.isset(e.value)) { + moveSteps.push(e.direction) + } + else { + for (var i=0;i=0;}); + + var step=0; + + var animate=window.setInterval(function() { + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); + if (moveSteps.length==0) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + core.drawHero(null, x, y); + if (core.isset(callback)) callback(); + } + else { + var direction = moveSteps[0]; + + // ------ 前进/后退 + var o = direction == 'backward' ? -1 : 1; + if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); + + core.setHeroLoc('direction', direction); + step++; + if (step <= 4) { + core.drawHero(direction, x, y, 'leftFoot', 4 * o * step); + } + else if (step <= 8) { + core.drawHero(direction, x, y, 'rightFoot', 4 * o * step); + } + if (step == 8) { + step = 0; + core.setHeroLoc('x', x + o * core.utils.scan[direction].x, true); + core.setHeroLoc('y', y + o * core.utils.scan[direction].y, true); + core.updateFollowers(); + moveSteps.shift(); + } + } + }, time / 8 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; +} + +////// 勇士跳跃事件 ////// +control.prototype.jumpHero = function (ex, ey, time, callback) { + var sx=core.status.hero.loc.x, sy=core.status.hero.loc.y; + if (!core.isset(ex)) ex=sx; + if (!core.isset(ey)) ey=sy; + + time = time || 500; + + core.playSound('jump.mp3'); + + var dx = ex-sx, dy=ey-sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); + var jump_peak = 6 + distance, jump_count = jump_peak * 2; + var currx = sx, curry = sy; + + var heroIcon = core.material.icons.hero[core.getHeroLoc('direction')]; + var status = 'stop'; + var height = core.material.icons.hero.height; + + var drawX = function() { + return currx * 32; + } + var drawY = function() { + var ret = curry * 32; + if(jump_count >= jump_peak){ + var n = jump_count - jump_peak; + }else{ + var n = jump_peak - jump_count; + } + return ret - (jump_peak * jump_peak - n * n) / 2; + } + var updateJump = function() { + jump_count--; + currx = (currx * jump_count + ex) / (jump_count + 1.0); + curry = (curry * jump_count + ey) / (jump_count + 1.0); + } + + core.clearMap('hero'); + + var animate=window.setInterval(function() { + + if (jump_count>0) { + core.clearMap('hero', drawX()-core.bigmap.offsetX, drawY()-height+32-core.bigmap.offsetY, 32, height); + updateJump(); + var nowx = drawX(), nowy = drawY(); + core.bigmap.offsetX = core.clamp(nowx - 32*6, 0, 32*core.bigmap.width-416); + core.bigmap.offsetY = core.clamp(nowy - 32*6, 0, 32*core.bigmap.height-416); + core.control.updateViewport(); + core.drawImage('hero', core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, + nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); + } + else { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + core.setHeroLoc('x', ex); + core.setHeroLoc('y', ey); + core.drawHero(); + if (core.isset(callback)) callback(); + } + + }, time / 16 / core.status.replay.speed); + + core.animateFrame.asyncId[animate] = true; +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function (shopId, needVisited) { var shop = core.status.shops[shopId]; From 6e38f533bf2b92c2df33785e33da2aac8f0962ad Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 01:42:29 +0800 Subject: [PATCH 030/153] Replace 13/416 with core.__SIZE__ --- libs/control.js | 26 +++++++++++++------------- libs/events.js | 4 ++-- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/libs/control.js b/libs/control.js index 2924c3ff..1a509773 100644 --- a/libs/control.js +++ b/libs/control.js @@ -761,8 +761,8 @@ control.prototype.drawHero = function (direction, x, y, status, offset) { offset = offset || 0; var way = core.utils.scan[direction]; var dx = way.x, dy = way.y, offsetX = dx * offset, offsetY = dy * offset; - core.bigmap.offsetX = core.clamp((x - 6) * 32 + offsetX, 0, 32*core.bigmap.width-core.__PIXELS__); - core.bigmap.offsetY = core.clamp((y - 6) * 32 + offsetY, 0, 32*core.bigmap.height-core.__PIXELS__); + core.bigmap.offsetX = core.clamp((x - core.__HALF_SIZE__) * 32 + offsetX, 0, 32*core.bigmap.width-core.__PIXELS__); + core.bigmap.offsetY = core.clamp((y - core.__HALF_SIZE__) * 32 + offsetY, 0, 32*core.bigmap.height-core.__PIXELS__); core.clearAutomaticRouteNode(x+dx, y+dy); core.clearMap('hero'); @@ -814,10 +814,10 @@ control.prototype.setGameCanvasTranslate = function(canvas,x,y){ c.style.OTransform='translate('+x+'px,'+y+'px)'; c.style.MozTransform='translate('+x+'px,'+y+'px)'; if(main.mode==='editor' && editor.isMobile){ - c.style.transform='translate('+(x/416*96)+'vw,'+(y/416*96)+'vw)'; - c.style.webkitTransform='translate('+(x/416*96)+'vw,'+(y/416*96)+'vw)'; - c.style.OTransform='translate('+(x/416*96)+'vw,'+(y/416*96)+'vw)'; - c.style.MozTransform='translate('+(x/416*96)+'vw,'+(y/416*96)+'vw)'; + c.style.transform='translate('+(x/core.__PIXELS__*96)+'vw,'+(y/core.__PIXELS__*96)+'vw)'; + c.style.webkitTransform='translate('+(x/core.__PIXELS__*96)+'vw,'+(y/core.__PIXELS__*96)+'vw)'; + c.style.OTransform='translate('+(x/core.__PIXELS__*96)+'vw,'+(y/core.__PIXELS__*96)+'vw)'; + c.style.MozTransform='translate('+(x/core.__PIXELS__*96)+'vw,'+(y/core.__PIXELS__*96)+'vw)'; } }; @@ -1037,10 +1037,10 @@ control.prototype.setWeather = function (type, level) { if (!core.isset(level)) level=5; if (level<1) level=1; if (level>10) level=10; - level *= parseInt(20*core.bigmap.width*core.bigmap.height/169); + level *= parseInt(20*core.bigmap.width*core.bigmap.height/(core.__SIZE__*core.__SIZE__)); // 计算当前的宽高 - core.createCanvas('weather', 0, 0, 416, 416, 80); + core.createCanvas('weather', 0, 0, core.__PIXELS__, core.__PIXELS__, 80); core.animateFrame.weather.type = type; core.animateFrame.weather.level = level; core.animateFrame.weather.nodes = []; @@ -1099,7 +1099,7 @@ control.prototype.setFg = function(color, time, callback) { if (time==0) { // 直接变色 core.clearMap('curtain'); - core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA(color)); + core.fillRect('curtain', 0, 0, core.__PIXELS__, core.__PIXELS__, core.arrayToRGBA(color)); core.status.curtainColor = color; if (core.isset(callback)) callback(); return; @@ -1115,7 +1115,7 @@ control.prototype.setFg = function(color, time, callback) { (nowColor[3]*(step-1)+color[3])/step, ]; core.clearMap('curtain'); - core.fillRect('curtain', 0, 0, 416, 416, core.arrayToRGBA(nowColor)); + core.fillRect('curtain', 0, 0, core.__PIXELS__, core.__PIXELS__, core.arrayToRGBA(nowColor)); step--; if (step <= 0) { @@ -1612,13 +1612,13 @@ control.prototype.replay = function () { var shop=core.status.shops[shopId]; if (core.isset(shop) && shop.visited) { // 商店可用 var choices = shop.choices; - var topIndex = 6 - parseInt(choices.length / 2); + var topIndex = core.__HALF_SIZE__ - parseInt(choices.length / 2); core.status.event.selection = parseInt(selections.shift()); core.events.openShop(shopId, false); var shopInterval = setInterval(function () { - if (!core.actions._clickShop(6, topIndex+core.status.event.selection)) { + if (!core.actions._clickShop(core.__HALF_SIZE__, topIndex+core.status.event.selection)) { clearInterval(shopInterval); core.stopReplay(); core.drawTip("录像文件出错"); @@ -1626,7 +1626,7 @@ control.prototype.replay = function () { } if (selections.length==0) { clearInterval(shopInterval); - core.actions._clickShop(6, topIndex+choices.length); + core.actions._clickShop(core.__HALF_SIZE__, topIndex+choices.length); core.replay(); return; } diff --git a/libs/events.js b/libs/events.js index 475c3530..e0a988df 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1894,8 +1894,8 @@ control.prototype.jumpHero = function (ex, ey, time, callback) { core.clearMap('hero', drawX()-core.bigmap.offsetX, drawY()-height+32-core.bigmap.offsetY, 32, height); updateJump(); var nowx = drawX(), nowy = drawY(); - core.bigmap.offsetX = core.clamp(nowx - 32*6, 0, 32*core.bigmap.width-416); - core.bigmap.offsetY = core.clamp(nowy - 32*6, 0, 32*core.bigmap.height-416); + core.bigmap.offsetX = core.clamp(nowx - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.width-core.__PIXELS__); + core.bigmap.offsetY = core.clamp(nowy - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.height-core.__PIXELS__); core.control.updateViewport(); core.drawImage('hero', core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); From 9ac105ebff0e6e45721a9a87bf896d6ebf0af848 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 03:00:18 +0800 Subject: [PATCH 031/153] eventMoveHero & jumpHero --- libs/control.js | 2 +- libs/events.js | 165 +++++++++++++++++++----------------------------- libs/maps.js | 32 ++++++---- libs/utils.js | 20 ------ 4 files changed, 86 insertions(+), 133 deletions(-) diff --git a/libs/control.js b/libs/control.js index 1a509773..a9363be0 100644 --- a/libs/control.js +++ b/libs/control.js @@ -175,7 +175,7 @@ control.prototype._animationFrame_animate = function (timestamp) { } control.prototype._animationFrame_heroMoving = function (timestamp) { - if (!core.isMoving()) return; + if (core.status.heroMoving <= 0) return; var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); // 换腿 if (timestamp - core.animateFrame.moveTime > (core.values.moveSpeed||100)) { diff --git a/libs/events.js b/libs/events.js index e0a988df..be7371c0 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1789,131 +1789,96 @@ events.prototype._vibrate_update = function (shakeInfo) { } /////// 使用事件让勇士移动。这个函数将不会触发任何事件 ////// -control.prototype.eventMoveHero = function(steps, time, callback) { +events.prototype.eventMoveHero = function(steps, time, callback) { time = time || core.values.moveSpeed || 100; - - // 要运行的轨迹:将steps展开 - var moveSteps=[]; - steps.forEach(function (e) { - if (typeof e=="string") { - moveSteps.push(e); - } - else { - if (!core.isset(e.value)) { - moveSteps.push(e.direction) - } - else { - for (var i=0;i=0; }); - - moveSteps = moveSteps.filter(function (t) { return ['up','down','left','right','forward','backward'].indexOf(t)>=0;}); - - var step=0; - var animate=window.setInterval(function() { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); if (moveSteps.length==0) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); - core.drawHero(null, x, y); - if (core.isset(callback)) callback(); + core.drawHero(); + if (callback) callback(); } else { - var direction = moveSteps[0]; - - // ------ 前进/后退 - var o = direction == 'backward' ? -1 : 1; - if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); - - core.setHeroLoc('direction', direction); - step++; - if (step <= 4) { - core.drawHero(direction, x, y, 'leftFoot', 4 * o * step); - } - else if (step <= 8) { - core.drawHero(direction, x, y, 'rightFoot', 4 * o * step); - } - if (step == 8) { + if (core.events._eventMoveHero_moving(++step, moveSteps)) step = 0; - core.setHeroLoc('x', x + o * core.utils.scan[direction].x, true); - core.setHeroLoc('y', y + o * core.utils.scan[direction].y, true); - core.updateFollowers(); - moveSteps.shift(); - } } }, time / 8 / core.status.replay.speed); core.animateFrame.asyncId[animate] = true; } +events.prototype._eventMoveHero_moving = function (step, moveSteps) { + var direction = moveSteps[0], x = core.getHeroLoc('x'), y = core.getHeroLoc('y'); + // ------ 前进/后退 + var o = direction == 'backward' ? -1 : 1; + if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); + core.setHeroLoc('direction', direction); + if (step <= 4) { + core.drawHero(direction, x, y, 'leftFoot', 4 * o * step); + } + else if (step <= 8) { + core.drawHero(direction, x, y, 'rightFoot', 4 * o * step); + } + if (step == 8) { + core.setHeroLoc('x', x + o * core.utils.scan[direction].x, true); + core.setHeroLoc('y', y + o * core.utils.scan[direction].y, true); + core.updateFollowers(); + moveSteps.shift(); + return true; + } + return false; +} + ////// 勇士跳跃事件 ////// -control.prototype.jumpHero = function (ex, ey, time, callback) { +events.prototype.jumpHero = function (ex, ey, time, callback) { + var sx = core.getHeroLoc('x'), sy = core.getHeroLoc('y'); + if (ex == null) ex = sx; + if (ey == null) ey = sy; var sx=core.status.hero.loc.x, sy=core.status.hero.loc.y; if (!core.isset(ex)) ex=sx; if (!core.isset(ey)) ey=sy; + core.maps.__playJumpSound(); + var jumpInfo = core.maps.__generateJumpInfo(sx, sy, ex, ey, time || 500); + jumpInfo.icon = core.material.icons.hero[core.getHeroLoc('direction')]; + jumpInfo.height = core.material.icons.hero.height; - time = time || 500; + this._jumpHero_doJump(jumpInfo, callback); +} - core.playSound('jump.mp3'); - - var dx = ex-sx, dy=ey-sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); - var jump_peak = 6 + distance, jump_count = jump_peak * 2; - var currx = sx, curry = sy; - - var heroIcon = core.material.icons.hero[core.getHeroLoc('direction')]; - var status = 'stop'; - var height = core.material.icons.hero.height; - - var drawX = function() { - return currx * 32; - } - var drawY = function() { - var ret = curry * 32; - if(jump_count >= jump_peak){ - var n = jump_count - jump_peak; - }else{ - var n = jump_peak - jump_count; - } - return ret - (jump_peak * jump_peak - n * n) / 2; - } - var updateJump = function() { - jump_count--; - currx = (currx * jump_count + ex) / (jump_count + 1.0); - curry = (curry * jump_count + ey) / (jump_count + 1.0); - } - - core.clearMap('hero'); - - var animate=window.setInterval(function() { - - if (jump_count>0) { - core.clearMap('hero', drawX()-core.bigmap.offsetX, drawY()-height+32-core.bigmap.offsetY, 32, height); - updateJump(); - var nowx = drawX(), nowy = drawY(); - core.bigmap.offsetX = core.clamp(nowx - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.width-core.__PIXELS__); - core.bigmap.offsetY = core.clamp(nowy - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.height-core.__PIXELS__); - core.control.updateViewport(); - core.drawImage('hero', core.material.images.hero, heroIcon[status] * 32, heroIcon.loc * height, 32, height, - nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); - } - else { - delete core.animateFrame.asyncId[animate]; - clearInterval(animate); - core.setHeroLoc('x', ex); - core.setHeroLoc('y', ey); - core.drawHero(); - if (core.isset(callback)) callback(); - } - - }, time / 16 / core.status.replay.speed); +events.prototype._jumpHero_doJump = function (jumpInfo, callback) { + var animate = window.setInterval(function () { + if (jumpInfo.jump_count > 0) + core.events._jumpHero_jumping(jumpInfo) + else + core.events._jumpHero_finished(animate, jumpInfo.ex, jumpInfo.ey, callback); + }, jumpInfo.per_time); core.animateFrame.asyncId[animate] = true; } +events.prototype._jumpHero_jumping = function (jumpInfo) { + core.clearMap('hero'); + core.maps.__updateJumpInfo(jumpInfo); + var nowx = jumpInfo.px, nowy = jumpInfo.py, height = jumpInfo.height; + core.bigmap.offsetX = core.clamp(nowx - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.width-core.__PIXELS__); + core.bigmap.offsetY = core.clamp(nowy - 32*core.__HALF_SIZE__, 0, 32*core.bigmap.height-core.__PIXELS__); + core.control.updateViewport(); + core.drawImage('hero', core.material.images.hero, jumpInfo.icon.stop, jumpInfo.icon.loc * height, 32, height, + nowx - core.bigmap.offsetX, nowy + 32-height - core.bigmap.offsetY, 32, height); +} + +events.prototype._jumpHero_finished = function (animate, ex, ey, callback) { + delete core.animateFrame.asyncId[animate]; + clearInterval(animate); + core.setHeroLoc('x', ex); + core.setHeroLoc('y', ey); + core.drawHero(); + if (callback) callback(); +} + ////// 打开一个全局商店 ////// events.prototype.openShop = function (shopId, needVisited) { var shop = core.status.shops[shopId]; diff --git a/libs/maps.js b/libs/maps.js index 50fb037c..16e2eff4 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1545,7 +1545,9 @@ maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) { return; } var block = blockArr[0], blockInfo = blockArr[1]; - var moveSteps = core.utils.expandMoveSteps(steps); + var moveSteps = (steps||[]).filter(function (t) { + return ['up','down','left','right'].indexOf(t)>=0; + }); var canvases = this._initDetachedBlock(blockInfo, x, y, block.event.animate !== false); this._moveDetachedBlock(blockInfo, 32 * x, 32 * y, 1, canvases); @@ -1609,19 +1611,25 @@ maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) { var canvases = this._initDetachedBlock(blockInfo, sx, sy, block.event.animate !== false); this._moveDetachedBlock(blockInfo, 32 * sx, 32 * sy, 1, canvases); - this._jumpBlock_playSound(); + this.__playJumpSound(); + + var jumpInfo = ths.__generateJumpInfo(sx, sy, ex, ey, time); + jumpInfo.keep = keep; - var dx = ex - sx, dy = ey - sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); - var jump_peak = 6 + distance, jump_count = jump_peak * 2; - var jumpInfo = { - x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, keep: keep, - jump_peak: jump_peak, jump_count: jump_count, - step: 0, per_time: time / 16 / core.status.replay.speed - }; this._jumpBlock_doJump(blockInfo, canvases, jumpInfo, callback); } -maps.prototype._jumpBlock_playSound = function () { +maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) { + var dx = ex - sx, dy = ey - sy, distance = Math.round(Math.sqrt(dx * dx + dy * dy)); + var jump_peak = 6 + distance, jump_count = jump_peak * 2; + return { + x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, + jump_peak: jump_peak, jump_count: jump_count, + step: 0, per_time: time / 16 / core.status.replay.speed + }; +} + +maps.prototype.__playJumpSound = function () { core.playSound('jump.mp3'); } @@ -1636,7 +1644,7 @@ maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, call core.animateFrame.asyncId[animate] = true; } -maps.prototype._jumpBlock_updateJump = function (jumpInfo) { +maps.prototype.__updateJumpInfo = function (jumpInfo) { jumpInfo.jump_count--; jumpInfo.x = (jumpInfo.x * jumpInfo.jump_count + jumpInfo.ex) / (jumpInfo.jump_count + 1.0); jumpInfo.y = (jumpInfo.y * jumpInfo.jump_count + jumpInfo.ey) / (jumpInfo.jump_count + 1.0); @@ -1646,7 +1654,7 @@ maps.prototype._jumpBlock_updateJump = function (jumpInfo) { } maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) { - this._jumpBlock_updateJump(jumpInfo); + this.__updateJumpInfo(jumpInfo); core.maps._moveDetachedBlock(blockInfo, jumpInfo.px, jumpInfo.py, jumpInfo.opacity, canvases); } diff --git a/libs/utils.js b/libs/utils.js index 8e4bdfc1..013e669d 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -604,26 +604,6 @@ utils.prototype.getCookie = function (name) { return match ? match[2] : null; } -utils.prototype.expandMoveSteps = function (steps) { - var moveSteps = []; - steps.forEach(function (e) { - if (typeof e == "string") { - moveSteps.push(e); - } - else { - if (e.value == null) { - moveSteps.push(e.direction) - } - else { - for (var i = 0; i < e.value; i++) { - moveSteps.push(e.direction); - } - } - } - }); - return moveSteps; -} - ////// 设置statusBar的innerHTML,会自动斜体和放缩,也可以增加自定义css ////// utils.prototype.setStatusBarInnerHTML = function (name, value, css) { if (typeof value == 'number') value = this.formatBigNumber(value); From 58c0b8f1cecc6795599225407d2b2bcd7855f34c Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 18 Mar 2019 18:15:27 +0800 Subject: [PATCH 032/153] checkBlock --- libs/control.js | 145 +++++++++----------------- libs/events.js | 17 ++- libs/maps.js | 12 +-- libs/utils.js | 5 + project/functions.js | 242 ++++++++++++++++++++++--------------------- 5 files changed, 188 insertions(+), 233 deletions(-) diff --git a/libs/control.js b/libs/control.js index a9363be0..699bc34d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -182,7 +182,7 @@ control.prototype._animationFrame_heroMoving = function (timestamp) { core.animateFrame.leftLeg = !core.animateFrame.leftLeg; core.animateFrame.moveTime = timestamp; } - core.drawHero(direction, x, y, core.animateFrame.leftLeg?'leftFoot':'rightFoot', 4*core.status.heroMoving); + core.drawHero(core.animateFrame.leftLeg?'leftFoot':'rightFoot', 4*core.status.heroMoving); } control.prototype._animationFrame_weather = function (timestamp) { @@ -315,6 +315,7 @@ control.prototype._showStartAnimate_resetDom = function () { core.dom.musicBtn.style.display = 'block'; // 重置音量 core.events.setVolume(1, 0); + core.updateStatusBar(); } control.prototype._showStartAnimate_finished = function (start, callback) { @@ -594,7 +595,7 @@ control.prototype._moveAction_noPass = function (canMove, callback) { core.status.route.push(core.getHeroLoc('direction')); core.status.automaticRoute.moveStepBeforeStop = []; core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); - if (canMove) core.trigger(core.nextX(), core.nextY()); + if (canMove) core.events._trigger(core.nextX(), core.nextY()); core.drawHero(); if (core.status.automaticRoute.moveStepBeforeStop.length==0) { @@ -618,13 +619,14 @@ control.prototype._moveAction_moving = function (callback) { if (block!=null && block.block.event.trigger=='getItem' && !core.floors[core.status.floorId].afterGetItem[nowx+","+nowy]) { hasTrigger = true; - core.trigger(nowx, nowy); + core.events._trigger(nowx, nowy); } // 执行该点的阻激夹域事件 core.checkBlock(); // 执行该点事件 if (!hasTrigger) - core.trigger(nowx, nowy); + core.events._trigger(nowx, nowy); + core.updateStatusBar(); if (callback) callback(); }); } @@ -670,7 +672,8 @@ control.prototype._moveHero_moving = function () { if (core.hasFlag('debug') && core.status.ctrlDown) { if (core.status.heroMoving!=0) return; // 检测是否穿出去 - if (!core.insideMap(1)) return; + var nx = core.nextX(), ny = core.nextY(); + if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height) return; core.status.heroMoving=-1; core.eventMoveHero([core.getHeroLoc('direction')], core.values.moveSpeed, function () { core.status.heroMoving=0; @@ -752,12 +755,10 @@ control.prototype.tryMoveDirectly = function (destX, destY) { } ////// 绘制勇士 ////// -control.prototype.drawHero = function (direction, x, y, status, offset) { +control.prototype.drawHero = function (status, offset) { if (!core.isPlaying() || !core.status.floorId) return; - if (x == null) x = core.getHeroLoc('x'); - if (y == null) y = core.getHeroLoc('y'); + var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); status = status || 'stop'; - direction = direction || core.getHeroLoc('direction'); offset = offset || 0; var way = core.utils.scan[direction]; var dx = way.x, dy = way.y, offsetX = dx * offset, offsetY = dy * offset; @@ -854,7 +855,7 @@ control.prototype.setHeroLoc = function (itemName, itemVal, noGather) { ////// 获得勇士的位置 ////// control.prototype.getHeroLoc = function (itemName) { - if (!core.isset(itemName)) return core.status.hero.loc; + if (itemName == null) return core.status.hero.loc; return core.status.hero.loc[itemName]; } @@ -873,14 +874,6 @@ control.prototype.nearHero = function (x, y) { return Math.abs(x-core.getHeroLoc('x'))+Math.abs(y-core.getHeroLoc('y'))<=1; } -////// 判定下一个点是否在界面外 ////// -control.prototype.insideMap = function (n) { - n = n || 0; - var x = n==0?core.getHeroLoc('x'):core.nextX(n), - y = n==0?core.getHeroLoc('y'):core.nextY(n); - return x>=0 && x < core.bigmap.width && y >= 0 && y < core.bigmap.height; -} - ////// 聚集跟随者 ////// control.prototype.gatherFollowers = function () { var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), dir=core.getHeroLoc('direction'); @@ -922,99 +915,55 @@ control.prototype.updateCheckBlock = function(floorId) { ////// 检查并执行领域、夹击、阻击事件 ////// control.prototype.checkBlock = function () { - var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'); - var damage = core.status.checkBlock.damage[x+core.bigmap.width*y]; - if (damage>0) { + var x=core.getHeroLoc('x'), y=core.getHeroLoc('y'), loc = x+","+y; + var damage = core.status.checkBlock.damage[loc]; + if (damage) { core.status.hero.hp -= damage; - - // 检查阻击事件 - var snipe = []; - if (!core.hasFlag("no_snipe")) { - for (var direction in core.utils.scan) { - var nx = x+core.utils.scan[direction].x, ny=y+core.utils.scan[direction].y; - if (nx<0 || nx>=core.bigmap.width || ny<0 || ny>=core.bigmap.height) continue; - var id=core.status.checkBlock.map[nx+core.bigmap.width*ny]; - if (core.isset(id)) { - var enemy = core.material.enemys[id]; - if (core.isset(enemy) && core.enemys.hasSpecial(enemy.special, 18)) { - snipe.push({'direction': direction, 'x': nx, 'y': ny}); - } - } - } - } - - if (core.status.checkBlock.betweenAttack[x+core.bigmap.width*y] && damage>0) { - core.drawTip('受到夹击,生命变成一半'); - } - else if (core.status.checkBlock.map[x+core.bigmap.width*y]=='lavaNet') { - core.drawTip('受到血网伤害'+damage+'点'); - } - // 阻击 - else if (snipe.length>0 && damage>0) { - core.drawTip('受到阻击伤害'+damage+'点'); - } - else if (damage>0) { - core.drawTip('受到领域或激光伤害'+damage+'点'); - } - - if (damage>0) { - core.playSound('zone.mp3'); - core.drawAnimate("zone", x, y); - - // 禁用快捷商店 - if (core.flags.disableShopOnDamage) { - for (var shopId in core.status.shops) { - core.status.shops[shopId].visited = false; - } - } - - } - core.status.hero.statistics.extraDamage += damage; - - if (core.status.hero.hp<=0) { + core.drawTip("受到"+(core.status.checkBlock.type[loc]||"伤害")+damage+"点"); + this._checkBlock_soundAndAnimate(x, y); + if (core.status.hero.hp <= 0) { core.status.hero.hp=0; core.updateStatusBar(); core.events.lose(); return; } - snipe = snipe.filter(function (t) { - var x=t.x, y=t.y, direction = t.direction; - var nx = x+core.utils.scan[direction].x, ny=y+core.utils.scan[direction].y; - - return nx>=0 && nx=0 && ny0) - core.snipe(snipe); - } - // 检查捕捉 - var ambush = (core.status.checkBlock.ambush||[])[x+core.bigmap.width*y]; - if (core.isset(ambush)) { - // 捕捉效果 - var actions = []; - ambush.forEach(function (t) { - actions.push({"type": "move", "loc": [t[0],t[1]], "steps": [t[3]], "time": 500, "keep": false, "async":true}); - }); - actions.push({"type": "waitAsync"}); - // 强制战斗 - ambush.forEach(function (t) { - actions.push({"type": "battle", "id": t[2]}); - }) - core.insertAction(actions); } + this._checkBlock_snipe(core.status.checkBlock.snipe[loc]); + this._checkBlock_ambush(core.status.checkBlock.ambush[loc]); } -////// 阻击事件(动画效果) ////// -control.prototype.snipe = function (snipes) { - // 阻击改成moveBlock事件完成 +control.prototype._checkBlock_soundAndAnimate = function (x,y) { + core.playSound('zone.mp3'); + core.drawAnimate("zone", x, y); +} + +////// 阻击 ////// +control.prototype._checkBlock_snipe = function (snipe) { + if (!snipe || snipe.length == 0) return; var actions = []; - snipes.forEach(function (t) { - actions.push({"type": "move", "loc": [t.x, t.y], "steps": [t.direction], "time": 500, "keep": true, "async": true}); + snipe.forEach(function (t) { + actions.push({"type": "move", "loc": [t[0],t[1]], "steps": [t[3]], "time": 500, "keep": true, "async": true}); }); actions.push({"type": "waitAsync"}); core.insertAction(actions); } +////// 捕捉 ////// +control.prototype._checkBlock_ambush = function (ambush) { + if (!ambush || ambush.length == 0) return; + // 捕捉效果 + var actions = []; + ambush.forEach(function (t) { + actions.push({"type": "move", "loc": [t[0],t[1]], "steps": [t[3]], "time": 500, "keep": false, "async":true}); + }); + actions.push({"type": "waitAsync"}); + // 强制战斗 + ambush.forEach(function (t) { + actions.push({"type": "battle", "id": t[2]}); + }); + core.insertAction(actions); +} + ////// 更改天气效果 ////// control.prototype.setWeather = function (type, level) { @@ -1206,13 +1155,13 @@ control.prototype.updateDamage = function (floorId, canvas) { var width = core.floors[floorId].width, height = core.floors[floorId].height; for (var x=0;x0) { // 该点伤害 damage = core.formatBigNumber(damage, true); core.fillBoldText(canvas, damage, 32*x+16, 32*(y+1)-14, '#FF7F00'); } else { // 检查捕捉 - if ((core.status.checkBlock.ambush||[])[x+width*y]) { + if (core.status.checkBlock.ambush[x+","+y]) { core.fillBoldText(canvas, '!', 32*x+16, 32*(y+1)-14, '#FF7F00'); } } diff --git a/libs/events.js b/libs/events.js index be7371c0..6dba790c 100644 --- a/libs/events.js +++ b/libs/events.js @@ -250,14 +250,9 @@ events.prototype.doSystemEvent = function (type, data, callback) { } ////// 触发(x,y)点的事件 ////// -events.prototype.trigger = function (x, y) { - // 如果已经死亡,忽略 - if (core.status.gameOver) return; - // 如果正在自定义事件中,则插入 - if (core.status.event.id == 'action') { - core.insertAction({"type": "trigger", "loc": [x, y]}); - return; - } +events.prototype._trigger = function (x, y) { + // 如果已经死亡,或正处于某事件中,则忽略 + if (core.status.gameOver || core.status.event.id) return; core.status.isSkiing = false; var block = core.getBlock(x, y); @@ -690,7 +685,7 @@ events.prototype._sys_action = function (data, callback) { var ev = core.clone(data.event.data), ex = data.x, ey = data.y; // 检查是否需要改变朝向 if (ex == core.nextX() && ey == core.nextY()) { - var dir = {"up": "down", "down": "up", "left": "right", "right": "left"}[core.getHeroLoc('direction')]; + var dir = core.reverseDirection(); var id = data.event.id, toId = (data.event.faceIds || {})[dir]; if (toId && id != toId) { var number = core.icons.getNumberById(toId); @@ -1817,10 +1812,10 @@ events.prototype._eventMoveHero_moving = function (step, moveSteps) { if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); core.setHeroLoc('direction', direction); if (step <= 4) { - core.drawHero(direction, x, y, 'leftFoot', 4 * o * step); + core.drawHero('leftFoot', 4 * o * step); } else if (step <= 8) { - core.drawHero(direction, x, y, 'rightFoot', 4 * o * step); + core.drawHero('rightFoot', 4 * o * step); } if (step == 8) { core.setHeroLoc('x', x + o * core.utils.scan[direction].x, true); diff --git a/libs/maps.js b/libs/maps.js index 16e2eff4..85b4d216 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -416,7 +416,7 @@ maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, ext // 3. 检查是否能进将死的领域 if (floorId == core.status.floorId - && core.status.hero.hp <= core.status.checkBlock.damage[nx + core.bigmap.width * ny] + && core.status.hero.hp <= (core.status.checkBlock.damage[nx + "," + ny]||0) && !core.flags.canGoDeadZone && extraData.eventArray[ny][nx] == 0) return false; @@ -460,7 +460,7 @@ maps.prototype._canMoveDirectly_checkGlobal = function () { } maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) { - if (core.status.checkBlock.damage[sx + core.bigmap.width * sy] > 0) return false; + if (core.status.checkBlock.damage[sx + "," + sy]) return false; var block = core.getBlock(sx, sy); if (block != null) { // 只有起点是传送点才是能无视 @@ -498,9 +498,9 @@ maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) { // 该点是否有事件 if (blocksObj[index]) return false; // 是否存在阻激夹域伤害 - if (core.status.checkBlock.damage[x + core.bigmap.width * y] > 0) return false; + if (core.status.checkBlock.damage[x + "," + y]) return false; // 是否存在捕捉 - if (core.status.checkBlock.ambush[x + core.bigmap.width * y]) return false; + if (core.status.checkBlock.ambush[x + "," + y]) return false; return true; } @@ -568,9 +568,9 @@ maps.prototype._automaticRoute_deepAdd = function (x, y) { // if (nextBlock.block.event.trigger == 'changeFloor') deepAdd+=10; } // 绕过存在伤害的地方 - deepAdd += core.status.checkBlock.damage[x+","+y] * 100; + deepAdd += (core.status.checkBlock.damage[x+","+y]||0) * 100; // 绕过捕捉 - if ((core.status.checkBlock.ambush||[])[x+","+y]) deepAdd += 1000; + if (core.status.checkBlock.ambush[x+","+y]) deepAdd += 1000; return deepAdd; } diff --git a/libs/utils.js b/libs/utils.js index 013e669d..3f74feaa 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -625,6 +625,11 @@ utils.prototype.strlen = function (str) { return count; }; +utils.prototype.reverseDirection = function (direction) { + direction = direction || core.getHeroLoc('direction'); + return {"left":"right","right":"left","down":"up","up":"down"}[direction] || direction; +} + ////// Base64加密 ////// utils.prototype.encodeBase64 = function (str) { return btoa(encodeURIComponent(str).replace(/%([0-9A-F]{2})/g, function (match, p1) { diff --git a/project/functions.js b/project/functions.js index d95259e8..ea77402d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -181,7 +181,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // ------ 支援技能 ------ // if (x != null && y != null) { var index = x + "," + y, - cache = (core.status.checkBlock.cache || {})[index] || {}, + cache = core.status.checkBlock.cache[index] || {}, guards = cache.guards || []; // 如果存在支援怪 if (guards.length > 0) { @@ -507,7 +507,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // ------ 支援 ------ var guards = []; // 检查光环缓存 - if (!core.status.checkBlock.cache) core.status.checkBlock.cache = {}; var index = x != null && y != null ? (x + "," + y) : "floor"; var cache = core.status.checkBlock.cache[index]; if (!cache) { @@ -1014,147 +1013,154 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = floorId = floorId || core.status.floorId; if (!floorId || !core.status.maps) return; - var blocks = core.status.maps[floorId].blocks; - var width = core.floors[floorId].width, height = core.floors[floorId].height; + var width = core.floors[floorId].width, + height = core.floors[floorId].height; + var blocks = core.getMapBlocksObj(floorId); - core.status.checkBlock = {}; + var damage = {}, // 每个点的伤害值 + type = {}, // 每个点的伤害类型 + snipe = {}, // 每个点的阻击怪信息 + ambush = {}; // 每个点的捕捉信息 + + // 计算血网和领域、阻击、激光的伤害,计算捕捉信息 + for (var loc in blocks) { + var block = blocks[loc], + x = block.x, + y = block.y, + id = block.event.id, + enemy = core.material.enemys[id]; - // Step1: 更新怪物地图 - core.status.checkBlock.map = []; // 记录怪物地图 - for (var n = 0; n < blocks.length; n++) { - var block = blocks[n]; - if (!block.disable && block.event.cls.indexOf('enemy') == 0) { - var id = block.event.id, - enemy = core.material.enemys[id]; - if (enemy) core.status.checkBlock.map[block.x + width * block.y] = id; - } // 血网 - if (!block.disable && - block.event.id == 'lavaNet' && block.event.trigger == 'passNet' && !core.hasItem("shoes")) { - core.status.checkBlock.map[block.x + width * block.y] = "lavaNet"; + if (id == 'lavaNet' && block.event.trigger == 'passNet' && !core.hasItem('shoes')) { + damage[loc] = (damage[loc] || 0) + core.values.lavaDamage; + type[loc] = "血网伤害"; } - } - // Step2: 更新领域、阻击伤害 - core.status.checkBlock.damage = []; // 记录(x,y)点的伤害;(x,y)对应的值是 x+width*y - for (var x = 0; x < width * height; x++) core.status.checkBlock.damage[x] = 0; - core.status.checkBlock.ambush = []; + // 领域 + // 如果要防止领域伤害,可以直接简单的将 flag:no_zone 设为true + if (enemy && core.hasSpecial(enemy.special, 15) && !core.hasFlag('no_zone')) { + // 领域范围,默认为1 + var range = enemy.range || 1; + // 是否是九宫格领域 + var zoneSquare = false; + if (enemy.zoneSquare != null) zoneSquare = enemy.zoneSquare; + // 在范围内进行搜索,增加领域伤害值 + for (var dx = -range; dx <= range; dx++) { + for (var dy = -range; dy <= range; dy++) { + if (dx == 0 && dy == 0) continue; + var nx = x + dx, + ny = y + dy, + currloc = nx + "," + ny; + if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; + // 如果是十字领域,则还需要满足 |dx|+|dy|<=range + if (!zoneSquare && Math.abs(dx) + Math.abs(dy) > range) continue; + damage[currloc] = (damage[currloc] || 0) + (enemy.value || 0); + type[currloc] = "领域伤害"; + } + } + } - for (var x = 0; x < width; x++) { - for (var y = 0; y < height; y++) { - var id = core.status.checkBlock.map[x + width * y]; - if (id) { + // 阻击 + // 如果要防止阻击伤害,可以直接简单的将 flag:no_snipe 设为true + if (enemy && core.hasSpecial(enemy.special, 18) && !core.hasFlag('no_snipe')) { + 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; + damage[currloc] = (damage[currloc] || 0) + (enemy.value || 0); + type[currloc] = "阻击伤害"; - // 如果是血网,直接加上伤害值 - if (id == "lavaNet") { - core.status.checkBlock.damage[x + width * y] += core.values.lavaDamage || 0; - continue; + var rdir = core.reverseDirection(dir); + // 检查下一个点是否存在事件(从而判定是否移动) + var rnx = x + core.utils.scan[rdir].x, + rny = y + core.utils.scan[rdir].y; + if (rnx >= 0 && rnx < width && rny >= 0 && rny < height && core.getBlock(rnx, rny, floorId) == null) { + snipe[currloc] = (snipe[currloc] || []).concat([ + [x, y, id, rdir] + ]); } + } + } - var enemy = core.material.enemys[id]; - // 存在领域 - // 如果要防止领域伤害,可以直接简单的将 flag:no_zone 设为true - if (core.enemys.hasSpecial(enemy.special, 15) && !core.hasFlag("no_zone")) { - // 领域范围,默认为1 - var range = enemy.range || 1; - // 是否是九宫格领域 - var zoneSquare = false; - if (enemy.zoneSquare != null) zoneSquare = enemy.zoneSquare; - // 在范围内进行搜索,增加领域伤害值 - for (var dx = -range; dx <= range; dx++) { - for (var dy = -range; dy <= range; dy++) { - if (dx == 0 && dy == 0) continue; - var nx = x + dx, - ny = y + dy; - if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; - // 如果是十字领域,则还需要满足 |dx|+|dy|<=range - if (!zoneSquare && Math.abs(dx) + Math.abs(dy) > range) continue; - core.status.checkBlock.damage[nx + ny * width] += enemy.value || 0; - } - } + // 激光 + // 如果要防止激光伤害,可以直接简单的将 flag:no_laser 设为true + if (enemy && core.hasSpecial(enemy.special, 24) && !core.hasFlag("no_laser")) { + for (var nx = 0; nx < width; nx++) { + var currloc = nx + "," + y; + if (nx != x) { + damage[currloc] = (damage[currloc] || 0) + (enemy.value || 0); + type[currloc] = "激光伤害"; } - // 存在激光 - // 如果要防止激光伤害,可以直接简单的将 flag:no_laser 设为true - if (core.enemys.hasSpecial(enemy.special, 24) && !core.hasFlag("no_laser")) { - // 检查同行和同列,增加激光伤害值 - for (var nx = 0; nx < width; nx++) { - if (nx != x) core.status.checkBlock.damage[nx + y * width] += enemy.value || 0; - } - for (var ny = 0; ny < height; ny++) { - if (ny != y) core.status.checkBlock.damage[x + ny * width] += enemy.value || 0; - } - } - // 存在阻击 - // 如果要防止阻击伤害,可以直接简单的将 flag:no_snipe 设为true - if (core.enemys.hasSpecial(enemy.special, 18) && !core.hasFlag("no_snipe")) { - for (var dx = -1; dx <= 1; dx++) { - for (var dy = -1; dy <= 1; dy++) { - if (dx == 0 && dy == 0) continue; - var nx = x + dx, - ny = y + dy; - if (nx < 0 || nx >= width || ny < 0 || ny >= height || Math.abs(dx) + Math.abs(dy) > 1) continue; - core.status.checkBlock.damage[nx + ny * width] += enemy.value || 0; - } - } - } - // 存在捕捉 - if (core.enemys.hasSpecial(enemy.special, 27)) { - // 给周围格子加上【捕捉】记号 - for (var dir in core.utils.scan) { - var nx = x + core.utils.scan[dir].x, - ny = y + core.utils.scan[dir].y; - if (nx < 0 || nx >= width || ny < 0 || ny >= height) continue; - if (!core.status.checkBlock.ambush[nx + ny * width]) - core.status.checkBlock.ambush[nx + ny * width] = []; - core.status.checkBlock.ambush[nx + ny * width].push([x, y, id, dir]); - } + } + for (var ny = 0; ny < height; ny++) { + var currloc = x + "," + ny; + if (ny != y) { + damage[currloc] = (damage[currloc] || 0) + (enemy.value || 0); + type[currloc] = "激光伤害"; } } } + + // 捕捉 + // 如果要防止捕捉效果,可以直接简单的将 flag:no_ambush 设为true + if (enemy && core.enemys.hasSpecial(enemy.special, 27)) { + // 给周围格子加上【捕捉】记号 + 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; + ambush[currloc] = (ambush[currloc] || []).concat([ + [x, y, id, dir] + ]); + } + } } - // Step3: 更新夹击点坐标,并将夹击伤害加入到damage中 - core.status.checkBlock.betweenAttack = []; // 记录(x,y)点是否有夹击 + // 更新夹击伤害 // 如果要防止夹击伤害,可以简单的将 flag:no_betweenAttack 设为true if (!core.hasFlag('no_betweenAttack')) { for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { - // 该点是否存在夹击 - var has = false; - // 检测左右是否存在相同的怪物,且拥有夹击属性 - if (x > 0 && x < width - 1) { - var id1 = core.status.checkBlock.map[x - 1 +width * y], - id2 = core.status.checkBlock.map[x + 1 + width * y]; - if (id1 != null && id2 != null && id1 == id2) { - var enemy = core.material.enemys[id1]; - if (enemy && core.enemys.hasSpecial(enemy.special, 16)) { - has = true; - } - } + var loc = x + "," + y; + // 夹击怪物的ID + var enemyId = 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)) + enemyId = leftBlock.event.id; } - // 检测上下是否存在相同的怪物,且拥有夹击属性 - if (y > 0 && y < height - 1) { - var id1 = core.status.checkBlock.map[x + width * (y - 1)], - id2 = core.status.checkBlock.map[x + width * (y + 1)]; - if (id1 != null && id2 != null && id1 == id2) { - var enemy = core.material.enemys[id1]; - if (enemy && core.enemys.hasSpecial(enemy.special, 16)) { - has = true; - } - } + // 检查上下夹击 + var topBlock = block[x + "," + (y - 1)], + bottomBlock = blocks[x + "," + (y + 1)]; + if (topBlock && bottomBlock && topBlock.id == bottomBlock.id) { + if (core.hasSpecial(topBlock.event.id, 16)) + enemyId = topBlock.event.id; } - // 计算夹击伤害 - if (has) { - core.status.checkBlock.betweenAttack[x + width * y] = true; - // 先扣除该点领域/阻击/激光造成的伤害,再算夹击 - var leftHp = core.status.hero.hp - core.status.checkBlock.damage[x + width * y]; - // 1血不夹;core.flags.betweenAttackCeil控制向上还是向下 - if (leftHp > 1) - core.status.checkBlock.damage[x + width * y] += Math.floor((leftHp + (core.flags.betweenAttackCeil ? 0 : 1)) / 2); + + if (enemyId != null) { + var leftHp = core.status.hero.hp - (damage[x + "," + y] || 0); + if (leftHp > 1) { + // 上整/下整 + var value = Math.floor((leftHp + (core.flags.betweenAttackCeil ? 0 : 1)) / 2); + damage[loc] = (damage[loc] || 0) + value; + type[loc] = "夹击伤害"; + } } } } } + + core.status.checkBlock = { + damage: damage, + type: type, + snipe: snipe, + ambush: ambush, + cache: {} + }; }, "moveOneStep": function (x, y) { // 勇士每走一步后执行的操作,x,y为要移动到的坐标。 From a0538670a573d69551dde2bd665ba5a39407f263 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 18 Mar 2019 18:58:00 +0800 Subject: [PATCH 033/153] getBuff --- libs/control.js | 415 +++++++++++++++++++++++-------------------- libs/enemys.js | 2 +- libs/items.js | 8 +- libs/ui.js | 2 +- project/events.js | 10 +- project/functions.js | 4 - project/items.js | 4 +- 7 files changed, 233 insertions(+), 212 deletions(-) diff --git a/libs/control.js b/libs/control.js index 699bc34d..b88921fd 100644 --- a/libs/control.js +++ b/libs/control.js @@ -803,7 +803,7 @@ control.prototype._drawHero_getDrawObjs = function (direction, x, y, status, off }); } -// ------ 画布、位置、阻激夹域等 ------ // +// ------ 画布、位置、阻激夹域,显伤 ------ // ////// 设置画布偏移 control.prototype.setGameCanvasTranslate = function(canvas,x,y){ @@ -845,20 +845,6 @@ control.prototype.updateViewport = function() { core.relocateCanvas('route', core.status.automaticRoute.offsetX - core.bigmap.offsetX, core.status.automaticRoute.offsetY - core.bigmap.offsetY); } -////// 设置勇士的位置 ////// -control.prototype.setHeroLoc = function (itemName, itemVal, noGather) { - core.status.hero.loc[itemName] = itemVal; - if ((itemName=='x' || itemName=='y') && !noGather) { - this.gatherFollowers(); - } -} - -////// 获得勇士的位置 ////// -control.prototype.getHeroLoc = function (itemName) { - if (itemName == null) return core.status.hero.loc; - return core.status.hero.loc[itemName]; -} - ////// 获得勇士面对位置的x坐标 ////// control.prototype.nextX = function(n) { return core.getHeroLoc('x')+core.utils.scan[core.getHeroLoc('direction')].x*(n||1); @@ -964,137 +950,6 @@ control.prototype._checkBlock_ambush = function (ambush) { core.insertAction(actions); } -////// 更改天气效果 ////// -control.prototype.setWeather = function (type, level) { - - // 非雨雪 - if (type!='rain' && type!='snow' && type!='fog') { - // core.clearMap('weather'); - core.deleteCanvas('weather') - core.animateFrame.weather.type = null; - core.animateFrame.weather.level = 0; - core.animateFrame.weather.nodes = []; - return; - } - - level = parseInt(level); - - // 当前天气:则忽略 - if (type==core.animateFrame.weather.type && !core.isset(level)) { - return; - } - - if (!core.isset(level)) level=5; - if (level<1) level=1; if (level>10) level=10; - level *= parseInt(20*core.bigmap.width*core.bigmap.height/(core.__SIZE__*core.__SIZE__)); - // 计算当前的宽高 - - core.createCanvas('weather', 0, 0, core.__PIXELS__, core.__PIXELS__, 80); - core.animateFrame.weather.type = type; - core.animateFrame.weather.level = level; - core.animateFrame.weather.nodes = []; - - if (type == 'rain') { - for (var a=0;a 1) - core.screenFlash(color, time * 3, times - 1, callback); - else { - if (core.isset(callback)) callback(); - } - }); - }); -} - ////// 更新全地图显伤 ////// control.prototype.updateDamage = function (floorId, canvas) { floorId = floorId || core.status.floorId; @@ -1191,12 +1046,6 @@ control.prototype.doEffect = function (effect, need, times) { }); } -////// 开启debug模式 ////// -control.prototype.debug = function() { - core.setFlag('debug', true); - core.drawText("\t[调试模式开启]此模式下按住Ctrl键(或Ctrl+Shift键)可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"); -} - ////// 选择录像文件 ////// control.prototype.chooseReplayFile = function () { core.readFile(function (obj) { @@ -2197,77 +2046,116 @@ control.prototype.hasSave = function (index) { return core.saves.ids[index]||false; } +// ------ 属性,状态,位置,buff,变量,锁定控制等 ------ // + ////// 设置勇士属性 ////// -control.prototype.setStatus = function (statusName, statusVal) { - if (!core.isset(core.status.hero)) return; - if (statusName == 'exp') statusName = 'experience'; - if (core.isset(core.status.hero.loc[statusName])) - core.status.hero.loc[statusName] = statusVal; +control.prototype.setStatus = function (name, value) { + if (!core.status.hero) return; + if (name == 'exp') name = 'experience'; + if (name == 'x' || name == 'y' || name == 'direction') + this.setHeroLoc(name, value); else - core.status.hero[statusName] = statusVal; + core.status.hero[name] = value; +} + +////// 增减勇士属性 ////// +control.prototype.addStatus = function (name, value) { + this.setStatus(name, this.getStatus(name) + value); } ////// 获得勇士属性 ////// control.prototype.getStatus = function (name) { - if (!core.isset(core.status.hero)) return null; - // support status:x - if (core.isset(core.status.hero.loc[name])) - return core.status.hero.loc[name]; + if (!core.status.hero) return null; + if (name == 'x' || name == 'y' || name == 'direction') + return this.getHeroLoc('x'); if (name == 'exp') name = 'experience'; return core.status.hero[name]; } +////// 从status中获得属性,如果不存在则从勇士属性中获取 ////// control.prototype.getStatusOrDefault = function (status, name) { - if (core.isset(status) && name in status) + if (status && name in status) return status[name]; return this.getStatus(name); } +////// 获得勇士实际属性(增幅后的) ////// control.prototype.getRealStatus = function (name) { return this.getRealStatusOrDefault(null, name); } +////// 从status中获得实际属性(增幅后的),如果不存在则从勇士属性中获取 ////// control.prototype.getRealStatusOrDefault = function (status, name) { - return this.getStatusOrDefault(status, name) * core.getFlag('__'+name+'_buff__', 1); + return this.getStatusOrDefault(status, name) * this.getBuff(name); +} + +////// 设置某个属性的增幅值 ////// +control.prototype.setBuff = function (name, value) { + this.setFlag('flag:__'+name+'_buff__', value); +} + +////// 加减某个属性的增幅值 ////// +control.prototype.addBuff = function (name, value) { + this.setFlag('flag:__'+name+'_buff__', this.getBuff(name) + value); +} + +////// 获得某个属性的增幅值 ////// +control.prototype.getBuff = function (name) { + return core.getFlag('__'+name+'_buff__', 1); +} + +////// 设置勇士的位置 ////// +control.prototype.setHeroLoc = function (name, value, noGather) { + if (!core.status.hero) return; + core.status.hero.loc[name] = value; + if ((name=='x' || name=='y') && !noGather) { + this.gatherFollowers(); + } +} + +////// 获得勇士的位置 ////// +control.prototype.getHeroLoc = function (name) { + if (!core.status.hero) return; + if (name == null) return core.status.hero.loc; + return core.status.hero.loc[name]; } ////// 获得某个等级的名称 ////// -control.prototype.getLvName = function () { - if (!core.isset(core.status.hero)) return null; - return ((core.firstData.levelUp||[])[core.status.hero.lv-1]||{}).title || core.status.hero.lv; +control.prototype.getLvName = function (lv) { + if (!core.status.hero) return null; + if (lv == null) lv = core.status.hero.lv; + return ((core.firstData.levelUp||[])[lv-1]||{}).title || lv; } ////// 设置某个自定义变量或flag ////// -control.prototype.setFlag = function(flag, value) { - if (!core.isset(value)) return this.removeFlag(flag); - if (!core.isset(core.status.hero)) return; - core.status.hero.flags[flag]=value; -} - -////// 获得某个自定义变量或flag ////// -control.prototype.getFlag = function(flag, defaultValue) { - if (!core.isset(core.status.hero)) return defaultValue; - var value = core.status.hero.flags[flag]; - if (core.isset(value)) return value; - return defaultValue; -} - -////// 是否存在某个自定义变量或flag,且值为true ////// -control.prototype.hasFlag = function(flag) { - if (core.getFlag(flag)) return true; - return false; -} - -////// 删除某个自定义变量或flag ////// -control.prototype.removeFlag = function(flag) { - if (!core.isset(core.status.hero)) return; - delete core.status.hero.flags[flag]; +control.prototype.setFlag = function(name, value) { + if (value == null) return this.removeFlag(name); + if (!core.status.hero) return; + core.status.hero.flags[name]=value; } ////// 增加某个flag数值 ////// -control.prototype.addFlag = function(flag, delta) { - if (!core.isset(core.status.hero)) return; - core.setFlag(flag, core.getFlag(flag, 0) + delta); +control.prototype.addFlag = function(name, value) { + if (!core.status.hero) return; + core.setFlag(name, core.getFlag(name, 0) + value); +} + +////// 获得某个自定义变量或flag ////// +control.prototype.getFlag = function(name, defaultValue) { + if (!core.status.hero) return defaultValue; + var value = core.status.hero.flags[name]; + return value != null ? value : defaultValue; +} + +////// 是否存在某个自定义变量或flag,且值为true ////// +control.prototype.hasFlag = function(name) { + return !!core.getFlag(name); +} + +////// 删除某个自定义变量或flag ////// +control.prototype.removeFlag = function(name) { + if (!core.status.hero) return; + delete core.status.hero.flags[name]; } ////// 锁定状态栏,常常用于事件处理 ////// @@ -2280,6 +2168,145 @@ control.prototype.unLockControl = function () { core.status.lockControl = false; } +////// 开启debug模式 ////// +control.prototype.debug = function() { + core.setFlag('debug', true); + core.drawText("\t[调试模式开启]此模式下按住Ctrl键(或Ctrl+Shift键)可以穿墙并忽略一切事件。\n同时,录像将失效,也无法上传成绩。"); +} + +// ------ 天气,色调,BGM ------ // + +////// 更改天气效果 ////// +control.prototype.setWeather = function (type, level) { + + // 非雨雪 + if (type!='rain' && type!='snow' && type!='fog') { + // core.clearMap('weather'); + core.deleteCanvas('weather') + core.animateFrame.weather.type = null; + core.animateFrame.weather.level = 0; + core.animateFrame.weather.nodes = []; + return; + } + + level = parseInt(level); + + // 当前天气:则忽略 + if (type==core.animateFrame.weather.type && !core.isset(level)) { + return; + } + + if (!core.isset(level)) level=5; + if (level<1) level=1; if (level>10) level=10; + level *= parseInt(20*core.bigmap.width*core.bigmap.height/(core.__SIZE__*core.__SIZE__)); + // 计算当前的宽高 + + core.createCanvas('weather', 0, 0, core.__PIXELS__, core.__PIXELS__, 80); + core.animateFrame.weather.type = type; + core.animateFrame.weather.level = level; + core.animateFrame.weather.nodes = []; + + if (type == 'rain') { + for (var a=0;a 1) + core.screenFlash(color, time * 3, times - 1, callback); + else { + if (core.isset(callback)) callback(); + } + }); + }); +} + ////// 播放背景音乐 ////// control.prototype.playBgm = function (bgm, startTime) { if (main.mode!='play')return; diff --git a/libs/enemys.js b/libs/enemys.js index 02554f28..75f64ede 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -245,7 +245,7 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f for (var t = turn - 1; t >= 1; t--) { var nextAtk = Math.ceil(mon_hp / t) + mon_def; // 装备提升比例的计算临界 - nextAtk = Math.ceil(nextAtk / core.getFlag('__atk_buff__', 1)); + nextAtk = Math.ceil(nextAtk / core.getBuff('atk')); if (nextAtk <= hero_atk) break; if (nextAtk != pre) { var nextInfo = this.getDamageInfo(enemy, {"atk": nextAtk}, x, y, floorId); diff --git a/libs/items.js b/libs/items.js index e61c23f9..58faca5c 100644 --- a/libs/items.js +++ b/libs/items.js @@ -333,12 +333,12 @@ items.prototype._loadEquipEffect = function (equipId, unloadEquipId, isPercentag var result = core.compareEquipment(equipId, unloadEquipId); if (isPercentage) { - for (var v in result) - core.addFlag('__' + v + '_buff__', result[v] / 100); + for (var name in result) + core.addBuff(name, result[name] / 100); } else { - for (var v in result) - core.status.hero[v] += result[v]; + for (var name in result) + core.status.hero[name] += result[name]; } } diff --git a/libs/ui.js b/libs/ui.js index f7c437f8..76ad2603 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2059,7 +2059,7 @@ ui.prototype.drawEquipbox = function(index) { if (compare[name]<0) color = '#FF0000'; var nowValue = core.getStatus(name), newValue = nowValue + compare[name]; if (equip.equip.percentage) { - var nowBuff = core.getFlag('__'+name+"_buff__", 1), newBuff = nowBuff+compare[name]/100; + var nowBuff = core.getBuff(name), newBuff = nowBuff+compare[name]/100; nowValue = Math.floor(nowBuff*core.getStatus(name)); newValue = Math.floor(newBuff*core.getStatus(name)); } diff --git a/project/events.js b/project/events.js index 92458391..f9b4d108 100644 --- a/project/events.js +++ b/project/events.js @@ -118,14 +118,12 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = "text": "<1:扣比例" }, { - "type": "setValue2", - "name": "flag:__atk_buff__", - "value": "-core.values.weakValue" + "type": "function", + "function": "function(){\ncore.addBuff('atk', -core.values.weakValue);\n}" }, { - "type": "setValue2", - "name": "flag:__def_buff__", - "value": "-core.values.weakValue" + "type": "function", + "function": "function(){\ncore.addBuff('def', -core.values.weakValue);\n}" } ] } diff --git a/project/functions.js b/project/functions.js index ea77402d..4ff799de 100644 --- a/project/functions.js +++ b/project/functions.js @@ -60,10 +60,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.setFlag('hard', 4); // 可以用flag:hard来获得当前难度 } - // 设置三围的初始增幅属性(均为1) - ["atk", "def", "mdef"].forEach(function (name) { - core.setFlag("__" + name + "_buff__", 1); - }); // 设置已经到过的楼层 core.setFlag("__visited__", {}); diff --git a/project/items.js b/project/items.js index 1c464161..83b236c7 100644 --- a/project/items.js +++ b/project/items.js @@ -372,9 +372,9 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "upFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.ui.x, 'y': core.status.event.ui.y};\nif (core.status.event.id == 'action') {\n\tcore.insertAction([\n\t\t{\"type\": \"changeFloor\", \"loc\": [loc.x, loc.y], \"direction\": loc.direction, \"floorId\": core.status.event.ui.id},\n\t\t{\"type\": \"tip\", \"text\": core.material.items[itemId].name + '使用成功'}\n\t]);\n}\nelse {\n\tcore.changeFloor(core.status.event.ui.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t\tcore.replay();\n\t});\n}", "downFly": "var loc = {'direction': core.status.hero.loc.direction, 'x': core.status.event.ui.x, 'y': core.status.event.ui.y};\nif (core.status.event.id == 'action') {\n\tcore.insertAction([\n\t\t{\"type\": \"changeFloor\", \"loc\": [loc.x, loc.y], \"direction\": loc.direction, \"floorId\": core.status.event.ui.id},\n\t\t{\"type\": \"tip\", \"text\": core.material.items[itemId].name + '使用成功'}\n\t]);\n}\nelse {\n\tcore.changeFloor(core.status.event.ui.id, null, loc, null, function (){\n\tcore.drawTip(core.material.items[itemId].name + '使用成功');\n\t\tcore.replay();\n\t});\n}\n", "poisonWine": "core.removeFlag('poison');", - "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.addFlag(\"__atk_buff__\", core.values.weakValue);\n\tcore.addFlag(\"__def_buff__\", core.values.weakValue);\n}", + "weakWine": "core.removeFlag('weak');\nif (core.values.weakValue>=1) { // >=1:直接扣数值\n\tcore.status.hero.atk += core.values.weakValue;\n\tcore.status.hero.def += core.values.weakValue;\n}\nelse { // <1:扣比例\n\tcore.addBuff(\"atk\", core.values.weakValue);\n\tcore.addBuff(\"def\", core.values.weakValue);\n}", "curseWine": "core.removeFlag('curse');", - "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.addFlag(\"__atk_buff__\", core.values.weakValue);\n\t\tcore.addFlag(\"__def_buff__\", core.values.weakValue);\n\t}\n}\ncore.removeFlag('curse');", + "superWine": "core.removeFlag('poison');\nif (core.hasFlag('weak')) {\n\tcore.removeFlag('weak');\n\tif (core.values.weakValue>=1) { // >=1:直接扣数值\n\t\tcore.status.hero.atk += core.values.weakValue;\n\t\tcore.status.hero.def += core.values.weakValue;\n\t}\n\telse { // <1:扣比例\n\t\tcore.addBuff(\"atk\", core.values.weakValue);\n\t\tcore.addBuff(\"def\", core.values.weakValue);\n\t}\n}\ncore.removeFlag('curse');", "lifeWand": "core.insertAction([\n\t{\"type\": \"input\", \"text\": \"请输入生命魔杖使用次数:(0-${item:lifeWand})\"},\n\t{\"type\": \"if\", \"condition\": \"flag:input<=item:lifeWand\",\n\t\t\"true\": [\n\t\t\t{\"type\": \"setValue\", \"name\": \"item:lifeWand\", \"value\": \"item:lifeWand-flag:input\"},\n\t\t\t{\"type\": \"setValue\", \"name\": \"status:hp\", \"value\": \"status:hp+flag:input*100\"},\n\t\t\t\"成功使用${flag:input}次生命魔杖,恢复${flag:input*100}点生命。\"\n\t\t],\n\t\t\"false\": [\"输入不合法!\"]\n\t},\n]);\ncore.addItem('lifeWand', 1);", "jumpShoes": "core.insertAction({\"type\":\"jumpHero\",\"loc\":[core.nextX(2),core.nextY(2)]});", "redPotion": "core.status.hero.hp += core.values.redPotion", From 911c2c515909eb3d9afa891487ea7462a1bfc5b9 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 18 Mar 2019 19:21:23 +0800 Subject: [PATCH 034/153] updateDamage, addValue --- _docs/event.md | 8 +-- _server/blockly/MotaAction.g4 | 17 +++--- _server/editor_blockly.js | 12 ++--- libs/control.js | 99 ++++++++++++----------------------- libs/events.js | 18 ++++++- project/events.js | 4 +- 6 files changed, 70 insertions(+), 88 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 700a835f..bb18169f 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -441,7 +441,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam 另外注意一点的是,如果hp被设置成了0或以下,将触发lose事件,直接死亡。 -### setValue2:增减勇士的某个属性、道具个数,或某个变量/Flag的值 +### addValue:增减勇士的某个属性、道具个数,或某个变量/Flag的值 和`{"type": "setValue"}`的写法完全相同,不过此项是可以直接将值加减到原始数值上。 @@ -450,11 +450,11 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ``` js "x,y": [ // 实际执行的事件列表 {"type": "setValue", "name": "status:atk", "value": "status:atk+10" } // 攻击提高10点 - {"type": "setValue2", "name": "status:atk", "value": "10" } // 和上面写法等价 + {"type": "addVakue", "name": "status:atk", "value": "10" } // 和上面写法等价 {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey-3" } // 黄钥匙个数-3 - {"type": "setValue2", "name": "item:yellowKey", "value": "-3" } // 和上面写法等价 + {"type": "addValue", "name": "item:yellowKey", "value": "-3" } // 和上面写法等价 {"type": "setValue", "name": "flag:door2", "value": "flag:door2+1" } // 将变量door值+1 - {"type": "setValue2", "name": "flag:door2", "value": "01" } // 和上面写法等价 + {"type": "addValue", "name": "flag:door2", "value": "01" } // 和上面写法等价 ] ``` diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index bd5e3f4a..1b2005b3 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -228,7 +228,7 @@ action | setText_s | tip_s | setValue_s - | setValue2_s + | addValue_s | setFloor_s | setGlobalAttribute_s | setGlobalValue_s @@ -465,15 +465,15 @@ var code = '{"type": "setValue", "name": "'+idString_e_0+'", "value": "'+express return code; */; -setValue2_s +addValue_s : '数值增减' ':' '名称' idString_e '+=' expression Newline -/* setValue2_s -tooltip : setValue2:增减勇士的某个属性、道具个数, 或某个变量/Flag的值 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=setValue2%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc +/* addValue_s +tooltip : addValue:增减勇士的某个属性、道具个数, 或某个变量/Flag的值 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=addValue%ef%bc%9a%e5%a2%9e%e5%87%8f%e5%8b%87%e5%a3%ab%e7%9a%84%e6%9f%90%e4%b8%aa%e5%b1%9e%e6%80%a7%e3%80%81%e9%81%93%e5%85%b7%e4%b8%aa%e6%95%b0%ef%bc%8c%e6%88%96%e6%9f%90%e4%b8%aa%e5%8f%98%e9%87%8f%2fFlag%e7%9a%84%e5%80%bc colour : this.dataColor -var code = '{"type": "setValue2", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n'; +var code = '{"type": "addValue", "name": "'+idString_e_0+'", "value": "'+expression_0+'"},\n'; return code; */; @@ -2372,14 +2372,13 @@ ActionParser.prototype.parseAction = function() { break case "setValue": this.next = MotaActionBlocks['setValue_s'].xmlText([ - // MotaActionBlocks['idString_e'].xmlText([data.name]), this.tryToUseEvFlag_e('idString_e', [data.name]), MotaActionBlocks['evalString_e'].xmlText([data.value]), this.next]); break; case "setValue2": - this.next = MotaActionBlocks['setValue2_s'].xmlText([ - // MotaActionBlocks['idString_e'].xmlText([data.name]), + case "addValue": + this.next = MotaActionBlocks['addValue_s'].xmlText([ this.tryToUseEvFlag_e('idString_e', [data.name]), MotaActionBlocks['evalString_e'].xmlText([data.value]), this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index e1db7827..5cc6747a 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -75,7 +75,7 @@ editor_blockly = function () { MotaActionBlocks['setValue_s'].xmlText([ MotaActionBlocks['idString_1_e'].xmlText(['status','hp']) ]), - MotaActionBlocks['setValue2_s'].xmlText([ + MotaActionBlocks['addValue_s'].xmlText([ MotaActionBlocks['idString_1_e'].xmlText(['status','hp']) ]), MotaActionBlocks['setFloor_s'].xmlText(), @@ -157,7 +157,7 @@ editor_blockly = function () { MotaActionBlocks['setValue_s'].xmlText([ MotaActionBlocks['idString_1_e'].xmlText(['status','hp']) ]), - MotaActionBlocks['setValue2_s'].xmlText([ + MotaActionBlocks['addValue_s'].xmlText([ MotaActionBlocks['idString_1_e'].xmlText(['status','hp']) ]), MotaActionBlocks['expression_arithmetic_0'].xmlText(), @@ -184,8 +184,8 @@ editor_blockly = function () { {"text": "黄钥匙(\${9+flag:shop_times}金币)", "color": [255,255,0,1], "action": [ {"type": "if", "condition": "status:money>=9+flag:shop_times", "true": [ - {"type": "setValue2", "name": "status:money", "value": "-(9+flag:shop_times)"}, - {"type": "setValue2", "name": "item:yellowKey", "value": "1"}, + {"type": "addValue", "name": "status:money", "value": "-(9+flag:shop_times)"}, + {"type": "addValue", "name": "item:yellowKey", "value": "1"}, ], "false": [ "\t[老人,man]你的金钱不足!", @@ -200,7 +200,7 @@ editor_blockly = function () { ]} ] }, - {"type": "setValue2", "name": "flag:shop_times", "value": "1"}, + {"type": "addValue", "name": "flag:shop_times", "value": "1"}, {"type": "revisit"} ], 'event'), '', @@ -223,7 +223,7 @@ editor_blockly = function () { ],'afterBattle'), '', MotaActionFunctions.actionParser.parse([ - {"type": "setValue2", "name": "flag:__door__", "value": "1"}, + {"type": "addValue", "name": "flag:__door__", "value": "1"}, {"type": "if", "condition": "flag:__door__==2", "true": [ {"type": "openDoor", "loc": [10,5]} diff --git a/libs/control.js b/libs/control.js index b88921fd..44475dc2 100644 --- a/libs/control.js +++ b/libs/control.js @@ -951,13 +951,13 @@ control.prototype._checkBlock_ambush = function (ambush) { } ////// 更新全地图显伤 ////// -control.prototype.updateDamage = function (floorId, canvas) { +control.prototype.updateDamage = function (floorId, ctx) { floorId = floorId || core.status.floorId; - if (!core.isset(floorId)) return; + if (!core.isset(floorId) || core.status.gameOver) return; if (core.status.gameOver) return; var refreshCheckBlock = true; - if (!core.isset(canvas)) { - canvas = core.canvas.damage; + if (!core.isset(ctx)) { + ctx = core.canvas.damage; core.clearMap('damage'); refreshCheckBlock = false; } @@ -966,58 +966,46 @@ control.prototype.updateDamage = function (floorId, canvas) { var mapBlocks = core.status.maps[floorId].blocks; // 没有怪物手册 if (!core.hasItem('book')) return; - canvas.font = "bold 11px Arial"; + core.setFont(ctx, "bold 11px Arial"); + this._updateDamage_damage(floorId, ctx); + this._updateDamage_extraDamage(floorId, ctx, refreshCheckBlock); +} - if (core.flags.displayEnemyDamage || core.flags.displayCritical) { - canvas.textAlign = 'left'; - - for (var b = 0; b < mapBlocks.length; b++) { - var x = mapBlocks[b].x, y = mapBlocks[b].y; - if (core.isset(mapBlocks[b].event) && mapBlocks[b].event.cls.indexOf('enemy')==0 - && !mapBlocks[b].disable) { - - // 判定是否显伤 - if (mapBlocks[b].event.displayDamage === false) - continue; - - var id = mapBlocks[b].event.id; - - if (core.flags.displayEnemyDamage) { - var damageString = core.enemys.getDamageString(id, x, y, floorId); - var damage = damageString.damage, color = damageString.color; - core.fillBoldText(canvas, damage, 32*x+1, 32*(y+1)-1, color); - } - - // 临界显伤 - if (core.flags.displayCritical) { - var critical = core.enemys.nextCriticals(id, 1, x, y, floorId); - if (critical.length>0) critical=critical[0]; - critical = core.formatBigNumber(critical[0], true); - if (critical == '???') critical = '?'; - core.fillBoldText(canvas, critical, 32*x+1, 32*(y+1)-11, '#FFFFFF'); - } - - } +control.prototype._updateDamage_damage = function (floorId, ctx) { + core.setTextAlign(ctx, 'left'); + core.status.maps[floorId].blocks.forEach(function (block) { + var x = block.x, y = block.y; + if (!block.disable && block.event.cls.indexOf('enemy') == 0 && block.event.displayDamage !== false) { + 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) { + 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'); + } } - } - // 如果是领域&夹击 - if (core.flags.displayExtraDamage && core.isset((core.status.checkBlock||{}).damage)) { - canvas.textAlign = 'center'; - - if (refreshCheckBlock) - this.updateCheckBlock(floorId); + }); +} +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(canvas, damage, 32*x+16, 32*(y+1)-14, '#FF7F00'); + core.fillBoldText(ctx, damage, 32*x+16, 32*(y+1)-14, '#FF7F00'); } else { // 检查捕捉 if (core.status.checkBlock.ambush[x+","+y]) { - core.fillBoldText(canvas, '!', 32*x+16, 32*(y+1)-14, '#FF7F00'); + core.fillBoldText(ctx, '!', 32*x+16, 32*(y+1)-14, '#FF7F00'); } } } @@ -1025,26 +1013,7 @@ control.prototype.updateDamage = function (floorId, canvas) { } } -////// 执行一个表达式的effect操作 ////// -control.prototype.doEffect = function (effect, need, times) { - effect.split(";").forEach(function (expression) { - var arr = expression.split("+="); - if (arr.length!=2) return; - var name=arr[0], value=core.calValue(arr[1], null, need, times); - if (name.indexOf("status:")==0) { - var status=name.substring(7); - core.setStatus(status, core.getStatus(status)+value); - } - else if (name.indexOf("item:")==0) { - var itemId=name.substring(5); - core.setItem(itemId, core.itemCount(itemId)+value); - } - else if (name.indexOf("flag:")==0) { - var flag=name.substring(5); - core.setFlag(flag, core.getFlag(flag, 0)+value); - } - }); -} +// ------ 录像相关 ------ // ////// 选择录像文件 ////// control.prototype.chooseReplayFile = function () { diff --git a/libs/events.js b/libs/events.js index 6dba790c..7dfa9a27 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1213,7 +1213,11 @@ events.prototype._action_setValue = function (data, x, y, prefix) { } events.prototype._action_setValue2 = function (data, x, y, prefix) { - this.setValue2(data.name, data.value, prefix); + this._action_addValue(data, x, y, prefix); +} + +events.prototype._action_addValue = function (data, x, y, prefix) { + this.addValue(data.name, data.value, prefix); core.doAction(); } @@ -1592,10 +1596,20 @@ events.prototype._setValue_setSwitch = function (name, value, prefix) { } ////// 数值增减 ////// -events.prototype.setValue2 = function (name, value, prefix) { +events.prototype.addValue = function (name, value, prefix) { this.setValue(name, value, prefix, true); } +////// 执行一个表达式的effect操作 ////// +events.prototype.doEffect = function (effect, need, times) { + effect.split(";").forEach(function (expression) { + var arr = expression.split("+="); + if (arr.length != 2) return; + var name=arr[0], value=core.calValue(arr[1], null, need, times); + core.addValue(name, value); + }); +} + ////// 设置楼层属性 ////// events.prototype.setFloorInfo = function (name, value, floorId, prefix) { floorId = floorId || data.floorId; diff --git a/project/events.js b/project/events.js index f9b4d108..63924e63 100644 --- a/project/events.js +++ b/project/events.js @@ -102,12 +102,12 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = "text": ">=1:直接扣数值" }, { - "type": "setValue2", + "type": "addValue", "name": "status:atk", "value": "-core.values.weakValue" }, { - "type": "setValue2", + "type": "addValue", "name": "status:def", "value": "-core.values.weakValue" } From 83e97c83bc764aefb1a37de5a46ba886fd3d2cd4 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 23:08:57 +0800 Subject: [PATCH 035/153] replayActions --- libs/actions.js | 2 +- libs/control.js | 580 ++++++++++++++++++++----------------------- libs/core.js | 5 + libs/events.js | 34 ++- project/functions.js | 2 +- 5 files changed, 305 insertions(+), 318 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index c7e5fc70..5405fa6e 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -94,7 +94,7 @@ actions.prototype.doRegisteredAction = function (action) { var actions = this.actions[action]; if (!actions) return false; for (var i = 0; i < actions.length; ++i) { - if (actions[i].func.apply(this, Array.prototype.slice.call(arguments, 1))) + if (core.doFunc.apply(this, [actions[i].func].concat(Array.prototype.slice.call(arguments, 1)))) return true; } return false; diff --git a/libs/control.js b/libs/control.js index 44475dc2..cb54ae61 100644 --- a/libs/control.js +++ b/libs/control.js @@ -13,16 +13,28 @@ function control() { control.prototype._init = function () { this.controldata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.control; this.renderFrameFuncs = []; + this.replayActions = []; // --- 注册系统的animationFrame - this.registerAnimationFrame("_totalTime", false, this._animationFrame_totalTime); - this.registerAnimationFrame("_autoSave", true, this._animationFrame_autoSave); - this.registerAnimationFrame("_globalAnimate", true, this._animationFrame_globalAnimate); - this.registerAnimationFrame("_selector", false, this._animationFrame_selector); - this.registerAnimationFrame("_animate", true, this._animationFrame_animate); - this.registerAnimationFrame("_heroMoving", true, this._animationFrame_heroMoving); - this.registerAnimationFrame("_weather", true, this._animationFrame_weather); - this.registerAnimationFrame("_parallelDo", false, this._animationFrame_parallelDo); - this.registerAnimationFrame("_checkConsoleOpened", true, this._animationFrame_checkConsoleOpened); + this.registerAnimationFrame("totalTime", false, this._animationFrame_totalTime); + this.registerAnimationFrame("autoSave", true, this._animationFrame_autoSave); + this.registerAnimationFrame("globalAnimate", true, this._animationFrame_globalAnimate); + this.registerAnimationFrame("selector", false, this._animationFrame_selector); + this.registerAnimationFrame("animate", true, this._animationFrame_animate); + this.registerAnimationFrame("heroMoving", true, this._animationFrame_heroMoving); + this.registerAnimationFrame("weather", true, this._animationFrame_weather); + this.registerAnimationFrame("parallelDo", false, this._animationFrame_parallelDo); + this.registerAnimationFrame("checkConsoleOpened", true, this._animationFrame_checkConsoleOpened); + // --- 注册系统的replay + this.registerReplayAction("move", this._replayAction_move); + this.registerReplayAction("item", this._replayAction_item); + this.registerReplayAction("equip", this._replayAction_equip); + this.registerReplayAction("unEquip", this._replayAction_unEquip); + this.registerReplayAction("fly", this._replayAction_fly); + this.registerReplayAction("shop", this._replayAction_shop); + this.registerReplayAction("turn", this._replayAction_turn); + this.registerReplayAction("getNext", this._replayAction_getNext); + this.registerReplayAction("moveDirectly", this._replayAction_moveDirectly); + this.registerReplayAction("key", this._replayAction_key); } // ------ requestAnimationFrame 相关 ------ // @@ -48,12 +60,8 @@ control.prototype._setRequestAnimationFrame = function () { core.control.renderFrameFuncs.forEach(function (b) { if (b.func) { try { - if (core.isPlaying() || !b.needPlaying) { - if (b.func instanceof Function) - b.func(timestamp); - else if (typeof b.func == 'string') - core.plugin[b.func](timestamp); - } + if (core.isPlaying() || !b.needPlaying) + core.doFunc(b.func, timestamp); } catch (e) { main.log(e); @@ -1018,30 +1026,14 @@ control.prototype._updateDamage_extraDamage = function (floorId, ctx, refresh) { ////// 选择录像文件 ////// control.prototype.chooseReplayFile = function () { core.readFile(function (obj) { - if (obj.name!=core.firstData.name) { - alert("存档和游戏不一致!"); - return; - } - if (core.isset(obj.version) && obj.version!=core.firstData.version) { - // alert("游戏版本不一致!"); - if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) { + if (obj.name!=core.firstData.name) return alert("存档和游戏不一致!"); + if (obj.version && obj.version!=core.firstData.version) { + if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) return; - } } - if (!core.isset(obj.route)) { - alert("无效的录像!"); - return; - } - - if (core.flags.startUsingCanvas) { - core.startGame('', obj.seed, core.decodeRoute(obj.route)); - } - else { - core.startGame(obj.hard, obj.seed, core.decodeRoute(obj.route)); - } - }, function () { - - }) + if (!obj.route) return alert("无效的录像!"); + core.startGame(core.flags.startUsingCanvas?'':obj.hard||'', obj.seed, core.decodeRoute(obj.route)); + }); } ////// 开始播放 ////// @@ -1057,22 +1049,17 @@ control.prototype.startReplay = function (list) { core.updateStatusBar(); core.drawTip("开始播放"); this.replay(); - return; } ////// 更改播放状态 ////// control.prototype.triggerReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; if (core.status.replay.pausing) this.resumeReplay(); else this.pauseReplay(); } ////// 暂停播放 ////// control.prototype.pauseReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; + if (!core.isPlaying() || !core.isReplaying()) return; core.status.replay.pausing = true; core.updateStatusBar(); core.drawTip("暂停播放"); @@ -1080,9 +1067,9 @@ control.prototype.pauseReplay = function () { ////// 恢复播放 ////// control.prototype.resumeReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; + if (!core.isPlaying() || !core.isReplaying()) return; + if (core.isMoving() || core.status.replay.animate || core.status.event.id) + return core.drawTip("请等待当前事件的处理结束"); core.status.replay.pausing = false; core.updateStatusBar(); core.drawTip("恢复播放"); @@ -1091,12 +1078,10 @@ control.prototype.resumeReplay = function () { ////// 加速播放 ////// control.prototype.speedUpReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; - if (core.status.replay.speed==12) core.status.replay.speed=24.0; - else if (core.status.replay.speed==6) core.status.replay.speed=12.0; - else if (core.status.replay.speed==3) core.status.replay.speed=6.0; + if (!core.isPlaying() || !core.isReplaying()) return; + if (core.status.replay.speed==12) core.status.replay.speed=24; + else if (core.status.replay.speed==6) core.status.replay.speed=12; + else if (core.status.replay.speed==3) core.status.replay.speed=6; else if (core.status.replay.speed<3) { var toAdd = core.status.replay.speed>=2?2:1; core.status.replay.speed = parseInt(10*core.status.replay.speed + toAdd)/10; @@ -1106,9 +1091,7 @@ control.prototype.speedUpReplay = function () { ////// 减速播放 ////// control.prototype.speedDownReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; + if (!core.isPlaying() || !core.isReplaying()) return; if (core.status.replay.speed==24) core.status.replay.speed=12.0; else if (core.status.replay.speed==12) core.status.replay.speed=6.0; else if (core.status.replay.speed==6) core.status.replay.speed=3.0; @@ -1122,18 +1105,15 @@ control.prototype.speedDownReplay = function () { ////// 设置播放速度 ////// control.prototype.setReplaySpeed = function (speed) { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; + if (!core.isPlaying() || !core.isReplaying()) return; core.status.replay.speed = speed; core.drawTip("x"+core.status.replay.speed+"倍"); } ////// 停止播放 ////// -control.prototype.stopReplay = function () { +control.prototype.stopReplay = function (force) { if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - // if (!core.isReplaying()) return; + if (!core.isReplaying() && !force) return; core.status.replay.toReplay = []; core.status.replay.totalList = []; core.status.replay.replaying=false; @@ -1147,24 +1127,13 @@ control.prototype.stopReplay = function () { ////// 回退 ////// control.prototype.rewindReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; - if (!core.status.replay.pausing) { - core.drawTip("请先暂停录像"); - return; - } - if (core.status.replay.animate) { - core.drawTip("请等待当前事件的处理结束"); - return; - } - if (core.status.replay.save.length==0) { - core.drawTip("无法再回到上一个节点"); - return; - } - - var save = core.status.replay.save; - var data = save.pop(); + if (!core.isPlaying() || !core.isReplaying()) return; + if (!core.status.replay.pausing) return core.drawTip("请先暂停录像"); + if (core.isMoving() || core.status.replay.animate || core.status.event.id) + return core.drawTip("请等待当前事件的处理结束"); + if (core.status.replay.save.length==0) + return core.drawTip("无法再回到上一个节点"); + var save = core.status.replay.save, data = save.pop(); core.loadData(data.data, function () { core.status.replay = { "replaying": true, @@ -1178,22 +1147,15 @@ control.prototype.rewindReplay = function () { } core.updateStatusBar(); core.drawTip("成功回退到上一个节点"); - }) + }); } ////// 回放时存档 ////// control.prototype.saveReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - if (!core.isReplaying()) return; - if (!core.status.replay.pausing) { - core.drawTip("请先暂停录像"); - return; - } - if (core.status.replay.animate || core.isset(core.status.event.id)) { - core.drawTip("请等待当前事件的处理结束"); - return; - } + if (!core.isPlaying() || !core.isReplaying()) return; + if (!core.status.replay.pausing) return core.drawTip("请先暂停录像"); + if (core.isMoving() || core.status.replay.animate || core.status.event.id) + return core.drawTip("请等待当前事件的处理结束"); core.lockControl(); core.status.event.id='save'; @@ -1205,24 +1167,15 @@ control.prototype.saveReplay = function () { ////// 回放时查看怪物手册 ////// control.prototype.bookReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0) return; - if (!core.isReplaying()) return; - if (!core.status.replay.pausing) { - core.drawTip("请先暂停录像"); - return; - } + if (!core.isPlaying() || !core.isReplaying()) return; + if (!core.status.replay.pausing) return core.drawTip("请先暂停录像"); + if (core.isMoving() || core.status.replay.animate + || (core.status.event.id && core.status.event.id != 'viewMaps')) + return core.drawTip("请等待当前事件的处理结束"); // 从“浏览地图”页面打开 - if (core.status.event.id=='viewMaps') { + if (core.status.event.id=='viewMaps') core.status.event.selection = core.status.event.data; - core.status.event.id=null; - } - - if (core.status.replay.animate || core.isset(core.status.event.id)) { - core.drawTip("请等待当前事件的处理结束"); - return; - } core.lockControl(); core.status.event.id='book'; @@ -1231,38 +1184,75 @@ control.prototype.bookReplay = function () { ////// 回放录像时浏览地图 ////// control.prototype.viewMapReplay = function () { - if (!core.isPlaying()) return; - if (core.status.event.id=='save' || (core.status.event.id||"").indexOf('book')==0 || core.status.event.id=='viewMaps') return; - - if (!core.isReplaying()) return; - if (!core.status.replay.pausing) { - core.drawTip("请先暂停录像"); - return; - } - if (core.status.replay.animate || core.isset(core.status.event.id)) { - core.drawTip("请等待当前事件的处理结束"); - return; - } + if (!core.isPlaying() || !core.isReplaying()) return; + if (!core.status.replay.pausing) return core.drawTip("请先暂停录像"); + if (core.isMoving() || core.status.replay.animate || core.status.event.id) + return core.drawTip("请等待当前事件的处理结束"); core.lockControl(); core.status.event.id='viewMaps'; core.ui.drawMaps(); } +////// 是否正在播放录像 ////// +control.prototype.isReplaying = function () { + return (core.status.replay||{}).replaying; +} + ////// 回放 ////// control.prototype.replay = function () { - if (!core.isPlaying()) return; + if (!core.isPlaying() || !core.isReplaying() + || core.status.replay.pausing || core.status.replay.animate || core.status.event.id) return; + if (core.status.replay.toReplay.length==0) + return this._replay_finished(); + this._replay_save(); + var action=core.status.replay.toReplay.shift(); + if (this._doReplayAction(action)) return; + this._replay_error(action); +} - if (!core.isReplaying()) return; // 没有回放 - if (core.status.replay.pausing) return; // 暂停状态 - if (core.status.replay.animate) return; // 正在某段动画中 +////// 注册一个录像行为 ////// +// name:自定义名称,可用于注销使用 +// func:具体执行录像的函数,可为一个函数或插件中的函数名; +// 需要接受一个action参数,代表录像回放时的下一个操作 +// func返回true代表成功处理了此录像行为,false代表没有处理此录像行为。 +control.prototype.registerReplayAction = function (name, func) { + this.unregisterReplayAction(name); + this.replayActions.push({name: name, func: func}); +} - if (core.status.replay.toReplay.length==0) { // 回放完毕 - core.stopReplay(); - core.insertAction("录像回放完毕!"); - return; +////// 注销一个录像行为 ////// +control.prototype.unregisterReplayAction = function (name) { + this.replayActions = this.replayActions.filter(function (b) { return b.name != name; }); +} + +////// 执行录像行为,会在注册的函数中依次执行直到得到true为止 ////// +control.prototype._doReplayAction = function (action) { + for (var i in this.replayActions) { + try { + if (core.doFunc(this.replayActions[i].func, action)) return true; + } catch (e) { + main.log(e); + main.log("ERROR in replayActions["+this.replayActions[i].name+"]:已自动注销该项。"); + core.unregisterReplayAction(this.replayActions[i].name); + } } + return false; +} +control.prototype._replay_finished = function () { + core.status.replay.replaying = false; + core.ui.drawConfirmBox("录像播放完毕,你想退出播放吗?", function () { + core.ui.closePanel(); + core.stopReplay(true); + }, function () { + core.status.replay.replaying = true; + core.ui.closePanel(); + core.pauseReplay(); + }); +} + +control.prototype._replay_save = function () { core.status.replay.steps++; if (core.status.replay.steps%50==0) { if (core.status.replay.save.length == 30) @@ -1274,182 +1264,11 @@ control.prototype.replay = function () { "steps": core.status.replay.steps }}); } +} - var action=core.status.replay.toReplay.shift(); - - if (action == 'input2:===') { - core.replay(); - return; - } - - if (action=='up' || action=='down' || action=='left' || action=='right') { - core.moveHero(action, function () { - setTimeout(function() { - core.replay(); - }); - }); - return; - } - else if (action.indexOf("item:")==0) { - var itemId = action.substring(5); - if (core.canUseItem(itemId)) { - // 是否绘制道具栏 - if (core.material.items[itemId].hideInReplay) { - core.useItem(itemId, false, function () { - core.replay(); - }); - return; - } - else { - var tools = Object.keys(core.status.hero.items.tools).sort(); - var constants = Object.keys(core.status.hero.items.constants).sort(); - var index=-1; - if ((index=tools.indexOf(itemId))>=0) { - core.status.event.data = {"toolsPage":Math.floor(index/12)+1, "constantsPage":1, "selectId":null}; - index = index%12; - } - else if ((index=constants.indexOf(itemId))>=0) { - core.status.event.data = {"toolsPage":1, "constantsPage":Math.floor(index/12)+1, "selectId":null}; - index = index%12+12; - } - if (index>=0) { - core.ui.drawToolbox(index); - setTimeout(function () { - core.ui.closePanel(); - core.useItem(itemId, false, function () { - core.replay(); - }); - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - } - } - else if (action.indexOf("unEquip:")==0) { - var equipType = parseInt(action.substring(8)); - if (core.isset(equipType)) { - core.ui.drawEquipbox(equipType); - core.status.route.push(action); - setTimeout(function () { - core.ui.closePanel(); - core.unloadEquip(equipType, function () { - core.replay(); - }); - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - else if (action.indexOf("equip:")==0) { - var equipId = action.substring(6); - var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); - var index = ownEquipment.indexOf(equipId); - if (index>=0) { - core.status.route.push(action); - core.status.event.data = {"page":Math.floor(index/12)+1, "selectId":null}; - index = index%12+12; - core.ui.drawEquipbox(index); - setTimeout(function () { - core.ui.closePanel(); - core.loadEquip(equipId, function () { - core.replay(); - }); - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - else if (action.indexOf("fly:")==0) { - var floorId=action.substring(4); - var toIndex=core.floorIds.indexOf(floorId); - if (core.hasItem('fly')) { - core.ui.drawFly(toIndex); - setTimeout(function () { - if (!core.control.flyTo(floorId, function () {core.replay()})) { - core.stopReplay(); - core.insertAction("录像文件出错"); - } - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - else if (action.indexOf("shop:")==0) { - var sps=action.substring(5).split(":"); - var shopId=sps[0], selections=sps[1].split(""); - - if (selections.length>0) { - var shop=core.status.shops[shopId]; - if (core.isset(shop) && shop.visited) { // 商店可用 - var choices = shop.choices; - var topIndex = core.__HALF_SIZE__ - parseInt(choices.length / 2); - - core.status.event.selection = parseInt(selections.shift()); - - core.events.openShop(shopId, false); - var shopInterval = setInterval(function () { - if (!core.actions._clickShop(core.__HALF_SIZE__, topIndex+core.status.event.selection)) { - clearInterval(shopInterval); - core.stopReplay(); - core.drawTip("录像文件出错"); - return; - } - if (selections.length==0) { - clearInterval(shopInterval); - core.actions._clickShop(core.__HALF_SIZE__, topIndex+choices.length); - core.replay(); - return; - } - core.status.event.selection = parseInt(selections.shift()); - core.events.openShop(shopId, false); - - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - } - else if (action=='turn') { - core.turnHero(); - core.replay(); - return; - } - else if (action.indexOf("turn:")==0) { - core.turnHero(action.substring(5)); - core.replay(); - return; - } - else if (action=='getNext') { - if (core.getNextItem()) { - core.replay(); - return; - } - } - else if (action.indexOf('move:')==0) { - while (core.status.replay.toReplay.length>0 && - core.status.replay.toReplay[0].indexOf('move:')==0) { - action = core.status.replay.toReplay.shift(); - } - - var pos=action.substring(5).split(":"); - var x=parseInt(pos[0]), y=parseInt(pos[1]); - var nowx=core.getHeroLoc('x'), nowy=core.getHeroLoc('y'); - if (core.control.moveDirectly(x,y)) { - core.ui.drawArrow('ui', 32*nowx+16-core.bigmap.offsetX, 32*nowy+16-core.bigmap.offsetY, 32*x+16-core.bigmap.offsetX, 32*y+16-core.bigmap.offsetY, '#FF0000', 3); - setTimeout(function () { - core.clearMap('ui'); - core.replay(); - }, 750 / Math.max(1, core.status.replay.speed)); - return; - } - } - else if (action.indexOf('key:')==0) { - core.actions.keyUp(parseInt(action.substring(4)), false, true); - core.replay(); - return; - } - - // core.stopReplay(); - // core.insertAction("录像文件出错"); - +control.prototype._replay_error = function (action) { core.status.replay.replaying = false; - main.log("录像文件出错,当前操作:"+action+ + main.log("录像文件出错,当前操作:" + action + "\n接下来10个操作是:"+core.status.replay.toReplay.slice(0, 10).toString()); core.ui.drawConfirmBox("录像文件出错,你想回到上个节点吗?", function () { core.ui.closePanel(); @@ -1460,17 +1279,168 @@ control.prototype.replay = function () { } else { core.drawTip("无法回到上一个节点"); - core.stopReplay(); + core.stopReplay(true); } }, function () { core.ui.closePanel(); - core.stopReplay(); + core.stopReplay(true); }); - } -control.prototype.isReplaying = function () { - return (core.status.replay||{}).replaying; +control.prototype.__replay_getTimeout = function () { + return 750 / Math.max(1, core.status.replay.speed); +} + +control.prototype._replayAction_move = function (action) { + if (["up","down","left","right"].indexOf(action)<0) return false; + core.moveHero(action, function () { + setTimeout(core.replay); + }); + return true; +} + +control.prototype._replayAction_item = function (action) { + if (action.indexOf("item:")!=0) return false; + var itemId = action.substring(5); + if (!core.canUseItem(itemId)) return false; + if (core.material.items[itemId].hideInReplay) { + core.useItem(itemId, false, core.replay); + return true; + } + var tools = Object.keys(core.status.hero.items.tools).sort(); + var constants = Object.keys(core.status.hero.items.constants).sort(); + var index, per = core.__SIZE__-1; + if ((index=tools.indexOf(itemId))>=0) { + core.status.event.data = {"toolsPage": Math.floor(index/per)+1, "constantsPage":1}; + index = index%per; + } + else if ((index=constants.indexOf(itemId))>=0) { + core.status.event.data = {"toolsPage": 1, "constantsPage": Math.floor(index/per)+1}; + index = index%per+per; + } + if (index<0) return false; + core.ui.drawToolbox(index); + setTimeout(function () { + core.ui.closePanel(); + core.useItem(itemId, false, core.replay); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_equip = function (action) { + if (action.indexOf("equip:")!=0) return false; + var equipId = action.substring(6); + var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); + var index = ownEquipment.indexOf(equipId), per = core.__SIZE__-1; + if (index<0) return false; + core.status.route.push(action); + core.status.event.data = {"page":Math.floor(index/per)+1, "selectId":null}; + index = index%per+per; + core.ui.drawEquipbox(index); + setTimeout(function () { + core.ui.closePanel(); + core.loadEquip(equipId, core.replay); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_unEquip = function (action) { + if (action.indexOf("unEquip:")!=0) return false; + var equipType = parseInt(action.substring(8)); + if (!core.isset(equipType)) return false; + core.ui.drawEquipbox(equipType); + core.status.route.push(action); + setTimeout(function () { + core.ui.closePanel(); + core.unloadEquip(equipType, core.replay); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_fly = function (action) { + if (action.indexOf("fly:")!=0) return false; + var floorId=action.substring(4); + var toIndex=core.floorIds.indexOf(floorId); + if (!core.canUseItem('fly')) return false; + core.ui.drawFly(toIndex); + setTimeout(function () { + if (!core.control.flyTo(floorId, core.replay)) + core.control._replay_error(action); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_shop = function (action) { + if (action.indexOf("shop:")!=0) return false; + var sps=action.substring(5).split(":"); + var shopId=sps[0], selections=sps[1].split(""); + if (selections.length == 0) return false; + var shop=core.status.shops[shopId]; + if (!shop || !shop.visited) return false; + var choices = shop.choices; + var topIndex = core.__HALF_SIZE__ - parseInt(choices.length / 2); + core.status.event.selection = parseInt(selections.shift()); + core.events.openShop(shopId, false); + var shopInterval = setInterval(function () { + if (!core.actions._clickShop(core.__HALF_SIZE__, topIndex+core.status.event.selection)) { + clearInterval(shopInterval); + core.stopReplay(); + core.drawTip("录像文件出错"); + return; + } + if (selections.length==0) { + clearInterval(shopInterval); + core.actions._clickShop(core.__HALF_SIZE__, topIndex+choices.length); + core.replay(); + return; + } + core.status.event.selection = parseInt(selections.shift()); + core.events.openShop(shopId, false); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_turn = function (action) { + if (action != 'turn' || action.indexOf('turn:') != 0) return false; + if (action == 'turn') core.turnHero(); + else core.turnHero(action.substring(5)); + setTimeout(core.replay); + return true; +} + +control.prototype._replayAction_getNext = function (action) { + if (action != "getNext") return false; + if (!core.getNextItem()) return false; + setTimeout(core.replay); + return true; +} + +control.prototype._replayAction_moveDirectly = function (action) { + if (action.indexOf("move:")!=0) return false; + // 忽略连续的瞬移事件 + while (core.status.replay.toReplay.length>0 && + core.status.replay.toReplay[0].indexOf('move:')==0) { + action = core.status.replay.toReplay.shift(); + } + + var pos=action.substring(5).split(":"); + var x=parseInt(pos[0]), y=parseInt(pos[1]); + var nowx=core.getHeroLoc('x'), nowy=core.getHeroLoc('y'); + if (!core.moveDirectly(x, y)) return false; + core.ui.drawArrow('ui', 32*nowx+16-core.bigmap.offsetX, 32*nowy+16-core.bigmap.offsetY, + 32*x+16-core.bigmap.offsetX, 32*y+16-core.bigmap.offsetY, '#FF0000', 3); + setTimeout(function () { + core.clearMap('ui'); + core.replay(); + }, core.control.__replay_getTimeout()); + return true; +} + +control.prototype._replayAction_key = function (action) { + if (action.indexOf("key:") != 0) return false; + core.actions.keyUp(parseInt(action.substring(4)), false, true); + setTimeout(core.replay); + return true; } ////// 判断当前能否进入某个事件 ////// diff --git a/libs/core.js b/libs/core.js index c64b7c71..8aff5de9 100644 --- a/libs/core.js +++ b/libs/core.js @@ -379,6 +379,11 @@ core.prototype._forwardFunc = function (name, funcname) { eval("core." + funcname + " = function (" + parameters + ") {\n\treturn core." + name + "." + funcname + "(" + parameters + ");\n}"); } +core.prototype.doFunc = function (func) { + if (typeof func == 'string') func = core.plugin[func]; + return func.apply(this, Array.prototype.slice.call(arguments, 1)); +} + /** * 系统机制 end */ diff --git a/libs/events.js b/libs/events.js index 7dfa9a27..de2f9cb3 100644 --- a/libs/events.js +++ b/libs/events.js @@ -241,12 +241,18 @@ events.prototype.unregisterSystemEvent = function (type) { ////// 执行一个系统事件 ////// events.prototype.doSystemEvent = function (type, data, callback) { - if (this.systemEvents[type]) this.systemEvents[type](data, callback); - else if (this["_sys_" + type]) this["_sys_" + type](data, callback); - else { - main.log("未知的系统事件: " + type + "!"); - if (callback) callback(); + if (this.systemEvents[type]) { + try { + return core.doFunc(this.systemEvents[type], data, data, callback); + } + catch (e) { + main.log(e); + main.log("ERROR in systemEvents["+type+"]"); + } } + if (this["_sys_" + type]) return this["_sys_" + type](data, callback); + main.log("未知的系统事件: " + type + "!"); + if (callback) callback(); } ////// 触发(x,y)点的事件 ////// @@ -713,12 +719,18 @@ events.prototype.unregisterEvent = function (type) { ////// 执行一个自定义事件 events.prototype.doEvent = function (data, x, y, prefix) { var type = data.type; - if (this.actions[type]) this.actions[type](data, x, y, prefix); - else if (this["_action_" + type]) this["_action_" + type](data, x, y, prefix); - else { - core.insertAction("未知的自定义事件: " + type + "!"); - core.doAction(); + if (this.actions[type]) { + try { + return core.doFunc(this.actions[type], data, x, y, prefix); + } + catch (e) { + main.log(e); + main.log("ERROR in actions["+type+"]"); + } } + if (this["_action_" + type]) return this["_action_" + type](data, x, y, prefix); + core.insertAction("未知的自定义事件: " + type + "!"); + core.doAction(); } ////// 开始执行一系列自定义事件 ////// @@ -859,7 +871,7 @@ events.prototype.__action_getHeroLoc = function (loc, prefix) { events.prototype.__action_getLoc2D = function (loc, x, y, prefix) { if (!(loc && loc[0] instanceof Array)) - loc = [this.__action_getLoc(data.loc, x, y, prefix)]; + loc = [this.__action_getLoc(loc, x, y, prefix)]; return loc; } diff --git a/project/functions.js b/project/functions.js index 4ff799de..14f07ff2 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1130,7 +1130,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = enemyId = leftBlock.event.id; } // 检查上下夹击 - var topBlock = block[x + "," + (y - 1)], + 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)) From 845ed191ea1a7241ef488fe92c6c5c985e63bcec Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 18 Mar 2019 23:21:38 +0800 Subject: [PATCH 036/153] checkStatus -> events --- libs/actions.js | 2 +- libs/control.js | 161 +----------------------------------------------- libs/events.js | 137 +++++++++++++++++++++++++++++++++++++++- 3 files changed, 139 insertions(+), 161 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 5405fa6e..3a9c5357 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1004,7 +1004,7 @@ actions.prototype._clickFly = function (x, y) { if ((x == 10 || x == 11) && y == 4) core.ui.drawFly(this._getNextFlyFloor(10)); if (x >= 5 && x <= 7 && y == 12) core.ui.closePanel(); if (x >= 0 && x <= 9 && y >= 3 && y <= 11) - core.control.flyTo(core.floorIds[core.status.event.data]); + core.flyTo(core.floorIds[core.status.event.data]); return; } diff --git a/libs/control.js b/libs/control.js index cb54ae61..7ae47130 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1242,6 +1242,7 @@ control.prototype._doReplayAction = function (action) { control.prototype._replay_finished = function () { core.status.replay.replaying = false; + core.status.event.selection = 0; core.ui.drawConfirmBox("录像播放完毕,你想退出播放吗?", function () { core.ui.closePanel(); core.stopReplay(true); @@ -1443,165 +1444,7 @@ control.prototype._replayAction_key = function (action) { return true; } -////// 判断当前能否进入某个事件 ////// -control.prototype.checkStatus = function (name, need, item) { - if (need && core.status.event.id == name) { - core.ui.closePanel(); - return false; - } - - if (need && core.status.lockControl) return false; - if (core.isset(item) && item && !core.hasItem(name)) { - core.drawTip("你没有" + core.material.items[name].name); - return false; - } - if (core.isMoving()) { - core.drawTip("请先停止勇士行动"); - return false; - } - - core.lockControl(); - core.status.event.id = name; - return true; -} - -////// 点击怪物手册时的打开操作 ////// -control.prototype.openBook = function (need) { - if (core.isReplaying()) return; - - if (core.status.event.id == 'book' && core.events.recoverEvents(core.status.event.interval)) { - return; - } - - // 当前是book,且从“浏览地图”打开 - if (core.status.event.id == 'book' && core.isset(core.status.event.ui)) { - core.status.boxAnimateObjs = []; - core.ui.drawMaps(core.status.event.ui); - return; - } - - // 从“浏览地图”页面打开 - if (core.status.event.id=='viewMaps') { - need=false; - core.status.event.ui = core.status.event.data; - } - - if (!core.checkStatus('book', need, true)) - return; - core.useItem('book', true); -} - -////// 点击楼层传送器时的打开操作 ////// -control.prototype.useFly = function (need) { - if (core.isReplaying()) return; - if (!core.checkStatus('fly', need, true)) - return; - if (core.flags.flyNearStair && !core.nearStair()) { - core.drawTip("只有在楼梯边才能使用传送器"); - core.unLockControl(); - core.status.event.data = null; - core.status.event.id = null; - return; - } - if (!core.canUseItem('fly')) { - core.drawTip("楼层传送器好像失效了"); - core.unLockControl(); - core.status.event.data = null; - core.status.event.id = null; - return; - } - core.useItem('fly', true); - return; -} - -control.prototype.flyTo = function (toId, callback) { - return this.controldata.flyTo(toId, callback); -} - -////// 点击装备栏时的打开操作 ////// -control.prototype.openEquipbox = function (need) { - if (core.isReplaying()) return; - if (!core.checkStatus('equipbox', need)) - return; - core.ui.drawEquipbox(); -} - -////// 点击工具栏时的打开操作 ////// -control.prototype.openToolbox = function (need) { - if (core.isReplaying()) return; - if (!core.checkStatus('toolbox', need)) - return; - core.ui.drawToolbox(); -} - -////// 点击快捷商店按钮时的打开操作 ////// -control.prototype.openQuickShop = function (need) { - if (core.isReplaying()) return; - if (!core.checkStatus('selectShop', need)) - return; - core.ui.drawQuickShop(); -} - -control.prototype.openKeyBoard = function (need) { - if (core.isReplaying()) return; - - if (!core.checkStatus('keyBoard', need)) - return; - core.ui.drawKeyBoard(); -} - -////// 点击保存按钮时的打开操作 ////// -control.prototype.save = function(need) { - if (core.isReplaying()) return; - - if (core.status.event.id == 'save' && core.events.recoverEvents(core.status.event.interval)) { - return; - } - - if (!core.checkStatus('save', need)) - return; - - var saveIndex = core.saves.saveIndex; - var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; - - core.ui.drawSLPanel(10*page+offset); -} - -////// 点击读取按钮时的打开操作 ////// -control.prototype.load = function (need) { - if (core.isReplaying()) return; - - var saveIndex = core.saves.saveIndex; - var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; - - // 游戏开始前读档 - if (!core.isPlaying()) { - core.dom.startPanel.style.display = 'none'; - core.clearStatus(); - core.clearMap('all'); - core.deleteAllCanvas(); - core.status.event = {'id': 'load', 'data': null}; - core.status.lockControl = true; - core.ui.drawSLPanel(10*page+offset); - return; - } - - if (core.status.event.id == 'load' && core.events.recoverEvents(core.status.event.interval)) { - return; - } - - if (!core.checkStatus('load', need)) - return; - core.ui.drawSLPanel(10*page+offset); -} - -////// 点击设置按钮时的操作 ////// -control.prototype.openSettings = function (need) { - if (core.isReplaying()) return; - if (!core.checkStatus('settings', need)) - return; - core.ui.drawSettings(); -} +// ------ 存读档相关 ------ // ////// 自动存档 ////// control.prototype.autosave = function (removeLast) { diff --git a/libs/events.js b/libs/events.js index de2f9cb3..215f0c97 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1516,7 +1516,142 @@ events.prototype._action_exit = function (data, x, y, prefix) { core.doAction(); } -// ------ 样板提供的的自定义事件 END ------ // +// ------ 点击状态栏图标所进行的一些操作 ------ // + +////// 判断当前能否进入某个事件 ////// +events.prototype._checkStatus = function (name, fromUserAction, checkItem) { + if (fromUserAction && core.status.event.id == name) { + core.ui.closePanel(); + return false; + } + if (fromUserAction && core.status.lockControl) return false; + if (checkItem && !core.hasItem(name)) { + core.drawTip("你没有" + core.material.items[name].name); + return false; + } + if (core.isMoving()) { + core.drawTip("请先停止勇士行动"); + return false; + } + core.lockControl(); + core.status.event.id = name; + return true; +} + +////// 点击怪物手册时的打开操作 ////// +events.prototype.openBook = function (fromUserAction) { + if (core.isReplaying()) return; + // 如果能恢复事件(从callBook事件触发) + if (core.status.event.id == 'book' && core.events.recoverEvents(core.status.event.interval)) + return; + // 当前是book,且从“浏览地图”打开 + if (core.status.event.id == 'book' && core.status.event.ui) { + core.status.boxAnimateObjs = []; + core.ui.drawMaps(core.status.event.ui); + return; + } + // 从“浏览地图”页面打开 + if (core.status.event.id == 'viewMaps') { + fromUserAction = false; + core.status.event.ui = core.status.event.data; + } + if (!this._checkStatus('book', fromUserAction, true)) return; + core.useItem('book', true); +} + +////// 点击楼层传送器时的打开操作 ////// +events.prototype.useFly = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('fly', fromUserAction, true)) return; + if (core.flags.flyNearStair && !core.nearStair()) { + core.drawTip("只有在楼梯边才能使用传送器"); + core.unLockControl(); + core.status.event.data = null; + core.status.event.id = null; + return; + } + if (!core.canUseItem('fly')) { + core.drawTip("楼层传送器好像失效了"); + core.unLockControl(); + core.status.event.data = null; + core.status.event.id = null; + return; + } + core.useItem('fly', true); + return; +} + +events.prototype.flyTo = function (toId, callback) { + return this.controldata.flyTo(toId, callback); +} + +////// 点击装备栏时的打开操作 ////// +events.prototype.openEquipbox = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('equipbox', fromUserAction)) return; + core.ui.drawEquipbox(); +} + +////// 点击工具栏时的打开操作 ////// +events.prototype.openToolbox = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('toolbox', fromUserAction)) return; + core.ui.drawToolbox(); +} + +////// 点击快捷商店按钮时的打开操作 ////// +events.prototype.openQuickShop = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('selectShop', fromUserAction)) return; + core.ui.drawQuickShop(); +} + +events.prototype.openKeyBoard = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('keyBoard', fromUserAction)) return; + core.ui.drawKeyBoard(); +} + +////// 点击保存按钮时的打开操作 ////// +events.prototype.save = function (fromUserAction) { + if (core.isReplaying()) return; + if (core.status.event.id == 'save' && core.events.recoverEvents(core.status.event.interval)) + return; + if (!this._checkStatus('save', fromUserAction)) return; + var saveIndex = core.saves.saveIndex; + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; + core.ui.drawSLPanel(10*page+offset); +} + +////// 点击读取按钮时的打开操作 ////// +events.prototype.load = function (fromUserAction) { + if (core.isReplaying()) return; + var saveIndex = core.saves.saveIndex; + var page=parseInt((saveIndex-1)/5), offset=saveIndex-5*page; + // 游戏开始前读档 + if (!core.isPlaying()) { + core.dom.startPanel.style.display = 'none'; + core.clearStatus(); + core.clearMap('all'); + core.deleteAllCanvas(); + core.status.event = {'id': 'load', 'data': null}; + core.status.lockControl = true; + core.ui.drawSLPanel(10*page+offset); + return; + } + if (core.status.event.id == 'load' && core.events.recoverEvents(core.status.event.interval)) + return; + if (!this._checkStatus('load', fromUserAction)) return; + core.ui.drawSLPanel(10*page+offset); +} + +////// 点击设置按钮时的操作 ////// +events.prototype.openSettings = function (fromUserAction) { + if (core.isReplaying()) return; + if (!this._checkStatus('settings', fromUserAction)) + return; + core.ui.drawSettings(); +} // ------ 一些事件的具体执行过程 ------ // From 676dc5009258f2889af8c0943ac1919d6ec7425c Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 01:24:30 +0800 Subject: [PATCH 037/153] save & load v2.6 --- _server/functions.comment.js | 70 +++--- libs/actions.js | 4 + libs/control.js | 459 ++++++++++++++--------------------- libs/events.js | 10 - project/functions.js | 87 ++++++- 5 files changed, 294 insertions(+), 336 deletions(-) diff --git a/_server/functions.comment.js b/_server/functions.comment.js index af73b831..2120f717 100644 --- a/_server/functions.comment.js +++ b/_server/functions.comment.js @@ -16,7 +16,7 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "不同难度分别设置初始属性" + "_data": "设置初始属性" }, "win": { "_leaf": true, @@ -34,73 +34,61 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "正在切换楼层过程中的操作\n此函数的执行时间是在切换楼层过程中屏幕完全变黑的一刻" + "_data": "切换楼层中" }, "afterChangeFloor": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "转换楼层结束的事件\n此函数会在整个楼层切换完全结束后执行" + "_data": "切换楼层后" }, "beforeBattle": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "战斗前发生的事件" + "_data": "战前事件" }, "afterBattle": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "战斗结束后触发的事件" + "_data": "战后事件" }, "afterOpenDoor": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "开一个门后触发的事件" + "_data": "开门后事件" }, "afterGetItem": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "获得一个道具后触发的事件" + "_data": "获得道具后事件" }, "afterChangeLight": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "改变亮灯之后,可以触发的事件" + "_data": "改变亮灯事件" }, "afterPushBox": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "推箱子后的事件" + "_data": "推箱子事件" }, "afterUseBomb": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "使用炸弹/圣锤后的事件" - }, - "beforeSaveData": { - "_leaf": true, - "_type": "textarea", - "_lint": true, - "_data": "即将存档前可以执行的操作" - }, - "afterLoadData": { - "_leaf": true, - "_type": "textarea", - "_lint": true, - "_data": "读档事件后,载入事件前,可以执行的操作" + "_data": "炸弹事件" }, "canUseQuickShop": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "当前能否使用快捷商店" + "_data": "能否用快捷商店" } } }, @@ -111,25 +99,25 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "怪物特殊属性的定义(获得怪物的特殊属性)" + "_data": "怪物特殊属性定义" }, "getEnemyInfo": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "获得某个怪物的当前属性数据\n该函数主要是会被伤害计算和怪物手册等使用" + "_data": "获得怪物真实属性" }, "getDamageInfo": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "获得战斗伤害信息(实际伤害计算函数)" + "_data": "获得战斗伤害信息" }, "updateEnemys": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "更新怪物数据,可以在这里对怪物属性和数据进行动态更新" + "_data": "更新怪物数据" } } }, @@ -140,18 +128,30 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "按键处理;可以在这里自定义快捷键,详见文档-个性化-自定义快捷键" + "_data": "按键处理" } } }, "control": { "_type": "object", "_data": { + "saveData": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "存档操作" + }, + "loadData": { + "_leaf": true, + "_type": "textarea", + "_lint": true, + "_data": "读档操作" + }, "flyTo": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "使用楼层传送器飞到某层" + "_data": "楼层飞行" }, "updateStatusBar": { "_leaf": true, @@ -163,19 +163,19 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "阻激夹域的伤害值计算" + "_data": "阻激夹域伤害" }, "moveOneStep": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "勇士每走一步的操作" + "_data": "每一步后的操作" }, "moveDirectly": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "瞬间移动" + "_data": "瞬间移动处理" } } }, @@ -186,19 +186,19 @@ var functions_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "自定义绘制状态栏。\n当状态栏canvas化开启时,可以在这里对状态栏进行自定义绘制。\n仅当statusCanvas开启时有效。" + "_data": "自绘状态栏" }, "drawStatistics": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "地图数据统计项的注册" + "_data": "地图数据统计" }, "drawAbout": { "_leaf": true, "_type": "textarea", "_lint": true, - "_data": "绘制“关于”界面" + "_data": "绘制关于界面" } } }, diff --git a/libs/actions.js b/libs/actions.js index 3a9c5357..a83bff54 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -2061,6 +2061,8 @@ actions.prototype._clickStorageRemove = function (x, y) { var selection = y - topIndex; switch (selection) { case 0: + if (!confirm("你确定要清除【全部塔】的所有本地存档?\n此行为不可逆!!!")) + break; if (core.platform.useLocalForage) { core.ui.drawWaiting("正在清空,请稍后..."); localforage.clear(function () { @@ -2078,6 +2080,8 @@ actions.prototype._clickStorageRemove = function (x, y) { } break; case 1: + if (!confirm("你确定要清除本塔的所有本地存档?\n此行为不可逆!!!")) + break; if (core.platform.useLocalForage) { core.ui.drawWaiting("正在清空,请稍后..."); Object.keys(core.saves.ids).forEach(function (v) { diff --git a/libs/control.js b/libs/control.js index 7ae47130..8563df15 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1365,7 +1365,7 @@ control.prototype._replayAction_fly = function (action) { if (!core.canUseItem('fly')) return false; core.ui.drawFly(toIndex); setTimeout(function () { - if (!core.control.flyTo(floorId, core.replay)) + if (!core.flyTo(floorId, core.replay)) core.control._replay_error(action); }, core.control.__replay_getTimeout()); return true; @@ -1450,27 +1450,19 @@ control.prototype._replayAction_key = function (action) { control.prototype.autosave = function (removeLast) { if (core.status.event.id!=null) return; var x=null; - if (removeLast) - x=core.status.route.pop(); + if (removeLast) x=core.status.route.pop(); core.status.route.push("turn:"+core.getHeroLoc('direction')); - // core.setLocalForage("autoSave", core.saveData()); - // ----- Add to autosaveData core.saves.autosave.data = core.saveData(); core.saves.autosave.updated = true; core.saves.ids[0] = true; - // ----- Updated every 5s core.status.route.pop(); - if (removeLast && core.isset(x)) - core.status.route.push(x); + if (x) core.status.route.push(x); } /////// 实际进行自动存档 ////// control.prototype.checkAutosave = function () { - if (!core.animateFrame || !core.saves || !core.saves.autosave) return; - core.setLocalStorage('totalTime', core.animateFrame.totalTime); - if (core.saves.autosave.data == null || !core.saves.autosave.updated) return; core.saves.autosave.updated = false; core.setLocalForage("autoSave", core.saves.autosave.data); @@ -1478,168 +1470,152 @@ control.prototype.checkAutosave = function () { ////// 实际进行存读档事件 ////// control.prototype.doSL = function (id, type) { - if (type=='save') { - if (id=='autoSave') { - core.drawTip('不能覆盖自动存档!'); - return; - } - // 事件中的存档 - if (core.status.event.interval != null) { - core.setFlag("__events__", core.status.event.interval); - } - core.setLocalForage("save"+id, core.saveData(), function() { - if (id!="autoSave") { - core.saves.saveIndex=id; - core.setLocalStorage('saveIndex', core.saves.saveIndex); - } - if (core.events.recoverEvents(core.status.event.interval)) { - core.drawTip("存档成功!"); - return; - } + switch (type) { + case 'save': this._doSL_save(id); break; + case 'load': this._doSL_load(id); break; + case 'replayLoad': this._doSL_replayLoad(id); break; + } +} + +control.prototype._doSL_save = function (id) { + if (id=='autoSave') return core.drawTip('不能覆盖自动存档!'); + // 在事件中的存档 + if (core.status.event.interval != null) + core.setFlag("__events__", core.status.event.interval); + core.setLocalForage("save"+id, core.saveData(), function() { + core.saves.saveIndex=id; + core.setLocalStorage('saveIndex', core.saves.saveIndex); + // 恢复事件 + if (!core.events.recoverEvents(core.status.event.interval)) core.ui.closePanel(); - core.drawTip('存档成功!'); + core.drawTip('存档成功!'); + }, function(err) { + main.log(err); + if (core.platform.useLocalForage) { + alert("存档失败,错误信息:\n"+err); + } + else { + alert("存档失败,错误信息:\n"+err+"\n建议使用垃圾存档清理工具进行清理!"); + } + }); + core.removeFlag("__events__"); + return; +} + +control.prototype._doSL_load = function (id) { + if (id == 'autoSave' && core.saves.autosave.data != null) { + this._doSL_load_afterGet(id, core.clone(core.saves.autosave.data)); + } + else { + core.getLocalForage(id=='autoSave'?id:"save"+id, null, function(data) { + if (id == 'autoSave') core.saves.autosave.data = core.clone(data); + core.control._doSL_load_afterGet(id, data); }, function(err) { - console.info(err); - if (core.platform.useLocalForage) { - alert("存档失败,错误信息:\n"+err); - } - else { - alert("存档失败,错误信息:\n"+err+"\n建议使用垃圾存档清理工具进行清理!"); - } - }); - core.removeFlag("__events__"); + main.log(err); + alert("无效的存档"); + }) + } + return; +} + +control.prototype._doSL_load_afterGet = function (id, data) { + if (!data) return alert("无效的存档"); + if (core.flags.checkConsole && data.hashCode != null && data.hashCode != core.hashCode(data.hero)) { + if (confirm("存档校验失败,请勿修改存档文件!\n你想回放此存档的录像吗?")) + core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); return; } - else if (type=='load') { - var afterGet = function (data) { - if (!core.isset(data)) { - alert("无效的存档"); - return; - } - if (core.flags.checkConsole && core.isset(data.hashCode) && data.hashCode != core.utils.hashCode(data.hero)) { - if (confirm("存档校验失败,请勿修改存档文件!\n你想回放此存档的录像吗?")) { - core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); - } - return; - } - if (data.version != core.firstData.version) { - // core.drawTip("存档版本不匹配"); - if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。")) { - core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); - } - return; - } - core.ui.closePanel(); - core.loadData(data, function() { - core.drawTip("读档成功"); - if (id!="autoSave") { - core.saves.saveIndex=id; - core.setLocalStorage('saveIndex', core.saves.saveIndex); - } - }); - } - if (id == 'autoSave' && core.saves.autosave.data != null) { - afterGet(core.clone(core.saves.autosave.data)); - } - else { - core.getLocalForage(id=='autoSave'?id:"save"+id, null, function(data) { - if (id == 'autoSave') core.saves.autosave.data = core.clone(data); - afterGet(data); - }, function(err) { - main.log(err); - alert("无效的存档"); - }) - } + if (data.version != core.firstData.version) { + if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。")) + core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); return; } - else if (type == 'replayLoad') { - var afterGet = function (data) { - if (!core.isset(data)) { - core.drawTip("无效的存档"); - return; - } - if (data.version != core.firstData.version) { - core.drawTip("存档版本不匹配"); - return; - } - if (data.hard != core.status.hard) { - core.drawTip("游戏难度不匹配!"); - return; - } - if (core.isset(data.hashCode) && data.hashCode != core.utils.hashCode(data.hero)) { - alert("存档校验失败,请勿修改存档文件!"); - return; - } - var route = core.subarray(core.status.route, core.decodeRoute(data.route)); - if (!core.isset(route) || data.hero.flags.__seed__!=core.getFlag('__seed__')) { - core.drawTip("无法从此存档回放录像"); - return; - } - core.loadData(data, function () { - core.startReplay(route); - core.drawTip("回退到存档节点"); - }); - } - if (id == 'autoSave' && core.saves.autosave.data != null) { - afterGet(core.clone(core.saves.autosave.data)); - } - else { - core.getLocalForage(id=='autoSave'?id:"save"+id, null, function(data) { - if (id == 'autoSave') core.saves.autosave.data = core.clone(data); - afterGet(data); - }, function(err) { - main.log(err); - alert("无效的存档"); - }) + core.ui.closePanel(); + core.loadData(data, function() { + core.drawTip("读档成功"); + if (id!="autoSave") { + core.saves.saveIndex=id; + core.setLocalStorage('saveIndex', core.saves.saveIndex); } + }); + +} + +control.prototype._doSL_replayLoad = function (id) { + if (id == 'autoSave' && core.saves.autosave.data != null) { + this._doSL_replayLoad_afterGet(core.clone(core.saves.autosave.data)); } + else{ + core.getLocalForage(id=='autoSave'?id:"save"+id, null, function(data) { + if (id == 'autoSave') core.saves.autosave.data = core.clone(data); + core.control._doSL_replayLoad_afterGet(data); + }, function(err) { + main.log(err); + alert("无效的存档"); + }) + } +} + +control.prototype._doSL_replayLoad_afterGet = function (id, data) { + if (!data) return core.drawTip("无效的存档"); + if (data.version != core.firstData.version) return core.drawTip("存档版本不匹配"); + if (data.hard != core.status.hard) core.drawTip("游戏难度不匹配!"); + if (data.hashCode != null && data.hashCode != core.utils.hashCode(data.hero)) + return alert("存档校验失败,请勿修改存档文件!"); + var route = core.subarray(core.status.route, core.decodeRoute(data.route)); + if (route == null || data.hero.flags.__seed__ != core.getFlag('__seed__')) + return core.drawTip("无法从此存档回放录像"); + core.loadData(data, function () { + core.startReplay(route); + core.drawTip("回退到存档节点"); + }); + } ////// 同步存档到服务器 ////// control.prototype.syncSave = function (type) { core.ui.drawWaiting("正在同步,请稍后..."); core.control.getSaves(type=='all'?null:core.saves.saveIndex, function (saves) { - if (!core.isset(saves)) { - core.drawText("没有要同步的存档"); - return; + if (!saves) return core.drawText("没有要同步的存档"); + core.control._syncSave_http(saves); + }) +} + +control.prototype._syncSave_http = function (saves) { + var formData = new FormData(); + formData.append('type', 'save'); + formData.append('name', core.firstData.name); + formData.append('data', JSON.stringify(saves)); + + core.http("POST", "/games/sync.php", formData, function (data) { + var response = JSON.parse(data); + if (response.code<0) { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg); } - - var formData = new FormData(); - formData.append('type', 'save'); - formData.append('name', core.firstData.name); - var save_text = JSON.stringify(saves); - formData.append('data', save_text); - - core.http("POST", "/games/sync.php", formData, function (data) { - var response = JSON.parse(data); - if (response.code<0) { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+response.msg); - } - else { - core.drawText((type=='all'?"所有存档":"存档"+core.saves.saveIndex)+"同步成功!\n\n您的存档编号: " - +response.code+"\n您的存档密码: "+response.msg - +"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") - } - }, function (e) { - core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); - }) + else { + core.drawText((type=='all'?"所有存档":"存档"+core.saves.saveIndex)+"同步成功!\n\n您的存档编号: " + +response.code+"\n您的存档密码: "+response.msg + +"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") + } + }, function (e) { + core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); }) } ////// 从服务器加载存档 ////// control.prototype.syncLoad = function () { core.interval.onDownInterval = 'tmp'; - var id = prompt("请输入存档编号:"); - if (id==null || id=="") { - core.ui.drawSyncSave(); return; - } + var id = prompt("请输入存档编号:") || ""; + if (id=="") return core.ui.drawSyncSave(); core.interval.onDownInterval = 'tmp'; - var password = prompt("请输入存档密码:"); - if (password==null || password=="") { - core.ui.drawSyncSave(); return; - } - core.ui.drawWaiting("正在同步,请稍后..."); + var password = prompt("请输入存档密码:") || ""; + if (password=="") return core.ui.drawSyncSave(); + core.ui.drawWaiting("正在同步,请稍后..."); + this._syncLoad_http(id, password); +} + +control.prototype._syncLoad_http = function (id, password) { var formData = new FormData(); formData.append('type', 'load'); formData.append('name', core.firstData.name); @@ -1648,141 +1624,67 @@ control.prototype.syncLoad = function () { core.http("POST", "/games/sync.php", formData, function (data) { var response = JSON.parse(data); - switch (response.code) { - case 0: - // 成功 - var data=JSON.parse(response.msg); - if (data instanceof Array) { - core.status.event.selection=1; - core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () { - for (var i=1;i<=5*(main.savePages||30);i++) { - if (i<=data.length) { - // core.setLocalStorage("save"+i, data[i-1]); - core.setLocalForage("save"+i, data[i-1]); - } - else { - if (core.saves.ids[i]) - core.removeLocalForage("save"+i); - } - } - core.ui.closePanel(); - core.drawText("同步成功!\n你的本地所有存档均已被覆盖。"); - }, function () { - core.status.event.selection=0; - core.ui.drawSyncSave(); - }) - } - else { - // 只覆盖单存档 - core.setLocalForage("save"+core.saves.saveIndex, data, function() { - core.drawText("同步成功!\n单存档已覆盖至存档"+core.saves.saveIndex); - }); - } - break; - case -1: - core.drawText("出错啦!\n存档编号"+id+"不存在!"); - break; - case -2: - core.drawText("出错啦!\n存档密码错误!"); - break; - default: - core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg); - break; + if (response.code == 0) { + core.control._syncLoad_write(JSON.parse(response.msg)); + } + else { + core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+response.msg); } }, function (e) { core.drawText("出错啦!\n无法从服务器同步存档。\n错误原因:"+e); }); } +control.prototype._syncLoad_write = function (data) { + if (data instanceof Array) { + core.status.event.selection=1; + core.ui.drawConfirmBox("所有本地存档都将被覆盖,确认?", function () { + for (var i=1;i<=5*(main.savePages||30);i++) { + if (i<=data.length) + core.setLocalForage("save"+i, data[i-1]); + else if (core.saves.ids[i]) + core.removeLocalForage("save"+i); + } + core.ui.closePanel(); + core.drawText("同步成功!\n你的本地所有存档均已被覆盖。"); + }, function () { + core.status.event.selection=0; + core.ui.drawSyncSave(); + }); + } + else { + // 只覆盖单存档 + core.setLocalForage("save"+core.saves.saveIndex, data, function() { + core.drawText("同步成功!\n单存档已覆盖至存档"+core.saves.saveIndex); + }); + } +} + ////// 存档到本地 ////// control.prototype.saveData = function() { - var hero = core.clone(core.status.hero); - var hashCode = core.utils.hashCode(hero); - - var data = { - 'floorId': core.status.floorId, - 'hero': hero, - 'hard': core.status.hard, - 'maps': core.maps.saveMap(), - 'route': core.encodeRoute(core.status.route), - 'values': core.clone(core.values), - 'shops': {}, - 'version': core.firstData.version, - "time": new Date().getTime(), - "hashCode": hashCode - }; - // set shop times - for (var shop in core.status.shops) { - data.shops[shop]={ - 'times': core.status.shops[shop].times || 0, - 'visited': core.status.shops[shop].visited || false - } - } - core.events.beforeSaveData(data); - - return data; + return this.controldata.saveData(); } ////// 从本地读档 ////// control.prototype.loadData = function (data, callback) { - - core.resetGame(data.hero, data.hard, data.floorId, core.maps.loadMap(data.maps), data.values); - core.status.route = core.decodeRoute(data.route); - - // load shop times - for (var shop in core.status.shops) { - if (core.isset(data.shops[shop])) { - core.status.shops[shop].times = data.shops[shop].times; - core.status.shops[shop].visited = data.shops[shop].visited; - } - } - - core.status.textAttribute = core.getFlag('textAttribute', core.status.textAttribute); - var toAttribute = core.getFlag('globalAttribute', core.status.globalAttribute); - // if (core.utils.hashCode(toAttribute) != core.utils.hashCode(core.status.globalAttribute)) { - if (!core.same(toAttribute, core.status.globalAttribute)) { - core.status.globalAttribute = toAttribute; - core.control.updateGlobalAttribute(Object.keys(toAttribute)); - } - - // 重置音量 - core.events.setVolume(core.getFlag("__volume__", 1), 0); - - // load icons - var icon = core.getFlag("heroIcon", "hero.png"); - if (core.isset(core.material.images.images[icon])) { - core.material.images.hero.src = core.material.images.images[icon].src; - core.material.icons.hero.height = core.material.images.images[icon].height/4; - } - - core.events.afterLoadData(data); - - core.changeFloor(data.floorId, null, data.hero.loc, 0, function() { - if (core.isset(callback)) callback(); - }, true); + return this.controldata.loadData(data, callback); } control.prototype.getSaves = function (index, callback) { - if (core.isset(index)) { + if (index != null) { core.getLocalForage("save"+index, null, function(data) { - if (core.isset(callback)) callback(data); + if (callback) callback(data); }, function(err) { main.log(err); - if (core.isset(callback)) - callback(null); + if (callback) callback(null); }) return; } - var ids = Object.keys(core.saves.ids).filter(function(x){return x!=0;}) - .sort(function(a,b) {return a-b;}), number = ids.length; - - // 不计0 - var saves = []; - + .sort(function(a,b) {return a-b;}), number = ids.length, saves = []; var load = function (index, callback) { if (index > number) { - if (core.isset(callback)) callback(saves); + if (callback) callback(saves); return; } core.getLocalForage("save"+ids[index], null, function (data) { @@ -1799,33 +1701,32 @@ control.prototype.getSaves = function (index, callback) { ////// 获得所有存在存档的存档位 ////// control.prototype.getSaveIndexes = function (callback) { var indexes = {}; - - var getIndex = function (name) { - var e = new RegExp('^'+core.firstData.name+"_(save\\d+|autoSave)$").exec(name); - if (e!=null) { - if (e[1]=='autoSave') indexes[0]=true; - else indexes[parseInt(e[1].substring(4))] = true; - } - }; - - if (!core.platform.useLocalForage) { + if (core.platform.useLocalForage) { + localforage.iterate(function (value, key, n) { + core.control._getSaveIndexes_getIndex(indexes, key); + }, function () { + callback(indexes); + }); + } + else { Object.keys(localStorage).forEach(function (key) { - getIndex(key); + core.control._getSaveIndexes_getIndex(indexes, key); }); callback(indexes); } - else { - localforage.iterate(function (value, key, n) { - getIndex(key) - }, function () { - callback(indexes); - }) +} + +control.prototype._getSaveIndexes_getIndex = function (indexes, name) { + var e = new RegExp('^'+core.firstData.name+"_(save\\d+|autoSave)$").exec(name); + if (e) { + if (e[1]=='autoSave') indexes[0]=true; + else indexes[parseInt(e[1].substring(4))] = true; } } ////// 判断某个存档位是否存在存档 ////// control.prototype.hasSave = function (index) { - return core.saves.ids[index]||false; + return core.saves.ids[index] || false; } // ------ 属性,状态,位置,buff,变量,锁定控制等 ------ // diff --git a/libs/events.js b/libs/events.js index 215f0c97..bfe41532 100644 --- a/libs/events.js +++ b/libs/events.js @@ -2157,16 +2157,6 @@ events.prototype.afterUseBomb = function () { return this.eventdata.afterUseBomb(); } -////// 即将存档前可以执行的操作 ////// -events.prototype.beforeSaveData = function (data) { - return this.eventdata.beforeSaveData(data); -} - -////// 读档事件后,载入事件前,可以执行的操作 ////// -events.prototype.afterLoadData = function (data) { - return this.eventdata.afterLoadData(data); -} - ////// 上传当前数据 ////// events.prototype.uploadCurrent = function (username) { var formData = new FormData(); diff --git a/project/functions.js b/project/functions.js index 14f07ff2..505ba563 100644 --- a/project/functions.js +++ b/project/functions.js @@ -63,7 +63,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 设置已经到过的楼层 core.setFlag("__visited__", {}); - core.events.afterLoadData(); + core.updateEnemys(); }, "win": function(reason, norank) { // 游戏获胜事件 @@ -401,16 +401,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } */ -}, - "beforeSaveData": function(data) { - // 即将存档前可以执行的操作 - -}, - "afterLoadData": function(data) { - // 读档事件后,载入事件前,可以执行的操作 - // 怪物数据的动态修改迁移到了“脚本编辑 - updateEnemys”中,详见文档说明 - - core.enemys.updateEnemys(); }, "canUseQuickShop": function(shopId) { // 当前能否使用某个快捷商店 @@ -719,6 +709,8 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = }, "updateEnemys": function () { // 更新怪物数据,可以在这里对怪物属性和数据进行动态更新,详见文档——事件——怪物数据的动态修改 + // 此函数执行时间:重新开始游戏、读档后、通过事件调用“更新怪物数据”时 + // 比如下面这个例子,如果flag:xxx为真,则将绿头怪的攻击设为100,金币设为20 /* if (core.hasFlag('xxx')) { @@ -726,7 +718,6 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.material.enemys.greenSlime.money = 20; } */ - // 别忘了在事件中调用“更新怪物数据”事件! } }, "actions": { @@ -895,6 +886,78 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = } }, "control": { + "saveData": function () { + // 存档操作,此函数应该返回“具体要存档的内容” + + // 勇士和hash值(防改存档文件来作弊) + var hero = core.clone(core.status.hero), + hashCode = core.utils.hashCode(hero); + // 差异化存储values + var values = {}; + for (var key in core.values) { + if (!core.same(core.values[key], core.data.values[key])) + values[key] = core.clone(core.values[key]); + } + + // 要存档的内容 + var data = { + 'floorId': core.status.floorId, + 'hero': hero, + 'hard': core.status.hard, + 'maps': core.maps.saveMap(), + 'route': core.encodeRoute(core.status.route), + 'values': values, + 'shops': {}, + 'version': core.firstData.version, + "time": new Date().getTime(), + "hashCode": hashCode + }; + // 设置商店次数 + for (var shopId in core.status.shops) { + data.shops[shopId] = { + 'times': core.status.shops[shopId].times || 0, + 'visited': core.status.shops[shopId].visited || false + }; + } + + return data; +}, + "loadData": function (data, callback) { + // 读档操作;从存储中读取了内容后的行为 + + // 重置游戏和路线 + core.resetGame(data.hero, data.hard, data.floorId, core.maps.loadMap(data.maps), data.values); + core.status.route = core.decodeRoute(data.route); + // 加载商店信息 + for (var shopId in core.status.shops) { + if (data.shops[shopId]) { + core.status.shops[shopId].times = data.shops[shopId].times; + core.status.shops[shopId].visited = data.shops[shopId].visited; + } + } + // 文字属性,全局属性 + core.status.textAttribute = core.getFlag('textAttribute', core.status.textAttribute); + var toAttribute = core.getFlag('globalAttribute', core.status.globalAttribute); + if (!core.same(toAttribute, core.status.globalAttribute)) { + core.status.globalAttribute = toAttribute; + core.control.updateGlobalAttribute(Object.keys(toAttribute)); + } + // 重置音量 + core.events.setVolume(core.getFlag("__volume__", 1), 0); + // 加载勇士图标 + var icon = core.getFlag("heroIcon", "hero.png"); + if (core.material.images.images[icon]) { + core.material.images.hero.src = core.material.images.images[icon].src; + core.material.icons.hero.height = core.material.images.images[icon].height / 4; + } + // 刷新怪物数据 + core.updateEnemys(); + + // TODO:增加自己的一些读档处理 + + // 切换到对应的楼层 + core.changeFloor(data.floorId, null, data.hero.loc, 0, callback, true); +}, "flyTo": function (toId, callback) { // 楼层传送器的使用,从当前楼层飞往toId // 如果不能飞行请返回false From aa3229620dc8555b9bea4de681e84f589ba5cbd8 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 02:08:02 +0800 Subject: [PATCH 038/153] Weather, bgm, statusBar --- libs/control.js | 315 +++++++++++++++++++------------------------ libs/core.js | 1 - libs/events.js | 10 +- project/functions.js | 10 +- 4 files changed, 149 insertions(+), 187 deletions(-) diff --git a/libs/control.js b/libs/control.js index 8563df15..fa1c0c2d 100644 --- a/libs/control.js +++ b/libs/control.js @@ -195,7 +195,7 @@ control.prototype._animationFrame_heroMoving = function (timestamp) { control.prototype._animationFrame_weather = function (timestamp) { var weather = core.animateFrame.weather; - if (timestamp - weather.time <= 30 || weather.level <= 0 || !core.dymCanvas.weather) return; + if (timestamp - weather.time <= 30 || !core.dymCanvas.weather) return; core.control["_animationFrame_weather_"+weather.type](); weather.time = timestamp; } @@ -1861,83 +1861,71 @@ control.prototype.debug = function() { ////// 更改天气效果 ////// control.prototype.setWeather = function (type, level) { - // 非雨雪 - if (type!='rain' && type!='snow' && type!='fog') { - // core.clearMap('weather'); + if (type == null) { core.deleteCanvas('weather') core.animateFrame.weather.type = null; - core.animateFrame.weather.level = 0; core.animateFrame.weather.nodes = []; return; } - - level = parseInt(level); - // 当前天气:则忽略 - if (type==core.animateFrame.weather.type && !core.isset(level)) { - return; - } - - if (!core.isset(level)) level=5; - if (level<1) level=1; if (level>10) level=10; + if (type==core.animateFrame.weather.type && level == null) return; + level = core.clamp(parseInt(level) || 5, 1, 10); level *= parseInt(20*core.bigmap.width*core.bigmap.height/(core.__SIZE__*core.__SIZE__)); - // 计算当前的宽高 + // 计算当前的宽高 core.createCanvas('weather', 0, 0, core.__PIXELS__, core.__PIXELS__, 80); core.animateFrame.weather.type = type; - core.animateFrame.weather.level = level; core.animateFrame.weather.nodes = []; + this._setWeather_createNodes(type, level); +} - if (type == 'rain') { - for (var a=0;a 1) core.screenFlash(color, time * 3, times - 1, callback); else { - if (core.isset(callback)) callback(); + if (callback) callback(); } }); }); @@ -1992,9 +1981,7 @@ control.prototype.screenFlash = function (color, time, times, callback) { ////// 播放背景音乐 ////// control.prototype.playBgm = function (bgm, startTime) { - if (main.mode!='play')return; - // 音频不存在 - if (!core.isset(core.material.bgms[bgm])) return; + if (main.mode!='play' || !core.material.bgms[bgm]) return; // 如果不允许播放 if (!core.musicStatus.bgmStatus) { try { @@ -2010,22 +1997,7 @@ control.prototype.playBgm = function (bgm, startTime) { this.setMusicBtn(); try { - // 缓存BGM - core.loader.loadBgm(bgm); - // 如果当前正在播放,且和本BGM相同,直接忽略 - if (core.musicStatus.playingBgm == bgm && !core.material.bgms[core.musicStatus.playingBgm].paused) { - return; - } - // 如果正在播放中,暂停 - if (core.isset(core.musicStatus.playingBgm)) { - core.material.bgms[core.musicStatus.playingBgm].pause(); - } - // 播放当前BGM - core.material.bgms[bgm].volume = core.musicStatus.volume; - core.material.bgms[bgm].currentTime = startTime || 0; - core.material.bgms[bgm].play(); - core.musicStatus.playingBgm = bgm; - core.musicStatus.lastBgm = bgm; + this._playBgm_play(bgm, startTime); } catch (e) { console.log("无法播放BGM "+bgm); @@ -2034,11 +2006,30 @@ control.prototype.playBgm = function (bgm, startTime) { } } +control.prototype._playBgm_play = function (bgm, startTime) { + // 缓存BGM + core.loader.loadBgm(bgm); + // 如果当前正在播放,且和本BGM相同,直接忽略 + if (core.musicStatus.playingBgm == bgm && !core.material.bgms[core.musicStatus.playingBgm].paused) { + return; + } + // 如果正在播放中,暂停 + if (core.musicStatus.playingBgm) { + core.material.bgms[core.musicStatus.playingBgm].pause(); + } + // 播放当前BGM + core.material.bgms[bgm].volume = core.musicStatus.volume; + core.material.bgms[bgm].currentTime = startTime || 0; + core.material.bgms[bgm].play(); + core.musicStatus.playingBgm = bgm; + core.musicStatus.lastBgm = bgm; +} + ////// 暂停背景音乐的播放 ////// control.prototype.pauseBgm = function () { - // 直接暂停播放 + if (main.mode!='play')return; try { - if (core.isset(core.musicStatus.playingBgm)) { + if (core.musicStatus.playingBgm) { core.material.bgms[core.musicStatus.playingBgm].pause(); core.musicStatus.playingBgm = null; } @@ -2053,8 +2044,6 @@ control.prototype.pauseBgm = function () { ////// 恢复背景音乐的播放 ////// control.prototype.resumeBgm = function () { if (main.mode!='play')return; - - // 恢复BGM try { core.playBgm(core.musicStatus.playingBgm || core.musicStatus.lastBgm); } @@ -2074,25 +2063,19 @@ control.prototype.setMusicBtn = function () { ////// 更改背景音乐的播放 ////// control.prototype.triggerBgm = function () { - if (main.mode!='play')return; + if (main.mode!='play') return; core.musicStatus.bgmStatus = !core.musicStatus.bgmStatus; if (core.musicStatus.bgmStatus) this.resumeBgm(); - else { + else this.pauseBgm(); - } core.setLocalStorage('bgmStatus', core.musicStatus.bgmStatus); } ////// 播放音频 ////// control.prototype.playSound = function (sound) { - if (main.mode!='play')return; - // 如果不允许播放 - if (!core.musicStatus.soundStatus) return; - // 音频不存在 - if (!core.isset(core.material.sounds[sound])) return; - + if (main.mode!='play' || !core.musicStatus.soundStatus || !core.material.sounds[sound]) return; try { if (core.musicStatus.audioContext != null) { var source = core.musicStatus.audioContext.createBufferSource(); @@ -2102,18 +2085,8 @@ control.prototype.playSound = function (sound) { source.onended = function () { delete core.musicStatus.playingSounds[id]; } - try { - source.start(0); - } - catch (e) { - try { - source.noteOn(0); - } - catch (ee) { - main.log(ee); - return; - } - } + if (source.start) source.start(0); + else if (source.noteOn) source.noteOn(0); core.musicStatus.playingSounds[id] = source; } else { @@ -2121,75 +2094,67 @@ control.prototype.playSound = function (sound) { core.material.sounds[sound].play(); } } - catch (eee) { + catch (e) { console.log("无法播放SE "+sound); - main.log(eee); + main.log(e); } } +////// 停止所有音频 ////// control.prototype.stopSound = function () { for (var i in core.musicStatus.playingSounds) { var source = core.musicStatus.playingSounds[i]; try { - source.stop(); + if (source[i].stop) source[i].stop(); + else if (source[i].noteOff) source[i].noteOff(); } catch (e) { - try { - source.noteOff(0); - } - catch (e) { - main.log(e); - } + main.log(e); } } + core.musicStatus.playingSounds = {}; } +////// 检查bgm状态 ////// control.prototype.checkBgm = function() { core.playBgm(core.musicStatus.playingBgm || main.startBgm); } +// ------ 状态栏,工具栏等相关 ------ // + ////// 清空状态栏 ////// control.prototype.clearStatusBar = function() { Object.keys(core.statusBar).forEach(function (e) { core.statusBar[e].innerHTML = ""; }) core.statusBar.image.book.style.opacity = 0.3; - if (!core.flags.equipboxButton) { + if (!core.flags.equipboxButton) core.statusBar.image.fly.style.opacity = 0.3; - } } ////// 更新状态栏 ////// control.prototype.updateStatusBar = function () { - if (core.isPlaying()) this.controldata.updateStatusBar(); + this._updateStatusBar_setToolboxImage(); +} - // 回放 +control.prototype._updateStatusBar_setToolboxImage = function () { if (core.isReplaying()) { core.statusBar.image.book.src = core.status.replay.pausing ? core.statusBar.icons.play.src : core.statusBar.icons.pause.src; core.statusBar.image.book.style.opacity = 1; - core.statusBar.image.fly.src = core.statusBar.icons.stop.src; core.statusBar.image.fly.style.opacity = 1; - core.statusBar.image.toolbox.src = core.statusBar.icons.rewind.src; - core.statusBar.image.keyboard.src = core.statusBar.icons.book.src; - core.statusBar.image.shop.src = core.statusBar.icons.floor.src; - core.statusBar.image.save.src = core.statusBar.icons.speedDown.src; - core.statusBar.image.load.src = core.statusBar.icons.speedUp.src; - core.statusBar.image.settings.src = core.statusBar.icons.save.src; - } else { core.statusBar.image.book.src = core.statusBar.icons.book.src; core.statusBar.image.book.style.opacity = core.hasItem('book') ? 1 : 0.3; - if (!core.flags.equipboxButton) { core.statusBar.image.fly.src = core.statusBar.icons.fly.src; core.statusBar.image.fly.style.opacity = core.hasItem('fly') ? 1 : 0.3; @@ -2198,52 +2163,46 @@ control.prototype.updateStatusBar = function () { core.statusBar.image.fly.src = core.statusBar.icons.equipbox.src; core.statusBar.image.fly.style.opacity = 1; } - core.statusBar.image.toolbox.src = core.statusBar.icons.toolbox.src; - core.statusBar.image.keyboard.src = core.statusBar.icons.keyboard.src; - core.statusBar.image.shop.src = core.statusBar.icons.shop.src; - core.statusBar.image.save.src = core.statusBar.icons.save.src; - core.statusBar.image.load.src = core.statusBar.icons.load.src; - core.statusBar.image.settings.src = core.statusBar.icons.settings.src; } } -control.prototype.triggerStatusBar = function (name, showToolbox) { - if (name!='hide') name='show'; - - // 如果是隐藏 -> 显示工具栏,则先显示 - if (name == 'hide' && !core.domStyle.showStatusBar) { - this.triggerStatusBar("show"); - this.triggerStatusBar("hide", showToolbox); - return; - } - +control.prototype.showStatusBar = function () { + if (core.domStyle.showStatusBar) return; var statusItems = core.dom.status; - var toolItems = core.dom.tools; - core.domStyle.showStatusBar = name == 'show'; - core.setFlag('hideStatusBar', core.domStyle.showStatusBar?null:true); - core.setFlag('showToolbox', showToolbox?true:null); - if (!core.domStyle.showStatusBar) { - for (var i = 0; i < statusItems.length; ++i) - statusItems[i].style.opacity = 0; - if (!core.domStyle.isVertical || !showToolbox) { - for (var i = 0; i < toolItems.length; ++i) - toolItems[i].style.display = 'none'; - } - } - else { - for (var i = 0; i < statusItems.length; ++i) - statusItems[i].style.opacity = 1; - this.setToolbarButton(false); - core.dom.tools.hard.style.display = 'block'; + core.domStyle.showStatusBar = true; + core.removeFlag('hideStatusBar'); + // 显示 + for (var i = 0; i < statusItems.length; ++i) + statusItems[i].style.opacity = 1; + this.setToolbarButton(false); + core.dom.tools.hard.style.display = 'block'; +} + +control.prototype.hideStatusBar = function (showToolbox) { + // 如果原本就是隐藏的,则先显示 + if (!core.domStyle.showStatusBar) + this.showStatusBar(); + + var statusItems = core.dom.status, toolItems = core.dom.tools; + core.domStyle.showStatusBar = false; + core.setFlag('hideStatusBar', true); + core.setFlag('showToolbox', showToolbox || null); + // 隐藏 + for (var i = 0; i < statusItems.length; ++i) + statusItems[i].style.opacity = 0; + if (!core.domStyle.isVertical || !showToolbox) { + for (var i = 0; i < toolItems.length; ++i) + toolItems[i].style.display = 'none'; } } +////// 更新状态栏的勇士图标 ////// control.prototype.updateHeroIcon = function (name) { name = name || "hero.png"; if (core.statusBar.icons.name == name) return; @@ -2261,11 +2220,10 @@ control.prototype.updateHeroIcon = function (name) { context.drawImage(image, 0, 0, 32, height, left, 0, width, 32); core.statusBar.image.name.src = canvas.toDataURL("image/png"); - } control.prototype.updateGlobalAttribute = function (name) { - if (!core.isset(name)) return; + if (name == null) name = Object.keys(core.status.globalAttribute); if (name instanceof Array) { name.forEach(function (t) { core.control.updateGlobalAttribute(t); @@ -2273,7 +2231,7 @@ control.prototype.updateGlobalAttribute = function (name) { return; } var attribute = core.status.globalAttribute || core.initStatus.globalAttribute; - if (!core.isset(attribute)) return; + if (attribute == null) return; switch (name) { case 'statusLeftBackground': if (!core.domStyle.isVertical) { @@ -2334,11 +2292,10 @@ control.prototype.setToolbarButton = function (useButton) { else core.dom.tools.hard.style.display = 'block'; } - if (!core.isset(useButton)) useButton = core.domStyle.toolbarBtn; - if (!core.domStyle.isVertical) useButton = false; - if (!core.platform.extendKeyboard) useButton = false; - + if (useButton == null) useButton = core.domStyle.toolbarBtn; + if (!core.domStyle.isVertical || !core.platform.extendKeyboard) useButton = false; core.domStyle.toolbarBtn = useButton; + if (useButton) { ["book","fly","toolbox","keyboard","shop","save","load","settings"].forEach(function (t) { core.statusBar.image[t].style.display = 'none'; @@ -2360,14 +2317,16 @@ control.prototype.setToolbarButton = function (useButton) { } } -control.prototype.needDraw = function(id) { - if (!core.isset(id)) { +////// ------ resize处理 ------ // + +control.prototype._shouldDisplayStatus = function(id) { + if (id == null) { var toDraw = [], status = core.dom.status; for (var i = 0; i Date: Tue, 19 Mar 2019 19:12:55 +0800 Subject: [PATCH 039/153] resize --- libs/control.js | 596 +++++++++++++++++------------------------------- libs/core.js | 2 - main.js | 4 +- styles.css | 12 +- 4 files changed, 217 insertions(+), 397 deletions(-) diff --git a/libs/control.js b/libs/control.js index fa1c0c2d..e0ab9750 100644 --- a/libs/control.js +++ b/libs/control.js @@ -14,6 +14,7 @@ control.prototype._init = function () { this.controldata = functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.control; this.renderFrameFuncs = []; this.replayActions = []; + this.resizes = []; // --- 注册系统的animationFrame this.registerAnimationFrame("totalTime", false, this._animationFrame_totalTime); this.registerAnimationFrame("autoSave", true, this._animationFrame_autoSave); @@ -35,6 +36,12 @@ control.prototype._init = function () { this.registerReplayAction("getNext", this._replayAction_getNext); this.registerReplayAction("moveDirectly", this._replayAction_moveDirectly); this.registerReplayAction("key", this._replayAction_key); + // --- 注册系统的resize + this.registerResize("gameGroup", this._resize_gameGroup); + this.registerResize("canvas", this._resize_canvas); + this.registerResize("statusBar", this._resize_statusBar); + this.registerResize("status", this._resize_status); + this.registerResize("tools", this._resize_tools); } // ------ requestAnimationFrame 相关 ------ // @@ -970,8 +977,6 @@ control.prototype.updateDamage = function (floorId, ctx) { refreshCheckBlock = false; } - // 更新显伤 - var mapBlocks = core.status.maps[floorId].blocks; // 没有怪物手册 if (!core.hasItem('book')) return; core.setFont(ctx, "bold 11px Arial"); @@ -2136,10 +2141,10 @@ control.prototype.clearStatusBar = function() { control.prototype.updateStatusBar = function () { if (core.isPlaying()) this.controldata.updateStatusBar(); - this._updateStatusBar_setToolboxImage(); + this._updateStatusBar_setToolboxIcon(); } -control.prototype._updateStatusBar_setToolboxImage = function () { +control.prototype._updateStatusBar_setToolboxIcon = function () { if (core.isReplaying()) { core.statusBar.image.book.src = core.status.replay.pausing ? core.statusBar.icons.play.src : core.statusBar.icons.pause.src; core.statusBar.image.book.style.opacity = 1; @@ -2349,397 +2354,125 @@ control.prototype._shouldDisplayStatus = function(id) { } } -////// 屏幕分辨率改变后重新自适应 ////// -control.prototype.resize = function(clientWidth, clientHeight) { - if (main.mode=='editor')return; - - clientWidth = clientWidth || main.dom.body.clientWidth; - clientHeight = clientHeight || main.dom.body.clientHeight; - - // 默认画布大小 - var DEFAULT_CANVAS_WIDTH = 422; - // 默认边栏宽度 - var DEFAULT_BAR_WIDTH = 132; - - var BASE_LINEHEIGHT = 32; - var SPACE = 3; - var DEFAULT_FONT_SIZE = 16; - //适配宽度 422 - var ADAPT_WIDTH = DEFAULT_CANVAS_WIDTH; - var CHANGE_WIDTH = DEFAULT_CANVAS_WIDTH+DEFAULT_BAR_WIDTH; - //判断横竖屏 - var width = clientWidth; - var isHorizontal = false; - if(clientWidth > clientHeight && clientHeight < ADAPT_WIDTH){ - isHorizontal = true; - width = clientHeight; - } - // 各元素大小的变量声明 - var gameGroupWidth, gameGroupHeight, borderRight, - canvasWidth, canvasTop, // canvasLeft, - statusBarWidth, statusBarHeight, statusBarBorder, - statusWidth, statusHeight, statusMaxWidth,statusLabelsLH, - toolBarWidth, toolBarHeight, toolBarTop, toolBarBorder, - toolsWidth, toolsHeight,toolsMargin,toolsPMaxwidth, - fontSize, toolbarFontSize, margin, statusBackground, toolsBackground, - statusCanvasWidth, statusCanvasHeight, musicBtnBottom, musicBtnRight; - - var toDraw = this._shouldDisplayStatus(); - var count = toDraw.length; - var statusCanvas = core.flags.statusCanvas, statusCanvasRows = core.flags.statusCanvasRowsOnMobile || 3; - - if (!statusCanvas && count>12) alert("当前状态栏数目("+count+")大于12,请调整到不超过12以避免手机端出现显示问题。"); - var col = Math.ceil(count / 3); - if (statusCanvas) col = statusCanvasRows; - - var statusLineHeight = BASE_LINEHEIGHT * 9 / count; - var statusLineFontSize = DEFAULT_FONT_SIZE; - if (count>9) statusLineFontSize = statusLineFontSize * 9 / count; - - var borderColor = (core.status.globalAttribute||core.initStatus.globalAttribute).borderColor; - - statusBarBorder = '3px '+borderColor+' solid'; - toolBarBorder = '3px '+borderColor+' solid'; - var zoom = (ADAPT_WIDTH - width) / 4.22; - var aScale = 1 - zoom / 100; - - core.domStyle.toolbarBtn = false; - - // 移动端 - if (width < CHANGE_WIDTH) { - if(width < ADAPT_WIDTH){ - - core.domStyle.scale = aScale; - canvasWidth = width; - }else{ - canvasWidth = DEFAULT_CANVAS_WIDTH; - core.domStyle.scale = 1; - } - - var scale = core.domStyle.scale - var tempWidth = DEFAULT_CANVAS_WIDTH * scale; - if(!isHorizontal){ //竖屏 - core.domStyle.screenMode = 'vertical'; - core.domStyle.isVertical = true; - - var tempTopBarH = scale * (BASE_LINEHEIGHT * col + SPACE * 2) + 6; - var tempBotBarH = scale * (BASE_LINEHEIGHT + SPACE * 4) + 6; - - gameGroupHeight = tempWidth + tempTopBarH + tempBotBarH; - - gameGroupWidth = tempWidth - statusCanvasWidth = canvasWidth; - statusCanvasHeight = tempTopBarH; - canvasTop = tempTopBarH; - // canvasLeft = 0; - toolBarWidth = statusBarWidth = canvasWidth; - statusBarHeight = tempTopBarH; - statusBarBorder = '3px '+borderColor+' solid'; - - statusHeight = scale*BASE_LINEHEIGHT * .8; - statusLabelsLH = .8 * BASE_LINEHEIGHT *scale; - statusMaxWidth = scale * DEFAULT_BAR_WIDTH * .95; - statusBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).statusTopBackground; - toolBarHeight = tempBotBarH; - - toolBarTop = statusBarHeight + canvasWidth; - toolBarBorder = '3px '+borderColor+' solid'; - toolsHeight = scale * BASE_LINEHEIGHT * 0.95; - toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH * .4; - toolsBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).toolsBackground; - borderRight = '3px '+borderColor+' solid'; - - margin = scale * SPACE * 2; - toolsMargin = scale * SPACE * 3; - fontSize = DEFAULT_FONT_SIZE * scale; - toolbarFontSize = DEFAULT_FONT_SIZE * scale; - musicBtnRight = 3; - musicBtnBottom = 3; - }else { //横屏 - core.domStyle.screenMode = 'horizontal'; - core.domStyle.isVertical = false; - gameGroupWidth = tempWidth + DEFAULT_BAR_WIDTH * scale; - gameGroupHeight = tempWidth; - canvasTop = 0; - // canvasLeft = DEFAULT_BAR_WIDTH * scale; - toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH * scale; - statusBarHeight = gameGroupHeight - SPACE; - statusBarBorder = '3px '+borderColor+' solid'; - statusCanvasWidth = toolBarWidth + SPACE; - statusCanvasHeight = statusBarHeight; - statusBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).statusLeftBackground; - - statusHeight = scale*statusLineHeight * .8; - statusLabelsLH = .8 * statusLineHeight *scale; - toolBarTop = scale*statusLineHeight * count + SPACE * 2; - toolBarHeight = canvasWidth - toolBarTop; - toolBarBorder = '3px '+borderColor+' solid'; - toolsHeight = scale * BASE_LINEHEIGHT; - toolsBackground = 'transparent'; - fontSize = statusLineFontSize * scale; - toolbarFontSize = DEFAULT_FONT_SIZE * scale; - borderRight = ''; - statusMaxWidth = scale * DEFAULT_BAR_WIDTH; - toolsPMaxwidth = scale * DEFAULT_BAR_WIDTH; - - margin = scale * SPACE * 2; - toolsMargin = 2 * SPACE * scale; - musicBtnRight = 3; - musicBtnBottom = 3; - } - - }else { //大屏设备 pc端 - core.domStyle.scale = 1; - core.domStyle.screenMode = 'bigScreen'; - core.domStyle.isVertical = false; - - gameGroupWidth = DEFAULT_CANVAS_WIDTH + DEFAULT_BAR_WIDTH; - gameGroupHeight = DEFAULT_CANVAS_WIDTH; - canvasWidth = DEFAULT_CANVAS_WIDTH; - canvasTop = 0; - // canvasLeft = DEFAULT_BAR_WIDTH; - - toolBarWidth = statusBarWidth = DEFAULT_BAR_WIDTH; - // statusBarHeight = statusLineHeight * count + SPACE * 2; //一共有9行 - statusBackground = (core.status.globalAttribute||core.initStatus.globalAttribute).statusLeftBackground; - statusBarHeight = gameGroupHeight - SPACE; - statusCanvasWidth = toolBarWidth + SPACE; - statusCanvasHeight = statusBarHeight; - - statusHeight = statusLineHeight * .8; - statusLabelsLH = .8 * statusLineHeight; - toolBarTop = statusLineHeight * count + SPACE * 2; - toolBarHeight = DEFAULT_CANVAS_WIDTH - toolBarTop; - toolsBackground = 'transparent'; - - toolsHeight = BASE_LINEHEIGHT; - borderRight = ''; - fontSize = statusLineFontSize; - toolbarFontSize = DEFAULT_FONT_SIZE; - statusMaxWidth = DEFAULT_BAR_WIDTH; - toolsPMaxwidth = DEFAULT_BAR_WIDTH * .9; - margin = SPACE * 2; - toolsMargin = 2 * SPACE; - - musicBtnRight = (clientWidth-gameGroupWidth)/2; - musicBtnBottom = (clientHeight-gameGroupHeight)/2 - 27; - } - - var unit = 'px' - core.domStyle.styles = [ - { - id: 'gameGroup', - rules:{ - width: gameGroupWidth + unit, - height: gameGroupHeight + unit, - top: (clientHeight-gameGroupHeight)/2 + unit, - left: (clientWidth-gameGroupWidth)/2 + unit, - } - }, - { - className: 'gameCanvas', - rules:{ - width: (canvasWidth - SPACE*2) + unit, - height: (canvasWidth - SPACE*2) + unit, - } - }, - { - id: 'statusCanvas', - rules: { - width: (statusCanvasWidth - SPACE*2) + unit, - height: (statusCanvasHeight - SPACE) + unit, - display: statusCanvas?'block':'none' - } - }, - { - id: 'gif', - rules: { - width: (canvasWidth - SPACE*2) + unit, - height:(canvasWidth - SPACE*2) + unit, - } - }, - { - id: 'gif2', - rules: { - width: (canvasWidth - SPACE*2) + unit, - height:(canvasWidth - SPACE*2) + unit, - } - }, - { - id: 'gameDraw', - rules: { - width: (canvasWidth - SPACE*2) + unit, - height:(canvasWidth - SPACE*2) + unit, - top: canvasTop + unit, - right: 0, - border: statusBarBorder - } - }, - { - id: 'floorMsgGroup', - rules:{ - width: (canvasWidth - SPACE*2) + unit, - height: (gameGroupHeight - SPACE*2) + unit, - top: SPACE + unit, - right: SPACE + unit, - background: (core.status.globalAttribute||core.initStatus.globalAttribute).floorChangingBackground, - color: (core.status.globalAttribute||core.initStatus.globalAttribute).floorChangingTextColor - } - }, - { - id: 'statusBar', - rules:{ - width: statusBarWidth + unit, - height: statusBarHeight + unit, - top: 0, - left: 0, - padding: SPACE + unit, - - borderTop: statusBarBorder, - borderLeft: statusBarBorder, - borderRight: borderRight, - fontSize: fontSize + unit, - background: statusBackground - } - }, - { - className: 'status', - rules:{ - width: '100%', - maxWidth: statusMaxWidth + unit, - height: statusHeight + unit, - margin: margin/2 + unit, - display: !statusCanvas?'block':'none' - } - }, - { - className: 'statusLabels', - rules:{ - marginLeft: margin + unit, - lineHeight: statusLabelsLH + unit - } - }, - { - className: 'statusTexts', - rules: { - color: (core.status.globalAttribute||core.initStatus.globalAttribute).statusBarColor - } - }, - { - id: 'toolBar', - rules:{ - width: toolBarWidth + unit, - height: toolBarHeight + unit, - top: toolBarTop +unit, - left: 0, - padding: SPACE + unit, - borderBottom: toolBarBorder, - borderLeft: toolBarBorder, - borderRight: borderRight, - fontSize: toolbarFontSize + unit, - background: toolsBackground, - } - }, - { - className: 'tools', - rules:{ - height: toolsHeight + unit, - maxWidth: toolsPMaxwidth + unit, - marginLeft: toolsMargin + unit, - marginTop: margin + unit, - } - }, - { - imgId: 'keyboard', - rules:{ - display: core.domStyle.isVertical && core.domStyle.showStatusBar - } - }, - { - id: 'hard', - rules: { - lineHeight: toolsHeight + unit, - color: (core.status.globalAttribute||core.initStatus.globalAttribute).hardLabelColor - } - }, - { - id: 'musicBtn', - rules: { - display: 'block', - right: musicBtnRight + unit, - bottom: musicBtnBottom + unit - } - } - ] - for (var i = 0; i < core.dom.status.length; ++i) { - var id = core.dom.status[i].id; - core.domStyle.styles.push({ - id: id, - rules: { - display: toDraw.indexOf(id.substring(0, id.length-3))>=0 && !statusCanvas ? "block": "none" - } - }); - } - - core.domRenderer(); - this.setToolbarButton(); - - if (core.domStyle.isVertical) { - core.dom.statusCanvas.width = 416; - core.dom.statusCanvas.height = col * BASE_LINEHEIGHT + SPACE + 6; - } - else { - core.dom.statusCanvas.width = 129; - core.dom.statusCanvas.height = 416; - } - this.setMusicBtn(); - if (core.isPlaying()) - core.updateStatusBar(); +////// 注册一个resize函数 ////// +// name为名称,可供注销使用 +// func可以是一个函数,或者是插件中的函数名;可以接受obj参数,详见resize函数。 +control.prototype.registerResize = function (name, func) { + this.unregisterResize(name); + this.resizes.push({ name: name, func: func }); } -////// 渲染DOM ////// -control.prototype.domRenderer = function(){ +////// 注销一个resize函数 ////// +control.prototype.unregisterResize = function (name) { + this.resizes = this.resizes.filter(function (b) { return b.name != name; }); +} - core.dom.statusBar.style.display = 'block'; - core.dom.toolBar.style.display = 'block'; - - var styles = core.domStyle.styles; - - for(var i=0; i= CANVAS_WIDTH + BAR_WIDTH || (clientWidth > clientHeight && clientHeight < CANVAS_WIDTH)) { + // 横屏 + core.domStyle.isVertical = false; + core.domStyle.scale = Math.min(1, clientHeight / CANVAS_WIDTH); } - // resize map - if (core.isPlaying() && core.isset(core.status) && core.isset(core.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"; - }); + else { + // 竖屏 + core.domStyle.isVertical = true; + core.domStyle.scale = Math.min(1, clientWidth / CANVAS_WIDTH); } - // 动态canvas + + var statusDisplayArr = this._shouldDisplayStatus(), count = statusDisplayArr.length; + var statusCanvas = core.flags.statusCanvas, statusCanvasRows = core.flags.statusCanvasRowsOnMobile || 3; + var col = statusCanvas ? statusCanvasRows : Math.ceil(count / 3); + if (col > 4) { + if (statusCanvas) alert("自绘状态栏的在竖屏下的行数应不超过4!"); + else alert("当前状态栏数目("+count+")大于12,请调整到不超过12以避免手机端出现显示问题。"); + } + var globalAttribute = core.status.globalAttribute || core.initStatus.globalAttribute; + + var obj = { + clientWidth: clientWidth, + clientHeight: clientHeight, + CANVAS_WIDTH: CANVAS_WIDTH, + BAR_WIDTH: BAR_WIDTH, + outerSize: CANVAS_WIDTH * core.domStyle.scale, + globalAttribute: globalAttribute, + border: '3px ' + globalAttribute.borderColor + ' solid', + statusDisplayArr: statusDisplayArr, + count: count, + col: col, + statusBarHeightInVertical: core.domStyle.isVertical ? (32 * col + 6) * core.domStyle.scale + 6 : 0, + toolbarHeightInVertical: core.domStyle.isVertical ? 44 * core.domStyle.scale + 6 : 0, + }; + + this._doResize(obj); + this.setToolbarButton(); + core.updateStatusBar(); +} + +control.prototype._resize_gameGroup = function (obj) { + var gameGroup = core.dom.gameGroup; + var totalWidth, totalHeight; + if (core.domStyle.isVertical) { + totalWidth = obj.outerSize; + totalHeight = obj.outerSize + obj.statusBarHeightInVertical + obj.toolbarHeightInVertical + } + else { + totalWidth = (obj.CANVAS_WIDTH + obj.BAR_WIDTH) * core.domStyle.scale; + totalHeight = obj.outerSize; + } + gameGroup.style.width = totalWidth + "px"; + gameGroup.style.height = totalHeight + "px"; + gameGroup.style.left = (obj.clientWidth - totalWidth) / 2 + "px"; + gameGroup.style.top = (obj.clientHeight - totalHeight) / 2 + "px"; + // floorMsgGroup + var floorMsgGroup = core.dom.floorMsgGroup; + floorMsgGroup.style.width = obj.outerSize - 6 + "px"; + floorMsgGroup.style.height = totalHeight - 6 + "px"; + floorMsgGroup.style.background = obj.globalAttribute.floorChangingBackground; + floorMsgGroup.style.color = obj.globalAttribute.floorChangingTextColor; + // musicBtn + if (core.domStyle.isVertical || core.domStyle.scale < 1) { + core.dom.musicBtn.style.right = core.dom.musicBtn.style.height = "3px"; + } + else { + core.dom.musicBtn.style.right = (obj.clientWidth - totalWidth) / 2 + "px"; + core.dom.musicBtn.style.bottom = (obj.clientHeight - totalHeight) / 2 - 27 + "px"; + } +} + +control.prototype._resize_canvas = function (obj) { + var innerSize = (obj.outerSize - 6) + "px"; + for (var i = 0; i < core.dom.gameCanvas.length; ++i) + core.dom.gameCanvas[i].style.width = core.dom.gameCanvas[i].style.height = innerSize; + core.dom.gif.style.width = core.dom.gif.style.height = innerSize; + core.dom.gif2.style.width = core.dom.gif2.style.height = innerSize; + core.dom.gameDraw.style.width = core.dom.gameDraw.style.height = innerSize; + core.dom.gameDraw.style.top = obj.statusBarHeightInVertical; + 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"; + }); + // resize dynamic canvas for (var name in core.dymCanvas) { var ctx = core.dymCanvas[name], canvas = ctx.canvas; canvas.style.width = canvas.width * core.domStyle.scale + "px"; @@ -2747,4 +2480,89 @@ control.prototype.domRenderer = function(){ canvas.style.left = parseFloat(canvas.getAttribute("_left")) * core.domStyle.scale + "px"; canvas.style.top = parseFloat(canvas.getAttribute("_top")) * core.domStyle.scale + "px"; } -} \ No newline at end of file +} + +control.prototype._resize_statusBar = function (obj) { + // statusBar + var statusBar = core.dom.statusBar; + if (core.domStyle.isVertical) { + statusBar.style.width = obj.outerSize + "px"; + statusBar.style.height = obj.statusBarHeightInVertical + "px"; + statusBar.style.background = obj.globalAttribute.statusTopBackground; + statusBar.style.fontSize = 16 * core.domStyle.scale + "px"; + } + else { + statusBar.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px"; + statusBar.style.height = obj.outerSize - 3 + "px"; + statusBar.style.background = obj.globalAttribute.statusLeftBackground; + // --- 计算文字大小 + statusBar.style.fontSize = 16 * Math.min(1, (core.__HALF_SIZE__ + 3) / obj.count) * core.domStyle.scale + "px"; + } + statusBar.style.borderTop = statusBar.style.borderLeft = obj.border; + statusBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; + // 自绘状态栏 + if (core.domStyle.isVertical) { + core.dom.statusCanvas.style.width = obj.outerSize - 6 + "px"; + core.dom.statusCanvas.width = core.__PIXELS__; + core.dom.statusCanvas.style.height = obj.statusBarHeightInVertical - 3 + "px"; + core.dom.statusCanvas.height = obj.col * 32 + 9; + } + else { + core.dom.statusCanvas.style.width = obj.BAR_WIDTH * core.domStyle.scale - 3 + "px"; + core.dom.statusCanvas.width = obj.BAR_WIDTH - 3; + core.dom.statusCanvas.style.height = obj.outerSize - 6 + "px"; + core.dom.statusCanvas.height = core.__PIXELS__; + } + core.dom.statusCanvas.style.display = core.flags.statusCanvas ? "block" : "none"; +} + +control.prototype._resize_status = function (obj) { + var statusHeight = (core.domStyle.isVertical ? 1 : obj.count / (core.__HALF_SIZE__ + 3)) * 32 * core.domStyle.scale * 0.8; + // status + for (var i = 0; i < core.dom.status.length; ++i) { + var id = core.dom.status[i].id, style = core.dom.status[i].style; + if (id.endsWith("Col")) id = id.substring(0, id.length-3); + style.display = core.flags.statusCanvas || obj.statusDisplayArr.indexOf(id) < 0 ? 'none': 'block'; + style.margin = 3 * core.domStyle.scale + "px"; + style.height = statusHeight + "px"; + style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1) + "px"; + } + // statusLabels, statusTexts + for (var i = 0; i < core.dom.statusLabels.length; ++i) { + core.dom.statusLabels[i].style.lineHeight = statusHeight + "px"; + core.dom.statusLabels[i].style.marginLeft = 6 * core.domStyle.scale + "px"; + } + for (var i = 0; i < core.dom.statusTexts.length; ++i) + core.dom.statusTexts[i].style.color = obj.globalAttribute.statusBarColor; +} + +control.prototype._resize_tools = function (obj) { + // toolBar + var toolBar = core.dom.toolBar; + if (core.domStyle.isVertical) { + toolBar.style.width = obj.outerSize + "px"; + toolBar.style.height = obj.toolbarHeightInVertical + "px"; + toolBar.style.background = obj.globalAttribute.toolsBackground; + } + else { + toolBar.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px"; + toolBar.style.top = 0.718 * obj.outerSize + "px"; + toolBar.style.height = 0.281 * obj.outerSize + "px"; + toolBar.style.background = 'transparent'; + } + toolBar.style.borderLeft = toolBar.style.borderBottom = obj.border; + toolBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; + toolBar.style.fontSize = 16 * core.domStyle.scale + "px"; + // tools + var tools = core.dom.tools; + var toolsHeight = 16 * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1); + for (var i = 0; i < tools; ++i) { + var style = core.dom.tools[i].style; + style.height = toolsHeight + "px"; + style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * 0.95 + "px" + style.marginLeft = (core.domStyle.isVertical ? 3 : 2) * 3 * core.domStyle.scale + "px"; + style.marginTop = 3 * core.domStyle.scale + "px" + } + core.dom.hard.style.lineHeight = toolsHeight + "px"; + core.dom.hard.style.color = obj.globalAttribute.hardLabelColor; +} diff --git a/libs/core.js b/libs/core.js index 2467d7b0..61cb7d6d 100644 --- a/libs/core.js +++ b/libs/core.js @@ -81,9 +81,7 @@ function core() { } // 样式 this.domStyle = { - styles: [], scale: 1.0, - screenMode: null, isVertical: false, toolbarBtn: false, showStatusBar: true, diff --git a/main.js b/main.js index b26f7136..a84e55f0 100644 --- a/main.js +++ b/main.js @@ -226,7 +226,7 @@ main.prototype.init = function (mode, callback) { coreData[t] = main[t]; }) main.core.init(coreData, callback); - main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); + main.core.resize(); }); }); }); @@ -327,7 +327,7 @@ main.prototype.listen = function () { ////// 窗口大小变化时 ////// window.onresize = function () { try { - main.core.resize(main.dom.body.clientWidth, main.dom.body.clientHeight); + main.core.resize(); }catch (e) { main.log(e); } } diff --git a/styles.css b/styles.css index da593b91..3dd84ee5 100644 --- a/styles.css +++ b/styles.css @@ -142,10 +142,8 @@ } #floorMsgGroup { - /* width: 100%; - height: 100%; */ - /* top: 0; - right: 0; */ + top: 3px; + right: 3px; position: absolute; text-align: center; display: none; @@ -181,11 +179,15 @@ background: url(project/images/ground.png) repeat; z-index: 185; display: none; + top: 0; + left: 0; + padding: 3px; } #statusBar .status{ position: relative; display: block; float: left; + width: 100%; } .status img{ vertical-align: middle; @@ -213,6 +215,8 @@ -moz-box-sizing: border-box; -webkit-box-sizing: border-box; display: none; + left: 0; + padding: 3px; } #toolBar .tools{ position: relative; From d8d8190d10114ae168daed5d4e4c7b19a555ed56 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 21:21:01 +0800 Subject: [PATCH 040/153] Fix resize --- libs/control.js | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/libs/control.js b/libs/control.js index e0ab9750..606ce574 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2130,7 +2130,8 @@ control.prototype.checkBgm = function() { ////// 清空状态栏 ////// control.prototype.clearStatusBar = function() { Object.keys(core.statusBar).forEach(function (e) { - core.statusBar[e].innerHTML = ""; + if (core.statusBar[e].innerHTML != null) + core.statusBar[e].innerHTML = " "; }) core.statusBar.image.book.style.opacity = 0.3; if (!core.flags.equipboxButton) @@ -2464,7 +2465,7 @@ control.prototype._resize_canvas = function (obj) { core.dom.gif.style.width = core.dom.gif.style.height = innerSize; core.dom.gif2.style.width = core.dom.gif2.style.height = innerSize; core.dom.gameDraw.style.width = core.dom.gameDraw.style.height = innerSize; - core.dom.gameDraw.style.top = obj.statusBarHeightInVertical; + core.dom.gameDraw.style.top = obj.statusBarHeightInVertical + "px"; core.dom.gameDraw.style.right = 0; core.dom.gameDraw.style.border = obj.border; // resize bigmap @@ -2498,6 +2499,7 @@ control.prototype._resize_statusBar = function (obj) { // --- 计算文字大小 statusBar.style.fontSize = 16 * Math.min(1, (core.__HALF_SIZE__ + 3) / obj.count) * core.domStyle.scale + "px"; } + statusBar.style.display = 'block'; statusBar.style.borderTop = statusBar.style.borderLeft = obj.border; statusBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; // 自绘状态栏 @@ -2517,7 +2519,7 @@ control.prototype._resize_statusBar = function (obj) { } control.prototype._resize_status = function (obj) { - var statusHeight = (core.domStyle.isVertical ? 1 : obj.count / (core.__HALF_SIZE__ + 3)) * 32 * core.domStyle.scale * 0.8; + var statusHeight = (core.domStyle.isVertical ? 1 : (core.__HALF_SIZE__ + 3) / obj.count) * 32 * core.domStyle.scale * 0.8; // status for (var i = 0; i < core.dom.status.length; ++i) { var id = core.dom.status[i].id, style = core.dom.status[i].style; @@ -2532,8 +2534,9 @@ control.prototype._resize_status = function (obj) { core.dom.statusLabels[i].style.lineHeight = statusHeight + "px"; core.dom.statusLabels[i].style.marginLeft = 6 * core.domStyle.scale + "px"; } - for (var i = 0; i < core.dom.statusTexts.length; ++i) + for (var i = 0; i < core.dom.statusTexts.length; ++i) { core.dom.statusTexts[i].style.color = obj.globalAttribute.statusBarColor; + } } control.prototype._resize_tools = function (obj) { @@ -2541,6 +2544,7 @@ control.prototype._resize_tools = function (obj) { var toolBar = core.dom.toolBar; if (core.domStyle.isVertical) { toolBar.style.width = obj.outerSize + "px"; + toolBar.style.top = obj.statusBarHeightInVertical + obj.outerSize + "px"; toolBar.style.height = obj.toolbarHeightInVertical + "px"; toolBar.style.background = obj.globalAttribute.toolsBackground; } @@ -2550,19 +2554,23 @@ control.prototype._resize_tools = function (obj) { toolBar.style.height = 0.281 * obj.outerSize + "px"; toolBar.style.background = 'transparent'; } + toolBar.style.display = 'block'; toolBar.style.borderLeft = toolBar.style.borderBottom = obj.border; toolBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; toolBar.style.fontSize = 16 * core.domStyle.scale + "px"; // tools - var tools = core.dom.tools; - var toolsHeight = 16 * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1); - for (var i = 0; i < tools; ++i) { + var toolsHeight = 32 * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1); + for (var i = 0; i < core.dom.tools.length; ++i) { var style = core.dom.tools[i].style; style.height = toolsHeight + "px"; style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * 0.95 + "px" style.marginLeft = (core.domStyle.isVertical ? 3 : 2) * 3 * core.domStyle.scale + "px"; - style.marginTop = 3 * core.domStyle.scale + "px" + style.marginTop = 6 * core.domStyle.scale + "px" } core.dom.hard.style.lineHeight = toolsHeight + "px"; core.dom.hard.style.color = obj.globalAttribute.hardLabelColor; + if (core.domStyle.isVertical) + core.dom.hard.style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * 0.4 + "px"; + else + core.dom.hard.style.marginTop = 0; } From 0b143eeb7602eb600e0e1c8cb9b991274791200c Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 21:55:45 +0800 Subject: [PATCH 041/153] toolbar hard resize --- libs/control.js | 24 +++++++++++++++++------- styles.css | 8 -------- 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/libs/control.js b/libs/control.js index 606ce574..c447949e 100644 --- a/libs/control.js +++ b/libs/control.js @@ -41,6 +41,7 @@ control.prototype._init = function () { this.registerResize("canvas", this._resize_canvas); this.registerResize("statusBar", this._resize_statusBar); this.registerResize("status", this._resize_status); + this.registerResize("toolBar", this._resize_toolBar); this.registerResize("tools", this._resize_tools); } @@ -2539,7 +2540,7 @@ control.prototype._resize_status = function (obj) { } } -control.prototype._resize_tools = function (obj) { +control.prototype._resize_toolBar = function (obj) { // toolBar var toolBar = core.dom.toolBar; if (core.domStyle.isVertical) { @@ -2558,19 +2559,28 @@ control.prototype._resize_tools = function (obj) { toolBar.style.borderLeft = toolBar.style.borderBottom = obj.border; toolBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; toolBar.style.fontSize = 16 * core.domStyle.scale + "px"; - // tools +} + +control.prototype._resize_tools = function (obj) { var toolsHeight = 32 * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1); + var toolsMarginLeft; + if (core.domStyle.isVertical) + toolsMarginLeft = (core.__HALF_SIZE__ - 3) * 3 * core.domStyle.scale; + else + toolsMarginLeft = (obj.BAR_WIDTH * core.domStyle.scale - 9 - toolsHeight * 3) / 4; for (var i = 0; i < core.dom.tools.length; ++i) { var style = core.dom.tools[i].style; style.height = toolsHeight + "px"; - style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * 0.95 + "px" - style.marginLeft = (core.domStyle.isVertical ? 3 : 2) * 3 * core.domStyle.scale + "px"; + style.marginLeft = toolsMarginLeft + "px"; style.marginTop = 6 * core.domStyle.scale + "px" } core.dom.hard.style.lineHeight = toolsHeight + "px"; core.dom.hard.style.color = obj.globalAttribute.hardLabelColor; - if (core.domStyle.isVertical) - core.dom.hard.style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * 0.4 + "px"; - else + if (core.domStyle.isVertical) { + core.dom.hard.style.width = obj.outerSize - (obj.toolbarHeightInVertical - 7 * core.domStyle.scale) * 8 - 3 + "px"; + } + else { + core.dom.hard.style.width = obj.BAR_WIDTH * core.domStyle.scale - 9 - 2 * toolsMarginLeft + "px"; core.dom.hard.style.marginTop = 0; + } } diff --git a/styles.css b/styles.css index 3dd84ee5..16958ed2 100644 --- a/styles.css +++ b/styles.css @@ -308,12 +308,4 @@ p#name { #data { z-index: 170; -} - -.clearfix:before, -.clearfix:after { - content: "."; - display: block; - height: 0; - visibility: hidden; } \ No newline at end of file From 833164e206656ef8a469c97836377b435bc0c7c8 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 22:10:38 +0800 Subject: [PATCH 042/153] resize --- libs/control.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/libs/control.js b/libs/control.js index c447949e..2b4ce7ca 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2421,6 +2421,7 @@ control.prototype.resize = function() { col: col, statusBarHeightInVertical: core.domStyle.isVertical ? (32 * col + 6) * core.domStyle.scale + 6 : 0, toolbarHeightInVertical: core.domStyle.isVertical ? 44 * core.domStyle.scale + 6 : 0, + is15x15: core.__SIZE__ == 15 }; this._doResize(obj); @@ -2529,6 +2530,8 @@ control.prototype._resize_status = function (obj) { style.margin = 3 * core.domStyle.scale + "px"; style.height = statusHeight + "px"; style.maxWidth = obj.BAR_WIDTH * core.domStyle.scale * (core.domStyle.isVertical ? 0.95 : 1) + "px"; + if (obj.is15x15 && !core.domStyle.isVertical) + style.marginLeft = 11 * core.domStyle.scale + "px"; } // statusLabels, statusTexts for (var i = 0; i < core.dom.statusLabels.length; ++i) { @@ -2577,10 +2580,10 @@ control.prototype._resize_tools = function (obj) { core.dom.hard.style.lineHeight = toolsHeight + "px"; core.dom.hard.style.color = obj.globalAttribute.hardLabelColor; if (core.domStyle.isVertical) { - core.dom.hard.style.width = obj.outerSize - (obj.toolbarHeightInVertical - 7 * core.domStyle.scale) * 8 - 3 + "px"; + core.dom.hard.style.width = obj.outerSize - 9 * toolsMarginLeft - 8.5 * toolsHeight - 12 + "px"; } else { core.dom.hard.style.width = obj.BAR_WIDTH * core.domStyle.scale - 9 - 2 * toolsMarginLeft + "px"; - core.dom.hard.style.marginTop = 0; + if (!obj.is15x15) core.dom.hard.style.marginTop = 0; } } From bb8182d589e9f8c6fbc8f74f643eb25ad31a8eee Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 19 Mar 2019 23:57:43 +0800 Subject: [PATCH 043/153] type:insert --- _docs/event.md | 16 +++++++++-- _server/blockly/MotaAction.g4 | 51 +++++++++++++++++++++++++++++------ libs/control.js | 4 +-- libs/events.js | 22 ++++++++++----- libs/ui.js | 2 ++ main.js | 1 + project/events.js | 34 +++++++++-------------- project/functions.js | 18 +++++-------- 8 files changed, 96 insertions(+), 52 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index bb18169f..0ff220b4 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -616,10 +616,11 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` ``` js "x,y": [ // 实际执行的事件列表 - {"type": "insert", "name": "加点事件"}, // 插入公共事件:加点事件 - {"type": "insert", "name": "毒衰咒处理"}, // 插入公共事件:毒衰咒处理 + {"type": "insert", "name": "加点事件", "args": [10] }, // 插入公共事件:加点事件,传入参数10 + {"type": "insert", "name": "毒衰咒处理", "args": [0]}, // 插入公共事件:毒衰咒处理,传入参数0 {"type": "insert", "loc": [3,6]}, // 插入[3,6]点的事件并执行 {"type": "insert", "loc": [10,10], "floorId": "MT1"}, // 插入MT1层[10,10]点的事件并执行 + {"type": "insert", "loc": [2,2], "args": [1,"flag:abc","status:atk+status:def"]}, // 传入三个参数 "上面的插入事件执行完毕后会接着继续执行后面的事件" ] ``` @@ -631,6 +632,7 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` - 否则,如果写了`"loc": [x,y]`,则会插入另一个地点的事件 - loc为另一个地点的坐标 - floorId可选,代表另一个地点所在的楼层;如果不写则默认为当前层。 + - 从V2.6开始,还可以传可选的which,可以为`afterBattle`/`afterGetItem`/`afterOpenDoor`,代表插入该点的战后/获得道具后/开门后事件。 和`type:trigger`不同的是,**`type:trigger`是立刻将当前事件结束(剩下所有内容都忽略),然后重新启动另一个地点的action事件。** @@ -638,6 +640,16 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` **这个过程中,当前事件不会被结束,当前的楼层和事件坐标不会发生改变。** 插入的事件执行完毕后,会继续执行接下来的内容。 +从V2.6开始,插入事件允许传参。如果需要传参,则需要增加一个`args`数组。 + +例如: `"args": [1,"flag:abc","status:atk+status:def"]` 传入了三个参数。 + +系统会自动把`flag:arg1`设置为第一个参数数值,`flag:arg2`设置为第二个参数数值,等等。 + +(`flag:arg0`则会被置为公共事件名称,或者插入的点的坐标) + +即可在事件中直接取用`flag:arg1`等等来获得各项参数值!。 + ### revisit:立即重启当前事件 revisit和trigger完全相同,只不过是立刻触发的还是本地点的事件 diff --git a/_server/blockly/MotaAction.g4 b/_server/blockly/MotaAction.g4 index 1b2005b3..a31b4afd 100644 --- a/_server/blockly/MotaAction.g4 +++ b/_server/blockly/MotaAction.g4 @@ -614,29 +614,55 @@ return code; */; insert_1_s - : '插入公共事件' EvalString Newline + : '插入公共事件' EvalString '参数列表' EvalString? Newline /* insert_1_s tooltip : insert: 插入公共事件并执行 helpUrl : https://h5mota.com/games/template/docs/#/event?id=insert%ef%bc%9a%e6%8f%92%e5%85%a5%e5%85%ac%e5%85%b1%e4%ba%8b%e4%bb%b6%e6%88%96%e5%8f%a6%e4%b8%80%e4%b8%aa%e5%9c%b0%e7%82%b9%e7%9a%84%e4%ba%8b%e4%bb%b6%e5%b9%b6%e6%89%a7%e8%a1%8c -default : ["加点事件"] +default : ["加点事件", ""] colour : this.eventColor -var code = '{"type": "insert", "name": "'+EvalString_0+'"},\n'; +if (EvalString_1) { + if (EvalString_1.indexOf('"')>=0) + throw new Error('请勿在此处使用双引号!尝试使用单引号吧~'); + // 检查是不是数组 + try { + if (!(JSON.parse(EvalString_1.replace(/'/g, '"')) instanceof Array)) throw new Error(); + } + catch (e) { + throw new Error('参数列表必须是个有效的数组!'); + } + EvalString_1 = ', "args": ' +EvalString_1; +} +var code = '{"type": "insert", "name": "'+EvalString_0+'"'+EvalString_1+'},\n'; return code; */; insert_2_s - : '插入事件' 'x' PosString ',' 'y' PosString '楼层' IdString? Newline + : '插入事件' 'x' PosString ',' 'y' PosString Event_List? '楼层' IdString? '参数列表' EvalString? ENewline /* insert_2_s tooltip : insert: 立即插入另一个地点的事件执行,当前事件不会中断,事件坐标不会改变 helpUrl : https://h5mota.com/games/template/docs/#/event?id=insert%ef%bc%9a%e6%8f%92%e5%85%a5%e5%85%ac%e5%85%b1%e4%ba%8b%e4%bb%b6%e6%88%96%e5%8f%a6%e4%b8%80%e4%b8%aa%e5%9c%b0%e7%82%b9%e7%9a%84%e4%ba%8b%e4%bb%b6%e5%b9%b6%e6%89%a7%e8%a1%8c -default : ["0","0",""] +default : ["0","0",null,"",""] colour : this.eventColor IdString_0 = IdString_0 && (', "floorId": "'+IdString_0+'"'); -var code = '{"type": "insert", "loc": ['+PosString_0+','+PosString_1+']'+IdString_0+'},\n'; +if (EvalString_0) { + if (EvalString_0.indexOf('"')>=0) + throw new Error('请勿在此处使用双引号!尝试使用单引号吧~'); + try { + if (!(JSON.parse(EvalString_0.replace(/'/g, '"')) instanceof Array)) throw new Error(); + } + catch (e) { + throw new Error('参数列表必须是个有效的数组!'); + } + EvalString_0 = ', "args": ' +EvalString_0; +} +if (Event_List_0 && Event_List_0 !=='null') + Event_List_0 = ', "which": "'+Event_List_0+'"'; +else Event_List_0 = ''; +var code = '{"type": "insert", "loc": ['+PosString_0+','+PosString_1+']'+Event_List_0+IdString_0+EvalString_0+'},\n'; return code; */; @@ -1852,6 +1878,10 @@ Bg_Fg_List : '背景层'|'前景层' /*Bg_Fg_List ['bg','fg']*/; +Event_List + : '事件'|'战后事件'|'道具后事件'|'开门后事件' + /*Event_List ['null','afterBattle','afterGetItem','afterOpenDoor']*/; + Floor_Meta_List : '楼层中文名'|'状态栏名称'|'能否使用楼传'|'能否打开快捷商店'|'是否不可浏览地图'|'是否不可瞬间移动'|'默认地面ID'|'楼层贴图'|'宝石血瓶效果'|'上楼点坐标'|'下楼点坐标'|'背景音乐'|'画面色调'|'天气和强度'|'是否地下层' /*Floor_Meta_List ['title','name','canFlyTo', 'canUseQuickShop', 'cannotViewMap', 'cannotMoveDirectly', 'defaultGround', 'images', 'item_ratio', 'upFloor', 'downFloor', 'bgm', 'color', 'weather', 'underGround']*/; @@ -2329,13 +2359,18 @@ ActionParser.prototype.parseAction = function() { data.loc[0],data.loc[1],this.next]); break; case "insert": // 强制插入另一个点的事件在当前事件列表执行,当前坐标和楼层不会改变 + if (data.args instanceof Array) { + try { data.args = JSON.stringify(data.args).replace(/"/g, "'"); } + catch (e) {data.args = '';} + } + else data.args = null; if (this.isset(data.name)) { this.next = MotaActionBlocks['insert_1_s'].xmlText([ - data.name, this.next]); + data.name, data.args||"", this.next]); } else { this.next = MotaActionBlocks['insert_2_s'].xmlText([ - data.loc[0],data.loc[1],data.floorId||'',this.next]); + data.loc[0],data.loc[1],data.which,data.floorId||'',data.args||"",this.next]); } break; case "playSound": diff --git a/libs/control.js b/libs/control.js index 2b4ce7ca..7bc57e08 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2141,8 +2141,8 @@ control.prototype.clearStatusBar = function() { ////// 更新状态栏 ////// control.prototype.updateStatusBar = function () { - if (core.isPlaying()) - this.controldata.updateStatusBar(); + if (!core.isPlaying()) return; + this.controldata.updateStatusBar(); this._updateStatusBar_setToolboxIcon(); } diff --git a/libs/events.js b/libs/events.js index 8f481339..6821c204 100644 --- a/libs/events.js +++ b/libs/events.js @@ -579,16 +579,13 @@ events.prototype.passNet = function (data) { if (core.hasItem('shoes')) return; // 血网 lavaNet 移动到 checkBlock 中处理 if (data.event.id == 'poisonNet') { // 毒网 - core.setFlag('debuff', 'poison'); - core.insertAction('毒衰咒处理'); + core.insertAction({"type":"insert","name":"毒衰咒处理","args":[0]}); } else if (data.event.id == 'weakNet') { // 衰网 - core.setFlag('debuff', 'weak'); - core.insertAction('毒衰咒处理'); + core.insertAction({"type":"insert","name":"毒衰咒处理","args":[1]}); } else if (data.event.id == 'curseNet') { // 咒网 - core.setFlag('debuff', 'curse'); - core.insertAction('毒衰咒处理'); + core.insertAction({"type":"insert","name":"毒衰咒处理","args":[2]}); } core.updateStatusBar(); } @@ -1166,13 +1163,24 @@ events.prototype._action_trigger = function (data, x, y, prefix) { } events.prototype._action_insert = function (data, x, y, prefix) { + // 设置参数 + if (data.args instanceof Array) { + for (var i = 0; i < data.args.length; ++i) { + try { + core.setFlag('arg'+(i+1), core.calValue(data.args[i], prefix)); + } catch (e) { main.log(e); } + } + } if (data.name) { // 公共事件 + core.setFlag('arg0', data.name); core.insertAction(this.getCommonEvent(data.name)); } else { var loc = this.__action_getLoc(data.loc, x, y, prefix); + core.setFlag('arg0', loc); var floorId = data.floorId || core.status.floorId; - var event = core.floors[floorId].events[loc[0] + "," + loc[1]]; + var which = data.which || "events"; + var event = (core.floors[floorId][which]||[])[loc[0] + "," + loc[1]]; if (event) this.insertAction(event.data || event); } core.doAction(); diff --git a/libs/ui.js b/libs/ui.js index 76ad2603..700de21c 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1483,6 +1483,7 @@ ui.prototype.drawBookDetail = function (index) { var enemy = enemys[index], enemyId = enemy.id; var hints=core.enemys.getSpecialHint(enemyId); + var damageInfo = core.enemys.getDamageInfo(enemy, null, null, null, floorId); if (hints.length==0) hints.push("该怪物无特殊属性。"); @@ -1553,6 +1554,7 @@ ui.prototype.drawBookDetail = function (index) { } hints.push(""); + hints.push("战斗回合数:"+((damageInfo||{}).turn||0)); var criticals = core.enemys.nextCriticals(enemyId, 10, null, null, floorId).map(function (v) { return core.formatBigNumber(v[0])+":"+core.formatBigNumber(v[1]); }); diff --git a/main.js b/main.js index a84e55f0..54edafc8 100644 --- a/main.js +++ b/main.js @@ -69,6 +69,7 @@ function main() { 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), 'statusCanvas': document.getElementById('statusCanvas'), + 'statusCanvasCtx': document.getElementById('statusCanvas').getContext('2d') }; this.mode = 'play'; this.loadList = [ diff --git a/project/events.js b/project/events.js index 63924e63..fef815b6 100644 --- a/project/events.js +++ b/project/events.js @@ -4,60 +4,55 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = "加点事件": [ { "type": "comment", - "text": "flag:point表示当前应该的加点数值" + "text": "通过传参,flag:arg1表示当前应该的加点数值" }, { "type": "choices", "choices": [ { - "text": "攻击+${1*flag:point}", + "text": "攻击+${1*flag:arg1}", "action": [ { "type": "setValue", "name": "status:atk", - "value": "status:atk+1*flag:point" + "value": "status:atk+1*flag:arg1" } ] }, { - "text": "防御+${2*flag:point}", + "text": "防御+${2*flag:arg1}", "action": [ { "type": "setValue", "name": "status:def", - "value": "status:def+2*flag:point" + "value": "status:def+2*flag:arg1" } ] }, { - "text": "生命+${200*flag:point}", + "text": "生命+${200*flag:arg1}", "action": [ { "type": "setValue", "name": "status:hp", - "value": "status:hp+200*flag:point" + "value": "status:hp+200*flag:arg1" } ] } ] - }, - { - "type": "setValue", - "name": "flag:point", - "value": "null" } ], "毒衰咒处理": [ { "type": "comment", - "text": "获得毒衰咒效果,flag:debuff为要获得的类型" + "text": "获得毒衰咒效果,flag:arg1为要获得的类型" }, { "type": "switch", - "condition": "flag:debuff", + "condition": "flag:arg1", "caseList": [ { - "case": "'poison'", + "case": "0", "action": [ { "type": "comment", @@ -78,7 +73,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = ] }, { - "case": "'weak'", + "case": "1", "action": [ { "type": "comment", @@ -133,7 +128,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = ] }, { - "case": "'curse'", + "case": "2", "action": [ { "type": "comment", @@ -154,11 +149,6 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = ] } ] - }, - { - "type": "setValue", - "name": "flag:debuff", - "value": "null" } ] } diff --git a/project/functions.js b/project/functions.js index d3387715..c8c7ce29 100644 --- a/project/functions.js +++ b/project/functions.js @@ -271,18 +271,15 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var special = enemy.special; // 中毒 if (core.enemys.hasSpecial(special, 12)) { - core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'poison'" }]); - core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理", "args": [0] }]); } // 衰弱 if (core.enemys.hasSpecial(special, 13)) { - core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'weak'" }]); - core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理", "args": [1] }]); } // 诅咒 if (core.enemys.hasSpecial(special, 14)) { - core.push(todo, [{ "type": "setValue", "name": "flag:debuff", "value": "'curse'" }]); - core.push(todo, [{ "type": "insert", "name": "毒衰咒处理" }]); + core.push(todo, [{ "type": "insert", "name": "毒衰咒处理", "args": [2] }]); } // 仇恨属性:减半 if (core.flags.hatredDecrease && core.enemys.hasSpecial(special, 17)) { @@ -318,8 +315,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果有加点 var point = core.material.enemys[enemyId].point; if (core.flags.enableAddPoint && point > 0) { - core.push(todo, [{ "type": "setValue", "name": "flag:point", "value": point }]); - core.push(todo, [{ "type": "insert", "name": "加点事件" }]); + core.push(todo, [{ "type": "insert", "name": "加点事件", "args": [point] }]); } // 如果该点存在事件 -- V2.5.4 以后阻击怪也可以有战后事件了 @@ -1289,7 +1285,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // 如果是非状态栏canvas化,直接返回 if (!core.flags.statusCanvas) return; var canvas = core.dom.statusCanvas, - ctx = canvas.getContext('2d'); + ctx = core.dom.statusCanvasCtx; // 清空状态栏 ctx.clearRect(0, 0, canvas.width, canvas.height); // 如果是隐藏状态栏模式,直接返回 @@ -1372,7 +1368,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = core.lockControl(); core.status.event.id = 'about'; - var left = 48, top = 36, right = 416 - 2 * left, bottom = 416 - 2 * top; + var left = 48, top = 36, right = core.__PIXELS__ - 2 * left, bottom = core.__PIXELS__ - 2 * top; core.setAlpha('ui', 0.85); core.fillRect('ui', left, top, right, bottom, '#000000'); @@ -1459,7 +1455,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var ctx = core.getContextByName(name); if (ctx == null) { if (typeof name == 'string') - ctx = core.createCanvas(name, 0, 0, 416, 416, 98); + ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 98); else return; } From d017c5e54999f1c1ec02abd5094a1750bfe27595 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 19 Mar 2019 13:19:13 -0400 Subject: [PATCH 044/153] slicing files --- _server/editor_file.js | 1 + _server/plugins.comment.js | 27 +++++++++++++++ main.js | 2 +- project/functions.js | 70 ++++---------------------------------- project/plugins.js | 62 +++++++++++++++++++++++++++++++++ 5 files changed, 98 insertions(+), 64 deletions(-) create mode 100644 _server/plugins.comment.js create mode 100644 project/plugins.js diff --git a/_server/editor_file.js b/_server/editor_file.js index ffc860ab..413a1bfa 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -8,6 +8,7 @@ editor_file = function (editor, callback) { 'data.comment': 'dataComment', 'functions.comment': 'functionsComment', 'events.comment': 'eventsComment', + 'plugins.comment': 'pluginsComment', } for (var key in commentjs) { (function (key) { diff --git a/_server/plugins.comment.js b/_server/plugins.comment.js new file mode 100644 index 00000000..d556f4d6 --- /dev/null +++ b/_server/plugins.comment.js @@ -0,0 +1,27 @@ +var plugins_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = +{ + "_type": "object", + "_data": function (key) { + var obj = { + "test": { + "_leaf": true, + "_type": "textarea", + "_range": "thiseval instanceof Array", + "_data": "插件函数执行测试, 这个函数在导入后被直接执行(因此不允许删除)" + }, + "drawLight": { + "_leaf": true, + "_type": "textarea", + "_range": "thiseval instanceof Array || thiseval==null", + "_data": "绘制灯光/漆黑层效果" + }, + } + if (obj[key]) return obj[key]; + return { + "_leaf": true, + "_type": "textarea", + "_range": "thiseval instanceof Array || thiseval==null", + "_data": "自定义插件" + } + } +} \ No newline at end of file diff --git a/main.js b/main.js index 54edafc8..f76b89f5 100644 --- a/main.js +++ b/main.js @@ -76,7 +76,7 @@ function main() { 'loader', 'control', 'utils', 'items', 'icons', 'maps', 'enemys', 'events', 'actions', 'data', 'ui', 'core' ]; this.pureData = [ - 'data', 'enemys', 'icons', 'maps', 'items', 'functions', 'events' + 'data', 'enemys', 'icons', 'maps', 'items', 'functions', 'events', 'plugins' ]; this.materials = [ 'animates', 'enemys', 'hero', 'items', 'npcs', 'terrains', 'enemy48', 'npc48' diff --git a/project/functions.js b/project/functions.js index c8c7ce29..3305d8c2 100644 --- a/project/functions.js +++ b/project/functions.js @@ -1422,78 +1422,22 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = }, "plugin": function () { - ////// 插件编写,可以在这里写自己额外需要执行的脚本 ////// + ////// 插件编写,此处会导入插件编写中的所有函数 ////// // 在这里写的代码,在所有模块加载完毕后,游戏开始前会被执行 console.log("插件编写测试"); // 可以写一些其他的被直接执行的代码 - // 在这里写所有需要自定义的函数 - // 写法必须是 this.xxx = function (args) { ... - // 如果不写this的话,函数将无法被外部所访问 - this.test = function () { - console.log("插件函数执行测试"); - }; - - - // 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...) - // 【参数说明】 - // name:必填,要绘制到的画布名;可以是一个系统画布,或者是个自定义画布;如果不存在则创建 - // color:可选,只能是一个0~1之间的数,为不透明度的值。不填则默认为0.9。 - // lights:可选,一个数组,定义了每个独立的灯光。 - // 其中每一项是三元组 [x,y,r] x和y分别为该灯光的横纵坐标,r为该灯光的半径。 - // lightDec:可选,0到1之间,光从多少百分比才开始衰减(在此范围内保持全亮),不设置默认为0。 - // 比如lightDec为0.5代表,每个灯光部分内圈50%的范围全亮,50%以后才开始快速衰减。 - // 【调用样例】 - // core.plugin.drawLight('curtain'); // 在curtain层绘制全图不透明度0.9,等价于更改画面色调为[0,0,0,0.9]。 - // core.plugin.drawLight('ui', 0.95, [[25,11,46]]); // 在ui层绘制全图不透明度0.95,其中在(25,11)点存在一个半径为46的灯光效果。 - // core.plugin.drawLight('test', 0.2, [[25,11,46,0.1]]); // 创建一个test图层,不透明度0.2,其中在(25,11)点存在一个半径为46的灯光效果,灯光中心不透明度0.1。 - // core.plugin.drawLight('test2', 0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 创建test2图层,且存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 - // core.plugin.drawLight('xxx', 0.3, [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,且40%后才开始衰减。 - this.drawLight = function (name, color, lights, lightDec) { - // 清空色调层;也可以修改成其它层比如animate/weather层,或者用自己创建的canvas - var ctx = core.getContextByName(name); - if (ctx == null) { - if (typeof name == 'string') - ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 98); - else return; - } - - ctx.mozImageSmoothingEnabled = false; - ctx.webkitImageSmoothingEnabled = false; - ctx.msImageSmoothingEnabled = false; - ctx.imageSmoothingEnabled = false; - - core.clearMap(name); - // 绘制色调层,默认不透明度 - if (color == null) color = 0.9; - ctx.fillStyle = "rgba(0,0,0,"+color+")"; - ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); - - lightDec = core.clamp(lightDec, 0, 1); - - // 绘制每个灯光效果 - ctx.globalCompositeOperation = 'destination-out'; - lights.forEach(function (light) { - // 坐标,半径,中心不透明度 - var x = light[0], y = light[1], r = light[2]; - // 计算衰减距离 - var decDistance = parseInt(r * lightDec); - // 正方形区域的直径和左上角坐标 - var grd=ctx.createRadialGradient(x,y,decDistance,x,y,r); - grd.addColorStop(0, "rgba(0,0,0,1)"); - grd.addColorStop(1, "rgba(0,0,0,0)"); - ctx.beginPath(); - ctx.fillStyle=grd; - ctx.arc(x,y,r,0,2*Math.PI); - ctx.fill(); - }); - ctx.globalCompositeOperation = 'source-over'; + var pluginsData=plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 + for(var functionName in pluginsData){ + this[functionName]=pluginsData[functionName] } - // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); + // 可以在此处直接执行插件编写中的函数 + core.plugin.test(); + } } } \ No newline at end of file diff --git a/project/plugins.js b/project/plugins.js new file mode 100644 index 00000000..a014ba64 --- /dev/null +++ b/project/plugins.js @@ -0,0 +1,62 @@ +var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = +{ + "test": function(){ + console.log("插件函数执行测试"); + }, + "drawLight" : function (name, color, lights, lightDec) { + // 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...) + // 【参数说明】 + // name:必填,要绘制到的画布名;可以是一个系统画布,或者是个自定义画布;如果不存在则创建 + // color:可选,只能是一个0~1之间的数,为不透明度的值。不填则默认为0.9。 + // lights:可选,一个数组,定义了每个独立的灯光。 + // 其中每一项是三元组 [x,y,r] x和y分别为该灯光的横纵坐标,r为该灯光的半径。 + // lightDec:可选,0到1之间,光从多少百分比才开始衰减(在此范围内保持全亮),不设置默认为0。 + // 比如lightDec为0.5代表,每个灯光部分内圈50%的范围全亮,50%以后才开始快速衰减。 + // 【调用样例】 + // core.plugin.drawLight('curtain'); // 在curtain层绘制全图不透明度0.9,等价于更改画面色调为[0,0,0,0.9]。 + // core.plugin.drawLight('ui', 0.95, [[25,11,46]]); // 在ui层绘制全图不透明度0.95,其中在(25,11)点存在一个半径为46的灯光效果。 + // core.plugin.drawLight('test', 0.2, [[25,11,46,0.1]]); // 创建一个test图层,不透明度0.2,其中在(25,11)点存在一个半径为46的灯光效果,灯光中心不透明度0.1。 + // core.plugin.drawLight('test2', 0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 创建test2图层,且存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 + // core.plugin.drawLight('xxx', 0.3, [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,且40%后才开始衰减。 + + // 清空色调层;也可以修改成其它层比如animate/weather层,或者用自己创建的canvas + var ctx = core.getContextByName(name); + if (ctx == null) { + if (typeof name == 'string') + ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 98); + else return; + } + + ctx.mozImageSmoothingEnabled = false; + ctx.webkitImageSmoothingEnabled = false; + ctx.msImageSmoothingEnabled = false; + ctx.imageSmoothingEnabled = false; + + core.clearMap(name); + // 绘制色调层,默认不透明度 + if (color == null) color = 0.9; + ctx.fillStyle = "rgba(0,0,0,"+color+")"; + ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); + + lightDec = core.clamp(lightDec, 0, 1); + + // 绘制每个灯光效果 + ctx.globalCompositeOperation = 'destination-out'; + lights.forEach(function (light) { + // 坐标,半径,中心不透明度 + var x = light[0], y = light[1], r = light[2]; + // 计算衰减距离 + var decDistance = parseInt(r * lightDec); + // 正方形区域的直径和左上角坐标 + var grd=ctx.createRadialGradient(x,y,decDistance,x,y,r); + grd.addColorStop(0, "rgba(0,0,0,1)"); + grd.addColorStop(1, "rgba(0,0,0,0)"); + ctx.beginPath(); + ctx.fillStyle=grd; + ctx.arc(x,y,r,0,2*Math.PI); + ctx.fill(); + }); + ctx.globalCompositeOperation = 'source-over'; + // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); + } +} \ No newline at end of file From eda91df9f0cc3cefd2d89f6192afb1203807f54c Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 19 Mar 2019 14:23:43 -0400 Subject: [PATCH 045/153] ui --- _server/editor_file.js | 78 ++++++++++++++++++++++++++++++++++++++ _server/editor_mode.js | 19 +++++++++- _server/plugins.comment.js | 6 +-- editor-mobile.html | 18 +++++++++ editor.html | 18 +++++++++ project/plugins.js | 4 +- 6 files changed, 137 insertions(+), 6 deletions(-) diff --git a/_server/editor_file.js b/_server/editor_file.js index 413a1bfa..545867b2 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -850,6 +850,65 @@ editor_file = function (editor, callback) { //////////////////////////////////////////////////////////////////// + var plmap = {}; + var pljson = JSON.stringify(plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1, function (k, v) { + if (v instanceof Function) { + var id_ = editor.guid(); + plmap[id_] = v.toString(); + return id_; + } else if(v===null){ + var id_ = editor.guid(); + plmap[id_] = 'null'; + return id_; + } return v + }, 4); + var plobj = JSON.parse(pljson); + editor_file.pluginsMap = plmap; + editor_file.pluginsObj = plobj; + var buildpllocobj = function (locObj) { + for (var key in locObj) { + if (typeof(locObj[key]) !== typeof('')) buildpllocobj(locObj[key]); + else locObj[key] = plmap[locObj[key]]; + } + }; + + editor_file.editPlugins = function (actionList, callback) { + /*actionList:[ + ["change","['test']","function(x,y){console.log(x,y)}"], + ] + 为[]时只查询不修改 + */ + if (!isset(callback)) { + printe('未设置callback'); + throw('未设置callback') + } + ; + if (isset(actionList) && actionList.length > 0) { + saveSetting('plugins', actionList, function (err) { + callback([ + (function () { + var locObj = JSON.parse(JSON.stringify(plobj)); + buildpllocobj(locObj); + return locObj; + })(), + editor_file.pluginsComment, + err]); + }); + } else { + callback([ + (function () { + var locObj = JSON.parse(JSON.stringify(plobj)); + buildpllocobj(locObj); + return locObj; + })(), + editor_file.pluginsComment, + null]); + } + } + //callback([obj,commentObj,err:String]) + + //////////////////////////////////////////////////////////////////// + var isset = function (val) { if (val == undefined || val == null) { return false; @@ -1026,6 +1085,25 @@ editor_file = function (editor, callback) { }); return; } + if (file == 'plugins') { + actionList.forEach(function (value) { + if(value[0]==='add'){ + eval("plobj" + value[1] + '=' + JSON.stringify(value[2])); + } else { + eval("plmap[plobj" + value[1] + ']=' + JSON.stringify(value[2])); + } + }); + var plraw = JSON.stringify(plobj,null,4); + for (var id_ in plmap) { + plraw = plraw.replace('"' + id_ + '"', plmap[id_]) + } + var datastr = 'var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = \n'; + datastr += plraw; + fs.writeFile('project/plugins.js', encode(datastr), 'base64', function (err, data) { + callback(err); + }); + return; + } callback('出错了,要设置的文件名不识别'); } diff --git a/_server/editor_mode.js b/_server/editor_mode.js index cbb63f17..2c95a8e9 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -13,6 +13,7 @@ editor_mode = function (editor) { 'appendpic': 'left1', 'commonevent': 'left9', + 'plugins': 'left10', } this._ids = {} this.dom = {} @@ -385,6 +386,9 @@ editor_mode = function (editor) { case 'commonevent': editor.file.editCommonEvent(actionList, cb); break; + case 'plugins': + editor.file.editPlugins(actionList, cb); + break; default: break; } @@ -394,7 +398,7 @@ editor_mode = function (editor) { if (editor_mode.mode != mode) { if (mode === 'save') editor_mode.doActionList(editor_mode.mode, editor_mode.actionList); if (editor_mode.mode === 'nextChange' && mode) editor_mode.showMode(mode); - editor_mode.mode = mode; + if (mode !== 'save') editor_mode.mode = mode; editor_mode.actionList = []; } } @@ -526,6 +530,19 @@ editor_mode = function (editor) { tableinfo.listen(tableinfo.guids); if (Boolean(callback)) callback(); } + + editor_mode.prototype.plugins = function (callback) { + var objs = []; + editor.file.editPlugins([], function (objs_) { + objs = objs_; + //console.log(objs_) + }); + //只查询不修改时,内部实现不是异步的,所以可以这么写 + var tableinfo = editor_mode.objToTable_(objs[0], objs[1]); + document.getElementById('table_e2c034ec_47c6_48ae_8db8_4f8f32fea2d6').innerHTML = tableinfo.HTML; + tableinfo.listen(tableinfo.guids); + if (Boolean(callback)) callback(); + } ///////////////////////////////////////////////////////////////////////////// diff --git a/_server/plugins.comment.js b/_server/plugins.comment.js index d556f4d6..20a3f361 100644 --- a/_server/plugins.comment.js +++ b/_server/plugins.comment.js @@ -6,13 +6,13 @@ var plugins_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "test": { "_leaf": true, "_type": "textarea", - "_range": "thiseval instanceof Array", + "_range": "typeof(thiseval)=='string'", "_data": "插件函数执行测试, 这个函数在导入后被直接执行(因此不允许删除)" }, "drawLight": { "_leaf": true, "_type": "textarea", - "_range": "thiseval instanceof Array || thiseval==null", + "_range": "typeof(thiseval)=='string' || thiseval==null", "_data": "绘制灯光/漆黑层效果" }, } @@ -20,7 +20,7 @@ var plugins_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = return { "_leaf": true, "_type": "textarea", - "_range": "thiseval instanceof Array || thiseval==null", + "_range": "typeof(thiseval)=='string' || thiseval==null", "_data": "自定义插件" } } diff --git a/editor-mobile.html b/editor-mobile.html index 681feb8f..4b82dfc4 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -260,6 +260,23 @@ +
+

插件编写       +

+
+
+ + + + + + + + +
条目注释
+
+
+
@@ -329,6 +346,7 @@ +
diff --git a/project/plugins.js b/project/plugins.js index a014ba64..23cbb414 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -1,9 +1,9 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { - "test": function(){ + "test": function(){ console.log("插件函数执行测试"); }, - "drawLight" : function (name, color, lights, lightDec) { + "drawLight": function (name, color, lights, lightDec) { // 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...) // 【参数说明】 // name:必填,要绘制到的画布名;可以是一个系统画布,或者是个自定义画布;如果不存在则创建 From 69e4215e03523de7f330edb3a1ad9dd2e64c7548 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 20 Mar 2019 02:32:31 +0800 Subject: [PATCH 046/153] myprompt & myconfirm --- _server/editor_mode.js | 4 +- editor-mobile.html | 8 +++ editor.html | 8 +++ index.html | 9 ++++ libs/actions.js | 108 +++++++++++++++++++++-------------------- libs/control.js | 39 ++++++++------- libs/events.js | 45 +++++++++-------- libs/utils.js | 24 +++++++++ main.js | 36 +++++++++++++- styles.css | 57 ++++++++++++++++++++++ 10 files changed, 245 insertions(+), 93 deletions(-) diff --git a/_server/editor_mode.js b/_server/editor_mode.js index cbb63f17..009499ad 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -791,7 +791,7 @@ editor_mode = function (editor) { var pixel = getPixel(imgData, i, j); if (pixel[3]==0) trans++; if (pixel[0]==255 && pixel[1]==255 && pixel[2]==255 && pixel[3]==255) white++; - if (pixel[0]==0 && pixel[1]==0 && pixel[2]==0 && pixel[3]==255) black++; + // if (pixel[0]==0 && pixel[1]==0 && pixel[2]==0 && pixel[3]==255) black++; } } if (white>black && white>trans*10 && confirm("看起来这张图片是以纯白为底色,是否自动调整为透明底色?")) { @@ -807,6 +807,7 @@ editor_mode = function (editor) { tempCanvas.putImageData(imgData, 0, 0); changed = true; } + /* if (black>white && black>trans*10 && confirm("看起来这张图片是以纯黑为底色,是否自动调整为透明底色?")) { for (var i=0;i此浏览器不支持HTML5
+
+
+

请输入文字...

+ + + +
+
diff --git a/editor.html b/editor.html index 4584bff7..29091d0d 100644 --- a/editor.html +++ b/editor.html @@ -474,6 +474,14 @@ 此浏览器不支持HTML5 +
+
+

请输入文字...

+ + + +
+
diff --git a/index.html b/index.html index afa4c129..06398202 100644 --- a/index.html +++ b/index.html @@ -25,6 +25,7 @@

资源即将开始加载

+

HTML5魔塔游戏平台,享受更多魔塔游戏:
https://h5mota.com/

@@ -148,6 +149,14 @@ 此浏览器不支持HTML5 +
+
+

请输入文字...

+ + + +
+
diff --git a/libs/actions.js b/libs/actions.js index a83bff54..44574b82 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1606,10 +1606,11 @@ actions.prototype._clickSL = function (x, y) { core.ui.drawSLPanel(index); } else { - var index = parseInt(prompt("请输入读档编号")) || 0; - if (index > 0) { - core.doSL(index, core.status.event.id); - } + core.myprompt("请输入读档编号", null, function (index) { + index = parseInt(index) || 0; + if (index > 0) + core.doSL(index, core.status.event.id); + }); } return; } @@ -1722,11 +1723,12 @@ actions.prototype._keyUpSL = function (keycode) { } return; } - if (keycode == 69 && core.status.event.id == 'load') { // E - var index = parseInt(prompt("请输入读档编号")) || 0; - if (index > 0) { - core.doSL(index, core.status.event.id); - } + if (keycode == 69 && core.status.event.id != 'save') { // E + core.myprompt("请输入读档编号", null, function (index) { + index = parseInt(index) || 0; + if (index > 0) + core.doSL(index, core.status.event.id); + }); return; } if (keycode == 46) { @@ -2061,55 +2063,55 @@ actions.prototype._clickStorageRemove = function (x, y) { var selection = y - topIndex; switch (selection) { case 0: - if (!confirm("你确定要清除【全部塔】的所有本地存档?\n此行为不可逆!!!")) - break; - if (core.platform.useLocalForage) { - core.ui.drawWaiting("正在清空,请稍后..."); - localforage.clear(function () { - core.ui.closePanel(); + core.myconfirm("你确定要清除【全部塔】的所有本地存档?\n此行为不可逆!!!", function () { + if (core.platform.useLocalForage) { + core.ui.drawWaiting("正在清空,请稍后..."); + localforage.clear(function () { + core.ui.closePanel(); + core.drawText("\t[操作成功]你的所有存档已被清空。"); + core.saves.saveIndex = 1; + core.removeLocalStorage('saveIndex'); + }); + } + else { + localStorage.clear(); core.drawText("\t[操作成功]你的所有存档已被清空。"); core.saves.saveIndex = 1; core.removeLocalStorage('saveIndex'); - }); - } - else { - localStorage.clear(); - core.drawText("\t[操作成功]你的所有存档已被清空。"); - core.saves.saveIndex = 1; - core.removeLocalStorage('saveIndex'); - } + } + }); break; case 1: - if (!confirm("你确定要清除本塔的所有本地存档?\n此行为不可逆!!!")) - break; - if (core.platform.useLocalForage) { - core.ui.drawWaiting("正在清空,请稍后..."); - Object.keys(core.saves.ids).forEach(function (v) { - if (v != 0) - core.removeLocalForage("save" + v); - }); - core.removeLocalForage("autoSave", function () { + core.myconfirm("你确定要清除本塔的所有本地存档?\n此行为不可逆!!!", function () { + if (core.platform.useLocalForage) { + core.ui.drawWaiting("正在清空,请稍后..."); + Object.keys(core.saves.ids).forEach(function (v) { + if (v != 0) + core.removeLocalForage("save" + v); + }); + core.removeLocalForage("autoSave", function () { + core.saves.autosave.data = null; + core.saves.autosave.updated = false; + core.ui.closePanel(); + core.drawText("\t[操作成功]当前塔的存档已被清空。"); + core.saves.saveIndex = 1; + core.removeLocalStorage('saveIndex'); + }); + } + else { + Object.keys(core.saves.ids).forEach(function (v) { + if (v != 0) + core.removeLocalStorage("save" + v); + }); + core.removeLocalStorage("autoSave"); core.saves.autosave.data = null; core.saves.autosave.updated = false; - core.ui.closePanel(); core.drawText("\t[操作成功]当前塔的存档已被清空。"); core.saves.saveIndex = 1; core.removeLocalStorage('saveIndex'); - }); - } - else { - Object.keys(core.saves.ids).forEach(function (v) { - if (v != 0) - core.removeLocalStorage("save" + v); - }); - core.removeLocalStorage("autoSave"); - core.saves.autosave.data = null; - core.saves.autosave.updated = false; - core.drawText("\t[操作成功]当前塔的存档已被清空。"); - core.saves.saveIndex = 1; - core.removeLocalStorage('saveIndex'); - } - break; + } + break; + }); case 2: core.status.event.selection = 6; core.ui.drawSyncSave(); @@ -2200,8 +2202,10 @@ actions.prototype._clickGameInfo = function (x, y) { case 1: if (core.platform.isPC) window.open("editor.html", "_blank"); - else if (confirm("即将离开本塔,跳转至本塔工程页面,确认?")) { - window.location.href = "editor-mobile.html"; + else { + core.myconfirm("即将离开本塔,跳转至本塔工程页面,确认?", function () { + window.location.href = "editor-mobile.html"; + }); } break; case 2: @@ -2209,9 +2213,9 @@ actions.prototype._clickGameInfo = function (x, y) { window.open("/score.php?name=" + core.firstData.name + "&num=10", "_blank"); } else { - if (confirm("即将离开本塔,跳转至本塔评论页面,确认?")) { + core.myconfirm("即将离开本塔,跳转至本塔评论页面,确认?", function () { window.location.href = "/score.php?name=" + core.firstData.name + "&num=10"; - } + }); } break; case 3: diff --git a/libs/control.js b/libs/control.js index 7bc57e08..ad0ee9cd 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1033,12 +1033,15 @@ control.prototype._updateDamage_extraDamage = function (floorId, ctx, refresh) { control.prototype.chooseReplayFile = function () { core.readFile(function (obj) { if (obj.name!=core.firstData.name) return alert("存档和游戏不一致!"); - if (obj.version && obj.version!=core.firstData.version) { - if (!confirm("游戏版本不一致!\n你仍然想播放录像吗?")) - return; - } if (!obj.route) return alert("无效的录像!"); - core.startGame(core.flags.startUsingCanvas?'':obj.hard||'', obj.seed, core.decodeRoute(obj.route)); + var _replay = function () { + core.startGame(core.flags.startUsingCanvas?'':obj.hard||'', obj.seed, core.decodeRoute(obj.route)); + } + if (obj.version && obj.version!=core.firstData.version) { + core.myconfirm("游戏版本不一致!\n你仍然想播放录像吗?", _replay); + return; + } + _replay(); }); } @@ -1526,14 +1529,15 @@ control.prototype._doSL_load = function (id) { control.prototype._doSL_load_afterGet = function (id, data) { if (!data) return alert("无效的存档"); + var _replay = function () { + core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); + }; if (core.flags.checkConsole && data.hashCode != null && data.hashCode != core.hashCode(data.hero)) { - if (confirm("存档校验失败,请勿修改存档文件!\n你想回放此存档的录像吗?")) - core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); + core.myconfirm("存档校验失败,请勿修改存档文件!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。", _replay); return; } if (data.version != core.firstData.version) { - if (confirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。")) - core.startGame(data.hard, data.hero.flags.__seed__, core.decodeRoute(data.route)); + core.myconfirm("存档版本不匹配!\n你想回放此存档的录像吗?\n可以随时停止录像播放以继续游戏。", _replay); return; } core.ui.closePanel(); @@ -1610,15 +1614,14 @@ control.prototype._syncSave_http = function (saves) { ////// 从服务器加载存档 ////// control.prototype.syncLoad = function () { - core.interval.onDownInterval = 'tmp'; - var id = prompt("请输入存档编号:") || ""; - if (id=="") return core.ui.drawSyncSave(); - core.interval.onDownInterval = 'tmp'; - var password = prompt("请输入存档密码:") || ""; - if (password=="") return core.ui.drawSyncSave(); - - core.ui.drawWaiting("正在同步,请稍后..."); - this._syncLoad_http(id, password); + core.myprompt("请输入存档编号", null, function (id) { + if (!id) return core.ui.drawSyncSave(); + core.myprompt("请输入存档密码:", null, function (password) { + if (!password) return core.ui.drawSyncSave(); + core.ui.drawWaiting("正在同步,请稍后..."); + core.control._syncLoad_http(id, password); + }); + }); } control.prototype._syncLoad_http = function (id, password) { diff --git a/libs/events.js b/libs/events.js index 6821c204..cf447186 100644 --- a/libs/events.js +++ b/libs/events.js @@ -142,8 +142,14 @@ events.prototype._gameOver_confirmUpload = function (ending, norank) { return; } core.ui.drawConfirmBox("你想记录你的ID和成绩吗?", function () { - var username = main.isCompetition ? "" : prompt("请输入你的ID:", core.getCookie('id') || ""); - core.events._gameOver_doUpload(username, ending, norank); + if (main.isCompetition) { + core.events._gameOver_doUpload("", ending, norank); + } + else { + core.myprompt("请输入你的ID:", core.getCookie('id') || "", function (username) { + core.events._gameOver_doUpload(username, ending, norank); + }); + } }, function () { if (main.isCompetition) core.events._gameOver_confirmDownload(ending); @@ -184,9 +190,7 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { else core.http("POST", "/games/upload.php", formData); - setTimeout(function () { - core.events._gameOver_confirmDownload(ending); - }, 200); + core.events._gameOver_confirmDownload(ending); } events.prototype._gameOver_confirmDownload = function (ending) { @@ -1267,23 +1271,24 @@ events.prototype._action_setHeroIcon = function (data, x, y, prefix) { } events.prototype._action_input = function (data, x, y, prefix) { - var value = this.__action_getInput(data.text, false); - if (value == null) return; - value = Math.abs(parseInt(value) || 0); - core.status.route.push("input:" + value); - core.setFlag("input", value); - core.doAction(); + this.__action_getInput(data.text, false, function (value) { + value = Math.abs(parseInt(value) || 0); + core.status.route.push("input:" + value); + core.setFlag("input", value); + core.doAction(); + }); } events.prototype._action_input2 = function (data, x, y, prefix) { - var value = this.__action_getInput(data.text, true); - if (value == null) return; - core.status.route.push("input2:" + core.encodeBase64(value)); - core.setFlag("input", value); - core.doAction(); + this.__action_getInput(data.text, true, function (value) { + value = value || ""; + core.status.route.push("input2:" + core.encodeBase64(value)); + core.setFlag("input", value); + core.doAction(); + }); } -events.prototype.__action_getInput = function (hint, isText) { +events.prototype.__action_getInput = function (hint, isText, callback) { var value, prefix = isText ? "input2:" : "input:"; if (core.isReplaying()) { var action = core.status.replay.toReplay.shift(); @@ -1292,20 +1297,18 @@ events.prototype.__action_getInput = function (hint, isText) { throw new Error("录像文件出错!当前需要一个 " + prefix + " 项,实际为 " + action); if (isText) value = core.decodeBase64(action.substring(7)); else value = parseInt(action.substring(6)); + callback(value); } catch (e) { main.log(e); core.stopReplay(); core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type": "exit"}]); core.doAction(); - return null; } } else { - core.interval.onDownInterval = 'tmp'; - value = prompt(core.replaceText(hint)) || ""; + core.myprompt(core.replaceText(hint), null, callback); } - return value; } events.prototype._action_if = function (data, x, y, prefix) { diff --git a/libs/utils.js b/libs/utils.js index 3f74feaa..d4dc8be7 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -884,6 +884,30 @@ utils.prototype.copy = function (data) { return successful; } +////// 显示一段confirm ////// +utils.prototype.myconfirm = function (hint, yesCallback, noCallback) { + main.dom.inputDiv.style.display = 'block'; + main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); + main.dom.inputBox.style.display = 'none'; + main.dom.inputYes.focus(); + + core.platform.successCallback = yesCallback; + core.platform.errorCallback = noCallback; +} + +////// 让用户输入一段文字 ////// +utils.prototype.myprompt = function (hint, value, callback) { + main.dom.inputDiv.style.display = 'block'; + main.dom.inputMessage.innerHTML = hint.replace(/\n/g, '
'); + main.dom.inputBox.style.display = 'block'; + main.dom.inputBox.value = value==null?"":value; + setTimeout(function () { + main.dom.inputBox.focus(); + }); + + core.platform.successCallback = core.platform.errorCallback = callback; +} + ////// 动画显示某对象 ////// utils.prototype.show = function (obj, speed, callback) { obj.style.display = 'block'; diff --git a/main.js b/main.js index 54edafc8..284fb529 100644 --- a/main.js +++ b/main.js @@ -69,7 +69,12 @@ function main() { 'skillCol': document.getElementById('skillCol'), 'hard': document.getElementById('hard'), 'statusCanvas': document.getElementById('statusCanvas'), - 'statusCanvasCtx': document.getElementById('statusCanvas').getContext('2d') + 'statusCanvasCtx': document.getElementById('statusCanvas').getContext('2d'), + 'inputDiv': document.getElementById('inputDiv'), + 'inputMessage': document.getElementById('inputMessage'), + 'inputBox': document.getElementById('inputBox'), + 'inputYes': document.getElementById('inputYes'), + 'inputNo': document.getElementById('inputNo') }; this.mode = 'play'; this.loadList = [ @@ -335,6 +340,7 @@ window.onresize = function () { ////// 在界面上按下某按键时 ////// main.dom.body.onkeydown = function(e) { try { + if (main.dom.inputDiv.style.display == 'block') return; if (main.core && (main.core.isPlaying() || main.core.status.lockControl)) main.core.onkeyDown(e); } catch (ee) { main.log(ee); } @@ -343,6 +349,7 @@ main.dom.body.onkeydown = function(e) { ////// 在界面上放开某按键时 ////// main.dom.body.onkeyup = function(e) { try { + if (main.dom.inputDiv.style.display == 'block') return; if (main.core && (main.core.isPlaying() || main.core.status.lockControl)) main.core.onkeyUp(e); } catch (ee) { main.log(ee); } @@ -672,6 +679,33 @@ window.onblur = function () { } } +main.dom.inputYes.onclick = function () { + main.dom.inputDiv.style.display = 'none'; + var func = core.platform.successCallback; + core.platform.successCallback = core.platform.errorCallback = null; + if (func) func(main.dom.inputBox.value); +} + +main.dom.inputNo.onclick = function () { + main.dom.inputDiv.style.display = 'none'; + var func = core.platform.errorCallback; + core.platform.successCallback = core.platform.errorCallback = null; + if (func) func(null); +} + +main.dom.inputDiv.onkeyup = function (e) { + if (e.keyCode == 13) { + setTimeout(function () { + main.dom.inputYes.click(); + }, 50); + } + else if (e.keyCode == 27) { + setTimeout(function () { + main.dom.inputNo.click(); + }, 50); + } +} + }//listen end var main = new main(); \ No newline at end of file diff --git a/styles.css b/styles.css index 16958ed2..34bed2c4 100644 --- a/styles.css +++ b/styles.css @@ -79,6 +79,15 @@ z-index: 15; } +#startTopHint { + color: #66CCFF; + position: absolute; + bottom: 0; + left: 5%; + z-index: 15; + font-size: 18px; +} + #startBackground { position:absolute; top:50%; @@ -308,4 +317,52 @@ p#name { #data { z-index: 170; +} + +#inputDiv { + display: none; + width: 100%; + height: 100%; + position: fixed; + top: 0; + left: 0; + background: rgba(127,127,127,0.6); + z-index: 2000 +} + +#inputDialog { + position: fixed; + top: 50%; + left: 50%; + transform: translate(-50%, -60%); + background: white; + width: 250px; + min-height: 50px; + max-height: 250px; +} + +#inputMessage { + word-wrap: break-word; + text-align: left; + margin-left: 8%; + margin-right: 5%; +} + +#inputBox { + margin-left: 8%; + width: 80%; + margin-bottom: 10px; + padding: 5px 3px; + border: 1px solid; + background: #F0F0F0; +} + +#inputYes { + margin-bottom: 15px; + margin-left: 8%; +} + +#inputNo { + float:right; + margin-right: 10%; } \ No newline at end of file From 4fa318a6b4dc350aa8bec2e65ebff2e59bb7d168 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 19 Mar 2019 22:19:41 -0400 Subject: [PATCH 047/153] step1:buttons --- _server/vm.js | 189 ++++++++++++++++++++------------------------- editor-mobile.html | 8 +- editor.html | 8 +- 3 files changed, 91 insertions(+), 114 deletions(-) diff --git a/_server/vm.js b/_server/vm.js index 6707dea0..8fe05935 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -1,46 +1,39 @@ -// vue 相关处理 -var exportMap = new Vue({ - el: '#exportMap', - data: { - isExport: false, - }, - methods: { - exportMap: function () { - editor.updateMap(); - var sx=editor.map.length-1,sy=editor.map[0].length-1; +var exportMap = document.getElementById('exportMap') +exportMap.isExport=false +exportMap.onclick=function(){ + editor.updateMap(); + var sx=editor.map.length-1,sy=editor.map[0].length-1; - var filestr = ''; - for (var yy = 0; yy <= sy; yy++) { - filestr += '[' - for (var xx = 0; xx <= sx; xx++) { - var mapxy = editor.map[yy][xx]; - if (typeof(mapxy) == typeof({})) { - if ('idnum' in mapxy) mapxy = mapxy.idnum; - else { - // mapxy='!!?'; - tip.whichShow = 3; - return; - } - } else if (typeof(mapxy) == 'undefined') { - tip.whichShow = 3; - return; - } - mapxy = String(mapxy); - mapxy = Array(Math.max(4 - mapxy.length, 0)).join(' ') + mapxy; - filestr += mapxy + (xx == sx ? '' : ',') + var filestr = ''; + for (var yy = 0; yy <= sy; yy++) { + filestr += '[' + for (var xx = 0; xx <= sx; xx++) { + var mapxy = editor.map[yy][xx]; + if (typeof(mapxy) == typeof({})) { + if ('idnum' in mapxy) mapxy = mapxy.idnum; + else { + // mapxy='!!?'; + tip.whichShow = 3; + return; } - - filestr += ']' + (yy == sy ? '' : ',\n'); + } else if (typeof(mapxy) == 'undefined') { + tip.whichShow = 3; + return; } - pout.value = filestr; - editArea.mapArr = filestr; - this.isExport = true; - editArea.error = 0; - tip.whichShow = 2; + mapxy = String(mapxy); + mapxy = Array(Math.max(4 - mapxy.length, 0)).join(' ') + mapxy; + filestr += mapxy + (xx == sx ? '' : ',') } + + filestr += ']' + (yy == sy ? '' : ',\n'); } -}) + pout.value = filestr; + editArea.mapArr = filestr; + exportMap.isExport = true; + editArea.error = 0; + tip.whichShow = 2; +} var editArea = new Vue({ el: '#editArea', data: { @@ -133,80 +126,64 @@ var editArea = new Vue({ } } }); -var copyMap = new Vue({ - el: '#copyMap', - data: { - err: '' - }, - methods: { - copyMap: function () { - - tip.whichShow = 0; - if (pout.value.trim() != '') { - if (editArea.error) { - this.err = editArea.errors[editArea.error - 1]; - tip.whichShow = 5 - return; - } - try { - pout.focus(); - pout.setSelectionRange(0, pout.value.length); - document.execCommand("Copy"); - tip.whichShow = 6; - } catch (e) { - this.err = e; - tip.whichShow = 5; - } - } else { - tip.whichShow = 7; - } +var copyMap=document.getElementById('copyMap') +copyMap.err='' +copyMap.onclick=function(){ + tip.whichShow = 0; + if (pout.value.trim() != '') { + if (editArea.error) { + copyMap.err = editArea.errors[editArea.error - 1]; + tip.whichShow = 5 + return; } - }, -}) -var clearMap = new Vue({ - el: '#clearMap', - - methods: { - clearMap: function () { - editor.mapInit(); - editor_mode.onmode(''); - editor.file.saveFloorFile(function (err) { - if (err) { - printe(err); - throw(err) - } - ;printf('地图清除成功'); - }); - editor.updateMap(); - clearTimeout(editArea.formatTimer); - clearTimeout(tip.timer); - pout.value = ''; - editArea.mapArr = ''; - tip.whichShow = 4; - editArea.error = 0; + try { + pout.focus(); + pout.setSelectionRange(0, pout.value.length); + document.execCommand("Copy"); + tip.whichShow = 6; + } catch (e) { + copyMap.err = e; + tip.whichShow = 5; } + } else { + tip.whichShow = 7; } -}) -var deleteMap = new Vue({ - el: '#deleteMap', - methods: { - deleteMap: function () { - editor_mode.onmode(''); - var index = core.floorIds.indexOf(editor.currentFloorId); - if (index>=0) { - core.floorIds.splice(index,1); - editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_); - if (objs_.slice(-1)[0] != null) { - printe(objs_.slice(-1)[0]); - throw(objs_.slice(-1)[0]) - } - ;printe('删除成功,请F5刷新编辑器生效'); - }); - } - else printe('删除成功,请F5刷新编辑器生效'); +} +var clearMapButton=document.getElementById('clearMapButton') +clearMapButton.onclick=function () { + editor.mapInit(); + editor_mode.onmode(''); + editor.file.saveFloorFile(function (err) { + if (err) { + printe(err); + throw(err) } + ;printf('地图清除成功'); + }); + editor.updateMap(); + clearTimeout(editArea.formatTimer); + clearTimeout(tip.timer); + pout.value = ''; + editArea.mapArr = ''; + tip.whichShow = 4; + editArea.error = 0; +} +var deleteMap=document.getElementById('deleteMap') +deleteMap.onclick=function () { + editor_mode.onmode(''); + var index = core.floorIds.indexOf(editor.currentFloorId); + if (index>=0) { + core.floorIds.splice(index,1); + editor.file.editTower([['change', "['main']['floorIds']", core.floorIds]], function (objs_) {//console.log(objs_); + if (objs_.slice(-1)[0] != null) { + printe(objs_.slice(-1)[0]); + throw(objs_.slice(-1)[0]) + } + ;printe('删除成功,请F5刷新编辑器生效'); + }); } -}) + else printe('删除成功,请F5刷新编辑器生效'); +} printf = function (str_, type) { selectBox.isSelected = false; if (!type) { diff --git a/editor-mobile.html b/editor-mobile.html index 4a14c201..e90fe59a 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -34,10 +34,10 @@
- - - - + + + +
- - - - + + + +
diff --git a/editor.html b/editor.html index cc870582..0fe2bc80 100644 --- a/editor.html +++ b/editor.html @@ -325,7 +325,7 @@
-
+
From a1e144f2da72a4f342d9ba57ae8f81d0826c4c9d Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 19 Mar 2019 22:36:13 -0400 Subject: [PATCH 049/153] editArea-1 --- _server/css/editor.css | 4 +-- _server/css/editor_mobile.css | 4 +-- _server/vm.js | 54 ++++++++++++++++------------------- editor-mobile.html | 6 ++-- editor.html | 6 ++-- 5 files changed, 35 insertions(+), 39 deletions(-) diff --git a/_server/css/editor.css b/_server/css/editor.css index b37149bb..dd9c0e18 100644 --- a/_server/css/editor.css +++ b/_server/css/editor.css @@ -54,7 +54,7 @@ body { height: 630px; } -#editArea { +#mapEditArea { position: absolute; width: 100%; height: 400px; @@ -107,7 +107,7 @@ body { top: 530px; } -#editArea p { +#mapEditArea p { margin: 10px; display: block; width: 70%; diff --git a/_server/css/editor_mobile.css b/_server/css/editor_mobile.css index 7bdf8953..1120c9fd 100644 --- a/_server/css/editor_mobile.css +++ b/_server/css/editor_mobile.css @@ -37,7 +37,7 @@ body { position: absolute; } -#editArea { +#mapEditArea { position: absolute; width: 100%; height: 70%; @@ -64,7 +64,7 @@ body { overflow: auto; } -#editArea p { +#mapEditArea p { margin: 10px; display: block; width: 70%; diff --git a/_server/vm.js b/_server/vm.js index 5e4fbe21..1b40bf3a 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -29,13 +29,13 @@ exportMap.onclick=function(){ filestr += ']' + (yy == sy ? '' : ',\n'); } pout.value = filestr; - editArea.mapArr = filestr; + mapEditArea.mapArr = filestr; exportMap.isExport = true; - editArea.error = 0; + mapEditArea.error = 0; tip.whichShow = 2; } -var editArea = new Vue({ - el: '#editArea', +var mapEditArea = new Vue({ + el: '#mapEditArea', data: { mapArr: '', errors: [ // 编号1,2,3,4 @@ -49,39 +49,36 @@ var editArea = new Vue({ }, watch: { mapArr: function (val, oldval) { - var that = this; if (val == '') return; if (exportMap.isExport) { exportMap.isExport = false; return; } - if (that.formatArr()) { - that.error = 0; + if (mapEditArea.formatArr()) { + mapEditArea.error = 0; setTimeout(function () { - that.mapArr = that.formatArr(); - that.drawMap(); + mapEditArea.mapArr = mapEditArea.formatArr(); + mapEditArea.drawMap(); tip.whichShow = 8 }, 1000); - that.formatTimer = setTimeout(function () { - pout.value = that.formatArr(); + mapEditArea.formatTimer = setTimeout(function () { + pout.value = mapEditArea.formatArr(); }, 5000); //5s后再格式化,不然光标跳到最后很烦 } else { - that.error = 1; + mapEditArea.error = 1; } }, error: function () { - // console.log(editArea.mapArr); - if (this.error>0) - printe(this.errors[this.error-1]) + // console.log(mapEditArea.mapArr); + if (mapEditArea.error>0) + printe(mapEditArea.errors[mapEditArea.error-1]) } }, methods: { drawMap: function () { - var that = this; - - // var mapArray = that.mapArr.split(/\D+/).join(' ').trim().split(' '); - var mapArray = JSON.parse('[' + that.mapArr + ']'); + // var mapArray = mapEditArea.mapArr.split(/\D+/).join(' ').trim().split(' '); + var mapArray = JSON.parse('[' + mapEditArea.mapArr + ']'); var sy=editor.map.length,sx=editor.map[0].length; for (var y = 0; y < sy; y++) for (var x = 0; x < sx; x++) { @@ -89,7 +86,7 @@ var editArea = new Vue({ if (num == 0) editor.map[y][x] = 0; else if (typeof(editor.indexs[num][0]) == 'undefined') { - that.error = 2; + mapEditArea.error = 2; editor.map[y][x] = undefined; } else editor.map[y][x] = editor.ids[[editor.indexs[num][0]]]; } @@ -99,11 +96,10 @@ var editArea = new Vue({ }, formatArr: function () { var formatArrStr = ''; - var that = this; - clearTimeout(that.formatTimer); + clearTimeout(mapEditArea.formatTimer); var si=editor.map.length,sk=editor.map[0].length; - if (this.mapArr.split(/\D+/).join(' ').trim().split(' ').length != si*sk) return false; - var arr = this.mapArr.replace(/\s+/g, '').split('],['); + if (mapEditArea.mapArr.split(/\D+/).join(' ').trim().split(' ').length != si*sk) return false; + var arr = mapEditArea.mapArr.replace(/\s+/g, '').split('],['); if (arr.length != si) return; for (var i = 0; i < si; i++) { @@ -131,8 +127,8 @@ copyMap.err='' copyMap.onclick=function(){ tip.whichShow = 0; if (pout.value.trim() != '') { - if (editArea.error) { - copyMap.err = editArea.errors[editArea.error - 1]; + if (mapEditArea.error) { + copyMap.err = mapEditArea.errors[mapEditArea.error - 1]; tip.whichShow = 5 return; } @@ -161,12 +157,12 @@ clearMapButton.onclick=function () { ;printf('地图清除成功'); }); editor.updateMap(); - clearTimeout(editArea.formatTimer); + clearTimeout(mapEditArea.formatTimer); clearTimeout(tip.timer); pout.value = ''; - editArea.mapArr = ''; + mapEditArea.mapArr = ''; tip.whichShow = 4; - editArea.error = 0; + mapEditArea.error = 0; } var deleteMap=document.getElementById('deleteMap') deleteMap.onclick=function () { diff --git a/editor-mobile.html b/editor-mobile.html index 66d38e6f..34d7c12d 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -18,7 +18,7 @@
-
+
@@ -522,8 +522,8 @@ if (location.protocol.indexOf("http")!=0) { + diff --git a/editor.html b/editor.html index 391c4745..1367f96d 100644 --- a/editor.html +++ b/editor.html @@ -510,6 +510,7 @@ if (location.protocol.indexOf("http")!=0) { + From 8eddb7f7b5a3c2f1a5c5dcc5b93c04beb73f40bd Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 23 Mar 2019 16:50:10 -0400 Subject: [PATCH 082/153] editor_util --- _server/README.md | 2 +- _server/editor.js | 69 +++++++++------------ _server/editor_file.js | 12 ++-- _server/editor_mode.js | 127 ++------------------------------------ _server/editor_multi.js | 4 +- _server/editor_table.js | 8 +-- _server/editor_util.js | 132 +++++++++++++++++++++++++++++++++++++++- _server/refactoring.md | 1 + editor-mobile.html | 3 +- editor.html | 3 +- 10 files changed, 182 insertions(+), 179 deletions(-) diff --git a/_server/README.md b/_server/README.md index ccd28558..d23bfb43 100644 --- a/_server/README.md +++ b/_server/README.md @@ -33,7 +33,7 @@ ``` js editor.mapInit();//清空地图 editor.changeFloor('MT2')//切换地图 -editor.guid()//产生一个可以作为id的长随机字符串 +editor.util.guid()//产生一个可以作为id的长随机字符串 ``` `editor.updateMap`中画未定义快的报错 diff --git a/_server/editor.js b/_server/editor.js index d1b9e5dd..03b0cf01 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -41,31 +41,9 @@ editor.info /////////// 数据相关 /////////// editor.prototype.init = function (callback) { - var afterCoreReset = function () { - editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 - editor.drawInitData(core.icons.icons); // 初始化绘图 - - editor.fetchMapFromCore(); - editor.updateMap(); - editor.buildMark(); - editor.drawEventBlock(); - - editor.pos = {x: 0, y: 0}; - editor.mode.loc(); - editor.info = editor.ids[editor.indexs[201]]; - editor.mode.enemyitem(); - editor.mode.floor(); - editor.mode.tower(); - editor.mode.functions(); - editor.mode.commonevent(); - editor.mode.showMode('tower'); - - editor_multi = editor_multi(); - editor_blockly = editor_blockly(); - if (Boolean(callback)) callback(); - - } + editor_util_wrapper(editor); + editor_table_wrapper(editor); var afterMainInit = function () { core.floors = JSON.parse(JSON.stringify(core.floors, function (k, v) { @@ -90,7 +68,6 @@ editor.prototype.init = function (callback) { editor.file = editor_file; editor_mode = editor_mode(editor); editor.mode = editor_mode; - editor_table_wrapper(editor); core.resetGame(core.firstData.hero, null, core.firstData.floorId, core.initStatus.maps); core.changeFloor(core.status.floorId, null, core.firstData.hero.loc, null, function () { afterCoreReset(); @@ -98,6 +75,33 @@ editor.prototype.init = function (callback) { core.events.setInitData(null); }); } + + var afterCoreReset = function () { + + editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 + editor.drawInitData(core.icons.icons); // 初始化绘图 + + editor.fetchMapFromCore(); + editor.updateMap(); + editor.buildMark(); + editor.drawEventBlock(); + + editor.pos = {x: 0, y: 0}; + editor.mode.loc(); + editor.info = editor.ids[editor.indexs[201]]; + editor.mode.enemyitem(); + editor.mode.floor(); + editor.mode.tower(); + editor.mode.functions(); + editor.mode.commonevent(); + editor.mode.showMode('tower'); + + editor_multi = editor_multi(); + editor_blockly = editor_blockly(); + if (Boolean(callback)) callback(); + + } + afterMainInit(); } @@ -355,21 +359,6 @@ editor.prototype.moveViewport=function(x,y){ editor.drawPosSelection(); } -/////////// 通用 /////////// - -editor.prototype.guid = function () { - return 'id_' + 'xxxxxxxx_xxxx_4xxx_yxxx_xxxxxxxxxxxx'.replace(/[xy]/g, function (c) { - var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); -} - -editor.prototype.HTMLescape = function (str_) { - return String(str_).split('').map(function (v) { - return '&#' + v.charCodeAt(0) + ';' - }).join(''); -} - /////////// 界面交互相关 /////////// editor.prototype.drawInitData = function (icons) { diff --git a/_server/editor_file.js b/_server/editor_file.js index 545867b2..89b7f6c5 100644 --- a/_server/editor_file.js +++ b/_server/editor_file.js @@ -94,7 +94,7 @@ editor_file = function (editor, callback) { } // format 更改实现方式以支持undefined删除 var tempJsonObj=Object.assign({},editor.currentFloorData); - var tempMap=[['map',editor.guid()],['bgmap',editor.guid()],['fgmap',editor.guid()]]; + var tempMap=[['map',editor.util.guid()],['bgmap',editor.util.guid()],['fgmap',editor.util.guid()]]; tempMap.forEach(function(v){ v[2]=tempJsonObj[v[0]]; tempJsonObj[v[0]]=v[1]; @@ -764,7 +764,7 @@ editor_file = function (editor, callback) { var fmap = {}; var fjson = JSON.stringify(functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a, function (k, v) { if (v instanceof Function) { - var id_ = editor.guid(); + var id_ = editor.util.guid(); fmap[id_] = v.toString(); return id_; } else return v @@ -853,11 +853,11 @@ editor_file = function (editor, callback) { var plmap = {}; var pljson = JSON.stringify(plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1, function (k, v) { if (v instanceof Function) { - var id_ = editor.guid(); + var id_ = editor.util.guid(); plmap[id_] = v.toString(); return id_; } else if(v===null){ - var id_ = editor.guid(); + var id_ = editor.util.guid(); plmap[id_] = 'null'; return id_; } return v @@ -980,7 +980,7 @@ editor_file = function (editor, callback) { var emap = {}; var estr = JSON.stringify(maps_90f36752_8815_4be8_b32b_d7fad1d0542e, function (k, v) { if (v.id != null) { - var id_ = editor.guid(); + var id_ = editor.util.guid(); emap[id_] = JSON.stringify(v); return id_; } else return v @@ -1014,7 +1014,7 @@ editor_file = function (editor, callback) { var emap = {}; var estr = JSON.stringify(enemys_fcae963b_31c9_42b4_b48c_bb48d09f3f80, function (k, v) { if (v.hp != null) { - var id_ = editor.guid(); + var id_ = editor.util.guid(); emap[id_] = JSON.stringify(v); return id_; } else return v diff --git a/_server/editor_mode.js b/_server/editor_mode.js index ac428c07..d38a69e1 100644 --- a/_server/editor_mode.js +++ b/_server/editor_mode.js @@ -474,21 +474,8 @@ editor_mode = function (editor) { } selectAppend.onchange(); - var getPixel=function(imgData, x, y) { - var offset = (x + y * imgData.width) * 4; - var r = imgData.data[offset+0]; - var g = imgData.data[offset+1]; - var b = imgData.data[offset+2]; - var a = imgData.data[offset+3]; - return [r,g,b,a]; - } - var setPixel=function(imgData, x, y, rgba) { - var offset = (x + y * imgData.width) * 4; - imgData.data[offset+0]=rgba[0]; - imgData.data[offset+1]=rgba[1]; - imgData.data[offset+2]=rgba[2]; - imgData.data[offset+3]=rgba[3]; - } + var getPixel=editor.util.getPixel + var setPixel=editor.util.setPixel var autoAdjust = function (image, callback) { var changed = false; @@ -647,113 +634,9 @@ editor_mode = function (editor) { var nimgData=new ImageData(imgData.width,imgData.height); // ImageData .data 形如一维数组,依次排着每个点的 R(0~255) G(0~255) B(0~255) A(0~255) var convert=function(rgba,delta){ - var round=Math.round; - // rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git - //-------------------------------------------- - // The MIT License (MIT) - // - // Copyright (c) 2014 Carlos Cabo - // - // Permission is hereby granted, free of charge, to any person obtaining a copy - // of this software and associated documentation files (the "Software"), to deal - // in the Software without restriction, including without limitation the rights - // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - // copies of the Software, and to permit persons to whom the Software is - // furnished to do so, subject to the following conditions: - // - // The above copyright notice and this permission notice shall be included in all - // copies or substantial portions of the Software. - // - // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - // SOFTWARE. - //-------------------------------------------- - // https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js - var rgbToHsl = function (rgba) { - var arg, r, g, b, h, s, l, d, max, min; - - arg = rgba; - - if (typeof arg[0] === 'number') { - r = arg[0]; - g = arg[1]; - b = arg[2]; - } else { - r = arg[0][0]; - g = arg[0][1]; - b = arg[0][2]; - } - - r /= 255; - g /= 255; - b /= 255; - - max = Math.max(r, g, b); - min = Math.min(r, g, b); - l = (max + min) / 2; - - if (max === min) { - h = s = 0; // achromatic - } else { - d = max - min; - s = l > 0.5 ? d / (2 - max - min) : d / (max + min); - - switch (max) { - case r: h = (g - b) / d + (g < b ? 6 : 0); break; - case g: h = (b - r) / d + 2; break; - case b: h = (r - g) / d + 4; break; - } - - h /= 6; - } - - //CARLOS - h = round(h * 360); - s = round(s * 100); - l = round(l * 100); - - return [h, s, l]; - } - // - var hue2rgb = function (p, q, t) { - if (t < 0) { t += 1; } - if (t > 1) { t -= 1; } - if (t < 1 / 6) { return p + (q - p) * 6 * t; } - if (t < 1 / 2) { return q; } - if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; } - return p; - } - var hslToRgb = function (hsl) { - var arg, r, g, b, h, s, l, q, p; - - arg = hsl; - - if (typeof arg[0] === 'number') { - h = arg[0] / 360; - s = arg[1] / 100; - l = arg[2] / 100; - } else { - h = arg[0][0] / 360; - s = arg[0][1] / 100; - l = arg[0][2] / 100; - } - - if (s === 0) { - r = g = b = l; // achromatic - } else { - - q = l < 0.5 ? l * (1 + s) : l + s - l * s; - p = 2 * l - q; - r = hue2rgb(p, q, h + 1 / 3); - g = hue2rgb(p, q, h); - b = hue2rgb(p, q, h - 1 / 3); - } - return [round(r * 255), round(g * 255), round(b * 255)]; - } + var rgbToHsl = editor.util.rgbToHsl + var hue2rgb = editor.util.hue2rgb + var hslToRgb = editor.util.hslToRgb // var hsl=rgbToHsl(rgba) hsl[0]=(hsl[0]+delta)%360 diff --git a/_server/editor_multi.js b/_server/editor_multi.js index 5125c4e3..9ccd00c9 100644 --- a/_server/editor_multi.js +++ b/_server/editor_multi.js @@ -103,7 +103,7 @@ editor_multi = function () { var tmap = {}; var tstr = JSON.stringify(tobj, function (k, v) { if (typeof(v) === typeof('') && v.slice(0, 8) === 'function') { - var id_ = editor.guid(); + var id_ = editor.util.guid(); tmap[id_] = v.toString(); return id_; } else return v @@ -146,7 +146,7 @@ editor_multi = function () { var tmap = {}; var tstr = JSON.stringify(tobj, function (k, v) { if (v instanceof Function) { - var id_ = editor.guid(); + var id_ = editor.util.guid(); tmap[id_] = v.toString(); return id_; } else return v diff --git a/_server/editor_table.js b/_server/editor_table.js index 32b5aa3d..09009ab2 100644 --- a/_server/editor_table.js +++ b/_server/editor_table.js @@ -184,7 +184,7 @@ editor_table_wrapper = function (editor) { * @param {Object} cobj */ editor_table.prototype.objToTr = function (obj, commentObj, field, cfield, vobj, cobj) { - var guid = editor.guid(); + var guid = editor.util.guid(); var thiseval = vobj; var comment = String(cobj._data); @@ -195,14 +195,14 @@ editor_table_wrapper = function (editor) { shortField = (shortField.length < charlength ? shortField : shortField.slice(0, charlength) + '...'); // 完整的内容转义后供悬停查看 - var commentHTMLescape = editor.HTMLescape(comment); + var commentHTMLescape = editor.util.HTMLescape(comment); // 把长度超过 charlength 的字符改成 固定长度+...的形式 - var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.HTMLescape(comment.slice(0, charlength)) + '...'); + var shortCommentHTMLescape = (comment.length < charlength ? commentHTMLescape : editor.util.HTMLescape(comment.slice(0, charlength)) + '...'); var cobjstr = Object.assign({}, cobj); delete cobjstr._data; // 把cobj塞到第二个td的[cobj]中, 方便绑定事件时取 - cobjstr = editor.HTMLescape(JSON.stringify(cobjstr)); + cobjstr = editor.util.HTMLescape(JSON.stringify(cobjstr)); var tdstr = editor.table.objToTd(obj, commentObj, field, cfield, vobj, cobj) var outstr = editor.table.tr(guid, field, shortField, commentHTMLescape, cobjstr, shortCommentHTMLescape, tdstr) diff --git a/_server/editor_util.js b/_server/editor_util.js index f34d26f4..bab29837 100644 --- a/_server/editor_util.js +++ b/_server/editor_util.js @@ -10,13 +10,141 @@ editor_util_wrapper = function (editor) { return v.toString(16); }); } - + editor_util.prototype.HTMLescape = function (str_) { return String(str_).split('').map(function (v) { return '&#' + v.charCodeAt(0) + ';' }).join(''); } - + + editor_util.prototype.getPixel = function (imgData, x, y) { + var offset = (x + y * imgData.width) * 4; + var r = imgData.data[offset + 0]; + var g = imgData.data[offset + 1]; + var b = imgData.data[offset + 2]; + var a = imgData.data[offset + 3]; + return [r, g, b, a]; + } + + editor_util.prototype.setPixel = function (imgData, x, y, rgba) { + var offset = (x + y * imgData.width) * 4; + imgData.data[offset + 0] = rgba[0]; + imgData.data[offset + 1] = rgba[1]; + imgData.data[offset + 2] = rgba[2]; + imgData.data[offset + 3] = rgba[3]; + } + + // rgbToHsl hue2rgb hslToRgb from https://github.com/carloscabo/colz.git + //-------------------------------------------- + // The MIT License (MIT) + // + // Copyright (c) 2014 Carlos Cabo + // + // Permission is hereby granted, free of charge, to any person obtaining a copy + // of this software and associated documentation files (the "Software"), to deal + // in the Software without restriction, including without limitation the rights + // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + // copies of the Software, and to permit persons to whom the Software is + // furnished to do so, subject to the following conditions: + // + // The above copyright notice and this permission notice shall be included in all + // copies or substantial portions of the Software. + // + // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + // SOFTWARE. + //-------------------------------------------- + // https://github.com/carloscabo/colz/blob/master/public/js/colz.class.js + var round=Math.round; + var rgbToHsl = function (rgba) { + var arg, r, g, b, h, s, l, d, max, min; + + arg = rgba; + + if (typeof arg[0] === 'number') { + r = arg[0]; + g = arg[1]; + b = arg[2]; + } else { + r = arg[0][0]; + g = arg[0][1]; + b = arg[0][2]; + } + + r /= 255; + g /= 255; + b /= 255; + + max = Math.max(r, g, b); + min = Math.min(r, g, b); + l = (max + min) / 2; + + if (max === min) { + h = s = 0; // achromatic + } else { + d = max - min; + s = l > 0.5 ? d / (2 - max - min) : d / (max + min); + + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; break; + } + + h /= 6; + } + + //CARLOS + h = round(h * 360); + s = round(s * 100); + l = round(l * 100); + + return [h, s, l]; + } + // + var hue2rgb = function (p, q, t) { + if (t < 0) { t += 1; } + if (t > 1) { t -= 1; } + if (t < 1 / 6) { return p + (q - p) * 6 * t; } + if (t < 1 / 2) { return q; } + if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; } + return p; + } + var hslToRgb = function (hsl) { + var arg, r, g, b, h, s, l, q, p; + + arg = hsl; + + if (typeof arg[0] === 'number') { + h = arg[0] / 360; + s = arg[1] / 100; + l = arg[2] / 100; + } else { + h = arg[0][0] / 360; + s = arg[0][1] / 100; + l = arg[0][2] / 100; + } + + if (s === 0) { + r = g = b = l; // achromatic + } else { + + q = l < 0.5 ? l * (1 + s) : l + s - l * s; + p = 2 * l - q; + r = hue2rgb(p, q, h + 1 / 3); + g = hue2rgb(p, q, h); + b = hue2rgb(p, q, h - 1 / 3); + } + return [round(r * 255), round(g * 255), round(b * 255)]; + } + editor_util.prototype.rgbToHsl=rgbToHsl + editor_util.prototype.hue2rgb=hue2rgb + editor_util.prototype.hslToRgb=hslToRgb + editor.constructor.prototype.util = new editor_util(); } //editor_util_wrapper(editor); \ No newline at end of file diff --git a/_server/refactoring.md b/_server/refactoring.md index f0e7d13f..5d92d0f4 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -33,6 +33,7 @@ editor: { util: 组件 } game: 来自游戏的数据 + config: 编辑器配置 mode: 当前的模式(左侧的选择) map: 当前编辑层的地图 ... diff --git a/editor-mobile.html b/editor-mobile.html index 6e516541..01fd3454 100644 --- a/editor-mobile.html +++ b/editor-mobile.html @@ -525,9 +525,10 @@ if (location.protocol.indexOf("http")!=0) { + - + diff --git a/editor.html b/editor.html index 1367f96d..8f826432 100644 --- a/editor.html +++ b/editor.html @@ -508,9 +508,10 @@ if (location.protocol.indexOf("http")!=0) { + - + From 018dbe83325abc25b8f37ec5e2c5c4117fe11a2c Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 24 Mar 2019 16:05:46 +0800 Subject: [PATCH 083/153] rewrite drawTextBox & drawChoices --- libs/ui.js | 949 +++++++++++++++++++++-------------------------------- styles.css | 2 +- 2 files changed, 380 insertions(+), 571 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 4ab8359a..790ce132 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -13,7 +13,7 @@ function ui() { this.HSIZE = core.__HALF_SIZE__; this.LAST = this.SIZE - 1; this.PIXEL = core.__PIXELS__; - this.HPIXEL = this.PIX / 2; + this.HPIXEL = this.PIXEL / 2; } // 初始化UI @@ -341,10 +341,11 @@ ui.prototype._getTitleAndIcon = function (content) { if (blockInfo != null) { if (core.material.enemys[s4]) title = core.material.enemys[s4].name; image = blockInfo.image; - icon = blockInfo.posX; + icon = blockInfo.posY; height = blockInfo.height; animate = blockInfo.animate; } + else title = s4; } } if (s3) title = s3; @@ -360,65 +361,31 @@ ui.prototype._getTitleAndIcon = function (content) { }; } -ui.prototype.getTitleAndIcon = function (content) { - var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; - - var getInfo = function (v) { - var number = core.maps.getNumberById(v); - if (number>0) { - var block = core.maps.initBlock(0,0,number,true); - var cls = block.event.cls; - image = core.material.images[cls]; - icon = core.material.icons[cls][v]; - iconHeight = block.event.height; - animate = block.event.animate; - } - }; - - if (content.indexOf("\t[")==0 || content.indexOf("\\t[")==0) { - var index = content.indexOf("]"); - if (index>=0) { - var str=content.substring(2, index); - if (content.indexOf("\\t[")==0) str=content.substring(3, index); - content=content.substring(index+1); - var ss=str.split(","); - if (ss.length==1) { - if (/^[-\w.]+\.png$/.test(ss[0])) { - image = core.material.images.images[ss[0]]; - } - else { - id=ss[0]; - if (id=='hero') name = core.status.hero.name; - else if (core.isset(core.material.enemys[id])) { - name = core.material.enemys[id].name; - getInfo(id); - } - else { - name=id; - id='npc'; - } - } - } - else { - name=ss[0]; - id = 'npc'; - if (ss[1]=='hero') id = 'hero'; - else if (/^[-\w.]+\.png$/.test(ss[1])) { - image = core.material.images.images[ss[1]]; - } - else getInfo(ss[1]); - } - } +////// 正则处理 \b[up,xxx] 问题 +ui.prototype._getPosition = function (content) { + var pos = null, px = null, py = null; + if (core.status.event.id=='action') { + px = core.status.event.data.x; + py = core.status.event.data.y; } - return { - "content": content, - "id": id, - "name": name, - "image": image, - "icon": icon, - "iconHeight": iconHeight, - "animate": animate - }; + content = content.replace("\b", "\\b") + .replace(/\\b\[(up|center|down)(,(hero|null|\d+,\d+))?]/g, function (s0, s1, s2, s3) { + pos = s1; + if (s3 == 'hero') { + px = core.status.hero.loc.x; + py = core.status.hero.loc.y; + } + else if (s3 == 'null') { + px = py = null; + } + else if (s3) { + var str = s3.split(','); + px = parseInt(str[0]); + py = parseInt(str[1]); + } + return ""; + }); + return {content: content, position: pos, px: px, py: py}; } ////// 绘制选择光标 @@ -480,9 +447,9 @@ ui.prototype.drawWindowSkin = function(background, ctx, x, y, w, h, direction, p } ////// 计算有效文本框的宽度 -ui.prototype.calTextBoxWidth = function (ctx, content, min_width, max_width) { +ui.prototype.calTextBoxWidth = function (ctx, content, min_width, max_width, font) { // 无限长度自动换行 - var allLines = core.splitLines(ctx, content); + var allLines = core.splitLines(ctx, content, null, font); // 如果不存在手动换行,尽量调成半行形式 if (allLines.length == 1) { @@ -515,8 +482,10 @@ ui.prototype._getDrawableIconInfo = function (id) { return [image,icon]; } -ui.prototype._buildFont = function (fontSize) { - return (core.status.textAttribute.bold?"bold ":"") + fontSize + "px " +core.status.globalAttribute.font; +ui.prototype._buildFont = function (fontSize, bold) { + var textAttribute = core.status.textAttribute, globalAttribute = core.status.globalAttribute; + if (bold == null) bold = textAttribute.bold; + return (bold?"bold ":"") + (fontSize || textAttribute.textfont) + "px " + globalAttribute.font; } ////// 绘制一段文字到某个画布上面 @@ -524,7 +493,7 @@ ui.prototype._buildFont = function (fontSize) { // content:要绘制的内容;转义字符目前只允许留 \n, \r[...] 和 \i[...] // config:绘制配置项,目前暂时包含如下内容(均为可选) // left, top:起始点位置;maxWidth:单行最大宽度;color:默认颜色;align:左中右 -// fontSize:字体大小;font:字体样式;lineHeight:行高;time:打字机间隔 +// fontSize:字体大小;lineHeight:行高;time:打字机间隔 ui.prototype.drawTextContent = function (ctx, content, config) { ctx = core.getContextByName(ctx); if (!ctx) return; @@ -533,316 +502,215 @@ ui.prototype.drawTextContent = function (ctx, content, config) { config.left = config.left || 0; config.right = config.left + (config.maxWidth == null ? ctx.canvas.width : config.maxWidth); config.top = config.top || 0; - config.color = config.color || "#FFFFFF"; - config.align = config.align || "left"; + config.color = config.color || core.arrayToRGBA(core.status.textAttribute.text); + config.bold = config.bold || false; + config.align = config.align || core.status.textAttribute.align || "left"; config.fontSize = config.fontSize || core.status.textAttribute.textfont; - config.lineHeight = config.lineHeight || (config.fontSize * 1.2); + config.lineHeight = config.lineHeight || (config.fontSize * 1.3); config.time = config.time || 0; config.index = 0; - config.changed = true; config.currcolor = config.color; config.offsetX = 0; config.offsetY = 0; + config.line = 0; + config.blocks = []; // 创建一个新的临时画布 - var tempCtx = document.createElement('canvas').getContext('2d'); - tempCtx.canvas.height = config.lineHeight; + var tempCtx = core.bigmap.tempCanvas; + tempCtx.canvas.height = ctx.canvas.height; tempCtx.canvas.width = ctx.canvas.width; + var _textBaseLine = tempCtx.textBaseline; tempCtx.textBaseline = 'top'; - tempCtx.font = this._buildFont(config.fontSize); - + tempCtx.font = this._buildFont(config.fontSize, config.bold); + tempCtx.fillStyle = config.color; this._drawTextContent_draw(ctx, tempCtx, content, config); + tempCtx.textBaseline = _textBaseLine; } +// 绘制的基本逻辑: +// 1. 一个个字符绘制到对应画布上(靠左对齐);这个过程中,记下来每个字对应的方块 [x, y, w, h] +// 2. 每次换行时,计算当前行的宽度,然后如果是居中或者靠右对齐,则对当前行的每个小方块增加偏移量 +// 3. 实际绘制时,从临时画布直接将一个个小方块绘制到目标画布上,一次全部绘制,或者打字机效果一个个绘制 ui.prototype._drawTextContent_draw = function (ctx, tempCtx, content, config) { + // Step 1: 绘制到tempCtx上,并记录下图块信息 + while (this._drawTextContent_next(tempCtx, content, config)); + + // Step 2: 从tempCtx绘制到画布上 + config.index = 0; + var _drawNext = function () { + if (config.index >= config.blocks.length) return false; + var block = config.blocks[config.index++]; + ctx.drawImage(tempCtx.canvas, block.left, block.top, block.width, block.height, + config.left + block.left + block.marginLeft, config.top + block.top, block.width, block.height); + return true; + } if (config.time == 0) { - while (!core.ui._drawTextContent_next(ctx, tempCtx, content, config)); - core.ui._drawTextContent_drawLineToCtx(ctx, tempCtx, content, config); + while (_drawNext()); } else { core.status.event.interval = setInterval(function () { - config.changed = true; - if (!core.ui._drawTextContent_next(ctx, tempCtx, content, config)) { + if (!_drawNext()) { clearInterval(core.status.event.interval); core.status.event.interval = null; - core.ui._drawTextContent_drawLineToCtx(ctx, tempCtx, content, config); } - }, time); + }, config.time); } } -// 进行下一次绘制 -ui.prototype._drawTextContent_next = function (ctx, tempCtx, content, config) { - if (config.index >= content.length) return false; - // 是否需要改变颜色 - if (config.changed) { - core.setFillStyle(tempCtx, config.currcolor); - config.changed = false; +ui.prototype._drawTextContent_next = function (tempCtx, content, config) { + if (config.index >= content.length) { + this._drawTextContent_newLine(tempCtx, config); + return false; } // get next character var ch = content.charAt(config.index++); - return this._drawTextContent_drawChar(ctx, tempCtx, content, config, ch); + return this._drawTextContent_drawChar(tempCtx, content, config, ch); } // 绘制下一个字符 -ui.prototype._drawTextContent_drawChar = function (ctx, tempCtx, content, config, ch) { +ui.prototype._drawTextContent_drawChar = function (tempCtx, content, config, ch) { // \n, \\n if (ch == '\n' || (ch=='\\' && content.charAt(config.index)=='n')) { - this._drawTextContent_drawLineToCtx(ctx, tempCtx, content, config); + this._drawTextContent_newLine(tempCtx, config); if (ch=='\\') config.index++; - return this._drawTextContent_next(ctx, tempCtx, content, config); + return this._drawTextContent_next(tempCtx, content, config); } // \r, \\r if (ch == '\r' || (ch=='\\' && content.charAt(config.index)=='r')) { if (ch == '\\') config.index++; - return this._drawTextContent_changeColor(ctx, tempCtx, content, config); + return this._drawTextContent_changeColor(tempCtx, content, config); } // \\i 绘制图标 if (ch == '\\' && content.charAt(config.index)=='i') { - return this._drawTextContent_drawIcon(ctx, tempCtx, content, config); + return this._drawTextContent_drawIcon(tempCtx, content, config); } // 检查是不是自动换行 var charwidth = core.calWidth(tempCtx, ch); if (config.maxWidth != null && config.offsetX + charwidth > config.maxWidth) { - this._drawTextContent_drawLineToCtx(ctx, tempCtx, content, config); + this._drawTextContent_newLine(tempCtx, config); config.index--; - return this._drawTextContent_next(ctx, tempCtx, content, config); + return this._drawTextContent_next(tempCtx, content, config); } // 输出 - core.fillText(tempCtx, ch, config.offsetX, 0); + var left = config.offsetX, top = config.offsetY + (config.lineHeight - config.fontSize) / 2; + core.fillText(tempCtx, ch, left, top); + config.blocks.push({left: config.offsetX, top: config.offsetY, + width: charwidth, height: config.lineHeight, line: config.line, marginLeft: 0}); config.offsetX += charwidth; return true; } -// 从临时画布绘制到正式画布上面 -ui.prototype._drawTextContent_drawLineToCtx = function (ctx, tempCtx, content, config) { - // 计算坐标,宽高 - var left = config.left, top = config.top + config.offsetY; - var width = config.offsetX, height = config.lineHeight; - // 计算起点横坐标 +ui.prototype._drawTextContent_newLine = function (tempCtx, config) { + // 计算偏移量 + var width = config.offsetX, totalWidth = config.right - config.left; + var marginLeft = 0; if (config.align == 'center') - left = (config.left + config.right - width) / 2; + marginLeft = (totalWidth - width) / 2; else if (config.align == 'right') - left = config.right - width; + marginLeft = totalWidth - width; - core.drawImage(ctx, tempCtx.canvas, 0, 0, width, height, left, top, width, height); + config.blocks.forEach(function (b) { + if (b.line == config.line) + b.marginLeft = marginLeft; + }); config.offsetX = 0; config.offsetY += config.lineHeight; + config.line++; } -ui.prototype._drawTextContent_changeColor = function (ctx, tempCtx, content, config) { - config.changed = true; +ui.prototype._drawTextContent_changeColor = function (tempCtx, content, config) { // 检查是不是 [] var index = config.index, index2; if (content.charAt(index) == '[' && ((index2=content.indexOf(']', index))>=0)) { // 变色 var str = content.substring(index+1, index2); - if (str=="") config.currcolor = config.color; - else config.currcolor = str; + if (str=="") tempCtx.fillStyle = config.color; + else tempCtx.fillStyle = str; config.index = index2 + 1; } - else config.currcolor = color; - return this._drawTextContent_next(ctx, tempCtx,content, config); + else tempCtx.fillStyle = config.color; + return this._drawTextContent_next(tempCtx, content, config); } -ui.prototype._drawTextContent_drawIcon = function (ctx, tempCtx, content, config) { +ui.prototype._drawTextContent_drawIcon = function (tempCtx, content, config) { // 绘制一个 \i 效果 var index = config.index, index2; if (content.charAt(config.index+1) == '[' && ((index2=content.indexOf(']', index+1))>=0)) { var str = content.substring(index+2, index2); // --- 获得图标 var iconInfo = core.ui._getDrawableIconInfo(str), image = iconInfo[0], icon = iconInfo[1]; - if (image == null) return this._drawTextContent_next(ctx, tempCtx, content, config); + if (image == null) return this._drawTextContent_next(tempCtx, content, config); // 检查自动换行 - var width = config.fontSize + 2, left = config.offsetX + 2, top = (config.lineHeight - width) / 2; + var width = config.fontSize + 2, left = config.offsetX + 2, top = config.offsetY + (config.lineHeight - width) / 2 - 1; if (config.maxWidth != null && left + width > config.maxWidth) { - this._drawTextContent_drawLineToCtx(ctx, tempCtx, content, config); + this._drawTextContent_newLine(tempCtx, config); config.index--; - this._drawTextContent_next(ctx, tempCtx, content, config); + this._drawTextContent_next(tempCtx, content, config); } // 绘制到画布上 core.drawImage(tempCtx, image, 0, 32*icon, 32, 32, left, top, width, width); + + config.blocks.push({left: left, top: config.offsetY, + width: config.lineHeight, height: config.lineHeight, line: config.line, marginLeft: 0}); + config.offsetX += width + 6; config.index = index2 + 1; return true; } - return this._drawTextContent_next(ctx, tempCtx, content, config); + return this._drawTextContent_next(tempCtx, content, config); } -ui.prototype.__drawText = function (canvas, content, content_left, content_top, valid_width, - color, per_height, text_font, time) { - core.setTextAlign(canvas, 'left'); - - var offsetx = content_left, offsety = content_top; - core.setFillStyle(canvas, color); - var index = 0, currcolor = color, changed = false; - - var drawNext = function () { - if (index >= content.length) return false; - if (changed) { - core.setFillStyle(canvas, currcolor); - changed = false; - } - - // get next character - var ch = content.charAt(index++); - // \n, \\n - if (ch == '\n' || (ch=='\\' && content.charAt(index)=='n')) { - offsetx = content_left; - offsety += per_height; - if (ch=='\\') index++; - return drawNext(); - } - // \r, \\r - if (ch == '\r' || (ch=='\\' && content.charAt(index)=='r')) { - if (ch == '\\') index++; - changed = true; - // 检查是不是 [] - var index2; - if (content.charAt(index) == '[' && ((index2=content.indexOf(']', index))>=0)) { - // 变色 - var str = content.substring(index+1, index2); - if (str=="") currcolor = color; - else currcolor = str; - index = index2+1; - } - else currcolor = color; - return drawNext(); - } - // \\i 绘制图标 - if (ch == '\\' && content.charAt(index)=='i') { - // 绘制图标 - var index2; - if (content.charAt(index+1) == '[' && ((index2=content.indexOf(']', index+1))>=0)) { - var str = content.substring(index+2, index2); - // --- 获得图标 - var iconInfo = core.ui._getDrawableIconInfo(str), image = iconInfo[0], icon = iconInfo[1]; - if (image != null) { - if (core.isset(valid_width) && offsetx + text_font + 6 > content_left + valid_width) { - index --; - offsetx = content_left; - offsety += per_height; - return drawNext(); - } - // --- 绘制 - core.drawImage(canvas, image, 0, 32*icon, 32, 32, offsetx + 2, offsety - text_font + 1, text_font+2, text_font+2); - offsetx += text_font + 6; - index = index2+1; - return true; - } - } - } - // 检查是不是自动换行 - var charwidth = core.calWidth(canvas, ch); - if (core.isset(valid_width) && offsetx + charwidth > content_left + valid_width) { - index--; - offsetx = content_left; - offsety += per_height; - return drawNext(); - } - // 输出 - core.fillText(canvas, ch, offsetx, offsety); - offsetx += charwidth; - return true; - }; - - if (!core.isset(time) || time<=0) while (drawNext()); - else { - core.status.event.interval = setInterval(function () { - changed = true; - if (!drawNext()) { - clearInterval(core.status.event.interval); - core.status.event.interval = null; - } - }, time); - } +ui.prototype._getRealContent = function (content) { + return content.replace(/(\r|\\r)(\[.*?])?/g, "").replace(/(\\i)(\[.*?])?/g, "占1"); } ////// 绘制一个对话框 ////// ui.prototype.drawTextBox = function(content, showAll) { - - if (core.isset(core.status.event) && core.status.event.id=='action') { + if (core.status.event && core.status.event.id == 'action') core.status.event.ui = content; - } clearInterval(core.status.event.interval); core.status.event.interval = null; - - // 获得name, image, icon - var info = this.getTitleAndIcon(content); - content = info.content; - var id=info.id, name=info.name, image=info.image, icon=info.icon, iconHeight=info.iconHeight, animate=info.animate; - - // 获得颜色的盒子等信息 - var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; - var titlefont = textAttribute.titlefont || 22; - var textfont = textAttribute.textfont || 16; - var offset = textAttribute.offset || 0; - var background = core.status.textAttribute.background; - var isWindowSkin = false; - if (typeof background == 'string') { - background = core.material.images.images[background]; - if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; - else background = core.initStatus.textAttribute.background; - } - - var titleColor = core.arrayToRGBA(textAttribute.title); - var textColor = core.arrayToRGBA(textAttribute.text); - var borderColor = core.status.globalAttribute.borderColor; - var alpha = isWindowSkin?0.85:background[3]; - - // 获得位置信息 - var position = textAttribute.position, px=null, py=null, ydelta=iconHeight-32; - if (content.indexOf("\b[")==0 || content.indexOf("\\b[")==0) { - var index = content.indexOf("]"); - if (index>=0) { - var str = content.substring(2, index); - if (content.indexOf("\\b[")==0) str = content.substring(3, index); - content = content.substring(index + 1); - - var ss=str.split(","); - - if (ss[0]=='up' || ss[0]=='center' || ss[0]=='down') { - position=ss[0]; - if (core.status.event.id=='action') { - px = core.status.event.data.x; - py = core.status.event.data.y; - } - else { - px = null; py=null; - } - - if (ss.length>=2) { - if (ss[1]=='hero') { - px=core.getHeroLoc('x'); - py=core.getHeroLoc('y'); - ydelta = core.material.icons.hero.height-32; - } - else if (ss[1] == 'null') { - px = py = null; - } - else if (ss.length>=3) { - px=parseInt(ss[1]); - py=parseInt(ss[2]); - } - } - } - } - } + core.status.boxAnimateObjs = []; + core.clearSelector(); + core.clearMap('ui'); content = core.replaceText(content); - core.status.boxAnimateObjs = []; - core.clearSelector(); + // Step 1: 获得标题信息和位置信息 + var textAttribute = core.status.textAttribute; + var titleInfo = this._getTitleAndIcon(content); + var posInfo = this._getPosition(titleInfo.content); + if (!posInfo.position) posInfo.position = textAttribute.position; + if (posInfo.position != 'up' && posInfo.position != 'down') posInfo.px = posInfo.py = null; + content = this._drawTextBox_drawImages(posInfo.content); - // drawImage - content = content.replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { + // Step 2: 计算对话框的矩形位置 + var hPos = this._drawTextBox_getHorizontalPosition(content, titleInfo, posInfo); + var vPos = this._drawTextBox_getVerticalPosition(content, titleInfo, posInfo, hPos.validWidth); + + // Step 3: 绘制背景图 + var isWindowSkin = this._drawTextBox_drawBackground(titleInfo, posInfo, hPos, vPos); + var alpha = isWindowSkin ? 0.85 : (textAttribute.background[3] || core.initStatus.textAttribute.background[3]); + + // Step 4: 绘制标题、头像、 + var content_top = this._drawTextBox_drawTitleAndIcon(titleInfo, hPos, vPos, alpha); + + // Step 5: 绘制正文 + this.drawTextContent('ui', content, { + left: hPos.content_left, top: content_top, maxWidth: hPos.validWidth, + lineHeight: vPos.lineHeight, time: (showAll || textAttribute.time<=0 || core.status.event.id!='action')?0:textAttribute.time + }); +} + +ui.prototype._drawTextBox_drawImages = function (content) { + return content.replace(/(\f|\\f)\[(.*?)]/g, function (text, sympol, str) { var ss = str.split(","); if (ss.length!=3 && ss.length!=5 && ss.length!=9) return ""; var img = core.material.images.images[ss[0]]; - if (!core.isset(img)) return ""; + if (!img) return ""; // 绘制 if (ss.length==3) core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2])); @@ -852,184 +720,183 @@ ui.prototype.drawTextBox = function(content, showAll) { core.drawImage('ui', img, parseFloat(ss[1]), parseFloat(ss[2]), parseFloat(ss[3]), parseFloat(ss[4]), parseFloat(ss[5]), parseFloat(ss[6]), parseFloat(ss[7]), parseFloat(ss[8])); return ""; }); +} - var globalFont = core.status.globalAttribute.font; - var font = textfont + 'px '+globalFont; - if (textAttribute.bold) font = "bold "+font; - var realContent = content.replace(/(\r|\\r)(\[.*?])?/g, "").replace(/(\\i)(\[.*?])?/g, "啊1"); - - var leftSpace = 25, rightSpace = 12; - if (core.isset(px) && core.isset(py)) leftSpace = 20; - if (id=='hero' || core.isset(icon)) leftSpace = 62; // 行走图:15+32+15 - else if (core.isset(image)) leftSpace = 90; // 大头像:10+70+10 - var left = 7, right = 416 - left, width = right - left, validWidth = width - leftSpace - rightSpace; - +ui.prototype._drawTextBox_getHorizontalPosition = function (content, titleInfo, posInfo) { + var realContent = this._getRealContent(content); + var paddingLeft = 25, paddingRight = 12; + if (posInfo.px != null && posInfo.py != null) paddingLeft = 20; + if (titleInfo.icon != null) paddingLeft = 62; // 15 + 32 + 15 + else if (titleInfo.image) paddingLeft = 90; // 10 + 70 + 10 + var left = 7 + 3 * (this.HSIZE - 6), right = this.PIXEL - left, + width = right - left, validWidth = width - paddingLeft - paddingRight; // 对话框效果:改为动态计算 - if (core.isset(px) && core.isset(py)) { - var min_width = 220 - leftSpace, max_width = validWidth; + if (posInfo.px != null && posInfo.py != null) { + var min_width = 220 - paddingLeft, max_width = validWidth; // 无行走图或头像,则可以适当缩小min_width - if (leftSpace == 20) min_width = 160; - core.setFont('ui', font); - validWidth = this.calTextBoxWidth('ui', realContent, min_width, max_width); - width = validWidth + leftSpace + rightSpace; - // left必须在7~416-7-width区间内,以保证left>=7,right<=416-7 - left = core.clamp(32*px+16-width/2-core.bigmap.offsetX, 7, 416-7-width); + if (titleInfo.image == null) min_width = 160; + validWidth = this.calTextBoxWidth('ui', realContent, min_width, max_width, this._buildFont()); + width = validWidth + paddingLeft + paddingRight; + left = core.clamp(32 * posInfo.px + 16 - width / 2 - core.bigmap.offsetX, left, right - width); right = left + width; } + return { left: left, right: right, width: width, validWidth: validWidth, xoffset: 11, content_left: left + paddingLeft }; +} - var content_left = left + leftSpace; - var height = 30 + (textfont+5)*core.splitLines("ui", realContent, validWidth, font).length; - if (core.isset(name)) height += titlefont + 5; - if (id == 'hero') - height = Math.max(height, core.material.icons.hero.height+50); - else if (core.isset(icon)) - height = Math.max(height, iconHeight+50); - else if (core.isset(image)) +ui.prototype._drawTextBox_getVerticalPosition = function (content, titleInfo, posInfo, validWidth) { + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; + var lineHeight = textAttribute.textfont + 5; + var realContent = this._getRealContent(content); + var height = 30 + lineHeight * core.splitLines("ui", realContent, validWidth, this._buildFont()).length; + if (titleInfo.title) height += textAttribute.titlefont + 5; + if (titleInfo.icon != null) + height = Math.max(height, titleInfo.height+50); + else if (titleInfo.image) height = Math.max(height, 90); - var xoffset = 11, yoffset = 16; - - var top; - if (position=='center') { - top = parseInt((416 - height) / 2); - } - else if (position=='up') { - if (px==null || py==null) - top = 5 + offset; - else { - top = 32 * py - height - ydelta - yoffset; - top -= core.bigmap.offsetY; - } - } - else if (position=='down') { - if (px==null || py==null) - top = 416 - height - 5 - offset; - else { - top = 32 * py + 32 + yoffset; - top -= core.bigmap.offsetY; - } - } - var bottom = top + height; - - if (isWindowSkin) { - core.setAlpha('ui', alpha); - this.drawWindowSkin(background,'ui',left,top,width,height,position,px==null?null:px*32-core.bigmap.offsetX,py==null?null:py*32-core.bigmap.offsetY); - core.setAlpha('ui', 1); - } - else { - yoffset -= 4; - core.setAlpha('ui', alpha); - core.setStrokeStyle('ui', borderColor); - core.setFillStyle('ui', core.arrayToRGB(background)); - core.setLineWidth('ui', 2); - // 绘制 - var canvas = core.canvas.ui; - canvas.beginPath(); - canvas.moveTo(left,top); - // 上边缘 - if (position=='down' && core.isset(px) && core.isset(py)) { - canvas.lineTo(32*px+xoffset - core.bigmap.offsetX, top); - canvas.lineTo(32*px+16 - core.bigmap.offsetX, top-yoffset); - canvas.lineTo(32*(px+1)-xoffset - core.bigmap.offsetX, top); - } - canvas.lineTo(right, top); - canvas.lineTo(right, bottom); - // 下边缘 - if (position=='up' && core.isset(px) && core.isset(py)) { - canvas.lineTo(32*(px+1)-xoffset - core.bigmap.offsetX, bottom); - canvas.lineTo(32*px+16 - core.bigmap.offsetX, bottom+yoffset); - canvas.lineTo(32*px+xoffset - core.bigmap.offsetX, bottom); - } - canvas.lineTo(left, bottom); - canvas.closePath(); - canvas.fill(); - canvas.stroke(); - core.setAlpha('ui', 1); - } - // 名称 - core.setTextAlign('ui', 'left'); - - var content_top = top + 15 + textfont; - if (core.isset(id)) { - - content_top += (titlefont + 5); - core.setFillStyle('ui', titleColor); - core.setStrokeStyle('ui', titleColor); - - if (id == 'hero') { - var heroHeight=core.material.icons.hero.height; - core.setAlpha('ui', alpha); - core.strokeRect('ui', left + 15 - 1, top + 40 - 1, 34, heroHeight+2, null, 2); - core.setAlpha('ui', 1); - core.fillText('ui', name, content_left, top + 8 + titlefont, null, 'bold '+titlefont+'px '+globalFont); - core.clearMap('ui', left + 15, top + 40, 32, heroHeight); - core.fillRect('ui', left + 15, top + 40, 32, heroHeight, core.material.groundPattern); - var heroIcon = core.material.icons.hero['down']; - core.drawImage('ui', core.material.images.hero, heroIcon.stop * 32, heroIcon.loc * heroHeight, 32, heroHeight, left+15, top+40, 32, heroHeight); - } - else { - core.fillText('ui', name, content_left, top + 8 + titlefont, null, 'bold '+titlefont+'px '+globalFont); - if (core.isset(icon)) { - core.setAlpha('ui', alpha); - core.strokeRect('ui', left + 15 - 1, top + 40-1, 34, iconHeight + 2, null, 2); - core.setAlpha('ui', 1); - core.status.boxAnimateObjs = []; - core.status.boxAnimateObjs.push({ - 'bgx': left + 15, 'bgy': top + 40, 'bgWidth': 32, 'bgHeight': iconHeight, - 'x': left+15, 'y': top+40, 'height': iconHeight, 'animate': animate, - 'image': image, - 'pos': icon*iconHeight - }); - core.drawBoxAnimate(); + var yoffset = 16; + var top = parseInt((this.PIXEL - height) / 2); + switch (posInfo.position) { + case 'center': top = parseInt((this.PIXEL - height) / 2); break; + case 'up': + if (posInfo.px==null || posInfo.py==null) + top = 5 + textAttribute.offset; + else + top = 32 * posInfo.py - height - (titleInfo.height - 32) - yoffset - core.bigmap.offsetY; + break; + case 'down': + if (posInfo.px==null || posInfo.py==null) + top = this.PIXEL - height - 5 - textAttribute.offset; + else { + top = 32 * posInfo.py + 32 + yoffset - core.bigmap.offsetY; } + } + + return { top: top, height: height, bottom: top + height, yoffset: yoffset, lineHeight: lineHeight }; +} + +ui.prototype._drawTextBox_drawBackground = function (titleInfo, posInfo, hPos, vPos) { + var background = core.status.textAttribute.background; + var px = posInfo.px == null ? null : posInfo.px * 32 - core.bigmap.offsetX; + var py = posInfo.py == null ? null : posInfo.py * 32 - core.bigmap.offsetY; + var xoffset = hPos.xoffset, yoffset = vPos.yoffset - 4; + var left = hPos.left, right = hPos.right, top = vPos.top, bottom = vPos.bottom; + + if (typeof background == 'string' && core.material.images.images[background]) { + var image = core.material.images.images[background]; + if (image.width==192 && image.height==128) { + core.setAlpha('ui', 0.85); + this.drawWindowSkin(image, 'ui', left, top, right - left, bottom - top, posInfo.position, px, py); + core.setAlpha('ui', 1); + return true; + } + background = core.initStatus.textAttribute.background; + } + + var alpha = background[3]; + core.setAlpha('ui', alpha); + core.setStrokeStyle('ui', core.status.globalAttribute.borderColor); + core.setFillStyle('ui', core.arrayToRGB(background)); + core.setLineWidth('ui', 2); + + // 绘制 + var ctx = core.canvas.ui; + ctx.beginPath(); + ctx.moveTo(left, top); + // 上边缘三角 + if (posInfo.position == 'down' && px != null && py != null) { + ctx.lineTo(px + xoffset, top); + ctx.lineTo(px + 16, top - yoffset); + ctx.lineTo(px + 32 - xoffset, top); + } + ctx.lineTo(right, top); + ctx.lineTo(right, bottom); + // 下边缘三角 + if (posInfo.position == 'up' && px != null && py != null) { + ctx.lineTo(px + 32 - xoffset, bottom); + ctx.lineTo(px + 16, bottom + yoffset); + ctx.lineTo(px + xoffset, bottom); + } + ctx.lineTo(left, bottom); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + core.setAlpha('ui', 1); + return false; +} + +ui.prototype._drawTextBox_drawTitleAndIcon = function (titleInfo, hPos, vPos, alpha) { + core.setTextAlign('ui', 'left'); + var textAttribute = core.status.textAttribute; + var content_top = vPos.top + 15; + if (titleInfo.title != null) { + var titlefont = textAttribute.titlefont; + content_top += titlefont + 5; + core.setFillStyle('ui', core.arrayToRGB(textAttribute.title)); + core.setStrokeStyle('ui', core.arrayToRGB(textAttribute.title)); + + // --- title也要居中或者右对齐? + var title_width = core.calWidth('ui', titleInfo.title, 'bold '+titlefont+'px '+core.status.globalAttribute.font); + var title_left = hPos.content_left; + if (textAttribute.align == 'center') + title_left = hPos.left + (hPos.width - title_width) / 2; + else if (textAttribute.align == 'right') + title_left = hPos.right - title_width - 12; + + core.fillText('ui', titleInfo.title, title_left, vPos.top + 8 + titlefont); + + if (titleInfo.icon != null) { + core.setAlpha('ui', alpha); + core.strokeRect('ui', hPos.left + 15 - 1, vPos.top + 40-1, 34, titleInfo.height + 2, null, 2); + core.setAlpha('ui', 1); + core.status.boxAnimateObjs = []; + core.status.boxAnimateObjs.push({ + 'bgx': hPos.left + 15, 'bgy': vPos.top + 40, 'bgWidth': 32, 'bgHeight': titleInfo.height, + 'x': hPos.left + 15, 'y': vPos.top + 40, 'height': titleInfo.height, 'animate': titleInfo.animate, + 'image': titleInfo.image, 'pos': titleInfo.icon * titleInfo.height + }); + core.drawBoxAnimate(); } } - if (core.isset(image) && !core.isset(icon)) { - core.drawImage('ui', image, 0, 0, image.width, image.height, left+10, top+10, 70, 70); + if (titleInfo.image != null && titleInfo.icon == null) { // 头像图 + core.drawImage('ui', titleInfo.image, 0, 0, titleInfo.image.width, titleInfo.image.height, + hPos.left+10, vPos.top+10, 70, 70); } + return content_top; +} - core.setFont('ui', font); - - this.__drawText('ui', content, content_left, content_top, validWidth, textColor, textfont + 5, textfont, - (showAll || textAttribute.time<=0 || core.status.event.id!='action')?0:textAttribute.time); - +ui.prototype._createTextCanvas = function (content, lineHeight) { + var realContent = this._getRealContent(content); + var lines = core.splitLines('ui', realContent, null, this._buildFont()); + var width = this.PIXEL, height = lines.length * lineHeight; + var ctx = document.createElement('canvas').getContext('2d'); + ctx.canvas.width = width; + ctx.canvas.height = height; + ctx.clearRect(0, 0, width, height); } ////// 绘制滚动字幕 ////// ui.prototype.drawScrollText = function (content, time, callback) { - - content = content || ""; + content = core.replaceText(content || ""); time = time || 5000; - clearInterval(core.status.event.interval); core.status.event.interval = null; + var offset = core.status.textAttribute.offset || 15; + var lineHeight = core.status.textAttribute.textfont * 1.4; + var ctx = this._createTextCanvas(content, lineHeight); + var obj = { align: core.status.textAttribute.align, lineHeight: lineHeight }; + if (obj.align == 'right') obj.left = this.PIXEL - offset; + else if (obj.align != 'center') obj.left = offset; + this.drawTextContent(ctx, content, obj); + this._drawScrollText_animate(ctx, height, time, callback); +} - // 获得颜色的盒子等信息 - var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; - var textfont = textAttribute.textfont || 16; - var offset = textAttribute.offset || 15; - var textColor = core.arrayToRGBA(textAttribute.text); - - var font = textfont+"px "+core.status.globalAttribute.font; - if (textAttribute.bold) font = "bold "+font; - var realContent = content.replace(/(\r|\\r)(\[.*?])?/g, "").replace(/(\\i)(\[.*?])?/g, "啊1"); - var contents = core.splitLines('ui', realContent), lines = contents.length; - - // 计算总高度,按1.4倍行距计算 - var width = 416, height = textfont * 1.4 * lines; - var tempCanvas = core.bigmap.tempCanvas; - tempCanvas.canvas.width = width; - tempCanvas.canvas.height = height; - tempCanvas.clearRect(0, 0, width, height); - tempCanvas.font = font; - - this.__drawText(tempCanvas, content, offset, textfont, null, textColor, 1.4*textfont, textfont, 0); - +ui.prototype._drawScrollText_animate = function (ctx, height, time, callback) { // 开始绘制到UI上 core.clearMap('ui'); var per_pixel = 1, per_time = time * per_pixel / (416+height); var currH = 416; - core.drawImage('ui', tempCanvas.canvas, 0, currH); + core.drawImage('ui', ctx.canvas, 0, currH); var animate = setInterval(function () { core.clearMap('ui'); currH -= per_pixel; @@ -1039,197 +906,139 @@ ui.prototype.drawScrollText = function (content, time, callback) { if (core.isset(callback)) callback(); return; } - core.drawImage('ui', tempCanvas.canvas, 0, currH); + core.drawImage('ui', ctx.canvas, 0, currH); }, per_time); core.animateFrame.asyncId[animate] = true; } +////// 文本图片化 ////// +ui.prototype.textImage = function (content) { + content = core.replaceText(content || ""); + var lineHeight = core.status.textAttribute.textfont * 1.4; + var ctx = this._createTextCanvas(content, lineHeight); + this.drawTextContent(ctx, content, { align: core.status.textAttribute.align, lineHeight: lineHeight }); + return ctx.canvas; +} + ////// 绘制一个选项界面 ////// ui.prototype.drawChoices = function(content, choices) { choices = core.clone(choices || []); - var background = core.status.textAttribute.background; - var isWindowSkin = false; - if (typeof background == 'string') { - background = core.material.images.images[background]; - if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; - else background = core.initStatus.textAttribute.background; - } - if (!isWindowSkin) background = core.arrayToRGBA(background); - var borderColor = core.status.globalAttribute.borderColor; - var textColor = core.arrayToRGBA(core.status.textAttribute.text); - var titleColor = core.arrayToRGBA(core.status.textAttribute.title); - core.status.event.ui = {"text": content, "choices": choices}; + clearInterval(core.status.event.interval); + core.status.event.interval = null; + core.status.boxAnimateObjs = []; + core.clearSelector(); + core.clearMap('ui'); - // Step 1: 计算长宽高 - var length = choices.length; + content = core.replaceText(content || ""); + var titleInfo = this._getTitleAndIcon(content); + var hPos = this._drawChoices_getHorizontalPosition(titleInfo, choices); + var vPos = this._drawChoices_getVerticalPosition(titleInfo, choices, hPos); + var isWindowSkin = this._drawTextBox_drawBackground(titleInfo, {}, hPos, vPos); + this._drawChoices_drawTitle(titleInfo, hPos, vPos); + this._drawChoices_drawChoices(choices, isWindowSkin, hPos, vPos); +} + +ui.prototype._drawChoices_getHorizontalPosition = function (titleInfo, choices) { // 宽度计算:考虑选项的长度 - var width = 416 - 2*85; - var globalFont = core.status.globalAttribute.font; - core.setFont('ui', "bold 17px "+globalFont); + var width = this.PIXEL - 2 * 85; + core.setFont('ui', "bold 17px "+core.status.globalAttribute.font); for (var i = 0; i < choices.length; i++) { if (typeof choices[i] === 'string') choices[i] = {"text": choices[i]}; choices[i].text = core.replaceText(choices[i].text); choices[i].width = core.calWidth('ui', core.replaceText(choices[i].text)); - if (core.isset(choices[i].icon)) choices[i].width += 28; + if (choices[i].icon != null) choices[i].width += 28; width = Math.max(width, choices[i].width+30); } + var left = (this.PIXEL - width) / 2, right = left + width; + var content_left = left + (titleInfo.icon == null ? 15: 60), validWidth = right - content_left - 10; - var left=parseInt((416 - width) / 2); // 左边界 - // 高度 - var height = 32*(length+2), bottom = 208+height/2; - if (length%2==0) bottom+=16; - var choice_top = bottom-height+56; + return { left: left, right: right, width: width, content_left: content_left, validWidth: validWidth }; +} - var id=null, name=null, image=null, icon=null, iconHeight=32, animate=null; - - var contents = null; - var content_left = left + 15; - var validWidth = width-(content_left-left)-10; - - if (core.isset(content)) { - // 获得name, image, icon - var info = this.getTitleAndIcon(content); - content = core.replaceText(info.content); - var realContent = content.replace(/(\r|\\r)(\[.*?])?/g, "").replace(/(\\i)(\[.*?])?/g, "啊1"); - id=info.id; name=info.name; image=info.image; - icon=info.icon; iconHeight=info.iconHeight; animate=info.animate; - if (id=='hero' || core.isset(icon)) - content_left = left+60; - validWidth = width-(content_left-left)-10 - contents = core.splitLines('ui', realContent, validWidth, 'bold 15px '+globalFont); - - // content部分高度 - var cheight=0; - // 如果含有标题,标题高度 - if (name!=null) cheight+=25; - cheight += contents.length*20; - height+=cheight; +ui.prototype._drawChoices_getVerticalPosition = function (titleInfo, choices, hPos) { + var length = choices.length; + var height = 32 * (length + 2), bottom = this.HPIXEL + height / 2; + if (length % 2 == 0) bottom += 16; + var choice_top = bottom - height + 56; + if (titleInfo.content) { + var realContent = this._getRealContent(titleInfo.content); + var lines = core.splitLines('ui', realContent, hPos.validWidth, this._buildFont(15, true)); + if (titleInfo.title) height += 25; + height += lines.length * 20; } - var top = bottom-height; + return {top: bottom - height, height: height, bottom: bottom, choice_top: choice_top }; +} - core.clearMap('ui'); - if (isWindowSkin) { - core.setAlpha('ui', 0.85); - this.drawWindowSkin(background,'ui',left,top,width,height); - } - else { - core.fillRect('ui', left, top, width, height, background); - core.strokeRect('ui', left - 1, top - 1, width + 1, height + 1, borderColor, 2); - } - core.setAlpha('ui', 1); +ui.prototype._drawChoices_drawTitle = function (titleInfo, hPos, vPos) { + if (!titleInfo.content) return; + var content_top = vPos.top + 21; + if (titleInfo.title != null) { + core.setTextAlign('ui', 'center'); - // 如果有内容 - if (core.isset(contents)) { + content_top = vPos.top + 41; + var title_offset = hPos.left+hPos.width/2; + // 动画 - var content_top = top + 35; + if (titleInfo.icon != null) { + title_offset += 12; + core.strokeRect('ui', hPos.left + 15 - 1, vPos.top + 30 - 1, 34, titleInfo.height + 2, '#DDDDDD', 2); + core.status.boxAnimateObjs = []; + core.status.boxAnimateObjs.push({ + 'bgx': hPos.left + 15, 'bgy': vPos.top + 30, 'bgWidth': 32, 'bgHeight': titleInfo.height, + 'x': hPos.left + 15, 'y': vPos.top + 30, 'height': titleInfo.height, 'animate': titleInfo.animate, + 'image': titleInfo.image, 'pos': titleInfo.icon * titleInfo.height + }); + core.drawBoxAnimate(); + }; - if (core.isset(id)) { - core.setTextAlign('ui', 'center'); - - content_top = top+55; - var title_offset = left+width/2; - // 动画 - - if (id=='hero' || core.isset(icon)) - title_offset += 12; - - if (id == 'hero') { - var heroHeight = core.material.icons.hero.height; - core.strokeRect('ui', left + 15 - 1, top + 30 - 1, 34, heroHeight+2, '#DDDDDD', 2); - core.fillText('ui', name, title_offset, top + 27, titleColor, 'bold 19px '+globalFont); - core.clearMap('ui', left + 15, top + 30, 32, heroHeight); - core.fillRect('ui', left + 15, top + 30, 32, heroHeight, core.material.groundPattern); - var heroIcon = core.material.icons.hero['down']; - core.drawImage('ui', core.material.images.hero, heroIcon.stop * 32, heroIcon.loc *heroHeight, 32, heroHeight, left+15, top+30, 32, heroHeight); - } - else { - core.fillText('ui', name, title_offset, top + 27, titleColor, 'bold 19px '+globalFont); - if (core.isset(icon)) { - core.strokeRect('ui', left + 15 - 1, top + 30 - 1, 34, iconHeight + 2, '#DDDDDD', 2); - core.status.boxAnimateObjs = []; - core.status.boxAnimateObjs.push({ - 'bgx': left + 15, 'bgy': top + 30, 'bgWidth': 32, 'bgHeight': iconHeight, - 'x': left+15, 'y': top+30, 'height': iconHeight, 'animate': animate, - 'image': image, - 'pos': icon*iconHeight - }); - core.drawBoxAnimate(); - } - } - } - - core.setFont('ui', 'bold 15px '+globalFont); - this.__drawText('ui', content, content_left, content_top, validWidth, textColor, 20, 15, 0); + core.fillText('ui', titleInfo.title, title_offset, vPos.top + 27, + core.arrayToRGBA(core.status.textAttribute.title), 'bold 19px '+core.status.globalAttribute.font); } + core.setTextAlign('ui', 'left'); + this.drawTextContent('ui', titleInfo.content, { + left: hPos.content_left, top: content_top, maxWidth: hPos.validWidth, + fontSize: 15, lineHeight: 20, bold: true + }); +} + +ui.prototype._drawChoices_drawChoices = function (choices, isWindowSkin, hPos, vPos) { // 选项 core.setTextAlign('ui', 'center'); + core.setFont('ui', "bold 17px " + core.status.globalAttribute.font); for (var i = 0; i < choices.length; i++) { - var color = choices[i].color || textColor; + var color = choices[i].color || core.status.textAttribute.text; if (color instanceof Array) color = core.arrayToRGBA(color); core.setFillStyle('ui', color); - var offset = 208; + var offset = this.HPIXEL; if (core.isset(choices[i].icon)) { var iconInfo = this._getDrawableIconInfo(choices[i].icon), image = iconInfo[0], icon = iconInfo[1]; if (image != null) { - core.drawImage('ui', image, 0, 32*icon, 32, 32, - 208 - choices[i].width/2, choice_top + 32*i - 17, 22, 22); + core.drawImage('ui', image, 0, 32 * icon, 32, 32, + this.HPIXEL - choices[i].width/2, vPos.choice_top + 32*i - 17, 22, 22); offset += 14; } } - core.fillText('ui', choices[i].text, offset, choice_top + 32 * i, null, "bold 17px "+globalFont); + core.fillText('ui', choices[i].text, offset, vPos.choice_top + 32 * i, color); } if (choices.length>0) { - if (!core.isset(core.status.event.selection)) core.status.event.selection=0; - while (core.status.event.selection<0) core.status.event.selection+=choices.length; - while (core.status.event.selection>=choices.length) core.status.event.selection-=choices.length; + core.status.event.selection = core.status.event.selection || 0; + while (core.status.event.selection < 0) core.status.event.selection += choices.length; + while (core.status.event.selection >= choices.length) core.status.event.selection -= choices.length; var len = choices[core.status.event.selection].width; if (isWindowSkin) - this.drawWindowSelector(background, 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28); + this.drawWindowSelector(core.material.images.images[core.status.textAttribute.background], + this.HPIXEL - len/2 - 5, vPos.choice_top + 32 * core.status.event.selection - 20, len + 10, 28); else - core.strokeRect('ui', 208-len/2-5, choice_top + 32 * core.status.event.selection - 20, len+10, 28, "#FFD700", 2); + core.strokeRect('ui', this.HPIXEL - len/2 - 5, vPos.choice_top + 32 * core.status.event.selection - 20, + len+10, 28, "#FFD700", 2); } - return; -} - -////// 文本图片化 ////// -ui.prototype.textImage = function (content) { - content = content || ""; - - // 获得颜色的盒子等信息 - var textAttribute = core.status.textAttribute || core.initStatus.textAttribute; - var textfont = textAttribute.textfont || 16; - var offset = textAttribute.offset || 15; - var textColor = core.arrayToRGBA(textAttribute.text); - - var font = textfont+"px "+core.status.globalAttribute.font; - if (textAttribute.bold) font = "bold "+font; - var contents = core.splitLines('ui', content), lines = contents.length; - - // 计算总高度,按1.4倍行距计算 - var width = 416, height = textfont * 1.4 * lines; - var tempCanvas = core.bigmap.tempCanvas; - tempCanvas.canvas.width = width; - tempCanvas.canvas.height = height; - tempCanvas.clearRect(0, 0, width, height); - tempCanvas.font = font; - tempCanvas.fillStyle = textColor; - - // 全部绘制 - var currH = textfont; - for (var i = 0; i < lines; ++i) { - var text = contents[i]; - tempCanvas.fillText(text, offset, currH); - currH += 1.4 * textfont; - } - - return tempCanvas.canvas; } ////// 绘制一个确认/取消的警告页面 ////// diff --git a/styles.css b/styles.css index 34bed2c4..a1d6649e 100644 --- a/styles.css +++ b/styles.css @@ -312,7 +312,7 @@ p#name { } #ui { - z-index: 160; + z-index: 140; } #data { From 38c8b81f480d737f75158a494c93bab178aea95f Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 24 Mar 2019 16:45:48 +0800 Subject: [PATCH 084/153] actions choices HSIZE --- libs/actions.js | 246 ++++++++++++++++++++++++------------------------ libs/control.js | 2 + libs/ui.js | 2 +- 3 files changed, 128 insertions(+), 122 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 5bf8c43a..37f39db2 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -7,6 +7,11 @@ actions.js:用户交互的事件的处理 function actions() { this._init(); + this.SIZE = core.__SIZE__; + this.HSIZE = core.__HALF_SIZE__; + this.LAST = this.SIZE - 1; + this.CHOICES_LEFT = 5; // choices + this.CHOICES_RIGHT = this.LAST - this.CHOICES_LEFT; } actions.prototype._init = function () { @@ -109,7 +114,7 @@ actions.prototype.checkReplaying = function () { ////// 检查是否在录像播放中,如果是,则停止交互 actions.prototype._sys_checkReplay = function () { - if (core.actions.checkReplaying()) return true; + if (this.checkReplaying()) return true; } ////// 按下某个键时 ////// @@ -127,10 +132,10 @@ actions.prototype._sys_onkeyDown = function (e) { } } core.status.holdingKeys.push(e.keyCode); - core.actions.pressKey(e.keyCode); + this.pressKey(e.keyCode); } else { if (e.keyCode == 17) core.status.ctrlDown = true; - core.actions.keyDown(e.keyCode); + this.keyDown(e.keyCode); } } @@ -140,7 +145,7 @@ actions.prototype.onkeyUp = function (e) { } actions.prototype._sys_onkeyUp_replay = function (e) { - if (core.actions.checkReplaying()) { + if (this.checkReplaying()) { if (e.keyCode == 27) // ESCAPE core.stopReplay(); else if (e.keyCode == 90) // Z @@ -179,10 +184,10 @@ actions.prototype._sys_onkeyUp = function (e) { break; } } - core.actions.keyUp(e.keyCode, e.altKey); + this.keyUp(e.keyCode, e.altKey); } else { if (e.keyCode == 17) core.status.ctrlDown = false; - core.actions.keyUp(e.keyCode, e.altKey); + this.keyUp(e.keyCode, e.altKey); } } @@ -209,32 +214,32 @@ actions.prototype._sys_keyDown_lockControl = function (keyCode) { if (!core.status.lockControl) return false; // Ctrl跳过对话 if (keyCode == 17) { - core.actions.keyDownCtrl(); + this.keyDownCtrl(); return true; } switch (core.status.event.id) { case 'action': - core.actions._keyDownAction(keyCode); + this._keyDownAction(keyCode); break; case 'book': - core.actions._keyDownBook(keyCode); + this._keyDownBook(keyCode); break; case 'fly': - core.actions._keyDownFly(keyCode); + this._keyDownFly(keyCode); break; case 'viewMaps': - core.actions._keyDownViewMaps(keyCode); + this._keyDownViewMaps(keyCode); break; case 'equipbox': - core.actions._keyDownEquipbox(keyCode); + this._keyDownEquipbox(keyCode); break; case 'toolbox': - core.actions._keyDownToolbox(keyCode); + this._keyDownToolbox(keyCode); break; case 'save': case 'load': case 'replayLoad': - core.actions._keyDownSL(keyCode); + this._keyDownSL(keyCode); break; case 'shop': case 'selectShop': @@ -246,10 +251,10 @@ actions.prototype._sys_keyDown_lockControl = function (keyCode) { case 'storageRemove': case 'replay': case 'gameInfo': - core.actions._keyDownChoices(keyCode); + this._keyDownChoices(keyCode); break; case 'cursor': - core.actions._keyDownCursor(keyCode); + this._keyDownCursor(keyCode); break; } return true; @@ -271,7 +276,6 @@ actions.prototype._sys_keyDown = function (keyCode) { case 40: core.moveHero('down'); break; - break; } return true; } @@ -282,7 +286,7 @@ actions.prototype.keyUp = function (keyCode, altKey, fromReplay) { } actions.prototype._sys_keyUp_replay = function (keyCode, altKey, fromReplay) { - if (!fromReplay && core.actions.checkReplaying()) return true; + if (!fromReplay && this.checkReplaying()) return true; } actions.prototype._sys_keyUp_lockControl = function (keyCode, altKey) { @@ -298,81 +302,81 @@ actions.prototype._sys_keyUp_lockControl = function (keyCode, altKey) { ok() && core.drawText(); break; case 'confirmBox': - core.actions._keyUpConfirmBox(keyCode); + this._keyUpConfirmBox(keyCode); break; case 'action': - core.actions._keyUpAction(keyCode); + this._keyUpAction(keyCode); break; case 'about': - ok() && core.ui.closePanel(); + ok() && core.closePanel(); break; case 'help': - ok() && core.ui.closePanel(); + ok() && core.closePanel(); break; case 'book': - core.actions._keyUpBook(keyCode); + this._keyUpBook(keyCode); break; case 'book-detail': - ok() && core.actions._clickBookDetail(); + ok() && this._clickBookDetail(); break; case 'fly': this._keyUpFly(keyCode); break; case 'viewMaps': - core.actions._keyUpViewMaps(keyCode); + this._keyUpViewMaps(keyCode); break; case 'shop': - core.actions._keyUpShop(keyCode); + this._keyUpShop(keyCode); break; case 'selectShop': - core.actions._keyUpQuickShop(keyCode); + this._keyUpQuickShop(keyCode); break; case 'toolbox': - core.actions._keyUpToolbox(keyCode); + this._keyUpToolbox(keyCode); break; case 'equipbox': - core.actions._keyUpEquipbox(keyCode, altKey); + this._keyUpEquipbox(keyCode, altKey); break; case 'save': case 'load': case 'replayLoad': - core.actions._keyUpSL(keyCode); + this._keyUpSL(keyCode); break; case 'keyBoard': - ok() && core.ui.closePanel(); + ok() && core.closePanel(); break; case 'switchs': - core.actions._keyUpSwitchs(keyCode); + this._keyUpSwitchs(keyCode); break; case 'settings': - core.actions._keyUpSettings(keyCode); + this._keyUpSettings(keyCode); break; case 'syncSave': - core.actions._keyUpSyncSave(keyCode); + this._keyUpSyncSave(keyCode); break; case 'syncSelect': - core.actions._keyUpSyncSelect(keyCode); + this._keyUpSyncSelect(keyCode); break; case 'localSaveSelect': - core.actions._keyUpLocalSaveSelect(keyCode); + this._keyUpLocalSaveSelect(keyCode); break; case 'storageRemove': - core.actions._keyUpStorageRemove(keyCode); + this._keyUpStorageRemove(keyCode); break; case 'cursor': - core.actions._keyUpCursor(keyCode); + this._keyUpCursor(keyCode); break; case 'replay': - core.actions._keyUpReplay(keyCode); + this._keyUpReplay(keyCode); break; case 'gameInfo': - core.actions._keyUpGameInfo(keyCode); + this._keyUpGameInfo(keyCode); break; case 'centerFly': - core.actions._keyUpCenterFly(keyCode); + this._keyUpCenterFly(keyCode); break; case 'paint': - core.actions._keyUpPaint(keyCode); + this._keyUpPaint(keyCode); break; } return true; @@ -399,7 +403,7 @@ actions.prototype.ondown = function (loc) { actions.prototype._sys_ondown_paint = function (x, y, px, py) { // 画板 if (core.status.played && (core.status.event || {}).id == 'paint') { - core.actions._ondownPaint(px, py); + this._ondownPaint(px, py); return true; } } @@ -492,7 +496,7 @@ actions.prototype.onup = function () { actions.prototype._sys_onup_paint = function () { // 画板 if (core.status.played && (core.status.event || {}).id == 'paint') { - core.actions._onupPaint(); + this._onupPaint(); return true; } } @@ -567,75 +571,75 @@ actions.prototype._sys_onclick_lockControl = function (x, y) { if (!core.status.lockControl) return false; switch (core.status.event.id) { case 'centerFly': - core.actions._clickCenterFly(x, y); + this._clickCenterFly(x, y); break; case 'book': - core.actions._clickBook(x, y); + this._clickBook(x, y); break; case 'book-detail': - core.actions._clickBookDetail(x, y); + this._clickBookDetail(x, y); break; case 'fly': - core.actions._clickFly(x, y); + this._clickFly(x, y); break; case 'viewMaps': - core.actions._clickViewMaps(x, y); + this._clickViewMaps(x, y); break; case 'switchs': - core.actions._clickSwitchs(x, y); + this._clickSwitchs(x, y); break; case 'settings': - core.actions._clickSettings(x, y); + this._clickSettings(x, y); break; case 'shop': - core.actions._clickShop(x, y); + this._clickShop(x, y); break; case 'selectShop': - core.actions._clickQuickShop(x, y); + this._clickQuickShop(x, y); break; case 'equipbox': - core.actions._clickEquipbox(x, y); + this._clickEquipbox(x, y); break; case 'toolbox': - core.actions._clickToolbox(x, y); + this._clickToolbox(x, y); break; case 'save': case 'load': case 'replayLoad': - core.actions._clickSL(x, y); + this._clickSL(x, y); break; case 'confirmBox': - core.actions._clickConfirmBox(x, y); + this._clickConfirmBox(x, y); break; case 'keyBoard': - core.actions._clickKeyBoard(x, y); + this._clickKeyBoard(x, y); break; case 'action': - core.actions._clickAction(x, y); + this._clickAction(x, y); break; case 'text': core.drawText(); break; case 'syncSave': - core.actions._clickSyncSave(x, y); + this._clickSyncSave(x, y); break; case 'syncSelect': - core.actions._clickSyncSelect(x, y); + this._clickSyncSelect(x, y); break; case 'localSaveSelect': - core.actions._clickLocalSaveSelect(x, y); + this._clickLocalSaveSelect(x, y); break; case 'storageRemove': - core.actions._clickStorageRemove(x, y); + this._clickStorageRemove(x, y); break; case 'cursor': - core.actions._clickCursor(x, y); + this._clickCursor(x, y); break; case 'replay': - core.actions._clickReplay(x, y); + this._clickReplay(x, y); break; case 'gameInfo': - core.actions._clickGameInfo(x, y); + this._clickGameInfo(x, y); break; case 'about': case 'help': @@ -668,15 +672,15 @@ actions.prototype._sys_onmousewheel = function (direct) { // 楼层飞行器 if (core.status.lockControl && core.status.event.id == 'fly') { - if (direct == 1) core.ui.drawFly(core.actions._getNextFlyFloor(1)); - if (direct == -1) core.ui.drawFly(core.actions._getNextFlyFloor(-1)); + if (direct == 1) core.ui.drawFly(this._getNextFlyFloor(1)); + if (direct == -1) core.ui.drawFly(this._getNextFlyFloor(-1)); return; } // 怪物手册 if (core.status.lockControl && core.status.event.id == 'book') { - if (direct == 1) core.ui.drawBook(core.status.event.data - 6); - if (direct == -1) core.ui.drawBook(core.status.event.data + 6); + if (direct == 1) core.ui.drawBook(core.status.event.data - this.HSIZE); + if (direct == -1) core.ui.drawBook(core.status.event.data + this.HSIZE); return; } @@ -689,8 +693,8 @@ actions.prototype._sys_onmousewheel = function (direct) { // 浏览地图 if (core.status.lockControl && core.status.event.id == 'viewMaps') { - if (direct == 1) core.actions._clickViewMaps(6, 3); - if (direct == -1) core.actions._clickViewMaps(6, 9); + if (direct == 1) this._clickViewMaps(this.HSIZE, this.HSIZE - 3); + if (direct == -1) this._clickViewMaps(this.HSIZE, this.HSIZE + 3); return; } @@ -740,7 +744,7 @@ actions.prototype._sys_longClick_lockControl = function (x, y) { // 长按楼传器的箭头可以快速翻页 if (core.status.event.id == 'fly') { if ((x == 10 || x == 11) && (y == 5 || y == 9)) { - core.actions._clickFly(x, y); + this._clickFly(x, y); return true; } } @@ -772,14 +776,14 @@ actions.prototype._sys_longClick = function (x, y, fromEvent) { // 数字键快速选择选项 actions.prototype._selectChoices = function (length, keycode, callback) { - var topIndex = 6 - parseInt((length - 1) / 2); + var topIndex = this.HSIZE - parseInt((length - 1) / 2); if (keycode == 13 || keycode == 32 || keycode == 67) { - callback.apply(this, [6, topIndex + core.status.event.selection]); + callback.apply(this, [this.HSIZE, topIndex + core.status.event.selection]); } if (keycode >= 49 && keycode <= 57) { var index = keycode - 49; if (index < length) { - callback.apply(this, [6, topIndex + index]); + callback.apply(this, [this.HSIZE, topIndex + index]); } } } @@ -824,9 +828,9 @@ actions.prototype._keyUpCenterFly = function (keycode) { ////// 点击确认框时 ////// actions.prototype._clickConfirmBox = function (x, y) { - if ((x == 4 || x == 5) && y == 7 && core.status.event.data.yes) + if ((x == this.HSIZE-2 || x == this.HSIZE-1) && y == this.HSIZE+1 && core.status.event.data.yes) core.status.event.data.yes(); - if ((x == 7 || x == 8) && y == 7 && core.status.event.data.no) + if ((x == this.HSIZE+2 || x == this.HSIZE+1) && y == this.HSIZE+1 && core.status.event.data.no) core.status.event.data.no(); } @@ -877,8 +881,8 @@ actions.prototype._clickAction = function (x, y) { var data = core.status.event.data.current; var choices = data.choices; if (choices.length == 0) return; - if (x >= 5 && x <= 7) { - var topIndex = 6 - parseInt((choices.length - 1) / 2); + if (x >= this.CHOICES_LEFT && x <= this.CHOICES_RIGHT) { + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { // 选择 core.status.route.push("choices:" + (y - topIndex)); @@ -925,17 +929,17 @@ actions.prototype._keyUpAction = function (keycode) { ////// 怪物手册界面的点击操作 ////// actions.prototype._clickBook = function (x, y) { // 上一页 - if ((x == 3 || x == 4) && y == 12) { - core.ui.drawBook(core.status.event.data - 6); + if ((x == this.HSIZE-2 || x == this.HSIZE-3) && y == this.LAST) { + core.ui.drawBook(core.status.event.data - this.HSIZE); return; } // 下一页 - if ((x == 8 || x == 9) && y == 12) { - core.ui.drawBook(core.status.event.data + 6); + if ((x == this.HSIZE+2 || x == this.HSIZE+3) && y == this.LAST) { + core.ui.drawBook(core.status.event.data + this.HSIZE); return; } // 返回 - if (x >= 10 && x <= 12 && y == 12) { + if (x >= this.LAST-2 && y == this.LAST) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -948,9 +952,9 @@ actions.prototype._clickBook = function (x, y) { } // 怪物信息 var data = core.status.event.data; - if (data != null && y < 12) { - var page = parseInt(data / 6); - var index = 6 * page + parseInt(y / 2); + if (data != null && y < this.LAST) { + var page = parseInt(data / this.HSIZE); + var index = this.HSIZE * page + parseInt(y / 2); core.ui.drawBook(index); core.ui.drawBookDetail(index); } @@ -959,12 +963,12 @@ actions.prototype._clickBook = function (x, y) { ////// 怪物手册界面时,按下某个键的操作 ////// actions.prototype._keyDownBook = function (keycode) { - if (keycode == 37) core.ui.drawBook(core.status.event.data - 6); + if (keycode == 37) core.ui.drawBook(core.status.event.data - this.HSIZE); if (keycode == 38) core.ui.drawBook(core.status.event.data - 1); - if (keycode == 39) core.ui.drawBook(core.status.event.data + 6); + if (keycode == 39) core.ui.drawBook(core.status.event.data + this.HSIZE); if (keycode == 40) core.ui.drawBook(core.status.event.data + 1); - if (keycode == 33) core.ui.drawBook(core.status.event.data - 6); - if (keycode == 34) core.ui.drawBook(core.status.event.data + 6); + if (keycode == 33) core.ui.drawBook(core.status.event.data - this.HSIZE); + if (keycode == 34) core.ui.drawBook(core.status.event.data + this.HSIZE); return; } @@ -984,7 +988,7 @@ actions.prototype._keyUpBook = function (keycode) { if (keycode == 13 || keycode == 32 || keycode == 67) { var data = core.status.event.data; if (data != null) { - this._clickBook(6, 2 * (data % 6)); + this._clickBook(this.HSIZE, 2 * (data % this.HSIZE)); } return; } @@ -998,12 +1002,12 @@ actions.prototype._clickBookDetail = function () { ////// 楼层传送器界面时的点击操作 ////// actions.prototype._clickFly = function (x, y) { - if ((x == 10 || x == 11) && y == 9) core.ui.drawFly(this._getNextFlyFloor(-1)); - if ((x == 10 || x == 11) && y == 5) core.ui.drawFly(this._getNextFlyFloor(1)); - if ((x == 10 || x == 11) && y == 10) core.ui.drawFly(this._getNextFlyFloor(-10)); - if ((x == 10 || x == 11) && y == 4) core.ui.drawFly(this._getNextFlyFloor(10)); - if (x >= 5 && x <= 7 && y == 12) core.ui.closePanel(); - if (x >= 0 && x <= 9 && y >= 3 && y <= 11) + if ((x == this.SIZE-2 || x == this.SIZE-3) && y == this.HSIZE+3) core.ui.drawFly(this._getNextFlyFloor(-1)); + if ((x == this.SIZE-2 || x == this.SIZE-3) && y == this.HSIZE-1) core.ui.drawFly(this._getNextFlyFloor(1)); + if ((x == this.SIZE-2 || x == this.SIZE-3) && y == this.HSIZE+4) core.ui.drawFly(this._getNextFlyFloor(-10)); + if ((x == this.SIZE-2 || x == this.SIZE-3) && y == this.HSIZE-2) core.ui.drawFly(this._getNextFlyFloor(10)); + if (x >= this.HSIZE-1 && x <= this.HSIZE+1 && y == this.LAST) core.ui.closePanel(); + if (x >= 0 && x <= this.HSIZE+3 && y >= 3 && y <= this.LAST - 1) core.flyTo(core.floorIds[core.status.event.data]); return; } @@ -1041,7 +1045,7 @@ actions.prototype._keyUpFly = function (keycode) { if (keycode == 71 || keycode == 27 || keycode == 88) core.ui.closePanel(); if (keycode == 13 || keycode == 32 || keycode == 67) - this._clickFly(5, 5); + this._clickFly(this.HSIZE-1, this.HSIZE-1); return; } @@ -1167,8 +1171,8 @@ actions.prototype._keyUpViewMaps = function (keycode) { actions.prototype._clickShop = function (x, y) { var shop = core.status.event.data.shop; var choices = shop.choices; - if (x >= 5 && x <= 7) { - var topIndex = 6 - parseInt(choices.length / 2); + if (x >= this.CHOICES_LEFT && x <= this.CHOICES_RIGHT) { + var topIndex = this.HSIZE - parseInt(choices.length / 2); if (y >= topIndex && y < topIndex + choices.length) { return core.events._useShop(shop, y - topIndex); } @@ -1196,8 +1200,8 @@ actions.prototype._clickQuickShop = function (x, y) { var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { return shopList[shopId].visited || !shopList[shopId].mustEnable }); - if (x >= 5 && x <= 7) { - var topIndex = 6 - parseInt(keys.length / 2); + if (x >= this.CHOICES_LEFT && x <= this.CHOICES_RIGHT) { + var topIndex = this.HSIZE - parseInt(keys.length / 2); if (y >= topIndex && y < topIndex + keys.length) { var reason = core.events.canUseQuickShop(keys[y - topIndex]); if (!core.flags.enableDisabledShop && reason) { @@ -1749,9 +1753,9 @@ actions.prototype._keyUpSL = function (keycode) { ////// 系统设置界面时的点击操作 ////// actions.prototype._clickSwitchs = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; core.status.event.selection = selection; @@ -1844,11 +1848,11 @@ actions.prototype._keyUpSwitchs = function (keycode) { this._selectChoices(core.status.event.ui.choices.length, keycode, this._clickSwitchs); } -////// 系统菜单栏界面时的点击事件 ////// +////// 系统菜单栏界面时的点击操作 ////// actions.prototype._clickSettings = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; core.status.event.selection = selection; @@ -1897,9 +1901,9 @@ actions.prototype._keyUpSettings = function (keycode) { ////// 同步存档界面时的点击操作 ////// actions.prototype._clickSyncSave = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; core.status.event.selection = selection; @@ -1979,10 +1983,10 @@ actions.prototype._keyUpSyncSave = function (keycode) { ////// 同步存档选择界面时的点击操作 ////// actions.prototype._clickSyncSelect = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; core.status.event.selection = selection; @@ -2013,10 +2017,10 @@ actions.prototype._keyUpSyncSelect = function (keycode) { ////// 存档下载界面时的点击操作 ////// actions.prototype._clickLocalSaveSelect = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; @@ -2051,10 +2055,10 @@ actions.prototype._keyUpLocalSaveSelect = function (keycode) { ////// 存档删除界面时的点击操作 ////// actions.prototype._clickStorageRemove = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; @@ -2132,10 +2136,10 @@ actions.prototype._keyUpStorageRemove = function (keycode) { ////// 回放选择界面时的点击操作 ////// actions.prototype._clickReplay = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; @@ -2186,10 +2190,10 @@ actions.prototype._keyUpReplay = function (keycode) { ////// 游戏信息界面时的点击操作 ////// actions.prototype._clickGameInfo = function (x, y) { - if (x < 5 || x > 7) return; + if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; var choices = core.status.event.ui.choices; - var topIndex = 6 - parseInt((choices.length - 1) / 2); + var topIndex = this.HSIZE - parseInt((choices.length - 1) / 2); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; diff --git a/libs/control.js b/libs/control.js index 3b4ddc2b..70f6ac48 100644 --- a/libs/control.js +++ b/libs/control.js @@ -625,6 +625,7 @@ control.prototype.moveAction = function (callback) { } control.prototype._moveAction_noPass = function (canMove, callback) { + core.status.route.push(core.getHeroLoc('direction')); core.status.automaticRoute.moveStepBeforeStop = []; core.status.automaticRoute.lastDirection = core.getHeroLoc('direction'); if (canMove) core.events._trigger(core.nextX(), core.nextY()); @@ -641,6 +642,7 @@ control.prototype._moveAction_moving = function (callback) { core.setHeroMoveInterval(function () { var direction = core.getHeroLoc('direction'); core.control._moveAction_popAutomaticRoute(); + core.status.route.push(direction); // 无事件的道具(如血瓶)需要优先于阻激夹域判定 var nowx = core.getHeroLoc('x'), nowy = core.getHeroLoc('y'); diff --git a/libs/ui.js b/libs/ui.js index 790ce132..72adee7c 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -944,7 +944,7 @@ ui.prototype.drawChoices = function(content, choices) { ui.prototype._drawChoices_getHorizontalPosition = function (titleInfo, choices) { // 宽度计算:考虑选项的长度 - var width = this.PIXEL - 2 * 85; + var width = 246; core.setFont('ui', "bold 17px "+core.status.globalAttribute.font); for (var i = 0; i < choices.length; i++) { if (typeof choices[i] === 'string') From 9813dc3115f49c87e89aa1794bdcc3efdfd1764e Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 25 Mar 2019 00:29:18 +0800 Subject: [PATCH 085/153] lineHeight, showImage, splitImage --- _docs/event.md | 17 ++++++---- _server/MotaAction.g4 | 70 +++++++++++++++++++++++++++++---------- _server/editor_blockly.js | 1 + libs/events.js | 27 +++++++++------ libs/loader.js | 2 +- libs/ui.js | 19 ++++++----- libs/utils.js | 26 +++++++++------ 7 files changed, 108 insertions(+), 54 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 73961975..3beb965a 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -338,7 +338,7 @@ time为可选项,代表该自动文本的时间。可以不指定,不指定 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "scrollText", "text": "第一排\n第二牌\n\n空行后的一排", "time": 5000, "async": true}, + {"type": "scrollText", "text": "第一排\n第二牌\n\n空行后的一排", "time": 5000, "lineHeight": 1.4, "async": true}, ] ``` @@ -346,6 +346,8 @@ text为正文文本内容。可以使用`${ }`来计算表达式的值,且使 time为可选项,代表总的滚动时间。默认为5000毫秒。 +lineHeight为可选项,代表行距。默认为1.4。 + async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 可以使用下面的[设置剧情文本的属性](event#setText:设置剧情文本的属性)来对文字颜色、文字大小、粗体、距离左边的偏移量进行设置。 @@ -1059,9 +1061,10 @@ loc可忽略,如果忽略则显示为事件当前点。 ``` js "x,y": [ // 实际执行的事件列表 - {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "dw": 100, "dy" : 100, "opacity": 1, "time" : 0}, // 在(231,297)显示bg.jpg - {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "dw": 100, "dy" : 100, "opacity": 0.5, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时不透明度为0.5,这张图片将遮盖上一张 - {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "dw": 50, "dy" : 50, "opacity": 1, "time" : 500, "async": true}, // 在(209,267)渐变显示hero.png,大小为原图片的一半,渐变时间为500毫秒,异步执行;这张图片将被上一张遮盖 + {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "opacity": 1, "time" : 0}, // 在(231,297)显示bg.jpg + {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "opacity": 0.5, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时不透明度为0.5,这张图片将遮盖上一张 + {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "opacity": 1, "time" : 500, "async": true}, // 在(209,267)渐变显示hero.png,渐变时间为500毫秒,异步执行;这张图片将被上一张遮盖 + {"type": "showImage", "code": 10, "image": "hero.png", "sloc": [100,100,100,100], "loc": [0,0,100,100], "opacity": 1, "time": 0} // 截取原图的一部分绘制到画布上的一部分。 ] ``` @@ -1069,9 +1072,9 @@ code为图片编号,如果两张图片重叠,编号较大会覆盖编号较 image为图片名。**请确保图片在全塔属性中的images中被定义过。** -loc为图片左上角坐标,以像素为单位进行计算。 +sloc为可选项;如果设置了则是个2或4元组,代表裁剪原始图片的左上角像素位置和宽高。 -dw和dh为图片的横向、纵向放大率,默认值为100,即不进行缩放。 +loc为2或4元组,代表要绘制的画布上的左上角像素位置和宽高。 opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 @@ -1097,6 +1100,8 @@ loc为图片左上角坐标,以像素为单位进行计算。 opacity为图片不透明度,在0~1之间,默认值为1,即不透明。 +lineHeight为可选项,代表行距。默认为1.4。 + time为渐变时间,默认值为0,即不渐变直接显示。 async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 6cf3b5d3..1aa58715 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -268,6 +268,7 @@ action | animate_s | vibrate_s | showImage_s + | showImage_1_s | hideImage_s | showTextImage_s | moveImage_s @@ -380,27 +381,28 @@ return code; */; scrollText_s - : '滚动剧情文本:' '时间' Int '不等待执行完毕' Bool? BGNL? EvalString Newline + : '滚动剧情文本:' '时间' Int '行距' Number '不等待执行完毕' Bool? BGNL? EvalString Newline /* scrollText_s tooltip : scrollText:滚动剧情文本,将从下到上进行滚动显示。 helpUrl : https://h5mota.com/games/template/docs/#/event?id=scrollText%ef%bc%9a%e6%bb%9a%e5%8a%a8%e5%89%a7%e6%83%85%e6%96%87%e6%9c%ac -default : [5000,false,"时间是总时间,可以使用setText事件来控制字体、颜色、大小、偏移量等"] +default : [5000,1.4,false,"时间是总时间,可以使用setText事件来控制字体、颜色、大小、偏移量等"] Bool_0 = Bool_0?', "async": true':''; -var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+'},\n'; +var code = '{"type": "scrollText", "text": "'+EvalString_0+'"'+Bool_0+', "time" :'+Int_0+', "lineHeight": '+Number_0+'},\n'; return code; */; setText_s - : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline + : '设置剧情文本的属性' '位置' SetTextPosition_List '偏移像素' EvalString? '对齐' SetTextAlign_List? BGNL? '标题颜色' EvalString? Colour '正文颜色' EvalString? Colour '背景色' EvalString? Colour BGNL? '粗体' B_1_List '标题字体大小' EvalString? '正文字体大小' EvalString? '打字间隔' EvalString? Newline /* setText_s tooltip : setText:设置剧情文本的属性,颜色为RGB三元组或RGBA四元组,打字间隔为剧情文字添加的时间间隔,为整数或不填 helpUrl : https://h5mota.com/games/template/docs/#/event?id=settext%EF%BC%9A%E8%AE%BE%E7%BD%AE%E5%89%A7%E6%83%85%E6%96%87%E6%9C%AC%E7%9A%84%E5%B1%9E%E6%80%A7 -default : [null,"","",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',null,"","",""] +default : [null,"",null,"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',"",'rgba(255,255,255,1)',null,"","",""] SetTextPosition_List_0 =SetTextPosition_List_0==='null'?'': ', "position": "'+SetTextPosition_List_0+'"'; +SetTextAlign_List_0 =SetTextAlign_List_0==='null'?'': ', "align": "'+SetTextAlign_List_0+'"'; var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/; if (EvalString_0) { if (!/^\d+$/.test(EvalString_0))throw new Error('像素偏移量必须是整数或不填'); @@ -438,7 +440,7 @@ if (EvalString_6) { EvalString_6 = ', "time": '+EvalString_6; } B_1_List_0 = B_1_List_0==='null'?'':', "bold": '+B_1_List_0; -var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+EvalString_6+'},\n'; +var code = '{"type": "setText"'+SetTextPosition_List_0+EvalString_0+SetTextAlign_List_0+EvalString_1+EvalString_2+B_1_List_0+EvalString_3+EvalString_4+EvalString_5+EvalString_6+'},\n'; return code; */; @@ -1132,34 +1134,54 @@ return code; */; showImage_s - : '显示图片' '图片编号' Int '图片' EvalString '起点像素位置' 'x' PosString 'y' PosString BGNL? - '放大率 : x' Int '% y' Int '% 不透明度' Number '时间' Int '不等待执行完毕' Bool Newline + : '显示图片' '图片编号' Int '图片' EvalString BGNL? + '绘制的起点像素' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline /* showImage_s tooltip : showImage:显示图片 helpUrl : https://h5mota.com/games/template/docs/#/event?id=showImage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87 -default : [1,"bg.jpg","0","0",100,100,1,0,false] +default : [1,"bg.jpg","0","0",1,0,false] colour : this.printColor if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var async = Bool_0?', "async": true':''; -var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "dw": '+Int_1+', "dh": '+Int_2+', "opacity": '+Number_0+', "time": '+Int_3+async+'},\n'; +var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Number_0+', "time": '+Int_1+async+'},\n'; +return code; +*/; + +showImage_1_s + : '显示图片' '图片编号' Int '图片' EvalString BGNL? + '裁剪的起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '不透明度' Number BGNL? + '绘制的起点像素' 'x' PosString 'y' PosString '宽' PosString? '高' PosString? '时间' Int '不等待执行完毕' Bool Newline + + +/* showImage_1_s +tooltip : showImage_1:显示图片 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=showImage%ef%bc%9a%e6%98%be%e7%a4%ba%e5%9b%be%e7%89%87 +default : [1,"bg.jpg","0","0","","",1,"0","0","","",0,false] +colour : this.printColor +if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); +var async = Bool_0?', "async": true':''; +var code = '{"type": "showImage", "code": '+Int_0+', "image": "'+EvalString_0+'", '+ + '"sloc": ['+PosString_0+','+PosString_1+','+PosString_2+','+PosString_3+'], '+ + '"loc": ['+PosString_4+','+PosString_5+','+PosString_6+','+PosString_7+'], '+ + '"opacity": '+Number_0+', "time": '+Int_1+async+'},\n'; return code; */; showTextImage_s : '显示图片化文本' '文本内容' EvalString BGNL? - '图片编号' Int '起点像素位置' 'x' PosString 'y' PosString '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline + '图片编号' Int '起点像素' 'x' PosString 'y' PosString '行距' Number '不透明度' Number '时间' Int '不等待执行完毕' Bool Newline /* showTextImage_s tooltip : showTextImage:显示图片化文本 helpUrl : https://h5mota.com/games/template/docs/#/event?id=showTextImage%ef%bc%9a%e6%98%be%e7%a4%ba%e6%96%87%e6%9c%ac%e5%8c%96%e5%9b%be%e7%89%87 colour : this.printColor -default : ["可以使用setText事件来控制字体、颜色、大小、偏移量等",1,"0","0",1,0,false] +default : ["可以使用setText事件来控制字体、颜色、大小、偏移量等",1,"0","0",1.4,1,0,false] if(Int_0<=0 || Int_0>50) throw new Error('图片编号在1~50之间'); var async = Bool_0?', "async": true':''; -var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "opacity": '+Number_0+', "time": '+Int_1+async+'},\n'; +var code = '{"type": "showTextImage", "code": '+Int_0+', "text": "'+EvalString_0+'", "loc": ['+PosString_0+','+PosString_1+'], "lineHeight": '+Number_0+', "opacity": '+Number_1+', "time": '+Int_1+async+'},\n'; return code; */; @@ -1872,6 +1894,10 @@ SetTextPosition_List : '不改变'|'距离顶部'|'居中'|'距离底部' /*SetTextPosition_List ['null','up','center','down']*/; +SetTextAlign_List + : '不改变'|'左对齐'|'左右居中'|'右对齐' + /*SetTextAlign_List ['null','left','center','right']*/; + ShopUse_List : '金币' | '经验' /*ShopUse_List ['money','experience']*/; @@ -2151,7 +2177,7 @@ ActionParser.prototype.parseAction = function() { break; case "scrollText": this.next = MotaActionBlocks['scrollText_s'].xmlText([ - data.time, data.async||false, this.EvalString(data.text), this.next]); + data.time, data.lineHeight||1.4, data.async||false, this.EvalString(data.text), this.next]); break; case "comment": // 注释 this.next = MotaActionBlocks['comment_s'].xmlText([this.EvalString(data.text),this.next],null,data.text); @@ -2163,7 +2189,7 @@ ActionParser.prototype.parseAction = function() { if (!/^\w+\.png$/.test(data.background)) data.background=setTextfunc(data.background); this.next = MotaActionBlocks['setText_s'].xmlText([ - data.position,data.offset,data.title,'rgba('+data.title+')', + data.position,data.offset,data.align,data.title,'rgba('+data.title+')', data.text,'rgba('+data.text+')',data.background,'rgba('+data.background+')', data.bold,data.titlefont,data.textfont,data.time,this.next]); break; @@ -2308,8 +2334,16 @@ ActionParser.prototype.parseAction = function() { break; case "showImage": // 显示图片 data.loc=data.loc||['',''] - this.next = MotaActionBlocks['showImage_s'].xmlText([ - data.code,data.image||data.name,data.loc[0],data.loc[1],data.dw,data.dh,data.opacity,data.time||0,data.async||false,this.next]); + if (data.sloc) { + this.next = MotaActionBlocks['showImage_1_s'].xmlText([ + data.code,data.image||data.name,data.sloc[0],data.sloc[1],data.sloc[2],data.sloc[3],data.opacity, + data.loc[0],data.loc[1],data.loc[2],data.loc[3],data.time||0,data.async||false,this.next + ]); + } + else { + this.next = MotaActionBlocks['showImage_s'].xmlText([ + data.code,data.image||data.name,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]); + } break; case "hideImage": // 清除图片 this.next = MotaActionBlocks['hideImage_s'].xmlText([ @@ -2318,7 +2352,7 @@ ActionParser.prototype.parseAction = function() { case "showTextImage": // 显示图片化文本 data.loc=data.loc||['',''] this.next = MotaActionBlocks['showTextImage_s'].xmlText([ - this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.opacity,data.time||0,data.async||false,this.next]); + this.EvalString(data.text),data.code,data.loc[0],data.loc[1],data.lineHeight||1.4,data.opacity,data.time||0,data.async||false,this.next]); break; case "moveImage": // 移动图片 data.to=data.to||['',''] diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 7fdf310f..9ebabaac 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -54,6 +54,7 @@ editor_blockly = function () { MotaActionBlocks['scrollText_s'].xmlText(), MotaActionBlocks['setText_s'].xmlText(), MotaActionBlocks['showImage_s'].xmlText(), + MotaActionBlocks['showImage_1_s'].xmlText(), MotaActionBlocks['hideImage_s'].xmlText(), MotaActionBlocks['showTextImage_s'].xmlText(), MotaActionBlocks['moveImage_s'].xmlText(), diff --git a/libs/events.js b/libs/events.js index 5aa7f0a4..e15598e3 100644 --- a/libs/events.js +++ b/libs/events.js @@ -885,7 +885,7 @@ events.prototype._action_autoText = function (data, x, y, prefix) { events.prototype._action_scrollText = function (data, x, y, prefix) { if (this.__action_checkReplaying()) return; - this.__action_doAsyncFunc(data.async, core.ui.drawScrollText, data.text, data.time || 5000); + this.__action_doAsyncFunc(data.async, core.ui.drawScrollText, data.text, data.lineHeight || 1.4, data.time || 5000); } events.prototype._action_comment = function (data, x, y, prefix) { @@ -893,7 +893,7 @@ events.prototype._action_comment = function (data, x, y, prefix) { } events.prototype._action_setText = function (data, x, y, prefix) { - ["position", "offset", "bold", "titlefont", "textfont", "time"].forEach(function (t) { + ["position", "offset", "align", "bold", "titlefont", "textfont", "time"].forEach(function (t) { if (data[t] != null) core.status.textAttribute[t] = data[t]; }); ["background", "title", "text"].forEach(function (t) { @@ -1030,10 +1030,9 @@ events.prototype._action_changePos = function (data, x, y, prefix) { } events.prototype._action_showImage = function (data, x, y, prefix) { - var loc = this.__action_getLoc(data.loc, 0, 0, prefix); if (core.isReplaying()) data.time = 0; this.__action_doAsyncFunc(data.async || data.time == 0, this.showImage, - data.code, data.image, loc[0], loc[1], data.dw, data.dh, data.opacity, data.time); + data.code, data.image, data.sloc, data.loc, data.opacity, data.time); } events.prototype._action_showTextImage = function (data, x, y, prefix) { @@ -1815,21 +1814,27 @@ events.prototype.closeDoor = function (x, y, id, callback) { } ////// 显示图片 ////// -events.prototype.showImage = function (code, image, x, y, dw, dh, opacityVal, time, callback) { - dw /= 100; - dh /= 100; - x = core.calValue(x) || 0; - y = core.calValue(y) || 0; +events.prototype.showImage = function (code, image, sloc, loc, opacityVal, time, callback) { if (typeof image == 'string') image = core.material.images.images[image]; if (!image) { if (callback) callback(); return; } + sloc = sloc || []; + var sx = core.calValue(sloc[0]) || 0, sy = core.calValue(sloc[1]) || 0; + var sw = core.calValue(sloc[2]), sh = core.calValue(sloc[3]); + if (sw == null) sw = image.width; + if (sh == null) sh = image.height; + loc = loc || []; + var x = core.calValue(loc[0]) || 0, y = core.calValue(loc[1]) || 0; + var w = core.calValue(loc[2]), h = core.calValue(loc[3]); + if (w == null) w = sw; + if (h == null) h = sh; var zIndex = code + 100; time = time || 0; var name = "image" + zIndex; - var ctx = core.createCanvas(name, x, y, image.width * dw, image.height * dh, zIndex); - ctx.drawImage(image, 0, 0, image.width * dw, image.height * dh); + var ctx = core.createCanvas(name, x, y, w, h, zIndex); + ctx.drawImage(image, sx, sy, sw, sh, 0, 0, w, h); if (time == 0) { core.setOpacity(name, opacityVal); if (callback) callback(); diff --git a/libs/loader.js b/libs/loader.js index 5613c33d..b2da0c6e 100644 --- a/libs/loader.js +++ b/libs/loader.js @@ -38,7 +38,7 @@ loader.prototype._load = function (callback) { loader.prototype._loadIcons = function () { this.loadImage("icons.png", function (id, image) { - var images = core.cropImage(image); + var images = core.splitImage(image); for (var key in core.statusBar.icons) { if (typeof core.statusBar.icons[key] == 'number') { core.statusBar.icons[key] = images[core.statusBar.icons[key]]; diff --git a/libs/ui.js b/libs/ui.js index 72adee7c..73ce42f8 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -873,29 +873,31 @@ ui.prototype._createTextCanvas = function (content, lineHeight) { ctx.canvas.width = width; ctx.canvas.height = height; ctx.clearRect(0, 0, width, height); + return ctx; } ////// 绘制滚动字幕 ////// -ui.prototype.drawScrollText = function (content, time, callback) { +ui.prototype.drawScrollText = function (content, time, lineHeight, callback) { content = core.replaceText(content || ""); + lineHeight = lineHeight || 1.4; time = time || 5000; clearInterval(core.status.event.interval); core.status.event.interval = null; var offset = core.status.textAttribute.offset || 15; - var lineHeight = core.status.textAttribute.textfont * 1.4; + lineHeight *= core.status.textAttribute.textfont; var ctx = this._createTextCanvas(content, lineHeight); var obj = { align: core.status.textAttribute.align, lineHeight: lineHeight }; if (obj.align == 'right') obj.left = this.PIXEL - offset; else if (obj.align != 'center') obj.left = offset; this.drawTextContent(ctx, content, obj); - this._drawScrollText_animate(ctx, height, time, callback); + this._drawScrollText_animate(ctx, time, callback); } -ui.prototype._drawScrollText_animate = function (ctx, height, time, callback) { +ui.prototype._drawScrollText_animate = function (ctx, time, callback) { // 开始绘制到UI上 core.clearMap('ui'); - var per_pixel = 1, per_time = time * per_pixel / (416+height); - var currH = 416; + var per_pixel = 1, height = ctx.canvas.height, per_time = time * per_pixel / (this.PIXEL+height); + var currH = this.PIXEL; core.drawImage('ui', ctx.canvas, 0, currH); var animate = setInterval(function () { core.clearMap('ui'); @@ -913,9 +915,10 @@ ui.prototype._drawScrollText_animate = function (ctx, height, time, callback) { } ////// 文本图片化 ////// -ui.prototype.textImage = function (content) { +ui.prototype.textImage = function (content, lineHeight) { content = core.replaceText(content || ""); - var lineHeight = core.status.textAttribute.textfont * 1.4; + lineHeight = lineHeight || 1.4; + lineHeight *= core.status.textAttribute.textfont; var ctx = this._createTextCanvas(content, lineHeight); this.drawTextContent(ctx, content, { align: core.status.textAttribute.align, lineHeight: lineHeight }); return ctx.canvas; diff --git a/libs/utils.js b/libs/utils.js index 4ebdffe9..1bca52b0 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -311,19 +311,25 @@ utils.prototype.clone = function (data) { } ////// 裁剪图片 ////// -utils.prototype.cropImage = function (image, size) { - size = size || 32; +utils.prototype.splitImage = function (image, width, height) { + if (typeof image == "string") + image = core.material.images.images[image]; + if (!image) return []; + width = width || 32; + height = height || width; var canvas = document.createElement("canvas"); var context = canvas.getContext("2d"); - canvas.width = size; - canvas.height = size; + canvas.width = width; + canvas.height = height; var ans = []; - for (var i = 0; i < image.height; i += size) { - context.drawImage(image, 0, i, size, size, 0, 0, size, size); - var img = new Image(); - img.src = canvas.toDataURL("image/png"); - ans.push(img); - context.clearRect(0, 0, size, size); + for (var j = 0; j < image.height; j += height) { + for (var i = 0; i < image.width; i += width) { + context.drawImage(image, i, j, width, height, 0, 0, width, height); + var img = new Image(); + img.src = canvas.toDataURL("image/png"); + ans.push(img); + context.clearRect(0, 0, width, height); + } } return ans; } From 798a751f2f18f673a5fc22f7373a459398ddc5d1 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 25 Mar 2019 11:04:17 +0800 Subject: [PATCH 086/153] Fix bigmap bug --- libs/maps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/maps.js b/libs/maps.js index a457b23b..cb7dbb7b 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -412,7 +412,7 @@ maps.prototype._canMoveHero_checkPoint = function (x, y, direction, floorId, ext 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].width) + if (nx < 0 || ny < 0 || nx >= core.floors[floorId].width || ny >= core.floors[floorId].height) return false; // 2. 检查该点素材的 cannotOut 和下一个点的 cannotIn From 400d91f697d6e5a76a8367af74717533194b1f40 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 25 Mar 2019 23:03:07 +0800 Subject: [PATCH 087/153] drawConfirmBox, drawPagination --- libs/control.js | 4 +- libs/ui.js | 191 ++++++++++++++++-------------------------------- 2 files changed, 64 insertions(+), 131 deletions(-) diff --git a/libs/control.js b/libs/control.js index 70f6ac48..e3946a74 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1610,11 +1610,11 @@ control.prototype.syncSave = function (type) { core.ui.drawWaiting("正在同步,请稍后..."); core.control.getSaves(type=='all'?null:core.saves.saveIndex, function (saves) { if (!saves) return core.drawText("没有要同步的存档"); - core.control._syncSave_http(saves); + core.control._syncSave_http(type, saves); }) } -control.prototype._syncSave_http = function (saves) { +control.prototype._syncSave_http = function (type, saves) { var formData = new FormData(); formData.append('type', 'save'); formData.append('name', core.firstData.name); diff --git a/libs/ui.js b/libs/ui.js index 73ce42f8..dba2f7b9 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -218,9 +218,7 @@ ui.prototype.drawImage = function (name, image, x, y, w, h, x1, y1, w1, h1) { ////// 结束一切事件和绘制,关闭UI窗口,返回游戏进程 ////// ui.prototype.closePanel = function () { - core.status.boxAnimateObjs = []; - clearInterval(core.status.event.interval); - core.clearSelector(); + this.clearUI(); core.maps.generateGroundPattern(); core.updateStatusBar(); core.unLockControl(); @@ -231,6 +229,15 @@ ui.prototype.closePanel = function () { core.status.event.interval = null; } +ui.prototype.clearUI = function () { + clearInterval(core.status.event.interval); + core.status.event.interval = null; + core.status.boxAnimateObjs = []; + core.clearSelector(); + core.clearMap('ui'); + core.setAlpha('ui', 1); +} + ////// 清除光标 ////// ui.prototype.clearSelector = function () { if (core.dymCanvas._selector) core.deleteCanvas("_selector"); @@ -390,6 +397,8 @@ ui.prototype._getPosition = function (content) { ////// 绘制选择光标 ui.prototype.drawWindowSelector = function(background, x, y, w, h) { + if (typeof background == 'string') + background = core.material.images.images[background]; w = Math.round(w), h = Math.round(h); var dstImage = core.ui.createCanvas("_selector", x, y, w, h, 165); core.setOpacity("_selector", 0.8); @@ -671,11 +680,7 @@ ui.prototype.drawTextBox = function(content, showAll) { if (core.status.event && core.status.event.id == 'action') core.status.event.ui = content; - clearInterval(core.status.event.interval); - core.status.event.interval = null; - core.status.boxAnimateObjs = []; - core.clearSelector(); - core.clearMap('ui'); + this.clearUI(); content = core.replaceText(content); @@ -881,8 +886,7 @@ ui.prototype.drawScrollText = function (content, time, lineHeight, callback) { content = core.replaceText(content || ""); lineHeight = lineHeight || 1.4; time = time || 5000; - clearInterval(core.status.event.interval); - core.status.event.interval = null; + this.clearUI(); var offset = core.status.textAttribute.offset || 15; lineHeight *= core.status.textAttribute.textfont; var ctx = this._createTextCanvas(content, lineHeight); @@ -895,7 +899,6 @@ ui.prototype.drawScrollText = function (content, time, lineHeight, callback) { ui.prototype._drawScrollText_animate = function (ctx, time, callback) { // 开始绘制到UI上 - core.clearMap('ui'); var per_pixel = 1, height = ctx.canvas.height, per_time = time * per_pixel / (this.PIXEL+height); var currH = this.PIXEL; core.drawImage('ui', ctx.canvas, 0, currH); @@ -929,11 +932,7 @@ ui.prototype.drawChoices = function(content, choices) { choices = core.clone(choices || []); core.status.event.ui = {"text": content, "choices": choices}; - clearInterval(core.status.event.interval); - core.status.event.interval = null; - core.status.boxAnimateObjs = []; - core.clearSelector(); - core.clearMap('ui'); + this.clearUI(); content = core.replaceText(content || ""); var titleInfo = this._getTitleAndIcon(content); @@ -1047,75 +1046,49 @@ ui.prototype._drawChoices_drawChoices = function (choices, isWindowSkin, hPos, v ////// 绘制一个确认/取消的警告页面 ////// ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { core.lockControl(); + text = core.replaceText(text || ""); core.status.event.id = 'confirmBox'; core.status.event.data = {'yes': yesCallback, 'no': noCallback}; core.status.event.ui = text; + if (core.status.event.selection != 0) core.status.event.selection = 1; + this.clearUI(); - if (!core.isset(core.status.event.selection) || core.status.event.selection>1) core.status.event.selection=1; - if (core.status.event.selection<0) core.status.event.selection=0; - - core.clearSelector(); - - var background = core.status.textAttribute.background; - var isWindowSkin = false; - if (typeof background == 'string') { - background = core.material.images.images[background]; - if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; - else background = core.initStatus.textAttribute.background; - } - if (!isWindowSkin) background = core.arrayToRGBA(background); - var borderColor = core.status.globalAttribute.borderColor; - var textColor = core.arrayToRGBA(core.status.textAttribute.text); - - var globalFont = core.status.globalAttribute.font; - core.setFont('ui', "bold 19px "+globalFont); - - var contents = text.split('\n'); - var lines = contents.length; - var max_length = 0; - for (var i in contents) { - max_length = Math.max(max_length, core.calWidth('ui', contents[i])); - } - - var left = Math.min(208 - 40 - parseInt(max_length / 2), 100); - var top = 140 - (lines-1)*30; - var right = 416 - left, bottom = 416 - 140, width = right - left, height = bottom - top; - - core.clearMap('ui'); - if (isWindowSkin) { - core.setAlpha('ui', 0.85); - this.drawWindowSkin(background,'ui',left,top,width,height); - } - else { - core.fillRect('ui', left, top, width, height, background); - core.strokeRect('ui', left - 1, top - 1, width + 1, height + 1, borderColor, 2); - } - core.setAlpha('ui', 1); + core.setFont('ui', this._buildFont(19, true)); + var contents = text.split("\n"); + var rect = this._drawConfirmBox_getRect(contents); + var isWindowSkin = this._drawTextBox_drawBackground({}, {}, rect, rect); core.setTextAlign('ui', 'center'); + core.setFillStyle('ui', core.arrayToRGBA(core.status.textAttribute.text)) for (var i in contents) { - core.fillText('ui', contents[i], 208, top + 50 + i*30, textColor); + core.fillText('ui', contents[i], this.HPIXEL, rect.top + 50 + i*30); } - core.fillText('ui', "确定", 208 - 38, bottom - 35, null, "bold 17px "+globalFont); - core.fillText('ui', "取消", 208 + 38, bottom - 35); - + core.fillText('ui', "确定", this.HPIXEL - 38, rect.bottom - 35, null, this._buildFont(17, true)); + core.fillText('ui', "取消", this.HPIXEL + 38, rect.bottom - 35); var len=core.calWidth('ui', "确定"); - - var strokeLeft = 208 + (76*core.status.event.selection-38) - parseInt(len/2) - 5; + var strokeLeft = this.HPIXEL + (76*core.status.event.selection-38) - parseInt(len/2) - 5; if (isWindowSkin) - this.drawWindowSelector(background, strokeLeft, bottom-35-20, len+10, 28); + this.drawWindowSelector(core.status.textAttribute.background, strokeLeft, rect.bottom-35-20, len+10, 28); else - core.strokeRect('ui', strokeLeft, bottom-35-20, len+10, 28, "#FFD700", 2); + core.strokeRect('ui', strokeLeft, rect.bottom-35-20, len+10, 28, "#FFD700", 2); } +ui.prototype._drawConfirmBox_getRect = function (contents) { + var max_width = contents.reduce(function (pre, curr) { + return Math.max(pre, core.calWidth('ui', curr)); + }, 0); + var left = Math.min(this.HPIXEL - 40 - parseInt(max_width / 2), 100), right = this.PIXEL - left; + var top = this.HPIXEL - 68 - (contents.length-1)*30, bottom = this.HPIXEL + 68; + return { top: top, left: left, bottom: bottom, right: right, width: right - left, height: bottom - top }; +} + ////// 绘制系统设置界面 ////// ui.prototype.drawSwitchs = function() { core.status.event.id = 'switchs'; - var choices = [ "背景音乐: "+(core.musicStatus.bgmStatus ? "[ON]" : "[OFF]"), "背景音效: "+(core.musicStatus.soundStatus ? "[ON]" : "[OFF]"), @@ -1133,7 +1106,6 @@ ui.prototype.drawSwitchs = function() { ////// 绘制系统菜单栏 ////// ui.prototype.drawSettings = function () { core.status.event.id = 'settings'; - this.drawChoices(null, [ "系统设置", "虚拟键盘", "浏览地图", "绘图模式", "同步存档", "游戏信息", "返回标题", "返回游戏" ]); @@ -1141,68 +1113,37 @@ ui.prototype.drawSettings = function () { ////// 绘制快捷商店选择栏 ////// ui.prototype.drawQuickShop = function () { - core.status.event.id = 'selectShop'; - - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) {return shopList[shopId].visited || !shopList[shopId].mustEnable}); + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); var choices = keys.map(function (shopId) { return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; }); - choices.push("返回游戏"); this.drawChoices(null, choices); } ////// 绘制等待界面 ////// ui.prototype.drawWaiting = function(text) { - core.lockControl(); core.status.event.id = 'waiting'; - core.clearSelector(); - - var background = core.status.textAttribute.background; - var isWindowSkin = false; - if (typeof background == 'string') { - background = core.material.images.images[background]; - if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; - else background = core.initStatus.textAttribute.background; - } - if (!isWindowSkin) background = core.arrayToRGBA(background); - var borderColor = core.status.globalAttribute.borderColor; - var textColor = core.arrayToRGBA(core.status.textAttribute.text); - - var globalFont = core.status.globalAttribute.font; - var text_length = core.calWidth('ui', text, "bold 19px "+globalFont); - - var right = Math.max(text_length+50, 220); - var left = 208-parseInt(right/2), top = 208 - 32 - 16, bottom = 416 - 2 * top; - - core.clearMap('ui'); - if (isWindowSkin) { - core.setAlpha('ui', 0.85); - this.drawWindowSkin(background,'ui',left,top,right,bottom); - } - else { - core.fillRect('ui', left, top, right, bottom, background); - core.strokeRect('ui', left - 1, top - 1, right + 1, bottom + 1, borderColor, 2); - } - core.setAlpha('ui', 1); - + text = core.replaceText(text || ""); + var text_length = core.calWidth('ui', text, this._buildFont(19, true)); + var width = Math.max(text_length + 80, 220), left = this.HPIXEL - parseInt(width / 2), right = left + width; + var top = this.HPIXEL - 48, height = 96, bottom = top + height; + this._drawTextBox_drawBackground({}, {}, {left: left, right: right}, {top: top, bottom: bottom}); core.setTextAlign('ui', 'center'); - core.fillText('ui', text, 208, top + 56, textColor); - + core.fillText('ui', text, 208, top + 56, core.arrayToRGBA(core.status.textAttribute.text)); } ////// 绘制存档同步界面 ////// ui.prototype.drawSyncSave = function () { - core.status.event.id = 'syncSave'; - this.drawChoices(null, [ "同步存档到服务器", "从服务器加载存档", "存档至本地文件", "从本地文件读档", "回放当前录像", "下载当前录像", "清空本地存档", "返回主菜单" ]); - } ////// 绘制存档同步选择页面 ////// @@ -1247,44 +1188,36 @@ ui.prototype.drawGameInfo = function () { ////// 绘制分页 ////// ui.prototype.drawPagination = function (page, totalPage, top) { // if (totalPage 1) - core.fillText('ui', '上一页', 208 - 80, top*32+19); + core.fillText('ui', '上一页', this.HPIXEL - 80, top*32+19); if (page < totalPage) - core.fillText('ui', '下一页', 208 + 80, top*32+19); + core.fillText('ui', '下一页', this.HPIXEL + 80, top*32+19); } ////// 绘制键盘光标 ////// ui.prototype.drawCursor = function () { - - if (!core.isset(core.status.automaticRoute.cursorX)) - core.status.automaticRoute.cursorX=core.getHeroLoc('x'); - if (core.status.automaticRoute.cursorX<0) core.status.automaticRoute.cursorX=0; - if (core.status.automaticRoute.cursorX>12) core.status.automaticRoute.cursorX=12; - if (!core.isset(core.status.automaticRoute.cursorY)) - core.status.automaticRoute.cursorY=core.getHeroLoc('y'); - if (core.status.automaticRoute.cursorY<0) core.status.automaticRoute.cursorY=0; - if (core.status.automaticRoute.cursorY>12) core.status.automaticRoute.cursorY=12; - + var automaticRoute = core.status.automaticRoute; + if (automaticRoute.cursorX == null) + automaticRoute.cursorX = core.getHeroLoc('x'); + if (automaticRoute.cursorY == null) + automaticRoute.cursorY = core.getHeroLoc('y'); + automaticRoute.cursorX = core.clamp(automaticRoute.cursorX, 0, this.LAST); core.status.event.id = 'cursor'; core.lockControl(); - - core.clearMap('ui'); - core.setAlpha('ui', 1); - + core.clearUI(); var width = 4; - core.strokeRect('ui', 32*core.status.automaticRoute.cursorX+width/2, 32*core.status.automaticRoute.cursorY+width/2, + core.strokeRect('ui', 32*automaticRoute.cursorX+width/2, 32*automaticRoute.cursorY+width/2, 32-width, 32-width, '#FFD700', width); } From 2cdac4930a6cbe05b7dd51e75d868d7acab854a1 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 25 Mar 2019 23:05:44 +0800 Subject: [PATCH 088/153] drawConfirmBox, drawPagination --- libs/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui.js b/libs/ui.js index dba2f7b9..7473fd11 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1135,7 +1135,7 @@ ui.prototype.drawWaiting = function(text) { var top = this.HPIXEL - 48, height = 96, bottom = top + height; this._drawTextBox_drawBackground({}, {}, {left: left, right: right}, {top: top, bottom: bottom}); core.setTextAlign('ui', 'center'); - core.fillText('ui', text, 208, top + 56, core.arrayToRGBA(core.status.textAttribute.text)); + core.fillText('ui', text, this.HPIXEL, top + 56, core.arrayToRGBA(core.status.textAttribute.text)); } ////// 绘制存档同步界面 ////// From f25a29574222bf180b3ec1509f4d2f88944a77ac Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 25 Mar 2019 23:35:10 +0800 Subject: [PATCH 089/153] drawKeyboard --- libs/actions.js | 71 ++++++++++++++++--------------- libs/ui.js | 111 ++++++++++++++++++++---------------------------- 2 files changed, 81 insertions(+), 101 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 37f39db2..9b68d44f 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -2252,11 +2252,12 @@ actions.prototype._keyUpGameInfo = function (keycode) { ////// “虚拟键盘”界面时的点击操作 ////// actions.prototype._clickKeyBoard = function (x, y) { - if (y == 3 && x >= 1 && x <= 11) { + var m = this.HSIZE; + if (y == m - 3 && x >= m - 5 && x <= m + 5) { core.ui.closePanel(); - core.keyUp(112 + x - 1); // F1-F12: 112-122 + core.keyUp(112 + x + 5 - m); } - if (y == 3 && x == 12) { + if (y == m - 3 && x == m + 6) { var val = prompt(); if (val != null) { try { @@ -2266,9 +2267,9 @@ actions.prototype._clickKeyBoard = function (x, y) { } } } - if (y == 4 && x >= 1 && x <= 10) { + if (y == m - 2 && x >= m - 5 && x <= m + 4) { core.ui.closePanel(); - core.keyUp(x == 10 ? 48 : 48 + x); // 1-9: 49-57; 0: 48 + core.keyUp(x == m + 4 ? 48 : 49 + x + 5 - m); // 1-9: 49-57; 0: 48 } // 字母 var lines = [ @@ -2276,46 +2277,46 @@ actions.prototype._clickKeyBoard = function (x, y) { ["A", "S", "D", "F", "G", "H", "J", "K", "L"], ["Z", "X", "C", "V", "B", "N", "M"], ]; - if (y == 5 && x >= 1 && x <= 10) { + if (y == m - 1 && x >= m - 5 && x <= m + 4) { core.ui.closePanel(); - core.keyUp(lines[0][x - 1].charCodeAt(0)); + core.keyUp(lines[0][x + 5 - m].charCodeAt(0)); } - if (y == 6 && x >= 1 && x <= 9) { + if (y == m && x >= m - 5 && x <= m + 3) { core.ui.closePanel(); - core.keyUp(lines[1][x - 1].charCodeAt(0)); + core.keyUp(lines[1][x + 5 - m].charCodeAt(0)); } - if (y == 7 && x >= 1 && x <= 7) { + if (y == m + 1 && x >= m - 5 && x <= m + 1) { core.ui.closePanel(); - core.keyUp(lines[2][x - 1].charCodeAt(0)); + core.keyUp(lines[2][x + 5 - m].charCodeAt(0)); } - if (y == 8 && x >= 1 && x <= 11) { + if (y == m + 2 && x >= m - 5 && x <= m + 5) { core.ui.closePanel(); - if (x == 1) core.keyUp(189); // - - if (x == 2) core.keyUp(187); // = - if (x == 3) core.keyUp(219); // [ - if (x == 4) core.keyUp(221); // ] - if (x == 5) core.keyUp(220); // \ - if (x == 6) core.keyUp(186); // ; - if (x == 7) core.keyUp(222); // ' - if (x == 8) core.keyUp(188); // , - if (x == 9) core.keyUp(190); // . - if (x == 10) core.keyUp(191); // / - if (x == 11) core.keyUp(192); // ` + if (x == m - 5) core.keyUp(189); // - + if (x == m - 4) core.keyUp(187); // = + if (x == m - 3) core.keyUp(219); // [ + if (x == m - 2) core.keyUp(221); // ] + if (x == m - 1) core.keyUp(220); // \ + if (x == m) core.keyUp(186); // ; + if (x == m + 1) core.keyUp(222); // ' + if (x == m + 2) core.keyUp(188); // , + if (x == m + 3) core.keyUp(190); // . + if (x == m + 4) core.keyUp(191); // / + if (x == m + 5) core.keyUp(192); // ` } - if (y == 9 && x >= 1 && x <= 10) { + if (y == m + 3 && x >= m - 5 && x <= m + 4) { core.ui.closePanel(); - if (x == 1) core.keyUp(27); // ESC - if (x == 2) core.keyUp(9); // TAB - if (x == 3) core.keyUp(20); // CAPS - if (x == 4) core.keyUp(16); // SHIFT - if (x == 5) core.keyUp(17); // CTRL - if (x == 6) core.keyUp(18); // ALT - if (x == 7) core.keyUp(32); // SPACE - if (x == 8) core.keyUp(8); // BACKSPACE - if (x == 9) core.keyUp(13); // ENTER - if (x == 10) core.keyUp(46); // DEL + if (x == m - 5) core.keyUp(27); // ESC + if (x == m - 4) core.keyUp(9); // TAB + if (x == m - 3) core.keyUp(20); // CAPS + if (x == m - 2) core.keyUp(16); // SHIFT + if (x == m - 1) core.keyUp(17); // CTRL + if (x == m) core.keyUp(18); // ALT + if (x == m + 1) core.keyUp(32); // SPACE + if (x == m + 2) core.keyUp(8); // BACKSPACE + if (x == m + 3) core.keyUp(13); // ENTER + if (x == m + 4) core.keyUp(46); // DEL } - if (y == 10 && x >= 9 && x <= 11) + if (y == m + 4 && x >= m + 3 && x <= m + 5) core.ui.closePanel(); } diff --git a/libs/ui.js b/libs/ui.js index 7473fd11..6654b05b 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2148,41 +2148,19 @@ ui.prototype.drawSLPanel = function(index, refresh) { ui.prototype.drawKeyBoard = function () { core.lockControl(); core.status.event.id = 'keyBoard'; + core.clearUI(); - core.clearSelector(); - - var left = 16, top = 48, width = 416 - 2 * left, height = 416 - 2 * top; - - var background = core.status.textAttribute.background; - var isWindowSkin = false; - if (typeof background == 'string') { - background = core.material.images.images[background]; - if (core.isset(background) && background.width==192 && background.height==128) isWindowSkin = true; - else background = core.initStatus.textAttribute.background; - } - if (!isWindowSkin) background = core.arrayToRGBA(background); - var borderColor = core.status.globalAttribute.borderColor; - var titleColor = core.arrayToRGBA(core.status.textAttribute.title); - var textColor = core.arrayToRGBA(core.status.textAttribute.text); - - core.clearMap('ui'); - if (isWindowSkin) { - core.setAlpha('ui', 0.85); - this.drawWindowSkin(background,'ui',left,top,width,height); - } - else { - core.fillRect('ui', left, top, width, height, background); - core.strokeRect('ui', left - 1, top - 1, width + 1, height + 1, borderColor, 2); - } - core.setAlpha('ui', 1); + var width = 384, height = 320; + var left = (this.PIXEL - width) / 2, right = left + width; + var top = (this.PIXEL - height) / 2, bottom = top + height; + var isWindowSkin = this._drawTextBox_drawBackground({}, {}, {left:left, right:right}, {top:top, bottom: bottom}); core.setTextAlign('ui', 'center'); - var globalFont = core.status.globalAttribute.font; - core.fillText('ui', "虚拟键盘", 208, top+35, titleColor, "bold 22px "+globalFont); - - core.setFont('ui', '17px '+globalFont); - core.setFillStyle('ui', textColor); - var offset = 128-9; + core.setFillStyle('ui', core.arrayToRGBA(core.status.textAttribute.title)); + core.fillText('ui', '虚拟键盘', this.HPIXEL, top + 35, null, this._buildFont(22, true)); + core.setFont('ui', this._buildFont(17, false)); + core.setFillStyle('ui', core.arrayToRGBA(core.status.textAttribute.text)); + var offset = this.HPIXEL - 89; var lines = [ ["F1","F2","F3","F4","F5","F6","F7","F8","F9","10","11"], @@ -2196,17 +2174,17 @@ ui.prototype.drawKeyBoard = function () { lines.forEach(function (line) { for (var i=0;i Date: Mon, 25 Mar 2019 23:37:43 +0800 Subject: [PATCH 090/153] drawKeyboard --- libs/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui.js b/libs/ui.js index 6654b05b..126824d4 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2179,7 +2179,7 @@ ui.prototype.drawKeyBoard = function () { offset+=32; }); - core.fillText("ui", "返回游戏", this.PIXEL - 80, offset-3, '#FFFFFF', this._buildFont(15, true)); + core.fillText("ui", "返回游戏", this.HPIXEL + 128, offset-3, '#FFFFFF', this._buildFont(15, true)); if (isWindowSkin) this.drawWindowSelector(core.status.textAttribute.background, this.HPIXEL + 92, offset - 22, 72, 27); From 45c74f44e0c30ec6e92c1ee45a3e6da65d4a8dc6 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 26 Mar 2019 00:43:08 +0800 Subject: [PATCH 091/153] drawStatistics & drawBookDetail --- libs/ui.js | 473 ++++++++++++++++++++++++++--------------------------- 1 file changed, 235 insertions(+), 238 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 126824d4..02bbf3a4 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1375,60 +1375,96 @@ ui.prototype.drawBook = function (index) { ////// 绘制怪物属性的详细信息 ////// ui.prototype.drawBookDetail = function (index) { + var info = this._drawBookDetail_getInfo(index), enemy = info[0]; + var content = info[1].join("\n"); + core.status.event.id = 'book-detail'; + clearInterval(core.interval.tipAnimate); + core.clearMap('data'); + + var left = 10, width = this.PIXEL - 2 * left, right = left + width; + var content_left = left + 25, validWidth = right - content_left - 13; + var contents = core.splitLines("data", content, validWidth, this._buildFont(16, false)); + var height = Math.max(24 * contents.length + 55, 80), top = (this.PIXEL - height) / 2, bottom = top + height; + + core.setAlpha('data', 0.9); + core.fillRect('data', left, top, width, height, '#000000'); + core.setAlpha('data', 1); + core.strokeRect('data', left - 1, top - 1, width + 1, height + 1, + core.status.globalAttribute.borderColor, 2); + + this._drawBookDetail_drawContent(enemy, contents, {top: top, content_left: content_left, bottom: bottom}); +} + +ui.prototype._drawBookDetail_getInfo = function (index) { var floorId = core.floorIds[(core.status.event.ui||{}).index] || core.status.floorId; var enemys = core.enemys.getCurrentEnemys(floorId); - if (enemys.length==0) return; - if (index<0) index=0; - if (index>=enemys.length) index=enemys.length-1; - + index = core.clamp(index, 0, enemys.length - 1); var enemy = enemys[index], enemyId = enemy.id; - var hints=core.enemys.getSpecialHint(enemyId); + var texts=core.enemys.getSpecialHint(enemyId); var damageInfo = core.enemys.getDamageInfo(enemy, null, null, null, floorId); + if (texts.length == 0) texts.push("该怪物无特殊属性。"); + texts.push(""); + this._drawBookDetail_getTexts(enemy, floorId, texts); + return [enemy, texts]; +} - if (hints.length==0) - hints.push("该怪物无特殊属性。"); +ui.prototype._drawBookDetail_getTexts = function (enemy, floorId, texts) { + // --- 模仿临界计算器 + this._drawBookDetail_mofang(enemy, texts); + // --- 吸血怪最低生命值 + this._drawBookDetail_vampire(enemy, texts); + // --- 仇恨伤害 + this._drawBookDetail_hatred(enemy, texts); + // --- 战斗回合数,临界表 + this._drawBookDetail_turnAndCriticals(enemy, floorId, texts); +} +ui.prototype._drawBookDetail_mofang = function (enemy, texts) { // 模仿临界计算器 if (core.enemys.hasSpecial(enemy.special, 10)) { var hp = enemy.hp; var delta = core.status.hero.atk - core.status.hero.def; if (delta0) { - hints.push(""); - hints.push("模仿临界计算器:(当前攻防差"+core.formatBigNumber(delta)+")"); - var arr = []; - (function () { - var last=0, start=0; - for (var i=1;i=0) { var x1 = text.substring(0, index+1); - core.fillText('data', x1, content_left, content_top, '#FF6A6A', 'bold 16px '+globalFont); + core.fillText('data', x1, pos.content_left, content_top, '#FF6A6A', this._buildFont(16, true)); var len=core.calWidth('data', x1); - core.fillText('data', text.substring(index+1), content_left+len, content_top, '#FFFFFF', '16px '+globalFont); + core.fillText('data', text.substring(index+1), pos.content_left+len, content_top, '#FFFFFF', this._buildFont(16, false)); } else { - core.fillText('data', contents[i], content_left, content_top, '#FFFFFF', '16px '+globalFont); + core.fillText('data', contents[i], pos.content_left, content_top, '#FFFFFF', this._buildFont(16, false)); } content_top+=24; } - - core.fillText('data', '<点击任意位置继续>', 270, top+height-13, '#CCCCCC', '13px '+globalFont); } ////// 绘制楼层传送器 ////// @@ -2193,177 +2207,21 @@ ui.prototype.drawStatusBar = function () { } ////// 绘制“数据统计”界面 ////// -ui.prototype.drawStatistics = function () { - - // 数据统计要统计如下方面: - // 1. 当前全塔剩余下的怪物数量,总金币数,总经验数,总加点数 - // 2. 当前全塔剩余的黄蓝红铁门数量,和对应的钥匙数量 - // 3. 当前全塔剩余的三种宝石数量,血瓶数量,装备数量;总共增加的攻防生命值 - // 4. 当前层的上述信息 - // 5. 当前已走的步数;瞬间移动的步数,瞬间移动的次数(和少走的步数);游戏时长 - // 6. 当前已恢复的生命值;当前总伤害、战斗伤害、阻激夹域血网伤害、中毒伤害。 - - var ori = this.uidata.drawStatistics(); - var ids = ori.filter(function (e) { - return e.endsWith("Door") || core.isset(core.material.items[e]); +ui.prototype.drawStatistics = function (floorIds) { + var obj = this._drawStatistics_buildObj(); + if (typeof floorIds == 'string') floorIds = [floorIds]; + (floorIds || core.floorIds).forEach(function (floorId) { + core.ui._drawStatistics_floorId(floorId, obj); }); - var obj = {}; - var cls = {}; - ids.forEach(function (e) { - if (e.endsWith("Door")) cls[e] = "doors"; - else cls[e] = core.material.items[e].cls; - obj[e] = 0; - }) - var order = ["doors", "keys", "items", "tools", "constants", "equips"]; - ids.sort(function (a, b) { - var c1 = order.indexOf(cls[a]), c2 = order.indexOf(cls[b]); - if (c1==c2) return ori.indexOf(a)-ori.indexOf(b); - return c1-c2; - }); - var ext = {}; - - var total = { - 'monster': { - 'count': 0, 'money': 0, 'experience': 0, 'point': 0, - }, - 'count': obj, - 'add': { - 'hp': 0, 'atk': 0, 'def': 0, 'mdef': 0 - } - }; - var current = core.clone(total); - - core.floorIds.forEach(function (floorId) { - var floor=core.status.maps[floorId]||core.floors[floorId]; - var blocks=core.status.maps[floorId].blocks; - // 隐藏层不给看 - if (floor.cannotViewMap && floorId!=core.status.floorId) return; - - blocks.forEach(function (block) { - if (block.disable) return; - var event = block.event; - if (event.cls.indexOf("enemy")==0) { - var enemyId = event.id, enemy = core.material.enemys[enemyId]; - total.monster.money+=enemy.money||0; - total.monster.experience+=enemy.experience||0; - total.monster.point+=enemy.point||0; - total.monster.count++; - if (floorId==core.status.floorId) { - current.monster.money+=enemy.money||0; - current.monster.experience+=enemy.experience||0; - current.monster.point+=enemy.point||0; - current.monster.count++; - } - } - else { - var id = event.id; - - if (core.isset(total.count[id])) { - var hp=0, atk=0, def=0, mdef=0; - - if (cls[id]=='items' && id!='superPotion') { - var temp = core.clone(core.status.hero); - core.setFlag("__statistics__", true); - var ratio = floor.item_ratio||1; - if (core.isset(core.items.itemEffect[id])) { - try { - // 需要检查是否是测试状态... - eval(core.items.itemEffect[id]); - } - catch (e) {} - } - hp = core.status.hero.hp - temp.hp; - atk = core.status.hero.atk - temp.atk; - def = core.status.hero.def - temp.def; - mdef = core.status.hero.mdef - temp.mdef; - core.status.hero = temp; - } - else { - // 装备 - if (cls[id]=='equips') { - var values = core.material.items[id].equip||{}; - atk = values.atk||0; - def = values.def||0; - mdef = values.mdef||0; - } - } - - if (id.indexOf('sword')==0 || id.indexOf('shield')==0 || cls[id]=='equips') { - var t = ""; - if (atk>0) t+=atk+"攻"; - if (def>0) t+=def+"防"; - if (mdef>0) t+=mdef+"魔防"; - if (t!="") ext[id]=t; - } - - total.count[id]++; - total.add.hp+=hp; - total.add.atk+=atk; - total.add.def+=def; - total.add.mdef+=mdef; - if (floorId==core.status.floorId) { - current.count[id]++; - current.add.hp+=hp; - current.add.atk+=atk; - current.add.def+=def; - current.add.mdef+=mdef; - } - } - } - }) - }) - - var getText = function (type, data) { - var text = type+"地图中:\n"; - text += "共有怪物"+data.monster.count+"个"; - if (core.flags.enableMoney) text+=",总金币数"+data.monster.money; - if (core.flags.enableExperience) text+=",总经验数"+data.monster.experience; - if (core.flags.enableAddPoint) text+=",总加点数"+data.monster.point; - text+="。\n"; - - var prev = ""; - ids.forEach(function (key) { - var value = data.count[key]; - if (value==0) return; - var c = cls[key]; - if (c!=prev) { - if (prev != "") text += "。"; - text += "\n"; - } - else - text += ","; - prev = c; - var name = null; - if (key=='yellowDoor') name="黄门"; - else if (key=='blueDoor') name="蓝门"; - else if (key=='redDoor') name="红门"; - else if (key=='greenDoor') name="绿门"; - else if (key=='steelDoor') name="铁门"; - else name=core.material.items[key].name; - text+=name+value+"个"; - if (core.isset(ext[key])) - text+="("+ext[key]+")"; - }) - - if (prev!="") text+="。"; - text+="\n\n"; - text+="共加生命值"+core.formatBigNumber(data.add.hp)+"点,攻击" - +core.formatBigNumber(data.add.atk)+"点,防御" - +core.formatBigNumber(data.add.def)+"点,魔防" - +core.formatBigNumber(data.add.mdef)+"点。"; - return text; - } - var formatTime = function (time) { return core.setTwoDigits(parseInt(time/3600000)) +":"+core.setTwoDigits(parseInt(time/60000)%60) +":"+core.setTwoDigits(parseInt(time/1000)%60); } - var statistics = core.status.hero.statistics; core.drawText([ - getText("全塔", total), - getText("当前", current), + this._drawStatistics_generateText(obj, "全塔", obj.total), + this._drawStatistics_generateText(obj, "当前", obj.current), "当前总步数:"+core.status.hero.steps+",当前游戏时长:"+formatTime(statistics.currTime) +",总游戏时长"+formatTime(statistics.totalTime) +"。\n瞬间移动次数:"+statistics.moveDirectly+",共计少走"+statistics.ignoreSteps+"步。" @@ -2375,10 +2233,148 @@ ui.prototype.drawStatistics = function () { +",领域/夹击/阻击/血网伤害"+core.formatBigNumber(statistics.extraDamage)+"点。", "\t[说明]1. 地图数据统计的效果仅模拟当前立刻获得该道具的效果。\n2. 不会计算“不可被浏览地图”的隐藏层的数据。\n" + "3. 不会计算任何通过事件得到的道具(显示事件、改变图块、或直接增加道具等)。\n"+ - "4. 在自定义道具(例如其他宝石)后,需在ui.js的drawStatistics中注册,不然不会进行统计。\n"+ + "4. 在自定义道具(例如其他宝石)后,需在脚本编辑的drawStatistics中注册,不然不会进行统计。\n"+ "5. 所有统计信息仅供参考,如有错误,概不负责。" ]) +} +ui.prototype._drawStatistics_buildObj = function () { + // 数据统计要统计如下方面: + // 1. 当前全塔剩余下的怪物数量,总金币数,总经验数,总加点数 + // 2. 当前全塔剩余的黄蓝红铁门数量,和对应的钥匙数量 + // 3. 当前全塔剩余的三种宝石数量,血瓶数量,装备数量;总共增加的攻防生命值 + // 4. 当前层的上述信息 + // 5. 当前已走的步数;瞬间移动的步数,瞬间移动的次数(和少走的步数);游戏时长 + // 6. 当前已恢复的生命值;当前总伤害、战斗伤害、阻激夹域血网伤害、中毒伤害。 + var ori = this.uidata.drawStatistics(); + var ids = ori.filter(function (e) { + return e.endsWith("Door") || core.material.items[e]; + }); + var cnt = {}, cls = {}, ext = {}; + ids.forEach(function (e) { + if (e.endsWith("Door")) cls[e] = "doors"; + else cls[e] = core.material.items[e].cls; + cnt[e] = 0; + }) + var order = ["doors", "keys", "items", "tools", "constants", "equips"]; + ids.sort(function (a, b) { + var c1 = order.indexOf(cls[a]), c2 = order.indexOf(cls[b]); + if (c1==c2) return ori.indexOf(a)-ori.indexOf(b); + return c1-c2; + }); + var obj = { + 'monster': { + 'count': 0, 'money': 0, 'experience': 0, 'point': 0, + }, + 'count': cnt, + 'add': { + 'hp': 0, 'atk': 0, 'def': 0, 'mdef': 0 + } + }; + return {ids: ids, cls: cls, ext: ext, total: core.clone(obj), current: core.clone(obj)}; +} + +ui.prototype._drawStatistics_add = function (floorId, obj, x1, x2, value) { + obj.total[x1][x2] += value || 0; + if (floorId == core.status.floorId) + obj.current[x1][x2] += value || 0; +} + +ui.prototype._drawStatistics_floorId = function (floorId, obj) { + var floor = core.status.maps[floorId], blocks = floor.blocks; + // 隐藏层不给看 + if (floor.cannotViewMap && floorId!=core.status.floorId) return; + blocks.forEach(function (block) { + if (block.disable) return; + var event = block.event; + if (event.cls.indexOf("enemy")==0) { + core.ui._drawStatistics_enemy(floorId, event.id, obj); + } + else { + var id = event.id; + if (obj.total.count[id] != null) + core.ui._drawStatistics_items(floorId, floor, id, obj); + } + }) +} + +ui.prototype._drawStatistics_enemy = function (floorId, id, obj) { + var enemy = core.material.enemys[id]; + this._drawStatistics_add(floorId, obj, 'monster', 'money', enemy.money); + this._drawStatistics_add(floorId, obj, 'monster', 'experience', enemy.experience); + this._drawStatistics_add(floorId, obj, 'monster', 'point', enemy.point); + this._drawStatistics_add(floorId, obj, 'monster', 'count', 1); +} + +ui.prototype._drawStatistics_items = function (floorId, floor, id, obj) { + var hp=0, atk=0, def=0, mdef=0; + if (obj.cls[id]=='items' && id!='superPotion') { + var temp = core.clone(core.status.hero); + core.setFlag("__statistics__", true); + var ratio = floor.item_ratio||1; + try { eval(core.items.itemEffect[id]); } + catch (e) {} + hp = core.status.hero.hp - temp.hp; + atk = core.status.hero.atk - temp.atk; + def = core.status.hero.def - temp.def; + mdef = core.status.hero.mdef - temp.mdef; + core.status.hero = temp; + } + else if (obj.cls[id]=='equips') { + var values = core.material.items[id].equip || {}; + atk = values.atk || 0; + def = values.def || 0; + mdef = values.mdef || 0; + } + if (id.indexOf('sword')==0 || id.indexOf('shield')==0 || obj.cls[id]=='equips') { + var t = ""; + if (atk > 0) t += atk + "攻"; + if (def > 0) t += def + "防"; + if (mdef > 0) t += mdef + "魔防"; + if (t != "") obj.ext[id] = t; + } + this._drawStatistics_add(floorId, obj, 'count', id, 1); + this._drawStatistics_add(floorId, obj, 'add', 'hp', hp); + this._drawStatistics_add(floorId, obj, 'add', 'atk', atk); + this._drawStatistics_add(floorId, obj, 'add', 'def', def); + this._drawStatistics_add(floorId, obj, 'add', 'mdef', mdef); +} + +ui.prototype._drawStatistics_generateText = function (obj, type, data) { + var text = type+"地图中:\n"; + text += "共有怪物"+data.monster.count+"个"; + if (core.flags.enableMoney) text+=",总金币数"+data.monster.money; + if (core.flags.enableExperience) text+=",总经验数"+data.monster.experience; + if (core.flags.enableAddPoint) text+=",总加点数"+data.monster.point; + text+="。\n"; + + var prev = ""; + obj.ids.forEach(function (key) { + var value = data.count[key]; + if (value==0) return; + if (obj.cls[key] != prev) { + if (prev != "") text += "。"; + text += "\n"; + } + else text += ","; + prev = obj.cls[key]; + text+=core.ui._drawStatistics_getName(key)+value+"个"; + if (obj.ext[key]) + text+="("+obj.ext[key]+")"; + }) + if (prev!="") text+="。"; + + text+="\n\n"; + text+="共加生命值"+core.formatBigNumber(data.add.hp)+"点,攻击" + +core.formatBigNumber(data.add.atk)+"点,防御" + +core.formatBigNumber(data.add.def)+"点,魔防" + +core.formatBigNumber(data.add.mdef)+"点。"; + return text; +} + +ui.prototype._drawStatistics_getName = function (key) { + return {"yellowDoor": "黄门", "blueDoor": "蓝门", "redDoor": "红门", "greenDoor": "绿门", + "steelDoor": "铁门"}[key] || core.material.items[key].name; } ////// 绘制“关于”界面 ////// @@ -2434,7 +2430,8 @@ ui.prototype.drawHelp = function () { core.status.event.id = 'help'; core.lockControl(); core.setAlpha('ui', 1); - core.drawImage('ui', core.material.images.keyboard, 0, 0); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#FFFFFF'); + core.drawImage('ui', core.material.images.keyboard, 32 * (this.HSIZE - 6), 32 * (this.HSIZE - 6)); } else { core.drawText([ From c91831841e6c551e16ec9f9526098972f4b26e9d Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 26 Mar 2019 00:55:11 +0800 Subject: [PATCH 092/153] drawFly --- libs/ui.js | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 02bbf3a4..cb56a773 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1525,34 +1525,31 @@ ui.prototype._drawBookDetail_drawContent = function (enemy, contents, pos) { ////// 绘制楼层传送器 ////// ui.prototype.drawFly = function(page) { - core.status.event.data = page; - var floorId = core.floorIds[page]; var title = core.status.maps[floorId].title; - core.clearMap('ui'); core.setAlpha('ui', 0.85); - core.fillRect('ui', 0, 0, 416, 416, '#000000'); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000'); core.setAlpha('ui', 1); core.setTextAlign('ui', 'center'); - var globalFont = core.status.globalAttribute.font - core.fillText('ui', '楼层跳跃', 208, 60, '#FFFFFF', "bold 28px "+globalFont); - core.fillText('ui', '返回游戏', 208, 403, '#FFFFFF', "bold 15px "+globalFont) - core.fillText('ui', title, 356, 247, '#FFFFFF', "bold 19px "+globalFont); + core.fillText('ui', '楼层跳跃', this.HPIXEL, 60, '#FFFFFF', this._buildFont(28, true)); + core.fillText('ui', '返回游戏', this.HPIXEL, this.PIXEL - 13, null, this._buildFont(15, true)) + core.fillText('ui', title, this.PIXEL - 60, this.HPIXEL + 39, null, this._buildFont(19, true)); + var middle = this.HPIXEL + 39; if (core.actions._getNextFlyFloor(1) != page) { - core.fillText('ui', '▲', 356, 247 - 64, '#FFFFFF', "17px "+globalFont); - core.fillText('ui', '▲', 356, 247 - 96, '#FFFFFF', "17px "+globalFont); - core.fillText('ui', '▲', 356, 247 - 96 - 7, '#FFFFFF', "17px "+globalFont); + core.fillText('ui', '▲', this.PIXEL - 60, middle - 64, null, this._buildFont(17, false)); + core.fillText('ui', '▲', this.PIXEL - 60, middle - 96,); + core.fillText('ui', '▲', this.PIXEL - 60, middle - 96 - 7); } if (core.actions._getNextFlyFloor(-1) != page) { - core.fillText('ui', '▼', 356, 247 + 64, '#FFFFFF', "17px "+globalFont); - core.fillText('ui', '▼', 356, 247 + 96, '#FFFFFF', "17px "+globalFont); - core.fillText('ui', '▼', 356, 247 + 96 + 7, '#FFFFFF', "17px "+globalFont); + core.fillText('ui', '▼', this.PIXEL - 60, middle + 64, null, this._buildFont(17, false)); + core.fillText('ui', '▼', this.PIXEL - 60, middle + 96); + core.fillText('ui', '▼', this.PIXEL - 60, middle + 96 + 7); } - core.strokeRect('ui', 20, 100, 273, 273, '#FFFFFF', 2); - - core.drawThumbnail(floorId, null, null, {ctx: 'ui', x: 20, y: 100, size: 273}); + 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}); } ////// 绘制中心对称飞行器 From 5c0e3ade0b8d3a09c607ba099023c60c1b2d81cc Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 26 Mar 2019 02:16:06 +0800 Subject: [PATCH 093/153] drawMaps --- libs/actions.js | 34 +++++------ libs/ui.js | 159 +++++++++++++++++++++++------------------------- 2 files changed, 93 insertions(+), 100 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 9b68d44f..c8e9baeb 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1055,60 +1055,60 @@ actions.prototype._clickViewMaps = function (x, y) { core.ui.drawMaps(core.floorIds.indexOf(core.status.floorId)); return; } - var now = core.floorIds.indexOf(core.status.floorId); var index = core.status.event.data.index; var cx = core.status.event.data.x, cy = core.status.event.data.y; var floorId = core.floorIds[index], mw = core.floors[floorId].width, mh = core.floors[floorId].height; + var per = this.HSIZE - 4; - if (x == 0 && y == 0) { + if (x <= per - 2 && y <= per - 2) { core.status.event.data.damage = !core.status.event.data.damage; core.ui.drawMaps(index, cx, cy); return; } - if (x == 0 && y == 12) { + if (x <= per - 2 && y >= this.SIZE + 1 - per) { core.status.event.data.paint = !core.status.event.data.paint; core.ui.drawMaps(index, cx, cy); return; } - if (x == 12 && y == 0) { + if (x >= this.SIZE + 1 - per && y <= per - 2) { core.status.event.data.all = !core.status.event.data.all; core.ui.drawMaps(index, cx, cy); return; } - if (x >= 2 && x <= 10 && y <= 1 && mh > 13) { + if (x >= per && x <= this.LAST - per && y <= per - 1 && mh > this.SIZE) { core.ui.drawMaps(index, cx, cy - 1); return; } - if (x >= 2 && x <= 10 && y >= 11 && mh > 13) { + if (x >= per && x <= this.LAST - per && y >= this.SIZE - per && mh > this.SIZE) { core.ui.drawMaps(index, cx, cy + 1); return; } - if (x <= 1 && y >= 2 && y <= 10) { + if (x <= per - 1 && y >= per && y <= this.LAST - per) { core.ui.drawMaps(index, cx - 1, cy); return; } - if (x >= 11 && y >= 2 && y <= 10) { + if (x >= this.SIZE - per && y >= per && y <= this.LAST - per) { core.ui.drawMaps(index, cx + 1, cy); return; } - if (y <= 4 && (mh == 13 || (x >= 2 && x <= 10))) { + if (y <= this.HSIZE - 2 && (mh == this.SIZE || (x >= per && x <= this.LAST - per))) { index++; while (index < core.floorIds.length && index != now && core.status.maps[core.floorIds[index]].cannotViewMap) index++; if (index < core.floorIds.length) core.ui.drawMaps(index); } - else if (y >= 8 && (mh == 13 || (x >= 2 && x <= 10))) { + else if (y >= this.HSIZE + 2 && (mh == this.SIZE || (x >= per && x <= this.LAST - per))) { index--; while (index >= 0 && index != now && core.status.maps[core.floorIds[index]].cannotViewMap) index--; if (index >= 0) core.ui.drawMaps(index); } - else if (x >= 2 && x <= 10 && y >= 5 && y <= 7) { + else if (x >= per && x <= this.LAST - per && y >= this.HSIZE - 1 && y <= this.HSIZE + 1) { core.clearMap('data'); core.ui.closePanel(); } @@ -1120,12 +1120,12 @@ actions.prototype._keyDownViewMaps = function (keycode) { var floorId = core.floorIds[core.status.event.data.index], mh = core.floors[floorId].height; - if (keycode == 38 || keycode == 33) this._clickViewMaps(6, 3); - if (keycode == 40 || keycode == 34) this._clickViewMaps(6, 9); - if (keycode == 87 && mh > 13) this._clickViewMaps(6, 0); - if (keycode == 65) this._clickViewMaps(0, 6); - if (keycode == 83 && mh > 13) this._clickViewMaps(6, 12); - if (keycode == 68) this._clickViewMaps(12, 6); + if (keycode == 38 || keycode == 33) this._clickViewMaps(this.HSIZE, this.HSIZE - 3); + if (keycode == 40 || keycode == 34) this._clickViewMaps(this.HSIZE, this.HSIZE + 3); + if (keycode == 87 && mh > this.SIZE) this._clickViewMaps(this.HSIZE, 0); + if (keycode == 65) this._clickViewMaps(0, this.HSIZE); + if (keycode == 83 && mh > this.SIZE) this._clickViewMaps(this.HSIZE, this.LAST); + if (keycode == 68) this._clickViewMaps(this.LAST, this.HSIZE); return; } diff --git a/libs/ui.js b/libs/ui.js index cb56a773..304f5d8f 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1402,7 +1402,6 @@ ui.prototype._drawBookDetail_getInfo = function (index) { index = core.clamp(index, 0, enemys.length - 1); var enemy = enemys[index], enemyId = enemy.id; var texts=core.enemys.getSpecialHint(enemyId); - var damageInfo = core.enemys.getDamageInfo(enemy, null, null, null, floorId); if (texts.length == 0) texts.push("该怪物无特殊属性。"); texts.push(""); this._drawBookDetail_getTexts(enemy, floorId, texts); @@ -1600,100 +1599,94 @@ ui.prototype.drawShop = function (shopId) { ui.prototype.drawMaps = function (index, x, y) { core.lockControl(); core.status.event.id = 'viewMaps'; - - if (!core.isset(index)) { - core.status.event.data = null; - core.clearSelector(); - - core.fillRect('ui', 0, 0, 416, 416, 'rgba(0,0,0,0.4)'); - - core.strokeRect('ui', 66, 2, 284, 60, "#FFD700", 4); - core.strokeRect('ui', 2, 66, 60, 284); - core.strokeRect('ui', 66, 416-62, 284, 60); - core.strokeRect('ui', 416-62, 66, 60, 284); - core.strokeRect('ui', 66, 66, 284, 92); - core.strokeRect('ui', 66, 32*8+2, 284, 92); - core.setTextAlign('ui', 'center'); - core.fillText('ui', "上移地图 [W]", 208, 38, '#FFD700', '20px Arial'); - core.fillText('ui', "下移地图 [S]", 208, 390); - - core.strokeRect('ui', 2, 2, 28, 28); - core.fillText('ui', 'V', 16, 24); - core.strokeRect('ui', 2, 416-30, 28, 28); - core.fillText('ui', 'M', 16, 408); - core.strokeRect('ui', 416-30, 2, 28, 28); - core.fillText('ui', 'Z', 400, 24); - - var top = 150; - core.fillText('ui', "左", 32, top); - core.fillText('ui', "移", 32, top+32); - core.fillText('ui', "地", 32, top+32*2); - core.fillText('ui', "图", 32, top+32*3); - core.fillText('ui', "[A]", 32, top+32*4); - core.fillText('ui', "右", 384, top); - core.fillText('ui', "移", 384, top+32); - core.fillText('ui', "地", 384, top+32*2); - core.fillText('ui', "图", 384, top+32*3); - core.fillText('ui', "[D]", 384, top+32*4); - - core.fillText('ui', "前张地图 [▲ / PGUP]", 208, 64+54); - core.fillText('ui', "后张地图 [▼ / PGDN]", 208, 32*8+54); - - core.fillText('ui', "退出 [ESC / ENTER]", 208, 208+8); - core.fillText('ui', "[X] 可查看怪物手册", 285, 208+40, null, '13px Arial'); - - return; - } - - var damage = (core.status.event.data||{}).damage, paint = (core.status.event.data||{}).paint; - var all = (core.status.event.data||{}).all; - if (core.isset(index.damage)) damage=index.damage; - if (core.isset(index.paint)) paint=index.paint; - if (core.isset(index.all)) all=index.all; - - if (core.isset(index.index)) { - x=index.x; - y=index.y; - index=index.index; - } - - if (index<0) index=0; - if (index>=core.floorIds.length) index=core.floorIds.length-1; - var floorId = core.floorIds[index], mw = core.floors[floorId].width, mh = core.floors[floorId].height; - if (!core.isset(x)) x = parseInt(mw/2); - if (!core.isset(y)) y = parseInt(mh/2); - if (x<6) x=6; - if (x>mw-7) x=mw-7; - if (y<6) y=6; - if (y>mh-7) y=mh-7; - - core.status.event.data = {"index": index, "x": x, "y": y, "damage": damage, "paint": paint, "all": all}; - + this.clearUI(); + if (index == null) return this._drawMaps_drawHint(); clearTimeout(core.interval.tipAnimate); - core.clearSelector(); core.status.checkBlock.cache = {}; - core.drawThumbnail(floorId, null, {damage: damage}, {ctx: 'ui', centerX: x, centerY: y, all: all}); - + var data = this._drawMaps_buildData(index, x, y); + core.drawThumbnail(data.floorId, null, {damage: data.damage}, + {ctx: 'ui', centerX: data.x, centerY: data.y, all: data.all}); // 绘图 - if (core.status.event.data.paint) { - var offsetX = core.clamp(x-6, 0, mw-13), offsetY = core.clamp(y-6, 0, mh-13); - var value = core.paint[floorId]; - if (core.isset(value)) value = lzw_decode(value).split(","); - core.utils.decodeCanvas(value, 32*mw, 32*mh); - core.drawImage('ui', core.bigmap.tempCanvas.canvas, offsetX*32, offsetY*32, 416, 416, 0, 0, 416, 416); + if (data.paint) { + var offsetX = 32 * (data.x - this.HSIZE), offsetY = 32 * (data.y - this.HSIZE); + var value = core.paint[data.floorId]; + if (value) value = lzw_decode(value).split(","); + core.utils.decodeCanvas(value, 32 * data.mw, 32 * data.mh); + core.drawImage('ui', core.bigmap.tempCanvas.canvas, offsetX * 32, offsetY * 32, + this.PIXEL, this.PIXEL, 0, 0, this.PIXEL, this.PIXEL); } - core.clearMap('data'); core.setTextAlign('data', 'left'); core.setFont('data', '16px Arial'); - - var text = core.status.maps[floorId].title; - if (!all && (mw>13 || mh>13)) text+=" ["+(x-6)+","+(y-6)+"]"; + var text = core.status.maps[data.floorId].title; + if (!data.all && (data.mw>this.SIZE || data.mh>this.SIZE)) + text+=" ["+(data.x-this.HSIZE)+","+(data.y-this.HSIZE)+"]"; var textX = 16, textY = 18, width = textX + core.calWidth('data', text) + 16, height = 42; core.fillRect('data', 5, 5, width, height, 'rgba(0,0,0,0.4)'); core.fillText('data', text, textX + 5, textY + 15, 'rgba(255,255,255,0.6)'); } +ui.prototype._drawMaps_drawHint = function () { + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, 'rgba(0,0,0,0.4)'); + core.setTextAlign('ui', 'center'); + var stroke = function (left, top, width, height, fillStyle, lineWidth) { + core.strokeRect('ui', left*32+2, top*32+2, width*32-4, height*32-4, fillStyle, lineWidth); + } + var per = this.HSIZE - 4; + stroke(per, 0, 9, per, '#FFD700', 4); // up + stroke(0, per, per, 9); // left + stroke(per, this.SIZE - per, 9, per); // down + stroke(this.SIZE - per, per, per, 9); // right + stroke(per, per, 9, 3); // prev + stroke(per, this.SIZE - per - 3, 9, 3); // next + stroke(0, 0, per-1, per-1); // left top + stroke(this.SIZE-(per - 1), 0, per-1, per-1); // right top + stroke(0, this.SIZE-(per-1), per-1, per-1); // left bottom + + core.setTextBaseline('ui', 'middle'); + core.fillText('ui', "上移地图 [W]", this.HPIXEL, per * 16, '#FFD700', '20px Arial'); + core.fillText('ui', "下移地图 [S]", this.HPIXEL, this.PIXEL - per * 16); + core.fillText('ui', 'V', (per-1)*16, (per-1)*16); + core.fillText('ui', 'Z', this.PIXEL - (per-1)*16, (per-1)*16); + core.fillText('ui', 'M', (per-1)*16, this.PIXEL - (per-1)*16); + + var top = this.HPIXEL - 66, left = per * 16, right = this.PIXEL - left; + var lt = ["左", "移", "地", "图", "[A]"], rt = ["右", "移", "地", "图", "[D]"]; + for (var i = 0; i < 5; ++i) { + core.fillText("ui", lt[i], left, top + 32 * i); + core.fillText("ui", rt[i], right, top + 32 * i); + } + core.fillText('ui', "前张地图 [▲ / PGUP]", this.HPIXEL, 32 * per + 48); + core.fillText('ui', "后张地图 [▼ / PGDN]", this.HPIXEL, this.PIXEL - (32 * per + 48)); + + core.fillText('ui', "退出 [ESC / ENTER]", this.HPIXEL, this.HPIXEL); + core.fillText('ui', "[X] 可查看怪物手册", this.HPIXEL + 77, this.HPIXEL + 32, null, '13px Arial'); + + core.setTextBaseline('ui', 'alphabetic'); +} + +ui.prototype._drawMaps_buildData = function (index, x, y) { + var damage = (core.status.event.data||{}).damage; + var paint = (core.status.event.data||{}).paint; + var all = (core.status.event.data||{}).all; + if (index.damage != null) damage=index.damage; + if (index.paint != null) paint=index.paint; + if (index.all != null) all=index.all; + if (index.index != null) { x=index.x; y=index.y; index=index.index; } + index = core.clamp(index, 0, core.floorIds.length-1); + if (damage == null) damage = true; // 浏览地图默认开显伤好了 + + var floorId = core.floorIds[index], mw = core.floors[floorId].width, mh = core.floors[floorId].height; + if (x == null) x = parseInt(mw / 2); + if (y == null) y = parseInt(mh / 2); + x = core.clamp(x, this.HSIZE, mw - this.HSIZE - 1); + y = core.clamp(y, this.HSIZE, mh - this.HSIZE - 1); + + core.status.event.data = {index: index, x: x, y: y, floorId: floorId, mw: mw, mh: mh, + damage: damage, paint: paint, all: all }; + return core.status.event.data; +} + ////// 绘制道具栏 ////// ui.prototype.drawToolbox = function(index) { // 设定eventdata From 4e8c4c1798523ce30595d2f306adc374c5feba89 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 26 Mar 2019 22:32:21 +0800 Subject: [PATCH 094/153] startGame replay & init sys flags --- libs/core.js | 17 ++++++++++------- libs/events.js | 8 ++++++-- project/functions.js | 1 + 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/libs/core.js b/libs/core.js index 58d41ec9..4ef06a69 100644 --- a/libs/core.js +++ b/libs/core.js @@ -227,13 +227,7 @@ core.prototype._init_flags = function () { core.flags = core.clone(core.data.flags); core.values = core.clone(core.data.values); core.firstData = core.clone(core.data.firstData); - - if (!core.flags.enableExperience) core.flags.enableLevelUp = false; - if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false; - if (core.flags.equipboxButton) core.flags.equipment = true; - core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); - core.flags.displayCritical = core.getLocalStorage('critical', core.flags.displayCritical); - core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', core.flags.displayExtraDamage); + this._init_sys_flags(); core.dom.versionLabel.innerHTML = core.firstData.version; core.dom.logoLabel.innerHTML = core.firstData.title; @@ -248,6 +242,15 @@ core.prototype._init_flags = function () { core.material.icons = core.icons.getIcons(); } +core.prototype._init_sys_flags = function () { + if (!core.flags.enableExperience) core.flags.enableLevelUp = false; + if (!core.flags.enableLevelUp) core.flags.levelUpLeftMode = false; + if (core.flags.equipboxButton) core.flags.equipment = true; + core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', core.flags.displayEnemyDamage); + core.flags.displayCritical = core.getLocalStorage('critical', core.flags.displayCritical); + core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', core.flags.displayExtraDamage); +} + core.prototype._init_platform = function () { core.platform.isOnline = location.protocol.indexOf("http") == 0; if (!core.platform.isOnline) alert("请勿直接打开html文件!使用启动服务或者APP进行离线游戏。"); diff --git a/libs/events.js b/libs/events.js index e15598e3..fd81f219 100644 --- a/libs/events.js +++ b/libs/events.js @@ -16,7 +16,7 @@ events.prototype._init = function () { /// 初始化游戏 events.prototype.resetGame = function (hero, hard, floorId, maps, values) { - return this.eventdata.resetGame(hero, hard, floorId, maps, values); + this.eventdata.resetGame(hero, hard, floorId, maps, values); } ////// 游戏开始事件 ////// @@ -75,7 +75,11 @@ events.prototype._startGame_afterStart = function (nowLoc, callback) { core.ui.closePanel(); core.showStatusBar(); core.dom.musicBtn.style.display = 'none'; - core.changeFloor(core.firstData.floorId, null, nowLoc, null, callback); + core.changeFloor(core.firstData.floorId, null, nowLoc, null, function () { + // 插入一个空事件避免直接回放录像出错 + core.insertAction([]); + if (callback) callback(); + }); this._startGame_upload(); } diff --git a/project/functions.js b/project/functions.js index 64fc7537..64e05bf8 100644 --- a/project/functions.js +++ b/project/functions.js @@ -34,6 +34,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = var globalFlags = core.getFlag("globalFlags", {}); for (var key in globalFlags) core.flags[key] = globalFlags[key]; + core._init_sys_flags(); // 初始化界面,状态栏等 core.resize(); core.updateGlobalAttribute(); From 209f10d7a29c096e1320fde8697d31248cdc4ddf Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 27 Mar 2019 00:33:18 +0800 Subject: [PATCH 095/153] drawBook --- libs/ui.js | 267 ++++++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 124 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 304f5d8f..14007f9a 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1226,151 +1226,170 @@ ui.prototype.drawCursor = function () { ui.prototype.drawBook = function (index) { var floorId = core.floorIds[(core.status.event.ui||{}).index] || core.status.floorId; var enemys = core.enemys.getCurrentEnemys(floorId); - - core.clearSelector(); + core.clearUI(); core.clearMap('data'); + if (this._drawBook_drawBackground(floorId, enemys)) return; + index = core.clamp(index, 0, enemys.length - 1); + var perpage = this.HSIZE, page = parseInt(index / perpage) + 1; + var totalPage = parseInt((enemys.length - 1) / perpage) + 1; + core.status.event.data = index; + var start = (page - 1) * perpage, end = Math.min(page * perpage, enemys.length); + enemys = enemys.slice(start, end); + + for (var i = 0; i < enemys.length; i++) { + this._drawBook_drawOne(floorId, i, enemys[i]); + } + + if (index - start >= 0 && index - start < enemys.length) { + core.strokeRect('ui', 10, 62 * (index - start) + 13, this.PIXEL - 10 * 2, 62, '#FFD700'); + } + + core.drawBoxAnimate(); + this.drawPagination(page, totalPage); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); +} + +ui.prototype._drawBook_drawBackground = function (floorId, enemys) { // 生成groundPattern core.maps.generateGroundPattern(floorId); core.setFillStyle('ui', core.material.groundPattern); - core.fillRect('ui', 0, 0, 416, 416); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL); core.setAlpha('ui', 0.6); core.setFillStyle('ui', '#000000'); - core.fillRect('ui', 0, 0, 416, 416); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL); core.setAlpha('ui', 1); - core.setTextAlign('ui', 'left'); - var globalFont = core.status.globalAttribute.font; - core.setFont('ui', 'bold 15px '+globalFont); - if (enemys.length == 0) { - core.fillText('ui', "本层无怪物", 83, 222, '#999999', "bold 50px "+globalFont); - // 退出 core.setTextAlign('ui', 'center'); - core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); - return; + core.fillText('ui', "本层无怪物", this.HPIXEL, this.HPIXEL + 14, '#999999', this._buildFont(50, true)); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); + return true; } + return false; +} - if (index<0) index=0; - if (index>=enemys.length) index=enemys.length-1; - var perpage = 6; - var page=parseInt(index/perpage)+1; - var totalPage = parseInt((enemys.length - 1) / perpage) + 1; - core.status.event.data = index; - var start = (page - 1) * perpage, end = Math.min(page * perpage, enemys.length); +ui.prototype._drawBook_drawOne = function (floorId, index, enemy) { + // --- 区域规划:每个区域总高度为62,宽度为 PIXEL + var top = 62 * index + 12; // 最上面margin是12px + // 横向规划: + // 22 + 42 = 64 是头像框 + this._drawBook_drawBox(index, enemy, top); + // 剩余 PIXEL - 64 的宽度,按照 10 : 9 : 8 : 8 的比例划分 + var left = 64, total_width = this.PIXEL - left; + var name_width = total_width * 10 / 35, + col1_width = total_width * 9 / 35, col1_offset = left + name_width, + col2_width = total_width * 8 / 35, col2_offset = col1_offset + col2_width, + col3_width = total_width * 8 / 35, col3_offset = col2_offset + col3_width; + this._drawBook_drawNameCol(index, enemy, top, left, name_width); - enemys = enemys.slice(start, end); - core.status.boxAnimateObjs = []; - for (var i = 0; i < enemys.length; i++) { - // 边框 - var enemy = enemys[i]; - core.strokeRect('ui', 22, 62 * i + 22, 42, 42, '#DDDDDD', 2); + // 第二行:金币、加点、经验 + var second_line = []; + if (core.flags.enableMoney) second_line.push(["金币", core.formatBigNumber(enemy.money || 0)]); + if (core.flags.enableAddPoint) second_line.push(["加点", core.formatBigNumber(enemy.point || 0)]); + if (core.flags.enableExperience && second_line.length < 2) + second_line.push(["经验", core.formatBigNumber(enemy.experience || 0)]); + var cnt = second_line.length; - var cls = 'enemys'; - if (core.isset(core.material.icons.enemy48[enemy.id])) - cls = 'enemy48'; - var height = cls=='enemy48'?48:32; - var animate = cls=='enemy48'?4:2; + this._drawBook_drawCol1(index, enemy, top, col1_offset, col1_width, second_line); + this._drawBook_drawCol2(index, enemy, top, col2_offset, col2_width, second_line); + this._drawBook_drawCol3(index, enemy, top, col3_offset, col3_width); - // 怪物 - core.status.boxAnimateObjs.push({ - 'bgx': 22, 'bgy': 62 * i + 22, 'bgWidth': 42, 'bgHeight': 42, - 'x': 27, 'y': 62 * i + 27, 'height': 32, 'animate': animate, - 'image': core.material.images[cls], - 'pos': core.material.icons[cls][enemy.id] * height - }); + // get damage offset + var damageOffset = col1_offset + (col1_width + col2_width + col3_width) / 2 - 12; + if (cnt == 1) damageOffset = col2_offset + (col2_width + col3_width) / 2 - 12; + else if (cnt == 2) damageOffset = col3_offset + col3_width / 2 - 12; + this._drawBook_drawDamage(index, enemy, top, damageOffset); +} - // 数据 - core.setTextAlign('ui', 'center'); +ui.prototype._drawBook_drawBox = function (index, enemy, top) { + // 横向:22+42;纵向:10 + 42 + 10(正好居中);内部图像 32x32 + var border_top = top + 10, border_left = 22; + var img_top = border_top + 5, img_left = border_left + 5; + core.strokeRect('ui', 22, border_top, 42, 42, '#DDDDDD', 2); + var blockInfo = core.getBlockInfo(enemy.id); + core.status.boxAnimateObjs.push({ + 'bgx': border_left, 'bgy': border_top, 'bgWidth': 42, 'bgHeight': 42, + 'x': img_left, 'y': img_top, 'height': 32, 'animate': blockInfo.animate, + 'image': blockInfo.image, 'pos': blockInfo.posY * blockInfo.height + }); +} - if (enemy.specialText=='') { - core.fillText('ui', enemy.name, 115, 62 * i + 47, '#DDDDDD', 'bold 17px '+globalFont); - } - else { - core.fillText('ui', enemy.name, 115, 62 * i + 40, '#DDDDDD', 'bold 17px '+globalFont); - core.fillText('ui', enemy.specialText, 115, 62 * i + 62, '#FF6A6A', 'bold 15px '+globalFont); - } - core.setTextAlign('ui', 'left'); - core.fillText('ui', '生命', 165, 62 * i + 32, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.hp||0), 195, 62 * i + 32, '#DDDDDD', 'bold 13px '+globalFont); - core.fillText('ui', '攻击', 255, 62 * i + 32, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.atk||0), 285, 62 * i + 32, '#DDDDDD', 'bold 13px '+globalFont); - core.fillText('ui', '防御', 335, 62 * i + 32, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.def||0), 365, 62 * i + 32, '#DDDDDD', 'bold 13px '+globalFont); - - var expOffset = 165, line_cnt=0; - if (core.flags.enableMoney) { - core.fillText('ui', '金币', 165, 62 * i + 50, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.money||0), 195, 62 * i + 50, '#DDDDDD', 'bold 13px '+globalFont); - expOffset = 255; - line_cnt++; - } - - // 加点 - if (core.flags.enableAddPoint) { - core.setTextAlign('ui', 'left'); - core.fillText('ui', '加点', expOffset, 62 * i + 50, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.point||0), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px '+globalFont); - expOffset = 255; - line_cnt++; - } - - if (core.flags.enableExperience && line_cnt<2) { - core.setTextAlign('ui', 'left'); - core.fillText('ui', '经验', expOffset, 62 * i + 50, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.experience||0), expOffset + 30, 62 * i + 50, '#DDDDDD', 'bold 13px '+globalFont); - line_cnt++; - } - - var damageOffset = 281; - if (line_cnt==1) damageOffset=326; - if (line_cnt==2) damageOffset=361; - - core.setTextAlign('ui', 'center'); - - var damage = enemy.damage; - var color = '#FFFF00'; - if (damage == null) { - damage = '无法战斗'; - color = '#FF0000'; - } - else { - if (damage >= core.status.hero.hp) color = '#FF0000'; - if (damage<=0) color = '#00FF00'; - - damage = core.formatBigNumber(damage); - if (core.enemys.hasSpecial(enemy, 19)) - damage += "+"; - if (core.enemys.hasSpecial(enemy, 21)) - damage += "-"; - if (core.enemys.hasSpecial(enemy, 11)) - damage += "^"; - } - if (enemy.notBomb) - damage += "[b]"; - core.fillText('ui', damage, damageOffset, 62 * i + 50, color, 'bold 13px '+globalFont); - - core.setTextAlign('ui', 'left'); - - core.fillText('ui', '临界', 165, 62 * i + 68, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.critical||0), 195, 62 * i + 68, '#DDDDDD', 'bold 13px '+globalFont); - core.fillText('ui', '减伤', 255, 62 * i + 68, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.criticalDamage||0), 285, 62 * i + 68, '#DDDDDD', 'bold 13px '+globalFont); - core.fillText('ui', '1防', 335, 62 * i + 68, '#DDDDDD', '13px '+globalFont); - core.fillText('ui', core.formatBigNumber(enemy.defDamage||0), 365, 62 * i + 68, '#DDDDDD', 'bold 13px '+globalFont); - - if (index == start+i) { - core.strokeRect('ui', 10, 62 * i + 13, 416-10*2, 62, '#FFD700'); - } - - } - core.drawBoxAnimate(); - this.drawPagination(page, totalPage, 12); +ui.prototype._drawBook_drawNameCol = function (index, enemy, top, left, width) { + // 绘制第零列(名称和特殊属性) + // 如果需要添加自己的比如怪物的称号等,也可以在这里绘制 core.setTextAlign('ui', 'center'); - // 退出 - core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); + if (enemy.specialText=='') { + core.fillText('ui', enemy.name, left + width / 2, + top + 35, '#DDDDDD', this._buildFont(17, true)); + } + else { + core.fillText('ui', enemy.name, left + width / 2, + top + 28, '#DDDDDD', this._buildFont(17, true)); + core.fillText('ui', enemy.specialText, left + width / 2, + top + 50, '#FF6A6A', this._buildFont(15, true)); + } +} + +ui.prototype._drawBook_drawCol1 = function (index, enemy, top, left, width, second_line) { + // 绘制第一列 + core.setTextAlign('ui', 'left'); + var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); + core.fillText('ui', '生命', left, top + 20, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.hp||0), left + 30, top + 20, null, b13); + if (second_line.length>0) { + var one = second_line.shift(); + core.fillText('ui', one[0], left, top + 38, '#DDDDDD', f13); + core.fillText('ui', one[1], left + 30, top + 38, null, b13); + } + core.fillText('ui', '临界', left, top + 56, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.critical||0), left + 30, top + 56, null, b13); +} + +ui.prototype._drawBook_drawCol2 = function (index, enemy, top, left, width, second_line) { + // 绘制第二列 + core.setTextAlign('ui', 'left'); + var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); + core.fillText('ui', '攻击', left, top + 20, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.atk||0), left + 30, top + 20, null, b13); + if (second_line.length>0) { + var one = second_line.shift(); + core.fillText('ui', one[0], left, top + 38, '#DDDDDD', f13); + core.fillText('ui', one[1], left + 30, top + 38, null, b13); + } + core.fillText('ui', '减伤', left, top + 56, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.criticalDamage||0), left + 30, top + 56, null, b13); +} + +ui.prototype._drawBook_drawCol3 = function (index, enemy, top, left, width) { + // 绘制第三列 + core.setTextAlign('ui', 'left'); + var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); + core.fillText('ui', '防御', left, top + 20, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.def||0), left + 30, top + 20, null, b13); + core.fillText('ui', '1防', left, top + 56, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.defDamage||0), left + 30, top + 56, null, b13); +} + +ui.prototype._drawBook_drawDamage = function (index, enemy, top, damageOffset) { + core.setTextAlign('ui', 'center'); + var damage = enemy.damage, color = '#FFFF00'; + if (damage == null) { + damage = '无法战斗'; + color = '#FF0000'; + } + else { + if (damage >= core.status.hero.hp) color = '#FF0000'; + if (damage <= 0) color = '#00FF00'; + damage = core.formatBigNumber(damage); + if (core.enemys.hasSpecial(enemy, 19)) damage += "+"; + if (core.enemys.hasSpecial(enemy, 21)) damage += "-"; + if (core.enemys.hasSpecial(enemy, 11)) damage += "^"; + } + if (enemy.notBomb) damage += "[b]"; + core.fillText('ui', damage, damageOffset, top + 38, color, this._buildFont(13, true)); } ////// 绘制怪物属性的详细信息 ////// From 2da164af9c62b60cdcbf2eba25f629b08b12a53b Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 26 Mar 2019 14:02:47 -0400 Subject: [PATCH 096/153] fix bug in editor_table --- _server/editor_table.js | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/_server/editor_table.js b/_server/editor_table.js index 09009ab2..33a1465f 100644 --- a/_server/editor_table.js +++ b/_server/editor_table.js @@ -8,12 +8,11 @@ editor_table_wrapper = function (editor) { // HTML模板 editor_table.prototype.select = function (value, values) { - return `\n` + return `\n` } editor_table.prototype.option = function (value) { return `\n` @@ -165,7 +164,9 @@ editor_table_wrapper = function (editor) { var listen = function (guids) { // 每个叶节点的事件绑定 - guids.forEach(editor.table.guidListen); + guids.forEach(function (guid) { + editor.table.guidListen(guid, obj, commentObj) + }); } return { "HTML": outstr.join(''), "guids": guids, "listen": listen }; } @@ -249,7 +250,7 @@ editor_table_wrapper = function (editor) { * 监听一个guid对应的表格项 * @param {String} guid */ - editor_table.prototype.guidListen = function (guid) { + editor_table.prototype.guidListen = function (guid, obj, commentObj) { // tr>td[title=field] // >td[title=comment,cobj=cobj:json] // >td>div>input[value=thiseval] @@ -262,7 +263,7 @@ editor_table_wrapper = function (editor) { modeNode = modeNode.parentNode; } input.onchange = function () { - editor.table.onchange(guid, thisTr, input, field, cobj, modeNode) + editor.table.onchange(guid, obj, commentObj, thisTr, input, field, cobj, modeNode) } // 用检测两次单击的方式来实现双击(以支持手机端的双击) var doubleClickCheck = [0]; @@ -271,7 +272,7 @@ editor_table_wrapper = function (editor) { var lastClick = doubleClickCheck.shift(); doubleClickCheck.push(newClick); if (newClick - lastClick < 500) { - editor.table.dblclickfunc(guid, thisTr, input, field, cobj, modeNode) + editor.table.dblclickfunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode) } } } @@ -279,7 +280,7 @@ editor_table_wrapper = function (editor) { /** * 表格的值变化时 */ - editor_table.prototype.onchange = function (guid, thisTr, input, field, cobj, modeNode) { + editor_table.prototype.onchange = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) { editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]); var thiseval = null; if (input.checked != null) input.value = input.checked; @@ -304,23 +305,23 @@ editor_table_wrapper = function (editor) { * 删除: 删除该项, 刷新后生效 * 在点击按钮 添加/删除 后,下一次双击将被视为 添加/删除 */ - editor_table.prototype.dblclickfunc = function (guid, thisTr, input, field, cobj, modeNode) { + editor_table.prototype.dblclickfunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) { if (editor_mode.doubleClickMode === 'change') { if (cobj._type === 'event') editor_blockly.import(guid, { type: cobj._event }); if (cobj._type === 'textarea') editor_multi.import(guid, { lint: cobj._lint, string: cobj._string }); } else if (editor_mode.doubleClickMode === 'add') { editor_mode.doubleClickMode = 'change'; - editor.table.addfunc(guid, thisTr, input, field, cobj, modeNode) + editor.table.addfunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode) } else if (editor_mode.doubleClickMode === 'delete') { editor_mode.doubleClickMode = 'change'; - editor.table.deletefunc(guid, thisTr, input, field, cobj, modeNode) + editor.table.deletefunc(guid, obj, commentObj, thisTr, input, field, cobj, modeNode) } } /** * 删除表格项 */ - editor_table.prototype.deletefunc = function (guid, thisTr, input, field, cobj, modeNode) { + editor_table.prototype.deletefunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) { editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]); if (editor.table.checkRange(cobj, null)) { editor_mode.addAction(['delete', field, undefined]); @@ -333,7 +334,7 @@ editor_table_wrapper = function (editor) { /** * 添加表格项 */ - editor_table.prototype.addfunc = function (guid, thisTr, input, field, cobj, modeNode) { + editor_table.prototype.addfunc = function (guid, obj, commentObj, thisTr, input, field, cobj, modeNode) { editor_mode.onmode(editor_mode._ids[modeNode.getAttribute('id')]); var mode = document.getElementById('editModeSelect').value; From 0023a16007e1020710d2fde537d69e9c940f9ffd Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Tue, 26 Mar 2019 14:27:10 -0400 Subject: [PATCH 097/153] Update refactoring.md --- _server/refactoring.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/_server/refactoring.md b/_server/refactoring.md index 5d92d0f4..0dd94dd4 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -10,32 +10,34 @@ + [x] editor_blockly 图块化事件编辑器, 基本不改动 + [x] editor_multi 多行文本编辑器, 基本不改动 -+ [ ] editor_table 处理表格的生成, 及其响应的事件, 从原editor\_mode中分离 ++ [x] editor_table 处理表格的生成, 及其响应的事件, 从原editor\_mode中分离 + [ ] editor_file 调用fs.js编辑文件, 把原editor\_file模块化 + [ ] editor_game 处理来自core的数据, 导入为editor的数据, 从原editor中分离 -+ [ ] editor_util 生成guid等函数, 从editor分离 ++ [x] editor_util 生成guid等函数, 从editor分离 + [ ] editor 执行初始化流程加组合各组件 - + [ ] 原editor_mode 移除 + [ ] 原vm 移除 --- -对象结构 ++ [ ] 对象结构 ``` editor: { __proto__: { - blockly: 组件 - multi: 组件 - file: 组件 - table: 组件 - util: 组件 + fs + util + file + table + multi + blockly } game: 来自游戏的数据 config: 编辑器配置 mode: 当前的模式(左侧的选择) map: 当前编辑层的地图 + isMobile: 编辑器是否是手机端 + currentFloorData: 当前编辑的楼层数据 ... } ``` From eb9dbf1953ebb66fdef5acb1920afded6e1b3c50 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Wed, 27 Mar 2019 17:46:34 +0800 Subject: [PATCH 098/153] drawBook_row & drawBackground --- libs/ui.js | 275 +++++++++++++++++++++++++++-------------------------- 1 file changed, 138 insertions(+), 137 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 14007f9a..7cdd32b7 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -455,6 +455,57 @@ ui.prototype.drawWindowSkin = function(background, ctx, x, y, w, h, direction, p // 仿RM窗口皮肤 ↑ } +////// 绘制一个背景图,可绘制 winskin 或纯色背景;支持小箭头绘制 +ui.prototype.drawBackground = function (left, top, right, bottom, posInfo) { + posInfo = posInfo || {}; + var px = posInfo.px == null ? null : posInfo.px * 32 - core.bigmap.offsetX; + var py = posInfo.py == null ? null : posInfo.py * 32 - core.bigmap.offsetY; + var xoffset = posInfo.xoffset || 0, yoffset = posInfo.yoffset || 0; + var background = core.status.textAttribute.background; + + if (typeof background == 'string' && core.material.images.images[background]) { + var image = core.material.images.images[background]; + if (image.width==192 && image.height==128) { + core.setAlpha('ui', 0.85); + this.drawWindowSkin(image, 'ui', left, top, right - left, bottom - top, posInfo.position, px, py); + core.setAlpha('ui', 1); + return true; + } + background = core.initStatus.textAttribute.background; + } + + var alpha = background[3]; + core.setAlpha('ui', alpha); + core.setStrokeStyle('ui', core.status.globalAttribute.borderColor); + core.setFillStyle('ui', core.arrayToRGB(background)); + core.setLineWidth('ui', 2); + + // 绘制 + var ctx = core.canvas.ui; + ctx.beginPath(); + ctx.moveTo(left, top); + // 上边缘三角 + if (posInfo.position == 'down' && px != null && py != null) { + ctx.lineTo(px + xoffset, top); + ctx.lineTo(px + 16, top - yoffset); + ctx.lineTo(px + 32 - xoffset, top); + } + ctx.lineTo(right, top); + ctx.lineTo(right, bottom); + // 下边缘三角 + if (posInfo.position == 'up' && px != null && py != null) { + ctx.lineTo(px + 32 - xoffset, bottom); + ctx.lineTo(px + 16, bottom + yoffset); + ctx.lineTo(px + xoffset, bottom); + } + ctx.lineTo(left, bottom); + ctx.closePath(); + ctx.fill(); + ctx.stroke(); + core.setAlpha('ui', 1); + return false; +} + ////// 计算有效文本框的宽度 ui.prototype.calTextBoxWidth = function (ctx, content, min_width, max_width, font) { // 无限长度自动换行 @@ -697,8 +748,10 @@ ui.prototype.drawTextBox = function(content, showAll) { var vPos = this._drawTextBox_getVerticalPosition(content, titleInfo, posInfo, hPos.validWidth); // Step 3: 绘制背景图 - var isWindowSkin = this._drawTextBox_drawBackground(titleInfo, posInfo, hPos, vPos); - var alpha = isWindowSkin ? 0.85 : (textAttribute.background[3] || core.initStatus.textAttribute.background[3]); + var pInfo = core.clone(posInfo); + pInfo.xoffset = hPos.xoffset; pInfo.yoffset = vPos.yoffset - 4; + var isWindowSkin = this.drawBackground(hPos.left, vPos.top, hPos.right, vPos.bottom, pInfo); + var alpha = isWindowSkin ? 0.85 : textAttribute.background[3]; // Step 4: 绘制标题、头像、 var content_top = this._drawTextBox_drawTitleAndIcon(titleInfo, hPos, vPos, alpha); @@ -780,56 +833,6 @@ ui.prototype._drawTextBox_getVerticalPosition = function (content, titleInfo, po return { top: top, height: height, bottom: top + height, yoffset: yoffset, lineHeight: lineHeight }; } -ui.prototype._drawTextBox_drawBackground = function (titleInfo, posInfo, hPos, vPos) { - var background = core.status.textAttribute.background; - var px = posInfo.px == null ? null : posInfo.px * 32 - core.bigmap.offsetX; - var py = posInfo.py == null ? null : posInfo.py * 32 - core.bigmap.offsetY; - var xoffset = hPos.xoffset, yoffset = vPos.yoffset - 4; - var left = hPos.left, right = hPos.right, top = vPos.top, bottom = vPos.bottom; - - if (typeof background == 'string' && core.material.images.images[background]) { - var image = core.material.images.images[background]; - if (image.width==192 && image.height==128) { - core.setAlpha('ui', 0.85); - this.drawWindowSkin(image, 'ui', left, top, right - left, bottom - top, posInfo.position, px, py); - core.setAlpha('ui', 1); - return true; - } - background = core.initStatus.textAttribute.background; - } - - var alpha = background[3]; - core.setAlpha('ui', alpha); - core.setStrokeStyle('ui', core.status.globalAttribute.borderColor); - core.setFillStyle('ui', core.arrayToRGB(background)); - core.setLineWidth('ui', 2); - - // 绘制 - var ctx = core.canvas.ui; - ctx.beginPath(); - ctx.moveTo(left, top); - // 上边缘三角 - if (posInfo.position == 'down' && px != null && py != null) { - ctx.lineTo(px + xoffset, top); - ctx.lineTo(px + 16, top - yoffset); - ctx.lineTo(px + 32 - xoffset, top); - } - ctx.lineTo(right, top); - ctx.lineTo(right, bottom); - // 下边缘三角 - if (posInfo.position == 'up' && px != null && py != null) { - ctx.lineTo(px + 32 - xoffset, bottom); - ctx.lineTo(px + 16, bottom + yoffset); - ctx.lineTo(px + xoffset, bottom); - } - ctx.lineTo(left, bottom); - ctx.closePath(); - ctx.fill(); - ctx.stroke(); - core.setAlpha('ui', 1); - return false; -} - ui.prototype._drawTextBox_drawTitleAndIcon = function (titleInfo, hPos, vPos, alpha) { core.setTextAlign('ui', 'left'); var textAttribute = core.status.textAttribute; @@ -939,7 +942,7 @@ ui.prototype.drawChoices = function(content, choices) { var hPos = this._drawChoices_getHorizontalPosition(titleInfo, choices); var vPos = this._drawChoices_getVerticalPosition(titleInfo, choices, hPos); - var isWindowSkin = this._drawTextBox_drawBackground(titleInfo, {}, hPos, vPos); + var isWindowSkin = this.drawBackground(hPos.left, vPos.top, hPos.right, vPos.bottom); this._drawChoices_drawTitle(titleInfo, hPos, vPos); this._drawChoices_drawChoices(choices, isWindowSkin, hPos, vPos); } @@ -1035,7 +1038,7 @@ ui.prototype._drawChoices_drawChoices = function (choices, isWindowSkin, hPos, v while (core.status.event.selection >= choices.length) core.status.event.selection -= choices.length; var len = choices[core.status.event.selection].width; if (isWindowSkin) - this.drawWindowSelector(core.material.images.images[core.status.textAttribute.background], + this.drawWindowSelector(core.status.textAttribute.background, this.HPIXEL - len/2 - 5, vPos.choice_top + 32 * core.status.event.selection - 20, len + 10, 28); else core.strokeRect('ui', this.HPIXEL - len/2 - 5, vPos.choice_top + 32 * core.status.event.selection - 20, @@ -1057,7 +1060,7 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { core.setFont('ui', this._buildFont(19, true)); var contents = text.split("\n"); var rect = this._drawConfirmBox_getRect(contents); - var isWindowSkin = this._drawTextBox_drawBackground({}, {}, rect, rect); + var isWindowSkin = this.drawBackground(rect.left, rect.top, rect.right, rect.bottom); core.setTextAlign('ui', 'center'); core.setFillStyle('ui', core.arrayToRGBA(core.status.textAttribute.text)) @@ -1133,7 +1136,7 @@ ui.prototype.drawWaiting = function(text) { var text_length = core.calWidth('ui', text, this._buildFont(19, true)); var width = Math.max(text_length + 80, 220), left = this.HPIXEL - parseInt(width / 2), right = left + width; var top = this.HPIXEL - 48, height = 96, bottom = top + height; - this._drawTextBox_drawBackground({}, {}, {left: left, right: right}, {top: top, bottom: bottom}); + this.drawBackground(left, top, right, bottom); core.setTextAlign('ui', 'center'); core.fillText('ui', text, this.HPIXEL, top + 56, core.arrayToRGBA(core.status.textAttribute.text)); } @@ -1228,50 +1231,43 @@ ui.prototype.drawBook = function (index) { var enemys = core.enemys.getCurrentEnemys(floorId); core.clearUI(); core.clearMap('data'); + // 生成groundPattern + core.maps.generateGroundPattern(floorId); + this._drawBook_drawBackground(); + core.setAlpha('ui', 1); + + if (enemys.length == 0) { + core.setTextAlign('ui', 'center'); + core.fillText('ui', "本层无怪物", this.HPIXEL, this.HPIXEL + 14, '#999999', this._buildFont(50, true)); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); + return; + } - if (this._drawBook_drawBackground(floorId, enemys)) return; index = core.clamp(index, 0, enemys.length - 1); - var perpage = this.HSIZE, page = parseInt(index / perpage) + 1; - var totalPage = parseInt((enemys.length - 1) / perpage) + 1; core.status.event.data = index; - var start = (page - 1) * perpage, end = Math.min(page * perpage, enemys.length); - enemys = enemys.slice(start, end); + var perpage = this.HSIZE, page = parseInt(index / perpage) + 1, totalPage = Math.ceil(enemys.length / perpage); + var start = (page - 1) * perpage; + enemys = enemys.slice(start, page * perpage); - for (var i = 0; i < enemys.length; i++) { - this._drawBook_drawOne(floorId, i, enemys[i]); - } - - if (index - start >= 0 && index - start < enemys.length) { - core.strokeRect('ui', 10, 62 * (index - start) + 13, this.PIXEL - 10 * 2, 62, '#FFD700'); - } + for (var i = 0; i < enemys.length; i++) + this._drawBook_drawOne(floorId, i, enemys[i], index == start + i); core.drawBoxAnimate(); this.drawPagination(page, totalPage); core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); } -ui.prototype._drawBook_drawBackground = function (floorId, enemys) { - // 生成groundPattern - core.maps.generateGroundPattern(floorId); - +ui.prototype._drawBook_drawBackground = function () { + core.setAlpha('ui', 1); core.setFillStyle('ui', core.material.groundPattern); core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL); core.setAlpha('ui', 0.6); core.setFillStyle('ui', '#000000'); core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL); - - core.setAlpha('ui', 1); - if (enemys.length == 0) { - core.setTextAlign('ui', 'center'); - core.fillText('ui', "本层无怪物", this.HPIXEL, this.HPIXEL + 14, '#999999', this._buildFont(50, true)); - core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); - return true; - } - return false; } -ui.prototype._drawBook_drawOne = function (floorId, index, enemy) { +ui.prototype._drawBook_drawOne = function (floorId, index, enemy, selected) { // --- 区域规划:每个区域总高度为62,宽度为 PIXEL var top = 62 * index + 12; // 最上面margin是12px // 横向规划: @@ -1279,29 +1275,11 @@ ui.prototype._drawBook_drawOne = function (floorId, index, enemy) { this._drawBook_drawBox(index, enemy, top); // 剩余 PIXEL - 64 的宽度,按照 10 : 9 : 8 : 8 的比例划分 var left = 64, total_width = this.PIXEL - left; - var name_width = total_width * 10 / 35, - col1_width = total_width * 9 / 35, col1_offset = left + name_width, - col2_width = total_width * 8 / 35, col2_offset = col1_offset + col2_width, - col3_width = total_width * 8 / 35, col3_offset = col2_offset + col3_width; - this._drawBook_drawNameCol(index, enemy, top, left, name_width); - - // 第二行:金币、加点、经验 - var second_line = []; - if (core.flags.enableMoney) second_line.push(["金币", core.formatBigNumber(enemy.money || 0)]); - if (core.flags.enableAddPoint) second_line.push(["加点", core.formatBigNumber(enemy.point || 0)]); - if (core.flags.enableExperience && second_line.length < 2) - second_line.push(["经验", core.formatBigNumber(enemy.experience || 0)]); - var cnt = second_line.length; - - this._drawBook_drawCol1(index, enemy, top, col1_offset, col1_width, second_line); - this._drawBook_drawCol2(index, enemy, top, col2_offset, col2_width, second_line); - this._drawBook_drawCol3(index, enemy, top, col3_offset, col3_width); - - // get damage offset - var damageOffset = col1_offset + (col1_width + col2_width + col3_width) / 2 - 12; - if (cnt == 1) damageOffset = col2_offset + (col2_width + col3_width) / 2 - 12; - else if (cnt == 2) damageOffset = col3_offset + col3_width / 2 - 12; - this._drawBook_drawDamage(index, enemy, top, damageOffset); + var name_width = total_width * 10 / 35; + this._drawBook_drawName(index, enemy, top, left, name_width); + this._drawBook_drawContent(index, enemy, top, left + name_width); + if (selected) + core.strokeRect('ui', 10, top + 1, this.PIXEL - 10 * 2, 62, '#FFD700'); } ui.prototype._drawBook_drawBox = function (index, enemy, top) { @@ -1317,7 +1295,7 @@ ui.prototype._drawBook_drawBox = function (index, enemy, top) { }); } -ui.prototype._drawBook_drawNameCol = function (index, enemy, top, left, width) { +ui.prototype._drawBook_drawName = function (index, enemy, top, left, width) { // 绘制第零列(名称和特殊属性) // 如果需要添加自己的比如怪物的称号等,也可以在这里绘制 core.setTextAlign('ui', 'center'); @@ -1333,47 +1311,70 @@ ui.prototype._drawBook_drawNameCol = function (index, enemy, top, left, width) { } } -ui.prototype._drawBook_drawCol1 = function (index, enemy, top, left, width, second_line) { - // 绘制第一列 +ui.prototype._drawBook_drawContent = function (index, enemy, top, left) { + var width = this.PIXEL - left; // 9 : 8 : 8 划分三列 + this._drawBook_drawRow1(index, enemy, top, left, width, top + 20); + this._drawBook_drawRow2(index, enemy, top, left, width, top + 38); + this._drawBook_drawRow3(index, enemy, top, left, width, top + 56); +} + +ui.prototype._drawBook_drawRow1 = function (index, enemy, top, left, width, position) { + // 绘制第一行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); - core.fillText('ui', '生命', left, top + 20, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.hp||0), left + 30, top + 20, null, b13); - if (second_line.length>0) { + var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; + core.fillText('ui', '生命', col1, position, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.hp||0), col1 + 30, position, null, b13); + core.fillText('ui', '攻击', col2, position, null, f13); + core.fillText('ui', core.formatBigNumber(enemy.atk||0), col2 + 30, position, null, b13); + core.fillText('ui', '防御', col3, position, null, f13); + core.fillText('ui', core.formatBigNumber(enemy.def||0), col3 + 30, position, null, b13); +} + +ui.prototype._drawBook_drawRow2 = function (index, enemy, top, left, width, position) { + // 绘制第三行 + core.setTextAlign('ui', 'left'); + var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); + var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; + // 获得第二行绘制的内容 + var second_line = []; + if (core.flags.enableMoney) second_line.push(["金币", core.formatBigNumber(enemy.money || 0)]); + if (core.flags.enableAddPoint) second_line.push(["加点", core.formatBigNumber(enemy.point || 0)]); + if (core.flags.enableExperience) second_line.push(["经验", core.formatBigNumber(enemy.experience || 0)]); + + var damage_offset = col1 + (this.PIXEL - col1) / 2 - 12; + // 第一列 + if (second_line.length > 0) { var one = second_line.shift(); - core.fillText('ui', one[0], left, top + 38, '#DDDDDD', f13); - core.fillText('ui', one[1], left + 30, top + 38, null, b13); + core.fillText('ui', one[0], col1, position, '#DDDDDD', f13); + core.fillText('ui', one[1], col1 + 30, position, null, b13); + damage_offset = col2 + (this.PIXEL - col2) / 2 - 12; } - core.fillText('ui', '临界', left, top + 56, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.critical||0), left + 30, top + 56, null, b13); -} - -ui.prototype._drawBook_drawCol2 = function (index, enemy, top, left, width, second_line) { - // 绘制第二列 - core.setTextAlign('ui', 'left'); - var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); - core.fillText('ui', '攻击', left, top + 20, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.atk||0), left + 30, top + 20, null, b13); - if (second_line.length>0) { + // 第二列 + if (second_line.length > 0) { var one = second_line.shift(); - core.fillText('ui', one[0], left, top + 38, '#DDDDDD', f13); - core.fillText('ui', one[1], left + 30, top + 38, null, b13); + core.fillText('ui', one[0], col2, position, '#DDDDDD', f13); + core.fillText('ui', one[1], col2 + 30, position, null, b13); + damage_offset = col3 + (this.PIXEL - col3) / 2 - 12; } - core.fillText('ui', '减伤', left, top + 56, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.criticalDamage||0), left + 30, top + 56, null, b13); + // 忽略第三列,直接绘制伤害 + this._drawBook_drawDamage(index, enemy, damage_offset, position); } -ui.prototype._drawBook_drawCol3 = function (index, enemy, top, left, width) { - // 绘制第三列 +ui.prototype._drawBook_drawRow3 = function (index, enemy, top, left, width, position) { + // 绘制第三行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); - core.fillText('ui', '防御', left, top + 20, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.def||0), left + 30, top + 20, null, b13); - core.fillText('ui', '1防', left, top + 56, '#DDDDDD', f13); - core.fillText('ui', core.formatBigNumber(enemy.defDamage||0), left + 30, top + 56, null, b13); + var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; + core.fillText('ui', '临界', col1, position, '#DDDDDD', f13); + core.fillText('ui', core.formatBigNumber(enemy.critical||0), col1 + 30, position, null, b13); + core.fillText('ui', '减伤', col2, position, null, f13); + core.fillText('ui', core.formatBigNumber(enemy.criticalDamage||0), col2 + 30, position, null, b13); + core.fillText('ui', '1防', col3, position, null, f13); + core.fillText('ui', core.formatBigNumber(enemy.defDamage||0), col3 + 30, position, null, b13); } -ui.prototype._drawBook_drawDamage = function (index, enemy, top, damageOffset) { +ui.prototype._drawBook_drawDamage = function (index, enemy, offset, position) { core.setTextAlign('ui', 'center'); var damage = enemy.damage, color = '#FFFF00'; if (damage == null) { @@ -1389,7 +1390,7 @@ ui.prototype._drawBook_drawDamage = function (index, enemy, top, damageOffset) { if (core.enemys.hasSpecial(enemy, 11)) damage += "^"; } if (enemy.notBomb) damage += "[b]"; - core.fillText('ui', damage, damageOffset, top + 38, color, this._buildFont(13, true)); + core.fillText('ui', damage, offset, position, color, this._buildFont(13, true)); } ////// 绘制怪物属性的详细信息 ////// @@ -2177,7 +2178,7 @@ ui.prototype.drawKeyBoard = function () { var left = (this.PIXEL - width) / 2, right = left + width; var top = (this.PIXEL - height) / 2, bottom = top + height; - var isWindowSkin = this._drawTextBox_drawBackground({}, {}, {left:left, right:right}, {top:top, bottom: bottom}); + var isWindowSkin = this.drawBackground(left, top, right, bottom); core.setTextAlign('ui', 'center'); core.setFillStyle('ui', core.arrayToRGBA(core.status.textAttribute.title)); core.fillText('ui', '虚拟键盘', this.HPIXEL, top + 35, null, this._buildFont(22, true)); From 13b09ff91160b891ef03dcb8f50beea9542c0d69 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 28 Mar 2019 00:24:13 +0800 Subject: [PATCH 099/153] type:insert set args --- libs/events.js | 3 ++- libs/ui.js | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/events.js b/libs/events.js index fd81f219..a79963ff 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1163,7 +1163,8 @@ events.prototype._action_insert = function (data, x, y, prefix) { if (data.args instanceof Array) { for (var i = 0; i < data.args.length; ++i) { try { - core.setFlag('arg'+(i+1), core.calValue(data.args[i], prefix)); + if (data.args[i] != null) + core.setFlag('arg'+(i+1), data.args[i]); } catch (e) { main.log(e); } } } diff --git a/libs/ui.js b/libs/ui.js index 7cdd32b7..956234ba 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1332,7 +1332,7 @@ ui.prototype._drawBook_drawRow1 = function (index, enemy, top, left, width, posi } ui.prototype._drawBook_drawRow2 = function (index, enemy, top, left, width, position) { - // 绘制第三行 + // 绘制第二行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; @@ -1396,6 +1396,7 @@ ui.prototype._drawBook_drawDamage = function (index, enemy, offset, position) { ////// 绘制怪物属性的详细信息 ////// ui.prototype.drawBookDetail = function (index) { var info = this._drawBookDetail_getInfo(index), enemy = info[0]; + if (!enemy) return; var content = info[1].join("\n"); core.status.event.id = 'book-detail'; clearInterval(core.interval.tipAnimate); @@ -1418,7 +1419,7 @@ ui.prototype.drawBookDetail = function (index) { ui.prototype._drawBookDetail_getInfo = function (index) { var floorId = core.floorIds[(core.status.event.ui||{}).index] || core.status.floorId; var enemys = core.enemys.getCurrentEnemys(floorId); - if (enemys.length==0) return; + if (enemys.length==0) return []; index = core.clamp(index, 0, enemys.length - 1); var enemy = enemys[index], enemyId = enemy.id; var texts=core.enemys.getSpecialHint(enemyId); From dd48678d2d43c108fe2447cf157230f1e904cc01 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 28 Mar 2019 00:40:22 +0800 Subject: [PATCH 100/153] Fix animateBlock for none --- libs/maps.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/libs/maps.js b/libs/maps.js index cb7dbb7b..f09d6b27 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1696,6 +1696,7 @@ maps.prototype.animateBlock = function (loc, type, time, callback) { var isHide = type == 'hide'; if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc]; + // --- 检测所有是0的点 var list = this._animateBlock_getList(loc); if (list.length == 0) { if (callback) callback(); @@ -1714,7 +1715,8 @@ maps.prototype._animateBlock_doAnimate = function (loc, list, isHide, delta, cal delete core.animateFrame.asyncId[animate]; clearInterval(animate); list.forEach(function (t) { - core.maps._deleteDetachedBlock(t.canvases); + if (t.blockInfo) + core.maps._deleteDetachedBlock(t.canvases); }); loc.forEach(function (t) { if (isHide) core.removeBlock(t[0], t[1]); @@ -1735,7 +1737,10 @@ maps.prototype._animateBlock_getList = function (loc) { block = block.block; var blockInfo = core.maps.getBlockInfo(block); - if (blockInfo == null) return; + if (blockInfo == null) { + list.push({ 'x': t[0], 'y': t[1] }); + return; + } var canvases = core.maps._initDetachedBlock(blockInfo, t[0], t[1], block.event.displayDamage !== false); list.push({ @@ -1748,7 +1753,8 @@ maps.prototype._animateBlock_getList = function (loc) { maps.prototype._animateBlock_drawList = function (list, opacity) { list.forEach(function (t) { - core.maps._moveDetachedBlock(t.blockInfo, t.x * 32, t.y * 32, opacity, t.canvases); + if (t.blockInfo) + core.maps._moveDetachedBlock(t.blockInfo, t.x * 32, t.y * 32, opacity, t.canvases); }); } From 2b0de5127d72176c673de36556d42197c77f14a0 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 28 Mar 2019 01:26:59 +0800 Subject: [PATCH 101/153] fix drawHero in gameOver --- libs/control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/control.js b/libs/control.js index e3946a74..9b5272d9 100644 --- a/libs/control.js +++ b/libs/control.js @@ -795,7 +795,7 @@ control.prototype.tryMoveDirectly = function (destX, destY) { ////// 绘制勇士 ////// control.prototype.drawHero = function (status, offset) { - if (!core.isPlaying() || !core.status.floorId) return; + if (!core.isPlaying() || !core.status.floorId || core.status.gameOver) return; var x = core.getHeroLoc('x'), y = core.getHeroLoc('y'), direction = core.getHeroLoc('direction'); status = status || 'stop'; offset = offset || 0; From bf20f9ce929bf30d0a933bef0ea60ce1c98c54ce Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 28 Mar 2019 15:19:20 +0800 Subject: [PATCH 102/153] buildFont --- libs/ui.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 956234ba..9c326cc7 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -543,7 +543,8 @@ ui.prototype._getDrawableIconInfo = function (id) { } ui.prototype._buildFont = function (fontSize, bold) { - var textAttribute = core.status.textAttribute, globalAttribute = core.status.globalAttribute; + var textAttribute = core.status.textAttribute || core.initStatus.textAttribute, + globalAttribute = core.status.globalAttribute || core.initStatus.globalAttribute; if (bold == null) bold = textAttribute.bold; return (bold?"bold ":"") + (fontSize || textAttribute.textfont) + "px " + globalAttribute.font; } @@ -844,7 +845,7 @@ ui.prototype._drawTextBox_drawTitleAndIcon = function (titleInfo, hPos, vPos, al core.setStrokeStyle('ui', core.arrayToRGB(textAttribute.title)); // --- title也要居中或者右对齐? - var title_width = core.calWidth('ui', titleInfo.title, 'bold '+titlefont+'px '+core.status.globalAttribute.font); + var title_width = core.calWidth('ui', titleInfo.title, this._buildFont(titlefont, true)); var title_left = hPos.content_left; if (textAttribute.align == 'center') title_left = hPos.left + (hPos.width - title_width) / 2; @@ -950,7 +951,7 @@ ui.prototype.drawChoices = function(content, choices) { ui.prototype._drawChoices_getHorizontalPosition = function (titleInfo, choices) { // 宽度计算:考虑选项的长度 var width = 246; - core.setFont('ui', "bold 17px "+core.status.globalAttribute.font); + core.setFont('ui', this._buildFont(17, true)); for (var i = 0; i < choices.length; i++) { if (typeof choices[i] === 'string') choices[i] = {"text": choices[i]}; @@ -1002,7 +1003,7 @@ ui.prototype._drawChoices_drawTitle = function (titleInfo, hPos, vPos) { }; core.fillText('ui', titleInfo.title, title_offset, vPos.top + 27, - core.arrayToRGBA(core.status.textAttribute.title), 'bold 19px '+core.status.globalAttribute.font); + core.arrayToRGBA(core.status.textAttribute.title), this._buildFont(19, true)); } core.setTextAlign('ui', 'left'); @@ -1015,7 +1016,7 @@ ui.prototype._drawChoices_drawTitle = function (titleInfo, hPos, vPos) { ui.prototype._drawChoices_drawChoices = function (choices, isWindowSkin, hPos, vPos) { // 选项 core.setTextAlign('ui', 'center'); - core.setFont('ui', "bold 17px " + core.status.globalAttribute.font); + core.setFont('ui', this._buildFont(17, true)); for (var i = 0; i < choices.length; i++) { var color = choices[i].color || core.status.textAttribute.text; if (color instanceof Array) color = core.arrayToRGBA(color); @@ -1195,8 +1196,7 @@ ui.prototype.drawPagination = function (page, totalPage, top) { if (top == null) top = this.LAST; core.setFillStyle('ui', '#DDDDDD'); - var length = core.calWidth('ui', page + " / " + page, - "bold 15px " + (core.status.globalAttribute || core.initStatus.globalAttribute).font); + var length = core.calWidth('ui', page + " / " + page, this._buildFont(15, true)); core.setTextAlign('ui', 'left'); core.fillText('ui', page + " / " + totalPage, parseInt((this.PIXEL - length) / 2), top*32+19); From d7fb0a2f3f742d48dc86ee5476dc7b1aac237560 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 28 Mar 2019 15:58:01 +0800 Subject: [PATCH 103/153] Custom System Event --- _server/comment.js | 4 ++-- libs/events.js | 7 ++++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/_server/comment.js b/_server/comment.js index cdf576e4..d4c1ac53 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -227,8 +227,8 @@ var comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "openDoor", "passNet", "changeLight", - "ski", - "pushBox" + "pushBox", + "custom" ] }, "_data": "该图块的默认触发器" diff --git a/libs/events.js b/libs/events.js index a79963ff..7a0bef05 100644 --- a/libs/events.js +++ b/libs/events.js @@ -251,7 +251,7 @@ events.prototype.unregisterSystemEvent = function (type) { events.prototype.doSystemEvent = function (type, data, callback) { if (this.systemEvents[type]) { try { - return core.doFunc(this.systemEvents[type], this, data, data, callback); + return core.doFunc(this.systemEvents[type], this, data, callback); } catch (e) { main.log(e); @@ -688,6 +688,11 @@ events.prototype._sys_action = function (data, callback) { this.insertAction(ev, ex, ey, callback); } +events.prototype._sys_custom = function (data, callback) { + core.insertAction(["请使用\r[yellow]core.registerSystemEvent('custom', func)\r来处理自己添加的系统触发器!"], + data.x, data.y, callback); +} + // ------ 自定义事件的处理 ------ // ////// 注册一个自定义事件 ////// From 5e978fa2d416f5f4399a342244d2e9beed827924 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Thu, 28 Mar 2019 19:38:44 +0800 Subject: [PATCH 104/153] format date --- libs/ui.js | 9 ++------- libs/utils.js | 6 ++++++ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 9c326cc7..e145f275 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2224,17 +2224,12 @@ ui.prototype.drawStatistics = function (floorIds) { (floorIds || core.floorIds).forEach(function (floorId) { core.ui._drawStatistics_floorId(floorId, obj); }); - var formatTime = function (time) { - return core.setTwoDigits(parseInt(time/3600000)) - +":"+core.setTwoDigits(parseInt(time/60000)%60) - +":"+core.setTwoDigits(parseInt(time/1000)%60); - } var statistics = core.status.hero.statistics; core.drawText([ this._drawStatistics_generateText(obj, "全塔", obj.total), this._drawStatistics_generateText(obj, "当前", obj.current), - "当前总步数:"+core.status.hero.steps+",当前游戏时长:"+formatTime(statistics.currTime) - +",总游戏时长"+formatTime(statistics.totalTime) + "当前总步数:"+core.status.hero.steps+",当前游戏时长:"+core.formatTime(statistics.currTime) + +",总游戏时长"+core.formatTime(statistics.totalTime) +"。\n瞬间移动次数:"+statistics.moveDirectly+",共计少走"+statistics.ignoreSteps+"步。" +"\n\n总计通过血瓶恢复生命值为"+core.formatBigNumber(statistics.hp)+"点。\n\n" +"总计打死了"+statistics.battle+"个怪物,得到了"+core.formatBigNumber(statistics.money)+"金币,"+core.formatBigNumber(statistics.experience)+"点经验。\n\n" diff --git a/libs/utils.js b/libs/utils.js index 1bca52b0..d3bac9d3 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -348,6 +348,12 @@ utils.prototype.formatDate2 = function (date) { + core.setTwoDigits(date.getHours()) + core.setTwoDigits(date.getMinutes()) + core.setTwoDigits(date.getSeconds()); } +utils.prototype.formatTime = function (time) { + return core.setTwoDigits(parseInt(time/3600000)) + +":"+core.setTwoDigits(parseInt(time/60000)%60) + +":"+core.setTwoDigits(parseInt(time/1000)%60); +} + ////// 两位数显示 ////// utils.prototype.setTwoDigits = function (x) { return parseInt(x) < 10 ? "0" + x : x; From 90407e94a09587ab654a600cf724b0abbb3c7262 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 29 Mar 2019 00:43:26 +0800 Subject: [PATCH 105/153] drawToolbox --- libs/actions.js | 85 +++++++++++----------- libs/ui.js | 182 +++++++++++++++++++++--------------------------- 2 files changed, 124 insertions(+), 143 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index c8e9baeb..31089b5b 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1234,49 +1234,47 @@ actions.prototype._keyUpQuickShop = function (keycode) { ////// 工具栏界面时的点击操作 ////// actions.prototype._clickToolbox = function (x, y) { // 装备栏 - if (x >= 10 && x <= 12 && y == 0) { + if (x >= this.LAST - 2 && y == 0) { core.ui.closePanel(); core.openEquipbox(); return; } - // 返回 - if (x >= 10 && x <= 12 && y == 12) { + if (x >= this.LAST - 2 && y == this.LAST) { core.ui.closePanel(); return; } + var toolsPage = core.status.event.data.toolsPage; var constantsPage = core.status.event.data.constantsPage; // 上一页 - if (x == 3 || x == 4) { - if (y == 7 && toolsPage > 1) { + if (x == this.HSIZE-2 || x == this.HSIZE-3) { + if (y == this.LAST - 5 && toolsPage > 1) { core.status.event.data.toolsPage--; core.ui.drawToolbox(core.status.event.selection); } - if (y == 12 && constantsPage > 1) { + if (y == this.LAST && constantsPage > 1) { core.status.event.data.toolsPage--; core.ui.drawToolbox(core.status.event.selection); } } // 下一页 - if (x == 8 || x == 9) { - if (y == 7 && toolsPage < Math.ceil(Object.keys(core.status.hero.items.tools).length / 12)) { + if (x == this.HSIZE+2 || x == this.HSIZE+3) { + if (y == this.LAST - 5 && toolsPage < Math.ceil(Object.keys(core.status.hero.items.tools).length / this.LAST)) { core.status.event.data.toolsPage++; core.ui.drawToolbox(core.status.event.selection); } - if (y == 12 && constantsPage < Math.ceil(Object.keys(core.status.hero.items.constants).length / 12)) { + if (y == this.LAST && constantsPage < Math.ceil(Object.keys(core.status.hero.items.constants).length / this.LAST)) { core.status.event.data.constantsPage++; core.ui.drawToolbox(core.status.event.selection); } } var index = parseInt(x / 2); - ; - if (y == 4) index += 0; - else if (y == 6) index += 6; - else if (y == 9) index += 12; - else if (y == 11) index += 18; + if (y == this.LAST - 8) index += 0; + else if (y == this.LAST - 6) index += this.HSIZE; + else if (y == this.LAST - 3) index += this.LAST; + else if (y == this.LAST - 1) index += this.LAST + this.HSIZE; else index = -1; - if (index >= 0) this._clickToolboxIndex(index); } @@ -1285,12 +1283,12 @@ actions.prototype._clickToolbox = function (x, y) { actions.prototype._clickToolboxIndex = function (index) { var items = null; var select; - if (index < 12) { - select = index + 12 * (core.status.event.data.toolsPage - 1); + if (index < this.LAST) { + select = index + this.LAST * (core.status.event.data.toolsPage - 1); items = Object.keys(core.status.hero.items.tools).sort(); } else { - select = index % 12 + 12 * (core.status.event.data.constantsPage - 1); + select = index % this.LAST + this.LAST * (core.status.event.data.constantsPage - 1); items = Object.keys(core.status.hero.items.constants).sort(); } if (items == null) return; @@ -1308,33 +1306,35 @@ actions.prototype._clickToolboxIndex = function (index) { actions.prototype._keyDownToolbox = function (keycode) { if (core.status.event.data == null) return; + var last_index = this.LAST - 1; + var tools = Object.keys(core.status.hero.items.tools).sort(); var constants = Object.keys(core.status.hero.items.constants).sort(); var index = core.status.event.selection; var toolsPage = core.status.event.data.toolsPage; var constantsPage = core.status.event.data.constantsPage; - var toolsTotalPage = Math.ceil(tools.length / 12); - var constantsTotalPage = Math.ceil(constants.length / 12); - var toolsLastIndex = toolsPage < toolsTotalPage ? 11 : (tools.length + 11) % 12; - var constantsLastIndex = 12 + (constantsPage < constantsTotalPage ? 11 : (constants.length + 11) % 12); + var toolsTotalPage = Math.ceil(tools.length / this.LAST); + var constantsTotalPage = Math.ceil(constants.length / this.LAST); + var toolsLastIndex = toolsPage < toolsTotalPage ? last_index : (tools.length + last_index) % this.LAST; + var constantsLastIndex = this.LAST + (constantsPage < constantsTotalPage ? last_index : (constants.length + last_index) % this.LAST); if (keycode == 37) { // left if (index == 0) { // 处理向前翻页 if (toolsPage > 1) { core.status.event.data.toolsPage--; - index = 11; + index = last_index; } else return; // 第一页不向前翻 } - else if (index == 12) { + else if (index == this.LAST) { if (constantsPage == 1) { if (toolsTotalPage == 0) return; core.status.event.data.toolsPage = toolsTotalPage; - index = (tools.length + 11) % 12; + index = (tools.length + last_index) % this.LAST; } else { core.status.event.data.constantsPage--; - index = 23; + index = 2 * this.LAST - 1; } } else index -= 1; @@ -1342,29 +1342,29 @@ actions.prototype._keyDownToolbox = function (keycode) { return; } if (keycode == 38) { // up - if (index >= 12 && index <= 17) { // 进入tools + if (index >= this.LAST && index < this.LAST + this.HSIZE) { // 进入tools if (toolsTotalPage == 0) return; - if (toolsLastIndex >= 6) index = Math.min(toolsLastIndex, index - 6); - else index = Math.min(toolsLastIndex, index - 12); + if (toolsLastIndex >= this.HSIZE) index = Math.min(toolsLastIndex, index - this.HSIZE); + else index = Math.min(toolsLastIndex, index - this.LAST); } - else if (index < 6) return; // 第一行没有向上 - else index -= 6; + else if (index < this.HSIZE) return; // 第一行没有向上 + else index -= this.HSIZE; this._clickToolboxIndex(index); return; } if (keycode == 39) { // right - if (toolsPage < toolsTotalPage && index == 11) { + if (toolsPage < toolsTotalPage && index == last_index) { core.status.event.data.toolsPage++; index = 0; } - else if (constantsPage < constantsTotalPage && index == 23) { + else if (constantsPage < constantsTotalPage && index == 2 * this.LAST - 1) { core.status.event.data.constantsPage++; - index = 12; + index = this.LAST; } else if (index == toolsLastIndex) { if (constantsTotalPage == 0) return; core.status.event.data.constantsPage = 1; - index = 12; + index = this.LAST; } else if (index == constantsLastIndex) // 一个物品无操作 return; @@ -1374,16 +1374,17 @@ actions.prototype._keyDownToolbox = function (keycode) { } if (keycode == 40) { // down var nextIndex = null; - if (index <= 5) { - if (toolsLastIndex > 5) nextIndex = Math.min(toolsLastIndex, index + 6); - else index += 6; + if (index < this.HSIZE) { + if (toolsLastIndex >= this.HSIZE) nextIndex = Math.min(toolsLastIndex, index + this.HSIZE); + else index += this.HSIZE; } - if (nextIndex == null && index <= 11) { + if (nextIndex == null && index < this.LAST) { if (constantsTotalPage == 0) return; - nextIndex = Math.min(index + 6, constantsLastIndex); + nextIndex = Math.min(index + this.HSIZE, constantsLastIndex); } - if (nextIndex == null && index <= 17) { - if (constantsLastIndex > 17) nextIndex = Math.min(constantsLastIndex, index + 6); + if (nextIndex == null && index < this.LAST + this.HSIZE) { + if (constantsLastIndex >= this.LAST + this.HSIZE) + nextIndex = Math.min(constantsLastIndex, index + this.HSIZE); } if (nextIndex != null) { this._clickToolboxIndex(nextIndex); diff --git a/libs/ui.js b/libs/ui.js index e145f275..294c2043 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1710,149 +1710,129 @@ ui.prototype._drawMaps_buildData = function (index, x, y) { ////// 绘制道具栏 ////// ui.prototype.drawToolbox = function(index) { - // 设定eventdata - if (!core.isset(core.status.event.data) || !core.isset(core.status.event.data.toolsPage) || !core.isset(core.status.event.data.constantsPage)) - core.status.event.data = {"toolsPage":1, "constantsPage":1, "selectId":null} + var info = this._drawToolbox_getInfo(index); + this._drawToolbox_drawBackground(); + // 绘制线 + core.setAlpha('ui', 1); + core.setStrokeStyle('ui', '#DDDDDD'); + core.canvas.ui.lineWidth = 2; + core.canvas.ui.strokeWidth = 2; + core.setTextAlign('ui', 'right'); + var line1 = this.PIXEL - 306; + this._drawToolbox_drawLine(line1, "消耗道具"); + var line2 = this.PIXEL - 146; + this._drawToolbox_drawLine(line2, "永久道具"); + + this._drawToolbox_drawDescription(info, line1); + + this._drawToolbox_drawContent(info, line1, info.tools, info.toolsPage, true); + this.drawPagination(info.toolsPage, info.toolsTotalPage, this.LAST - 5); + this._drawToolbox_drawContent(info, line2, info.constants, info.constantsPage); + this.drawPagination(info.constantsPage, info.constantsTotalPage); + + core.setTextAlign('ui', 'center'); + core.fillText('ui', '[装备栏]', this.PIXEL - 46, 25, '#DDDDDD', this._buildFont(15, true)); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD'); +} + +ui.prototype._drawToolbox_getInfo = function (index) { + // 设定eventdata + if (!core.status.event.data || core.status.event.data.toolsPage == null) + core.status.event.data = {"toolsPage":1, "constantsPage":1, "selectId":null} // 获取物品列表 var tools = Object.keys(core.status.hero.items.tools).sort(); var constants = Object.keys(core.status.hero.items.constants).sort(); - // 处理页数 var toolsPage = core.status.event.data.toolsPage; var constantsPage = core.status.event.data.constantsPage; - var toolsTotalPage = Math.ceil(tools.length/12); - var constantsTotalPage = Math.ceil(constants.length/12); - + var toolsTotalPage = Math.ceil(tools.length/this.LAST); + var constantsTotalPage = Math.ceil(constants.length/this.LAST); // 处理index - if (!core.isset(index)) { - if (tools.length>0) index=0; - else if (constants.length>0) index=12; - else index=0; - } + if (index == null) + index = tools.length == 0 && constants.length > 0 ? this.LAST : 0; core.status.event.selection=index; - // 确认选择对象 - var select; - var selectId; - if (index<12) { - select = index + (toolsPage-1)*12; + var select, selectId; + if (index=tools.length) select=Math.max(0, tools.length-1); selectId = tools[select]; } else { - select = index%12 + (constantsPage-1)*12; + select = index%this.LAST + (constantsPage-1)*this.LAST; if (select>=constants.length) select=Math.max(0, constants.length-1); selectId = constants[select]; } if (!core.hasItem(selectId)) selectId=null; core.status.event.data.selectId=selectId; + return { + index: index, tools: tools, constants: constants, toolsPage: toolsPage, constantsPage: constantsPage, + toolsTotalPage: toolsTotalPage, constantsTotalPage: constantsTotalPage, selectId: selectId + }; +} +ui.prototype._drawToolbox_drawBackground = function () { // 绘制 core.clearMap('ui'); core.setAlpha('ui', 0.85); - core.fillRect('ui', 0, 0, 416, 416, '#000000'); - core.setAlpha('ui', 1); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000'); +} + +ui.prototype._drawToolbox_drawLine = function (yoffset, text) { core.setFillStyle('ui', '#DDDDDD'); - core.setStrokeStyle('ui', '#DDDDDD'); - core.canvas.ui.lineWidth = 2; - core.canvas.ui.strokeWidth = 2; - - var ydelta = 20; - - // 画线 core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(0, 130-ydelta); - core.canvas.ui.lineTo(416, 130-ydelta); + core.canvas.ui.moveTo(0, yoffset); + core.canvas.ui.lineTo(this.PIXEL, yoffset); core.canvas.ui.stroke(); core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(416,129-ydelta); - core.canvas.ui.lineTo(416,105-ydelta); - core.canvas.ui.lineTo(416-72,105-ydelta); - core.canvas.ui.lineTo(416-102,129-ydelta); + core.canvas.ui.moveTo(this.PIXEL, yoffset-1); + core.canvas.ui.lineTo(this.PIXEL, yoffset-25); + core.canvas.ui.lineTo(this.PIXEL-72, yoffset-25); + core.canvas.ui.lineTo(this.PIXEL-102, yoffset-1); core.canvas.ui.fill(); + core.fillText('ui', text, this.PIXEL - 5, yoffset-6, '#333333', this._buildFont(16, true)); +} - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(0, 290-ydelta); - core.canvas.ui.lineTo(416, 290-ydelta); - core.canvas.ui.stroke(); - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(416,289-ydelta); - core.canvas.ui.lineTo(416,265-ydelta); - core.canvas.ui.lineTo(416-72,265-ydelta); - core.canvas.ui.lineTo(416-102,289-ydelta); - core.canvas.ui.fill(); - - // 文字 - core.setTextAlign('ui', 'right'); - var globalFont = core.status.globalAttribute.font; - core.fillText('ui', "消耗道具", 411, 124-ydelta, '#333333', "bold 16px "+globalFont); - core.fillText('ui', "永久道具", 411, 284-ydelta); - +ui.prototype._drawToolbox_drawDescription = function (info, max_height) { core.setTextAlign('ui', 'left'); // 描述 - if (core.isset(selectId)) { - var item=core.material.items[selectId]; - core.fillText('ui', item.name, 10, 32, '#FFD700', "bold 20px "+globalFont) - + if (info.selectId) { + var item=core.material.items[info.selectId]; + core.fillText('ui', item.name, 10, 32, '#FFD700', this._buildFont(20, true)) var text = item.text||"该道具暂无描述。"; try { // 检查能否eval text = core.replaceText(text); } catch (e) {} - - var lines = core.splitLines('ui', text, 406, '17px '+globalFont); - - core.fillText('ui', lines[0], 10, 62, '#FFFFFF', '17px '+globalFont); - - if (lines.length==1) { - core.fillText('ui', '<继续点击该道具即可进行使用>', 10, 89, '#CCCCCC', '14px '+globalFont); + var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(17, false)); + // --- 开始逐行绘制 + var curr = 62, line_height = 25; + core.setFillStyle('ui', '#FFFFFF'); + for (var i=0;i=max_height) break; } - else { - var leftText = text.substring(lines[0].length); - core.fillText('ui', leftText, 10, 89, '#FFFFFF', '17px '+globalFont); + if (curr < max_height) { + core.fillText('ui', '<继续点击该道具即可进行使用>', 10, curr, '#CCCCCC', this._buildFont(14, false)); } } +} +ui.prototype._drawToolbox_drawContent = function (info, line, items, page, drawCount) { core.setTextAlign('ui', 'right'); - var images = core.material.images.items; - - // 消耗道具 - for (var i=0;i<12;i++) { - var tool=tools[12*(toolsPage-1)+i]; - if (!core.isset(tool)) break; - var yoffset = 144 + Math.floor(i/6)*54 + 5 - ydelta; - var icon=core.material.icons.items[tool]; - core.drawImage('ui', images, 0, icon*32, 32, 32, 16*(4*(i%6)+1)+5, yoffset, 32, 32) - // 个数 - core.fillText('ui', core.itemCount(tool), 16*(4*(i%6)+1)+40, yoffset+33, '#FFFFFF', "bold 14px "+globalFont); - if (selectId == tool) - core.strokeRect('ui', 16*(4*(i%6)+1)+1, yoffset-4, 40, 40, '#FFD700'); + for (var i = 0; i < this.LAST; i++) { + var item = items[this.LAST * (page - 1) + i]; + if (!item) continue; + var yoffset = line + 54 * Math.floor(i / this.HSIZE) + 19; + var icon = core.material.icons.items[item], image = core.material.images.items; + core.drawImage('ui', image, 0, 32 * icon, 32, 32, 64 * (i % this.HSIZE) + 21, yoffset, 32, 32); + if (drawCount) + core.fillText('ui', core.itemCount(item), 64 * (i % this.HSIZE) + 56, yoffset + 33, '#FFFFFF', this._buildFont(14, true)); + if (info.selectId == item) + core.strokeRect('ui', 64 * (i % this.HSIZE) + 17, yoffset - 4, 40, 40, '#FFD700'); } - - // 永久道具 - for (var i=0;i<12;i++) { - var constant=constants[12*(constantsPage-1)+i]; - if (!core.isset(constant)) break; - var yoffset = 304+Math.floor(i/6)*54+5-ydelta; - var icon=core.material.icons.items[constant]; - core.drawImage('ui', images, 0, icon*32, 32, 32, 16*(4*(i%6)+1)+5, yoffset, 32, 32) - if (selectId == constant) - core.strokeRect('ui', 16*(4*(i%6)+1)+1, yoffset-4, 40, 40, '#FFD700'); - } - - // 分页 - this.drawPagination(toolsPage, toolsTotalPage, 7); - this.drawPagination(constantsPage, constantsTotalPage, 12); - - core.setTextAlign('ui', 'center'); - - // 装备栏 - // if (core.flags.equipment) - core.fillText('ui', '[装备栏]', 370, 25,'#DDDDDD', 'bold 15px '+globalFont); - // core.fillText('ui', '删除道具', 370, 32,'#DDDDDD', 'bold 15px '+globalFont); - // 退出 - core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); } ////// 绘制装备界面 ////// From 9aa7cca037b1c5833ac66f2d9724124e9ff6b272 Mon Sep 17 00:00:00 2001 From: dljgs1 <906348668@qq.com> Date: Fri, 29 Mar 2019 06:52:04 +0800 Subject: [PATCH 106/153] drawSLPanel --- libs/actions.js | 155 +++++++++++++++++++------- libs/ui.js | 284 ++++++++++++++++++++++++++++++------------------ 2 files changed, 293 insertions(+), 146 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index c8e9baeb..c44030e9 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -686,8 +686,9 @@ actions.prototype._sys_onmousewheel = function (direct) { // 存读档 if (core.status.lockControl && (core.status.event.id == 'save' || core.status.event.id == 'load')) { - if (direct == 1) core.ui.drawSLPanel(core.status.event.data - 10); - if (direct == -1) core.ui.drawSLPanel(core.status.event.data + 10); + var index = core.status.event.data.page*10+core.status.event.data.offset; + if (direct == 1) core.ui.drawSLPanel(index - 10); + if (direct == -1) core.ui.drawSLPanel(index + 10); return; } @@ -1576,23 +1577,24 @@ actions.prototype._keyUpEquipbox = function (keycode, altKey) { } ////// 存读档界面时的点击操作 ////// -actions.prototype._clickSL = function (x, y) { - - var index = core.status.event.data; - var page = parseInt(index / 10), offset = index % 10; +actions.prototype._clickSL = function (x, y, px, py) { + var page = core.status.event.data.page, offset = core.status.event.data.offset; + var index = page*10 + offset; + //var index = core.status.event.data; + //var page = parseInt(index / 10), offset = index % 10; // 上一页 - if ((x == 3 || x == 4) && y == 12) { + if ((x == this.HSIZE-2 || x == this.HSIZE-3) && y == this.LAST) { core.ui.drawSLPanel(10 * (page - 1) + offset); return; } // 下一页 - if ((x == 8 || x == 9) && y == 12) { + if ((x == this.HSIZE+2 || x == this.HSIZE+3) && y == this.LAST) { core.ui.drawSLPanel(10 * (page + 1) + offset); return; } // 返回 - if (x >= 10 && x <= 12 && y == 12) { + if (x >= this.LAST-2 && y == this.LAST) { if (core.events.recoverEvents(core.status.event.interval)) { return; } @@ -1603,32 +1605,52 @@ actions.prototype._clickSL = function (x, y) { return; } // 删除 - if (x >= 0 && x <= 2 && y == 12) { - + if (x >= 0 && x <= 2 && y == this.LAST) { if (core.status.event.id == 'save') { core.status.event.selection = !core.status.event.selection; core.ui.drawSLPanel(index); } - else { - core.myprompt("请输入读档编号", null, function (index) { - index = parseInt(index) || 0; - if (index > 0) - core.doSL(index, core.status.event.id); - }); + else {// 显示收藏 + core.status.event.data.mode = core.status.event.data.mode == 'all'?'fav':'all'; + core.saves.index = {}; + for(var i in core.saves.favorite){ + core.saves.index[i] = core.saves.favorite[i]; + } + core.ui.drawSLPanel(index,true); } return; } + // 收藏 + var fav = null; + var centerX = parseInt(this.SIZE/2), leftX = 2, rightX = this.LAST-2; - var id = null; - if (y >= 1 && y <= 4) { - if (x >= 1 && x <= 3) id = "autoSave"; - if (x >= 5 && x <= 7) id = 5 * page + 1; - if (x >= 9 && x <= 11) id = 5 * page + 2; + // 三个关键坐标: + var xLeft = parseInt(this.SIZE/3),xRight = parseInt(this.SIZE*2/3); + var topY1 = 0, topY2 = parseInt(this.SIZE/2); + + if(y==topY1){ + if (x >= xLeft && x < xRight) fav = 5 * page + 1; + if (x >= xRight) fav = 5 * page + 2; } - if (y >= 7 && y <= 10) { - if (x >= 1 && x <= 3) id = 5 * page + 3; - if (x >= 5 && x <= 7) id = 5 * page + 4; - if (x >= 9 && x <= 11) id = 5 * page + 5; + if(y==topY2){ + if (x < xLeft) fav = 5 * page + 3; + if (x >= xLeft && x < xRight) fav = 5 * page + 4; + if (x >= xRight) fav = 5 * page + 5; + } + if (fav != null){ + this._keyDownFav(page,fav%5); + } + var id = null; + var topSpan = parseInt(this.SIZE/7); + if (y >= topY1 + topSpan && y <= topY1 + topSpan + 3) { + if (x < xLeft) id = "autoSave"; + if (x >= xLeft && x < xRight) id = 5 * page + 1; + if (x >= xRight) id = 5 * page + 2; + } + if (y >= topY2+1 && y <= topY2+5) { + if (x < xLeft) id = 5 * page + 3; + if (x >= xLeft && x < xRight) id = 5 * page + 4; + if (x >= xRight) id = 5 * page + 5; } if (id != null) { if (core.status.event.selection) { @@ -1638,13 +1660,19 @@ actions.prototype._clickSL = function (x, y) { else { // core.removeLocalStorage("save"+id); core.removeLocalForage("save" + id, function () { - core.ui.drawSLPanel(index, true); + var idx = core.saves.favorite.indexOf(id); + core.saves.favorite.splice(idx,1); + delete core.saves.favName[id]; + core.ui._drawSLPanel_saveFav(function(){ + core.ui._drawSLPanel_flushIndex(); + core.ui.drawSLPanel(index, true)}); }, function () { core.drawTip("无法删除存档!"); }) } } else { + if(core.status.event.data.mode=='fav')id = core.saves.favIndex[id]; core.doSL(id, core.status.event.id); } } @@ -1653,8 +1681,9 @@ actions.prototype._clickSL = function (x, y) { ////// 存读档界面时,按下某个键的操作 ////// actions.prototype._keyDownSL = function (keycode) { - var index = core.status.event.data; - var page = parseInt(index / 10), offset = index % 10; +// var index = core.status.event.data; + var page = core.status.event.data.page, offset = core.status.event.data.offset; + var index = page*10 + offset; if (keycode == 37) { // left if (offset == 0) { @@ -1700,13 +1729,46 @@ actions.prototype._keyDownSL = function (keycode) { core.ui.drawSLPanel(10 * (page + 1) + offset); return; } + if (keycode == 70){ // F + this._keyDownFav(page,offset); + } +} +actions.prototype._keyDownFav = function(page, offset){ + var fav = page*5+offset; + var idx = fav; + var index = page*10 + offset; + if(core.status.event.data.mode=='fav'){//收藏模式下点击的下标直接对应favorite + fav = core.saves.favIndex[idx]; + var dataIdx = index; + core.myprompt("请输入想要显示的存档名(长度不超过5字符)", null, function (index) { + if(index && index.length<=5 && index.length>0){ + core.saves.favName[fav]=index; + core.ui._drawSLPanel_saveFav(function(){core.ui.drawSLPanel(dataIdx, false)}); + }else{ + alert("无效的输入!"); + } + }); + }else{ + idx = core.saves.favorite.indexOf(fav); + if(idx>=0){ + core.saves.favorite.splice(idx,1); + delete core.saves.favName[fav]; + }else{ + if(core.hasSave(fav)){ + core.saves.favorite.push(fav); + core.saves.favName[idx] = fav;//暂时的 收藏下标到名字的映射(实际存储的是收藏ID到名字的映射) + } + } + core.ui._drawSLPanel_saveFav(function(){ + core.ui._drawSLPanel_flushIndex(); + core.ui.drawSLPanel(index, false)}); + } } ////// 存读档界面时,放开某个键的操作 ////// actions.prototype._keyUpSL = function (keycode) { - - var index = core.status.event.data; - var page = parseInt(index / 10), offset = index % 10; + var page = core.status.event.data.page, offset = core.status.event.data.offset; + var index = page*10 + offset; if (keycode == 27 || keycode == 88 || (core.status.event.id == 'save' && keycode == 83) || (core.status.event.id == 'load' && keycode == 68)) { if (core.events.recoverEvents(core.status.event.interval)) { @@ -1723,16 +1785,20 @@ actions.prototype._keyUpSL = function (keycode) { core.doSL("autoSave", core.status.event.id); } else { - core.doSL(5 * page + offset, core.status.event.id); + var id = 5 * page + offset; + if(core.status.event.data.mode=='fav')id = core.saves.favIndex[id]; + core.doSL(id, core.status.event.id); } return; } - if (keycode == 69 && core.status.event.id != 'save') { // E - core.myprompt("请输入读档编号", null, function (index) { - index = parseInt(index) || 0; - if (index > 0) - core.doSL(index, core.status.event.id); - }); + if (keycode == 69 && core.status.event.id != 'save') { // E 收藏切换 + core.status.event.data.mode = core.status.event.data.mode == 'all'?'fav':'all'; + core.saves.index = {}; + for(var i in core.saves.favorite){ + core.saves.index[i] = core.saves.favorite[i]; + } + core.ui.drawSLPanel(core.saves.saveIndex,true); + return; } if (keycode == 46) { @@ -1740,10 +1806,14 @@ actions.prototype._keyUpSL = function (keycode) { core.drawTip("无法删除自动存档!"); } else { - // core.removeLocalStorage("save"+(5*page+offset)); - // core.ui.drawSLPanel(index); core.removeLocalForage("save" + (5 * page + offset), function () { - core.ui.drawSLPanel(index, true); + var id = 5 * page + offset; + var idx = core.saves.favorite.indexOf(id); + core.saves.favorite.splice(idx,1); + delete core.saves.favName[id]; + core.ui._drawSLPanel_saveFav(function(){ + core.ui._drawSLPanel_flushIndex(); + core.ui.drawSLPanel(index, true)}); }, function () { core.drawTip("无法删除存档!"); }) @@ -1751,6 +1821,7 @@ actions.prototype._keyUpSL = function (keycode) { } } + ////// 系统设置界面时的点击操作 ////// actions.prototype._clickSwitchs = function (x, y) { if (x < this.CHOICES_LEFT || x > this.CHOICES_RIGHT) return; diff --git a/libs/ui.js b/libs/ui.js index e145f275..c50a56d5 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2047,129 +2047,205 @@ ui.prototype.drawSLPanel = function(index, refresh) { var page = parseInt(index/10), offset=index%10; var max_page = main.savePages || 30; + if(core.status.event.data && core.status.event.data.mode=='fav') + max_page = Math.ceil((core.saves.favorite||[]).length/5); if (page>=max_page) page=max_page - 1; if (offset>5) offset=5; index=10*page+offset; var last_page = -1; + var mode = 'all'; if (core.isset(core.status.event.data)) { - last_page = parseInt(core.status.event.data/10); + //last_page = parseInt(core.status.event.data/10); + last_page = core.status.event.data.page; + mode = core.status.event.data.mode; } - core.status.event.data=index; + core.status.event.data={ + 'page':page, + 'offset':offset, + 'mode':mode + }; if (!core.isset(core.status.event.ui)) core.status.event.ui = []; - var u=416/6, size=118; - - var strokeColor = '#FFD700'; - if (core.status.event.selection) strokeColor = '#FF6A6A'; - var globalFont = (core.status.globalAttribute||core.initStatus.globalAttribute).font; - - var drawBg = function() { - core.clearMap('ui'); - core.setAlpha('ui', 0.85); - core.fillRect('ui', 0, 0, 416, 416, '#000000'); - core.setAlpha('ui', 1); - - core.ui.drawPagination(page+1, max_page, 12); - core.setTextAlign('ui', 'center'); - // 退出 - core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); - - if (core.status.event.selection) - core.setFillStyle('ui', '#FF6A6A'); - if (core.status.event.id=='save') - core.fillText('ui', '删除模式', 48, 403); - else - core.fillText('ui', '输入编号', 48, 403); - } - - var draw = function (data, i) { - var name=core.status.event.id=='save'?"存档":core.status.event.id=='load'?"读档":core.status.event.id=='replayLoad'?"回放":""; - core.status.event.ui[i] = data; - var id=5*page+i; - if (i<3) { - core.fillText('ui', i==0?"自动存档":name+id, (2*i+1)*u, 30, '#FFFFFF', "bold 17px "+globalFont); - core.strokeRect('ui', (2*i+1)*u-size/2, 45, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); - if (core.isset(data) && core.isset(data.floorId)) { - core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { - heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, flags: data.hero.flags - }, { - ctx: 'ui', x: (2*i+1)*u-size/2, y: 45, size: size, centerX: data.hero.loc.x, centerY: data.hero.loc.y - }); - var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); - var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); - if (v.length+v2.length<=21) v+=v2; - core.fillText('ui', v, (2*i+1)*u, 60+size, '#FFD700', '10px '+globalFont); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 73+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF'); - } - else { - core.fillRect('ui', (2*i+1)*u-size/2, 45, size, size, '#333333', 2); - core.fillText('ui', '空', (2*i+1)*u, 112, '#FFFFFF', 'bold 30px '+globalFont); - } - } - else { - core.fillText('ui', name+id, (2*i-5)*u, 218, '#FFFFFF', "bold 17px "+globalFont); - core.strokeRect('ui', (2*i-5)*u-size/2, 233, size, size, i==offset?strokeColor:'#FFFFFF', i==offset?6:2); - if (core.isset(data) && core.isset(data.floorId)) { - core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { - heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, flags: data.hero.flags - }, { - ctx: 'ui', x: (2*i-5)*u-size/2, y: 233, size: size, centerX: data.hero.loc.x, centerY: data.hero.loc.y - }); - var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); - var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); - if (v.length+v2.length<=21) v+=v2; - core.fillText('ui', v, (2*i-5)*u, 248+size, '#FFD700', '10px '+globalFont); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 261+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF', '10px '+globalFont); - } - else { - core.fillRect('ui', (2*i-5)*u-size/2, 233, size, size, '#333333', 2); - core.fillText('ui', '空', (2*i-5)*u, 297, '#FFFFFF', 'bold 30px '+globalFont); - } - } - }; - - function loadSave(i, callback) { - if (i==6) { - callback(); - return; - } - - if (i==0) { - if (core.saves.autosave.data!=null) { - core.status.event.ui[i] = core.saves.autosave.data; - loadSave(1, callback); - } - else { - core.getLocalForage("autoSave", null, function(data) { - core.saves.autosave.data = data; - core.status.event.ui[i]=data; - loadSave(i+1, callback); - }, function(err) {main.log(err);}); - } - } - else { - core.getLocalForage("save"+(5*page+i), null, function(data) { - core.status.event.ui[i]=data; - loadSave(i+1, callback); - }, function(err) {main.log(err);}); - } - } - function drawAll() { - drawBg(); - for (var i=0;i<6;i++) - draw(core.status.event.ui[i], i); + core.ui._drawSLPanel_drawBg(page,max_page); + core.ui._drawSLPanel_drawNRecords(6); } if (refresh || page!=last_page) { core.status.event.ui = []; - loadSave(0, drawAll); + this._drawSLPanel_loadFav( + function(){ + core.ui._drawSLPanel_loadSave(page, 0, drawAll); + } + ); } else drawAll(); } +// 存档读档的背景 页码 +ui.prototype._drawSLPanel_drawBg = function(page, max_page) { + core.clearMap('ui'); + core.setAlpha('ui', 0.85); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000');//可改成背景图图 + core.setAlpha('ui', 1); + var globalFont = (core.status.globalAttribute||core.initStatus.globalAttribute).font; + + core.ui.drawPagination(page+1, max_page, null); + core.setTextAlign('ui', 'center'); + // 退出 + //core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); + var bottom = this.PIXEL-13; + core.fillText('ui', '返回游戏', this.PIXEL-48, bottom,'#DDDDDD', 'bold 15px '+globalFont); + + if (core.status.event.selection) + core.setFillStyle('ui', '#FF6A6A'); + if (core.status.event.id=='save') + core.fillText('ui', '删除模式', 48, bottom); + else{ + if(core.status.event.data.mode=='all'){ + core.fillText('ui', '[E]显示收藏', 48, bottom); + }else{ + core.fillText('ui', '[E]显示全部', 48, bottom); + } + } +} + +ui.prototype._drawSLPanel_flushIndex = function(){ + core.saves.favIndex = {}; + for(var i in core.saves.favorite){ + core.saves.favIndex[parseInt(i)+1]=core.saves.favorite[i]; + } +} + +// 读取收藏信息到core.saves.favorite中 +ui.prototype._drawSLPanel_loadFav = function(callback){ + if(!core.saves.favorite || !core.saves.favName){ + core.getLocalForage("favorite", null, function(data) { + core.saves.favorite = data || []; + core.ui._drawSLPanel_flushIndex(); + core.getLocalForage("favName", null, function(data) { + core.saves.favName = data || {}; + callback(); + })}); + }else{ + callback(); + } +} +// 写入收藏信息 | 收藏信息包括收藏id列表favorite、id到收藏名的映射favName +ui.prototype._drawSLPanel_saveFav = function(callback){ + if(!core.saves.favorite){ + core.saves.favorite = []; + core.saves.favName = {}; + } + core.setLocalForage("favorite", core.saves.favorite, + function(){ + core.setLocalForage("favName", core.saves.favName,callback) + }); +} + + +// TODO:递归改并发 | 读取page页的i号存档数据到ui数组中 +ui.prototype._drawSLPanel_loadSave = function(page, i, callback) { + if (i==6) { + callback(); + return; + } + if (i==0) { + if (core.saves.autosave.data!=null) { + core.status.event.ui[i] = core.saves.autosave.data; + core.ui._drawSLPanel_loadSave(page, 1, callback); + } + else { + core.getLocalForage("autoSave", null, function(data) { + core.saves.autosave.data = data; + core.status.event.ui[i]=data; + core.ui._drawSLPanel_loadSave(page, i+1, callback); + }, function(err) {main.log(err);}); + } + } + else { + var id = 5*page+i; + if(core.status.event.data.mode=='fav'){ + id = core.saves.favorite[id-1];//因为favorite第一个不是自动存档 所以要偏移1 + } + core.getLocalForage("save"+id, null, function(data) { + core.status.event.ui[i]=data; + core.ui._drawSLPanel_loadSave(page, i+1, callback); + }, function(err) {main.log(err);}); + } +} + +// 在以x为中心轴 y为顶坐标 的位置绘制一条宽为size的记录 cho表示是否被选中 选中会加粗 highlight表示高亮标题 ✐ +ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, highLight){ + var globalFont = (core.status.globalAttribute||core.initStatus.globalAttribute).font; + var strokeColor = '#FFD700'; + if (core.status.event.selection) strokeColor = '#FF6A6A'; + + if (!core.isset(data) || !core.isset(data.floorId)) { //存在数据时才高亮 + highLight = false; + } + core.fillText('ui', title, x, y, highLight?'#FFD700':'#FFFFFF', this._buildFont(17))//"bold 17px "+globalFont);//名字 + + core.strokeRect('ui', x-size/2, y+15, size, size, cho?strokeColor:'#FFFFFF', cho?6:2); + if (core.isset(data) && core.isset(data.floorId)) { + core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { + heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, 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 + }); + var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); + var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); + if (v.length+v2.length<=21) v+=v2; + core.fillText('ui', v, x, y+30+size, '#FFD700', this._buildFont(10)); + core.fillText('ui', core.formatDate(new Date(data.time)), x, y+43+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF', this._buildFont(10));//'10px '+globalFont); + } + else { + core.fillRect('ui', x-size/2, y+15, size, size, '#333333', 2); + core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30))//'bold 30px '+globalFont); + } +} + +// 绘制n条记录到画板 +ui.prototype._drawSLPanel_drawNRecords = function (n) +{ + var page = core.status.event.data.page;//Math.floor(core.status.event.data/10); + var offset = core.status.event.data.offset;//core.status.event.data%10; + var u = Math.floor(this.PIXEL/6), size = Math.floor(this.PIXEL/3-20);//118 + for (var i=0;i=0 || core.status.event.data.mode=='fav'; + if(highLight)title = '★ ' + title + else title = '☆ ' + title; + var fid = id; + if(core.status.event.data.mode=='fav' && i!=0){//收藏模式下显示修改符号以及自己标识的名字 + fid = core.saves.favIndex[id]; + if(!data && i>0){ + continue; + } +// name = core.saves.favName[fid] ? core.status.event.id=='save'?"S:":core.status.event.id=='load'?"L:":core.status.event.id=='replayLoad'?"re:":"" : name; + title = name + (core.saves.favName[fid]||fid) + '✐'; + }else{ +// name = core.saves.favName[fid] ? core.status.event.id=='save'?"S:":core.status.event.id=='load'?"L:":core.status.event.id=='replayLoad'?"re:":"" : name; + title += name + (core.saves.favName[fid]||fid); + } + var charSize = 32;// 字体占用像素范围 + var topSpan = parseInt((this.PIXEL-charSize-2*(charSize*2 + size))/3);// Margin + var yTop1 = topSpan+parseInt(charSize/2);//文字的中心 + var yTop2 = yTop1+charSize*2+size+topSpan; + if (i<3) { + this._drawSLPanel_drawRecord(i==0?"自动存档":title, data, (2*i+1)*u, yTop1, size, i==offset, highLight); + } + else { + this._drawSLPanel_drawRecord(title, data, (2*i-5)*u, yTop2, size, i==offset, highLight); + } + } +}; + ui.prototype.drawKeyBoard = function () { core.lockControl(); core.status.event.id = 'keyBoard'; From 9b4572feb765d58a03b7989ff6cb4657fae42a26 Mon Sep 17 00:00:00 2001 From: dljgs1 <906348668@qq.com> Date: Fri, 29 Mar 2019 07:00:15 +0800 Subject: [PATCH 107/153] drawSLPanel --- libs/ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index c50a56d5..2cd3b480 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2186,7 +2186,7 @@ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, hi if (!core.isset(data) || !core.isset(data.floorId)) { //存在数据时才高亮 highLight = false; } - core.fillText('ui', title, x, y, highLight?'#FFD700':'#FFFFFF', this._buildFont(17))//"bold 17px "+globalFont);//名字 + core.fillText('ui', title, x, y, highLight?'#FFD700':'#FFFFFF', this._buildFont(17,true));//"bold 17px "+globalFont);//名字 core.strokeRect('ui', x-size/2, y+15, size, size, cho?strokeColor:'#FFFFFF', cho?6:2); if (core.isset(data) && core.isset(data.floorId)) { @@ -2203,7 +2203,7 @@ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, hi } else { core.fillRect('ui', x-size/2, y+15, size, size, '#333333', 2); - core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30))//'bold 30px '+globalFont); + core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30,true));//'bold 30px '+globalFont); } } From 46aa0c82788a8773876d753cca990c198786cbf4 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 00:30:56 +0800 Subject: [PATCH 108/153] drawSL --- libs/actions.js | 190 +++++++++++++++++++-------------------------- libs/control.js | 107 +++++++++++++++++++------ libs/core.js | 2 + libs/events.js | 6 +- libs/ui.js | 202 ++++++++++++++++-------------------------------- 5 files changed, 234 insertions(+), 273 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 18e1f560..96008b98 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1578,11 +1578,9 @@ actions.prototype._keyUpEquipbox = function (keycode, altKey) { } ////// 存读档界面时的点击操作 ////// -actions.prototype._clickSL = function (x, y, px, py) { +actions.prototype._clickSL = function (x, y) { var page = core.status.event.data.page, offset = core.status.event.data.offset; - var index = page*10 + offset; - //var index = core.status.event.data; - //var page = parseInt(index / 10), offset = index % 10; + var index = page * 10 + offset; // 上一页 if ((x == this.HSIZE-2 || x == this.HSIZE-3) && y == this.LAST) { @@ -1596,13 +1594,11 @@ actions.prototype._clickSL = function (x, y, px, py) { } // 返回 if (x >= this.LAST-2 && y == this.LAST) { - if (core.events.recoverEvents(core.status.event.interval)) { + if (core.events.recoverEvents(core.status.event.interval)) return; - } core.ui.closePanel(); - if (!core.isPlaying()) { + if (!core.isPlaying()) core.showStartAnimate(true); - } return; } // 删除 @@ -1611,36 +1607,31 @@ actions.prototype._clickSL = function (x, y, px, py) { core.status.event.selection = !core.status.event.selection; core.ui.drawSLPanel(index); } - else {// 显示收藏 + else { // 显示收藏 core.status.event.data.mode = core.status.event.data.mode == 'all'?'fav':'all'; - core.saves.index = {}; - for(var i in core.saves.favorite){ - core.saves.index[i] = core.saves.favorite[i]; + if (core.status.event.data.mode == 'fav') + core.ui.drawSLPanel(1, true); + else { + page = parseInt((core.saves.saveIndex-1)/5); + offset = core.saves.saveIndex-5*page; + core.ui.drawSLPanel(10*page + offset); } - core.ui.drawSLPanel(index,true); } return; } - // 收藏 - var fav = null; - var centerX = parseInt(this.SIZE/2), leftX = 2, rightX = this.LAST-2; - - // 三个关键坐标: - var xLeft = parseInt(this.SIZE/3),xRight = parseInt(this.SIZE*2/3); - var topY1 = 0, topY2 = parseInt(this.SIZE/2); - + // 点存档名 + var xLeft = parseInt(this.SIZE/3), xRight = parseInt(this.SIZE*2/3); + var topY1 = 0, topY2 = this.HSIZE; if(y==topY1){ - if (x >= xLeft && x < xRight) fav = 5 * page + 1; - if (x >= xRight) fav = 5 * page + 2; + if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 1); + if (x >= xRight) return this._clickSL_favorite(page, 2); } if(y==topY2){ - if (x < xLeft) fav = 5 * page + 3; - if (x >= xLeft && x < xRight) fav = 5 * page + 4; - if (x >= xRight) fav = 5 * page + 5; - } - if (fav != null){ - this._keyDownFav(page,fav%5); + if (x < xLeft) return this._clickSL_favorite(page, 3); + if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 4); + if (x >= xRight) return this._clickSL_favorite(page, 5); } + var id = null; var topSpan = parseInt(this.SIZE/7); if (y >= topY1 + topSpan && y <= topY1 + topSpan + 3) { @@ -1655,30 +1646,52 @@ actions.prototype._clickSL = function (x, y, px, py) { } if (id != null) { if (core.status.event.selection) { - if (id == 'autoSave') { + if (id == 'autoSave') core.drawTip("无法删除自动存档!"); - } else { - // core.removeLocalStorage("save"+id); - core.removeLocalForage("save" + id, function () { - var idx = core.saves.favorite.indexOf(id); - core.saves.favorite.splice(idx,1); - delete core.saves.favName[id]; - core.ui._drawSLPanel_saveFav(function(){ - core.ui._drawSLPanel_flushIndex(); - core.ui.drawSLPanel(index, true)}); - }, function () { - core.drawTip("无法删除存档!"); - }) + core.removeSave(id, function () { + core.ui.drawSLPanel(index, true); + }); } } else { - if(core.status.event.data.mode=='fav')id = core.saves.favIndex[id]; + if(core.status.event.data.mode == 'fav' && id != 'autoSave') + id = core.saves.favorite[id - 1]; core.doSL(id, core.status.event.id); } } } +actions.prototype._clickSL_favorite = function (page, offset) { + if (offset == 0) return; + var index = 5 * page + offset; + if (core.status.event.data.mode == 'fav') { // 收藏模式下点击的下标直接对应favorite + index = core.saves.favorite[index - 1]; + core.myprompt("请输入想要显示的存档名(长度不超过5字符)", null, function (value) { + if(value && value.length <= 5){ + core.saves.favoriteName[index] = value; + core.control._updateFavoriteSaves(); + core.drawSLPanel(10 * page + offset); + } else if (value) { + alert("无效的输入!"); + } + }); + } else { + var v = core.saves.favorite.indexOf(index); + if (v >= 0) { // 已经处于收藏状态:取消收藏 + core.saves.favorite.splice(v, 1); + delete core.saves.favoriteName[index]; + } + else if (core.hasSave(index)) { // 存在存档则进行收藏 + core.saves.favorite.push(index); + core.saves.favorite = core.saves.favorite.sort(function (a,b) {return a-b;}); // 保证有序 + core.drawTip("收藏成功!"); + } + core.control._updateFavoriteSaves(); + core.ui.drawSLPanel(10 * page + offset); + } +} + ////// 存读档界面时,按下某个键的操作 ////// actions.prototype._keyDownSL = function (keycode) { @@ -1730,76 +1743,30 @@ actions.prototype._keyDownSL = function (keycode) { core.ui.drawSLPanel(10 * (page + 1) + offset); return; } - if (keycode == 70){ // F - this._keyDownFav(page,offset); - } -} -actions.prototype._keyDownFav = function(page, offset){ - var fav = page*5+offset; - var idx = fav; - var index = page*10 + offset; - if(core.status.event.data.mode=='fav'){//收藏模式下点击的下标直接对应favorite - fav = core.saves.favIndex[idx]; - var dataIdx = index; - core.myprompt("请输入想要显示的存档名(长度不超过5字符)", null, function (index) { - if(index && index.length<=5 && index.length>0){ - core.saves.favName[fav]=index; - core.ui._drawSLPanel_saveFav(function(){core.ui.drawSLPanel(dataIdx, false)}); - }else{ - alert("无效的输入!"); - } - }); - }else{ - idx = core.saves.favorite.indexOf(fav); - if(idx>=0){ - core.saves.favorite.splice(idx,1); - delete core.saves.favName[fav]; - }else{ - if(core.hasSave(fav)){ - core.saves.favorite.push(fav); - core.saves.favName[idx] = fav;//暂时的 收藏下标到名字的映射(实际存储的是收藏ID到名字的映射) - } - } - core.ui._drawSLPanel_saveFav(function(){ - core.ui._drawSLPanel_flushIndex(); - core.ui.drawSLPanel(index, false)}); - } } ////// 存读档界面时,放开某个键的操作 ////// actions.prototype._keyUpSL = function (keycode) { var page = core.status.event.data.page, offset = core.status.event.data.offset; - var index = page*10 + offset; + var index = page * 10 + offset; - if (keycode == 27 || keycode == 88 || (core.status.event.id == 'save' && keycode == 83) || (core.status.event.id == 'load' && keycode == 68)) { - if (core.events.recoverEvents(core.status.event.interval)) { - return; - } - core.ui.closePanel(); - if (!core.isPlaying()) { - core.showStartAnimate(true); - } + if (keycode == 27 || keycode == 88 || (core.status.event.id == 'save' && keycode == 83) + || (core.status.event.id == 'load' && keycode == 68)) { + this._clickSL(this.LAST, this.LAST); return; } if (keycode == 13 || keycode == 32 || keycode == 67) { - if (offset == 0) { + if (offset == 0) core.doSL("autoSave", core.status.event.id); - } else { var id = 5 * page + offset; - if(core.status.event.data.mode=='fav')id = core.saves.favIndex[id]; + if(core.status.event.data.mode == 'fav') id = core.saves.favorite[id - 1]; core.doSL(id, core.status.event.id); } return; } if (keycode == 69 && core.status.event.id != 'save') { // E 收藏切换 - core.status.event.data.mode = core.status.event.data.mode == 'all'?'fav':'all'; - core.saves.index = {}; - for(var i in core.saves.favorite){ - core.saves.index[i] = core.saves.favorite[i]; - } - core.ui.drawSLPanel(core.saves.saveIndex,true); - + this._clickSL(0, this.LAST); return; } if (keycode == 46) { @@ -1807,19 +1774,16 @@ actions.prototype._keyUpSL = function (keycode) { core.drawTip("无法删除自动存档!"); } else { - core.removeLocalForage("save" + (5 * page + offset), function () { - var id = 5 * page + offset; - var idx = core.saves.favorite.indexOf(id); - core.saves.favorite.splice(idx,1); - delete core.saves.favName[id]; - core.ui._drawSLPanel_saveFav(function(){ - core.ui._drawSLPanel_flushIndex(); - core.ui.drawSLPanel(index, true)}); - }, function () { - core.drawTip("无法删除存档!"); - }) + var id = 5 * page + offset; + if(core.status.event.data.mode == 'fav') id = core.saves.favorite[id - 1]; + core.removeSave(id, function () { + core.ui.drawSLPanel(index, true); + }); } } + if (keycode == 70 && core.status.event.data.mode == 'all') { // F + this._clickSL_favorite(page, offset); + } } @@ -2098,7 +2062,7 @@ actions.prototype._clickLocalSaveSelect = function (x, y) { var selection = y - topIndex; core.status.event.selection = selection; if (selection < 2) { - core.control.getSaves(selection == 0 ? null : core.saves.saveIndex, function (saves) { + core.getAllSaves(selection == 0 ? null : core.saves.saveIndex, function (saves) { if (saves) { var content = { "name": core.firstData.name, @@ -2154,9 +2118,12 @@ actions.prototype._clickStorageRemove_all = function () { core.saves.autosave.data = null; core.saves.autosave.updated = false; core.ui.closePanel(); - core.drawText("\t[操作成功]你的所有存档已被清空。"); core.saves.saveIndex = 1; + core.saves.favorite = []; + core.saves.favoriteName = {}; + core.control._updateFavoriteSaves(); core.removeLocalStorage('saveIndex'); + core.drawText("\t[操作成功]你的所有存档已被清空。"); }; if (core.platform.useLocalForage) { core.ui.drawWaiting("正在清空,请稍后..."); @@ -2175,9 +2142,12 @@ actions.prototype._clickStorageRemove_current = function () { core.saves.autosave.data = null; core.saves.autosave.updated = false; core.ui.closePanel(); - core.drawText("\t[操作成功]当前塔的存档已被清空。"); core.saves.saveIndex = 1; + core.saves.favorite = []; + core.saves.favoriteName = {}; + core.control._updateFavoriteSaves(); core.removeLocalStorage('saveIndex'); + core.drawText("\t[操作成功]当前塔的存档已被清空。"); } if (core.platform.useLocalForage) { core.ui.drawWaiting("正在清空,请稍后..."); diff --git a/libs/control.js b/libs/control.js index 9b5272d9..7f9b5324 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1608,7 +1608,7 @@ control.prototype._doSL_replayLoad_afterGet = function (id, data) { ////// 同步存档到服务器 ////// control.prototype.syncSave = function (type) { core.ui.drawWaiting("正在同步,请稍后..."); - core.control.getSaves(type=='all'?null:core.saves.saveIndex, function (saves) { + core.getAllSaves(type=='all'?null:core.saves.saveIndex, function (saves) { if (!saves) return core.drawText("没有要同步的存档"); core.control._syncSave_http(type, saves); }) @@ -1702,32 +1702,54 @@ control.prototype.loadData = function (data, callback) { return this.controldata.loadData(data, callback); } -control.prototype.getSaves = function (index, callback) { - if (index != null) { - core.getLocalForage("save"+index, null, function(data) { - if (callback) callback(data); - }, function(err) { - main.log(err); - if (callback) callback(null); - }) +control.prototype.getSave = function (index, callback) { + if (index == 0) { + // --- 自动存档先从缓存中获取 + if (core.saves.autosave.data != null) + callback(core.clone(core.saves.autosave.data)); + else { + core.getLocalForage("autoSave", null, function(data) { + callback(data); + }, function(err) { + main.log(err); + callback(null); + }); + } return; } - var ids = Object.keys(core.saves.ids).filter(function(x){return x!=0;}) - .sort(function(a,b) {return a-b;}), number = ids.length, saves = []; - var load = function (index, callback) { - if (index > number) { - if (callback) callback(saves); - return; - } - core.getLocalForage("save"+ids[index], null, function (data) { - saves.push(data); - load(index+1, callback); - }, function(err) { - main.log(err); - load(index+1, callback); - }) + core.getLocalForage("save"+index, null, function(data) { + if (callback) callback(data); + }, function(err) { + main.log(err); + if (callback) callback(null); + }); +} + +control.prototype.getSaves = function (ids, callback) { + if (!(ids instanceof Array)) return this.getSave(ids, callback); + var count = ids.length, data = {}; + for (var i = 0; i < ids.length; ++i) { + (function (i) { + core.getSave(ids[i], function (result) { + data[i] = result; + if (Object.keys(data).length == count) + callback(data); + }) + })(i); } - load(0, callback); +} + +control.prototype.getAllSaves = function (id, callback) { + if (id != null) return this.getSave(id, callback); + var ids = Object.keys(core.saves.ids).filter(function(x){return x!=0;}) + .sort(function(a,b) {return a-b;}), saves = []; + this.getSaves(ids, function (data) { + for (var i = 0; i < ids.length; ++i) { + if (data[i] != null) + saves.push(data[i]); + } + callback(saves); + }); } ////// 获得所有存在存档的存档位 ////// @@ -1761,6 +1783,43 @@ control.prototype.hasSave = function (index) { return core.saves.ids[index] || false; } +////// 删除一个或多个存档 +control.prototype.removeSave = function (index, callback) { + if (index == 0 || index == "autoSave") { + index = "autoSave"; + core.removeLocalForage(index, function () { + core.saves.autosave.data = null; + core.saves.autosave.updated = false; + if (callback) callback(); + }); + return; + } + core.removeLocalForage("save" + index, function () { + core.saves.favorite = core.saves.favorite.filter(function (i) { return core.hasSave(i); }); + delete core.saves.favoriteName[index]; + core.control._updateFavoriteSaves(); + if (callback) callback(); + }, function () { + core.drawTip("无法删除存档!"); + if (callback) callback(); + }); +} + +////// 读取收藏信息 +control.prototype._loadFavoriteSaves = function () { + core.saves.favorite = core.getLocalStorage("favorite", []); + // --- 移除不存在的收藏 + core.saves.favorite = core.saves.favorite.filter(function (i) { return core.hasSave(i); }); + core.saves.favoriteName = core.getLocalStorage("favoriteName", {}); +} + +control.prototype._updateFavoriteSaves = function () { + core.setLocalStorage("favorite", core.saves.favorite); + core.setLocalStorage("favoriteName", core.saves.favoriteName); +} + +////// 加载某个存档 + // ------ 属性,状态,位置,buff,变量,锁定控制等 ------ // ////// 设置勇士属性 ////// diff --git a/libs/core.js b/libs/core.js index 4ef06a69..fb6d0077 100644 --- a/libs/core.js +++ b/libs/core.js @@ -67,6 +67,7 @@ function core() { 'isPC': true, // 是否是PC 'isAndroid': false, // 是否是Android 'isIOS': false, // 是否是iOS + 'string': 'PC', 'isWeChat': false, // 是否是微信 'isQQ': false, // 是否是QQ 'isChrome': false, // 是否是Chrome @@ -272,6 +273,7 @@ core.prototype._init_platform = function () { core.platform.isPC = false; } }); + core.platform.string = core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""; core.platform.supportCopy = document.queryCommandSupported || document.queryCommandSupported("copy"); var chrome = /Chrome\/(\d+)\./i.exec(navigator.userAgent); if (chrome && parseInt(chrome[1]) >= 50) core.platform.isChrome = true; diff --git a/libs/events.js b/libs/events.js index 7a0bef05..2751d87b 100644 --- a/libs/events.js +++ b/libs/events.js @@ -89,7 +89,7 @@ events.prototype._startGame_upload = function () { formData.append('type', 'people'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); + formData.append('platform', core.platform.string); formData.append('hard', core.encodeBase64(core.status.hard)); formData.append('hardCode', core.getFlag('hard', 0)); formData.append('base64', 1); @@ -171,7 +171,7 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { formData.append('type', 'score'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); + formData.append('platform', core.platform.string); formData.append('hard', core.encodeBase64(core.status.hard)); formData.append('username', core.encodeBase64(username || "")); formData.append('ending', core.encodeBase64(ending)); @@ -2205,7 +2205,7 @@ events.prototype.uploadCurrent = function (username) { formData.append('type', 'score'); formData.append('name', core.firstData.name); formData.append('version', core.firstData.version); - formData.append('platform', core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""); + formData.append('platform', core.platform.string); formData.append('hard', core.encodeBase64(core.status.hard)); formData.append('username', core.encodeBase64(username || "current")); formData.append('lv', core.status.hero.lv); diff --git a/libs/ui.js b/libs/ui.js index cc867ec4..4d924361 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2022,8 +2022,9 @@ ui.prototype.drawEquipbox = function(index) { ////// 绘制存档/读档界面 ////// ui.prototype.drawSLPanel = function(index, refresh) { - if (!core.isset(index)) index=1; - if (index<0) index=0; + core.control._loadFavoriteSaves(); + if (index == null) index = 1; + if (index < 0) index = 0; var page = parseInt(index/10), offset=index%10; var max_page = main.savePages || 30; @@ -2031,53 +2032,35 @@ ui.prototype.drawSLPanel = function(index, refresh) { max_page = Math.ceil((core.saves.favorite||[]).length/5); if (page>=max_page) page=max_page - 1; if (offset>5) offset=5; - index=10*page+offset; + if (core.status.event.data && core.status.event.data.mode=='fav' && page == max_page - 1) { + offset = Math.min(offset, (core.saves.favorite||[]).length - 5 * page); + } var last_page = -1; var mode = 'all'; - if (core.isset(core.status.event.data)) { - //last_page = parseInt(core.status.event.data/10); + if (core.status.event.data) { last_page = core.status.event.data.page; mode = core.status.event.data.mode; } - - core.status.event.data={ - 'page':page, - 'offset':offset, - 'mode':mode - }; - if (!core.isset(core.status.event.ui)) + core.status.event.data={ 'page':page, 'offset':offset, 'mode':mode }; + core.status.event.ui = core.status.event.ui || []; + if (refresh || page != last_page) { core.status.event.ui = []; - - function drawAll() { - core.ui._drawSLPanel_drawBg(page,max_page); - core.ui._drawSLPanel_drawNRecords(6); + this._drawSLPanel_loadSave(page, function () { + core.ui._drawSLPanel_draw(page, max_page); + }); } - if (refresh || page!=last_page) { - core.status.event.ui = []; - this._drawSLPanel_loadFav( - function(){ - core.ui._drawSLPanel_loadSave(page, 0, drawAll); - } - ); - } - else drawAll(); + else this._drawSLPanel_draw(page, max_page); } -// 存档读档的背景 页码 -ui.prototype._drawSLPanel_drawBg = function(page, max_page) { - core.clearMap('ui'); - core.setAlpha('ui', 0.85); - core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000');//可改成背景图图 - core.setAlpha('ui', 1); - var globalFont = (core.status.globalAttribute||core.initStatus.globalAttribute).font; - - core.ui.drawPagination(page+1, max_page, null); +ui.prototype._drawSLPanel_draw = function (page, max_page) { + // --- 绘制背景 + this._drawSLPanel_drawBackground(); + // --- 绘制文字 + core.ui.drawPagination(page+1, max_page); core.setTextAlign('ui', 'center'); - // 退出 - //core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); var bottom = this.PIXEL-13; - core.fillText('ui', '返回游戏', this.PIXEL-48, bottom,'#DDDDDD', 'bold 15px '+globalFont); + core.fillText('ui', '返回游戏', this.PIXEL-48, bottom, '#DDDDDD', this._buildFont(15, true)); if (core.status.event.selection) core.setFillStyle('ui', '#FF6A6A'); @@ -2085,91 +2068,47 @@ ui.prototype._drawSLPanel_drawBg = function(page, max_page) { core.fillText('ui', '删除模式', 48, bottom); else{ if(core.status.event.data.mode=='all'){ - core.fillText('ui', '[E]显示收藏', 48, bottom); + core.fillText('ui', '[E]显示收藏', 52, bottom); }else{ - core.fillText('ui', '[E]显示全部', 48, bottom); + core.fillText('ui', '[E]显示全部', 52, bottom); } } + // --- 绘制记录 + this._drawSLPanel_drawRecords(); } -ui.prototype._drawSLPanel_flushIndex = function(){ - core.saves.favIndex = {}; - for(var i in core.saves.favorite){ - core.saves.favIndex[parseInt(i)+1]=core.saves.favorite[i]; +ui.prototype._drawSLPanel_drawBackground = function() { + core.clearMap('ui'); + core.setAlpha('ui', 0.85); + core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000');//可改成背景图图 + core.setAlpha('ui', 1); +} + +ui.prototype._drawSLPanel_loadSave = function(page, callback) { + var ids = [0]; + for (var i = 1; i <= 5; ++i) { + var id = 5 * page + i; + if(core.status.event.data.mode=='fav') + id = core.saves.favorite[id - 1]; // 因为favorite第一个不是自动存档 所以要偏移1 + ids.push(id); } -} - -// 读取收藏信息到core.saves.favorite中 -ui.prototype._drawSLPanel_loadFav = function(callback){ - if(!core.saves.favorite || !core.saves.favName){ - core.getLocalForage("favorite", null, function(data) { - core.saves.favorite = data || []; - core.ui._drawSLPanel_flushIndex(); - core.getLocalForage("favName", null, function(data) { - core.saves.favName = data || {}; - callback(); - })}); - }else{ + core.getSaves(ids, function (data) { + for (var i = 0; i < ids.length; ++i) + core.status.event.ui[i] = data[i]; + core.saves.autosave.data = data[0]; callback(); - } -} -// 写入收藏信息 | 收藏信息包括收藏id列表favorite、id到收藏名的映射favName -ui.prototype._drawSLPanel_saveFav = function(callback){ - if(!core.saves.favorite){ - core.saves.favorite = []; - core.saves.favName = {}; - } - core.setLocalForage("favorite", core.saves.favorite, - function(){ - core.setLocalForage("favName", core.saves.favName,callback) - }); -} - - -// TODO:递归改并发 | 读取page页的i号存档数据到ui数组中 -ui.prototype._drawSLPanel_loadSave = function(page, i, callback) { - if (i==6) { - callback(); - return; - } - if (i==0) { - if (core.saves.autosave.data!=null) { - core.status.event.ui[i] = core.saves.autosave.data; - core.ui._drawSLPanel_loadSave(page, 1, callback); - } - else { - core.getLocalForage("autoSave", null, function(data) { - core.saves.autosave.data = data; - core.status.event.ui[i]=data; - core.ui._drawSLPanel_loadSave(page, i+1, callback); - }, function(err) {main.log(err);}); - } - } - else { - var id = 5*page+i; - if(core.status.event.data.mode=='fav'){ - id = core.saves.favorite[id-1];//因为favorite第一个不是自动存档 所以要偏移1 - } - core.getLocalForage("save"+id, null, function(data) { - core.status.event.ui[i]=data; - core.ui._drawSLPanel_loadSave(page, i+1, callback); - }, function(err) {main.log(err);}); - } + }); } // 在以x为中心轴 y为顶坐标 的位置绘制一条宽为size的记录 cho表示是否被选中 选中会加粗 highlight表示高亮标题 ✐ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, highLight){ - var globalFont = (core.status.globalAttribute||core.initStatus.globalAttribute).font; var strokeColor = '#FFD700'; if (core.status.event.selection) strokeColor = '#FF6A6A'; + if (!data || !data.floorId) highLight = false; - if (!core.isset(data) || !core.isset(data.floorId)) { //存在数据时才高亮 - highLight = false; - } - core.fillText('ui', title, x, y, highLight?'#FFD700':'#FFFFFF', this._buildFont(17,true));//"bold 17px "+globalFont);//名字 - + core.fillText('ui', title, x, y, highLight?'#FFD700':'#FFFFFF', this._buildFont(17, true)); core.strokeRect('ui', x-size/2, y+15, size, size, cho?strokeColor:'#FFFFFF', cho?6:2); - if (core.isset(data) && core.isset(data.floorId)) { + if (data && data.floorId) { core.drawThumbnail(data.floorId, core.maps.loadMap(data.maps, data.floorId).blocks, { heroLoc: data.hero.loc, heroIcon: data.hero.flags.heroIcon, flags: data.hero.flags }, { @@ -2177,45 +2116,36 @@ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, hi }); var v = core.formatBigNumber(data.hero.hp,true)+"/"+core.formatBigNumber(data.hero.atk,true)+"/"+core.formatBigNumber(data.hero.def,true); var v2 = "/"+core.formatBigNumber(data.hero.mdef,true); - if (v.length+v2.length<=21) v+=v2; - core.fillText('ui', v, x, y+30+size, '#FFD700', this._buildFont(10)); - core.fillText('ui', core.formatDate(new Date(data.time)), x, y+43+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF', this._buildFont(10));//'10px '+globalFont); + if (core.calWidth('ui', v + v2, this._buildFont(10, false)) <= size) v += v2; + core.fillText('ui', v, x, y+30+size, '#FFD700'); + core.fillText('ui', core.formatDate(new Date(data.time)), x, y+43+size, data.hero.flags.__consoleOpened__?'#FF6A6A':'#FFFFFF'); } else { core.fillRect('ui', x-size/2, y+15, size, size, '#333333', 2); - core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30,true));//'bold 30px '+globalFont); + core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30,true)); } } -// 绘制n条记录到画板 -ui.prototype._drawSLPanel_drawNRecords = function (n) -{ - var page = core.status.event.data.page;//Math.floor(core.status.event.data/10); - var offset = core.status.event.data.offset;//core.status.event.data%10; - var u = Math.floor(this.PIXEL/6), size = Math.floor(this.PIXEL/3-20);//118 - for (var i=0;i=0 || core.status.event.data.mode=='fav'; - if(highLight)title = '★ ' + title - else title = '☆ ' + title; - var fid = id; - if(core.status.event.data.mode=='fav' && i!=0){//收藏模式下显示修改符号以及自己标识的名字 - fid = core.saves.favIndex[id]; - if(!data && i>0){ - continue; - } -// name = core.saves.favName[fid] ? core.status.event.id=='save'?"S:":core.status.event.id=='load'?"L:":core.status.event.id=='replayLoad'?"re:":"" : name; - title = name + (core.saves.favName[fid]||fid) + '✐'; - }else{ -// name = core.saves.favName[fid] ? core.status.event.id=='save'?"S:":core.status.event.id=='load'?"L:":core.status.event.id=='replayLoad'?"re:":"" : name; - title += name + (core.saves.favName[fid]||fid); + var id = 5 * page + i; + var highLight = (i>0&&core.saves.favorite.indexOf(id)>=0) || core.status.event.data.mode=='fav'; + var title = (highLight?'★ ':'☆ ') + (core.saves.favoriteName[id] || (name + id)); + if (i != 0 && core.status.event.data.mode=='fav') { + if (!data) break; + var real_id = core.saves.favorite[id - 1]; + title = (core.saves.favoriteName[real_id] || (name + real_id)) + ' ✐'; } + var charSize = 32;// 字体占用像素范围 var topSpan = parseInt((this.PIXEL-charSize-2*(charSize*2 + size))/3);// Margin - var yTop1 = topSpan+parseInt(charSize/2);//文字的中心 + var yTop1 = topSpan+parseInt(charSize/2) + 8;//文字的中心 var yTop2 = yTop1+charSize*2+size+topSpan; if (i<3) { this._drawSLPanel_drawRecord(i==0?"自动存档":title, data, (2*i+1)*u, yTop1, size, i==offset, highLight); From f961cc25ece3ee9548fc15732c419d89b5db7da1 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 00:43:35 +0800 Subject: [PATCH 109/153] drawSL --- libs/actions.js | 11 ++++++----- libs/ui.js | 2 +- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 96008b98..8c30b831 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1622,24 +1622,23 @@ actions.prototype._clickSL = function (x, y) { // 点存档名 var xLeft = parseInt(this.SIZE/3), xRight = parseInt(this.SIZE*2/3); var topY1 = 0, topY2 = this.HSIZE; - if(y==topY1){ + if(y >= topY1 && y <= topY1 + 1) { if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 1); if (x >= xRight) return this._clickSL_favorite(page, 2); } - if(y==topY2){ + if(y >= topY2 && y <= topY2 + 1) { if (x < xLeft) return this._clickSL_favorite(page, 3); if (x >= xLeft && x < xRight) return this._clickSL_favorite(page, 4); if (x >= xRight) return this._clickSL_favorite(page, 5); } var id = null; - var topSpan = parseInt(this.SIZE/7); - if (y >= topY1 + topSpan && y <= topY1 + topSpan + 3) { + if (y >= topY1 + 2 && y < this.HSIZE - 1) { if (x < xLeft) id = "autoSave"; if (x >= xLeft && x < xRight) id = 5 * page + 1; if (x >= xRight) id = 5 * page + 2; } - if (y >= topY2+1 && y <= topY2+5) { + if (y >= topY2 + 2 && y < this.SIZE - 1) { if (x < xLeft) id = 5 * page + 3; if (x >= xLeft && x < xRight) id = 5 * page + 4; if (x >= xRight) id = 5 * page + 5; @@ -2115,6 +2114,7 @@ actions.prototype._clickStorageRemove = function (x, y) { actions.prototype._clickStorageRemove_all = function () { core.myconfirm("你确定要清除【全部塔】的所有本地存档?\n此行为不可逆!!!", function () { var done = function () { + core.saves.ids = {}; core.saves.autosave.data = null; core.saves.autosave.updated = false; core.ui.closePanel(); @@ -2139,6 +2139,7 @@ actions.prototype._clickStorageRemove_all = function () { actions.prototype._clickStorageRemove_current = function () { core.myconfirm("你确定要清除本塔的所有本地存档?\n此行为不可逆!!!", function () { var done = function () { + core.saves.ids = {}; core.saves.autosave.data = null; core.saves.autosave.updated = false; core.ui.closePanel(); diff --git a/libs/ui.js b/libs/ui.js index 4d924361..010c2cfe 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -2122,7 +2122,7 @@ ui.prototype._drawSLPanel_drawRecord = function(title, data, x, y, size, cho, hi } else { core.fillRect('ui', x-size/2, y+15, size, size, '#333333', 2); - core.fillText('ui', '空', x, parseInt(y+15+size/2), '#FFFFFF', this._buildFont(30,true)); + core.fillText('ui', '空', x, parseInt(y+22+size/2), '#FFFFFF', this._buildFont(30,true)); } } From f98c1b0916565188a8d0442afea46bd9821437e6 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 00:49:19 +0800 Subject: [PATCH 110/153] drawSL --- libs/actions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/actions.js b/libs/actions.js index 8c30b831..742cb09f 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1614,7 +1614,7 @@ actions.prototype._clickSL = function (x, y) { else { page = parseInt((core.saves.saveIndex-1)/5); offset = core.saves.saveIndex-5*page; - core.ui.drawSLPanel(10*page + offset); + core.ui.drawSLPanel(10*page + offset, true); } } return; From 25d0ce95acddabff7cc91ab410f5781dfa7a9b2e Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 01:13:40 +0800 Subject: [PATCH 111/153] Fix compress --- libs/ui.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/ui.js b/libs/ui.js index 010c2cfe..2d35c988 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1559,7 +1559,7 @@ ui.prototype.drawFly = function(page) { var middle = this.HPIXEL + 39; if (core.actions._getNextFlyFloor(1) != page) { core.fillText('ui', '▲', this.PIXEL - 60, middle - 64, null, this._buildFont(17, false)); - core.fillText('ui', '▲', this.PIXEL - 60, middle - 96,); + core.fillText('ui', '▲', this.PIXEL - 60, middle - 96); core.fillText('ui', '▲', this.PIXEL - 60, middle - 96 - 7); } if (core.actions._getNextFlyFloor(-1) != page) { From 254484541d7dcd3b65b90dfbdfde3e16a7bb0c12 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 16:46:02 +0800 Subject: [PATCH 112/153] drawEquipbox --- libs/actions.js | 91 +++++++------- libs/control.js | 4 +- libs/core.js | 11 +- libs/items.js | 25 ++-- libs/ui.js | 317 +++++++++++++++++++++-------------------------- project/icons.js | 2 +- project/items.js | 2 +- project/maps.js | 2 +- 8 files changed, 212 insertions(+), 242 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index 742cb09f..5ec68a78 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1416,64 +1416,65 @@ actions.prototype._keyUpToolbox = function (keycode) { ////// 装备栏界面时的点击操作 ////// actions.prototype._clickEquipbox = function (x, y) { // 道具栏 - if (x >= 10 && x <= 12 && y == 0) { + if (x >= this.LAST - 2 && y == 0) { core.ui.closePanel(); core.openToolbox(); return; } // 返回 - if (x >= 10 && x <= 12 && y == 12) { + if (x >= this.LAST - 2 && y == this.LAST) { core.ui.closePanel(); return; } - // 当前页面 - var page = core.status.event.data.page; - // 上一页 - if ((x == 3 || x == 4) && y == 12) { - if (page > 1) { + if ((x == this.HSIZE-2 || x == this.HSIZE-3) && y == this.LAST) { + if (core.status.event.data.page > 1) { core.status.event.data.page--; core.ui.drawEquipbox(core.status.event.selection); } return; } // 下一页 - if ((x == 8 || x == 9) && y == 12) { - var lastPage = Math.ceil(Object.keys(core.status.hero.items.equips).length / 12); - if (page < lastPage) { + if ((x == this.HSIZE+2 || x == this.HSIZE+3) && y == this.LAST) { + var lastPage = Math.ceil(Object.keys(core.status.hero.items.equips).length / this.LAST); + if (core.status.event.data.page < lastPage) { core.status.event.data.page++; core.ui.drawEquipbox(core.status.event.selection); } return; } - var index = parseInt(x / 2); - if (y == 4) index += 0; - else if (y == 6) index += 6; - else if (y == 9) index += 12; - else if (y == 11) index += 18; - else index = -1; - - if (index >= 0) { - if (index < 12) index = parseInt(index / 2); - this._clickEquipboxIndex(index); + var per_page = this.HSIZE - 3, v = this.SIZE / per_page; + if (y == this.LAST - 8) { + for (var i = 0; i < per_page; ++i) + if (x >= i * v && x <= (i + 1) * v) + return this._clickEquipboxIndex(i); } + else if (y == this.LAST - 6) { + for (var i = 0; i < per_page; ++i) + if (x >= i * v && x <= (i + 1) * v) + return this._clickEquipboxIndex(per_page + i); + } + else if (y == this.LAST - 3) + this._clickEquipboxIndex(this.LAST + parseInt(x / 2)) + else if (y == this.LAST - 1) + this._clickEquipboxIndex(this.LAST + this.HSIZE + parseInt(x / 2)); } ////// 选择装备栏界面中某个Index后的操作 ////// actions.prototype._clickEquipboxIndex = function (index) { - if (index < 6) { + if (index < this.LAST) { if (index >= core.status.globalAttribute.equipName.length) return; if (index == core.status.event.selection && core.status.hero.equipment[index]) { core.unloadEquip(index); core.status.route.push("unEquip:" + index); } } - else if (index >= 12) { + else { var equips = Object.keys(core.status.hero.items.equips || {}).sort(); if (index == core.status.event.selection) { - var equipId = equips[index - 12 + (core.status.event.data.page - 1) * 12]; + var equipId = equips[index - this.LAST + (core.status.event.data.page - 1) * this.LAST]; core.loadEquip(equipId); core.status.route.push("equip:" + equipId); } @@ -1483,21 +1484,23 @@ actions.prototype._clickEquipboxIndex = function (index) { ////// 装备栏界面时,按下某个键的操作 ////// actions.prototype._keyDownEquipbox = function (keycode) { - if (core.status.event.data != null) return; + if (core.status.event.data == null) return; + var last_index = this.LAST - 1; + var per_line = this.HSIZE - 3; var equipCapacity = core.status.globalAttribute.equipName.length; var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); var index = core.status.event.selection; var page = core.status.event.data.page; - var totalPage = Math.ceil(ownEquipment.length / 12); - var totalLastIndex = 12 + (page < totalPage ? 11 : (ownEquipment.length + 11) % 12); + var totalPage = Math.ceil(ownEquipment.length / this.LAST); + var totalLastIndex = this.LAST + (page < totalPage ? last_index : (ownEquipment.length + last_index) % this.LAST); if (keycode == 37) { // left if (index == 0) return; - if (index == 12) { + if (index == this.LAST) { if (page > 1) { core.status.event.data.page--; - index = 23; + index = this.LAST + last_index; } else if (page == 1) index = equipCapacity - 1; @@ -1508,25 +1511,25 @@ actions.prototype._keyDownEquipbox = function (keycode) { return; } if (keycode == 38) { // up - if (index < 3) return; - else if (index < 6) index -= 3; - else if (index < 18) { - index = parseInt((index - 12) / 2); - if (equipCapacity > 3) index = Math.min(equipCapacity - 1, index + 3); + if (index < per_line) return; + else if (index < 2 * per_line) index -= per_line; + else if (index < this.LAST + this.HSIZE) { + index = parseInt((index - this.LAST) / 2); + if (equipCapacity > per_line) index = Math.min(equipCapacity - 1, index + per_line); else index = Math.min(equipCapacity - 1, index); } - else index -= 6; + else index -= this.HSIZE; this._clickEquipboxIndex(index); return; } if (keycode == 39) { // right - if (page < totalPage && index == 23) { + if (page < totalPage && index == this.LAST + last_index) { core.status.event.data.page++; - index = 12; + index = this.LAST; } else if (index == equipCapacity - 1) { if (totalPage == 0) return; - index = 12; + index = this.LAST; } else if (index == totalLastIndex) return; @@ -1535,19 +1538,19 @@ actions.prototype._keyDownEquipbox = function (keycode) { return; } if (keycode == 40) { // down - if (index < 3) { - if (equipCapacity > 3) index = Math.min(index + 3, equipCapacity - 1); + if (index < per_line) { + if (equipCapacity > per_line) index = Math.min(index + per_line, equipCapacity - 1); else { if (totalPage == 0) return; - index = Math.min(2 * index + 1 + 12, totalLastIndex); + index = Math.min(2 * index + 1 + this.LAST, totalLastIndex); } } - else if (index < 6) { + else if (index < 2 * per_line) { if (totalPage == 0) return; - index = Math.min(2 * (index - 3) + 1 + 12, totalLastIndex); + index = Math.min(2 * (index - per_line) + 1 + this.LAST, totalLastIndex); } - else if (index < 18) - index = Math.min(index + 6, totalLastIndex); + else if (index < this.LAST + this.HSIZE) + index = Math.min(index + this.HSIZE, totalLastIndex); else return; this._clickEquipboxIndex(index); return; diff --git a/libs/control.js b/libs/control.js index 7f9b5324..052cbed0 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1865,12 +1865,12 @@ control.prototype.getRealStatusOrDefault = function (status, name) { ////// 设置某个属性的增幅值 ////// control.prototype.setBuff = function (name, value) { - this.setFlag('flag:__'+name+'_buff__', value); + this.setFlag('__'+name+'_buff__', value); } ////// 加减某个属性的增幅值 ////// control.prototype.addBuff = function (name, value) { - this.setFlag('flag:__'+name+'_buff__', this.getBuff(name) + value); + this.setFlag('__'+name+'_buff__', this.getBuff(name) + value); } ////// 获得某个属性的增幅值 ////// diff --git a/libs/core.js b/libs/core.js index fb6d0077..966aa4d0 100644 --- a/libs/core.js +++ b/libs/core.js @@ -103,7 +103,9 @@ function core() { "data": null, "time": 0, "updated": false, - } + }, + "favorite": [], + "favoriteName": {} } this.initStatus = { 'played': false, @@ -295,7 +297,7 @@ core.prototype._init_platform = function () { } core.prototype._init_checkLocalForage = function () { - core.platform.useLocalForage = core.getLocalStorage('useLocalForage', !core.platform.isIOS); + core.platform.useLocalForage = core.getLocalStorage('useLocalForage', true); var _error = function (e) { main.log(e); core.platform.useLocalForage = false; @@ -384,13 +386,16 @@ core.prototype._forwardFunc = function (name, funcname) { } if (core[funcname]) { - console.error("ERROR: Cannot forward function " + funcname + " from " + name + "!"); + console.error("ERROR: 无法转发 "+name+" 中的函数 "+funcname+" 到 core 中!同名函数已存在。"); return; } var parameterInfo = /^\s*function\s*[\w_$]*\(([\w_,$\s]*)\)\s*\{/.exec(core[name][funcname].toString()); var parameters = (parameterInfo == null ? "" : parameterInfo[1]).replace(/\s*/g, '').replace(/,/g, ', '); // core[funcname] = new Function(parameters, "return core."+name+"."+funcname+"("+parameters+");"); eval("core." + funcname + " = function (" + parameters + ") {\n\treturn core." + name + "." + funcname + "(" + parameters + ");\n}"); + if (name == 'plugin') { + main.log("插件函数转发:core."+funcname+" = core.plugin."+funcname); + } } core.prototype.doFunc = function (func, _this) { diff --git a/libs/items.js b/libs/items.js index 58faca5c..23056d8d 100644 --- a/libs/items.js +++ b/libs/items.js @@ -311,20 +311,17 @@ items.prototype.unloadEquip = function (equipType, callback) { } items.prototype.compareEquipment = function (compareEquipId, beComparedEquipId) { - var compareAtk = 0, compareDef = 0, compareMdef = 0; - if (compareEquipId) { - var compareEquip = core.material.items[compareEquipId]; - compareAtk += (compareEquip.equip || {}).atk || 0; - compareDef += (compareEquip.equip || {}).def || 0; - compareMdef += (compareEquip.equip || {}).mdef || 0; + var result = {}; + var first = core.material.items[compareEquipId], second = core.material.items[beComparedEquipId]; + for (var name in core.status.hero) { + if (typeof core.status.hero[name] == 'number') { + var ans = 0; + if (first) ans += (first.equip || {})[name] || 0; + if (second) ans -= (second.equip || {})[name] || 0; + if (ans != 0) result[name] = ans; + } } - if (beComparedEquipId) { - var beComparedEquip = core.material.items[beComparedEquipId]; - compareAtk -= (beComparedEquip.equip || {}).atk || 0; - compareDef -= (beComparedEquip.equip || {}).def || 0; - compareMdef -= (beComparedEquip.equip || {}).mdef || 0; - } - return {"atk": compareAtk, "def": compareDef, "mdef": compareMdef}; + return result; } ////// 实际换装的效果 ////// @@ -349,7 +346,7 @@ items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { var loadPercentage = loadEquip.equip.percentage, unloadPercentage = unloadEquip.equip.percentage; - if (loadPercentage != null && unloadPercentage != null && loadPercentage != unloadPercentage) { + if (loadId && unloadId && (loadPercentage || false) != (unloadPercentage || false)) { this.unloadEquip(type); this.loadEquip(loadId); if (callback) callback(); diff --git a/libs/ui.js b/libs/ui.js index 2d35c988..2d1ecf01 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1733,7 +1733,7 @@ ui.prototype.drawToolbox = function(index) { core.setTextAlign('ui', 'center'); core.fillText('ui', '[装备栏]', this.PIXEL - 46, 25, '#DDDDDD', this._buildFont(15, true)); - core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD'); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13); } ui.prototype._drawToolbox_getInfo = function (index) { @@ -1795,28 +1795,25 @@ ui.prototype._drawToolbox_drawLine = function (yoffset, text) { } ui.prototype._drawToolbox_drawDescription = function (info, max_height) { - core.setTextAlign('ui', 'left'); - // 描述 - if (info.selectId) { - var item=core.material.items[info.selectId]; - core.fillText('ui', item.name, 10, 32, '#FFD700', this._buildFont(20, true)) - var text = item.text||"该道具暂无描述。"; - try { - // 检查能否eval - text = core.replaceText(text); - } catch (e) {} - var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(17, false)); - // --- 开始逐行绘制 - var curr = 62, line_height = 25; - core.setFillStyle('ui', '#FFFFFF'); - for (var i=0;i=max_height) break; - } - if (curr < max_height) { - core.fillText('ui', '<继续点击该道具即可进行使用>', 10, curr, '#CCCCCC', this._buildFont(14, false)); - } + if (!info.selectId) return; + var item=core.material.items[info.selectId]; + core.fillText('ui', item.name, 10, 32, '#FFD700', this._buildFont(20, true)) + var text = item.text||"该道具暂无描述。"; + try { + // 检查能否eval + text = core.replaceText(text); + } catch (e) {} + var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(17, false)); + // --- 开始逐行绘制 + var curr = 62, line_height = 25; + core.setFillStyle('ui', '#FFFFFF'); + for (var i=0;i=max_height) break; + } + if (curr < max_height) { + core.fillText('ui', '<继续点击该道具即可进行使用>', 10, curr, '#CCCCCC', this._buildFont(14, false)); } } @@ -1837,187 +1834,155 @@ ui.prototype._drawToolbox_drawContent = function (info, line, items, page, drawC ////// 绘制装备界面 ////// ui.prototype.drawEquipbox = function(index) { - // 设定eventdata - if (!core.isset(core.status.event.data) || !core.isset(core.status.event.data.page)) - core.status.event.data = {"page":1, "selectId":null}; + var info = this._drawEquipbox_getInfo(index); + this._drawToolbox_drawBackground(); + core.setAlpha('ui', 1); + core.setStrokeStyle('ui', '#DDDDDD'); + core.canvas.ui.lineWidth = 2; + core.canvas.ui.strokeWidth = 2; + core.setTextAlign('ui', 'right'); + var line1 = this.PIXEL - 306; + this._drawToolbox_drawLine(line1, "当前装备"); + var line2 = this.PIXEL - 146; + this._drawToolbox_drawLine(line2, "拥有装备"); + + this._drawEquipbox_description(info, line1); + + this._drawEquipbox_drawEquiped(info, line1); + this._drawToolbox_drawContent(info, line2, info.ownEquipment, info.page, true); + this.drawPagination(info.page, info.totalPage); + + core.setTextAlign('ui', 'center'); + core.fillText('ui', '[道具栏]', this.PIXEL - 46, 25, '#DDDDDD', this._buildFont(15, true)); + core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13); +} + +ui.prototype._drawEquipbox_getInfo = function (index) { + if (!core.status.event.data || core.status.event.data.page == null) + core.status.event.data = {"page":1, "selectId":null}; var allEquips = core.status.globalAttribute.equipName; var equipLength = allEquips.length; - - if (!core.isset(core.status.hero.equipment)) core.status.hero.equipment = []; - + if (!core.status.hero.equipment) core.status.hero.equipment = []; var equipEquipment = core.status.hero.equipment; var ownEquipment = Object.keys(core.status.hero.items.equips).sort(); - var page = core.status.event.data.page; - var totalPage = Math.ceil(ownEquipment.length/12); - + var totalPage = Math.ceil(ownEquipment.length / this.LAST); // 处理index - if (!core.isset(index)) { - if (equipLength>0 && core.isset(equipEquipment[0])) index=0; - else if (ownEquipment.length>0) index=12; - else index=0; + if (index == null) { + if (equipLength > 0 && equipEquipment[0]) index = 0; + else if (ownEquipment.length > 0) index = this.LAST; + else index = 0; } - if (index>=12 && ownEquipment.length==0) index = 0; + if (index >= this.LAST && ownEquipment.length == 0) index = 0; var selectId=null; - if (index<12) { + if (index < this.LAST) { if (index >= equipLength) index=Math.max(0, equipLength - 1); - selectId = equipEquipment[index]||null; + selectId = equipEquipment[index] || null; } else { - if (page == totalPage) index = Math.min(index, (ownEquipment.length+11)%12+12); - selectId = ownEquipment[index-12 + (page-1)*12]; + if (page == totalPage) index = Math.min(index, (ownEquipment.length+this.LAST-1)%this.LAST+this.LAST); + selectId = ownEquipment[index - this.LAST + (page - 1) * this.LAST]; if (!core.hasItem(selectId)) selectId=null; } core.status.event.selection=index; core.status.event.data.selectId=selectId; + return { index: index, selectId: selectId, page: page, totalPage: totalPage, allEquips: allEquips, + equipLength: equipLength, equipEquipment: equipEquipment, ownEquipment: ownEquipment}; +} - core.clearMap('ui', 0, 0, 416, 416); - core.setAlpha('ui', 0.85); - core.fillRect('ui', 0, 0, 416, 416, '#000000'); - core.setAlpha('ui', 1); - core.setFillStyle('ui', '#DDDDDD'); - core.setStrokeStyle('ui', '#DDDDDD'); - core.canvas.ui.lineWidth = 2; - core.canvas.ui.strokeWidth = 2; - - var ydelta = 20; - - // 画线 - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(0, 130-ydelta); - core.canvas.ui.lineTo(416, 130-ydelta); - core.canvas.ui.stroke(); - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(416,129-ydelta); - core.canvas.ui.lineTo(416,105-ydelta); - core.canvas.ui.lineTo(416-72,105-ydelta); - core.canvas.ui.lineTo(416-102,129-ydelta); - core.canvas.ui.fill(); - - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(0, 290-ydelta); - core.canvas.ui.lineTo(416, 290-ydelta); - core.canvas.ui.stroke(); - core.canvas.ui.beginPath(); - core.canvas.ui.moveTo(416,289-ydelta); - core.canvas.ui.lineTo(416,265-ydelta); - core.canvas.ui.lineTo(416-72,265-ydelta); - core.canvas.ui.lineTo(416-102,289-ydelta); - core.canvas.ui.fill(); - - // 文字 - core.setTextAlign('ui', 'right'); - var globalFont = core.status.globalAttribute.font; - core.fillText('ui', "当前装备", 411, 124-ydelta, '#333333', "bold 16px "+globalFont); - core.fillText('ui', "拥有装备", 411, 284-ydelta); - +ui.prototype._drawEquipbox_description = function (info, max_height) { core.setTextAlign('ui', 'left'); + if (!info.selectId) return; + var equip=core.material.items[info.selectId]; + // --- 标题 + if (!equip.equip) equip.equip = {"type": 0}; + var equipType = equip.equip.type, equipString; + if (typeof equipType === 'string') { + equipString = equipType || "未知部位"; + equipType = core.items.getEquipTypeByName(equipType); + } + else equipString = info.allEquips[equipType] || "未知部位"; + core.fillText('ui', equip.name + "(" + equipString + ")", 10, 32, '#FFD700', this._buildFont(20, true)) + // --- 描述 + var text = equip.text || "该装备暂无描述。"; + try { + text = core.replaceText(text); + } catch (e) {} + var lines = core.splitLines('ui', text, this.PIXEL - 15, this._buildFont(17, false)); + var curr = 62, line_height = 25; + core.setFillStyle('ui', '#FFFFFF'); + for (var i = 0; i < lines.length; ++i) { + core.fillText('ui', lines[i], 10, curr); + curr += line_height; + if (curr >= max_height) break; + } + // --- 变化值 + if (curr >= max_height) return; + this._drawEquipbox_drawStatusChanged(info, curr, equip, equipType); +} - // 描述 - if (core.isset(selectId)) { - var equip=core.material.items[selectId]; - if (!core.isset(equip.equip)) equip.equip = {"type": 0}; - var equipType = equip.equip.type; - var equipString; - if (typeof equipType === 'string') { - equipString = equipType||"未知部位"; - equipType = core.items.getEquipTypeByName(equipType); - } - else equipString = allEquips[equipType]||"未知部位"; - - core.fillText('ui', equip.name + "(" + equipString + ")", 10, 32, '#FFD700', "bold 20px "+globalFont) - - var text = equip.text||"该装备暂无描述。"; - try { - text = core.replaceText(text); - } catch (e) {} - var lines = core.splitLines('ui', text, 406, '17px '+globalFont); - - core.fillText('ui', lines[0], 10, 62, '#FFFFFF', '17px '+globalFont); - - // 比较属性 - if (lines.length==1) { - var compare, differentMode = null; - if (index<12) compare = core.compareEquipment(null, selectId); - else { - if (equipType<0) { - differentMode = '<当前没有该装备的空位,请先卸下装备>'; - } - else { - var last = core.material.items[equipEquipment[equipType]]||{}; - // 检查是不是数值模式和比例模式之间的切换 - if (core.isset(last.equip) && (last.equip.percentage||false) != (equip.equip.percentage||false)) { - differentMode = '<数值和比例模式之间的切换不显示属性变化>'; - } - else { - compare = core.compareEquipment(selectId, equipEquipment[equipType]); - } - } - } - if (differentMode != null) { - core.fillText('ui', differentMode, 10, 89, '#CCCCCC', '14px '+globalFont); - } - else { - var drawOffset = 10; - [['攻击','atk'], ['防御','def'], ['魔防','mdef']].forEach(function (t) { - var title = t[0], name = t[1]; - if (!core.isset(compare[name]) || compare[name]==0) return; - var color = '#00FF00'; - if (compare[name]<0) color = '#FF0000'; - var nowValue = core.getStatus(name), newValue = nowValue + compare[name]; - if (equip.equip.percentage) { - var nowBuff = core.getBuff(name), newBuff = nowBuff+compare[name]/100; - nowValue = Math.floor(nowBuff*core.getStatus(name)); - newValue = Math.floor(newBuff*core.getStatus(name)); - } - var content = title + ' ' + nowValue + '->'; - core.fillText('ui', content, drawOffset, 89, '#CCCCCC', 'bold 14px '+globalFont); - drawOffset += core.calWidth('ui', content); - core.fillText('ui', newValue, drawOffset, 89, color); - drawOffset += core.calWidth('ui', newValue) + 15; - }) - } - } +ui.prototype._drawEquipbox_drawStatusChanged = function (info, y, equip, equipType) { + var compare, differentMode = null; + if (info.index < this.LAST) compare = core.compareEquipment(null, info.selectId); + else { + if (equipType<0) differentMode = '<当前没有该装备的空位,请先卸下装备>'; else { - var leftText = text.substring(lines[0].length); - core.fillText('ui', leftText, 10, 89, '#FFFFFF', '17px '+globalFont); + var last = core.material.items[info.equipEquipment[equipType]]||{}; + if (last.equip && (last.equip.percentage || false) != (equip.equip.percentage || false)) + differentMode = '<数值和比例模式之间的切换不显示属性变化>'; + else + compare = core.compareEquipment(info.selectId, info.equipEquipment[equipType]); } } + if (differentMode != null) { + core.fillText('ui', differentMode, 10, y, '#CCCCCC', this._buildFont(14, false)); + return; + } + var drawOffset = 10; + // --- 变化值... + core.setFont('ui', this._buildFont(14, true)); + for (var name in compare) { + var img = core.statusBar.icons[name]; + if (img) { // 绘制图标 + core.drawImage('ui', img, 0, 0, 32, 32, drawOffset, y - 13, 16, 16); + drawOffset += 20; + } + else { // 绘制文字 + core.fillText('ui', name + " ", drawOffset, y, '#CCCCCC'); + drawOffset += core.calWidth('ui', name + " "); + } + var nowValue = core.getStatus(name) * core.getBuff(name), newValue = (nowValue + compare[name]) * core.getBuff(name); + if (equip.equip.percentage) { + var nowBuff = core.getBuff(name), newBuff = nowBuff + compare[name] / 100; + nowValue = Math.floor(nowBuff * core.getStatus(name)); + newValue = Math.floor(newBuff * core.getStatus(name)); + } + nowValue = core.formatBigNumber(nowValue); + newValue = core.formatBigNumber(newValue); + core.fillText('ui', nowValue + "->", drawOffset, y, '#CCCCCC'); + drawOffset += core.calWidth('ui', nowValue + "->"); + core.fillText('ui', newValue, drawOffset, y, compare[name]>0?'#00FF00':'#FF0000'); + drawOffset += core.calWidth('ui', newValue) + 8; + } +} +ui.prototype._drawEquipbox_drawEquiped = function (info, line) { core.setTextAlign('ui', 'right'); - var images = core.material.images.items; - + var per_line = this.HSIZE - 3, width = Math.floor(this.PIXEL / (per_line + 0.25)); // 当前装备 - for (var i = 0 ; i < equipLength ; i++) { - var equipId = equipEquipment[i] || null; - if (core.isset(equipId)) { + for (var i = 0; i < info.equipLength ; i++) { + var equipId = info.equipEquipment[i] || null; + var offset_text = width * (i % per_line) + 56; + var offset_image = width * (i % per_line) + width * 2 / 3; + var y = line + 54 * Math.floor(i / per_line) + 19; + if (equipId) { var icon = core.material.icons.items[equipId]; - core.drawImage('ui', images, 0, icon*32, 32, 32, 16*(8*(i%3)+5)+5, 144+Math.floor(i/3)*54+5-ydelta, 32, 32); + core.drawImage('ui', core.material.images.items, 0, 32 * icon, 32, 32, offset_image, y, 32, 32); } - core.fillText('ui', allEquips[i]||"未知", 16*(8*(i%3)+1)+40, 144+Math.floor(i/3)*54+32-ydelta, '#FFFFFF', "bold 16px "+globalFont); - core.strokeRect('ui', 16*(8*(i%3)+5)+1, 144+Math.floor(i/3)*54+1-ydelta, 40, 40, index==i?'#FFD700':"#FFFFFF"); + core.fillText('ui', info.allEquips[i] || "未知", offset_text, y + 27, '#FFFFFF', this._buildFont(16, true)) + core.strokeRect('ui', offset_image - 4, y - 4, 40, 40, info.index==i?'#FFD700':"#FFFFFF"); } - - // 现有装备 - for (var i=0;i<12;i++) { - var ownEquip=ownEquipment[12*(page-1)+i]; - if (!core.isset(ownEquip)) continue; - var icon=core.material.icons.items[ownEquip]; - core.drawImage('ui', images, 0, icon*32, 32, 32, 16*(4*(i%6)+1)+5, 304+Math.floor(i/6)*54+5-ydelta, 32, 32) - // 个数 - if (core.itemCount(ownEquip)>1) - core.fillText('ui', core.itemCount(ownEquip), 16*(4*(i%6)+1)+40, 304+Math.floor(i/6)*54+38-ydelta, '#FFFFFF', "bold 14px "+globalFont); - if (index>=12 && selectId == ownEquip) - core.strokeRect('ui', 16*(4*(i%6)+1)+1, 304+Math.floor(i/6)*54+1-ydelta, 40, 40, '#FFD700'); - } - - this.drawPagination(page, totalPage, 12); - // 道具栏 - core.setTextAlign('ui', 'center'); - core.fillText('ui', '[道具栏]', 370, 25,'#DDDDDD', 'bold 15px '+globalFont); - // 退出按钮 - core.fillText('ui', '返回游戏', 370, 403,'#DDDDDD', 'bold 15px '+globalFont); } ////// 绘制存档/读档界面 ////// diff --git a/project/icons.js b/project/icons.js index 71bce353..0fe339c2 100644 --- a/project/icons.js +++ b/project/icons.js @@ -259,7 +259,7 @@ var icons_4665ee12_3a1f_44a4_bea3_0fccba634dc1 = "hammer": 48, "jumpShoes": 49, "skill1": 30, - "I73": 10 + "wand": 10 }, "autotile": { "autotile": 0, diff --git a/project/items.js b/project/items.js index 83b236c7..efda5b71 100644 --- a/project/items.js +++ b/project/items.js @@ -303,7 +303,7 @@ var items_296f5d02_12fd_4166_a7c1_b5e830c9ee3a = "text": "可以打开或关闭主动技能二倍斩", "hideInReplay": true }, - "I73": { + "wand": { "cls": "items", "name": "新物品" } diff --git a/project/maps.js b/project/maps.js index 78a610d0..d631d0ba 100644 --- a/project/maps.js +++ b/project/maps.js @@ -67,7 +67,7 @@ var maps_90f36752_8815_4be8_b32b_d7fad1d0542e = "70": {"cls":"items","id":"sword0"}, "71": {"cls":"items","id":"shield0"}, "72": {"cls":"items","id":"skill1"}, - "73": {"cls":"items","id":"I73"}, + "73": {"cls":"items","id":"wand"}, "81": {"cls":"terrains","id":"yellowDoor","trigger":"openDoor"}, "82": {"cls":"terrains","id":"blueDoor","trigger":"openDoor"}, "83": {"cls":"terrains","id":"redDoor","trigger":"openDoor"}, From 67f98f2da634384870e77135dac909f2048ed9a6 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 17:04:48 +0800 Subject: [PATCH 113/153] toolbox textalign --- libs/ui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/ui.js b/libs/ui.js index 2d1ecf01..8a569922 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1795,6 +1795,7 @@ ui.prototype._drawToolbox_drawLine = function (yoffset, text) { } ui.prototype._drawToolbox_drawDescription = function (info, max_height) { + core.setTextAlign('ui', 'left'); if (!info.selectId) return; var item=core.material.items[info.selectId]; core.fillText('ui', item.name, 10, 32, '#FFD700', this._buildFont(20, true)) From f7056d699f9ded847463716445c582adab038e95 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 17:15:12 +0800 Subject: [PATCH 114/153] fix status:x --- libs/control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/control.js b/libs/control.js index 052cbed0..d85b2cf6 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1841,7 +1841,7 @@ control.prototype.addStatus = function (name, value) { control.prototype.getStatus = function (name) { if (!core.status.hero) return null; if (name == 'x' || name == 'y' || name == 'direction') - return this.getHeroLoc('x'); + return this.getHeroLoc(name); if (name == 'exp') name = 'experience'; return core.status.hero[name]; } From 16980c527ab7f817a7e0201dfab5212679658d05 Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 19:18:57 +0800 Subject: [PATCH 115/153] quickCommonEvents --- _docs/event.md | 6 +++ _server/MotaAction.g4 | 17 +++++++++ _server/data.comment.js | 6 +++ _server/editor_blockly.js | 1 + libs/actions.js | 50 ++++++++++++++++++------- libs/control.js | 11 ++++++ libs/events.js | 27 +++++++++++++- libs/ui.js | 18 ++++++--- libs/utils.js | 7 +++- main.js | 2 +- project/data.js | 1 + project/events.js | 77 +++++++++++++++++++++++++++++++++++++++ project/functions.js | 2 +- 13 files changed, 200 insertions(+), 25 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 3beb965a..57825ba7 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -682,6 +682,12 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不 ] ``` +### addToList:将本公共事件插入到快捷列表中 + +使用 `{"type": "addToList"}` 可以将当前公共事件插入到快捷商店列表中。 + +此项只能在公共事件中被执行。详见[公共事件](personalization#公共事件)。 + ### setBlock:设置某个图块 我们可以采用 `{"type": "setBlock"}` 来改变某个地图块。 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 1aa58715..c1c31050 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -240,6 +240,7 @@ action | insert_2_s | revisit_s | exit_s + | addToList_s | setBlock_s | showFloorImg_s | hideFloorImg_s @@ -693,6 +694,18 @@ var code = '{"type": "exit"},\n'; return code; */; +addToList_s + : '将本公共事件插入到快捷列表中' Newline + + +/* addToList_s +tooltip : addToList: 将本公共事件插入到快捷列表中 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=exit%EF%BC%9A%E7%AB%8B%E5%88%BB%E7%BB%93%E6%9D%9F%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6 +colour : this.eventColor +var code = '{"type": "addToList"},\n'; +return code; +*/; + setBlock_s : '转变图块为' Int 'x' PosString? ',' 'y' PosString? '楼层' IdString? Newline @@ -2604,6 +2617,10 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['exit_s'].xmlText([ this.next]); break; + case "addToList": // 立刻结束事件 + this.next = MotaActionBlocks['addToList_s'].xmlText([ + this.next]); + break; case "animateImage": // 兼容 animateImage break; default: diff --git a/_server/data.comment.js b/_server/data.comment.js index c4ad3175..8df587e1 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -660,6 +660,12 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否在经过领域/夹击/路障等伤害后禁用快捷商店。" }, + "quickCommonEvents": { + "_leaf": true, + "_type": "checkbox", + "_bool": "bool", + "_data": "是否使用自定义的公共事件列表来代替快捷商店列表。\n如果此项开启,则快捷商店列表中将会显示加入的公共事件。" + }, "checkConsole": { "_leaf": true, "_type": "checkbox", diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 9ebabaac..ee887b02 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -123,6 +123,7 @@ editor_blockly = function () { MotaActionBlocks['hideBgFgMap_s'].xmlText(), MotaActionBlocks['trigger_s'].xmlText(), MotaActionBlocks['insert_1_s'].xmlText(), + MotaActionBlocks['addToList_s'].xmlText(), MotaActionBlocks['insert_2_s'].xmlText(), MotaActionBlocks['move_s'].xmlText(), MotaActionBlocks['jump_s'].xmlText(), diff --git a/libs/actions.js b/libs/actions.js index 5ec68a78..ad1c3c1d 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1198,20 +1198,35 @@ actions.prototype._keyUpShop = function (keycode) { ////// 快捷商店界面时的点击操作 ////// actions.prototype._clickQuickShop = function (x, y) { - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { - return shopList[shopId].visited || !shopList[shopId].mustEnable - }); + var keys = []; + if (core.flags.quickCommonEvents) { + keys = core.getFlag("__commonEventList__", []); + } + else { + keys = Object.keys(core.status.shops).filter(function (shopId) { + return core.status.shops[shopId].visited || !core.status.shops[shopId].mustEnable + }); + } + if (x >= this.CHOICES_LEFT && x <= this.CHOICES_RIGHT) { var topIndex = this.HSIZE - parseInt(keys.length / 2); if (y >= topIndex && y < topIndex + keys.length) { - var reason = core.events.canUseQuickShop(keys[y - topIndex]); - if (!core.flags.enableDisabledShop && reason) { - core.drawText(reason); - return; + if (core.flags.quickCommonEvents) { + var name = keys[y - topIndex]; + core.ui.closePanel(); + core.status.route.push("common:" + core.encodeBase64(name)); + core.insertAction(name); + } + else { + var reason = core.events.canUseQuickShop(keys[y - topIndex]); + if (!core.flags.enableDisabledShop && reason) { + core.drawText(reason); + return; + } + core.events.openShop(keys[y - topIndex], true); + if (core.status.event.id == 'shop') + core.status.event.data.fromList = true; } - core.events.openShop(keys[y - topIndex], true); - if (core.status.event.id == 'shop') - core.status.event.data.fromList = true; } // 离开 else if (y == topIndex + keys.length) @@ -1225,10 +1240,17 @@ actions.prototype._keyUpQuickShop = function (keycode) { core.ui.closePanel(); return; } - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { - return shopList[shopId].visited || !shopList[shopId].mustEnable - }); - this._selectChoices(keys.length + 1, keycode, this._clickQuickShop); + var length = 0; + if (core.flags.quickCommonEvents) { + length = core.getFlag("__commonEventList__", []).length; + } + else { + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); + length = keys.length; + } + this._selectChoices(length + 1, keycode, this._clickQuickShop); return; } diff --git a/libs/control.js b/libs/control.js index d85b2cf6..b980955b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -33,6 +33,7 @@ control.prototype._init = function () { this.registerReplayAction("fly", this._replayAction_fly); this.registerReplayAction("shop", this._replayAction_shop); this.registerReplayAction("turn", this._replayAction_turn); + this.registerReplayAction("common", this._replayAction_common); this.registerReplayAction("getNext", this._replayAction_getNext); this.registerReplayAction("moveDirectly", this._replayAction_moveDirectly); this.registerReplayAction("key", this._replayAction_key); @@ -1441,6 +1442,16 @@ control.prototype._replayAction_turn = function (action) { return true; } +control.prototype._replayAction_common = function (action) { + if (action.indexOf("common:") != 0) return false; + var name = core.decodeBase64(action.substring(7)); + if (core.getFlag("__commonEventList__").indexOf(name) == -1) return false; + core.status.route.push(action); + core.insertAction(name); + setTimeout(core.replay); + return true; +} + control.prototype._replayAction_getNext = function (action) { if (action != "getNext") return false; if (!core.getNextItem()) return false; diff --git a/libs/events.js b/libs/events.js index 2751d87b..4a1be196 100644 --- a/libs/events.js +++ b/libs/events.js @@ -806,7 +806,10 @@ events.prototype.insertAction = function (action, x, y, callback, addToLast) { // ------ 判定commonEvent var commonEvent = this.getCommonEvent(action); - if (commonEvent instanceof Array) action = commonEvent; + if (commonEvent instanceof Array) { + this._addCommentEventToList(action, commonEvent); + action = commonEvent; + } if (!action) return; if (core.status.event.id != 'action') { @@ -827,6 +830,22 @@ events.prototype.getCommonEvent = function (name) { return this.commonEvent[name] || null; } +events.prototype._addCommentEventToList = function (name, list) { + if (list == null) list = this.getCommonEvent(name); + if (!list || !core.flags.quickCommonEvents) return; + var addToList = false; + for (var x in list) { + if (list[x].type == 'addToList') { + addToList = true; + break; + } + } + if (!addToList) return; + var obj = core.getFlag("__commonEventList__", []); + if (obj.indexOf(name) == -1) obj.push(name); + core.setFlag("__commonEventList__", obj); +} + ////// 恢复一个事件 ////// events.prototype.recoverEvents = function (data) { if (data) { @@ -1175,7 +1194,7 @@ events.prototype._action_insert = function (data, x, y, prefix) { } if (data.name) { // 公共事件 core.setFlag('arg0', data.name); - core.insertAction(this.getCommonEvent(data.name)); + core.insertAction(data.name); } else { var loc = this.__action_getLoc(data.loc, x, y, prefix); @@ -1188,6 +1207,10 @@ events.prototype._action_insert = function (data, x, y, prefix) { core.doAction(); } +events.prototype._action_addToList = function (data, x, y, prefix) { + core.doAction(); +} + events.prototype._action_playBgm = function (data, x, y, prefix) { core.playBgm(data.name); core.doAction(); diff --git a/libs/ui.js b/libs/ui.js index 8a569922..7529f589 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1118,12 +1118,18 @@ ui.prototype.drawSettings = function () { ////// 绘制快捷商店选择栏 ////// ui.prototype.drawQuickShop = function () { core.status.event.id = 'selectShop'; - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { - return shopList[shopId].visited || !shopList[shopId].mustEnable - }); - var choices = keys.map(function (shopId) { - return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; - }); + var choices; + if (core.flags.quickCommonEvents) { + choices = core.clone(core.getFlag("__commonEventList__", [])); + } + else { + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); + choices = keys.map(function (shopId) { + return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; + }); + } choices.push("返回游戏"); this.drawChoices(null, choices); } diff --git a/libs/utils.js b/libs/utils.js index d3bac9d3..4dbd3e34 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -467,6 +467,8 @@ utils.prototype._encodeRoute_encodeOne = function (t) { return "P" + t.substring(6); else if (t.indexOf('input2:') == 0) return "Q" + t.substring(7) + ":"; + else if (t.indexOf('common:') == 0) + return "c" + t.substring(7) + ":"; else if (t == 'no') return 'N'; else if (t.indexOf('move:') == 0) @@ -525,7 +527,7 @@ utils.prototype._decodeRoute_number2id = function (number) { } utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { - var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't') ? + var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't' || c == 'c') ? this._decodeRoute_getString(decodeObj) : this._decodeRoute_getNumber(decodeObj); var mp = {"U": "up", "D": "down", "L": "left", "R": "right"}; @@ -570,6 +572,9 @@ utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { case "Q": decodeObj.ans.push("input2:" + nxt); break; + case "c": + decodeObj.ans.push("common:" + nxt); + break; case "N": decodeObj.ans.push("no"); break; diff --git a/main.js b/main.js index a6c60bba..9d26b266 100644 --- a/main.js +++ b/main.js @@ -675,7 +675,7 @@ window.onblur = function () { if (main.core && main.core.control) { try { main.core.control.checkAutosave(); - } catch (e) {main.log(e);} + } catch (e) {} } } diff --git a/project/data.js b/project/data.js index 878a6ca0..6173ffed 100644 --- a/project/data.js +++ b/project/data.js @@ -397,6 +397,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableMoveDirectly": true, "enableDisabledShop": true, "disableShopOnDamage": false, + "quickCommonEvents": false, "checkConsole": false } } \ No newline at end of file diff --git a/project/events.js b/project/events.js index 85eb07ca..b546b4a2 100644 --- a/project/events.js +++ b/project/events.js @@ -237,6 +237,83 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = ], "false": [] } + ], + "回收钥匙商店": [ + { + "type": "comment", + "text": "公共事件:回收钥匙商店" + }, + { + "type": "addToList" + }, + { + "type": "comment", + "text": "使用上述事件并在全塔属性打开quickCommonEvent开关" + }, + { + "type": "comment", + "text": "就可以在快捷列表(V键)中使用本公共事件" + }, + { + "type": "while", + "condition": "1", + "data": [ + { + "type": "choices", + "text": "\t[商人,woman]你有多余的钥匙想要出售吗?", + "choices": [ + { + "text": "黄钥匙(10金币)", + "color": [ + 255, + 255, + 0, + 1 + ], + "action": [ + { + "type": "if", + "condition": "item:yellowKey >= 1", + "true": [ + { + "type": "addValue", + "name": "item:yellowKey", + "value": "-1" + }, + { + "type": "addValue", + "name": "status:money", + "value": "10" + } + ], + "false": [ + "\t[商人,woman]你没有黄钥匙!" + ] + } + ] + }, + { + "text": "蓝钥匙(50金币)", + "color": [ + 0, + 0, + 255, + 1 + ], + "action": [] + }, + { + "text": "离开", + "action": [ + { + "type": "exit" + } + ] + } + ] + } + ] + } ] } } \ No newline at end of file diff --git a/project/functions.js b/project/functions.js index 64e05bf8..2044fe73 100644 --- a/project/functions.js +++ b/project/functions.js @@ -699,7 +699,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = gid = guards[i][2]; // 递归计算支援怪伤害信息,这里不传x,y保证不会重复调用 // 这里的mdef传0,因为护盾应该只会被计算一次 - var info = core.enemys.getDamageInfo(core.material.enemys[gid], origin_hero_hp, origin_hero_atk, origin_hero_def, 0); + var info = core.enemys.getDamageInfo(core.material.enemys[gid], { hp: origin_hero_hp, atk: origin_hero_atk, def: origin_hero_def, mdef: 0 }); if (info == null) { // 小队中任何一个怪物不可战斗,直接返回null return null; } From e822543bf1732e0dbbf8cf1e1f35a4480820b9ad Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 20:15:43 +0800 Subject: [PATCH 116/153] prev replays --- libs/control.js | 8 ++++++-- libs/maps.js | 13 ++++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libs/control.js b/libs/control.js index b980955b..fa0eaf5a 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1302,8 +1302,12 @@ control.prototype._replay_save = function () { control.prototype._replay_error = function (action) { core.status.replay.replaying = false; - main.log("录像文件出错,当前操作:" + action + - "\n接下来10个操作是:"+core.status.replay.toReplay.slice(0, 10).toString()); + var len = core.status.replay.toReplay.length; + var prevList = core.status.replay.totalList.slice(-len - 11, -len - 1); + var nextList = core.status.replay.toReplay.slice(0, 10); + main.log("录像文件出错,当前操作:" + action); + main.log("之前的10个操作是:\n" + prevList.toString()); + main.log("接下来10个操作是:\n" + nextList.toString()); core.ui.drawConfirmBox("录像文件出错,你想回到上个节点吗?", function () { core.ui.closePanel(); if (core.status.replay.save.length > 0) { diff --git a/libs/maps.js b/libs/maps.js index f09d6b27..9d05a272 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -30,11 +30,14 @@ maps.prototype.loadFloor = function (floorId, map) { map = {"map": map}; } var content = {}; - ["floorId", "title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "cannotMoveDirectly", "color", "weather", - "defaultGround", "images", "item_ratio", "upFloor", "bgm", "downFloor", "underGround"].forEach(function (e) { - if (map[e] != null) content[e] = core.clone(map[e]); - else content[e] = core.clone(floor[e]); - }); + for (var name in floor) { + if (name != 'map' && name != 'bgmap' && name != 'fgmap' && floor[name] != null) + content[name] = core.clone(floor[name]); + } + for (var name in map) { + if (name != 'map' && name != 'bgmap' && name != 'fgmap' && map[name] != null) + content[name] = core.clone(map[name]); + } map = this.decompressMap(map.map, floorId); // 事件处理 content['blocks'] = this._mapIntoBlocks(map, floor, floorId); From 3b1c8b8a8095e673e54abc65c59c94e23dc72e5d Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 22:08:15 +0800 Subject: [PATCH 117/153] Fix animate async --- libs/actions.js | 4 ++-- libs/control.js | 23 ++++++++++------------- libs/events.js | 6 +++++- libs/maps.js | 16 ++++++---------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/libs/actions.js b/libs/actions.js index ad1c3c1d..90a42d46 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -717,7 +717,7 @@ actions.prototype._sys_keyDownCtrl = function () { } if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' && !core.status.event.data.current.noSkip) { - if (core.timeout.sleepTimeout && Object.keys(core.animateFrame.asyncId).length == 0) { + if (core.timeout.sleepTimeout && !core.hasAsync()) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.doAction(); @@ -752,7 +752,7 @@ actions.prototype._sys_longClick_lockControl = function (x, y) { // 长按可以跳过等待事件 if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' && !core.status.event.data.current.noSkip) { - if (core.timeout.sleepTimeout && Object.keys(core.animateFrame.asyncId).length == 0) { + if (core.timeout.sleepTimeout && !core.hasAsync()) { clearTimeout(core.timeout.sleepTimeout); core.timeout.sleepTimeout = null; core.doAction(); diff --git a/libs/control.js b/libs/control.js index fa0eaf5a..fce75b34 100644 --- a/libs/control.js +++ b/libs/control.js @@ -169,25 +169,22 @@ control.prototype._animationFrame_animate = function (timestamp) { if (timestamp - core.animateFrame.animateTime < 50 || !core.status.animateObjs || core.status.animateObjs.length == 0) return; core.clearMap('animate'); // 更新帧 - var animateObjs = []; - for (var i=0;i 0 || (core.status.animateObjs || []).length > 0; +} + ////// 跟随 ////// events.prototype.follow = function (name) { core.status.hero.followers = core.status.hero.followers || []; diff --git a/libs/maps.js b/libs/maps.js index 9d05a272..bc874952 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1832,18 +1832,17 @@ maps.prototype.drawAnimate = function (name, x, y, callback) { // 播放音效 core.playSound(animate.se); - var animateId = parseInt(Math.random() * 100000000); + var id = setTimeout(null); core.status.animateObjs.push({ + "id": id, "animate": animate, "centerX": centerX, "centerY": centerY, "index": 0, - "id": animateId, "callback": callback }); - core.animateFrame.asyncId[animateId] = true; - return animateId; + return id; } ////// 绘制动画的某一帧 ////// @@ -1881,7 +1880,6 @@ maps.prototype.stopAnimate = function (id, doCallback) { for (var i = 0; i < core.status.animateObjs.length; i++) { var obj = core.status.animateObjs[i]; if (obj.id == id) { - delete core.animateFrame.asyncId[obj.id]; if (doCallback) { (function (callback) { setTimeout(function () { @@ -1890,10 +1888,8 @@ maps.prototype.stopAnimate = function (id, doCallback) { })(obj.callback); } } - core.status.animateObjs.splice(i, 1); - if (core.status.animateObjs.length == 0) { - core.clearMap('animate'); - } - break; } + core.status.animateObjs = core.status.animateObjs.filter(function (x) { return x.id != id }); + if (core.status.animateObjs.length == 0) + core.clearMap('animate'); } From 6e5e8f46abd31cb18bca5eae974c47ac2c5dcf74 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 30 Mar 2019 11:13:11 -0400 Subject: [PATCH 118/153] shop_event & unknow_event --- _docs/event.md | 6 ---- _server/MotaAction.g4 | 71 ++++++++++++++++++++++++++++----------- _server/data.comment.js | 6 ---- _server/editor_blockly.js | 7 +++- project/data.js | 11 ++++++ project/events.js | 31 +++++++++++++---- 6 files changed, 93 insertions(+), 39 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 57825ba7..3beb965a 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -682,12 +682,6 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不 ] ``` -### addToList:将本公共事件插入到快捷列表中 - -使用 `{"type": "addToList"}` 可以将当前公共事件插入到快捷商店列表中。 - -此项只能在公共事件中被执行。详见[公共事件](personalization#公共事件)。 - ### setBlock:设置某个图块 我们可以采用 `{"type": "setBlock"}` 来改变某个地图块。 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index c1c31050..1fa52eba 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -65,6 +65,7 @@ return code; shoplist : shopsub + | shopcommonevent | emptyshop ; @@ -77,6 +78,24 @@ var code = ' \n'; return code; */; +shopcommonevent + : '商店 id' IdString '快捷商店栏中名称' EvalString BGNL? '未开启状态则不显示在列表中' Bool BGNL? '执行的公共事件 id' EvalString '参数列表' EvalString? + +/* shopcommonevent +tooltip : 全局商店, 执行一个公共事件 +helpUrl : https://h5mota.com/games/template/docs/#/ +default : ["shop1","回收钥匙商店",false,"回收钥匙商店",""] +var code = { + 'id': IdString_0, + 'textInList': EvalString_0, + 'mustEnable': Bool_0, + 'commonEvent': EvalString_1, + 'args': EvalString_2 +} +code=JSON.stringify(code,null,2)+',\n'; +return code; +*/; + shopsub : '商店 id' IdString '标题' EvalString '图标' IdString BGNL? Newline '快捷商店栏中名称' EvalString '共用times' Bool BGNL? Newline '未开启状态则不显示在列表中' Bool BGNL? NewLine '使用' ShopUse_List '消耗' EvalString BGNL? Newline '显示文字' EvalString BGNL? Newline shopChoices+ BEND @@ -240,7 +259,6 @@ action | insert_2_s | revisit_s | exit_s - | addToList_s | setBlock_s | showFloorImg_s | hideFloorImg_s @@ -304,6 +322,7 @@ action | callBook_s | callSave_s | callLoad_s + | unknow_s | function_s | pass_s ; @@ -694,18 +713,6 @@ var code = '{"type": "exit"},\n'; return code; */; -addToList_s - : '将本公共事件插入到快捷列表中' Newline - - -/* addToList_s -tooltip : addToList: 将本公共事件插入到快捷列表中 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=exit%EF%BC%9A%E7%AB%8B%E5%88%BB%E7%BB%93%E6%9D%9F%E5%BD%93%E5%89%8D%E4%BA%8B%E4%BB%B6 -colour : this.eventColor -var code = '{"type": "addToList"},\n'; -return code; -*/; - setBlock_s : '转变图块为' Int 'x' PosString? ',' 'y' PosString? '楼层' IdString? Newline @@ -1739,6 +1746,19 @@ var code = '{"type": "callLoad"},\n'; return code; */; +unknow_s + : '自定义事件' BGNL? RawEvalString + +/* unknow_s +tooltip : 通过脚本自定义的事件类型, 以及编辑器不识别的事件类型 +helpUrl : https://h5mota.com/games/template/docs/#/ +default : ['{"type":"eventType1"}'] +colour : this.dataColor +var tempobj={}; +eval("tempobj='"+RawEvalString_0+"'"); +var code = tempobj +',\n'; +return code; +*/; function_s : '自定义JS脚本' '不自动执行下一个事件' Bool BGNL? Newline RawEvalString Newline BEND Newline @@ -2127,10 +2147,21 @@ ActionParser.prototype.parse = function (obj,type) { obj.id,obj.name,obj.icon,obj.textInList,obj.commonTimes,obj.mustEnable,obj.use,obj.need,parser.EvalString(obj.text),text_choices,next ]); } + var buildcommentevent = function(obj,parser,next){ + return MotaActionBlocks['shopcommonevent'].xmlText([ + obj.id,parser.EvalString(obj.textInList),obj.mustEnable,parser.EvalString(obj.commonEvent),parser.EvalString(obj.args),next + ]); + } var next=null; if(!obj)obj=[]; while(obj.length){ - next=buildsub(obj.pop(),this,next); + var shopobj=obj.pop() + if(shopobj.choices) + next=buildsub(shopobj,this,next); + else if(shopobj.commonEvent) + next=buildcommentevent(shopobj,this,next); + else + throw new Error("[警告]出错啦!\n"+shopobj.id+" 无效的商店"); } return MotaActionBlocks['shop_m'].xmlText([next]); @@ -2617,14 +2648,16 @@ ActionParser.prototype.parseAction = function() { this.next = MotaActionBlocks['exit_s'].xmlText([ this.next]); break; - case "addToList": // 立刻结束事件 - this.next = MotaActionBlocks['addToList_s'].xmlText([ - this.next]); - break; case "animateImage": // 兼容 animateImage break; default: - throw new Error("[警告]出错啦!\n"+data.type+" 事件不被支持..."); + var rawdata = JSON.stringify(data,function(k,v){ + if(typeof(v)=='string')return v.split('\n').join('\\n'); + else return v; + },2); + rawdata=rawdata.split('\n').join('\\n'); + this.next = MotaActionBlocks['unknow_s'].xmlText([ + rawdata,this.next]); } this.parseAction(); return; diff --git a/_server/data.comment.js b/_server/data.comment.js index 8df587e1..c4ad3175 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -660,12 +660,6 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_bool": "bool", "_data": "是否在经过领域/夹击/路障等伤害后禁用快捷商店。" }, - "quickCommonEvents": { - "_leaf": true, - "_type": "checkbox", - "_bool": "bool", - "_data": "是否使用自定义的公共事件列表来代替快捷商店列表。\n如果此项开启,则快捷商店列表中将会显示加入的公共事件。" - }, "checkConsole": { "_leaf": true, "_type": "checkbox", diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index ee887b02..92ecfee2 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -37,6 +37,11 @@ editor_blockly = function () { {"text": "防御+4", "effect": "status:def+=4"}, {"text": "魔防+10", "effect": "status:mdef+=10"} ] + },{ + "id": "keyShop1", + "textInList": "回收钥匙商店", + "commonEvent": "回收钥匙商店", + "args": "" }],'shop'), MotaActionBlocks['afterBattle_m'].xmlText(), MotaActionBlocks['afterGetItem_m'].xmlText(), @@ -123,7 +128,6 @@ editor_blockly = function () { MotaActionBlocks['hideBgFgMap_s'].xmlText(), MotaActionBlocks['trigger_s'].xmlText(), MotaActionBlocks['insert_1_s'].xmlText(), - MotaActionBlocks['addToList_s'].xmlText(), MotaActionBlocks['insert_2_s'].xmlText(), MotaActionBlocks['move_s'].xmlText(), MotaActionBlocks['jump_s'].xmlText(), @@ -584,6 +588,7 @@ function omitedcheckUpdateFunction(event) { 'showTextImage_s': 'EvalString_0', 'function_s': 'RawEvalString_0', 'shopsub': 'EvalString_3', + 'unknow_s': 'RawEvalString_0', } var f = b ? textStringDict[b.type] : null; if (f) { diff --git a/project/data.js b/project/data.js index 6173ffed..5b612081 100644 --- a/project/data.js +++ b/project/data.js @@ -249,6 +249,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "name": "贪婪之神", "icon": "blueShop", "textInList": "1F金币商店", + "commonTimes": false, + "mustEnable": false, "use": "money", "need": "20+10*times*(times+1)", "text": "勇敢的武士啊,给我${need}金币就可以:", @@ -276,6 +278,8 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "name": "经验之神", "icon": "pinkShop", "textInList": "1F经验商店", + "commonTimes": false, + "mustEnable": false, "use": "experience", "need": "-1", "text": "勇敢的武士啊,给我若干经验就可以:", @@ -296,6 +300,13 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "effect": "status:def+=5" } ] + }, + { + "id": "keyShop1", + "textInList": "1F回收钥匙商店", + "mustEnable": false, + "commonEvent": "回收钥匙商店", + "args": "" } ], "levelUp": [ diff --git a/project/events.js b/project/events.js index b546b4a2..cfc58540 100644 --- a/project/events.js +++ b/project/events.js @@ -241,18 +241,15 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = "回收钥匙商店": [ { "type": "comment", - "text": "公共事件:回收钥匙商店" - }, - { - "type": "addToList" + "text": "此事件在全局商店中被引用了(全局商店keyShop1)" }, { "type": "comment", - "text": "使用上述事件并在全塔属性打开quickCommonEvent开关" + "text": "解除引用前勿删除此事件" }, { "type": "comment", - "text": "就可以在快捷列表(V键)中使用本公共事件" + "text": "玩家在快捷列表(V键)中可以使用本公共事件" }, { "type": "while", @@ -300,7 +297,27 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = 255, 1 ], - "action": [] + "action": [ + { + "type": "if", + "condition": "item:blueKey >= 1", + "true": [ + { + "type": "addValue", + "name": "item:blueKey", + "value": "-1" + }, + { + "type": "addValue", + "name": "status:money", + "value": "50" + } + ], + "false": [ + "\t[商人,woman]你没有蓝钥匙!" + ] + } + ] }, { "text": "离开", From 48c1555e30a528010ff0f355fef211e9e769b38d Mon Sep 17 00:00:00 2001 From: oc Date: Sat, 30 Mar 2019 23:27:45 +0800 Subject: [PATCH 119/153] Add docs --- _docs/_sidebar.md | 1 - _docs/element.md | 91 +++++++++++------------------------------ _docs/img/keyboard.png | Bin 0 -> 54598 bytes _docs/index.md | 3 +- _docs/start.md | 19 ++++++++- 5 files changed, 43 insertions(+), 71 deletions(-) create mode 100644 _docs/img/keyboard.png diff --git a/_docs/_sidebar.md b/_docs/_sidebar.md index a7960592..039c2ea0 100644 --- a/_docs/_sidebar.md +++ b/_docs/_sidebar.md @@ -3,5 +3,4 @@ - [元件说明](element) - [事件](event) - [个性化](personalization) -- [V2.0版本介绍](V2.0) - [附录:API列表](api) diff --git a/_docs/element.md b/_docs/element.md index 8d352fef..4fed9b92 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -1,6 +1,6 @@ # 元件说明 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * 在本章中,将对样板里的各个元件进行说明。各个元件主要包括道具、门、怪物、楼梯等等。 @@ -56,6 +56,8 @@ type为该装备的类型,必填,和上面装备栏一一对应。例如,0 atk/def/mdef为该装备分别增加的攻防魔防数值(支持负数);如果不加也可省略不写。 +从V2.6开始,可以拓展到任何勇士的属性,如hpmax, atk, def, mdef, experience等等;自行添加的属性包括攻速speed也能使用。 + animate为该装备的攻击动画,仅对type为0时有效。具体可参见[动画和天气系统](#动画和天气系统)。 percentage为该装备是否按比例增加属性。 @@ -151,49 +153,13 @@ yellowWall, blueWall, whiteWall 怪物的特殊属性所对应的数字(special)在脚本编辑中的`getSpecials`中定义,请勿对已有的属性进行修改。 -``` js -function() { - // 获得怪物的特殊属性,每一行定义一个特殊属性。 - // 分为三项,第一项为该特殊属性的数字,第二项为特殊属性的名字,第三项为特殊属性的描述 - // 可以直接写字符串,也可以写个function将怪物传进去 - return [ - [1, "先攻", "怪物首先攻击"], - [2, "魔攻", "怪物无视勇士的防御"], - [3, "坚固", "勇士每回合最多只能对怪物造成1点伤害"], - [4, "2连击", "怪物每回合攻击2次"], - [5, "3连击", "怪物每回合攻击3次"], - [6, function(enemy) {return (enemy.n||4)+"连击";}, function(enemy) {return "怪物每回合攻击"+(enemy.n||4)+"次";}], - [7, "破甲", "战斗前,怪物附加角色防御的"+Math.floor(100*core.values.breakArmor||0)+"%作为伤害"], - [8, "反击", "战斗时,怪物每回合附加角色攻击的"+Math.floor(100*core.values.counterAttack||0)+"%作为伤害,无视角色防御"], - [9, "净化", "战斗前,怪物附加勇士魔防的"+core.values.purify+"倍作为伤害"], - [10, "模仿", "怪物的攻防和勇士攻防相等"], - [11, "吸血", function (enemy) {return "战斗前,怪物首先吸取角色的"+Math.floor(100*enemy.value||0)+"%生命作为伤害"+(enemy.add?",并把伤害数值加到自身生命上":"");}], - [12, "中毒", "战斗后,勇士陷入中毒状态,每一步损失生命"+core.values.poisonDamage+"点"], - [13, "衰弱", "战斗后,勇士陷入衰弱状态,攻防暂时下降"+(core.values.weakValue>=1?core.values.weakValue+"点":parseInt(core.values.weakValue*100)+"%")], - [14, "诅咒", "战斗后,勇士陷入诅咒状态,战斗无法获得金币和经验"], - [15, "领域", function (enemy) {return "经过怪物周围"+(enemy.range||1)+"格时自动减生命"+(enemy.value||0)+"点";}], - [16, "夹击", "经过两只相同的怪物中间,勇士生命值变成一半"], - [17, "仇恨", "战斗前,怪物附加之前积累的仇恨值作为伤害"+(core.flags.hatredDecrease?";战斗后,释放一半的仇恨值":"")+"。(每杀死一个怪物获得"+(core.values.hatred||0)+"点仇恨值)"], - [18, "阻击", function (enemy) {return "经过怪物的十字领域时自动减生命"+(enemy.value||0)+"点,同时怪物后退一格";}], - [19, "自爆", "战斗后勇士的生命值变成1"], - [20, "无敌", "勇士无法打败怪物,除非拥有十字架"], - [21, "退化", function (enemy) {return "战斗后勇士永久下降"+(enemy.atkValue||0)+"点攻击和"+(enemy.defValue||0)+"点防御";}], - [22, "固伤", function (enemy) {return "战斗前,怪物对勇士造成"+(enemy.damage||0)+"点固定伤害,无视勇士魔防。";}], - [23, "重生", "怪物被击败后,角色转换楼层则怪物将再次出现"], - [24, "激光", function (enemy) {return "经过怪物同行或同列时自动减生命"+(enemy.value||0)+"点";}] - ]; -} -``` - 多属性可采用数组的写法,比如`'special': [1,3]`视为同时拥有先攻和坚固属性;`'special': [5,10,14,18]`视为拥有3连击、魔防、诅咒、阻击四个属性。 -怪物可以负伤,在`data.js`的全局变量`enableNegativeDamage`中指定。 - -下面的`getSpecialHint`函数则给定了每个特殊属性的详细描述。这个描述将在怪物手册中看到。 +怪物可以负伤,在全塔属性的全局变量`enableNegativeDamage`中指定。 打败怪物后可以进行加点操作。有关加点塔的制作可参见[加点事件](event#加点事件)。 -如果`data.js`中的enableExperience为false,即不启用经验的话,怪物手册里将不显示怪物的经验值,打败怪物也不获得任何经验。 +如果全塔属性中的enableExperience为false,即不启用经验的话,怪物手册里将不显示怪物的经验值,打败怪物也不获得任何经验。 拿到幸运金币后,打怪获得的金币将翻倍。 @@ -286,16 +252,12 @@ N连击怪物的special是6,且我们可以为它定义n代表实际连击数 ## 路障,楼梯,传送门 -血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在 `data.js` 的values内定义。 +血网的伤害数值、中毒后每步伤害数值、衰弱时暂时攻防下降的数值,都在全塔属性的values内定义。 路障同样会尽量被自动寻路绕过。 有关楼梯和传送门,必须在该层样板的changeFloor里指定传送点的目标。 -![楼层转换](./img/changefloor.png) - -!> **请注意这里的`"x,y"`代表该点的横坐标为x,纵坐标为y;即从左到右第x列,从上到下的第y行(从0开始计算)。如(6,0)代表最上面一行的正中间一列。** - floorId指定的是目标楼层的唯一标识符(ID)。 也可以写`"floorId": ":before"`和`"floorId": ":next"`表示上一楼和下一楼。 @@ -347,7 +309,7 @@ floorId指定的是目标楼层的唯一标识符(ID)。 从V2.4开始,H5魔塔开始支持大地图。 -大地图在创建时可以指定宽高,要求**宽和高都不得小于13,且宽高之积不超过1000**。 +大地图在创建时可以指定宽高,要求**宽和高都不得小于13(15x15版本则是不小于15),且宽高之积不超过1000**。 大地图一旦创建成功则不得修改宽高数值。 @@ -355,13 +317,12 @@ floorId指定的是目标楼层的唯一标识符(ID)。 现在我们的H5魔塔支持播放动画,也支持天气系统了。 -要播放动画,你需要先使用“RM动画导出器”将动画导出,放在animates目录下,然后再data.js中定义。 +要播放动画,你需要先使用“RM动画导出器”将动画导出,放在animates目录下,然后在全塔属性的animates中定义。 ``` js -"animates": [// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 - // 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 - "hand", "sword", "zone", "yongchang", "thunder" // 根据需求自行添加 -] +// 在此存放所有可能使用的动画,必须是animate格式,在这里不写后缀名 +// 动画必须放在animates目录下;文件名不能使用中文,不能带空格或特殊字符 +"animates": ["hand", "sword", "zone", "yongchang", "thunder"] ``` !> 动画必须是animate格式,名称不能使用中文,不能带空格或特殊字符。 @@ -376,9 +337,9 @@ floorId指定的是目标楼层的唯一标识符(ID)。 !> 播放录像时,将默认忽略所有动画。 -目前天气系统只支持雨和雪两种天气。 +目前天气系统支持雨和雪和雾两种天气。 -在每层楼的剧本文件里存在一个weather选项,表示该层楼的默认天气。 +在每层楼的楼层属性中存在一个weather选项,表示该层楼的默认天气。 ``` js // 该层的默认天气。本项可忽略表示晴天,如果写则第一项为"rain","snow"或"fog"代表雨雪雾,第二项为1-10之间的数代表强度。 @@ -394,24 +355,18 @@ floorId指定的是目标楼层的唯一标识符(ID)。 要播放音乐和音效,你需要将对应的文件放在sounds目录下,然后在全塔属性中进行定义 ``` js -"bgms": [ // 在此存放所有的bgm,和文件名一致。 - // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - 'bgm.mp3' -]; -"sounds": [ // 在此存放所有的SE,和文件名一致 - // 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 - 'floor.mp3', 'attack.mp3', 'door.mp3', 'item.mp3', 'zone.mp3' -] +// 在此存放所有的bgm,和文件名一致。 +// 音频名不能使用中文,不能带空格或特殊字符;可以直接改名拼音就好 +"bgms": ["bgm.mp3"] + +// 在此存放所有的SE,和文件名一致 +"sounds": ["floor.mp3", "attack.mp3", "door.mp3", "item.mp3", "zone.mp3"] ``` !> 音频名不能使用中文,不能带空格或特殊字符。 -目前BGM支持主流的音乐格式,如mp3, ogg,格式等。不支持mid格式的播放。 - 定义完毕后,我们可以调用`playBgm`/`playSound`事件来播放对应的音乐/音效,有关事件的详细介绍请参见[事件](event)。 **另外,考虑到用户的流量问题,将遵循如下规则:** @@ -443,7 +398,7 @@ HTML5魔塔一大亮点就是存在录像系统,可以很方便进行录像回 录像的回放主要有两种方式: 1. 保存成的录像文件(.h5route文件):在标题界面点录像回放,再选择文件即可。 -2. 游戏过程中时的当前录像:随时按R可以进行回放;手机端则长按任何位置3秒以上调出虚拟键盘,再按R。 +2. 游戏过程中时的当前录像:随时按R可以进行回放;手机端则可调出虚拟键盘,再按R。 录像播放过程中,可以进行如下操作: @@ -474,6 +429,9 @@ HTML5魔塔一大亮点就是存在录像系统,可以很方便进行录像回 ## 操作说明 +![](img/keyboard.png) + +   diff --git a/_docs/img/keyboard.png b/_docs/img/keyboard.png new file mode 100644 index 0000000000000000000000000000000000000000..c2b9d2412fab08efa3397e4e09b7bdcdc915f79e GIT binary patch literal 54598 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 a==ki|Rk||P`-|>BC+o7c1Ej^$FY!OF+#~-0 literal 0 HcmV?d00001 diff --git a/_docs/index.md b/_docs/index.md index cb6a896c..d2f290e2 100644 --- a/_docs/index.md +++ b/_docs/index.md @@ -1,11 +1,10 @@ # HTML5 魔塔样板说明文档 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * 众所周知,魔塔的趋势是向移动端发展,贴吧中也常常能见到“求手机魔塔”的帖子。然而现有的工具中,NekoRPG有着比较大的局限性,游戏感较差,更是完全没法在iOS上运行。而一些APP的魔塔虽然可用,但是必须要下载安装,对于Android和iOS还必须开发不同的版本,非常麻烦。 但是,现在我们有了HTML5。 HTML5的画布(canvas)以及它被Android/iOS内置浏览器所支持的特性,可以让我们做出真正意义上的全平台覆盖的魔塔。 -事实上,在贴吧的试水发布也证明了,H5魔塔确实是可以成功的。两部即使是复刻的魔塔也受到了不少人的追捧,其流畅的手感和全平台支持的特性,也让很多没办法打开电脑的人爱不释手。 然而,一般而言使用非RMXP制作魔塔往往需要一定的编程技术,HTML5魔塔自然也不例外。但是,为了能让大家更加注重于“做塔”本身,而不用考虑做塔以外的各种脚本问题,我特意制作了这样一部HTML5的魔塔样板。 diff --git a/_docs/start.md b/_docs/start.md index a68ac244..004ea21f 100644 --- a/_docs/start.md +++ b/_docs/start.md @@ -1,6 +1,6 @@ # 快速上手 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * 在这一节中,将详细介绍做一部塔的流程。现在,让我们来做一部单层塔! @@ -28,6 +28,7 @@ * “地图编辑器”允许你以可视化的方式进行编辑地图。 * “便捷PS工具”能让你很方便的对自定义素材进行添加。参见[自定义素材](personalization#自定义素材)。 * “地图生成器”能让你从已有的截图(如RMXP项目)中立刻生成可被本样板识别的地图数据。 +* “怪物数据导出”能让你从RMXP中导出怪物数据而被H5魔塔使用。 * “RM动画导出器”能让你从RMXP中导出动画而被H5魔塔使用。 * “JS代码压缩工具”能对JS代码进行压缩,从而减少IO请求数和文件大小。 * “伤害和临界值计算器”是一个很便捷的小工具,能对怪物的伤害和临界值进行计算。 @@ -54,6 +55,8 @@ ### 从RMXP导入已有的地图 +!> 注:现在已经不推荐此方法,如需从RM刻塔请使用 [RM转H5刻塔器使用教程](https://www.bilibili.com/video/av43125840) 进行操作。 + 如果我们想复刻一个现有的,已经被RMXP所制作的塔,也有很便捷的方式,那就是用到我们的“地图生成器”。 首先,我们打开RMXP和对应的项目,可以看到它的地图。 @@ -176,7 +179,7 @@ 之后刷新编辑器即可。 -对于怪物和道具,我们也可以进行自动注册,只需要点击“自动注册”按钮,将对该栏下所有未注册的素材进行自动注册(自动分配ID和数字)。 +也可以进行自动注册,只需要点击“自动注册”按钮,将对该栏下所有未注册的素材进行自动注册(自动分配ID和数字)。 素材注册完毕后,即可在游戏中正常使用,也可以被地图生成器所识别(需要重开地图生成器)。 @@ -230,6 +233,18 @@ HTML5的塔都是可以进行控制台调试的。 更多API和详细参数介绍可参见[API列表](api)。 +## 编辑器的基本操作 + +- **Alt+0~9, Ctrl+0~9** 保存和读取当前选中图块 +- **W/A/S/D** 移动大地图 +- **Ctrl+Z** 撤销上次绘图 +- **Ctrl+Y** 重做上次绘图 +- **PgUp/PgDn** 切换楼层 +- **Ctrl+S** 保存事件编辑器/脚本编辑器 +- **地图上单击** 选中该点 +- **地图上双击** 选中该点图块 +- **地图上右键** 弹出菜单栏,包括选中、复制、清除等操作 +- **事件编辑器中Ctrl+C, Ctrl+X, 右键等** 执行相应操作 ## 报错处理 From 8aca0760c090536d05dbf924840e65bcd2e1b67d Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 00:22:26 +0800 Subject: [PATCH 120/153] commonEventShop --- _server/MotaAction.g4 | 48 ++++++++++++++++++++++++-------------- _server/editor_blockly.js | 1 + libs/actions.js | 49 +++++++++++---------------------------- libs/control.js | 17 +++++--------- libs/events.js | 49 +++++++++++++-------------------------- libs/ui.js | 18 +++++--------- libs/utils.js | 7 +----- project/data.js | 6 ++--- 8 files changed, 77 insertions(+), 118 deletions(-) diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 1fa52eba..bb3e0f44 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -85,13 +85,25 @@ shopcommonevent tooltip : 全局商店, 执行一个公共事件 helpUrl : https://h5mota.com/games/template/docs/#/ default : ["shop1","回收钥匙商店",false,"回收钥匙商店",""] +if (EvalString_2) { + if (EvalString_2.indexOf('"')>=0) + throw new Error('请勿在此处使用双引号!尝试使用单引号吧~'); + // 检查是不是数组 + try { + EvalString_2 = JSON.parse(EvalString_2.replace(/'/g, '"')); + if (!(EvalString_2 instanceof Array)) throw new Error(); + } + catch (e) { + throw new Error('参数列表必须是个有效的数组!'); + } +} var code = { 'id': IdString_0, 'textInList': EvalString_0, 'mustEnable': Bool_0, - 'commonEvent': EvalString_1, - 'args': EvalString_2 + 'commonEvent': EvalString_1 } +if (EvalString_2) code.args = EvalString_2; code=JSON.stringify(code,null,2)+',\n'; return code; */; @@ -322,7 +334,7 @@ action | callBook_s | callSave_s | callLoad_s - | unknow_s + | unknown_s | function_s | pass_s ; @@ -1746,17 +1758,19 @@ var code = '{"type": "callLoad"},\n'; return code; */; -unknow_s +unknown_s : '自定义事件' BGNL? RawEvalString -/* unknow_s +/* unknown_s tooltip : 通过脚本自定义的事件类型, 以及编辑器不识别的事件类型 helpUrl : https://h5mota.com/games/template/docs/#/ -default : ['{"type":"eventType1"}'] +default : ['{"type":"test", "data": "这是自定义的参数"}'] colour : this.dataColor -var tempobj={}; -eval("tempobj='"+RawEvalString_0+"'"); -var code = tempobj +',\n'; +try { + var tempobj = JSON.parse(RawEvalString_0); +} catch (e) {throw new Error("不合法的JSON格式!");} +if (!tempobj.type) throw new Error("自定义事件需要一个type:xxx"); +var code = JSON.stringify(tempobj) +',\n'; return code; */; @@ -2148,8 +2162,13 @@ ActionParser.prototype.parse = function (obj,type) { ]); } var buildcommentevent = function(obj,parser,next){ + if (obj.args instanceof Array) { + try { obj.args = JSON.stringify(obj.args).replace(/"/g, "'"); } + catch (e) {obj.args = '';} + } + else obj.args = null; return MotaActionBlocks['shopcommonevent'].xmlText([ - obj.id,parser.EvalString(obj.textInList),obj.mustEnable,parser.EvalString(obj.commonEvent),parser.EvalString(obj.args),next + obj.id,parser.EvalString(obj.textInList),obj.mustEnable,parser.EvalString(obj.commonEvent),obj.args,next ]); } var next=null; @@ -2651,13 +2670,8 @@ ActionParser.prototype.parseAction = function() { case "animateImage": // 兼容 animateImage break; default: - var rawdata = JSON.stringify(data,function(k,v){ - if(typeof(v)=='string')return v.split('\n').join('\\n'); - else return v; - },2); - rawdata=rawdata.split('\n').join('\\n'); - this.next = MotaActionBlocks['unknow_s'].xmlText([ - rawdata,this.next]); + this.next = MotaActionBlocks['unknown_s'].xmlText([ + JSON.stringify(data),this.next]); } this.parseAction(); return; diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 92ecfee2..5aca5463 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -159,6 +159,7 @@ editor_blockly = function () { ], '原生脚本':[ MotaActionBlocks['function_s'].xmlText(), + MotaActionBlocks['unknown_s'].xmlText(), ], '值块':[ MotaActionBlocks['setValue_s'].xmlText([ diff --git a/libs/actions.js b/libs/actions.js index 90a42d46..917af40f 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1198,35 +1198,21 @@ actions.prototype._keyUpShop = function (keycode) { ////// 快捷商店界面时的点击操作 ////// actions.prototype._clickQuickShop = function (x, y) { - var keys = []; - if (core.flags.quickCommonEvents) { - keys = core.getFlag("__commonEventList__", []); - } - else { - keys = Object.keys(core.status.shops).filter(function (shopId) { - return core.status.shops[shopId].visited || !core.status.shops[shopId].mustEnable - }); - } + var keys = Object.keys(core.status.shops).filter(function (shopId) { + return core.status.shops[shopId].visited || !core.status.shops[shopId].mustEnable + }); if (x >= this.CHOICES_LEFT && x <= this.CHOICES_RIGHT) { var topIndex = this.HSIZE - parseInt(keys.length / 2); if (y >= topIndex && y < topIndex + keys.length) { - if (core.flags.quickCommonEvents) { - var name = keys[y - topIndex]; - core.ui.closePanel(); - core.status.route.push("common:" + core.encodeBase64(name)); - core.insertAction(name); - } - else { - var reason = core.events.canUseQuickShop(keys[y - topIndex]); - if (!core.flags.enableDisabledShop && reason) { - core.drawText(reason); - return; - } - core.events.openShop(keys[y - topIndex], true); - if (core.status.event.id == 'shop') - core.status.event.data.fromList = true; + var reason = core.events.canUseQuickShop(keys[y - topIndex]); + if (!core.flags.enableDisabledShop && reason) { + core.drawText(reason); + return; } + core.events.openShop(keys[y - topIndex], true); + if (core.status.event.id == 'shop') + core.status.event.data.fromList = true; } // 离开 else if (y == topIndex + keys.length) @@ -1240,17 +1226,10 @@ actions.prototype._keyUpQuickShop = function (keycode) { core.ui.closePanel(); return; } - var length = 0; - if (core.flags.quickCommonEvents) { - length = core.getFlag("__commonEventList__", []).length; - } - else { - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { - return shopList[shopId].visited || !shopList[shopId].mustEnable - }); - length = keys.length; - } - this._selectChoices(length + 1, keycode, this._clickQuickShop); + var keys = Object.keys(core.status.shops).filter(function (shopId) { + return core.status.shops[shopId].visited || !core.status.shops[shopId].mustEnable + }); + this._selectChoices(keys.length + 1, keycode, this._clickQuickShop); return; } diff --git a/libs/control.js b/libs/control.js index fce75b34..7a1de28b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -33,7 +33,6 @@ control.prototype._init = function () { this.registerReplayAction("fly", this._replayAction_fly); this.registerReplayAction("shop", this._replayAction_shop); this.registerReplayAction("turn", this._replayAction_turn); - this.registerReplayAction("common", this._replayAction_common); this.registerReplayAction("getNext", this._replayAction_getNext); this.registerReplayAction("moveDirectly", this._replayAction_moveDirectly); this.registerReplayAction("key", this._replayAction_key); @@ -1412,6 +1411,12 @@ control.prototype._replayAction_shop = function (action) { if (selections.length == 0) return false; var shop=core.status.shops[shopId]; if (!shop || !shop.visited) return false; + // --- 判定commonEvent + if (shop.commonEvent) { + core.openShop(shopId, false); + setTimeout(core.replay); + return true; + } var choices = shop.choices; var topIndex = core.__HALF_SIZE__ - parseInt(choices.length / 2); core.status.event.selection = parseInt(selections.shift()); @@ -1443,16 +1448,6 @@ control.prototype._replayAction_turn = function (action) { return true; } -control.prototype._replayAction_common = function (action) { - if (action.indexOf("common:") != 0) return false; - var name = core.decodeBase64(action.substring(7)); - if (core.getFlag("__commonEventList__").indexOf(name) == -1) return false; - core.status.route.push(action); - core.insertAction(name); - setTimeout(core.replay); - return true; -} - control.prototype._replayAction_getNext = function (action) { if (action != "getNext") return false; if (!core.getNextItem()) return false; diff --git a/libs/events.js b/libs/events.js index 0c60d6aa..768cc35d 100644 --- a/libs/events.js +++ b/libs/events.js @@ -806,10 +806,7 @@ events.prototype.insertAction = function (action, x, y, callback, addToLast) { // ------ 判定commonEvent var commonEvent = this.getCommonEvent(action); - if (commonEvent instanceof Array) { - this._addCommentEventToList(action, commonEvent); - action = commonEvent; - } + if (commonEvent instanceof Array) action = commonEvent; if (!action) return; if (core.status.event.id != 'action') { @@ -830,22 +827,6 @@ events.prototype.getCommonEvent = function (name) { return this.commonEvent[name] || null; } -events.prototype._addCommentEventToList = function (name, list) { - if (list == null) list = this.getCommonEvent(name); - if (!list || !core.flags.quickCommonEvents) return; - var addToList = false; - for (var x in list) { - if (list[x].type == 'addToList') { - addToList = true; - break; - } - } - if (!addToList) return; - var obj = core.getFlag("__commonEventList__", []); - if (obj.indexOf(name) == -1) obj.push(name); - core.setFlag("__commonEventList__", obj); -} - ////// 恢复一个事件 ////// events.prototype.recoverEvents = function (data) { if (data) { @@ -1144,13 +1125,12 @@ events.prototype._action_useItem = function (data, x, y, prefix) { } events.prototype._action_openShop = function (data, x, y, prefix) { - if (core.isReplaying()) { // 正在播放录像,简单将visited置为true - core.status.shops[data.id].visited = true; - this.setEvents([]); - core.doAction(); - } - else + core.status.shops[data.id].visited = true; + this.setEvents([]); + if (!core.isReplaying()) this.openShop(data.id); + if (core.status.event.id == 'action') + core.doAction(); } events.prototype._action_disableShop = function (data, x, y, prefix) { @@ -1207,10 +1187,6 @@ events.prototype._action_insert = function (data, x, y, prefix) { core.doAction(); } -events.prototype._action_addToList = function (data, x, y, prefix) { - core.doAction(); -} - events.prototype._action_playBgm = function (data, x, y, prefix) { core.playBgm(data.name); core.doAction(); @@ -2109,9 +2085,9 @@ events.prototype.openShop = function (shopId, needVisited) { shop.times = shop.times || 0; if (shop.commonTimes) shop.times = core.getFlag('commonTimes', 0); if (needVisited && !shop.visited) { - if (!core.flags.enableDisabledShop) { - if (shop.times == 0) core.drawTip("该商店尚未开启"); - else core.drawTip("该商店已失效"); + if (!core.flags.enableDisabledShop || shop.commonEvent) { + if (shop.times == 0) core.drawTip("该项尚未开启"); + else core.drawTip("该项已失效"); return; } else { @@ -2119,6 +2095,13 @@ events.prototype.openShop = function (shopId, needVisited) { } } else shop.visited = true; + + // --- 商店 + if (shop.commonEvent) { + core.status.route.push("shop:"+shopId+":0"); + core.insertAction({"type": "insert", "name": shop.commonEvent, "args": shop.args}); + return; + } core.ui.drawShop(shopId); } diff --git a/libs/ui.js b/libs/ui.js index 7529f589..8a569922 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1118,18 +1118,12 @@ ui.prototype.drawSettings = function () { ////// 绘制快捷商店选择栏 ////// ui.prototype.drawQuickShop = function () { core.status.event.id = 'selectShop'; - var choices; - if (core.flags.quickCommonEvents) { - choices = core.clone(core.getFlag("__commonEventList__", [])); - } - else { - var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { - return shopList[shopId].visited || !shopList[shopId].mustEnable - }); - choices = keys.map(function (shopId) { - return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; - }); - } + var shopList = core.status.shops, keys = Object.keys(shopList).filter(function (shopId) { + return shopList[shopId].visited || !shopList[shopId].mustEnable + }); + var choices = keys.map(function (shopId) { + return {"text": shopList[shopId].textInList, "color": shopList[shopId].visited?null:"#999999"}; + }); choices.push("返回游戏"); this.drawChoices(null, choices); } diff --git a/libs/utils.js b/libs/utils.js index 4dbd3e34..d3bac9d3 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -467,8 +467,6 @@ utils.prototype._encodeRoute_encodeOne = function (t) { return "P" + t.substring(6); else if (t.indexOf('input2:') == 0) return "Q" + t.substring(7) + ":"; - else if (t.indexOf('common:') == 0) - return "c" + t.substring(7) + ":"; else if (t == 'no') return 'N'; else if (t.indexOf('move:') == 0) @@ -527,7 +525,7 @@ utils.prototype._decodeRoute_number2id = function (number) { } utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { - var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't' || c == 'c') ? + var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't') ? this._decodeRoute_getString(decodeObj) : this._decodeRoute_getNumber(decodeObj); var mp = {"U": "up", "D": "down", "L": "left", "R": "right"}; @@ -572,9 +570,6 @@ utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { case "Q": decodeObj.ans.push("input2:" + nxt); break; - case "c": - decodeObj.ans.push("common:" + nxt); - break; case "N": decodeObj.ans.push("no"); break; diff --git a/project/data.js b/project/data.js index 5b612081..096e2dc6 100644 --- a/project/data.js +++ b/project/data.js @@ -303,10 +303,9 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = }, { "id": "keyShop1", - "textInList": "1F回收钥匙商店", + "textInList": "回收钥匙商店", "mustEnable": false, - "commonEvent": "回收钥匙商店", - "args": "" + "commonEvent": "回收钥匙商店" } ], "levelUp": [ @@ -408,7 +407,6 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "enableMoveDirectly": true, "enableDisabledShop": true, "disableShopOnDamage": false, - "quickCommonEvents": false, "checkConsole": false } } \ No newline at end of file From b3fb8cf98a71f075962431b348323522411c25ff Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 00:35:35 +0800 Subject: [PATCH 121/153] remove double click unknow_s --- _server/editor_blockly.js | 1 - 1 file changed, 1 deletion(-) diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 5aca5463..595a55ff 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -589,7 +589,6 @@ function omitedcheckUpdateFunction(event) { 'showTextImage_s': 'EvalString_0', 'function_s': 'RawEvalString_0', 'shopsub': 'EvalString_3', - 'unknow_s': 'RawEvalString_0', } var f = b ? textStringDict[b.type] : null; if (f) { From 05f6b37121e67ae9ab9c9b3cf871ca463d2376fb Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 30 Mar 2019 12:38:56 -0400 Subject: [PATCH 122/153] update refactoring.md --- _server/refactoring.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_server/refactoring.md b/_server/refactoring.md index 0dd94dd4..9ae0e115 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -46,6 +46,10 @@ editor: { 某些注意到的点 ++ 插入公共事件的参数的转义处理 + ++ 转义改由editor.blockly处理,editor.multi原样接受和返回 + + 地图的编辑与其他(如全塔属性和楼层属性), 现在的文件操作的模式是完全不同的 楼层文件的储存与其他不同 @@ -62,7 +66,7 @@ editor: { + [ ] ? 表格折叠 变为四栏, 可以折叠展开 -+ [ ] blockly对于无法识别的图块原样返回 ++ [x] blockly对于无法识别的图块原样返回 + [ ] ? 简洁的事件方块注册 `editor.registerEvent('log',[['test','Int','测试',0],['floorId','Idstring','楼层','MT0']])` From 52abd1274025e4ff75f812afcb4232023b1d7505 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 30 Mar 2019 12:54:34 -0400 Subject: [PATCH 123/153] update refactoring.md --- _server/refactoring.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_server/refactoring.md b/_server/refactoring.md index 9ae0e115..90ae5681 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -59,6 +59,8 @@ editor: { ## 功能改进 ++ [ ] .g4中添加ObjectString, 要求其中的值可以JSON.parse, 生成的code中也是作为对象而不是字符串出现 + + [ ] 大地图 在切换时, 每次都回到最左上->每个楼层记录一个位置 四个箭头目前不能长按 From fa5fa402407400b83a4e0c9bd3bfc94a79424caf Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 01:01:13 +0800 Subject: [PATCH 124/153] loadFloor --- libs/maps.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libs/maps.js b/libs/maps.js index bc874952..445fc113 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -30,12 +30,14 @@ 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"]; for (var name in floor) { - if (name != 'map' && name != 'bgmap' && name != 'fgmap' && floor[name] != null) + if (notCopy.indexOf(name) == -1 && floor[name] != null) content[name] = core.clone(floor[name]); } for (var name in map) { - if (name != 'map' && name != 'bgmap' && name != 'fgmap' && map[name] != null) + if (notCopy.indexOf(name) == -1 && map[name] != null) content[name] = core.clone(map[name]); } map = this.decompressMap(map.map, floorId); From 11fe36a44edbb8dfbbfd5dd3e5e5babef6b8f54e Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 30 Mar 2019 19:25:57 -0400 Subject: [PATCH 125/153] editor_game --- _server/editor.js | 119 ++------------------------------------- _server/editor_game.js | 124 +++++++++++++++++++++++++++++++++++++++++ editor-mobile.html | 1 + editor.html | 1 + 4 files changed, 131 insertions(+), 114 deletions(-) create mode 100644 _server/editor_game.js diff --git a/_server/editor.js b/_server/editor.js index 03b0cf01..3d50fa1f 100644 --- a/_server/editor.js +++ b/_server/editor.js @@ -43,24 +43,11 @@ editor.info editor.prototype.init = function (callback) { editor_util_wrapper(editor); + editor_game_wrapper(editor, main, core); editor_table_wrapper(editor); var afterMainInit = function () { - core.floors = JSON.parse(JSON.stringify(core.floors, function (k, v) { - if (v instanceof Function) { - return v.toString() - } else return v - })); - core.data = JSON.parse(JSON.stringify(core.data, function (k, v) { - if (v instanceof Function) { - return v.toString() - } else return v - })); - data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = JSON.parse(JSON.stringify(data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d, function (k, v) { - if (v instanceof Function) { - return v.toString() - } else return v - })); + editor.game.fixFunctionInGameData(); editor.main = main; editor.core = core; editor.fs = fs; @@ -78,10 +65,10 @@ editor.prototype.init = function (callback) { var afterCoreReset = function () { - editor.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 + editor.game.idsInit(core.maps, core.icons.icons); // 初始化图片素材信息 editor.drawInitData(core.icons.icons); // 初始化绘图 - editor.fetchMapFromCore(); + editor.game.fetchMapFromCore(); editor.updateMap(); editor.buildMark(); editor.drawEventBlock(); @@ -105,69 +92,6 @@ editor.prototype.init = function (callback) { afterMainInit(); } -editor.prototype.idsInit = function (maps, icons) { - editor.ids = [0]; - editor.indexs = []; - var MAX_NUM = 0; - var keys=Object.keys(maps_90f36752_8815_4be8_b32b_d7fad1d0542e); - for(var ii=0;iiMAX_NUM && v 32*32*3000){ - alert(imgName+'上的图块数量超过了3000,请修改后刷新页面'); - } - for (var id=startOffset; idMAX_NUM && v 32*32*3000){ + alert(imgName+'上的图块数量超过了3000,请修改后刷新页面'); + } + for (var id=startOffset; id + diff --git a/editor.html b/editor.html index 8f826432..0b5c4187 100644 --- a/editor.html +++ b/editor.html @@ -510,6 +510,7 @@ if (location.protocol.indexOf("http")!=0) { + From cfd3058b7e6ba46decc7b563873f00fa976b7d23 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sat, 30 Mar 2019 19:35:10 -0400 Subject: [PATCH 126/153] update refactoring.md --- _server/refactoring.md | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/_server/refactoring.md b/_server/refactoring.md index 90ae5681..695e71ad 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -1,12 +1,11 @@ # 重构 -+ [ ] 按功能拆分文件 -+ [ ] 左侧页面模块化, 方便添加 -+ [ ] 不同的模式的文件操作尽可能模块化 ++ 按功能拆分文件 ++ 左侧页面模块化, 方便添加 ++ 不同的模式的文件操作尽可能模块化 ---- -文件结构 +## 文件结构 + [x] editor_blockly 图块化事件编辑器, 基本不改动 + [x] editor_multi 多行文本编辑器, 基本不改动 @@ -18,9 +17,8 @@ + [ ] 原editor_mode 移除 + [ ] 原vm 移除 ---- -+ [ ] 对象结构 +## 对象结构 ``` editor: { @@ -31,8 +29,8 @@ editor: { table multi blockly + game } - game: 来自游戏的数据 config: 编辑器配置 mode: 当前的模式(左侧的选择) map: 当前编辑层的地图 @@ -44,9 +42,9 @@ editor: { --- -某些注意到的点 +## 某些注意到的点&准备修改的内容 -+ 插入公共事件的参数的转义处理 ++ 插入公共事件的参数的转义处理, .g4中添加ObjectString, 要求其中的值可以JSON.parse, 生成的code中也是作为对象而不是字符串出现 + 转义改由editor.blockly处理,editor.multi原样接受和返回 @@ -57,9 +55,9 @@ editor: { + 目前editor.map中储存的是info\, 准备改为和core一致只储存数字 -## 功能改进 ++ editor.file在修改是不再返回obj和commentobj,只在查询时返回 -+ [ ] .g4中添加ObjectString, 要求其中的值可以JSON.parse, 生成的code中也是作为对象而不是字符串出现 +## 功能改进 + [ ] 大地图 在切换时, 每次都回到最左上->每个楼层记录一个位置 From 553ebe0deceeca3cce61913b8574237b60c4583d Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 11:10:16 +0800 Subject: [PATCH 127/153] fix ths --- libs/maps.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/maps.js b/libs/maps.js index 445fc113..b2da2f6f 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1632,7 +1632,7 @@ maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) { this.__playJumpSound(); - var jumpInfo = ths.__generateJumpInfo(sx, sy, ex, ey, time); + var jumpInfo = this.__generateJumpInfo(sx, sy, ex, ey, time); jumpInfo.keep = keep; this._jumpBlock_doJump(blockInfo, canvases, jumpInfo, callback); From 5eea4d33b43df7e4899c2d34652588ee1918d880 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 31 Mar 2019 14:34:45 +0800 Subject: [PATCH 128/153] add hint for syncSave --- libs/control.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/control.js b/libs/control.js index 7a1de28b..f348c10e 100644 --- a/libs/control.js +++ b/libs/control.js @@ -1635,7 +1635,7 @@ control.prototype._syncSave_http = function (type, saves) { else { core.drawText((type=='all'?"所有存档":"存档"+core.saves.saveIndex)+"同步成功!\n\n您的存档编号: " +response.code+"\n您的存档密码: "+response.msg - +"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。") + +"\n\n请牢记以上两个信息(如截图等),在从服务器\n同步存档时使用。\n\r[yellow]另外请注意,存档同步只会保存一个月的时间。\r") } }, function (e) { core.drawText("出错啦!\n无法同步存档到服务器。\n错误原因:"+e); From 1747eef582c772be96ea398122ad490c1d4ae917 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Sun, 31 Mar 2019 15:01:43 +0800 Subject: [PATCH 129/153] Fix stopSound bug --- libs/control.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/control.js b/libs/control.js index f348c10e..a3afd4fe 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2203,8 +2203,8 @@ control.prototype.stopSound = function () { for (var i in core.musicStatus.playingSounds) { var source = core.musicStatus.playingSounds[i]; try { - if (source[i].stop) source[i].stop(); - else if (source[i].noteOff) source[i].noteOff(); + if (source.stop) source.stop(); + else if (source.noteOff) source.noteOff(); } catch (e) { main.log(e); From 99a4a7b2a2115475c786d86dcab91a420cb0f612 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 19:40:55 +0800 Subject: [PATCH 130/153] playSound stop previous --- _docs/event.md | 2 ++ _server/MotaAction.g4 | 9 +++++---- libs/events.js | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 3beb965a..cb8f7b82 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1385,6 +1385,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 值得注意的是,如果是额外添加进文件的音效,则需在main.js中this.sounds里加载它。 +可以加`"stop": true`来停止之前正在播放的音效。 + ### stopSound:停止所有音效 使用`{"type": "stopSound"}`可以停止所有音效。 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index bb3e0f44..2555b855 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -1481,15 +1481,16 @@ return code; */; playSound_s - : '播放音效' EvalString Newline + : '播放音效' EvalString '停止之前音效' Bool? Newline /* playSound_s tooltip : playSound: 播放音效 helpUrl : https://h5mota.com/games/template/docs/#/event?id=playsound%EF%BC%9A%E6%92%AD%E6%94%BE%E9%9F%B3%E6%95%88 -default : ["item.mp3"] +default : ["item.mp3",false] colour : this.soundColor -var code = '{"type": "playSound", "name": "'+EvalString_0+'"},\n'; +Bool_0 = Bool_0 ? ', "stop": true' : ''; +var code = '{"type": "playSound", "name": "'+EvalString_0+'"'+Bool_0+'},\n'; return code; */; @@ -2495,7 +2496,7 @@ ActionParser.prototype.parseAction = function() { break; case "playSound": this.next = MotaActionBlocks['playSound_s'].xmlText([ - data.name,this.next]); + data.name,data.stop,this.next]); break; case "playBgm": this.next = MotaActionBlocks['playBgm_s'].xmlText([ diff --git a/libs/events.js b/libs/events.js index 768cc35d..bfabdb3c 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1213,6 +1213,7 @@ events.prototype._action_freeBgm = function (data, x, y, prefix) { } events.prototype._action_playSound = function (data, x, y, prefix) { + if (data.stop) core.stopSound(); core.playSound(data.name); core.doAction(); } From cf382a12714bebc485d459633791c9a07467a1c0 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 19:52:37 +0800 Subject: [PATCH 131/153] encode unknown route --- libs/utils.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/libs/utils.js b/libs/utils.js index d3bac9d3..2aab843f 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -475,7 +475,7 @@ utils.prototype._encodeRoute_encodeOne = function (t) { return 'K' + t.substring(4); else if (t.indexOf('random:') == 0) return 'X' + t.substring(7); - return ''; + return '('+t+')'; } ////// 解密路线 ////// @@ -485,7 +485,7 @@ utils.prototype.decodeRoute = function (route) { // 解压缩 try { var v = LZString.decompressFromBase64(route); - if (/^[a-zA-Z0-9+\/=:]*$/.test(v)) { + if (/^[a-zA-Z0-9+\/=:()]*$/.test(v)) { route = v; } } catch (e) { @@ -525,6 +525,15 @@ utils.prototype._decodeRoute_number2id = function (number) { } utils.prototype._decodeRoute_decodeOne = function (decodeObj, c) { + // --- 特殊处理自定义项 + if (c == '(') { + var idx = decodeObj.route.indexOf(')', decodeObj.index); + if (idx >= 0) { + decodeObj.ans.push(decodeObj.route.substring(decodeObj.index, idx)); + decodeObj.index = idx + 1; + return; + } + } var nxt = (c == 'I' || c == 'e' || c == 'F' || c == 'S' || c == 'Q' || c == 't') ? this._decodeRoute_getString(decodeObj) : this._decodeRoute_getNumber(decodeObj); From 61e0c582a0475ec5a3bc756305f504ad5bc9b860 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 20:01:02 +0800 Subject: [PATCH 132/153] Fix decodeRoute --- libs/utils.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libs/utils.js b/libs/utils.js index 2aab843f..26c8b8e2 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -485,8 +485,9 @@ utils.prototype.decodeRoute = function (route) { // 解压缩 try { var v = LZString.decompressFromBase64(route); - if (/^[a-zA-Z0-9+\/=:()]*$/.test(v)) { - route = v; + if (v != null && /^[-_a-zA-Z0-9+\/=:()]*$/.test(v)) { + if (v != "" || route.length < 8) + route = v; } } catch (e) { } From b1f7f1a9c7f0e30c6823ae9176a65f6e063ac4d0 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 20:19:24 +0800 Subject: [PATCH 133/153] getBgNumber --- libs/control.js | 2 +- libs/maps.js | 22 +++++++++++++++++++--- project/events.js | 2 +- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/libs/control.js b/libs/control.js index a3afd4fe..1aa32609 100644 --- a/libs/control.js +++ b/libs/control.js @@ -659,7 +659,7 @@ control.prototype._moveAction_moving = function (callback) { core.updateStatusBar(); // 检查该点是否是滑冰 - if (core.getBgFgNumber('bg') == 167) { + if (core.getBgNumber() == 167) { core.insertAction("滑冰事件", null, null, null, true); } diff --git a/libs/maps.js b/libs/maps.js index b2da2f6f..04287c39 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -362,12 +362,28 @@ maps.prototype.getBgFgMapArray = function (name, floorId, noCache) { return arr; } +maps.prototype.getBgMapArray = function (floorId, noCache) { + return this.getBgFgMapArray('bg', floorId, noCache); +} + +maps.prototype.getFgMapArray = function (floorId, noCache) { + return this.getBgFgMapArray('fg', floorId, noCache); +} + maps.prototype.getBgFgNumber = function (name, x, y, floorId, noCache) { if (x == null) x = core.getHeroLoc('x'); if (y == null) y = core.getHeroLoc('y'); return this.getBgFgMapArray(name, floorId, noCache)[y][x]; } +maps.prototype.getBgNumber = function (x, y, floorId, noCache) { + return this.getBgFgNumber('bg', x, y, floorId, noCache); +} + +maps.prototype.getFgNumber = function (x, y, floorId, noCache) { + return this.getBgFgNumber('fg', x, y, floorId, noCache); +} + // ------ 当前能否朝某方向移动,能否瞬间移动 ------ // ////// 生成全图的当前可移动信息 ////// @@ -375,8 +391,8 @@ maps.prototype.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.getBgFgMapArray('bg', floorId), - fgArray = this.getBgFgMapArray('fg', floorId), + var bgArray = this.getBgMapArray(floorId), + fgArray = this.getFgMapArray(floorId), eventArray = this.getMapArray(floorId); var generate = function (x, y, direction) { @@ -489,7 +505,7 @@ maps.prototype._canMoveDirectly_bfs = function (sx, sy, ex, ey) { var canMoveArray = this.generateMovableArray(); var blocksObj = this.getMapBlocksObj(core.status.floorId); // 滑冰 - var bgMap = this.getBgFgMapArray('bg'); + var bgMap = this.getBgMapArray(); var visited = [], queue = []; visited[sx + "," + sy] = 0; diff --git a/project/events.js b/project/events.js index cfc58540..d8559846 100644 --- a/project/events.js +++ b/project/events.js @@ -223,7 +223,7 @@ var events_c12a15a8_c380_4b28_8144_256cba95f760 = }, { "type": "if", - "condition": "core.getBgFgNumber('bg') == 167", + "condition": "core.getBgNumber() == 167", "true": [ { "type": "function", From 97386fa9cf0237e1265f9850ea6cdd4f429d489c Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sun, 31 Mar 2019 09:45:28 -0400 Subject: [PATCH 134/153] fix bug --- _server/vm.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_server/vm.js b/_server/vm.js index fcf7f4e4..be273557 100644 --- a/_server/vm.js +++ b/_server/vm.js @@ -240,7 +240,7 @@ tip.infos=function(value){ document.getElementById('isAirwall-else').innerHTML=(tip.hasId?`

图块编号:${ value['idnum'] }

图块ID:${ value['id'] }

`:`

该图块无对应的数字或ID存在,请先前往icons.js和maps.js中进行定义!

`)+` -

图块所在素材:${ value['images'] + (tip.isAutotile ? '( '+infos['id']+' )' : '') } +

图块所在素材:${ value['images'] + (tip.isAutotile ? '( '+value['id']+' )' : '') }

图块索引:${ value['y'] }

` } From 2d81d7ce7441ce3d5c4407b044a68c134b968c6d Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Sun, 31 Mar 2019 09:55:40 -0400 Subject: [PATCH 135/153] update regactoring.md --- _server/refactoring.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/_server/refactoring.md b/_server/refactoring.md index 695e71ad..55b02bfe 100644 --- a/_server/refactoring.md +++ b/_server/refactoring.md @@ -7,8 +7,8 @@ ## 文件结构 -+ [x] editor_blockly 图块化事件编辑器, 基本不改动 -+ [x] editor_multi 多行文本编辑器, 基本不改动 ++ [ ] editor_blockly 图块化事件编辑器 ++ [ ] editor_multi 多行文本编辑器 + [x] editor_table 处理表格的生成, 及其响应的事件, 从原editor\_mode中分离 + [ ] editor_file 调用fs.js编辑文件, 把原editor\_file模块化 + [ ] editor_game 处理来自core的数据, 导入为editor的数据, 从原editor中分离 @@ -16,7 +16,7 @@ + [ ] editor 执行初始化流程加组合各组件 + [ ] 原editor_mode 移除 + [ ] 原vm 移除 - ++ [ ] \*comment.js 表格注释与结构, 移至comment/\*comment.js ## 对象结构 @@ -61,7 +61,8 @@ editor: { + [ ] 大地图 在切换时, 每次都回到最左上->每个楼层记录一个位置 - 四个箭头目前不能长按 + 四个箭头支持长按 + ? 滚动条 + [ ] ? 表格折叠 变为四栏, 可以折叠展开 @@ -84,7 +85,12 @@ editor: { + [ ] 画地图也自动保存 ++ [ ] 修改系统的触发器(下拉菜单增加新项) + 在编辑器修改`comment.js`:现场发readFile请求读文件,然后开脚本编辑器进行编辑 ++ [ ] ? 删除注册项/修改图块ID + ++ [ ] ? 怪物和道具也能像其他类型那样查看“图块信息”(而不只是具体的怪物属性) ## 左侧页面模式 From f61ab6369310c722d3acc1494f12ad2685f7ef74 Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 23:03:16 +0800 Subject: [PATCH 136/153] status:manamax & documents --- _docs/event.md | 682 +++++++++++++++------------------------ _docs/personalization.md | 451 ++++++-------------------- _server/data.comment.js | 5 + project/data.js | 1 + project/functions.js | 281 ++++++++-------- 5 files changed, 517 insertions(+), 903 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index cb8f7b82..7f1e6969 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1,6 +1,6 @@ # 事件 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * 本章内将对样板所支持的事件进行介绍。 @@ -20,11 +20,13 @@ ## 关于V2.0的重要说明 -在V2.0版本中,所有事件均可以使用blockly来进行块的可视化编辑。 +在V2.0以后版本中,所有事件均可以使用blockly来进行块的可视化编辑。 它能通过拖动、复制粘贴等方式帮助你快速生成事件列表,而不用手动打大量字符。 -但是,仍然强烈建议要对每个事件的写法进行了解,因为在脚本编辑,`insertAction`等地方需要插入自定义事件时,还是很有必要的。 +下述所说的都是在事件编辑器右边所展示的,该事件的代码化写法。 + +强烈建议要对每个事件的写法进行了解,因为在脚本编辑,`insertAction`等地方需要插入自定义事件时,还是很有必要的。 ## 自定义事件 @@ -33,22 +35,18 @@ 所有自定义的事件都是如下的写法: ``` js -"events": { // 该楼的所有可能事件列表 - "x,y": { - "trigger": "action", // 触发的trigger, action代表自定义事件 - "enable": true, // 该事件初始状态下是否处于启用状态 - "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 - "data": [ // 实际执行的事件列表 - // 事件1 - // 事件2 - // ... - ] - } +{ + "trigger": "action", // 触发的trigger, action代表自定义事件 + "enable": true, // 该事件初始状态下是否处于启用状态 + "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 + "data": [ // 实际执行的事件列表 + // 事件1 + // 事件2 + // ... + ] } ``` -这里的`"x,y"`代表该点的横坐标为`x`,纵坐标为`y`;即从左到右第`x`列,从上到下的第`y`行(从0开始计算)。 - 我们上面提到,有很多系统已经默认的事件(例如开门、打怪等,相当于公共事件)。如果我们需要自定义一个事件,则需要`"trigger": "action"`,它表示该点是一个自定义事件。 !> **如果系统本身存在事件(如一个怪物),且你指定了`"trigger": "action"`,则原事件会被覆盖。** @@ -58,17 +56,15 @@ 如果该点本身不存在系统事件,则`"trigger":"action"`可被省略不写: ``` js -"events": { // 该楼的所有可能事件列表 - "x,y": { - // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 - "enable": true, // 该事件初始状态下是否处于启用状态 - "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 - "data": [ // 实际执行的事件列表 - // 事件1 - // 事件2 - // ... - ] - } +{ + // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 + "enable": true, // 该事件初始状态下是否处于启用状态 + "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 + "data": [ // 实际执行的事件列表 + // 事件1 + // 事件2 + // ... + ] } ``` @@ -77,17 +73,15 @@ 默认情况下`enable`是`true`,所以如果`enable`为`true`,该项也可以省略不写: ``` js -"events": { // 该楼的所有可能事件列表 - "x,y": { - // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 - // 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false - "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 - "data": [ // 实际执行的事件列表 - // 事件1 - // 事件2 - // ... - ] - } +{ + // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 + // 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false + "noPass": true, // 该点是否不可通行。true代表不可通行,false代表可通行。 + "data": [ // 实际执行的事件列表 + // 事件1 + // 事件2 + // ... + ] } ``` @@ -98,17 +92,15 @@ 因此,除非你想覆盖默认的可通行选项(比如将一个空地设为不可通行),否则该项可以忽略。 ``` js -"events": { // 该楼的所有可能事件列表 - "x,y": { - // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 - // 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false - // 除非你想覆盖系统默认的可通行状态,否则"noPass"项可以忽略 - "data": [ // 实际执行的事件列表 - // 事件1 - // 事件2 - // ... - ] - } +{ + // 除非你要覆盖该点已存在的系统默认事件,否则"trigger": "action"可以省略 + // 该事件初始状态下是启用状态,则可以省略"enable": true;如果是禁用状态则必须加上"enable": false + // 除非你想覆盖系统默认的可通行状态,否则"noPass"项可以忽略 + "data": [ // 实际执行的事件列表 + // 事件1 + // 事件2 + // ... + ] } ``` @@ -117,14 +109,12 @@ 如果大括号里只有`"data"`,则可以省略大括号和`"data"`,直接写中括号数组,换句话说,上面和下面这种写法也是等价的,可以进行一下比较: ``` js -"events": { // 该楼的所有可能事件列表 - // 如果大括号里只有"data"项(没有"action", "enable"或"noPass"),则可以省略到只剩下中括号 - "x,y": [ // 实际执行的事件列表 - // 事件1 - // 事件2 - // ... - ] -} +// 如果大括号里只有"data"项(没有"action", "enable"或"noPass"),则可以省略到只剩下中括号 +[ + // 事件1 + // 事件2 + // ... +] ``` 这种简写方式可以极大方便地造塔者进行造塔。 @@ -136,15 +126,13 @@ `"data"`中,是由一系列的自定义事件类型组成。每个元素类似于: ``` js -"events": { // 该楼的所有可能事件列表 - // 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号 - "x,y": [ // 实际执行的事件列表 - {"type": "xxx", ...}, // 事件1 - {"type": "xxx", ...}, // 事件2 - // ... - // 按顺序写事件,直到结束 - ] -} +// 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号 +[ + {"type": "xxx", ...}, // 事件1 + {"type": "xxx", ...}, // 事件2 + // ... + // 按顺序写事件,直到结束 +] ``` `"type"`为该自定义事件的类型;而后面的`...`则为具体的一些事件参数。 @@ -158,29 +146,23 @@ 使用`{"type": "text"}`可以显示一段文字。后面`"text"`可以指定文字内容。 ``` js -"events": { // 该楼的所有可能事件列表 - // 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号 - "x,y": [ // 实际执行的事件列表 - {"type": "text", "text": "在界面上的一段文字"}, // 显示文字事件 - {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件 - // ... - // 按顺序写事件,直到结束 - ] -} +[ + {"type": "text", "text": "在界面上的一段文字"}, // 显示文字事件 + {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件 + // ... + // 按顺序写事件,直到结束 +] ``` 该项可以简写成直接的字符串的形式,即下面这种方式也是可以的: ``` js -"events": { // 该楼的所有可能事件列表 - // 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号 - "x,y": [ // 实际执行的事件列表 - "在界面上的一段文字",// 直接简写,和下面写法完全等价 - {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件 - // ... - // 按顺序写事件,直到结束 - ] -} +[ + "在界面上的一段文字",// 直接简写,和下面写法完全等价 + {"type": "text", "text": "这是第二段文字"}, // 显示第二个文字事件 + // ... + // 按顺序写事件,直到结束 +] ``` 所有文字事件均可以进行简写,系统会自动转成`{"type": "text"}`的形式。 @@ -188,15 +170,12 @@ 值得注意的是,系统会自动对文字进行换行;不过我们也可以手动加入`\n`来换行。 ``` js -"events": { // 该楼的所有可能事件列表 - // 如果大括号里只有"data"项(没有"action"或"enable"),则可以省略到只剩下中括号 - "x,y": [ // 实际执行的事件列表 +[ "这一段文字特别特别长,但是系统可以对它进行自动换行,因此我们无需手动换行", "这是第一行\n这是第二行\n这是第三行", // ... // 按顺序写事件,直到结束 - ] -} +] ``` 我们可以给文字加上标题或图标,只要以`\t[...]`开头就可以。 @@ -210,7 +189,7 @@ 从V2.5.2以后,新增了绘制大头像的功能。绘制大头像图的基本写法是`\t[1.png]`或者`\t[标题,1.png]`。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "一段普通文字", "\t[勇士,hero]这是一段勇士说的话", "\t[hero]如果使用勇士默认名称也可以直接简写hero", @@ -233,7 +212,7 @@ - `\b[up,x,y]` 显示在(x,y)点的上方(下方);x和y都为整数且在0到12之间。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "\b[up]这段文字显示在当前点上方", "\b[down]这段文字显示在当前点上方", "\t[hero]\b[up,hero]这是一段勇士说的话,会显示在勇士上方", @@ -246,7 +225,7 @@ 还可以使用`\r[...]`来调整剧情文本的颜色。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "这句话是默认颜色,\r[red]将颜色变成红色,\r[blue]将颜色变成蓝色", "\r[#FF00FF]还可以使用RGB值来控制颜色,\r如果不加中括号则回到默认颜色", "\t[hero]\b[up,hero]啊啊啊,别过来,\r[red]别过来!!!\n\r你到底是什么东西!" @@ -260,7 +239,7 @@ 需要注意的是,这个图片是绘制在UI层上的,下一个事件执行时即会擦除;同时如果使用了\t的图标动画效果,重叠的地方也会被图标动画给覆盖掉。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "\t[勇士]\b[up,hero]\f[1.png,100,100]以(100,100)为左上角绘制1.png图片", "\t[hero]\f[1.png,100,100]\f[2.png,300,300]同时绘制了两张图片", "\f[1.png,100,100,300,300]也可以填写宽高,这样会把图片强制进行放缩到指定的宽高值", @@ -273,7 +252,7 @@ 这里可以使用一个合法ID(32x48图块除外),或使用一个系统图标(`core.statusBar.icons`中的内容)。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "\t[勇士]\b[up,hero]这是一个飞行器\\i[fly],这是一个破墙镐\\i[pickaxe]", "\t[hero]也可以使用系统图标,比如这是存档\\i[save],这是工具栏\\i[toolbox]", ] @@ -286,7 +265,7 @@ 另外值得一提的是,我们是可以在文字中计算一个表达式的值的。只需要将表达式用 `${ }`整个括起来就可以。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "1+2=${1+2}, 4*5+6=${4*5+6}", // 显示"1+2=3, 4*5+6=26" ] ``` @@ -294,7 +273,7 @@ 我们可以使用 `status:xxx` 代表勇士的一个属性值;`item:xxx` 代表某个道具的个数;`flag:xxx` 代表某个自定义的变量或flag值。 ``` js -"x,y": [ // 实际执行的事件列表 +[ "你当前的攻击力是${status:atk}, 防御是${status:def},坐标是(${status:x},${status:y})", "你的攻防和的十倍是${10*(status:atk+status:def)}", "你的红黄蓝钥匙总数为${item:yellowKey+item:blueKey+item:redKey}", @@ -306,18 +285,12 @@ - `item:xxx` 中的xxx为道具ID。所有道具的ID定义在items.js中,请自行查看。例如,`item:centerFly` 代表中心对称飞行器的个数。 - `flag:xxx` 中的xxx为一个自定义的变量/Flag;如果没有对其进行赋值则默认值为false。 -另外,有个小`trick`。是否想立刻知道显示效果? - -你可以用Chrome浏览器打开游戏,按Ctrl+Shift+I打开开发者工具,找到Console(控制台),并中输入`core.drawText("...")` 即可立刻看到文字显示的效果。适当调整文字,使得显示效果满意后,再复制粘贴到你的剧情文本中。 - -![调试](./img/eventdebug.png) - ### autoText:自动剧情文本 使用`{"type": "autoText"}`可以使用剧情文本。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "autoText", "text": "一段自动显示的剧情文字", "time": 5000} ] ``` @@ -337,7 +310,7 @@ time为可选项,代表该自动文本的时间。可以不指定,不指定 使用`{"type": "scrollText"}`可以使用滚动剧情文本,即将一段文字从屏幕最下方滚动到屏幕最上方。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "scrollText", "text": "第一排\n第二牌\n\n空行后的一排", "time": 5000, "lineHeight": 1.4, "async": true}, ] ``` @@ -359,7 +332,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 使用`{"type": "setText"}`可以设置剧情文本的各项属性。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setText", "title": [255,0,0], "text": [255,255,0], "background": [0,0,255,0.3], "time": 70}, {"type": "setText", "position": "up", "offset": 15, "bold": true, "titlefont": 26, "textfont": 17}, "这段话将显示在上方(距离顶端15像素),标题为红色,正文为黄色粗体,背景为透明度0.3的蓝色,标题26px,正文17px,70毫秒速度打字机效果", @@ -392,7 +365,7 @@ time为可选项,表示文字添加的速度。若此项设置为0将直接全 `{"type": "tip"}`可以在左上角显示一段提示文字。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "tip", "text": "这段话将在左上角以气泡形式显示"} ] ``` @@ -404,7 +377,7 @@ time为可选项,表示文字添加的速度。若此项设置为0将直接全 使用`{"type": "comment"}`可以添加一段注释 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "comment", "text": "这是一段会被跳过的注释内容"} ] ``` @@ -418,7 +391,7 @@ time为可选项,表示文字添加的速度。若此项设置为0将直接全 其大致写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setValue", "name": "...", "value": "..."}, // 设置一个属性、道具或自定义Flag ] ``` @@ -430,7 +403,7 @@ name为你要修改的属性/道具/Flag,每次只能修改一个值。写法 value是一个表达式,将通过这个表达式计算出的结果赋值给name。该表达式同样可以使用`status:xxx`, `item:xxx`, `flag:xxx`的写法表示勇士当前属性,道具个数和某个变量/Flag值。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setValue", "name": "status:atk", "value": "status:atk+10" } // 攻击提高10点 {"type": "setValue", "name": "status:money", "value": "1000" } // 将金币数设为1000(不是+1000) {"type": "setValue", "name": "status:hp", "value": "status:hp*2" } // 生命值翻倍 @@ -450,7 +423,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam 即下面的写法是等价的: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setValue", "name": "status:atk", "value": "status:atk+10" } // 攻击提高10点 {"type": "addVakue", "name": "status:atk", "value": "10" } // 和上面写法等价 {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey-3" } // 黄钥匙个数-3 @@ -465,7 +438,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam 使用`{"type":"setFloor"}`可以设置某层楼的楼层属性。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setFloor", "name": "title", "value": "'主塔 0 层'" } // 设置当前楼层的中文名为主塔0层 {"type": "setFloor", "name": "canFlyTo", "floorId": "MT2", "value": "false" } // 设置MT2层不可飞行 {"type": "setFloor", "name": "cannotViewMap", "floorId": "MT0", "value": "true" } // 设置MT0层不可被浏览地图 @@ -476,8 +449,7 @@ value是一个表达式,将通过这个表达式计算出的结果赋值给nam ] ``` -name为必填项,代表要修改的楼层属性。其和楼层属性中一一对应,目前只能为`"title", "name", "canFlyTo", "canUseQuickShop", "cannotViewMap", "cannotMoveDirectly", "color", "weather", -"defaultGround", "images", "item_ratio", "upFloor", "bgm", "downFloor", "underGround"`。 +name为必填项,代表要修改的楼层属性,和楼层属性中的一一对应。 floorId为可选项,代表要修改的楼层ID;可以省略代表当前楼层。 @@ -490,13 +462,12 @@ value为必填项,代表要修改到的数值。其应该和楼层属性中的 使用`{"type":"setGlobalAttribute"}`可以设置一个全局属性。 ``` js -"x,y": [ // 实际执行的事件列表 - {"type": "setGlobalAttribute", "name": "font", "value": "Verdana"}, // 设置字体为Verdana +[ + {"type": "setGlobalAttribute", "name": "font", "value": "Verdana"}, // 设置字体为Verdana ] ``` -name必填项,代表要修改的全局属性。目前只能为`"font", "statusLeftBackground", "statusTopBackground", "toolsBackground", -"borderColor", "statusBarColor", "hardLabelColor", "floorChangingBackground", "floorChangingTextColor"`。 +name必填项,代表要修改的全局属性。 value为必填项,代表要修改到的结果。此项无需再手动加单引号。 @@ -505,14 +476,12 @@ value为必填项,代表要修改到的结果。此项无需再手动加单引 使用`{"type":"setGlobalValue"}`可以设置一个全局数值。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setGlobalValue", "name": "lavaDamage", "value": 200}, // 设置血网伤害为200 ] ``` -name必填项,代表要修改的全局数值,其和全塔属性中的values一一对应。目前只能为`"lavaDamage", "poisonDamage", "weakValue", "redJewel", -"blueJewel", "greenJewel", "redPotion", "bluePotion", "yellowPotion", "greenPotion", "breakArmor", "counterAttack", -"purify", "hatred", "moveSpeed", "animateSpeed"`。 +name必填项,代表要修改的全局数值,其和全塔属性中的values一一对应。 value为必填项,代表要修改到的结果。该项必须是个数值。 @@ -521,15 +490,12 @@ value为必填项,代表要修改到的结果。该项必须是个数值。 使用`{"type":"setGlobalFlag"}`可以设置一个系统开关。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setGlobalFlag", "name": "enableMDef", "value": false}, // 不在状态栏显示魔防值 ] ``` -name必填项,代表要修改的系统开关,其是全塔属性中的flags中的一部分。目前只能为`"enableFloor", "enableName", "enableLv", -"enableHPMax", "enableMana", "enableMDef", "enableMoney", "enableExperience", "enableLevelUp", "levelUpLeftMode", -"enableKeys", "enablePZF", "enableDebuff", "enableSkill", "flyNearStair", "enableAddPoint", "enableNegativeDamage", -"useLoop", "enableGentleClick", "canGoDeadZone", "enableMoveDirectly", "disableShopOnDamage"`。 +name必填项,代表要修改的系统开关,其是全塔属性中的flags中的一部分。 value为必填项,只能为true或false,代表要修改到的结果。 @@ -540,7 +506,7 @@ value为必填项,只能为true或false,代表要修改到的结果。 使用`{"type":"show"}`可以将一个本身禁用的事件启用。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "show", "loc": [3,6], "floorId": "MT1", "time": 500}, // 启用MT1层[3,6]位置事件,动画500ms {"type": "show", "loc": [3,6], "time": 500}, // 如果启用目标是当前层,则可以省略floorId项 {"type": "show", "loc": [3,6]}, // 如果不指定动画时间,则立刻显示,否则动画效果逐渐显示,time为动画时间 @@ -576,7 +542,7 @@ loc同样可以简单的写[x,y]表示单个点,或二维数组[[x1,y1],[x2,y2 NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}`,可以不写loc选项代表当前事件,可以指定time使NPC动画消失。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "hide", "loc": [3,6], "floorId": "MT1", "time": 500}, // 禁用MT1层[3,6]位置事件,动画500ms {"type": "hide", "loc": [3,6], "time": 500}, // 如果启用目标是当前层,则可以省略floorId项 {"type": "hide", "loc": [3,6]}, // 如果不指定动画时间,则立刻消失,否则动画效果逐渐消失,time为动画时间 @@ -596,7 +562,7 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` 其基本写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "trigger", "loc": [3,6]}, // 立即触发loc位置的事件,当前剩下的事件全部不再执行 "执行trigger后,这段文字将不会再被显示" ] @@ -617,7 +583,7 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` 其基本写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "insert", "name": "加点事件", "args": [10] }, // 插入公共事件:加点事件,传入参数10 {"type": "insert", "name": "毒衰咒处理", "args": [0]}, // 插入公共事件:毒衰咒处理,传入参数0 {"type": "insert", "loc": [3,6]}, // 插入[3,6]点的事件并执行 @@ -657,7 +623,7 @@ NPC对话事件结束后如果需要NPC消失也需要调用 `{"type": "hide"}` revisit和trigger完全相同,只不过是立刻触发的还是本地点的事件 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "revisit"}, // 立即触发本事件,等价于 {"type": "trigger", "loc": [x,y]} "执行revisit后,这段文字将不会再被显示" ] @@ -676,7 +642,7 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不 例如玩家点击商人的"离开"选项,则可以调用exit返回游戏。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "exit" }, // 立即结束事件并恢复游戏,一切列表中的事件都将不再被执行 "执行exit后,这段文字将不会再被显示" ] @@ -687,7 +653,7 @@ revisit常常使用在一些商人之类的地方,当用户购买物品后不 我们可以采用 `{"type": "setBlock"}` 来改变某个地图块。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setBlock", "floorId": "MT1", "loc": [3,3], "number": 233}, // 将MT1层的(3,3)点变成数字233 {"type": "setBlock", "loc": [2,1], "number": 121}, // 省略floorId则默认为本层 {"type": "setBlock", "number": 57}, // loc也可省略,默认为当前点 @@ -715,7 +681,7 @@ number为**要更改到的数字**,有关“数字”的定义详见参见[素 有关贴图说明请参见[使用自己的图片作为某层楼的背景/前景素材](personalization#使用自己的图片作为某层楼的背景前景素材)。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "hideFloorImg", "loc": [3,6], "floorId": "MT1"}, // 隐藏[3,6]的贴图 {"type": "hideFloorImg", "loc": [3,6]}, // 如果是当前层,则可以省略floorId项 {"type": "hideFloorImg", "loc": [[3,6],[2,9],[1,2]]} // 我们也可以同时隐藏多个贴图。 @@ -735,7 +701,7 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。 其做法和参数,和隐藏贴图是完全一致的。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "showFloorImg", "loc": [3,6], "floorId": "MT1"}, // 显示[3,6]的贴图 ] ``` @@ -747,7 +713,7 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。 从V2.4.1开始,允许绘制三层图层(背景层,事件层和前景层)。使用`hideBgFgMap`可以隐藏背景或前景层中的图块。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "hideBgFgMap", "name": "bg", "loc": [3,6], "floorId": "MT1"}, // 隐藏MT1层[3,6]的背景层图块 {"type": "hideBgFgMap", "name": "bg", "loc": [3,6]}, // 如果是当前层,则可以省略floorId项 {"type": "hideBgFgMap", "name": "fg", "loc": [[3,6],[2,9],[1,2]]} // 我们也可以同时隐藏多个贴图。 @@ -767,7 +733,7 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。 其做法和参数,和隐藏贴图是完全一致的。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "showBgFgMap", "name": "bg", "loc": [3,6], "floorId": "MT1"}, // 显示MT1层[3,6]的前景层图块 ] ``` @@ -777,7 +743,7 @@ floorId为目标点的楼层,如果是当前楼层可以忽略不写。 我们可以采用 `{"type": "setBgFgBlock"}` 来改变某个背景或前景层地图块。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setBgFgBlock", "name": "bg", "floorId": "MT1", "loc": [3,3], "number": 233}, // 将MT1层背景层的(3,3)点变成数字233 {"type": "setBgFgBlock", "name": "bg", "loc": [2,1], "number": 121}, // 省略floorId则默认为本层 {"type": "setBgFgBlock", "name": "fg", "number": 57}, // loc也可省略,默认为当前点 @@ -797,7 +763,7 @@ loc为可选的,表示要更改地图块的坐标。如果忽略此项,则 使用`{"type": "setHeroIcon"}`可以更改角色行走图。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setHeroIcon", "name": "hero2.png"}, // 将勇士行走图改成hero2.png;必须在全塔属性的images中被定义过。 {"type": "setHeroIcon"}, // 如果不加name则恢复最初默认状态 {"type": "setValue", "name": "status:name", "value": "'可绒'"}, // 修改勇士名;请注意value必须加单引号。 @@ -839,7 +805,7 @@ name是可选的,代表目标行走图的文件名。 基本写法:`{"type": "sleep", "time": xxx}` ,其中xxx为指定的毫秒数。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "sleep", "time": 1000}, // 等待1000ms "等待1000ms后才开始执行这个事件", {"type": "sleep", "time": 2000, "noSkip": true}, // 等待2000毫秒,且不可被跳过 @@ -854,12 +820,10 @@ name是可选的,代表目标行走图的文件名。 调用battle可强制与某怪物进行战斗(而无需去触碰到它)。 -例如,《宿命的旋律》中,一区有个骷髅队长,当你拿了它周围三个物品时,就会立刻触发强制战斗事件。这时候就可以用`{"type": "battle"}` 实现。 - 其基本写法是: `{"type": "battle", "id": xxx}`,其中xxx为怪物ID。 ``` js -"10,4": [ // 开门后走进去的事件:强制战斗 +[ "\t[blackKing]你终于还是来了。", "\t[hero]放开我们的公主!", "\t[blackKing]如果我不愿意呢?", @@ -877,8 +841,6 @@ name是可选的,代表目标行走图的文件名。 如果强制战斗失败,则会立刻生命归0并死亡,调用lose函数,接下来的事件不会再被执行。 -打败怪物后可以进行加点操作。有关加点塔的制作可参见[加点事件](#加点事件)。 - 强制战斗没有指定loc的选项,因此战斗后需要调用hide使怪物消失(如果有必要)。 ### openDoor:开门 @@ -886,7 +848,7 @@ name是可选的,代表目标行走图的文件名。 调用`{"type":"openDoor"}`可以打开一扇门。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "openDoor", "loc": [3,6], "floorId": "MT1"}, // 打开MT1层的[3,6]位置的门 {"type": "openDoor", "loc": [3,6]}, // 如果是本层则可省略floorId {"type": "openDoor", "loc": [3,6], "needKey": true} // 打开此门需要钥匙 @@ -908,7 +870,7 @@ needKey是可选的,如果设置为true则需要钥匙才能打开此门。如 从V2.6开始提供了关门事件`{"type": "closeDoor"}`,拥有关门动画和对应的音效。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "closeDoor", "id": "yellowDoor", "loc": [3,6]}, // 给(3,6)点关上黄门 {"type": "closeDoor", "id": "specialDoor"}, // 不写loc则视为当前点 ] @@ -934,7 +896,7 @@ loc可选,为要关的位置,不填默认为当前点。 changeFloor的事件写法大致如下。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "changeFloor", "floorId": "sample0","loc": [10, 10], "direction": "left", "time": 1000 }, //后面几项依次为楼层id,楼层位置(这两项为必填);勇士方向可选,切换时间也是可选。 ] @@ -957,7 +919,7 @@ time为可选的,指定的话将作为楼层切换动画的时间。 这时候可以用changePos。其参数和changeFloor类似,但少了floorId和time两个选项。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "changePos", "loc": [10,10], "direction": "left"}, // 直接切换勇士的坐标,loc为目标地点,后面勇士换位后方向 {"type": "changePos", "loc", [10,10]}, // 如无需指定方向则direction可省略 {"type": "changePos", "direction": "left"} // loc也可省略,只指定direction;此时等价于当前勇士转向到某个方向。 @@ -969,7 +931,7 @@ time为可选的,指定的话将作为楼层切换动画的时间。 调用`{"type": "useItem"}`可以使用一个道具。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "changePos", "id": "pickaxe"}, // 尝试使用破 {"type": "changePos", "id": "bomb"}, // 尝试使用炸 {"type": "changePos", "id": "centerFly"} // 尝试使用飞 @@ -995,7 +957,7 @@ time为可选的,指定的话将作为楼层切换动画的时间。 使用 `{"type": "follow"}` 可以让一个npc加入跟随。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "follow", "name": "npc.png"}, // 将 npc.png 这个行走图加入跟随 {"type": "follow", "name": "hero.png"}, // 再将另一个行走图加入跟随 ] @@ -1010,7 +972,7 @@ name所指定的图片必须存在,在全塔属性中的images中被定义过 使用 `{"type": "unfollow"}` 来取消一个跟随。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "unfollow", "name": "npc.png"}, // 将 npc.png 这个行走图取消跟随 {"type": "follow"}, // 取消所有跟随 ] @@ -1037,7 +999,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 有关动画的详细介绍可参见[动画和天气系统](element#动画和天气系统)。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "animate", "name": "yongchang", "loc": [1,3]}, // 在(1,3)显示“咏唱魔法”动画 {"type": "animate", "name": "zone", "loc": "hero"}, // 在勇士位置显示“领域”动画 {"type": "animate", "name": "hand"}, // 可以不指定loc,则默认为当前事件点 @@ -1060,7 +1022,7 @@ loc可忽略,如果忽略则显示为事件当前点。 我们可以使用 `{"type": "showImage"}` 来显示一张图片。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "showImage", "code": 1, "image": "bg.jpg", "loc": [231,297], "opacity": 1, "time" : 0}, // 在(231,297)显示bg.jpg {"type": "showImage", "code": 12, "image": "1.png", "loc": [209,267], "opacity": 0.5, "time" : 1000}, // 在(209,267)渐变显示1.png,渐变时间为1000毫秒,完成时不透明度为0.5,这张图片将遮盖上一张 {"type": "showImage", "code": 8, "image": "hero.png", "loc": [349,367], "opacity": 1, "time" : 500, "async": true}, // 在(209,267)渐变显示hero.png,渐变时间为500毫秒,异步执行;这张图片将被上一张遮盖 @@ -1087,7 +1049,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "showTextImage"}` 以图片的方式显示文本。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "showTextImage", "code": 1, "text": "第一排\n第二排\n\n空行后的一排", "loc": [231,297], "opacity": 1, "time" : 0}, // 在(231,297)显示"第一排\n第二排\n\n空行后的一排" ] ``` @@ -1113,7 +1075,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "hideImage"}` 来清除一张图片。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "hideImage", "code": 1, "time" : 0}, // 使1号图片消失 {"type": "hideImage", "code": 12, "time" : 1000}, // 使12号图片渐变消失,时间为1000毫秒 ] @@ -1130,7 +1092,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "showGif"}` 来显示一张图片。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "showGif", "name": "timg.gif", "loc": [231,297]}, // 在(231,297)显示一张动图 {"type": "showGif"} // 如果不指定name则清除所有动图。 ] @@ -1147,7 +1109,7 @@ loc为动图左上角坐标,以像素为单位进行计算。 我们可以使用 `{"type": "moveImage"}` 来造成图片移动,淡入淡出等效果。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "moveImage", "code": 1, "to": [22,333], "opacity": 1, "time": 1000}, // 将1号图片移动到(22,333),动画时间为1000ms {"type": "moveImage", "code": 12, "opacity": 0.5, "time": 500}, // 将二号图片的透明度变为0.5,动画时间500ms {"type": "moveImage", "code": 1, "to": [109,167], "opacity": 0, "time": 300, "async": true}, // 将1号图片移动到(109,167),透明度设为0(不可见),动画时间300ms,异步执行 @@ -1169,7 +1131,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "setFg"}` 来更改画面色调。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setFg", "color": [255,255,255,0.6], "time": 1000}, // 更改画面色调为纯白,不透明度0.6,动画时间1000毫秒 {"type": "setFg", "color": [0,0,0], "async": true}, // 更改画面色调为纯黑,不透明度1,不指定动画时间(使用默认时间),且异步执行 {"type": "setFg"} // 如果不指定color则恢复原样。 @@ -1191,7 +1153,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "screenFlash"}` 来进行画面闪烁。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "screenFlash", "color": [255,255,255,0.6], "time": 500, "times": 1}, // 闪光为白色,不透明度0.6,动画时间1000毫秒 {"type": "screenFlash", "color": [255,0,0,1], "time": 100, "times": 2, "async": true}, // 闪光为红色,强度最大,动画时间100毫秒,闪烁两次且异步执行 ] @@ -1212,7 +1174,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 我们可以使用 `{"type": "setWeather"}` 来更改天气。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "setWeather", "name": "rain", "level": 6}, // 更改为雨天,强度为6级 {"type": "setWeather", "name": "snow", "level": 3}, // 更改为雪天,强度为3级 {"type": "setWeather"} // 更改回晴天 @@ -1236,10 +1198,9 @@ level为天气的强度等级,在1-10之间。1级为最弱,10级为最强 下面是该事件常见的写法: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "move", "time": 750, "loc": [x,y], "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),loc为位置可选,steps为移动数组 - {"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失 - "down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1 + "right", "right", "down" // 向右两格,向下一格 ], "keep": true, "async":true }, // keep可选,如果为true则不消失,否则渐变消失;async可选,如果为true则异步执行。 ] ``` @@ -1248,9 +1209,7 @@ time选项必须指定,为每移动一步所需要用到的时间。 loc为需要移动的事件位置。可以省略,如果省略则移动本事件。 -steps为一个数组,其每一项为一个 `{"direction" : xxx, "value": n}`,表示该步是向xxx方向移动n步。 - -如果只移动一步可以直接简单的写方向字符串(`up/left/down/right`)。 +steps为一个数组,其每一项是`up, down, left, right`之一,表示这一步应该朝哪个方向走。 keep为一个可选项,代表该事件移动完毕后是否消失。如果该项指定了并为true,则移动完毕后将不消失,否则以动画效果消失。 @@ -1265,7 +1224,7 @@ keep为一个可选项,代表该事件移动完毕后是否消失。如果该 ``` js "4,3": [ // [4,3]是一个NPC,比如小偷 {"type": "move", "time": 750, "steps": [ // 向上移动两格,每步750毫秒 - {"direction": "up", "value": 2}, + "up", "up" ], "keep": true}, // 移动完毕后不消失 ], "4,1": { // [4,1]为目标地点 @@ -1289,13 +1248,14 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 ``` js "x,y": [ // 实际执行的事件列表 {"type": "moveHero", "time": 750, "async": true, "steps": [// 动画效果,time为移动速度(比如这里每750ms一步),steps为移动数组 - {"direction": "right", "value": 2},// 这里steps 的效果为向右移动2步,在向下移动一步并消失 - "down" // 如果该方向上只移动一步则可以这样简写,效果等价于上面value为1 + "down", "right", "forward", "backward" // 向下、右、前、后各走一步 ]}, ] ``` -可以看到,和上面的move事件几乎完全相同,除了不能指定loc,且少了immediateHide选项。 +可以看到,和上面的move事件几乎完全相同,除了不能指定loc,且少了keep选项。 + +勇士的steps也允许`forward`和`backward`,即前进和后退。 不过值得注意的是,用这种方式移动勇士的过程中将无视一切地形,无视一切事件,中毒状态也不会扣血。 @@ -1308,7 +1268,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 下面是该事件常见的写法: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "jump", "from": [3,6], "to": [2,1], "time": 750, "keep": true, "async": true}, ] ``` @@ -1332,7 +1292,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 下面是该事件常见的写法: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "jump", "loc": [3,6], "time": 750, "async": true}, ] ``` @@ -1351,7 +1311,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 值得注意的是,额外添加进文件的背景音乐,需在main.js中this.bgms里加载它。 -目前支持mp3/ogg/wav/mid等多种格式的音乐播放。 +目前支持mp3/ogg/wav等多种格式的音乐播放。 有关BGM播放的详细说明参见[背景音乐](element#背景音乐) @@ -1385,7 +1345,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 值得注意的是,如果是额外添加进文件的音效,则需在main.js中this.sounds里加载它。 -可以加`"stop": true`来停止之前正在播放的音效。 +从V2.6开始,也可以加`"stop": true`来停止之前正在播放的音效。 ### stopSound:停止所有音效 @@ -1411,6 +1371,8 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 该事件会显示获胜页面,并重新游戏。 +可以增加`"norank": 1`来表示该结局不计入榜单。 + !> 如果`reason`不为空,则会以reason作为获胜的结局! ### lose:游戏失败 @@ -1442,7 +1404,7 @@ async可选,如果为true则会异步执行(即不等待当前事件执行 使用`{"type": "input"}`可以接受用户的输入的数字。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "input", "text": "请输入一个数"}, // 显示一个弹窗让用户输入数字 "你刚刚输入的数是${flag:input}" // 输入结果将被赋值为flag:input ] @@ -1461,7 +1423,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 类似于input事件,使用`{"type": "input2"}`可以接受用户的输入的文本。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "input2", "text": "请输入你的ID"}, // 显示一个弹窗让用户输入文本 "你好,${flag:input},欢迎来到本塔" // 输入结果将被赋值为flag:input ] @@ -1482,7 +1444,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 其大致写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "if", "condition": "...", // 测试某个条件 "true": [ // 条件成立则执行true里面的事件 @@ -1503,7 +1465,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 例如下面这个例子,每次将检查你的攻击力是否大于500,不是的场合将给你的攻击力加100点。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "if", "condition": "status:atk>500", // 判断攻击力是否大于500 "true": [ // 条件成立则执行true里面的事件 "你的攻击力已经大于500了!", @@ -1511,7 +1473,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 ], "false": [ // 条件不成立则执行false里的事件 "你当前攻击力为${status:atk}, 不足500!\n给你增加100点攻击力!", - {"type": "setValue", "name": "status:atk", "value": "status:atk+100"}, // 攻击力加100, 接着会执行revisit事件 + {"type": "addValue", "name": "status:atk", "value": "100"}, // 攻击力加100, 接着会执行revisit事件 ] }, {"type", "revisit"}, // 立刻重启本事件, 直到攻击力大于500后结束 @@ -1521,7 +1483,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 需要额外注意的几点: - 给定的表达式(condition)一般需要返回true或false。 -- `flag:xxx` 可取用一个自定义变量或flag。如果从未设置过该flag,则其值默认为false。而JS中,`false==0`这个判断是成立的,因此我们可以简单使用 `"flag:npc_times==0"` 来判断某个NPC是否被访问过。 +- `flag:xxx` 可取用一个自定义变量或flag。如果从未设置过该flag,则其值默认为0。 - 即使成功失败的场合不执行事件,对应的true或false数组也需要存在,不过简单的留空就好。 - if可以不断进行嵌套,一层套一层;如成立的场合再进行另一个if判断等。 - if语句内的内容执行完毕后将接着其后面的语句继续执行。 @@ -1534,7 +1496,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 其大致写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "switch", "condition": "...", // 计算某个表达式 "caseList": [ {"case": "a", "action": [// 若表达式的值等于a则执行该处事件 @@ -1560,7 +1522,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 例如下面这个例子,将检查当前游戏难度并赠送不同属性。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "switch", "condition": "flag:hard", // 判断当前游戏难度 "caseList": [ {"case": "0", "action": [// 若表达式的值等于0则执行该处事件 @@ -1583,12 +1545,32 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 需要额外注意的几点: -- 各个条件分支的判断是顺序执行的,因此若多个分支的条件都满足,将只执行最靠前的分支,同理,请不要在`default`分支后添加分支,这些分支将不可能被执行。 +- 各个条件分支的判断是顺序执行的,因此若多个分支的条件都满足,将只执行最靠前的分支。 + - 同理,请不要在`default`分支后添加分支,这些分支将不可能被执行。 - `default`分支并不是必要的,如果删除,则在没有满足条件的分支时将不执行任何事件。 - 即使某个场合不执行事件,对应的action数组也需要存在,不过简单的留空就好。 -- switch可以不断进行嵌套,一层套一层;如某条件成立的场合再进行另一个switch判断等。 - switch语句内的内容执行完毕后将接着其后面的语句继续执行。 +由于`case`中的内容是会被计算的,因此如下写法也是合法的 + +```js +[ + {"type": "switch", "condition": "true", // 条件:某一项为真时 + "caseList": [ + {"case": "flag:a==1", "action": [ // 如果 flag:a == 1 + "走进了 flag:a==1 分支!" + ], + {"case": "flag:b>=3", "action": [ // 如果 flag:b >= 3 + "走进了 flag:b>=3 分支!" + ], + {"case": "default", "action": [ // 上述两条均布成立 + "上述两条均不成立" + ] + ] + }, +] +``` + ### choices:给用户提供选项 @@ -1601,17 +1583,16 @@ choices是一个很麻烦的事件,它将弹出一个列表供用户进行选 其大致写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "choices", "text": "...", // 提示文字 - "color": [255,0,0,1], // 颜色 "choices": [ {"text": "选项1文字", "action": [ // 选项1执行的事件 ]}, - {"text": "选项2文字", "action": [ + {"text": "选项2文字", "color": [255,0,0,1], "action": [ // 选项2执行的事件 ]}, - {"text": "选项3文字", "action": [ + {"text": "选项3文字", "icon": "fly", "action": [ // 选项3执行的事件 ]}, ] @@ -1629,67 +1610,10 @@ action为当用户选择了该选项时将执行的事件。 color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数组([255,0,0,1])。 +icon是可选的,如果设置则会在选项前绘制图标,其可以是一个有效的ID,或者`core.statusBar.icons`中的系统图标。 + 选项可以有任意多个,但一般不要超过6个,否则屏幕可能塞不下。 -下面是一个卖钥匙的事件,是一个比较复杂却也较为典型的if和choices合并使用的样例。 - -``` js -"10,11": [ // 商人事件,if语句和choices语句的写法 - // 这部分逻辑相对比较长,细心看,很容易看懂的。 - {"type": "if", "condition": "flag:woman_times==0", // 条件判断:是否从未访问过此商人。 - "true": [ // 如果从未访问过该商人,显示一段文字 - "\t[老人,woman]这是个很复杂的例子,它将教会你如何使用if 语句进行条件判断,以及 choices 提供选项来供用户进行选择。", - "\t[老人,woman]第一次访问我将显示这段文字;从第二次开始将会向你出售钥匙。\n钥匙价格将随着访问次数递增。\n当合计出售了七把钥匙后,将送你一把大黄门钥匙,并消失不再出现。", - "\t[老人,woman]这部分的逻辑比较长,请细心看样板的写法,是很容易看懂并理解的。" - // 第一次访问结束 - ], - "false": [ // 如果已经访问过该商人 - {"type": "if", "condition": "flag:woman_times==8", // 条件判断:是否已经出售七把钥匙 - "true": [ // 如果已经出售过七把钥匙,则直接结束 - "\t[老人,woman]你购买的钥匙已经够多了,再继续卖给你的话我会有危险的。", - "\t[老人,woman]看在你贡献给我这么多钱的份上,送你一把大黄门钥匙吧,希望你能好好用它。", - {"type": "setValue", "name": "item:bigKey", "value": "item:bigKey+1"}, // 获得一把大黄门钥匙 - "\t[老人,woman]我先走了,拜拜~", - {"type":"hide", "time": 500}, // 消失 - {"type":"exit"} // 立刻结束当前事件。下面的 setValue 和 revisit 都不会再执行。 - ], - "false": [ // 否则,显示选择页面 - {"type": "choices", "text": "\t[老人,woman]少年,你需要钥匙吗?\n我这里有大把的!", // 显示一个卖钥匙的选择页面 - "choices": [ // 提供四个选项:黄钥匙、蓝钥匙、红钥匙、离开。前三个选项显示需要的金额 - {"text": "黄钥匙(${9+flag:woman_times}金币)", "color": [255,255,0,1], "action": [ // 第一个选项,黄钥匙 - // 选择该选项的执行内容 - {"type": "if", "condition": "status:money>=9+flag:woman_times", // 条件判断:钱够不够 - "true": [ - {"type": "setValue", "name": "status:money", "value": "status:money-(9+flag:woman_times)"}, // 扣减金钱 - {"type": "setValue", "name": "item:yellowKey", "value": "item:yellowKey+1"}, // 增加黄钥匙 - // 然后会继续执行下面的setValue来增加商人访问次数 - ], - "false": [ - "\t[老人,woman]你的金钱不足!", - {"type": "revisit"} // 直接重新访问;不执行下面的setValue来增加访问次数 - ] - } - ]}, - {"text": "蓝钥匙(${18+2*flag:woman_times}金币)", "color": [0,0,255,1], "action": [ // 第二个选项:蓝钥匙 - // 逻辑和上面黄钥匙完全相同,略 - ]}, - {"text": "红钥匙(${36+4*flag:woman_times}金币)", "color": [255,0,0,1], "action": [ // 第三个选项:红钥匙 - // 逻辑和上面黄钥匙完全相同,略 - ]}, - {"text": "离开", "action": [ // 第四个选项:离开 - {"type": "exit"} // 立刻结束当前事件 - ]} - ] - } - ] - } - ] - }, - {"type": "setValue", "name": "flag:woman_times", "value": "flag:woman_times+1"}, // 增加该商人的访问次数。 - {"type": "revisit"} // 立即重新开始这个事件 -], -``` - ### while:循环处理 从2.2.1样板开始,我们提供了循环处理(while事件)。 @@ -1697,7 +1621,7 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 其大致写法如下: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "while", "condition": "...", // 循环测试某个条件 "data": [ // 条件成立则执行data里面的事件 @@ -1715,10 +1639,10 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 下面是一个输出1到10之间的数字,每隔1秒显示一个的例子。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type":"while", "condition": "flag:i<=10", // 循环处理;注意flag未设置则默认为0 "data":[ - {"type": "setValue", "name": "flag:i", "value": "flag:i+1"}, // 递增i + {"type": "addValue", "name": "flag:i", "value": "1"}, // 递增i "${flag:i}", // 输出i {"type": "sleep","time":1000}, // 等待1秒 ] @@ -1739,10 +1663,10 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 上面的输出例子也可以这么写: ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type":"while", "condition": "true", // 循环处理;永远为真 "data":[ - {"type": "setValue", "name": "flag:i", "value": "flag:i+1"}, // 递增i + {"type": "addValue", "name": "flag:i", "value": "1"}, // 递增i "${flag:i}", // 输出i {"type": "sleep","time":1000}, // 等待1秒 {"type": "if", "condition": "flag:i<10", // 测试i是否小于10 @@ -1762,15 +1686,14 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 使用 `{"type": "wait"}` 可以等待用户进行操作(如点击、按键等)。 当用户执行操作后: -- 如果是键盘的按键操作,则会将flag:type置为0,并且把flag:keycode置为刚刚按键的keycode。 -- 如果是屏幕的点击操作,则会将flag:type置为1,并且设置flag:x和flag:y为刚刚的点击坐标(0-12之间),flag:px和flag:py置为刚刚的像素坐标(0-415之间)。 +- 如果是键盘的按键操作,则会将flag:type置为0,并且把flag:keycode置为按键的keycode。 +- 如果是屏幕的点击操作,则会将flag:type置为1,并且设置flag:x和flag:y为点击的位置坐标,flag:px和flag:py为点击的像素坐标。 下面是一个while事件和wait合并使用的例子,这个例子将不断接收用户的点击或按键行为,并输出该信息。 如果用户按下了ESC或者点击了屏幕正中心,则退出循环。 - ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "while", "condition": "true", // 永久循环 "data": [ {"type": "wait"}, // 等待用户操作 @@ -1793,7 +1716,6 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 ] } ] - ``` ### waitAsync:等待所有异步事件执行完毕 @@ -1814,7 +1736,7 @@ color为可选的,可以是一个字符串(#FF0000),或者一个RGBA数 上述给出了这么多事件,但有时候往往不能满足需求,这时候就需要执行自定义脚本了。 ``` js -"x,y": [ // 实际执行的事件列表 +[ {"type": "function", "function": function(){ // 执行一段js脚本 // 这里写js代码 alert(core.getStatus("atk")); // 弹窗显示勇士的攻击力 @@ -1931,7 +1853,6 @@ core.insertAction([ } ``` - 总之,记住如下两点: - 可以使用setBlock来更改一个图块。 @@ -2015,31 +1936,13 @@ if (core.getFlag("door",0)==2) { 如果要对某个怪物进行加点操作,则首先需要修改该怪物的`point`数值,代表怪物本身的加点数值。 -然后在脚本编辑中找到加点事件,双击进行修改。它将返回一个choices事件。修改此函数为我们需要的加点项即可。 +从V2.5.5开始,加点事件移动到了[公共事件](personalization#公共事件)之中,会通过传参的形式来传递怪物的加点值。 -``` js -////// 加点事件 ////// -"addPoint" : function (enemy) { - // 加点事件 - var point = enemy.point; - if (!core.flags.enableAddPoint || !core.isset(point) || point<=0) return []; - - // 加点,返回一个choices事件 - return [ - {"type": "choices", - "choices": [ // 提供三个选项:对于每一点,攻击+1/防御+2/生命+200 - {"text": "攻击+"+(1*point), "action": [ - {"type": "setValue", "name": "status:atk", "value": "status:atk+"+(1*point)} - ]}, - {"text": "防御+"+(2*point), "action": [ - {"type": "setValue", "name": "status:def", "value": "status:def+"+(2*point)} - ]}, - {"text": "生命+"+(200*point), "action": [ - {"type": "setValue", "name": "status:hp", "value": "status:hp+"+(200*point)} - ]}, - ] - } - ]; +```js +// 如果有加点 +var point = core.material.enemys[enemyId].point; +if (core.flags.enableAddPoint && point > 0) { + core.push(todo, [{ "type": "insert", "name": "加点事件", "args": [point] }]); } ``` @@ -2062,42 +1965,14 @@ if (core.getFlag("door",0)==2) { "textInList": "1F金币商店", // 在快捷商店栏中显示的名称 "use": "money", // 商店所要使用的。只能是"money"或"experience"。 "commonTimes": true, // 是否使用全局次数 - "mustEnable": true, // 如果未开启则不显示在状态栏中 - "need": "20+10*times*(times+1)", // 商店需要的金币/经验数值;可以是一个表达式,以times作为参数计算。 - // 这里用到的times为该商店的已经的访问次数。首次访问该商店时times的值为0。 - // 上面的例子是50层商店的计算公式。你也可以写任意其他的计算公式,只要以times作为参数即可。 - // 例如: "need": "25" 就是恒定需要25金币的商店; "need": "20+2*times" 就是第一次访问要20金币,以后每次递增2金币的商店。 - // 如果是对于每个选项有不同的计算公式,写 "need": "-1" 即可。可参见下面的经验商店。 - "text": "勇敢的武士啊,给我${need}金币就可以:", // 显示的文字,需手动加换行符。可以使用${need}表示上面的need值。 + "mustEnable": false, // 如果未开启则不显示在状态栏中 + "need": "20+10*times*(times+1)", // 商店需要的金币/经验数值;可以是一个表达式,以times(访问次数)作为参数计算。 + "text": "勇敢的武士啊,给我${need}金币就可以:", // 显示的文字。可以使用${need}表示上面的need值。 "choices": [ // 商店的选项 - {"text": "生命+800", "effect": "status:hp+=800"}, - // 如果有多个effect以分号分开,参见下面的经验商店 - {"text": "攻击+4", "effect": "status:atk+=4"}, - {"text": "防御+4", "effect": "status:def+=4"}, - {"text": "魔防+10", "effect": "status:mdef+=10"} - // effect可以对status,item和flag进行操作。 - // 必须是X+=Y的形式,其中Y可以是一个表达式,以status:xxx, item:xxx或flag:xxx为参数 - // 其他effect样例: - // "item:yellowKey+=1" 黄钥匙+1 - // "item:pickaxe+=3" 破墙镐+3 - // "status:hp+=2*(status:atk+status:def)" 将生命提升攻防和的数值的两倍 - ] - }, - { - "id": "expShop1", // 商店唯一ID - "name": "经验之神", - "icon": "pinkShop", - "textInList": "1F经验商店", - "use": "experience", // 该商店使用的是经验进行计算 - "need": "-1", // 如果是对于每个选项所需要的数值不同,这里直接写-1,然后下面选项里给定具体数值 - "text": "勇敢的武士啊,给我若干经验就可以:", - "choices": [ - // 在choices中写need,可以针对每个选项都有不同的需求。 - // 这里的need同样可以以times作为参数,比如 "need": "100+20*times" - {"text": "等级+1", "need": "100", "effect": "status:lv+=1;status:hp+=1000;status:atk+=7;status:def+=7"}, - // 多个effect直接以分号分开即可。如上面的意思是生命+1000,攻击+7,防御+7。 - {"text": "攻击+5", "need": "30", "effect": "status:atk+=5"}, - {"text": "防御+5", "need": "30", "effect": "status:def+=5"}, + // effect可以对status,item和flag进行操作;必须是X+=Y的形式,其中Y可以是一个表达式 + {"text": "生命+800", "effect": "status:hp+=800"}, // 生命+800 + {"text": "攻击+4", "need": 30, "effect": "status:atk+=4"}, // 规定具体的数值 + {"text": "防御+2,魔防+4", "effect": "status:def+=2;status:mdef+=4"}, // 多个效果用分号分开 ] } ], @@ -2119,14 +1994,15 @@ if (core.getFlag("door",0)==2) { - choices 为商店的各个选项,是一个list,每一项是一个选项 - text为显示文字。请注意这里不支持 ${} 的表达式计算。 - effect 为该选项的效果;effect必须是 `status:xxx+=yyy`, `item:xxx+=yyy`或`flag:xxx+=yyy`的形式。即中间必须是+=符号。 - - 如有多个effect(例如升级全属性提升),使用分号分开,参见经验商店的写法。 + - 如有多个effect(例如升级全属性提升),使用分号分开。 像这样定义了全局商店后,即可在快捷栏中看到。 请注意,快捷商店默认是不可被使用的。直到至少调用一次自定义事件中的 `{"type": "openShop"}` 打开商店后,才能真正在快捷栏中被使用。 ``` js -"1,0": [ // 金币商店 +// 事件列表 +[ // 打开商店前,你也可以添加自己的剧情 // 例如,通过if来事件来判断是不是第一次访问商店,是的则显示一段文字(类似宿命的华音那样) {"type": "openShop", "id": "moneyShop1"}, // 这里的id要和data.js中你定义的商店ID完全一致 @@ -2143,6 +2019,27 @@ if (core.getFlag("door",0)==2) { 另外需要注意的一点就是,每层楼都有一个 canUseQuickShop 选项。如果该选项置为false则无法在该层使用快捷商店。 +**从V2.6开始,也提出了“公共事件化的全局商店”,即打开使用全局商店实际上是执行一个公共事件。** + +```js +"shops": [ + // 定义公共事件化的全局商店 + { + "id": "keyShop1", // 商店唯一ID + "textInList": "回收钥匙商店", // 在快捷商店栏中显示的名称 + "mustEnable": false, // 如果未开启则不显示在状态栏中 + "commonEvent": "回收钥匙商店", // 公共事件名 + "args": [], // 向该公共事件传递的参数 + } +] +``` + +`id`, `textInList`, `mustEnable`和上述完全相同。 + +`commonEvent`为公共事件名,即选择此项时要执行的公共事件。 + +`args`为向该公共事件传递的参数,参见[type:insert](#insert:插入公共事件或另一个地点的事件并执行)的说明。 + ## 系统引发的自定义事件 我们知道,所有自定义事件都是需要定义在`"x,y"`处,并且得让用户经过或撞上才能触发的。 @@ -2181,17 +2078,13 @@ if (core.getFlag("door",0)==2) { !> 多个机关门请分别设置开门变量如door1, door2等等。请勿存在两个机关门用相同的变量! -同样,为了实现类似于RMXP中,到达某一层后自动触发某段事件的效果,样板中还存在`firstArrive`事件。 - -当且仅当勇士第一次到达某层时,将会触发此事件。可以利用此事件来显示一些剧情,或再让它调用 `{"type": "trigger"}` 来继续调用其他的事件。 +除此以外,每层楼还提供了`firstArrive`和`eachArrive`事件,分别为首次到达该楼层和每次到达该楼层时执行的事件。 ## 使用炸弹后的事件 上面的afterBattle事件只对和怪物进行战斗后才有会被处理。 -如果我们想在使用炸弹后也能触发一些事件(如开门),则可以在`functions.js`里面的`afterUseBomb`函数进行处理: - -!> V2.0版本可以直接在“脚本编辑 - 使用炸弹后的事件”中双击进行修改! +如果我们想在使用炸弹后也能触发一些事件(如开门),则可以在脚本编辑里面的`afterUseBomb`函数进行处理: ``` js ////// 使用炸弹/圣锤后的事件 ////// @@ -2207,47 +2100,42 @@ if (core.getFlag("door",0)==2) { } ``` -## 滑冰和推箱子事件 +## 滑冰事件 -最新的样板还支持滑冰和推箱子事件。 +从V2.6开始,滑冰事件被重写。现在的滑冰由公共事件执行。 -滑冰事件的数字是167,trigger为ski。 +在新版本中,冰面应该放在背景层上,上面可以放置道具、怪物、门等图块。 -当角色走上冰面时,将触发ski事件,并会一直向前滑行,直到撞上不可通行的块会触发事件(比如撞上怪物会触发battle,撞上门会触发openDoor等等),或者离开冰面为止。 +角色走上冰面后,将一直向前滑行,直到撞上不可通行的图块,或触发事件为止。 -!> 由于H5魔塔只有事件一层,因此滑冰的冰面上将无法摆放任何东西(如怪物,门或道具等);不过可以在战后/开门后/道具后的事件写转变图块成167,从而继续滑冰。 +如果撞上怪物将自动进行战斗,此战斗是强制的,打不过将直接死亡。 -!> 撞上怪物将触发battle进行战斗,该战斗是强制战斗,打不过将直接死亡。 +默认情况下,拾取冰面上道具后将停止滑冰行为。如果要继续滑冰,请在`afterGetItem`中插入公共事件:滑冰事件。打怪和开门同理。 + +!> 滑冰图块的数字是167,请勿修改此数字! + +## 推箱子事件 关于推箱子,存在三种状态:花(168),箱子(169)和已经推到花的箱子(170)。 !> 推箱子的前方不允许存在任何事件(花除外),包括已经禁用的自定义事件。 -推完箱子后将触发functions.js中的afterPushBox事件,你可以在这里进行开门判断。 +推完箱子后将触发脚本编辑中的afterPushBox函数,你可以在这里进行开门判断。 ``` js ////// 推箱子后的事件 ////// "afterPushBox" = function () { - - var noBoxLeft = function () { - // 地图上是否还存在未推到的箱子,如果不存在则返回true,存在则返回false - for (var i=0;i 如果reason不为空,则将会作为结局名! - -当失败(`{"type": "lose"}`,或者被怪强制战斗打死、被领域怪扣血死、中毒导致扣血死,路障导致扣血死等等)事件发生时,将调用`events.js`中的`lose`事件。其直接显示一段文字,并重新开始游戏。 - -``` js -////// 游戏失败事件 ////// -"lose": function(reason) { - core.ui.closePanel(); - var replaying = core.isReplaying(); - core.stopReplay(); - core.waitHeroToStop(function() { - core.drawText([ - "\t[结局1]你死了。\n如题。" - ], function () { - core.events.gameOver(null, replaying); - }); - }) -} -``` - -其参数reason为失败原因。你可以在这里修改失败界面时显示的文字。 - ========================================================================================== [继续阅读下一章:个性化](personalization) diff --git a/_docs/personalization.md b/_docs/personalization.md index f960eed9..80944d06 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -1,6 +1,6 @@ # 个性化 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * 有时候只靠样板本身可能是不够的。我们需要一些个性化、自定义的素材,道具效果,怪物属性,等等。 @@ -21,10 +21,14 @@ HTML5魔塔是使用画布(canvas)来绘制,存在若干个图层,它们 - route**[D]**:路线层;主要用来绘制勇士的行走路线图。 (z-index: 95) - paint**[D]**:绘图层;主要用来进行绘图模式。(z-index: 95) - curtain:色调层;用来控制当前楼层的画面色调 (z-index: 125) -- image1\~50**[D]**:图片层;用来绘制图片等操作。(z-index: 100+code, 101~150;也就是图片编号在1~25的在色调层之下,26~50的在色调层之上) -- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 160) +- image1\~50**[D]**:图片层;用来绘制图片等操作。(z-index: 100+code, 101~150) +- ui:UI层;用来绘制一切UI窗口,如剧情文本、怪物手册、楼传器、系统菜单等等 (z-index: 140) - data:数据层;用来绘制一些顶层的或更新比较快的数据,如左上角的提示,战斗界面中数据的变化等等。 (z-index: 170) +请注意:显示图片事件将自动创建一个图片层,z-index是100+图片编号。 + +而,色调层的z-index是25,ui层的z-index是140;因此,图片编号在1~24的将被色调层遮挡,25~40的将被ui层遮挡,41~50的将遮挡UI层。 + ### 动态创建canvas 从V2.5.3开始,可以在H5样板中任意动态创建canvas并进行使用。 @@ -104,11 +108,11 @@ core.fillText('test', '这是一段文字', 10, 30, '#FF0000', '16px Verdana'); 从V2.5.4开始,贴图也允许进行帧动画,只要设置第五项的数值。 ``` js -"images": [[96,120,"bg.jpg",0]], // 背景图;你可以选择一张或多张图片来作为背景/前景素材。 -"images": [], // 无任何背景图 -"images": [[32,32,"house.png",0], [160,170,"bed.png",1]] // 在(32,32)放一个house.png在背景层,且(160,170)放bed.png在前景层 -"images": [[96,120,"tree.png",2]] // 如果写2,则会自动调节遮挡效果 -"images": [[64,0,"x.png",1,4]] // 这是一个前景层的4帧动画贴图 +[[96,120,"bg.jpg",0]] // 背景图;你可以选择一张或多张图片来作为背景/前景素材。 +[] // 无任何背景图 +[[32,32,"house.png",0], [160,170,"bed.png",1]] // 在(32,32)放一个house.png在背景层,且(160,170)放bed.png在前景层 +[[96,120,"tree.png",2]] // 如果写2,则会自动调节遮挡效果 +[[64,0,"x.png",1,4]] // 这是一个前景层的4帧动画贴图 ``` images为一个数组,代表当前层所有作为背景素材的图片信息。每一项为一个五元组,分别为该背景素材的x,y,图片名,遮挡方式和帧数。 @@ -129,18 +133,21 @@ images为一个数组,代表当前层所有作为背景素材的图片信息 关于楼层贴图和前景、背景层的层叠覆盖关系,默认是:**地板 - 背景贴图 - 背景图块 - 事件 - 勇士 - 前景贴图 - 前景图块**。 -可以通过修改`libs/maps.js`的`drawMap`函数中下面三行的顺序来改变其覆盖关系。 +可以通过修改`libs/maps.js`的`drawBg`和`drawFg`函数来改变其覆盖关系。 ``` js -// ----- 可以调整这三行的顺序来修改覆盖关系;同层画布上,后绘制的覆盖先绘制的 -// ----- ui.js的drawThumbnail函数也需要对应进行修改。 - -// 绘制楼层贴图 -core.maps.drawFloorImages(floorId, images); -// 绘制背景层图块 -core.maps.drawBgFgMap(floorId, core.canvas.bg, "bg", true); -// 绘制前景层图块 -core.maps.drawBgFgMap(floorId, core.canvas.fg, "fg", true); +////// 绘制背景层 ////// +maps.prototype.drawBg = function (floorId, ctx) { + var onMap = ctx == null; + if (onMap) { + ctx = core.canvas.bg; + core.clearMap(ctx); + } + this._drawBg_drawBackground(floorId, ctx); + // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 + this._drawFloorImages(floorId, ctx, 'bg'); + this._drawBgFgMap(floorId, ctx, 'bg', onMap); +} ``` 楼层贴图可以被事件隐藏和显示,详见[隐藏贴图](event#hideFloorImg:隐藏贴图)的写法。 @@ -192,7 +199,7 @@ ID必须由数字字母下划线组成,数字在1000以内,且均不能和 之后刷新编辑器即可。 -对于怪物和道具,我们也可以进行自动注册,只需要点击“自动注册”按钮,将对该栏下所有未注册的素材进行自动注册(自动分配ID和数字)。 +我们也可以进行自动注册,只需要点击“自动注册”按钮,将对该栏下所有未注册的素材进行自动注册(自动分配ID和数字)。 素材注册完毕后,即可在游戏中正常使用,也可以被地图生成器所识别(需要重开地图生成器)。 @@ -206,85 +213,6 @@ ID必须由数字字母下划线组成,数字在1000以内,且均不能和 2. 下拉框选择autotile,然后点“追加” 3. 看到成功的提示后刷新编辑器即可。 - - - -### 地图生成器使用自定义素材 - -地图生成器是直接从js文件中读取数字-图标对应关系的。 - -因此,在你修改了icons.js和maps.js两个文件,也就是将素材添加到游戏后,地图生成器的对应关系也将同步更新。 - ### 额外素材 从V2.4.2开始,HTML5魔塔样板开始支持额外素材。 @@ -300,6 +228,7 @@ ID必须由数字字母下划线组成,数字在1000以内,且均不能和 **该素材的宽高必须都是32的倍数,且图片上的总图块数不超过1000(即最多有1000个32*32的图块在该图片上)。** ```js +// 在全塔属性中的tilesets导入素材 "tilesets": ["1.png", "2.png"] // 导入两个额外素材,文件名分别是1.png和2.png ``` @@ -350,19 +279,6 @@ core.status.hero.atk += core.values.redJewel + 2*ratio 具体过程比较复杂,需要一定的JS能力,在这里就不多说了,有需求可以找`艾之葵`进行了解。 -但值得一提的是,我们可以使用`core.hasItem(name)` 来判断是否某个道具是否存在。例如下面是passNet(通过路障处理)的一部分: - -``` js -/****** 经过路障 ******/ -events.prototype.passNet = function (data) { - // 有鞋子 - if (core.hasItem('shoes')) return; - if (data.event.id=='lavaNet') { // 血网 -// ... 下略 -``` - -我们进行了一个简单的判断,如果拥有绿鞋,则不进行任何路障的处理。 - ### 实战!拿到神圣盾后免疫吸血、领域、夹击效果 1. 在itemEffect中修改拿到神圣盾时的效果,标记一个自定义Flag。 @@ -444,86 +360,9 @@ control.prototype.useFly = function (need) { ``` 修改时,请先把`null`改成空字符串`""`,然后再双击进行编辑。 - - ## 自定义怪物属性 -如果你对现有的怪物不满意,想自行添加怪物属性也是可以的。具体参见脚本编辑-getSpecials。 +如果你对现有的怪物不满意,想自行添加怪物属性也是可以的。具体参见脚本编辑的getSpecials。 你需自己指定一个special数字,修改属性名和属性提示文字。后两者可以直接写字符串,或写个函数传入怪物。 @@ -552,7 +391,8 @@ case 89: // 使用该按键的keyCode,比如Y键就是89 // ... 在这里写你要执行脚本 // **强烈建议所有新增的自定义快捷键均能给个对应的道具可点击,以方便手机端的行为** if (core.hasItem('...')) { - core.useItem('...'); + core.status.route.push("key:0"); // 记录按键到录像中 + core.useItem('...', true); // 第二个参数true代表该次使用道具是被按键触发的,使用过程不计入录像 } break; @@ -560,6 +400,10 @@ case 89: // 使用该按键的keyCode,比如Y键就是89 强烈建议所有新增的自定义快捷键均给个对应的永久道具可点击,以方便手机端的行为。 +使用`core.status.route.push("key:"+keyCode)`可以将这次按键记录在录像中。 + +!> 如果记录了按键,且使用道具的话,需要将useItem的第二个参数设为true,避免重复记录! + 可以使用altKey来判断Alt键是否被同时按下。 ## 公共事件 @@ -574,13 +418,9 @@ case 89: // 使用该按键的keyCode,比如Y键就是89 ## 插件系统 -在H5中,提供了“插件”系统。具体参见“脚本编辑 - 插件编写”。 +在H5中,提供了“插件”系统。在V2.6中提供了一个插件下拉框,用户可以自行创建和写插件。 -![插件编写](./img/plugin.png) - -当我们在这上面定义了自己需要的函数(插件后),就可以通过任何方式进行调用。 - -在这个插件编写的过程中,我们可以使用任何[常见API](api)里面的代码调用;也可以通过`core.insertAction`来插入自定义事件执行。 +在插件编写的过程中,我们可以使用任何[常见API](api)里面的代码调用;也可以通过`core.insertAction`来插入自定义事件执行。 下面是一个很简单的例子,我编写一个插件函数,其效果是让勇士生命值变成原来的x倍,并令面前的图块消失。 @@ -599,11 +439,13 @@ this.myfunc = function(x) { 网站上也提供了一个[插件库](https://h5mota.com/plugins/),欢迎大家把自己写的插件进行共享。 +从V2.6开始,在插件中用`this.xxx`定义的函数将会被转发到core中。例如上述的`myfunc`除了`core.plugin.myfunc`外也可以直接`core.myfunc`调用。 + +详见[函数转发](api#函数转发)。 + ## 标题界面事件化 -从V2.5.3开始,我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、 - -全塔属性,flags中的startUsingCanvas可以决定是否开启标题界面事件化。 +从V2.5.3开始,我们可以将标题界面的绘制和游戏开始用事件来完成。可以通过绘制画布、全塔属性,flags中的startUsingCanvas可以决定是否开启标题界面事件化。 然后就可以使用“事件流”的形式来绘制标题界面、提供选项等等。 @@ -619,36 +461,70 @@ this.myfunc = function(x) { 从V2.5.3以后,我们可以给手机端增加按键了,这样将非常有利于技能的释放。 -当用户在竖屏模式下点击工具栏,就会在工具栏按钮和快捷键模式之间进行切换。 +用户在菜单栏打开“拓展键盘”后,在竖屏模式下点击工具栏,就会在工具栏按钮和快捷键模式之间进行切换。 -切换到快捷键模式后,可以点1-7,分别等价于在电脑端按键1-7。 +切换到快捷键模式后,可以点1-8,分别等价于在电脑端按键1-8。 可以在脚本编辑的onKeyUp中定义每个快捷键的使用效果,比如使用道具或释放技能等。 -默认值下,1使用破,2使用炸,3使用飞,4使用其他存在的道具,5-7未定义。可以相应修改成自己的效果。 +默认值下,1使用破,2使用炸,3使用飞,4使用其他存在的道具,5-8未定义。可以相应修改成自己的效果。 -也可以替换icons.png中的对应图标,以及修改main.js中`main.statusBar.image.btn1~7`中的onclick事件来自定义按钮和对应按键。 +也可以替换icons.png中的对应图标,以及修改main.js中`main.statusBar.image.btn1~8`中的onclick事件来自定义按钮和对应按键。 非竖屏模式下、回放录像中、隐藏状态栏中,将不允许进行切换。 -## 自定义状态栏(新增显示项) +## 自绘状态栏 + +从V2.5.3开始允许自绘状态栏。要自绘状态栏,则应该打开全塔属性中的`statusCanvas`开关。 + +自绘模式下,全塔属性中的`statusCanvasRowsOnMobile`将控制竖屏模式下的状态栏行数。 + +开启自绘模式后,可以在脚本编辑的`drawStatusBar`中自行进行绘制。 + +横屏模式下的状态栏为`129x416`(15x15则是`149x480`);竖屏模式下的状态栏为`416*(32*rows+9)`(15x15是480)。 + +具体可详见脚本编辑的`drawStatusBar`函数。 + +## 自定义状态栏的显示项 在V2.2以后,我们可以自定义状态栏背景图(全塔属性 - statusLeftBackground)等等。 但是,如果我们还想新增其他项目的显示,比如攻速或者暴击,该怎么办? -需要进行如下几个操作: +我们可以[自绘状态栏](#自绘状态栏),或者采用下面两个方式之一来新增。 + +### 利用已有项目 + +一个最为简单的方式是,直接利用已有项目。 + +例如,如果本塔中没有技能栏,则可以使用技能栏所对应的显示项。 + +1. 覆盖project/icons.png中技能的图标 +2. 打开全塔属性的enableSkill开关 +3. 在脚本编辑-updateStatusBar中可以直接替换技能栏的显示内容 + +``` + // 设置技能栏 + if (core.flags.enableSkill) { + // 替换成你想显示的内容,比如你定义的一个flag:abc。 + core.setStatusBarInnerHTML('skill', core.getFlag("abc", 0)); + } +``` + +### 额外新增新项目 + +如果是在需要给状态栏新定义项目,则需要进行如下几个操作: 1. 定义ID;比如攻速我就定义speed,暴击可以简单的定义baoji;你也可以定义其他的ID,但是不能和已有的重复。这里以speed为例。 -2. 在index.html的statusBar中(44行起),进行该状态栏项的定义。仿照其他几项,插在其应当显示的位置,注意替换掉相应的ID。 +2. 在index.html的statusBar中(46行起),进行该状态栏项的定义。仿照其他几项,插在其应当显示的位置,注意替换掉相应的ID。 ``` html

``` -3. 在editor.html中的statusBar(323行起),仿照第二点同样添加;这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。 -4. 使用便捷PS工具,打开icons.png,新增一行并将魔力的图标P上去;记下其索引比如37(从0开始数)。 +3. 在editor.html中的statusBar(383行起),仿照第二点同样添加;这一项如果不进行则会地图编辑器报错。editor-mobile.html同理。 +4. 使用便捷PS工具,打开project/icons.png,新增一行并将魔力的图标P上去;记下其索引比如37(从0开始数)。 5. 在main.js的this.statusBar中增加图片、图标和内容的定义。 ``` js this.statusBar = { @@ -674,17 +550,15 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0); ## 技能塔的支持 -其实,在HTML5上制作技能塔是完全可行的。 - 要支持技能塔,可能需要如下几个方面: +从V2.5开始,内置了"二倍斩"技能,可以仿照其制作自己的技能。 + - 魔力(和上限)的添加;技能的定义 - 状态栏的显示 - 技能的触发(按键与录像问题) - 技能的效果 -从V2.5开始,内置了"二倍斩"技能,可以仿照其制作自己的技能。 - ### 魔力的定义添加;技能的定义 从V2.5开始,提供了status:mana选项,可以直接代表当前魔力值。 @@ -697,6 +571,8 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0); 如果flag:skill不为0,则代表当前处于某个技能开启状态,且状态栏显示flag:skillName值。伤害计算函数中只需要对flag:skill进行处理即可。 +!> 关于魔力上限:样板中默认没有提供status:manamax + ### 状态栏的显示 从V2.5开始,魔力值和技能名的状态栏项目已经被添加,可以直接使用。 @@ -706,9 +582,14 @@ core.statusBar.speed.innerHTML = core.getFlag('speed', 0); ``` js // 设置魔力值 if (core.flags.enableMana) { - // 也可以使用flag:manaMax来表示最大魔力值 - // core.status.hero.mana = Math.max(core.status.hero.mana, core.getFlag('manaMax', 10)); - // core.statusBar.mana.innerHTML = core.status.hero.mana + "/" + core.getFlag('manaMax', 10); + // status:manamax 只有在非负时才生效。 + if (core.status.hero.manamax != null && core.status.hero.manamax >= 0) { + core.status.hero.mana = Math.min(core.status.hero.mana, core.status.hero.manamax); + core.setStatusBarInnerHTML('mana', core.status.hero.mana + "/" + core.status.hero.manamax); + } + else { + core.setStatusBarInnerHTML("mana", core.status.hero.mana); + } } // 设置技能栏 if (core.flags.enableSkill) { @@ -761,14 +642,15 @@ else { // 关闭技能 case 87: // W:开启技能“二倍斩” // 检测技能栏是否开启,是否拥有“二倍斩”这个技能道具 if (core.flags.enableSkill && core.hasItem('skill1')) { - core.useItem('skill1'); + core.status.route.push("key:87"); + core.useItem('skill1', true); } break; ``` 在勇士处于停止的条件下,按下W键时,判断技能的道具是否存在,如果存在再使用它。 -!> 1,2,3这三个键被默认绑定到了破炸飞;如果想用的话也是一样,只不过是把已有的实现进行替换。 +!> 由于现在手机端存在拓展键盘,也强烈建议直接覆盖1-8的使用效果,这样手机端使用也非常方便。 ### 技能的效果 @@ -816,141 +698,6 @@ if (core.flags.enableSkill) { 通过上述这几种方式,我们就能成功的让H5支持技能啦! -## 成就系统 - -我们还可以给HTML5魔塔增加成就系统。注意到成就是和游戏相关,因此需要使用getLocalStorage而不是getFlag判定。 - -可将下面的代码粘贴到脚本编辑 - 插件编写中。 - -``` js -// 所有成就项的定义 -this.achievements = [ - // 每行一个,分别定义flag、名称、描述、是否存在提示、成就点数 - {"flag": "a1", "name": "成就1", "text": "成就1的达成描述", "hint": false, "point": 1}, - // 可以继续往后新增其他的。 -]; - -// 达成成就;如 core.plugin.achieve("a1") 即达成a1对应的成就 -this.achieve = function (flag) { - // 获得已达成的成就;如果跟存档而不是跟游戏则改成getFlag - var achieved = core.getLocalStorage("achievements", []); - var point = core.getLocalStorage("achievePoint", 0); - // 已经获得该成就 - if (achieved.indexOf(flag)>=0) return; - // 尝试达成成就;找到对应的成就项 - this.achievements.forEach(function (one) { - if (one.flag == flag) { - // 执行达成成就的操作;也可以自行在上面加上达成成就后的事件 - core.insertAction("\t[达成成就:"+one.name+"]"+one.text); - point += one.point || 0; - } - }); - achieved.push(flag); - // 存入localStorage中;如果跟存档走则使用setFlag - core.setLocalStorage("achievements", achieved); - core.setLocalStorage("achievePoint", point); -} - -// 获得所有成就说明;这里简单使用两个insertAction,你也可以修改成自己的实现 -// 简单一点的可以使用insertAction+剧情文本;稍微复杂一点的可以使用图片化文本等;更复杂的可以自绘UI。 -this.getAchievements = function () { - var achieved = core.getLocalStorage("achievements", []); - var yes = [], no = []; - // 对所有成就进行遍历 - this.achievements.forEach(function (one) { - // 检测是否达成 - if (achieved.indexOf(one.flag)>=0) { - yes.push(one.name+":"+one.text); - } - else { - no.push(one.name+":"+(one.hint?one.text:"达成条件请自行探索")); - } - }); - core.insertAction([ - "\t[已达成的成就]"+(yes.length==0?"暂无":yes.join("\n")), - "\t[尚未达成的成就]"+(no.length==0?"暂无":no.join("\n")) - ]); -} -``` - - - -## 多角色的支持 - -其实,我们的样板还能支持多角色的制作。比如《黑·白·间》之类的塔也是完全可以刻的。 - -你只需要如下几步来达到多角色的效果。 - -1. 每个角色弄一张行走图。相关信息参见[自定义事件:setHeroIcon](event#setHeroIcon:更改角色行走图)。 -2. [覆盖楼传事件](#覆盖楼传事件),这样可以通过点工具栏的楼层传送按钮来切换角色。当然你也完全可以自己写一个道具,或[自定义快捷键](#自定义快捷键)来进行绑定。 -3. 将下述代码直接贴入脚本编辑 - 插件编写中。 - ``` js - // 所有需要保存的内容;这些保存的内容不会多角色共用,在切换时会进行恢复。 - // 你也可以自行新增或删除,比如不共用金币则可以加上"money"的初始化,不共用道具则可以加上"items"的初始化, - // 多角色共用hp的话则删除hp,等等。总之,不共用的属性都在这里进行定义就好。 - var hero1 = { // 1号勇士(默认的是0号) - "floorId": "MT0", // 该角色楼层ID - "icon": "hero1.png", // 角色的行走图名称 - "name": "1号角色", - "lv": 1, - "hp": 1000, - "atk": 10, - "def": 10, - "mdef": 0, - "loc": {"x": 0, "y": 0, "direction": "up"}, - // 如果道具不共用就将下面这句话取消注释 - // "items": {"keys":{"yellowKey":0,"blueKey":0,"redKey":0},"tools":{},"constants":{}} - } - // 也可以类似新增其他勇士 - // var hero2 = { ... - - var heroCount = 2; // 包含默认的在内总共多少个勇士,该值需手动修改。 - - // 初始化该勇士 - this.initHeros = function () { - core.status.hero.icon = "hero.png"; - core.setFlag("hero1", core.clone(hero1)); // 将属性值存到变量中 - // core.setFlag("hero2", core.clone(hero2)); // 更多的勇士... - } - - // 切换勇士 - this.changeHero = function (toHeroId) { - var currHeroId = core.getFlag("heroId", 0); // 获得当前角色ID - if (!core.isset(toHeroId)) { - toHeroId = (currHeroId+1)%heroCount; - } - if (currHeroId == toHeroId) return; - - var saveList = Object.keys(hero1); - - // 保存当前内容 - var toSave = {}; - saveList.forEach(function(name) { - if (name=='floorId') toSave[name] = core.status.floorId; // 楼层单独设置 - else toSave[name] = core.clone(core.status.hero[name]); // 使用core.clone()来创建新对象 - }) - - core.setFlag("hero"+currHeroId, toSave); // 将当前角色信息进行保存 - var data = core.getFlag("hero"+toHeroId); // 获得要切换的角色保存内容 - - // 设置角色的属性值 - saveList.forEach(function(name) { - if (name != 'floorId') - core.status.hero[name] = core.clone(data[name]); - }) - - // 插入事件:改变角色行走图并进行楼层切换 - core.insertAction([ - {"type": "setHeroIcon", "name": data.icon||"hero.png"}, // 改变行走图 - {"type": "changeFloor", "floorId": data.floorId, "loc": [data.loc.x, data.loc.y], - "direction": data.loc.direction, "time": 0} // 楼层切换事件 - ]) - core.setFlag("heroId", toHeroId); // 保存切换到的角色ID - } - ``` -3. 在脚本编辑 - setInitData中加上`core.plugin.initHeros()`来初始化新勇士。(写在`core.events.afterLoadData()`后,反大括号之前。) -4. 如果需要切换角色(包括事件、道具或者快捷键等),可以直接调用自定义JS脚本:`core.plugin.changeHero();`进行切换。也可以指定参数调用`core.plugin.changeHero(1)`来切换到某个具体的勇士上。 - ## 系统使用的flag变量 众所周知,自定义flag变量都可以任意定义并取用(未定义直接取用的flag默认值为0)。 diff --git a/_server/data.comment.js b/_server/data.comment.js index c4ad3175..c4b8b951 100644 --- a/_server/data.comment.js +++ b/_server/data.comment.js @@ -187,6 +187,11 @@ var data_comment_c456ea59_6018_45ef_8bcc_211a24c627dc = "_type": "textarea", "_data": "初始生命值" }, + "manamax": { + "_leaf": true, + "_type": "textarea", + "_data": "魔力上限;此项非负才会生效(null或小于0都不会生效)" + }, "mana": { "_leaf": true, "_type": "textarea", diff --git a/project/data.js b/project/data.js index 096e2dc6..ba2c9d99 100644 --- a/project/data.js +++ b/project/data.js @@ -78,6 +78,7 @@ var data_a1e2fb4a_e986_4524_b0da_9b7ba7c0874d = "lv": 1, "hpmax": 9999, "hp": 1000, + "manamax": -1, "mana": 0, "atk": 100, "def": 100, diff --git a/project/functions.js b/project/functions.js index 2044fe73..07507e3d 100644 --- a/project/functions.js +++ b/project/functions.js @@ -753,152 +753,156 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // keyCode:当前按键的keyCode(每个键的keyCode自行百度) // altKey:Alt键是否被按下,为true代表同时按下了Alt键 // 可以在这里任意增加或编辑每个按键的行为 - + // 如果处于正在行走状态,则不处理 - if (!core.status.heroStop || core.status.heroMoving > 0) + if (core.isMoving()) return; // Alt+0~9,快捷换上套装 - if (altKey && keyCode>=48 && keyCode<=57) { - core.items.quickLoadEquip(keyCode-48); + if (altKey && keyCode >= 48 && keyCode <= 57) { + core.items.quickLoadEquip(keyCode - 48); return; } // 根据keyCode值来执行对应操作 switch (keyCode) { - case 27: // ESC:打开菜单栏 - core.openSettings(true); - break; - case 88: // X:使用怪物手册 - core.openBook(true); - break; - case 71: // G:使用楼传器 - core.useFly(true); - break; - case 65: // A:读取自动存档(回退) - core.doSL("autoSave", "load"); - break; - case 83: // S:存档 - core.save(true); - break; - case 68: // D:读档 - core.load(true); - break; - case 69: // E:打开光标 - core.ui.drawCursor(); - break; - case 84: // T:打开道具栏 - core.openToolbox(true); - break; - case 81: // Q:打开装备栏 - core.openEquipbox(true); - break; - case 90: // Z:转向 - core.turnHero(); - break; - case 75: case 86: // V:打开快捷商店列表 - core.openQuickShop(true); - break; - case 32: // SPACE:轻按 - core.getNextItem(); - break; - case 82: // R:回放录像 - core.actions._clickSyncSave_replay(); - break; - case 33: case 34: // PgUp/PgDn:浏览地图 - core.ui.drawMaps(); - break; - case 77: // M:绘图模式 - core.ui.drawPaint(); - break; - case 66: // B:打开数据统计 - core.ui.drawStatistics(); - break; - case 72: // H:打开帮助页面 - core.ui.drawHelp(); - break; - case 78: // N:重新开始 - core.confirmRestart(); - break; - case 79: // O:查看工程 - core.actions._clickGameInfo_openProject(); - break; - case 80: // P:游戏主页 - core.actions._clickGameInfo_openComments(); - break; - case 49: // 快捷键1: 破 - if (core.hasItem('pickaxe')) { - if (core.canUseItem('pickaxe')) { - core.useItem('pickaxe'); - } - else { - core.drawTip('当前不能使用破墙镐'); - } + case 27: // ESC:打开菜单栏 + core.openSettings(true); + break; + case 88: // X:使用怪物手册 + core.openBook(true); + break; + case 71: // G:使用楼传器 + core.useFly(true); + break; + case 65: // A:读取自动存档(回退) + core.doSL("autoSave", "load"); + break; + case 83: // S:存档 + core.save(true); + break; + case 68: // D:读档 + core.load(true); + break; + case 69: // E:打开光标 + core.ui.drawCursor(); + break; + case 84: // T:打开道具栏 + core.openToolbox(true); + break; + case 81: // Q:打开装备栏 + core.openEquipbox(true); + break; + case 90: // Z:转向 + core.turnHero(); + break; + case 75: + case 86: // V:打开快捷商店列表 + core.openQuickShop(true); + break; + case 32: // SPACE:轻按 + core.getNextItem(); + break; + case 82: // R:回放录像 + core.actions._clickSyncSave_replay(); + break; + case 33: + case 34: // PgUp/PgDn:浏览地图 + core.ui.drawMaps(); + break; + case 77: // M:绘图模式 + core.ui.drawPaint(); + break; + case 66: // B:打开数据统计 + core.ui.drawStatistics(); + break; + case 72: // H:打开帮助页面 + core.ui.drawHelp(); + break; + case 78: // N:重新开始 + core.confirmRestart(); + break; + case 79: // O:查看工程 + core.actions._clickGameInfo_openProject(); + break; + case 80: // P:游戏主页 + core.actions._clickGameInfo_openComments(); + break; + case 49: // 快捷键1: 破 + if (core.hasItem('pickaxe')) { + if (core.canUseItem('pickaxe')) { + core.status.route.push("key:49"); // 将按键记在录像中 + core.useItem('pickaxe', true); // 第二个参数true代表该次使用道具是被按键触发的,使用过程不计入录像 + } else { + core.drawTip('当前不能使用破墙镐'); } - break; - case 50: // 快捷键2: 炸 - if (core.hasItem('bomb')) { - if (core.canUseItem('bomb')) { - core.useItem('bomb'); - } - else { - core.drawTip('当前不能使用炸弹'); - } + } + break; + case 50: // 快捷键2: 炸 + if (core.hasItem('bomb')) { + if (core.canUseItem('bomb')) { + core.status.route.push("key:50"); // 将按键记在录像中 + core.useItem('bomb', true); // 第二个参数true代表该次使用道具是被按键触发的,使用过程不计入录像 + } else { + core.drawTip('当前不能使用炸弹'); } - else if (core.hasItem('hammer')) { - if (core.canUseItem('hammer')) { - core.useItem('hammer'); - } - else { - core.drawTip('当前不能使用圣锤'); - } - - } - break; - case 51: // 快捷键3: 飞 - if (core.hasItem('centerFly')) { - core.ui.drawCenterFly(); - } - break; - case 52: // 快捷键4:破冰/冰冻/地震/上下楼器/... 其他道具依次判断 - { - var list = ["icePickaxe", "snow", "earthquake", "upFly", "downFly", "jumpShoes", "lifeWand", "poisonWine", "weakWine", "curseWine", "superWine"]; - for (var i=0;i= 0) { + core.status.hero.mana = Math.min(core.status.hero.mana, core.status.hero.manamax); + core.setStatusBarInnerHTML('mana', core.status.hero.mana + "/" + core.status.hero.manamax); + } + else { + core.setStatusBarInnerHTML("mana", core.status.hero.mana); + } } // 设置技能栏 if (core.flags.enableSkill) { From f65eab56f65d5462ae4cb7e751ca4a98034a6f4f Mon Sep 17 00:00:00 2001 From: oc Date: Sun, 31 Mar 2019 23:58:30 +0800 Subject: [PATCH 137/153] api docs --- _docs/_api.md | 689 +++++++++++++++++++++++++++++++++++++++ _docs/_sidebar.md | 2 +- _docs/api.md | 50 ++- _docs/element.md | 2 +- _docs/event.md | 4 +- _docs/img/console.jpg | Bin 0 -> 18716 bytes _docs/personalization.md | 4 +- _docs/start.md | 2 +- 8 files changed, 744 insertions(+), 9 deletions(-) create mode 100644 _docs/_api.md create mode 100644 _docs/img/console.jpg diff --git a/_docs/_api.md b/_docs/_api.md new file mode 100644 index 00000000..64362e3b --- /dev/null +++ b/_docs/_api.md @@ -0,0 +1,689 @@ +# 附录: API列表 + +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * + +**这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** + +如有任何疑问,请联系小艾寻求帮助。 + +可以在chrome浏览器的控制台中(`ctrl+shift+I`,找到Console)中直接进行调用,以查看效果。 + +**以下所有异步API都会加上[异步]的说明,存在此说明的请勿在事件处理的自定义脚本中使用。** + +!> 最常用的新手向命令,强烈建议每个人了解 + +``` text + +core.status.floorId +获得当前层的floorId。 + + +core.status.maps +获得所有楼层的地图信息。 + + +core.status.thisMap +获得当前楼层信息,其等价于core.status.maps[core.status.floorId]。 + + +core.floors +获得所有楼层的信息。例如core.floors[core.status.floorId].events可获得本楼层的所有自定义事件。 + + +core.status.hero +获得当前勇士状态信息。例如core.status.hero.atk就是当前勇士的攻击力数值。 + + +core.material.enemys +获得所有怪物信息。例如core.material.enemys.greenSlime就是获得绿色史莱姆的属性数据。 + + +core.material.items +获得所有道具的信息。 + + +core.debug() +开启调试模式。此模式下可以按Ctrl键进行穿墙,并忽略一切事件。 +此模式下不可回放录像和上传成绩。 + + +core.updateStatusBar() +立刻刷新状态栏和地图显伤。 + + +core.setStatus('atk', 1000) +将攻击力设置为1000;这里把atk可以改成hp, def, mdef, money, experience等等。 +本句等价于 core.status.hero.atk = 1000 + + +core.getStatus('atk') +返回当前攻击力数值。本句等价于 core.status.hero.atk。 + + +core.setHeroLoc('x', 5) +设置勇士位置。这句话的意思是将勇士当前位置的横坐标设置为5。 +同理可以设置勇士纵坐标 core.setHeroLoc('y', 3)。 +值得注意的是,这句话虽然会使勇士改变位置,但并不会使界面重新绘制;如需立刻重新绘制地图还需调用: +core.clearMap('hero'); core.drawHero(); +来对界面进行更新。 + + +core.setItem('pickaxe', 10) +将破墙镐个数设置为10个。这里可以写任何道具的ID。 + + +core.addItem('pickaxe', 2) +将破墙镐的个数增加2个,无任何特效。这里可以写任何道具的ID。 + + +core.getItem('pickaxe', 4) +令勇士获得4个破墙镐。这里可以写任何道具的ID。 +和addItem相比,使用getItem会播放获得道具的音效,也会在左上角绘制获得提示。 + + +core.removeItem('pickaxe', 3) +删除3个破墙镐。第二项可忽略,默认值为1。 + + +core.itemCount('pickaxe') +返回当前破墙镐的个数。这里可以写任何道具的ID。 + + +core.hasItem('pickaxe') +返回当前是否存在某个道具。等价于 core.itemCount('pickaxe')>0 。 + + +core.getEquip(0) +获得0号装备类型(武器)的当前装备的itemId。如果不存在则返回null。 +这里可以写任意装备类型,从0开始和全塔属性中的equipName一一对应。 + + +core.hasEquip('sword1') +获得当前某个具体的装备是否处于正在被装备状态。 + + +core.setFlag('xyz', 2) +设置某个flag/变量的值为2。这里可以写任何的flag变量名。 + + +core.getFlag('xyz', 7) +获得某个flag/变量的值;如果该变量不存在,则返回第二个参数。 +比如 core.getFlag('point', 2) 则获得变量point的值;如果该变量从未定义过则返回2。 + + +core.hasFlag('xyz') +返回是否存在某个变量且不为0。等价于 core.getFlag('xyz', 0)!=0 。 + + +core.removeFlag('xyz') +删除某个flag/变量。 + + +core.insertAction(list, x, y, callback) +插入并执行一段自定义事件。在这里你可以写任意的自定义事件列表,有关详细写法请参见文档-事件。 +x和y如果设置则覆盖"当前事件点"的坐标,callback如果设置则覆盖事件执行完毕后的回调函数。 +例如: core.insertAction(["楼层切换", {"type":"changeFloor", "floorId": "MT3"}]) +将依次显示剧情文本,并执行一个楼层切换的自定义事件。 +-------- +从V2.5.4开始提出了“公共事件”的说法,这里也可以插入一个公共事件名。 +例如:core.insertAction("毒衰咒处理") 将插入公共事件“毒衰咒处理”。 + + +core.changeFloor(floorId, stair, heroLoc, time, callback) [异步] +立刻切换到指定楼层。 +floorId为目标楼层ID,stair为到达的目标楼梯,heroLoc为到达的指定点,time为动画时间,callback为切换完毕后的回调。 +例如: +core.changeFloor('MT2', 'upFloor', null, 600) 切换到MT2层的上楼点,动画事件600ms +core.changeFloor('MT5', null, {'x': 3, 'y': 6}, 0) 无动画切换到MT5层的(3,6)位置。 + + +core.resetMap() +重置当前楼层地图和楼层属性。 +此函数参数有三种形式: + - 不加任何参数,表示重置当前层:core.resetMap() + - 加上一个floorId,表示重置某一层:core.resetMap("MT1") + - 使用一个数组,表示重置若干层:core.resetMap(["MT1", "MT2", "MT3"]) +--------------------------- +** 说明:从V2.5.5开始存档方式发生了改变,在编辑器修改了地图后现在将直接生效,无需再重置地图。 + +R +录像回放的快捷键;这不是一个控制台命令,但是也把它放在这里供使用。 +录像回放在修改地图或新增数据后会很有用。 + +``` + +!> 一些相对高级的命令,针对有一定脚本经验的人 + +``` text + +========== 可直接从core中调用的,最常被使用的函数 ========== +core.js实际上是所有API的入口(路由),核心API的实现在其他几个文件中,core.js主要进行转发操作。 + + +core.nextX(n) +获得勇士面向的第n个位置的x坐标,n可以省略默认为1(即正前方) + + +core.nextY(n) +获得勇士面向的第n个位置的y坐标,n可以省略默认为1(即正前方) + + +core.nearHero(x, y) +判断某个点是否和勇士的距离不超过1。 + + +core.openDoor(id, x, y, needKey, callback) [异步] +尝试开门操作。id为目标点的ID,x和y为坐标,needKey表示是否需要使用钥匙,callback为开门完毕后的回调函数。 +id可为null代表使用地图上的值。 +例如:core.openDoor('yellowDoor', 10, 3, false, function() {console.log("1")}) +此函数返回true代表成功开门,并将执行callback回调;返回false代表无法开门,且不会执行回调函数。 + + +core.battle(id, x, y, force, callback) [异步] +执行战斗事件。id为怪物的id,x和y为坐标,force为bool值表示是否是强制战斗,callback为战斗完毕后的回调函数。 +id可为null代表使用地图上的值。 +例如:core.battle('greenSlime', null, null, true) + + +core.trigger(x, y) [异步] +触发某个地点的事件。 + + +core.isReplaying() +当前是否正在录像播放中 + + +core.drawBlock(block) +重绘某个图块。block应为core.status.thisMap.blocks中的一项。 + + +core.drawMap(floorId, callback) +重绘某一层的地图。floorId为要绘制楼层的floorId,callback为绘制完毕后的回调函数。 + + +core.terrainExists(x, y, id, floorId) +检测某个点是否存在(指定的)地形。 +x和y为坐标;id为地形ID,可为null表示任意地形;floorId为楼层ID,可忽略表示当前楼层。 + + +core.enemyExists(x, y, id, floorId) +检测某个点是否存在(指定的)怪物。 +x和y为坐标;id为怪物ID,可为null表示任意怪物;floorId为楼层ID,可忽略表示当前楼层。 + + +core.getBlock(x, y, floorId, showDisable) +获得某个点的当前图块信息。 +x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 +showDisable如果为true,则对于禁用的点和事件也会进行返回。 +如果该点不存在图块,则返回null。 +否则,返回值如下: {"index": xxx, "block": xxx} +其中index为该点在该楼层blocks数组中的索引,block为该图块实际内容。 + + +core.getBlockId(x, y, floorId, showDisable) +获得某个点的图块ID。 +x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 +showDisable如果为true,则对于禁用的点和事件也会进行返回。 +如果该点不存在图块,则返回null,否则返回该点的图块ID。 + + +core.getBlockCls(x, y, floorId, showDisable) +获得某个点的图块cls。 +x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 +showDisable如果为true,则对于禁用的点和事件也会进行返回。 +如果该点不存在图块,则返回null,否则返回该点的图块cls。 + + +core.showBlock(x, y, floorId) +将某个点从禁用变成启用状态。 + + +core.hideBlock(x, y, floorId) +将某个点从启用变成禁用状态,但不会对其进行删除。 +此函数不会实际将该块从地图中进行删除,而是将该点设置为禁用,以供以后可能的启用事件。 + + +core.removeBlock(x, y, floorId) +将从启用变成禁用状态,并尽可能将其从地图上删除。 +和hideBlock相比,如果该点不存在自定义事件(比如门或普通的怪物),则将直接从地图中删除。 +如果存在自定义事件,则简单的禁用它,以供以后可能的启用事件。 + + +core.setBlock(number, x, y, floorId) +改变图块。number为要改变到的图块数字,x和y为坐标,floorId为楼层ID,可忽略表示当前楼层。 + + +core.useItem(itemId, noRoute, callback) +尝试使用某个道具。itemId为道具ID,noRoute如果为真则该道具的使用不计入录像。 +callback为成功或失败后的回调。 + + +core.canUseItem(itemId) +返回当前能否使用某个道具。 + + +core.loadEquip(itemId, callback) +装备上某个装备。itemId为装备的ID,callback为成功或失败后的回调。 + + +core.unloadEquip(equipType, callback) +卸下某个部位的装备。equipType为装备类型,从0开始;callback为成功或失败后的回调。 + + +core.getNextItem() +轻按。 + + +core.drawTip(text, itemIcon) +在左上角绘制一段提示信息,2秒后消失。itemIcon为道具图标的索引。 + + +core.drawText(contents, callback) [异步] +绘制一段文字。 +不推荐使用此函数,尽量使用core.insertAction(contents)来显示剧情文本。 + + +core.closePanel() +结束一切事件和绘制,关闭UI窗口,返回游戏进程。 + + +core.replaceText(text) +将一段文字中的${}进行计算并替换。 + + +core.calValue(value, prefix, need, times) +计算表达式的实际值。这个函数可以传入status:atk等这样的参数。 + + +core.getLocalStorage(key, defaultValue) +从localStorage中获得某个数据(已被parse);如果对应的key不存在则返回defaultValue。 + + +core.getLocalForage(key, defaultValue, successCallback, errorCallback) +从localForage中获得某个数据(已被parse),如果对应的key不存在则返回defaultValue。 +如果成功则通过successCallback回调,失败则通过errorCallback回调。 + + +core.hasSave(index) +判定当前某个存档位是否存在存档,返回true/false。 +index为存档编号,0代表自动存档,大于0则为正常的存档位。 + + +core.clone(data) +深拷贝某个对象。 + + +core.isset(x) +测试x是否不为null,不为undefined也不为NaN。 + + +core.rand(num) +使用伪种子生成伪随机数。该随机函数能被录像支持。 +num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到1之间的浮点数。 +此函数为伪随机算法,SL大法无效。(即多次SL后调用的该函数返回的值都是相同的。) + + +core.rand2(num) +使用系统的随机数算法得到的随机数。该随机函数能被录像支持。 +num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到2147483647之间的整数。 +此函数使用了系统的Math.random()函数,支持SL大法。 +但是,此函数会将生成的随机数值存入录像,因此如果调用次数太多则会导致录像文件过大。 + + +core.restart() [异步] +返回标题界面。 + + +========== core.actions.XXX 和游戏控制相关的函数 ========== +actions.js主要用来进行用户交互行为的处理。 +所有用户行为,比如按键、点击、滑动等等,都会被此文件接收并进行操作。 + + +========== core.control.XXX 和游戏控制相关的函数 ========== +control.js主要用来进行游戏控制,比如行走控制、自动寻路、存读档等等游戏核心内容。 + +core.control.setGameCanvasTranslate(canvasId, x, y) +设置大地图的偏移量 + + +core.control.updateViewport() +更新大地图的可见区域 + + +core.control.gatherFollowers() +立刻聚集所有的跟随者 + + +core.control.replay() +回放下一个操作 + + +========== core.enemys.XXX 和怪物相关的函数 ========== +enemys.js主要用来进行怪物相关的内容,比如怪物的特殊属性,伤害和临界计算等。 + + +core.enemys.hasSpecial(special, test) +测试怪物是否含有某个特殊属性。 +常见用法: core.enemys.hasSpecial(monster.special, 3) ## 测试是否拥有坚固 + + +core.enemys.getSpecialText(enemyId) +返回一个列表,包含该怪物ID对应的所有特殊属性。 + + +core.enemys.getSpecialHint(enemy, special) +获得怪物某个(或全部)特殊属性的文字说明。 + + +core.enemys.canBattle(enemyId, x, y, floorId) +返回当前能否战胜某个怪物。 +后面三个参数是怪物坐标和楼层。 + + +core.enemys.getDamage(enemyId, x, y, floorId) +返回当前对某个怪物的战斗伤害。如果无法战斗,返回null。 +后面三个参数是怪物坐标和楼层。 + + +core.enemys.getExtraDamage(enemyId) +返回某个怪物会对勇士造成的额外伤害(不可被魔防抵消),例如仇恨、固伤等等。 + + +core.enemys.nextCriticals(enemyId, number, x, y, floorId) +返回一个列表,为接下来number(可忽略,默认为1)个该怪物的临界值和临界减伤。 +列表每一项类似 [x,y] 表示临界值为x,且临界减伤为y。 +如果无临界值,则返回空列表。 + + +core.enemys.getDefDamage(enemyId, k, x, y, floorId) +获得k(可忽略,默认为1)防减伤值。 + + +core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) +获得实际战斗信息,比如伤害,回合数,每回合伤害等等。 +此函数是实际战斗过程的计算。 + + +core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) +获得在某个勇士属性下怪物伤害;实际返回的是上面getDamageInfo中伤害的数值。 + + +core.enemys.getCurrentEnemys(floorId) +获得某一层楼剩余所有怪物的信息(供怪物手册使用) + + +========== core.events.XXX 和事件相关的函数 ========== +events.js主要用来进行事件处理,比如自定义事件,以及某些条件下可能会被触发的事件。 +大多数事件API都在脚本编辑中存在,这里只列出部分比较重要的脚本编辑中不存在的API。 + + +core.events.gameOver(ending, fromReplay) +游戏结束并上传的事件。 +该函数将提问是否上传和是否下载录像,并返回标题界面。 + + +core.events.doEvents(list, x, y, callback) [异步] +开始执行某个事件。 +请不要执行此函数,尽量使用 core.insertAction(list, x, y, callback) 来开始执行一段事件。 + + +core.events.doAction() +执行下一个事件。此函数中将对所有自定义事件类型分别处理。 + + +core.events.getCommonEvent(name) +根据名称获得一个公共事件;如果不存在对应的公共事件则返回null。 + + +core.events.openShop(shopId, needVisited) [异步] +打开一个全局商店。needVisited表示是否需要该商店已被打开过。 + + +core.events.disableQuickShop(shopId) +禁用一个全局商店 + + +core.events.canUseQuickShop(shopId) +当前能否使用某个快捷商店 + + +core.events.setHeroIcon(name) +设置勇士行走图 + + +========== core.items.XXX 和道具相关的函数 ========== +items.js将处理和道具相关的内容,比如道具的使用,获取和删除等等。 + + +core.items.compareEquipment(equipId1, equipId2) +比较两个装备的属性变化值 + + +========== core.loader.XXX 和游戏加载相关的函数 ========== +loader.js将主要用来进行资源的加载,比如加载音乐、图片、动画等等。 + + +========== core.maps.XXX 和地图处理相关的函数 ========== +maps.js主要用来进行地图相关的的操作。包括绘制地图,获取地图上的点等等。 + + +core.maps.getNumberById(id) +根据ID来获得对应的数字。如果该ID不存在对应的数字则返回0。 + + +core.maps.canMoveHero(x,y,direction,floorId) +判断能否前往某个方向。x,y为坐标,可忽略为当前点;direction为方向,可忽略为当前方向。 +floorId为楼层ID,可忽略为当前楼层。 + + +core.maps.canMoveDirectly(destX, destY) +判断当前能否瞬间移动到某个点。 +该函数如果返回0则不可瞬间移动,大于0则可以瞬间移动,且返回值是跨度(即少走的步数)。 + + +core.maps.removeBlockById(index, floorId) +根据索引删除或禁用某块。 + + +core.maps.removeBlockByIds(floorId, ids) +根据索引删除或禁用若干块。 + + +core.maps.drawAnimate(name, x, y, callback) +播放一段动画,name为动画名(需在全塔属性注册),x和y为坐标(0-12之间),callback可选,为播放完毕的回调函数。 +播放过程是异步的,如需等待播放完毕请使用insertAction插入一条type:waitAsync事件。 +此函数将随机返回一个数字id,为此异步动画的唯一标识符。 + + +core.maps.stopAnimate(id, doCallback) +立刻停止一个异步动画。 +id为该动画的唯一标识符(由drawAnimate函数返回),doCallback可选,若为true则会执行该动画所绑定的回调函数。 + + +========== core.ui.XXX 和对话框绘制相关的函数 ========== +ui.js主要用来进行UI窗口的绘制,比如对话框、怪物手册、楼传器、存读档界面等等。 + + +core.ui.getContextByName(canvas) +根据画布名找到一个画布的context;支持系统画布和自定义画布。如果不存在画布返回null。 +也可以传画布的context自身,则返回自己。 + + +core.clearMap(name) +清空某个画布图层。 +name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名;还可以直接传画布的context本身。(下同) +如果name也可以是'all',若为all则为清空所有系统画布。 + + +core.ui.fillText(name, text, x, y, style, font) +在某个画布上绘制一段文字。 +text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同) + + +core.ui.fillBoldText(name, text, x, y, style, font) +在某个画布上绘制一个描黑边的文字。 + + +core.ui.fillRect(name, x, y, width, height, style) +绘制一个矩形。style可选为绘制样式。 + + +core.ui.strokeRect(name, x, y, width, height, style) +绘制一个矩形的边框。 + + +core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth) +绘制一条线。lineWidth可选为线宽。 + + +core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth) +绘制一个箭头。 + + +core.ui.setFont(name, font) / core.ui.setLineWidth(name, lineWidth) +设置一个画布的字体/线宽。 + + +core.ui.setAlpha(name, font) / core.ui.setOpacity(name, font) +设置一个画布的绘制不透明度和画布本身的不透明度。 +两者区别如下: + - setAlpha是设置"接下来绘制的内容的不透明度",不会对已经绘制的内容产生影响。比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。 + - setOpacity是设置"画布本身的不透明度",已经绘制的内容也会产生影响。比如我已经在UI层绘制了一段文字,再setOpacity则也会看起来变得透明。 +尽量不要对系统画布使用setOpacity(因为会对已经绘制的内容产生影响),自定义创建的画布则不受此限制。 + + +core.ui.setFillStyle(name, style) / core.ui.setStrokeStyle(name, style) +设置一个画布的填充样式/描边样式。 + + +core.ui.setTextAlign(name, align) +设置一个画布的文字对齐模式。 + + +core.ui.calWidth(name, text, font) +计算一段文字在画布上的绘制宽度 +font可选,如果存在则会先设置该画布上的字体。 + + +core.ui.drawImage(name, image, x, y, w, h, x1, y1, w1, h1) +在一个画布上绘制图片。 +name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名;还可以直接传画布的context本身。 +image为要绘制的图片,可以是一个全塔属性中定义的图片名(会从images中去获取),图片本身,或者一个画布。 +后面的8个坐标参数与canvas的drawImage的八个参数完全相同。 +请查看 http://www.w3school.com.cn/html5/canvas_drawimage.asp 了解更多。 + + +core.ui.createCanvas(name, x, y, width, height, zIndex) +动态创建一个画布。name为要创建的画布名,如果已存在则会直接取用当前存在的。 +x,y为创建的画布相对窗口左上角的像素坐标,width,height为创建的长宽。 +zIndex为创建的纵向高度(关系到画布之间的覆盖),z值高的将覆盖z值低的;系统画布的z值可在个性化中查看。 +返回创建的画布的context,也可以通过core.dymCanvas[name]调用。 + + +core.ui.relocateCanvas(name, x, y) +重新定位一个自定义画布。 + + +core.ui.resizeCanvas(name, x, y) +重新设置一个自定义画布的大小。 + + +core.ui.deleteCanvas(name) +删除一个自定义画布。 + + +core.ui.deleteAllCanvas() +清空所有的自定义画布。 + + +core.ui.drawThumbnail(floorId, canvas, blocks, x, y, size, heroLoc, heroIcon) +绘制一个缩略图,比如楼传器界面,存读档界面等情况。 +floorId为目标楼层ID,canvas为要绘制到的图层,blocks为要绘制的所有图块。 +x,y为该图层开始绘制的起始点坐标,size为每一格的像素,heroLoc为勇士坐标,heroIcon为勇士图标。 + + +========== core.utils.XXX 工具类的辅助函数 ========== +utils.js主要用来进行一些辅助函数的计算。 + + +core.utils.splitLines(canvas, text, maxLength, font) +自动切分长文本的换行。 +canvas为图层,text为要自动换行的内容,maxLength为每行最长像素,font为文本的字体。 + + +core.utils.cropImage(image, size) +纵向对图片进行切分(裁剪)。 + + +core.utils.push(a,b) +向某个数组后插入另一个数组或元素 + + +core.utils.unshift(a, b) +向某个数组前插入另一个数组或元素 + + +core.utils.encodeBase64(str) +Base64加密字符串 + + +core.utils.decodeBase64(str) +Base64解密字符串 + + +core.utils.formatBigNumber(x, onMap) +大数据的格式化 + + +core.utils.subarray(a, b) +检查b是否是a的从头开始子串。 +如果是,则返回a删去b的一段;否则返回null。 + + +core.utils.same(a, b) +比较a和b两个对象是否相同 + + +core.utils.clamp(x, a, b) +将x限制在[a,b]之间的范围内 + + +core.utils.arrayToRGB(color) +将形如[255,0,0]之类的数组转成#FF0000这样的RGB形式。 + + +core.utils.arrayToRGBA(color) +将形如[255,0,0,1]之类的数组转成rgba(255,0,0,1)这样的RGBA形式。 + + +core.utils.encodeRoute(list) +压缩加密路线。可以使用core.encodeRoute(core.status.route)来压缩当前路线。 + + +core.utils.decodeRoute(route) +解压缩(解密)路线。 + + +core.utils.readFile(success, error, readType) [异步] +尝试请求读取一个本地文件内容。 +success和error为成功/失败后的回调,readType不设置则以文本读取,否则以DataUrl形式读取。 + + +core.utils.readFileContent(content) [异步] +文件读取完毕后的内容处理。 + + +core.utils.download(filename, content) +尝试生成并下载一个文件。 + + +core.utils.copy(data) +尝试复制一段文本到剪切板。 + + +core.utils.http(type, url, formData, success, error) [异步] +发送一个异步HTTP请求。 +type为'GET'或者'POST';url为目标地址;formData如果是POST请求则为表单数据。 +success为成功后的回调,error为失败后的回调。 + +``` diff --git a/_docs/_sidebar.md b/_docs/_sidebar.md index 039c2ea0..f7c5a0a1 100644 --- a/_docs/_sidebar.md +++ b/_docs/_sidebar.md @@ -3,4 +3,4 @@ - [元件说明](element) - [事件](event) - [个性化](personalization) -- [附录:API列表](api) +- [脚本](api) diff --git a/_docs/api.md b/_docs/api.md index 88697135..f445d204 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -1,6 +1,52 @@ -# 附录: API列表 +# 脚本 -?> 目前版本**v2.5.5**,上次更新时间:* {docsify-updated} * +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * + +在V2.6版本中,基本对整个项目代码进行了重写,更加方便 + +## 控制台的使用 + +在Chrome浏览器中,按(Ctrl+Shift+I)可打开控制台。 + +![](img/console.jpg) + +控制台中有很多的标签,最常用的是`Console`, `Sources`和`Elements`。 + +有关更详尽的控制台使用可自行搜索[Chrome开发者工具](https://www.baidu.com/s?wd=chrome%20%E5%BC%80%E5%8F%91%E8%80%85%E5%B7%A5%E5%85%B7)了解更多。 + +### Console:命令行 + +### Sources:断点调试 + +### Elements:网页元素查看 + +## 整体项目架构 + +## 函数的转发,复写函数 + +## 附录:API列表 + +### core.js + +### actions.js + +### control.js + +### enemys.js + +### events.js + +### icons.js + +### items.js + +### loader.js + +### map.js + +### ui.js + +### utils.js **这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** diff --git a/_docs/element.md b/_docs/element.md index 4fed9b92..6f4551d3 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -85,7 +85,7 @@ percentage为该装备是否按比例增加属性。 使用`core.getEquip(equipType)`来获得某个装备类型的当前装备。 -更多相关API详见[附录:API列表](api)。 +更多相关API详见[附录:API列表](api#附录:API列表)。 ### 多重装备 diff --git a/_docs/event.md b/_docs/event.md index 7f1e6969..cac07dc8 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1746,11 +1746,11 @@ icon是可选的,如果设置则会在选项前绘制图标,其可以是一 `{"type":"function"}`需要有一个`"function"`参数,它是一个JS函数,里面可以写任何自定义的JS脚本;系统将会执行它。 -系统常见可能会被造塔所用到的的API都在[附录:API列表](api)中给出,请进行参照。 +系统常见可能会被造塔所用到的的API都在[API列表](api#附录:API列表)中给出,请进行参照。 **警告:自定义脚本中只能执行同步代码,不可执行任何异步代码,比如直接调用core.changeFloor(...)之类都是不行的。** -[附录:API列表](api)中的所有异步API都进行了标记;如果你不确定一个函数是同步的还是异步的,请向小艾咨询。 +[API列表](api#附录:API列表)中的所有异步API都进行了标记;如果你不确定一个函数是同步的还是异步的,请向小艾咨询。 如果需要异步的代码都需要用事件(insertAction)来执行,这样事件处理过程和录像回放才不会出错。 diff --git a/_docs/img/console.jpg b/_docs/img/console.jpg new file mode 100644 index 0000000000000000000000000000000000000000..76d593787926c4c49dbe22a60a5fa3e9d3b2cdd4 GIT binary patch literal 18716 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 literal 0 HcmV?d00001 diff --git a/_docs/personalization.md b/_docs/personalization.md index 80944d06..246ffc33 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -51,7 +51,7 @@ core.fillText('test', '这是一段文字', 10, 30, '#FF0000', '16px Verdana'); `core.deleteAllCanvas()`可以删除所有动态创建的画布,`core.relocateCanvas(name, x, y)`和`core.resizeCanvas(name, x, y)`可以对画布的位置和大小进行改变。 -更多详细API请参见[API列表](api)。 +更多详细API请参见[API列表](api#附录:API列表)。 ## 自定义素材 @@ -726,4 +726,4 @@ if (core.flags.enableSkill) { ========================================================================================== -[继续阅读附录:所有API列表](api) +[继续阅读脚本](api) diff --git a/_docs/start.md b/_docs/start.md index 004ea21f..f5b4fa12 100644 --- a/_docs/start.md +++ b/_docs/start.md @@ -231,7 +231,7 @@ HTML5的塔都是可以进行控制台调试的。 - `core.resetMap()` 重置当前层地图。 - …… -更多API和详细参数介绍可参见[API列表](api)。 +更多API和详细参数介绍可参见[API列表](api#附录:API列表)。 ## 编辑器的基本操作 From ffda8bdf974dbc6d66d19845bb708af695ad1840 Mon Sep 17 00:00:00 2001 From: oc Date: Mon, 1 Apr 2019 01:27:14 +0800 Subject: [PATCH 138/153] api.md --- _docs/api.md | 911 ++++++++++----------------------------- _docs/img/console1.jpg | Bin 0 -> 50176 bytes _docs/img/elements.jpg | Bin 0 -> 174704 bytes _docs/img/sources.jpg | Bin 0 -> 118547 bytes _docs/personalization.md | 22 +- 5 files changed, 229 insertions(+), 704 deletions(-) create mode 100644 _docs/img/console1.jpg create mode 100644 _docs/img/elements.jpg create mode 100644 _docs/img/sources.jpg diff --git a/_docs/api.md b/_docs/api.md index f445d204..873aa9a2 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -16,13 +16,236 @@ ### Console:命令行 +Console页为命令行。可以在这里输入一些命令进行调试。 + +比如,进入游戏后,输入`core.status.hero.atk`即可获得勇士的当前攻击力数值。`core.status.hero.atk=100`可以设置攻击力为100。 + +更多的API可参见[附录:API列表](#附录:API列表)。 + +除此以外,游戏中的报错等信息也是可以在Console中进行查看的。 + +![](img/console1.jpg) + ### Sources:断点调试 +Sources页可以查看JS源代码,并进行断点调试等。 + +例如,如果相对脚本编辑中的伤害计算函数进行断点调试: +1. 在左边找到`project/functions.js`,单击打开文件 +2. 并找到对应的行(可以Ctrl+F搜索),比如搜索`getDamageInfo` +3. 在行号上点一下打断点,会出现一个蓝色标签 + +之后,当代码运行到你的断点处时,将自动停止运行。 + +![](img/sources.jpg) + +可以将鼠标移动到变量上,将弹窗形式显示这个变量的各项数值,从而查看变量值是否符合预期。 + +图中红色框内有几个按钮,从左到右分别是:**继续执行**,**执行到下一行**,**进入当前函数**,**跳出当前函数**,**单步执行**。 + +通过这几个按钮,可以一行一行的对代码进行执行,执行过程中能不断查看各个变量的数值变化,从而定位问题所在。 + +红圈下方是Call Stack,即当前的函数调用链(从哪些地方调用过来的)。 + +Sources还有更多有趣的功能,在此不做介绍,有兴趣的可自行网上搜索了解。 + ### Elements:网页元素查看 +Elements页可以查看网页的源代码,调整css布局等。 + +![](img/elements.jpg) + +不过对魔塔样板来说,最重要的是红圈中的按钮。点击此按钮可以进入**手机模式**。 + +手机模式下,左边可以对屏幕分辨率进行调整和模拟。 + +这可以很有效的帮我们进行测试样板在手机端的表现。 + ## 整体项目架构 -## 函数的转发,复写函数 +``` bash +├── /_server/ # 为可视化地图编辑器提供一些支持的目录 +├── /libs/ # ---- 系统库目录 ---- +│ ├─ /thirdparty/ # 游戏所用到的第三方库文件 +│ ├─ actions.js # 用户交互处理 +│ ├─ core.js # 系统核心文件(游戏入口,接口&转发) +│ ├─ control.js # 游戏逻辑控制 +│ ├─ data.js # 全塔属性等 +│ ├─ enemys.js # 怪物相关处理 +│ ├─ events.js # 各个事件的执行 +│ ├─ icons.js # 图标和素材 +│ ├─ items.js # 道具效果 +│ ├─ loader.js # 各个资源加载 +│ ├─ maps.js # 地图数据和绘制 +│ ├─ ui.js # UI窗口绘制 +│ └─ utils.js # 工具类函数 +├── /project/ # ---- 项目目录 ---- +│ ├─ /animates/ # 动画目录 +│ ├─ /floors/ # 楼层文件 +│ ├─ /images/ # 图片素材 +│ ├─ /sounds/ # bgm和音效 +│ ├─ data.js # 全塔属性 +│ ├─ enemys.js # 怪物属性 +│ ├─ events.js # 公共事件 +│ ├─ functions.js # 脚本编辑 +│ ├─ icons.js # 素材和ID的对应关系定义 +│ ├─ items.js # 道具的定义和效果 +│ ├─ maps.js # 地图和数字的对应关系 +│ └─ plugins.js # 自定义插件 +├── /常用工具/ # 辅助造塔的小工具 +├── editor.html # 地图编辑器 +├── editor-mobile.html # 手机版的地图编辑器 +├── index.html # 主程序,游戏的入口 +├── main.js # JS程序的入口,将动态对所需JS进行加载 +├── style.css # 游戏所需要用到的样式表 +└── 启动服务.exe # 一个本地的HTTP服务器,通过它来运行游戏 +``` + +`_server`为****,里面存放了地图编辑器相关的各项内容。 + +`libs`为**系统库目录**,里面存放了各个系统核心函数。 + +从V2.6开始,请勿直接修改libs下的代码,如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数) + +`project`为**项目目录**,你所造的塔的数据全部存放在project下。在不同样板之间接档也是直接迁移project目录即可。 + +## 函数的转发 + +在本样板中,`core.js`里面基本是没有定义什么函数的,所有的游戏内函数都在其他几个文件中实现。 + +例如,常见的获得某个变量值`getFlag`是定义在`control.js`中的: + +```js +////// 获得某个自定义变量或flag ////// +control.prototype.getFlag = function(name, defaultValue) { + if (!core.status.hero) return defaultValue; + var value = core.status.hero.flags[name]; + return value != null ? value : defaultValue; +} +``` + +也就是,我们可以通过`core.control.getFlag(name, value)`来调用此函数。 + +但是这样会十分不便,我们希望能直接调用`core.getFlag(name, value)`,而不需要中间的control。 + +为了达到这个目的,样板设置了**函数转发**,即**将其他文件中定义的函数,转发到core中执行**。 + +上述`getFlag`代码的转发实际上是增加了如下函数: + +```js +////// getFlag函数的转发 ////// +core.getFlag = function (name, defaultValue) { + return core.control.getFlag(name, defaultValue); +} +// 转发后,即可通过 core.getFlag() 来实际调用 core.control.getFlag() +``` + +转发是自动完成的,其满足如下两条规则: +- **在libs中其他文件定义的函数,如果不以下划线`_`开头,就会进行转发。** +- **如果core中已经存在同名函数,则会在控制台中打出一条报错信息,并不转发该函数。** + +具体函数的转发实现代码可参见`core.js`的`_forwardFunc`函数。 + +!> 除此以外,插件中以`this.xxx`来定义的函数也会被转发! + +例如,你可以直接调用`core.drawLight()`来实际调用插件中的`core.plugin.drawLight`。 + +## 复写函数 + +样板的功能毕竟是写死的,有时候我们也需要修改样板的一些行为。 + +在V2.6以前,需要直接打开libs目录下的对应文件并进行修改。但是开libs下的文件就会出现各种问题: +- 不容易随着新样板来接档迁移 +- 也不好找到自己改过什么,从而能整理成新的插件在别的塔使用 +- …… + +好消息的是,从V2.6开始,我们再也不需要开文件了,而是可以直接在插件中对原始函数进行复写。 + +如果我想对xxx文件中的yyy函数进行重写,其模式一般是:`core.xxx.yyy = function (参数列表) { ... }` + +下面是几个例子,从简单到复杂。 + +### 重写怪物手册的背景图绘制,使用winskin而不是默认的黑色 + +```js +// 重写ui.js中的_drawBook_drawBackground函数 +core.ui._drawBook_drawBackground = function () { + // 调用core.drawBackground函数来绘制winskin + // core.__PIXEL__为定义的一个宏,对于13x13的值是416,对于15x15的值是480 + core.drawBackground(0, 0, core.__PIXEL__, core.__PIXEL__); +} +``` + +### 重写点击楼传事件 + +```js +// 重写点击楼传事件 +core.events.useFly = function (fromUserAction) { + if (core.isMoving()) { + core.drawTip("请先停止勇士行动"); + return; + } + if (core.status.lockControl || core.status.event.id != null) return; + + if (core.canUseItem('fly')) core.useItem('fly'); + else core.drawTip("当前无法使用"+core.material.items.fly.name); +} +``` + +### 楼层切换时根据flag来播放不同的音效 + +```js +// 重写events.js中的_changeFloor_beforeChange,修改音效值 +core.events._changeFloor_beforeChange = function (info, callback) { + // 直接替换原始函数中的 core.playSound('floor.mp3'); + if (core.getFlag("floorSound") == 0) core.playSound('floor0.mp3'); + if (core.getFlag("floorSound") == 1) core.playSound('floor1.mp3'); + if (core.getFlag("floorSound") == 2) core.playSound('floor2.mp3'); + // ... + + // 下面是原始函数中的代码 + window.setTimeout(function () { + if (info.time == 0) + core.events._changeFloor_changing(info, callback); + else + core.show(core.dom.floorMsgGroup, info.time / 2, function () { + core.events._changeFloor_changing(info, callback); + }); + }, 25) +} +``` + +### 每次打开全局商店时播放一个音效 + +打开全局商店是在`events.js`中的`openShop`函数,因此需要对其进行重写。 + +然而,我们只需要在这个函数执行之前插一句音效播放,所以并不需要重写整个函数,而是直接插入一行就行。 + +```js +var openShop = core.events.openShop; // 先把原始函数用一个变量记录下来 +core.events.openShop = function (shopId, needVisited) { + core.playSound("shop.mp3"); // 播放一个音效 + return openShop(shopId, needVisited); // 直接调用原始函数 +} +``` + +### 每次绘制地图前在控制台打出一条信息 + +绘制地图在`maps.js`的`drawMap`函数,因此需要对其进行重写。 + +由于只需要额外在函数执行前增加一句控制台输出,所以直接插入一行即可。 + +但是需要注意的是,`drawMap`中使用了`this._drawMap_drawAll()`,因此使用函数时需要用`call`或者`apply`来告知this是什么。 + +```js +var drawMap = core.maps.drawMap; // 先把原始函数用一个变量记录下来 +core.maps.drawMap = function (floorId, callback) { + console.log("drawMap..."); // 控制台打出一条信息 + drawMap.call(core.maps, floorId, callback); // 需要使用`call`来告知this是core.maps +} +``` + +详见[`call`或`apply`的用法](https://www.jianshu.com/p/80ea0d1c04f8)。 ## 附录:API列表 @@ -47,689 +270,3 @@ ### ui.js ### utils.js - -**这里只列出所有可能会被造塔者用到的常用API,更多的有关内容请在代码内进行查询。** - -如有任何疑问,请联系小艾寻求帮助。 - -可以在chrome浏览器的控制台中(`ctrl+shift+I`,找到Console)中直接进行调用,以查看效果。 - -**以下所有异步API都会加上[异步]的说明,存在此说明的请勿在事件处理的自定义脚本中使用。** - -!> 最常用的新手向命令,强烈建议每个人了解 - -``` text - -core.status.floorId -获得当前层的floorId。 - - -core.status.maps -获得所有楼层的地图信息。 - - -core.status.thisMap -获得当前楼层信息,其等价于core.status.maps[core.status.floorId]。 - - -core.floors -获得所有楼层的信息。例如core.floors[core.status.floorId].events可获得本楼层的所有自定义事件。 - - -core.status.hero -获得当前勇士状态信息。例如core.status.hero.atk就是当前勇士的攻击力数值。 - - -core.material.enemys -获得所有怪物信息。例如core.material.enemys.greenSlime就是获得绿色史莱姆的属性数据。 - - -core.material.items -获得所有道具的信息。 - - -core.debug() -开启调试模式。此模式下可以按Ctrl键进行穿墙,并忽略一切事件。 -此模式下不可回放录像和上传成绩。 - - -core.updateStatusBar() -立刻刷新状态栏和地图显伤。 - - -core.setStatus('atk', 1000) -将攻击力设置为1000;这里把atk可以改成hp, def, mdef, money, experience等等。 -本句等价于 core.status.hero.atk = 1000 - - -core.getStatus('atk') -返回当前攻击力数值。本句等价于 core.status.hero.atk。 - - -core.setHeroLoc('x', 5) -设置勇士位置。这句话的意思是将勇士当前位置的横坐标设置为5。 -同理可以设置勇士纵坐标 core.setHeroLoc('y', 3)。 -值得注意的是,这句话虽然会使勇士改变位置,但并不会使界面重新绘制;如需立刻重新绘制地图还需调用: -core.clearMap('hero'); core.drawHero(); -来对界面进行更新。 - - -core.setItem('pickaxe', 10) -将破墙镐个数设置为10个。这里可以写任何道具的ID。 - - -core.addItem('pickaxe', 2) -将破墙镐的个数增加2个,无任何特效。这里可以写任何道具的ID。 - - -core.getItem('pickaxe', 4) -令勇士获得4个破墙镐。这里可以写任何道具的ID。 -和addItem相比,使用getItem会播放获得道具的音效,也会在左上角绘制获得提示。 - - -core.removeItem('pickaxe', 3) -删除3个破墙镐。第二项可忽略,默认值为1。 - - -core.itemCount('pickaxe') -返回当前破墙镐的个数。这里可以写任何道具的ID。 - - -core.hasItem('pickaxe') -返回当前是否存在某个道具。等价于 core.itemCount('pickaxe')>0 。 - - -core.getEquip(0) -获得0号装备类型(武器)的当前装备的itemId。如果不存在则返回null。 -这里可以写任意装备类型,从0开始和全塔属性中的equipName一一对应。 - - -core.hasEquip('sword1') -获得当前某个具体的装备是否处于正在被装备状态。 - - -core.setFlag('xyz', 2) -设置某个flag/变量的值为2。这里可以写任何的flag变量名。 - - -core.getFlag('xyz', 7) -获得某个flag/变量的值;如果该变量不存在,则返回第二个参数。 -比如 core.getFlag('point', 2) 则获得变量point的值;如果该变量从未定义过则返回2。 - - -core.hasFlag('xyz') -返回是否存在某个变量且不为0。等价于 core.getFlag('xyz', 0)!=0 。 - - -core.removeFlag('xyz') -删除某个flag/变量。 - - -core.insertAction(list, x, y, callback) -插入并执行一段自定义事件。在这里你可以写任意的自定义事件列表,有关详细写法请参见文档-事件。 -x和y如果设置则覆盖"当前事件点"的坐标,callback如果设置则覆盖事件执行完毕后的回调函数。 -例如: core.insertAction(["楼层切换", {"type":"changeFloor", "floorId": "MT3"}]) -将依次显示剧情文本,并执行一个楼层切换的自定义事件。 --------- -从V2.5.4开始提出了“公共事件”的说法,这里也可以插入一个公共事件名。 -例如:core.insertAction("毒衰咒处理") 将插入公共事件“毒衰咒处理”。 - - -core.changeFloor(floorId, stair, heroLoc, time, callback) [异步] -立刻切换到指定楼层。 -floorId为目标楼层ID,stair为到达的目标楼梯,heroLoc为到达的指定点,time为动画时间,callback为切换完毕后的回调。 -例如: -core.changeFloor('MT2', 'upFloor', null, 600) 切换到MT2层的上楼点,动画事件600ms -core.changeFloor('MT5', null, {'x': 3, 'y': 6}, 0) 无动画切换到MT5层的(3,6)位置。 - - -core.resetMap() -重置当前楼层地图和楼层属性。 -此函数参数有三种形式: - - 不加任何参数,表示重置当前层:core.resetMap() - - 加上一个floorId,表示重置某一层:core.resetMap("MT1") - - 使用一个数组,表示重置若干层:core.resetMap(["MT1", "MT2", "MT3"]) ---------------------------- -** 说明:从V2.5.5开始存档方式发生了改变,在编辑器修改了地图后现在将直接生效,无需再重置地图。 - -R -录像回放的快捷键;这不是一个控制台命令,但是也把它放在这里供使用。 -录像回放在修改地图或新增数据后会很有用。 - -``` - -!> 一些相对高级的命令,针对有一定脚本经验的人 - -``` text - -========== 可直接从core中调用的,最常被使用的函数 ========== -core.js实际上是所有API的入口(路由),核心API的实现在其他几个文件中,core.js主要进行转发操作。 - - -core.nextX(n) -获得勇士面向的第n个位置的x坐标,n可以省略默认为1(即正前方) - - -core.nextY(n) -获得勇士面向的第n个位置的y坐标,n可以省略默认为1(即正前方) - - -core.nearHero(x, y) -判断某个点是否和勇士的距离不超过1。 - - -core.openDoor(id, x, y, needKey, callback) [异步] -尝试开门操作。id为目标点的ID,x和y为坐标,needKey表示是否需要使用钥匙,callback为开门完毕后的回调函数。 -id可为null代表使用地图上的值。 -例如:core.openDoor('yellowDoor', 10, 3, false, function() {console.log("1")}) -此函数返回true代表成功开门,并将执行callback回调;返回false代表无法开门,且不会执行回调函数。 - - -core.battle(id, x, y, force, callback) [异步] -执行战斗事件。id为怪物的id,x和y为坐标,force为bool值表示是否是强制战斗,callback为战斗完毕后的回调函数。 -id可为null代表使用地图上的值。 -例如:core.battle('greenSlime', null, null, true) - - -core.trigger(x, y) [异步] -触发某个地点的事件。 - - -core.isReplaying() -当前是否正在录像播放中 - - -core.drawBlock(block) -重绘某个图块。block应为core.status.thisMap.blocks中的一项。 - - -core.drawMap(floorId, callback) -重绘某一层的地图。floorId为要绘制楼层的floorId,callback为绘制完毕后的回调函数。 - - -core.terrainExists(x, y, id, floorId) -检测某个点是否存在(指定的)地形。 -x和y为坐标;id为地形ID,可为null表示任意地形;floorId为楼层ID,可忽略表示当前楼层。 - - -core.enemyExists(x, y, id, floorId) -检测某个点是否存在(指定的)怪物。 -x和y为坐标;id为怪物ID,可为null表示任意怪物;floorId为楼层ID,可忽略表示当前楼层。 - - -core.getBlock(x, y, floorId, showDisable) -获得某个点的当前图块信息。 -x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 -showDisable如果为true,则对于禁用的点和事件也会进行返回。 -如果该点不存在图块,则返回null。 -否则,返回值如下: {"index": xxx, "block": xxx} -其中index为该点在该楼层blocks数组中的索引,block为该图块实际内容。 - - -core.getBlockId(x, y, floorId, showDisable) -获得某个点的图块ID。 -x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 -showDisable如果为true,则对于禁用的点和事件也会进行返回。 -如果该点不存在图块,则返回null,否则返回该点的图块ID。 - - -core.getBlockCls(x, y, floorId, showDisable) -获得某个点的图块cls。 -x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 -showDisable如果为true,则对于禁用的点和事件也会进行返回。 -如果该点不存在图块,则返回null,否则返回该点的图块cls。 - - -core.showBlock(x, y, floorId) -将某个点从禁用变成启用状态。 - - -core.hideBlock(x, y, floorId) -将某个点从启用变成禁用状态,但不会对其进行删除。 -此函数不会实际将该块从地图中进行删除,而是将该点设置为禁用,以供以后可能的启用事件。 - - -core.removeBlock(x, y, floorId) -将从启用变成禁用状态,并尽可能将其从地图上删除。 -和hideBlock相比,如果该点不存在自定义事件(比如门或普通的怪物),则将直接从地图中删除。 -如果存在自定义事件,则简单的禁用它,以供以后可能的启用事件。 - - -core.setBlock(number, x, y, floorId) -改变图块。number为要改变到的图块数字,x和y为坐标,floorId为楼层ID,可忽略表示当前楼层。 - - -core.useItem(itemId, noRoute, callback) -尝试使用某个道具。itemId为道具ID,noRoute如果为真则该道具的使用不计入录像。 -callback为成功或失败后的回调。 - - -core.canUseItem(itemId) -返回当前能否使用某个道具。 - - -core.loadEquip(itemId, callback) -装备上某个装备。itemId为装备的ID,callback为成功或失败后的回调。 - - -core.unloadEquip(equipType, callback) -卸下某个部位的装备。equipType为装备类型,从0开始;callback为成功或失败后的回调。 - - -core.getNextItem() -轻按。 - - -core.drawTip(text, itemIcon) -在左上角绘制一段提示信息,2秒后消失。itemIcon为道具图标的索引。 - - -core.drawText(contents, callback) [异步] -绘制一段文字。 -不推荐使用此函数,尽量使用core.insertAction(contents)来显示剧情文本。 - - -core.closePanel() -结束一切事件和绘制,关闭UI窗口,返回游戏进程。 - - -core.replaceText(text) -将一段文字中的${}进行计算并替换。 - - -core.calValue(value, prefix, need, times) -计算表达式的实际值。这个函数可以传入status:atk等这样的参数。 - - -core.getLocalStorage(key, defaultValue) -从localStorage中获得某个数据(已被parse);如果对应的key不存在则返回defaultValue。 - - -core.getLocalForage(key, defaultValue, successCallback, errorCallback) -从localForage中获得某个数据(已被parse),如果对应的key不存在则返回defaultValue。 -如果成功则通过successCallback回调,失败则通过errorCallback回调。 - - -core.hasSave(index) -判定当前某个存档位是否存在存档,返回true/false。 -index为存档编号,0代表自动存档,大于0则为正常的存档位。 - - -core.clone(data) -深拷贝某个对象。 - - -core.isset(x) -测试x是否不为null,不为undefined也不为NaN。 - - -core.rand(num) -使用伪种子生成伪随机数。该随机函数能被录像支持。 -num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到1之间的浮点数。 -此函数为伪随机算法,SL大法无效。(即多次SL后调用的该函数返回的值都是相同的。) - - -core.rand2(num) -使用系统的随机数算法得到的随机数。该随机函数能被录像支持。 -num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到2147483647之间的整数。 -此函数使用了系统的Math.random()函数,支持SL大法。 -但是,此函数会将生成的随机数值存入录像,因此如果调用次数太多则会导致录像文件过大。 - - -core.restart() [异步] -返回标题界面。 - - -========== core.actions.XXX 和游戏控制相关的函数 ========== -actions.js主要用来进行用户交互行为的处理。 -所有用户行为,比如按键、点击、滑动等等,都会被此文件接收并进行操作。 - - -========== core.control.XXX 和游戏控制相关的函数 ========== -control.js主要用来进行游戏控制,比如行走控制、自动寻路、存读档等等游戏核心内容。 - -core.control.setGameCanvasTranslate(canvasId, x, y) -设置大地图的偏移量 - - -core.control.updateViewport() -更新大地图的可见区域 - - -core.control.gatherFollowers() -立刻聚集所有的跟随者 - - -core.control.replay() -回放下一个操作 - - -========== core.enemys.XXX 和怪物相关的函数 ========== -enemys.js主要用来进行怪物相关的内容,比如怪物的特殊属性,伤害和临界计算等。 - - -core.enemys.hasSpecial(special, test) -测试怪物是否含有某个特殊属性。 -常见用法: core.enemys.hasSpecial(monster.special, 3) ## 测试是否拥有坚固 - - -core.enemys.getSpecialText(enemyId) -返回一个列表,包含该怪物ID对应的所有特殊属性。 - - -core.enemys.getSpecialHint(enemy, special) -获得怪物某个(或全部)特殊属性的文字说明。 - - -core.enemys.canBattle(enemyId, x, y, floorId) -返回当前能否战胜某个怪物。 -后面三个参数是怪物坐标和楼层。 - - -core.enemys.getDamage(enemyId, x, y, floorId) -返回当前对某个怪物的战斗伤害。如果无法战斗,返回null。 -后面三个参数是怪物坐标和楼层。 - - -core.enemys.getExtraDamage(enemyId) -返回某个怪物会对勇士造成的额外伤害(不可被魔防抵消),例如仇恨、固伤等等。 - - -core.enemys.nextCriticals(enemyId, number, x, y, floorId) -返回一个列表,为接下来number(可忽略,默认为1)个该怪物的临界值和临界减伤。 -列表每一项类似 [x,y] 表示临界值为x,且临界减伤为y。 -如果无临界值,则返回空列表。 - - -core.enemys.getDefDamage(enemyId, k, x, y, floorId) -获得k(可忽略,默认为1)防减伤值。 - - -core.enemys.getDamageInfo(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) -获得实际战斗信息,比如伤害,回合数,每回合伤害等等。 -此函数是实际战斗过程的计算。 - - -core.enemys.calDamage(enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) -获得在某个勇士属性下怪物伤害;实际返回的是上面getDamageInfo中伤害的数值。 - - -core.enemys.getCurrentEnemys(floorId) -获得某一层楼剩余所有怪物的信息(供怪物手册使用) - - -========== core.events.XXX 和事件相关的函数 ========== -events.js主要用来进行事件处理,比如自定义事件,以及某些条件下可能会被触发的事件。 -大多数事件API都在脚本编辑中存在,这里只列出部分比较重要的脚本编辑中不存在的API。 - - -core.events.gameOver(ending, fromReplay) -游戏结束并上传的事件。 -该函数将提问是否上传和是否下载录像,并返回标题界面。 - - -core.events.doEvents(list, x, y, callback) [异步] -开始执行某个事件。 -请不要执行此函数,尽量使用 core.insertAction(list, x, y, callback) 来开始执行一段事件。 - - -core.events.doAction() -执行下一个事件。此函数中将对所有自定义事件类型分别处理。 - - -core.events.getCommonEvent(name) -根据名称获得一个公共事件;如果不存在对应的公共事件则返回null。 - - -core.events.openShop(shopId, needVisited) [异步] -打开一个全局商店。needVisited表示是否需要该商店已被打开过。 - - -core.events.disableQuickShop(shopId) -禁用一个全局商店 - - -core.events.canUseQuickShop(shopId) -当前能否使用某个快捷商店 - - -core.events.setHeroIcon(name) -设置勇士行走图 - - -========== core.items.XXX 和道具相关的函数 ========== -items.js将处理和道具相关的内容,比如道具的使用,获取和删除等等。 - - -core.items.compareEquipment(equipId1, equipId2) -比较两个装备的属性变化值 - - -========== core.loader.XXX 和游戏加载相关的函数 ========== -loader.js将主要用来进行资源的加载,比如加载音乐、图片、动画等等。 - - -========== core.maps.XXX 和地图处理相关的函数 ========== -maps.js主要用来进行地图相关的的操作。包括绘制地图,获取地图上的点等等。 - - -core.maps.getNumberById(id) -根据ID来获得对应的数字。如果该ID不存在对应的数字则返回0。 - - -core.maps.canMoveHero(x,y,direction,floorId) -判断能否前往某个方向。x,y为坐标,可忽略为当前点;direction为方向,可忽略为当前方向。 -floorId为楼层ID,可忽略为当前楼层。 - - -core.maps.canMoveDirectly(destX, destY) -判断当前能否瞬间移动到某个点。 -该函数如果返回0则不可瞬间移动,大于0则可以瞬间移动,且返回值是跨度(即少走的步数)。 - - -core.maps.removeBlockById(index, floorId) -根据索引删除或禁用某块。 - - -core.maps.removeBlockByIds(floorId, ids) -根据索引删除或禁用若干块。 - - -core.maps.drawAnimate(name, x, y, callback) -播放一段动画,name为动画名(需在全塔属性注册),x和y为坐标(0-12之间),callback可选,为播放完毕的回调函数。 -播放过程是异步的,如需等待播放完毕请使用insertAction插入一条type:waitAsync事件。 -此函数将随机返回一个数字id,为此异步动画的唯一标识符。 - - -core.maps.stopAnimate(id, doCallback) -立刻停止一个异步动画。 -id为该动画的唯一标识符(由drawAnimate函数返回),doCallback可选,若为true则会执行该动画所绑定的回调函数。 - - -========== core.ui.XXX 和对话框绘制相关的函数 ========== -ui.js主要用来进行UI窗口的绘制,比如对话框、怪物手册、楼传器、存读档界面等等。 - - -core.ui.getContextByName(canvas) -根据画布名找到一个画布的context;支持系统画布和自定义画布。如果不存在画布返回null。 -也可以传画布的context自身,则返回自己。 - - -core.clearMap(name) -清空某个画布图层。 -name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名;还可以直接传画布的context本身。(下同) -如果name也可以是'all',若为all则为清空所有系统画布。 - - -core.ui.fillText(name, text, x, y, style, font) -在某个画布上绘制一段文字。 -text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同) - - -core.ui.fillBoldText(name, text, x, y, style, font) -在某个画布上绘制一个描黑边的文字。 - - -core.ui.fillRect(name, x, y, width, height, style) -绘制一个矩形。style可选为绘制样式。 - - -core.ui.strokeRect(name, x, y, width, height, style) -绘制一个矩形的边框。 - - -core.ui.drawLine(name, x1, y1, x2, y2, style, lineWidth) -绘制一条线。lineWidth可选为线宽。 - - -core.ui.drawArrow(name, x1, y1, x2, y2, style, lineWidth) -绘制一个箭头。 - - -core.ui.setFont(name, font) / core.ui.setLineWidth(name, lineWidth) -设置一个画布的字体/线宽。 - - -core.ui.setAlpha(name, font) / core.ui.setOpacity(name, font) -设置一个画布的绘制不透明度和画布本身的不透明度。 -两者区别如下: - - setAlpha是设置"接下来绘制的内容的不透明度",不会对已经绘制的内容产生影响。比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。 - - setOpacity是设置"画布本身的不透明度",已经绘制的内容也会产生影响。比如我已经在UI层绘制了一段文字,再setOpacity则也会看起来变得透明。 -尽量不要对系统画布使用setOpacity(因为会对已经绘制的内容产生影响),自定义创建的画布则不受此限制。 - - -core.ui.setFillStyle(name, style) / core.ui.setStrokeStyle(name, style) -设置一个画布的填充样式/描边样式。 - - -core.ui.setTextAlign(name, align) -设置一个画布的文字对齐模式。 - - -core.ui.calWidth(name, text, font) -计算一段文字在画布上的绘制宽度 -font可选,如果存在则会先设置该画布上的字体。 - - -core.ui.drawImage(name, image, x, y, w, h, x1, y1, w1, h1) -在一个画布上绘制图片。 -name为画布名,可以是系统画布之一,也可以是任意自定义动态创建的画布名;还可以直接传画布的context本身。 -image为要绘制的图片,可以是一个全塔属性中定义的图片名(会从images中去获取),图片本身,或者一个画布。 -后面的8个坐标参数与canvas的drawImage的八个参数完全相同。 -请查看 http://www.w3school.com.cn/html5/canvas_drawimage.asp 了解更多。 - - -core.ui.createCanvas(name, x, y, width, height, zIndex) -动态创建一个画布。name为要创建的画布名,如果已存在则会直接取用当前存在的。 -x,y为创建的画布相对窗口左上角的像素坐标,width,height为创建的长宽。 -zIndex为创建的纵向高度(关系到画布之间的覆盖),z值高的将覆盖z值低的;系统画布的z值可在个性化中查看。 -返回创建的画布的context,也可以通过core.dymCanvas[name]调用。 - - -core.ui.relocateCanvas(name, x, y) -重新定位一个自定义画布。 - - -core.ui.resizeCanvas(name, x, y) -重新设置一个自定义画布的大小。 - - -core.ui.deleteCanvas(name) -删除一个自定义画布。 - - -core.ui.deleteAllCanvas() -清空所有的自定义画布。 - - -core.ui.drawThumbnail(floorId, canvas, blocks, x, y, size, heroLoc, heroIcon) -绘制一个缩略图,比如楼传器界面,存读档界面等情况。 -floorId为目标楼层ID,canvas为要绘制到的图层,blocks为要绘制的所有图块。 -x,y为该图层开始绘制的起始点坐标,size为每一格的像素,heroLoc为勇士坐标,heroIcon为勇士图标。 - - -========== core.utils.XXX 工具类的辅助函数 ========== -utils.js主要用来进行一些辅助函数的计算。 - - -core.utils.splitLines(canvas, text, maxLength, font) -自动切分长文本的换行。 -canvas为图层,text为要自动换行的内容,maxLength为每行最长像素,font为文本的字体。 - - -core.utils.cropImage(image, size) -纵向对图片进行切分(裁剪)。 - - -core.utils.push(a,b) -向某个数组后插入另一个数组或元素 - - -core.utils.unshift(a, b) -向某个数组前插入另一个数组或元素 - - -core.utils.encodeBase64(str) -Base64加密字符串 - - -core.utils.decodeBase64(str) -Base64解密字符串 - - -core.utils.formatBigNumber(x, onMap) -大数据的格式化 - - -core.utils.subarray(a, b) -检查b是否是a的从头开始子串。 -如果是,则返回a删去b的一段;否则返回null。 - - -core.utils.same(a, b) -比较a和b两个对象是否相同 - - -core.utils.clamp(x, a, b) -将x限制在[a,b]之间的范围内 - - -core.utils.arrayToRGB(color) -将形如[255,0,0]之类的数组转成#FF0000这样的RGB形式。 - - -core.utils.arrayToRGBA(color) -将形如[255,0,0,1]之类的数组转成rgba(255,0,0,1)这样的RGBA形式。 - - -core.utils.encodeRoute(list) -压缩加密路线。可以使用core.encodeRoute(core.status.route)来压缩当前路线。 - - -core.utils.decodeRoute(route) -解压缩(解密)路线。 - - -core.utils.readFile(success, error, readType) [异步] -尝试请求读取一个本地文件内容。 -success和error为成功/失败后的回调,readType不设置则以文本读取,否则以DataUrl形式读取。 - - -core.utils.readFileContent(content) [异步] -文件读取完毕后的内容处理。 - - -core.utils.download(filename, content) -尝试生成并下载一个文件。 - - -core.utils.copy(data) -尝试复制一段文本到剪切板。 - - -core.utils.http(type, url, formData, success, error) [异步] -发送一个异步HTTP请求。 -type为'GET'或者'POST';url为目标地址;formData如果是POST请求则为表单数据。 -success为成功后的回调,error为失败后的回调。 - -``` diff --git a/_docs/img/console1.jpg b/_docs/img/console1.jpg new file mode 100644 index 0000000000000000000000000000000000000000..46d1f5ba472e127f05f7489b8c607bd253de65fc GIT binary patch literal 50176 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 literal 0 HcmV?d00001 diff --git a/_docs/img/elements.jpg b/_docs/img/elements.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d32ebaf22bc0b4948c9bdd5ad965296112f15815 GIT binary patch literal 174704 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 literal 0 HcmV?d00001 diff --git a/_docs/img/sources.jpg b/_docs/img/sources.jpg new file mode 100644 index 0000000000000000000000000000000000000000..7fce53b34473b8cd044c966c5beb19b4ecfe751d GIT binary patch literal 118547 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 literal 0 HcmV?d00001 diff --git a/_docs/personalization.md b/_docs/personalization.md index 246ffc33..6edfb2a6 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -337,28 +337,16 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { 对于特殊的塔,我们可以考虑修改楼传事件来完成一些特殊的要求,比如镜子可以按楼传来切换表里。 -要修改楼传事件,需要进行如下几步: +要修改楼传事件,需要进行如下两步: -1. 截获楼传的点击事件。在control.js中找到useFly函数,并将其替换成如下内容: -``` js -////// 点击楼层传送器时的打开操作 ////// -control.prototype.useFly = function (need) { - if (core.isMoving()) { - core.drawTip("请先停止勇士行动"); - return; - } - if (core.status.lockControl || core.status.event.id != null) return; - - if (core.canUseItem('fly')) core.useItem('fly'); - else core.drawTip("当前无法使用"+core.material.items.fly.name); -} -``` +1. 重写楼传的点击事件。在插件中对`core.control.useFly进行重写`。详细代码参见[重写点击楼传事件](api#重写点击楼传事件)。 2. 修改楼传的使用事件。和其他永久道具一样,在地图编辑器的图块属性中修改楼传的useItemEffect和canUseItemEffect两个内容。例如: ``` js "useItemEffect": "core.insertAction([...])" // 执行某段自定义事件,或者其他脚本 "canUseItemEffect": "true" // 任何时候可用 ``` -修改时,请先把`null`改成空字符串`""`,然后再双击进行编辑。 + +除了覆盖楼传事件外,对于快捷商店、虚拟键盘等等也可以进行覆盖,只不过是仿照上述代码重写对应的函数(`openQuickShop`,`openKeyboard`)即可。 ## 自定义怪物属性 @@ -441,7 +429,7 @@ this.myfunc = function(x) { 从V2.6开始,在插件中用`this.xxx`定义的函数将会被转发到core中。例如上述的`myfunc`除了`core.plugin.myfunc`外也可以直接`core.myfunc`调用。 -详见[函数转发](api#函数转发)。 +详见[函数的转发](api#函数的转发)。 ## 标题界面事件化 From e6e604ee7cd7e9ebb6803fe4b880325c489ff434 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 1 Apr 2019 20:37:08 +0800 Subject: [PATCH 139/153] statusBar Bottom, jump time, setAutomaticRoute --- libs/control.js | 20 ++++++++++++++------ libs/maps.js | 2 +- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/libs/control.js b/libs/control.js index 1aa32609..a77e7cf1 100644 --- a/libs/control.js +++ b/libs/control.js @@ -472,8 +472,14 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { if (this._setAutomaticRoute_isTurning(destX, destY, stepPostfix)) return; if (this._setAutomaticRoute_clickMoveDirectly(destX, destY, stepPostfix)) return; // 找寻自动寻路路线 - var moveStep = core.automaticRoute(destX, destY).concat(stepPostfix); - if (moveStep.length == 0) return core.deleteCanvas('route'); + var moveStep = core.automaticRoute(destX, destY); + if (moveStep.length == 0) { + if (destX != core.status.hero.loc.x || destY != core.status.hero.loc.y) + return; + moveStep = []; + } + var moveStep = moveStep.concat(stepPostfix); + if (moveStep.length == 0) return; core.status.automaticRoute.destX=destX; core.status.automaticRoute.destY=destY; this._setAutomaticRoute_drawRoute(moveStep); @@ -2353,10 +2359,11 @@ control.prototype.updateGlobalAttribute = function (name) { core.dom.statusBar.style.borderTop = border; core.dom.statusBar.style.borderLeft = border; core.dom.statusBar.style.borderRight = core.domStyle.isVertical?border:''; + core.dom.statusBar.style.borderBottom = core.domStyle.isVertical?'':border; core.dom.gameDraw.style.border = border; - core.dom.toolBar.style.borderBottom = border; core.dom.toolBar.style.borderLeft = border; core.dom.toolBar.style.borderRight = core.domStyle.isVertical?border:''; + core.dom.toolBar.style.borderBottom = core.domStyle.isVertical?border:''; break; } case 'statusBarColor': @@ -2588,7 +2595,7 @@ control.prototype._resize_statusBar = function (obj) { } else { statusBar.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px"; - statusBar.style.height = obj.outerSize - 3 + "px"; + statusBar.style.height = obj.outerSize + "px"; statusBar.style.background = obj.globalAttribute.statusLeftBackground; // --- 计算文字大小 statusBar.style.fontSize = 16 * Math.min(1, (core.__HALF_SIZE__ + 3) / obj.count) * core.domStyle.scale + "px"; @@ -2596,6 +2603,7 @@ control.prototype._resize_statusBar = function (obj) { statusBar.style.display = 'block'; statusBar.style.borderTop = statusBar.style.borderLeft = obj.border; statusBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; + statusBar.style.borderBottom = core.domStyle.isVertical ? '' : obj.border; // 自绘状态栏 if (core.domStyle.isVertical) { core.dom.statusCanvas.style.width = obj.outerSize - 6 + "px"; @@ -2651,8 +2659,8 @@ control.prototype._resize_toolBar = function (obj) { toolBar.style.background = 'transparent'; } toolBar.style.display = 'block'; - toolBar.style.borderLeft = toolBar.style.borderBottom = obj.border; - toolBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; + toolBar.style.borderLeft = obj.border; + toolBar.style.borderRight = toolBar.style.borderBottom = core.domStyle.isVertical ? obj.border : ''; toolBar.style.fontSize = 16 * core.domStyle.scale + "px"; } diff --git a/libs/maps.js b/libs/maps.js index 04287c39..b2b5dbb6 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1660,7 +1660,7 @@ maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) { return { x: sx, y: sy, ex: ex, ey: ey, px: 32 * sx, py: 32 * sy, opacity: 1, jump_peak: jump_peak, jump_count: jump_count, - step: 0, per_time: time / 16 / core.status.replay.speed + step: 0, per_time: time / jump_count }; } From 075899df872d43c6846f054bf3742490e843628a Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Mon, 1 Apr 2019 20:43:11 +0800 Subject: [PATCH 140/153] norank --- libs/control.js | 10 +++------- libs/events.js | 4 ++-- libs/maps.js | 8 +------- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/libs/control.js b/libs/control.js index a77e7cf1..c72fabff 100644 --- a/libs/control.js +++ b/libs/control.js @@ -473,13 +473,9 @@ control.prototype.setAutomaticRoute = function (destX, destY, stepPostfix) { if (this._setAutomaticRoute_clickMoveDirectly(destX, destY, stepPostfix)) return; // 找寻自动寻路路线 var moveStep = core.automaticRoute(destX, destY); - if (moveStep.length == 0) { - if (destX != core.status.hero.loc.x || destY != core.status.hero.loc.y) - return; - moveStep = []; - } - var moveStep = moveStep.concat(stepPostfix); - if (moveStep.length == 0) return; + if (moveStep.length == 0 && (destX != core.status.hero.loc.x || destY != core.status.hero.loc.y || stepPostfix.length == 0)) + return; + moveStep = moveStep.concat(stepPostfix); core.status.automaticRoute.destX=destX; core.status.automaticRoute.destY=destY; this._setAutomaticRoute_drawRoute(moveStep); diff --git a/libs/events.js b/libs/events.js index bfabdb3c..b8f10226 100644 --- a/libs/events.js +++ b/libs/events.js @@ -183,7 +183,7 @@ events.prototype._gameOver_doUpload = function (username, ending, norank) { formData.append('money', core.status.hero.money); formData.append('experience', core.status.hero.experience); formData.append('steps', core.status.hero.steps); - formData.append('norank', norank || 0); + formData.append('norank', norank ? 1 : 0); formData.append('seed', core.getFlag('__seed__')); formData.append('totalTime', Math.floor(core.status.hero.statistics.totalTime / 1000)); formData.append('route', core.encodeRoute(core.status.route)); @@ -2041,7 +2041,7 @@ events.prototype.jumpHero = function (ex, ey, time, callback) { var sx=core.status.hero.loc.x, sy=core.status.hero.loc.y; if (!core.isset(ex)) ex=sx; if (!core.isset(ey)) ey=sy; - core.maps.__playJumpSound(); + core.playSound('jump.mp3'); var jumpInfo = core.maps.__generateJumpInfo(sx, sy, ex, ey, time || 500); jumpInfo.icon = core.material.icons.hero[core.getHeroLoc('direction')]; jumpInfo.height = core.material.icons.hero.height; diff --git a/libs/maps.js b/libs/maps.js index b2b5dbb6..4a974ced 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -1645,9 +1645,7 @@ maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) { var block = blockArr[0], blockInfo = blockArr[1]; var canvases = this._initDetachedBlock(blockInfo, sx, sy, block.event.animate !== false); this._moveDetachedBlock(blockInfo, 32 * sx, 32 * sy, 1, canvases); - - this.__playJumpSound(); - + core.playSound('jump.mp3'); var jumpInfo = this.__generateJumpInfo(sx, sy, ex, ey, time); jumpInfo.keep = keep; @@ -1664,10 +1662,6 @@ maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) { }; } -maps.prototype.__playJumpSound = function () { - core.playSound('jump.mp3'); -} - maps.prototype._jumpBlock_doJump = function (blockInfo, canvases, jumpInfo, callback) { var animate = window.setInterval(function () { if (jumpInfo.jump_count > 0) From 9ecbd2aa42346faca04e4d0cc64e5293220ac2ab Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 2 Apr 2019 02:38:37 +0800 Subject: [PATCH 141/153] api for actions & control --- _docs/api.md | 714 +++++++++++++++++++++++++++++++++++++- _docs/event.md | 12 +- _docs/personalization.md | 2 +- _server/MotaAction.g4 | 29 +- _server/editor_blockly.js | 4 +- libs/actions.js | 22 +- libs/control.js | 43 ++- libs/core.js | 5 +- libs/events.js | 8 +- main.js | 8 +- project/floors/sample1.js | 4 +- 11 files changed, 777 insertions(+), 74 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index 873aa9a2..51e2b384 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -63,7 +63,7 @@ Elements页可以查看网页的源代码,调整css布局等。 ## 整体项目架构 -``` bash +``` text ├── /_server/ # 为可视化地图编辑器提供一些支持的目录 ├── /libs/ # ---- 系统库目录 ---- │ ├─ /thirdparty/ # 游戏所用到的第三方库文件 @@ -101,11 +101,11 @@ Elements页可以查看网页的源代码,调整css布局等。 └── 启动服务.exe # 一个本地的HTTP服务器,通过它来运行游戏 ``` -`_server`为****,里面存放了地图编辑器相关的各项内容。 +`_server`为**地图编辑器目录**,里面存放了地图编辑器相关的各项内容。 `libs`为**系统库目录**,里面存放了各个系统核心函数。 -从V2.6开始,请勿直接修改libs下的代码,如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数) +从V2.6开始,请勿直接修改libs下的代码,如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数)。 `project`为**项目目录**,你所造的塔的数据全部存放在project下。在不同样板之间接档也是直接迁移project目录即可。 @@ -167,10 +167,11 @@ core.getFlag = function (name, defaultValue) { ### 重写怪物手册的背景图绘制,使用winskin而不是默认的黑色 +直接重写怪物手册的背景图绘制,使用`core.drawBackground`来用winskin绘制一个背景图。 + ```js // 重写ui.js中的_drawBook_drawBackground函数 core.ui._drawBook_drawBackground = function () { - // 调用core.drawBackground函数来绘制winskin // core.__PIXEL__为定义的一个宏,对于13x13的值是416,对于15x15的值是480 core.drawBackground(0, 0, core.__PIXEL__, core.__PIXEL__); } @@ -178,8 +179,10 @@ core.ui._drawBook_drawBackground = function () { ### 重写点击楼传事件 +重写点击楼传事件,使得点击楼传按钮时能使用一个道具(比如item:fly)。 + ```js -// 重写点击楼传事件 +// 重写events.js的useFly函数,即点击楼传按钮时的事件 core.events.useFly = function (fromUserAction) { if (core.isMoving()) { core.drawTip("请先停止勇士行动"); @@ -192,10 +195,14 @@ core.events.useFly = function (fromUserAction) { } ``` +其他的几个按钮,如快捷商店`openQuickShop`,虚拟键盘`openKeyBoard`的重写也几乎完全一样。 + ### 楼层切换时根据flag来播放不同的音效 +整体复制并重写整个楼传切换前的函数,将`core.playSound('floor.mp3')`替换成根据flag来判定。 + ```js -// 重写events.js中的_changeFloor_beforeChange,修改音效值 +// 复制重写events.js中的_changeFloor_beforeChange,修改音效 core.events._changeFloor_beforeChange = function (info, callback) { // 直接替换原始函数中的 core.playSound('floor.mp3'); if (core.getFlag("floorSound") == 0) core.playSound('floor0.mp3'); @@ -203,7 +210,7 @@ core.events._changeFloor_beforeChange = function (info, callback) { if (core.getFlag("floorSound") == 2) core.playSound('floor2.mp3'); // ... - // 下面是原始函数中的代码 + // 下面是原始函数中的剩余代码,保持不变 window.setTimeout(function () { if (info.time == 0) core.events._changeFloor_changing(info, callback); @@ -245,16 +252,707 @@ core.maps.drawMap = function (floorId, callback) { } ``` -详见[`call`或`apply`的用法](https://www.jianshu.com/p/80ea0d1c04f8)。 +详见[call和apply的用法](https://www.jianshu.com/p/80ea0d1c04f8)。 ## 附录:API列表 +这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。 + +本附录量较大,如有什么需求请自行Ctrl+F进行搜索。 + +如有任何疑问,请联系小艾寻求帮助。 + ### core.js +core.js中只有很少的几个函数,主要是游戏开始前的初始化等。 + +但是,core中定义了很多游戏运行时的状态,这些状态很多都会被使用到。 + +``` text +core.__SIZE__, core.__PIXELS__ +游戏窗口大小;对于13x13的游戏而言这两个值分别是13和416,15x15来说分别是15和480。 + + +core.material +游戏中的所有资源列表,具体分为如下内容: +core.material.animates (动画) +core.material.bgms (背景音乐) +core.material.enemys (怪物信息,来自于 project/enemys.js) +core.material.icons (图标信息,来自于 project/icons.js) +core.material.images (图片素材,存放了各项素材图片如items.png等) + core.material.images.autotile (所有的自动元件图片) + core.material.images.tilesets (所有的额外素材图片) + core.material.images.images (用户引入的其他图片) +core.material.items (道具信息) +core.material.sounds (音效) + + +core.animateFrame +主要是记录和requestAnimationFrame相关的一些数据,常用的如下: +core.animateFrame.totalTime (游戏总的运行时时间) +core.animateFrame.weather (当前的天气信息) +core.animateFrame.asyncId (当前的异步处理事件的内容) + + +core.musicStatus +主要是记录和音效相关的内容,常用的如下: +core.musicStatus.bgmStatus (音乐开启状态) +core.musicStatus.soundStatus (音效开启状态) +core.musicStatus.playingBgm (当前正在播放的BGM) +core.musicStatus.lastBgm (最近一次尝试播放的BGM) +core.musicStatus.volume (当前的音量) +core.musicStatus.cachedBgms (背景音乐的缓存内从) +core.musicStatus.cacheBgmCount (背景音乐的缓存数量,默认值是4) + + +core.platform +游戏平台相关信息,常见的几个如下: +core.platform.isPC (是否是电脑端) +core.platform.isAndroid (是否是安卓端) +core.platform.isIOS (是否是iOS端) +core.platform.useLocalForage (是否开启了新版存档) +core.platform.extendKeyBoard (是否开启了拓展键盘) + + +core.domStyle +游戏的界面信息,包含如下几个: +core.domStyle.scale (当前的放缩比) +core.domStyle.isVertical (当前是否是竖屏状态) +core.domStyle.showStatusBar (当前是否显示状态栏) +core.domStyle.toolbarBtn (当前是否显示工具栏) + + +core.bigmap +当前的地图的尺寸信息,主要包含如下几个 +core.bigmap.width (当前地图的宽度) +core.bigmap.height (当前地图的高度) +core.bigmap.offsetX (当前地图针对窗口左上角的偏移像素x) +core.bigmap.offsetX (当前地图针对窗口左上角的偏移像素y) +core.bigmap.tempCanvas (一个临时画布,可以用来临时绘制很多东西) + + +core.saves +和存档相关的信息,包含如下几个: +core.saves.saveIndex (上次保存或读取的存档编号) +core.saves.ids (当前存在存档的编号列表) +core.saves.autosave (自动存档的信息) +core.saves.favorite (收藏的存档) +core.saves.favoriteNames (自定义存档的名称) + + +core.status +游戏的状态相关,是整个游戏中最重要的东西,其核心是如下几条: +请注意,每次重新开始、存档或读档时,core.status都会重新初始化。 +core.status.played (当前是否在游戏中) +core.status.gameOver (当前是否已经游戏结束,即win或lose) +core.status.hero (勇士信息;此项和全塔属性中的hero大体是对应的) + core.status.hero.name 勇士名 + core.status.hero.lv 当前等级 + core.status.hero.hpmax 当前生命上限 + core.status.hero.hp 当前生命值 + core.status.hero.manamax 当前魔力上限 + core.status.hero.mana 当前魔力值 + core.status.hero.atk 当前攻击力 + core.status.hero.def 当前防御力 + core.status.hero.mdef 当前魔防值 + core.status.hero.money 当前金币值 + core.status.hero.experience 当前经验值 + core.status.hero.loc 当前的位置信息 + core.status.hero.equipment 当前装上的装备 + core.status.hero.items 当前拥有的道具信息 + core.status.hero.flags 当前的各项flag信息 + core.status.hero.step 当前的步数值 + core.status.hero.statistics 当前的统计信息 +core.status.floorId (当前所在的楼层) +core.status.maps (所有的地图信息) +core.status.thisMap (当前的地图信息,等价于core.status.maps[core.status.floorId]) +core.status.bgmaps (所有背景层的信息) +core.status.fgmaps (所有的前景层的信息) +core.status.checkBlock (地图上的阻激夹域信息,也作为光环的缓存) +core.status.lockControl (当前是否是控制锁定状态) +core.status.automaticRoute (当前的自动寻路信息) +core.status.route (当前记录的录像) +core.status.replay (录像回放时要用到的信息) +core.status.shops (所有全局商店信息) +core.status.textAttribute (当前的文字属性,如颜色、背景等信息,和setText事件对应) +core.status.globalAttribute (当前的全局属性,如边框色、装备栏等) +core.status.curtainColor (当前色调层的颜色) +core.status.globalAnimateObjs (当前的全局帧动画效果) +core.status.floorAnimateObjs (当前的楼层贴图帧动画效果) +core.status.boxAnimateObjs (当前的盒子帧动画效果,例如怪物手册中的怪物) +core.status.autotileAnimateObjs (当前楼层的自动元件动画效果) +core.status.globalAnimateStatus (当前的帧动画的状态) +core.status.animateObjs (当前的播放动画信息) + + +core.floorIds +一个数组,表示所有的楼层ID,和全塔属性中的floorIds一致。 + + +core.floors +从楼层文件中读取全部的地图数据。 +和core.status.maps不同的是,后者在每次重新开始和读档时都会重置,也允许被修改(会存入存档)。 +而core.floors全程唯一,不允许被修改。 + + +core.statusBar +状态栏信息,例如状态栏图片,图标,以及各个内容的DOM定义等。 +core.statusBar.images (所有的系统图标,和icons.png对应) +core.statusBar.icons (状态栏中绘制的图标内容) + + +core.values +所有的全局数值信息,和全塔属性中的values一致。 +此项允许被直接修改,会存入存档。 + + +core.flags +所有的全塔开关,和全塔属性中的flags一致。 +此项不允许被直接修改,如有需要请使用“设置系统开关”事件,或者调用core.setGlobalFlag这个API。 + + +core.plugin +定义的插件函数。 + + +core.doFunc(func, _this) +执行一个函数,func为函数体或者插件中的函数名,_this为使用的this。 +如果func为一个字符串,则视为插件中的函数名,同时_this将被设置成core.plugin。 +此函数剩余参数将作为参数被传入func。 +``` + ### actions.js +actions.js主要是处理一些和用户交互相关的内容。 + +``` js +core.registerAction(action, name, func, priority) +注册一个用户交互行为。 +action:要注册的交互类型,如 ondown, onclick, keyDown 等等。 +name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。 +func:执行函数;可以是一个具体的函数体,或者是一个插件中的函数名。 +priority:优先级;优先级高的被注册项将会被执行。此项可不填,默认为0。 +返回:如果func返回true,则不会再继续执行其他的交互函数;否则会继续执行其他的交互函数。 + + +core.unregisterAction(action, name) +注销一个用户交互行为。 + + +core.doRegisteredAction(action) +执行一个用户交互行为。 +此函数将在该交互行为所注册的所有函数中,按照优先级从高到底依次执行。 +此函数剩余的参数将会作为参数传入该执行函数中。 +当某个执行函数返回true时将终止这一过程。 + + +core.onkeyDown(e) +当按下某个键时的操作,e为KeyboardEvent。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onkeyDown"的交互函数。 + + +core.onkeyUp(e) +当放开某个键时的操作,e为KeyboardEvent。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onkeyDown"的交互函数。 + + +core.pressKey(keyCode) +当按住某个键不动时的操作,目前只对方向键有效。 +如果需要添加对于其他键的长按,请复写_sys_onkeyDown和_sys_onkeyUp。 +请勿直接覆盖或调用此函数,如有需要请注册一个"pressKey"的交互函数。 + + +core.keyDown(keyCode) +当按下某个键时的操作,参数为该键的keyCode值。 +请勿直接覆盖或调用此函数,如有需要请注册一个"keyDown"的交互函数。 + + +core.keyUp(keyCode, altKey, fromReplay) +当按下某个键时的操作,参数为该键的keyCode值。 +altKey标志了Alt键是否同时被按下,fromReplay表示是否是从录像回放中调用的。 +请勿直接覆盖或调用此函数,如有需要请注册一个"keyUp"的交互函数。 + + +core.ondown(loc) +当点击屏幕时的操作。loc为点击的信息。 +请勿直接覆盖或调用此函数,如有需要请注册一个"ondown"的交互函数。 +注册的ondown交互函数需要接受x, y, px, py四个参数,代表点击的位置和像素坐标。 + + +core.onmove(loc) +当在屏幕上滑动时的操作。loc为当前的坐标信息。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onmove"的交互函数。 +注册的onmove交互函数需要接受x, y, px, py四个参数,代表当前的的位置和像素坐标。 + + +core.onup() +当从屏幕上离开时的操作。请注意此函数是没有参数的。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onup"的交互函数。 + + +core.onclick(x, y) +当点击屏幕上的某点位置时执行的操作,请注意这里的x和y是位置坐标。 +一般而言,一个完整的ondown到onup将触发一个onclick事件。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onclick"的交互函数。 + + +core.onmousewheel(direct) +当滚动鼠标滑轮时执行的操作。direct为滑轮方向,上为1,下为-1。 +请勿直接覆盖或调用此函数,如有需要请注册一个"onmousewheel"的交互函数。 + + +core.keyDownCtrl() +当长按Ctrl键不动时执行的操作。 +请勿直接覆盖或调用此函数,如有需要请注册一个"keyDownCtrl"的交互函数。 + + +core.longClick() +当长按住屏幕时执行的操作。 +请勿直接覆盖或调用此函数,如有需要请注册一个"keyDownCtrl"的交互函数。 +注册的交互函数如果某一项返回true,则之后仍然会继续触发该长按, +如果全部返回false则将停止本次长按行为,直到手指离开屏幕并重新进行长按为止。 +``` + ### control.js +control.js将负责整个游戏的核心控制系统,分为如下几个部分: +- requestAnimationFrame相关 +- 标题界面,开始和重新开始游戏 +- 自动寻路和人物行走相关 +- 画布、位置、阻激夹域、显伤等相关 +- 录像的回放相关 +- 存读档,自动存档,同步存档等相关 +- 人物属性和状态、位置、变量等相关 +- 天气、色调、音乐和音效的播放 +- 状态栏和工具栏相关 +- 界面resize相关 + +```text +// ------ requestAnimationFrame 相关 ------ // + +core.registerAnimationFrame(name, needPlaying, func) +注册一个animationFrame。它将在每次浏览器的帧刷新时(约16.6ms)被执行。 +name:你的自定义名称,可被注销使用;同名重复注册将后者覆盖前者。 +needPlaying:如果此项为true,则仅在游戏开始后才会被执行(标题界面不执行) +func:执行函数;可以是一个具体的函数体,或者是一个插件中的函数名。 +func可以接受一个timestamp作为参数,表示从整个页面加载完毕到当前时刻所经过的毫秒数。 +如果func执行报错,将在控制台打出一条信息,并自动进行注销。 + + +core.unregisterAnimationFrame(name) +注销一个animationFrame,参数是你的上面的自定义名称。 + +// ------ 开始界面相关 ------ // + +core.showStartAnimate(noAnimate, callback) +重置所有内容并显示游戏标题界面。 +noAnimate如果为true则不会有淡入动画,callback为执行完毕的回调。 + + +core.hideStartAnimate(callback) +淡出隐藏游戏标题界面,callback为执行完毕的回调。 + + +core.isPlaying() +当前是否正在游戏中。 + + +core.restart() +重新开始游戏。本质上就是播放标题界面的BGM并调用showStartAnimate。 + + +core.confirmRestart() +确认用户是否需要重新开始。 + + +core.clearStatus() +清除所有的游戏状态和数据,包括状态栏的显示。 + +// ------ 自动寻路、人物行走 ------ // + +core.stopAutomaticRoute() +停止自动寻路的操作 + + +core.saveAndStopAutomaticRoute() +保存剩下的寻路路线并停止自动寻路操作。主要用于打怪开门后继续寻路使用。 + + +core.continueAutomaticRoute() +继续剩下的自动寻路操作。主要用于打怪开门后继续寻路使用。 + + +core.clearContinueAutomaticRoute() +清空剩下的自动寻路操作。 + + +core.setAutomaticRoute(destX, destY, stepPostfix) +尝试开始进行一个自动寻路。stepPostfix是鼠标拖动的路径。 +此函数将检测是否在寻路中(在则停止或双击瞬移),检测是否点击自己(转身或轻按), +检测是否能单击瞬移,最后找寻自动寻路路线并开始寻路。 + + +core.setAutoHeroMove(steps) +设置勇士的自动行走路线,并立刻开始行走。 + + +core.setHeroMoveInterval(callback) +设置勇士行走动画。callback是每一步行走完毕后的回调。 + + +core.moveOneStep(x, y) +每走完一步后执行的操作,被转发到了脚本编辑中。 + + +core.moveAction(callback) +尝试执行单步行走。callback是执行完毕的回调。 +如果勇士面对的方向是noPass的,将直接触发事件并执行回调。 + + +core.moveHero(direction, callback) +令勇士朝一个方向行走。如果设置了callback,则只会行走一步,并执行回调。 +否则,将一直朝该方向行走,直到core.status.heroStop为true为止。 + + +core.isMoving() +当前是否正在处于行走状态 + + +core.waitHeroToStop(callback) +停止勇士的行走,等待行动结束后,再异步执行回调。 + + +core.turnHero(direction) +转向。如果设置了direction则会转到该方向,否则会右转。该函数会自动计入录像。 + + +core.moveDirectly(destX, destY) +尝试瞬间移动到某点,被转发到了脚本编辑中。 +此函数返回非负值代表成功进行瞬移,返回值是省略的步数;如果返回-1则代表没有成功瞬移。 + + +core.tryMoveDirectly(destX, destY) +尝试单击瞬移到某点。 +如果该点可被直接瞬间移动到,则直接瞬移到该点;否则尝试瞬移到相邻的上下左右点并行走一步。 + + +core.drawHero(status, offset) +绘制勇士。 +status可选,为'stop','leftFoot'和'rightFoot'之一,不填或null默认是'stop'。 +offset可选,表示具体当前格子的偏移量。不填默认为0。 +此函数将重新计算地图的偏移量,调整窗口位置,绘制勇士和跟随者信息。 + +// ------ 画布、位置、阻激夹域、显伤 ------ // + +core.setGameCanvasTranslate(canvas, x, y) +设置某个画布的偏移量 + + +core.addGameCanvasTranslate(x, y) +加减所有系统画布(ui和data除外)的偏移量。主要是被“画面震动”所使用。 + + +core.updateViewport() +根据大地图的偏移量来更新窗口的视野范围。 + + +core.nextX(n) / core.nextY(m) +获得勇士面对的第n个位置的横纵坐标。n可不填,默认为1。 + + +core.nearHero(x, y) +判定某个点是否和勇士的距离不大于1。 + + +core.gatherFollowers() +聚集所有的跟随者到勇士的位置。 + + +core.updateFollowers() +更新跟随者们的坐标。 + + +core.updateCheckBlock(floorId) +更新阻激夹域的信息,被转发到了脚本编辑中。 + + +core.checkBlock() +检查勇士坐标点的阻激夹域信息。 + + +core.updateDamage(floorId, ctx) +更新全地图的显伤。floorId可选,默认为当前楼层。 +ctx可选,为画布;如果不为空,则将会绘制到该画布上而不是damage层上。 + +// ------ 录像相关 ------ // + +core.chooseReplayFile() +弹出选择文件窗口,让用户选择录像文件。 + + +core.startReplay(list) +开始播放一段录像。list为录像的操作数组。 + + +core.triggerReplay() +播放或暂停录像,实际上是pauseReplay或resumeReplay之一。 + + +core.pauseReplay() / core.resumeReplay() +暂停和继续录像播放。 + + +core.speedUpReplay() / core.speedDownReplay() +加速和减速录像播放。 + + +core.setReplaySpeed(speed) +直接设置录像回放速度。 + + +core.stopReplay(force) +停止录像回放。如果force为true则强制停止。 + + +core.rewindReplay() +回退一个录像节点。 + + +core.saveReplay() / core.bookReplay() / core.viewMapReplay() +回放录像时的存档、查看怪物手册、浏览地图操作。 + + +core.isReplaying() +当前是否正在录像播放中。 + + +core.registerReplayAction(name, func) +注册一个自定义的录像行为。 +name:自定义名称,可用户注销使用。 +func:具体执行录像的函数,是一个函数体或者插件中的函数名。 +func需要接受action参数,代表录像回放时的当前操作行为。 +如果func返回true,则代表成功处理了此次操作,返回false代表没有进行处理。 +请注意回放录像时的二次记录问题(即回放时录像会重新记录路线)。 + + +core.unregisterReplayAction(name) +注销一个录像行为。此函数一般不应当被使用。 + +// ------ 存读档相关 ------ // + +core.autosave(remoreLast) +进行一个自动存档,实际上是加入到缓存之中。 +removeLast如果为true则会从路线中删除最后一项再存(打怪开门前的状态)。 +在事件处理中不允许调用本函数,如有需要请呼出存档页面。 + + +core.checkAutosave() +将缓存的自动存档写入存储中。平均每五秒钟,或在窗口失去焦点时被执行。 + + +core.doSL(id, type) +实际执行一个存读档事件。id为存档编号,自动存档为'autoSave'。 +type只能为'save', 'load', 'replayLoad'之一,代表存档、读档和从存档回放录像。 + + +core.syncSave(type) / core.syncLoad() +向服务器同步存档,从服务器加载存档。type如果为'all'则会向服务器同步所有存档。 + + +core.saveData() +获得要存档的内容,实际转发到了脚本编辑中。 + + +core.loadData(data, callback) +实际执行一次读档行为,data为读取到的数据,callback为执行完毕的回调。 +实际转发到了脚本编辑中。 + + +core.getSave(index, callback) +获得某个存档位的存档。index为存档编号,0代表自动存档。 + + +core.getSaves(ids, callback) +获得若干个存档位的存档。ids为一个存档编号数组,0代表自动存档。 + + +core.getAllSaves(callback) +获得全部的存档内容。目前仅被同步全部存档和下载全部存档所调用。 + + +core.getSaveIndexes(callback) +刷新全部的存档信息,将哪些档位有存档的记录到core.saves.ids中。 + + +core.hasSave(index) +判定某个存档位是否存在存档。index为存档编号,0代表自动存档。 + + +core.removeSave(index) +删除某个存档。index为存档编号,0代表自动存档。 + + +// ------ 属性、状态、位置、变量等 ------ // + +core.setStatus(name, value) +设置勇士当前的某个属性。 + + +core.addStatus(name, value) +加减勇士当前的某个属性。等价于 core.setStatus(name, core.getStatus(name) + value) + + +core.getStatus(name) +获得勇士的某个原始属性值。 + + +core.getStatusOrDefault(status, name) +尝试从status中获得某个原始属性值;如果status为null或不存在对应属性值则从勇士属性中获取。 +此项在伤害计算函数中使用较多,例如传递新的攻击和防御来计算临界和1防减伤。 + + +core.getRealStatus(name) +获得勇士的某个计算属性值。该属性值是在加成buff之后得到的。 +该函数等价于 core.getStatus(name) * core.getBuff(name) + + +core.getRealStatusOrDefault(status, name) +尝试从status中获得某个原始属性值再进行增幅,如果不存在则获取勇士本身的计算属性值。 + + +core.setBuff(name, value) +设置勇士的某个属性的增幅值。value为1代表无增幅。 + + +core.addBuff(name, value) +增减勇士的某个属性的增幅值。等价于 core.setBuff(name, core.getBuff(name) + value) + + +core.getBuff(name) +获得勇士的某个属性的增幅值。默认值是1。 + + +core.setHeroLoc(name, value, noGather) +设置勇士位置属性。name只能为'x', 'y'和'direction'之一。 +如果noGather为true,则不会聚集所有的跟随者。 + + +core.getHeroLoc(name) +获得勇士的某个位置属性。如果name为null则直接返回core.status.hero.loc。 + + +core.getLvName(lv) +获得某个等级对应的名称,其在全塔属性的levelUp中定义。如果不存在则返回原始数值。 + + +core.setFlag(name, value) +设置某个自定义变量或flag。如果value为null则会调用core.removeFlag进行删除。 + + +core.addFlag(name, value) +加减某个自定义的变量或flag。等价于 core.setFlag(name, core.getFlag(name, 0) + value) + + +core.getFlag(name, defaultValue) +获得某个自定义的变量或flag。如果该flag不存在(从未赋值过),则返回defaultValue值。 + + +core.hasFlag(name) +判定是否拥有某个自定义变量或flag。等价于 !!core.getFlag(name, 0) + + +core.removeFlag(name) +删除一个自定义变量或flag。 + + +core.lockControl() / core.unlockControl() +锁定和解锁控制。常常应用于事件处理。 + + +core.debug() +开启调试模式。此模式下可以按住Ctrl进行穿墙。 + +// ------ 天气,色调,音乐和音效 ------ // + +core.setWeather(type, level) +设置当前的天气。type只能为'rain', 'snow'或'fog',level为1-10之间代表强度信息。 + + +core.setCurtain(color, time, callback) +更改画面色调。color为更改到的色调,是个三元或四元组;time为渐变时间,0代表立刻切换。 + + +core.screenFlash(color, time, times, callback) +画面闪烁。color为色调,三元或四元组;time为单次闪烁时间,times为总闪烁次数。 + + +core.playBgm(bgm, startTime) +播放一个bgm。startTime可以控制开始时间,不填默认为0。 +如果bgm不存在、不被支持,或当前不允许播放背景音乐,则会跳过。 + + +core.pauseBgm() / core.resumeBgm() +暂停和恢复当前bgm的播放。 + + +core.triggerBgm() +更改当前bgm的播放状态。 + + +core.playSound(sound) / core.stopSound() +播放一个音效,停止全部音效。 +如果sound不存在、不被支持,或当前不允许播放音效,则会忽略。 + + +core.checkBgm() +检查bgm的状态。 +有的时候,刚打开页面时,浏览器是不允许自动播放标题界面bgm的,一定要经过一次用户操作行为。 +这时候我们可以给开始按钮增加core.checkBgm(),如果之前没有成功播放则重新播放。 + +// ------ 状态栏和工具栏相关 ------ // + +core.clearStatusBar() +清空状态栏的数据。 + + +core.updateStatusBar() +更新状态栏,被转发到了脚本编辑中。此函数还会根据是否在回放来设置工具栏的图标。 + + +core.showStatusBar() / core.hideStatusBar(showToolbox) +显示和隐藏状态栏。 +如果showToolbox为true,则在竖屏模式下不隐藏工具栏,方便手机存读档操作。 + + +core.updateHeroIcon() +更新状态栏上的勇士图标。 + + +core.updateGlobalAttribute() +更新全局属性,例如状态栏的背景图等。 + + +core.setToolbarButton(useButtom) +设置工具栏是否是拓展键盘。 + +// ------ resize 相关 ------ // + +core.registerResize(name, func) +注册一个resize函数。 +name为自定义名称,可供注销使用。 +func可以是一个函数,或插件中的函数名,可以接受一个obj作为参数。 +具体详见resize函数。 + + +core.unregisterResize(name) +注销一个resize函数。 + + +core.resize() +屏幕分辨率改变后的重新自适应。 +此函数将根据当前的屏幕分辨率信息,生成一个obj,并传入各个注册好的resize函数中执行。 +``` + ### enemys.js ### events.js diff --git a/_docs/event.md b/_docs/event.md index cac07dc8..fbd0b094 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -912,7 +912,7 @@ time为可选的,指定的话将作为楼层切换动画的时间。 **如果time指定为小于100,则视为没有楼层切换动画。** -### changePos:当前位置切换/勇士转向 +### changePos:当前位置切换/set勇士转向 有时候我们不想要楼层切换的动画效果,而是直接让勇士从A点到B点。 @@ -1126,15 +1126,15 @@ time为总移动的时间。 async可选,如果为true则会异步执行(即不等待当前事件执行完毕,立刻执行下一个事件)。 -### setFg:更改画面色调 +### setCurtain:更改画面色调 -我们可以使用 `{"type": "setFg"}` 来更改画面色调。 +我们可以使用 `{"type": "setCurtain"}` 来更改画面色调。 ``` js [ - {"type": "setFg", "color": [255,255,255,0.6], "time": 1000}, // 更改画面色调为纯白,不透明度0.6,动画时间1000毫秒 - {"type": "setFg", "color": [0,0,0], "async": true}, // 更改画面色调为纯黑,不透明度1,不指定动画时间(使用默认时间),且异步执行 - {"type": "setFg"} // 如果不指定color则恢复原样。 + {"type": "setCurtain", "color": [255,255,255,0.6], "time": 1000}, // 更改画面色调为纯白,不透明度0.6,动画时间1000毫秒 + {"type": "setCurtain", "color": [0,0,0], "async": true}, // 更改画面色调为纯黑,不透明度1,不指定动画时间(使用默认时间),且异步执行 + {"type": "setCurtain"} // 如果不指定color则恢复原样。 ] ``` diff --git a/_docs/personalization.md b/_docs/personalization.md index 6edfb2a6..904b6e45 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -346,7 +346,7 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { "canUseItemEffect": "true" // 任何时候可用 ``` -除了覆盖楼传事件外,对于快捷商店、虚拟键盘等等也可以进行覆盖,只不过是仿照上述代码重写对应的函数(`openQuickShop`,`openKeyboard`)即可。 +除了覆盖楼传事件外,对于快捷商店、虚拟键盘等等也可以进行覆盖,只不过是仿照上述代码重写对应的函数(`openQuickShop`,`openKeyBoard`)即可。 ## 自定义怪物属性 diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 2555b855..b7e93322 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -305,8 +305,8 @@ action | moveImage_s | showGif_0_s | showGif_1_s - | setFg_0_s - | setFg_1_s + | setCurtain_0_s + | setCurtain_1_s | screenFlash_s | setWeather_s | move_s @@ -1277,35 +1277,35 @@ var code = '{"type": "moveImage", "code": '+Int_0+toloc+EvalString_0+',"time": ' return code; */; -setFg_0_s +setCurtain_0_s : '更改画面色调' EvalString Colour '动画时间' Int? '不等待执行完毕' Bool Newline -/* setFg_0_s -tooltip : setFg: 更改画面色调,动画时间可不填 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=setfg%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83 +/* setCurtain_0_s +tooltip : setCurtain: 更改画面色调,动画时间可不填 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=setcurtain%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83 default : ["255,255,255,1",'rgba(255,255,255,1)',500,false] colour : this.soundColor var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/; if (!colorRe.test(EvalString_0))throw new Error('颜色格式错误,形如:0~255,0~255,0~255,0~1'); Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; var async = Bool_0?', "async": true':''; -var code = '{"type": "setFg", "color": ['+EvalString_0+']'+Int_0 +async+'},\n'; +var code = '{"type": "setCurtain", "color": ['+EvalString_0+']'+Int_0 +async+'},\n'; return code; */; -setFg_1_s +setCurtain_1_s : '恢复画面色调' '动画时间' Int? '不等待执行完毕' Bool Newline -/* setFg_1_s -tooltip : setFg: 恢复画面色调,动画时间可不填 -helpUrl : https://h5mota.com/games/template/docs/#/event?id=setfg%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83 +/* setCurtain_1_s +tooltip : setCurtain: 恢复画面色调,动画时间可不填 +helpUrl : https://h5mota.com/games/template/docs/#/event?id=setcurtain%EF%BC%9A%E6%9B%B4%E6%94%B9%E7%94%BB%E9%9D%A2%E8%89%B2%E8%B0%83 default : [500,false] colour : this.soundColor Int_0 = Int_0!=='' ?(', "time": '+Int_0):''; var async = Bool_0?', "async": true':''; -var code = '{"type": "setFg"'+Int_0 +async+'},\n'; +var code = '{"type": "setCurtain"'+Int_0 +async+'},\n'; return code; */; @@ -2433,11 +2433,12 @@ ActionParser.prototype.parseAction = function() { } break; case "setFg": // 颜色渐变 + case "setCurtain": if(this.isset(data.color)){ - this.next = MotaActionBlocks['setFg_0_s'].xmlText([ + this.next = MotaActionBlocks['setCurtain_0_s'].xmlText([ data.color,'rgba('+data.color+')',data.time||0,data.async||false,this.next]); } else { - this.next = MotaActionBlocks['setFg_1_s'].xmlText([ + this.next = MotaActionBlocks['setCurtain_1_s'].xmlText([ data.time||0,data.async||false,this.next]); } break; diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 595a55ff..08fc8c74 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -141,8 +141,8 @@ editor_blockly = function () { MotaActionBlocks['animate_s'].xmlText(), MotaActionBlocks['showStatusBar_s'].xmlText(), MotaActionBlocks['hideStatusBar_s'].xmlText(), - MotaActionBlocks['setFg_0_s'].xmlText(), - MotaActionBlocks['setFg_1_s'].xmlText(), + MotaActionBlocks['setCurtain_0_s'].xmlText(), + MotaActionBlocks['setCurtain_1_s'].xmlText(), MotaActionBlocks['screenFlash_s'].xmlText(), MotaActionBlocks['setWeather_s'].xmlText(), MotaActionBlocks['playBgm_s'].xmlText(), diff --git a/libs/actions.js b/libs/actions.js index 917af40f..6b288e15 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -105,7 +105,7 @@ actions.prototype.doRegisteredAction = function (action) { return false; } -actions.prototype.checkReplaying = function () { +actions.prototype._checkReplaying = function () { if (core.isReplaying() && core.status.event.id != 'save' && (core.status.event.id || "").indexOf('book') != 0 && core.status.event.id != 'viewMaps') return true; @@ -114,7 +114,7 @@ actions.prototype.checkReplaying = function () { ////// 检查是否在录像播放中,如果是,则停止交互 actions.prototype._sys_checkReplay = function () { - if (this.checkReplaying()) return true; + if (this._checkReplaying()) return true; } ////// 按下某个键时 ////// @@ -145,7 +145,7 @@ actions.prototype.onkeyUp = function (e) { } actions.prototype._sys_onkeyUp_replay = function (e) { - if (this.checkReplaying()) { + if (this._checkReplaying()) { if (e.keyCode == 27) // ESCAPE core.stopReplay(); else if (e.keyCode == 90) // Z @@ -286,7 +286,7 @@ actions.prototype.keyUp = function (keyCode, altKey, fromReplay) { } actions.prototype._sys_keyUp_replay = function (keyCode, altKey, fromReplay) { - if (!fromReplay && this.checkReplaying()) return true; + if (!fromReplay && this._checkReplaying()) return true; } actions.prototype._sys_keyUp_lockControl = function (keyCode, altKey) { @@ -389,7 +389,7 @@ actions.prototype._sys_keyUp = function (keyCode, altKey) { if (core.status.automaticRoute && core.status.automaticRoute.autoHeroMove) { core.stopAutomaticRoute(); } - core.stopHero(); + core.status.heroStop = true; return true; } @@ -539,8 +539,8 @@ actions.prototype._sys_onup = function () { return true; } -////// 获得点击事件相对左上角的坐标(0到12之间) ////// -actions.prototype.getClickLoc = function (x, y) { +////// 获得点击事件相对左上角的坐标 ////// +actions.prototype._getClickLoc = function (x, y) { var statusBar = {'x': 0, 'y': 0}; var size = 32; @@ -663,7 +663,7 @@ actions.prototype.onmousewheel = function (direct) { actions.prototype._sys_onmousewheel = function (direct) { // 向下滚动是 -1 ,向上是 1 - if (this.checkReplaying()) { + if (this._checkReplaying()) { // 滚轮控制速度 if (direct == 1) core.speedUpReplay(); if (direct == -1) core.speedDownReplay(); @@ -2065,7 +2065,7 @@ actions.prototype._clickLocalSaveSelect = function (x, y) { var selection = y - topIndex; core.status.event.selection = selection; if (selection < 2) { - core.getAllSaves(selection == 0 ? null : core.saves.saveIndex, function (saves) { + var callback = function (saves) { if (saves) { var content = { "name": core.firstData.name, @@ -2074,7 +2074,9 @@ actions.prototype._clickLocalSaveSelect = function (x, y) { } core.download(core.firstData.name + "_" + core.formatDate2(new Date()) + ".h5save", JSON.stringify(content)); } - }) + }; + if (selection == 0) core.getAllSaves(callback); + else core.getSave(core.saves.saveIndex, callback); } core.status.event.selection = 2; diff --git a/libs/control.js b/libs/control.js index c72fabff..df0d7796 100644 --- a/libs/control.js +++ b/libs/control.js @@ -371,7 +371,6 @@ control.prototype.confirmRestart = function (fromSettings) { }); } - ////// 清除游戏状态和数据 ////// control.prototype.clearStatus = function() { // 停止各个Timeout和Interval @@ -424,7 +423,7 @@ control.prototype.stopAutomaticRoute = function () { core.status.automaticRoute.destX=null; core.status.automaticRoute.destY=null; core.status.automaticRoute.lastDirection = null; - core.stopHero(); + core.status.heroStop = true; if (core.status.automaticRoute.moveStepBeforeStop.length==0) core.deleteCanvas('route'); } @@ -751,11 +750,6 @@ control.prototype.waitHeroToStop = function(callback) { } } -////// 停止勇士的移动状态 ////// -control.prototype.stopHero = function () { - core.status.heroStop = true; -} - ////// 转向 ////// control.prototype.turnHero = function(direction) { if (direction) { @@ -1274,7 +1268,12 @@ control.prototype._doReplayAction = function (action) { control.prototype._replay_finished = function () { core.status.replay.replaying = false; core.status.event.selection = 0; - core.ui.drawConfirmBox("录像播放完毕,你想退出播放吗?", function () { + var str = "录像播放完毕,你想退出播放吗?"; + if (core.status.route.length != core.status.replay.totalList.length + || core.subarray(core.status.route, core.status.replay.totalList) == null) { + str = "录像播放完毕,但记录不一致。\n请检查录像播放时的二次记录问题。\n你想退出播放吗?"; + } + core.ui.drawConfirmBox(str, function () { core.ui.closePanel(); core.stopReplay(true); }, function () { @@ -1462,6 +1461,7 @@ control.prototype._replayAction_moveDirectly = function (action) { // 忽略连续的瞬移事件 while (core.status.replay.toReplay.length>0 && core.status.replay.toReplay[0].indexOf('move:')==0) { + core.status.route.push(action); action = core.status.replay.toReplay.shift(); } @@ -1617,13 +1617,15 @@ control.prototype._doSL_replayLoad_afterGet = function (id, data) { ////// 同步存档到服务器 ////// control.prototype.syncSave = function (type) { core.ui.drawWaiting("正在同步,请稍后..."); - core.getAllSaves(type=='all'?null:core.saves.saveIndex, function (saves) { - if (!saves) return core.drawText("没有要同步的存档"); + var callback = function (saves) { core.control._syncSave_http(type, saves); - }) + } + if (type == 'all') core.getAllSaves(callback); + else core.getSave(core.saves.saveIndex, callback); } control.prototype._syncSave_http = function (type, saves) { + if (!saves) return core.drawText("没有要同步的存档"); var formData = new FormData(); formData.append('type', 'save'); formData.append('name', core.firstData.name); @@ -1748,8 +1750,7 @@ control.prototype.getSaves = function (ids, callback) { } } -control.prototype.getAllSaves = function (id, callback) { - if (id != null) return this.getSave(id, callback); +control.prototype.getAllSaves = function (callback) { var ids = Object.keys(core.saves.ids).filter(function(x){return x!=0;}) .sort(function(a,b) {return a-b;}), saves = []; this.getSaves(ids, function (data) { @@ -1792,7 +1793,7 @@ control.prototype.hasSave = function (index) { return core.saves.ids[index] || false; } -////// 删除一个或多个存档 +////// 删除某个存档 control.prototype.removeSave = function (index, callback) { if (index == 0 || index == "autoSave") { index = "autoSave"; @@ -1827,8 +1828,6 @@ control.prototype._updateFavoriteSaves = function () { core.setLocalStorage("favoriteName", core.saves.favoriteName); } -////// 加载某个存档 - // ------ 属性,状态,位置,buff,变量,锁定控制等 ------ // ////// 设置勇士属性 ////// @@ -2019,7 +2018,7 @@ control.prototype._setWeather_createNodes = function (type, level) { } ////// 更改画面色调 ////// -control.prototype.setFg = function(color, time, callback) { +control.prototype.setCurtain = function(color, time, callback) { if (time == null) time=750; if (time<=0) time=0; if (!core.status.curtainColor) @@ -2037,10 +2036,10 @@ control.prototype.setFg = function(color, time, callback) { return; } - this._setFg_animate(core.status.curtainColor, color, time, callback); + this._setCurtain_animate(core.status.curtainColor, color, time, callback); } -control.prototype._setFg_animate = function (nowColor, color, time, callback) { +control.prototype._setCurtain_animate = function (nowColor, color, time, callback) { var per_time = 10, step = parseInt(time / per_time); var animate = setInterval(function() { nowColor = [ @@ -2068,8 +2067,8 @@ control.prototype.screenFlash = function (color, time, times, callback) { times = times || 1; time = time / 3; var nowColor = core.clone(core.status.curtainColor); - core.setFg(color, time, function() { - core.setFg(nowColor, time * 2, function() { + core.setCurtain(color, time, function() { + core.setCurtain(nowColor, time * 2, function() { if (times > 1) core.screenFlash(color, time * 3, times - 1, callback); else { @@ -2381,7 +2380,7 @@ control.prototype.updateGlobalAttribute = function (name) { } } -////// 改变工具栏为按钮1-7 ////// +////// 改变工具栏为按钮1-8 ////// control.prototype.setToolbarButton = function (useButton) { if (!core.domStyle.showStatusBar) { // 隐藏状态栏时检查竖屏 diff --git a/libs/core.js b/libs/core.js index 966aa4d0..c3040df4 100644 --- a/libs/core.js +++ b/libs/core.js @@ -16,8 +16,7 @@ function core() { 'ground': null, 'items': {}, 'enemys': {}, - 'icons': {}, - 'events': {} + 'icons': {} } this.timeout = { 'tipTimeout': null, @@ -84,8 +83,8 @@ function core() { this.domStyle = { scale: 1.0, isVertical: false, - toolbarBtn: false, showStatusBar: true, + toolbarBtn: false, } this.bigmap = { canvas: ["bg", "event", "event2", "fg", "damage"], diff --git a/libs/events.js b/libs/events.js index b8f10226..5b7ff3b9 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1068,13 +1068,17 @@ events.prototype._action_moveImage = function (data, x, y, prefix) { } events.prototype._action_setFg = function (data, x, y, prefix) { + return this._action_setCurtain(data, x, y, prefix); +} + +events.prototype._action_setCurtain = function (data, x, y, prefix) { if (data.async) { - core.setFg(data.color, data.time); + core.setCurtain(data.color, data.time); core.setFlag('__color__', data.color || null); core.doAction(); } else { - core.setFg(data.color, data.time, function () { + core.setCurtain(data.color, data.time, function () { core.setFlag('__color__', data.color || null); core.doAction(); }); diff --git a/main.js b/main.js index 9d26b266..6091c580 100644 --- a/main.js +++ b/main.js @@ -364,7 +364,7 @@ main.dom.body.onselectstart = function () { main.dom.data.onmousedown = function (e) { try { e.stopPropagation(); - var loc = main.core.getClickLoc(e.clientX, e.clientY); + var loc = main.core.actions._getClickLoc(e.clientX, e.clientY); if (loc == null) return; main.core.ondown(loc); } catch (ee) { main.log(ee); } @@ -374,7 +374,7 @@ main.dom.data.onmousedown = function (e) { main.dom.data.onmousemove = function (e) { try { e.stopPropagation(); - var loc = main.core.getClickLoc(e.clientX, e.clientY); + var loc = main.core.actions._getClickLoc(e.clientX, e.clientY); if (loc == null) return; main.core.onmove(loc); }catch (ee) { main.log(ee); } @@ -401,7 +401,7 @@ main.dom.data.onmousewheel = function(e) { main.dom.data.ontouchstart = function (e) { try { e.preventDefault(); - var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); + var loc = main.core.actions._getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); if (loc == null) return; main.core.ondown(loc); }catch (ee) { main.log(ee); } @@ -411,7 +411,7 @@ main.dom.data.ontouchstart = function (e) { main.dom.data.ontouchmove = function (e) { try { e.preventDefault(); - var loc = main.core.getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); + var loc = main.core.actions._getClickLoc(e.targetTouches[0].clientX, e.targetTouches[0].clientY); if (loc == null) return; main.core.onmove(loc); }catch (ee) { main.log(ee); } diff --git a/project/floors/sample1.js b/project/floors/sample1.js index a7d256df..92b3a0e8 100644 --- a/project/floors/sample1.js +++ b/project/floors/sample1.js @@ -151,7 +151,7 @@ main.floors.sample1= "type": "hide" }, { - "type": "setFg", + "type": "setCurtain", "color": [ 0, 0, @@ -184,7 +184,7 @@ main.floors.sample1= "2,11": [ "\t[杰克,thief]喂!醒醒!快醒醒!", { - "type": "setFg", + "type": "setCurtain", "time": 1500 }, "\t[hero]额,我这是在什么地方?", From 1ec4994f3cd23467e80f16cfa63bd883a6fc8ad1 Mon Sep 17 00:00:00 2001 From: oc Date: Tue, 2 Apr 2019 11:17:17 +0800 Subject: [PATCH 142/153] drawBook textAlign center --- libs/ui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/ui.js b/libs/ui.js index 8a569922..6c887f92 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1254,6 +1254,7 @@ ui.prototype.drawBook = function (index) { core.drawBoxAnimate(); this.drawPagination(page, totalPage); + core.setTextAlign('ui', 'center'); core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13,'#DDDDDD', this._buildFont(15, true)); } From 2fc11cab08aa82bad271fb6d2cfdc209fced4465 Mon Sep 17 00:00:00 2001 From: ckcz123 Date: Tue, 2 Apr 2019 18:30:13 +0800 Subject: [PATCH 143/153] toolBox PgUp & setMusicBtn & docs --- _docs/api.md | 121 ++++++++++++++++++++++++++++++++++++++++++++++++ libs/actions.js | 2 +- libs/control.js | 1 + libs/enemys.js | 16 ++++--- 4 files changed, 133 insertions(+), 7 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index 51e2b384..41942f38 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -955,8 +955,129 @@ core.resize() ### enemys.js +enemys.js中定义了一系列和怪物相关的API函数。 + +```js +core.hasSpecial(special, test) +判断是否含有某个特殊属性。test为要检查的特殊属性编号。 +special为要测试的内容,允许接收如下类型参数: + - 一个数字:将直接和test进行判等。 + - 一个数组:将检查test是否在该数组之中存在。 + - 一个怪物信息:将检查test是否在该怪物的特殊属性中存在 + - 一个字符串:视为怪物ID,将检查该怪物的特殊属性 + + +core.getSpecials() +获得所有特殊属性的列表。实际上被转发到了脚本编辑中。 + + +core.getSpecialText(enemy) +获得某个怪物的全部特殊属性名称。enemy可以是怪物信息或怪物ID。 +将返回一个数组,每一项是该怪物所拥有的一个特殊属性的名称。 + + +core.getSpecialHint(enemy, special) +获得怪物的某个特殊属性的描述。enemy可以是怪物信息或怪物ID,special为该特殊属性编号。 + + +core.canBattle(enemy, x, y, floorId) +判定当前能否战胜某个怪物。 +enemy可以是怪物信息或怪物ID,x,y,floorId为当前坐标和楼层。(下同) +能战胜返回true,不能战胜返回false。 + + +core.getDamage(enemy, x, y, floorId) +获得某个怪物的全部伤害值。 +如果没有破防或无法战斗则返回null,否则返回具体的伤害值。 + + +core.getExtraDamage(enemy, x, y, floorId) +获得某个怪物的额外伤害值(不可被魔防减伤)。 +目前暂时只包含了仇恨和固伤两者,如有需要可复写该函数。 + + +core.getDamageString(enemy, x, y, floorId) +获得某个怪物伤害字符串和颜色信息,以便于在地图上绘制显伤。 + + +core.nextCriticals(enemy, number, x, y, floorId) +获得接下来的N个临界值和临界减伤。enemy可以是怪物信息或怪物ID,x,y,floorId为当前坐标和楼层。 +number为要计算的临界值数量,不填默认为1。 +如果全塔属性中的useLoop开关被开启,则将使用循环法或二分法计算临界,否则使用回合法计算临界。 +返回一个二维数组 [[x1,y1],[x2,y2],...] 表示接下来的每个临界值和减伤值。 + + +core.getDefDamage(enemy, k, x, y, floorId) +获得某个怪物的k防减伤值。k可不填默认为1。 + + +core.getEnemyInfo(enemy, hero, x, y, floorId) +获得某个怪物的实际计算时的属性。该函数实际被转发到了脚本编辑中。 +hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, "atk")来获得攻击力数值。 +该函数应当返回一个对象,记录了怪物的实际计算时的属性。 + + +core.getDamageInfo(enemy, hero, x, y, floorId) +获得某个怪物的战斗信息。该函数实际被转发到了脚本编辑中。 +hero可为null或一个对象,具体将使用core.getRealStatusOrDefault(hero, "atk")来获得攻击力数值。 +如果该函数返回null,则代表不可战斗(如没有破防,或无敌等)。 +否则,该函数应该返回一个对象,记录了战斗伤害信息,如战斗回合数等。 +从V2.5.5开始,该函数也允许直接返回一个数字,代表战斗伤害值,此时回合数将视为0。 + + +core.updateEnemys() +更新怪物数据。该函数实际被转发到了脚本编辑中。详见文档-事件-更新怪物数据。 + + +core.getCurrentEnemys(floorId) +获得某个楼层不重复的怪物信息,floorId不填默认为当前楼层。该函数会被怪物手册所调用。 +该函数将返回一个列表,每一项都是一个不同的怪物,按照伤害值从小到大排序。 +另外值得注意的是,如果设置了某个怪物的displayIdInBook,则会返回对应的怪物。 + + +core.hasEnemyLeft(floorId) +检查某个楼层是否还有剩余的怪物。等价于 core.getCurrentEnemys(floorId).length > 0 +``` + ### events.js +events.js将处理所有和事件相关的操作。 + +```js +core.resetGame(hero, hard, floorId, maps, values) +重置整个游戏。该函数实际被转发到了脚本编辑中。 + + +core.startGame(hard, seed, route, callback) +开始新游戏。 +hard为难度字符串,会被设置为core.status.hard。 +seed为开始时要设置的的种子,route为要开始播放的录像,callback为回调函数。 +该函数将重置整个游戏,调用setInitData,执行startText事件,上传游戏人数统计信息等。 + + +core.setInitData() +根据难度分歧来初始化难度,包括设置flag:hard,设置初始属性等。 +该函数实际被转发到了脚本编辑中。 + + +core.win(reason, norank) +游戏胜利,reason为结局名,norank如果为真则该结局不计入榜单。 +该函数实际被转发到了脚本编辑中。 + + +core.lose(reason) +游戏失败,reason为结局名。该函数实际被转发到了脚本编辑中。 + + +core.gameOver(ending, fromReplay, norank) +游戏结束。ending为获胜结局名,null代表失败;fromReplay标识是否是录像触发的。 +此函数将询问是否上传成绩(如果ending不是null),是否下载录像等,并重新开始。 + + + +``` + + ### icons.js ### items.js diff --git a/libs/actions.js b/libs/actions.js index 6b288e15..e6f3aff0 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1255,7 +1255,7 @@ actions.prototype._clickToolbox = function (x, y) { core.ui.drawToolbox(core.status.event.selection); } if (y == this.LAST && constantsPage > 1) { - core.status.event.data.toolsPage--; + core.status.event.data.constantsPage--; core.ui.drawToolbox(core.status.event.selection); } } diff --git a/libs/control.js b/libs/control.js index df0d7796..b932169b 100644 --- a/libs/control.js +++ b/libs/control.js @@ -326,6 +326,7 @@ control.prototype._showStartAnimate_resetDom = function () { core.clearMap('all'); core.deleteAllCanvas(); core.dom.musicBtn.style.display = 'block'; + core.setMusicBtn(); // 重置音量 core.events.setVolume(1, 0); core.updateStatusBar(); diff --git a/libs/enemys.js b/libs/enemys.js index 75f64ede..2b7e551d 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -107,13 +107,13 @@ enemys.prototype.canBattle = function (enemy, x, y, floorId) { ////// 获得某个怪物的伤害 ////// enemys.prototype.getDamage = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - var damage = this.calDamage(enemy, null, x, y, floorId); + var damage = this._calDamage(enemy, null, x, y, floorId); if (damage == null) return null; - return damage + this.getExtraDamage(enemy); + return damage + this.getExtraDamage(enemy, x, y, floorId); } ////// 获得某个怪物的额外伤害 ////// -enemys.prototype.getExtraDamage = function (enemy) { +enemys.prototype.getExtraDamage = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; var extra_damage = 0; if (this.hasSpecial(enemy.special, 17)) { // 仇恨 @@ -265,8 +265,8 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; k = k || 1; - var nowDamage = this.calDamage(enemy, null, x, y, floorId); - var nextDamage = this.calDamage(enemy, {"def": core.status.hero.def + k}, x, y, floorId); + var nowDamage = this._calDamage(enemy, null, x, y, floorId); + var nextDamage = this._calDamage(enemy, {"def": core.status.hero.def + k}, x, y, floorId); if (nowDamage == null || nextDamage == null) return "???"; return nowDamage - nextDamage; } @@ -284,7 +284,7 @@ enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) { } ////// 获得在某个勇士属性下怪物伤害 ////// -enemys.prototype.calDamage = function (enemy, hero, x, y, floorId) { +enemys.prototype._calDamage = function (enemy, hero, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; var info = this.getDamageInfo(enemy, hero, x, y, floorId); @@ -357,4 +357,8 @@ enemys.prototype._getCurrentEnemys_sort = function (enemys) { } return a.damage - b.damage; }); +} + +enemys.prototype.hasEnemyLeft = function (floorId) { + return core.getCurrentEnemys(floorId).length > 0; } \ No newline at end of file From e280308da51801dd25f70044fda3650b4a3e531d Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 3 Apr 2019 00:23:12 +0800 Subject: [PATCH 144/153] docs for events/enemys/items/maps --- _docs/api.md | 778 +++++++++++++++++++++++++++++++++++++++++++++++- libs/actions.js | 2 +- libs/control.js | 23 -- libs/core.js | 2 +- libs/events.js | 162 +++++----- libs/items.js | 42 +-- libs/maps.js | 126 ++++---- libs/utils.js | 2 +- 8 files changed, 946 insertions(+), 191 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index 41942f38..8d085971 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -301,7 +301,7 @@ core.musicStatus.soundStatus (音效开启状态) core.musicStatus.playingBgm (当前正在播放的BGM) core.musicStatus.lastBgm (最近一次尝试播放的BGM) core.musicStatus.volume (当前的音量) -core.musicStatus.cachedBgms (背景音乐的缓存内从) +core.musicStatus.cachedBgms (背景音乐的缓存内容) core.musicStatus.cacheBgmCount (背景音乐的缓存数量,默认值是4) @@ -557,14 +557,6 @@ core.isPlaying() 当前是否正在游戏中。 -core.restart() -重新开始游戏。本质上就是播放标题界面的BGM并调用showStartAnimate。 - - -core.confirmRestart() -确认用户是否需要重新开始。 - - core.clearStatus() 清除所有的游戏状态和数据,包括状态栏的显示。 @@ -1041,9 +1033,17 @@ core.hasEnemyLeft(floorId) ### events.js -events.js将处理所有和事件相关的操作。 +events.js将处理所有和事件相关的操作,主要分为五个部分: +- 游戏的开始和结束 +- 系统事件的处理 +- 自定义事件的处理 +- 点击状态栏图标所进行的操作 +- 一些具体事件的执行内容 + ```js +// ------ 游戏的开始和结束 ------ // + core.resetGame(hero, hard, floorId, maps, values) 重置整个游戏。该函数实际被转发到了脚本编辑中。 @@ -1074,18 +1074,774 @@ core.gameOver(ending, fromReplay, norank) 此函数将询问是否上传成绩(如果ending不是null),是否下载录像等,并重新开始。 +core.restart() +重新开始游戏。本质上就是播放标题界面的BGM并调用showStartAnimate。 + +core.confirmRestart() +确认用户是否需要重新开始。 + +// ------ 系统事件处理 ------ // + +core.registerSystemEvent(type, func) +注册一个系统事件,即通过图块的默认触发器所触发的事件。 +type为一个要注册的事件类型,func为要执行的函数体或插件中的函数名。 +func需要接受(data, callback)作为参数,分别是触发点的图块信息,和执行完毕时的回调。 +如果注册一个已经存在的系统事件,比如openDoor,则会覆盖系统的默认函数。 + + +core.unregisterSystemEvent(type) +注销一个系统事件。type是上面你注册的事件类型。 + + +core.doSystemEvent(type, data, callback) +执行一个系统事件。type为事件类型,data为该事件点的图块信息,callback为执行完毕的回调。 + + +core.battle(id, x, y, force, callback) +和怪物进行战斗。 +id为怪物的ID,x和y为怪物坐标,force如果为真将强制战斗,callback为执行完毕的回调。 +如果填写了怪物坐标,则会删除对应点的图块并执行该点战后事件。 +如果是在事件流的执行过程中调用此函数,则不会进行自动存档,且会强制战斗。 + + +core.beforeBattle(enemyId, x, y) +战前事件。实际被转发到了脚本编辑中,可以在这里加上一些战前特效。 +此函数在“检测能否战斗和自动存档”【之后】执行。 +如果需要更早的战前事件,请在插件中覆重写 core.events.doSystemEvent 函数。 +此函数返回true则将继续本次战斗,返回false将不再战斗。 + + +core.afterBattle(enemyId, x, y, callback) +战后事件,将执行扣血、加金币经验、特殊属性处理、战后事件处理等操作。 +实际被转发到了脚本编辑中。 + + +core.openDoor(x, y, needKey, callback) +尝试开一个门。x和y为门的坐标,needKey表示是否需要钥匙,callback为执行完毕的回调。 +如果不是一个有效的门,需要钥匙且未持有等,均会忽略此事件并直接执行callback。 + + +core.afterOpenDoor(doorId, x, y, callback) +开完一个门后执行的事件,实际被转发到了脚本编辑中。 + + +core.getItem(id, num, x, y, callback) +获得若干个道具。itemId为道具ID,itemNum为获得的道具个数,不填默认为1。 +x和y为道具点的坐标,如果设置则会擦除地图上的该点。 + + +core.afterGetItem(id, x, y, callback) +获得一个道具后执行的事件,实际被转发到了脚本编辑中。 + + +core.getNextItem(noRoute) +轻按,即获得面对的道具。如果noRoute为真则这个轻按行为不会计入录像。 + + +core.changeFloor(floorId, stair, heroLoc, time, callback, fromLoad) +楼层切换。floorId为目标楼层ID,stair为是什么楼梯,heroLoc为目标点坐标。 +time为切换时间,callback为切换完毕的回调,fromLoad标志是否是从读档造成的切换。 +floorId也可以填":before"和":next"表示前一层和后一层。 +heroLoc为{"x": 0, "y": 0, "direction": "up"}的形式。不存在则从勇士位置取。 +如果stair不为null,则会在该楼层中找对应的图块作为目标点的坐标并覆盖heroLoc。 +一般设置的是"upFloor"和"downFloor",但也可以用任何其他的图块ID。 + + +core.changingFloor(floorId, heroLoc, fromLoad) +正在执行楼层切换中执行的操作,实际被转发到了脚本编辑中。 + + +core.hasVisitedFloor(floorId) +是否曾经到达过某一层。 + + +core.visitFloor(floorId) +标记曾经到达了某一层。 + + +core.passNet(data) +执行一个路障处理。这里只有毒衰咒网的处理,血网被移动到了updateCheckBlock中。 + + +core.pushBox(data) +执行一个推箱子事件。 + + +core.afterPushBox() +推箱子之后触发的事件,实际被转发到了脚本编辑中。 + + +core.changeLight(id, x, y) +踩灯后的事件。 + +// ------ 自定义事件的处理 ------ // + +core.registerEvent(type, func) +注册一个自定义事件。type为事件名,func为执行事件的函数体或插件中的函数名。 +func可以接受(data, x, y, prefix)参数,其中data为事件内容,x和y为该点坐标,prefix为该点前缀。 +同名注册的事件将进行覆盖。 +请记得在自定义处理事件完毕后调用core.doAction()再继续执行下一个事件! + + +core.unregisterEvent(type) +注销一个自定义事件。 + + +core.doEvent(data, x, y, prefix) +执行一个自定义事件。data为事件内容,将根据data.type去注册的事件列表中查找对应的执行函数。 +x和y为该点坐标,prefix为该点前缀。执行事件时也会把(data, x, y, prefix)传入执行函数。 + + +core.setEvents(list, x, y, callback) +设置自定义事件的执行列表,坐标和回调函数。 + + +core.startEvents(list, x, y, callback) +开始执行一系列的自定义事件。list为事件列表,x和y为事件坐标,callback为执行完毕的回调。 +此函数将调用core.setEvents,然后停止勇士,再执行core.doAction()。 + + +core.doAction() +执行下一个自定义事件。 +此函数将检测事件列表是否全部执行完毕,如果是则执行回调函数。 +否则,将从事件列表中弹出下一个事件,并调用core.doEvent进行执行。 + + +core.insertAction(action, x, y, callback, addToLast) +向当前的事件列表中插入一个或多个事件并执行。 +如果当前并不是在事件执行流中,则会调用core.startEvents()开始执行事件,否则仅仅执行插入操作。 +action为要插入的事件,可以是一个单独的事件,或者是一个事件列表。 +x,y,callback如果设置了且不为null,则会覆盖当前的坐标和回调函数。 +addToLast如果为真,则会插入到事件执行列表的尾部,否则是插入到执行列表的头部。 + + +core.getCommonEvent(name) +根据名称获得某个公共事件内容。 + + +core.recoverEvents(data) +恢复事件现场。一般用于呼出怪物手册、呼出存读档页面等时,恢复事件执行流。 + +// ------ 点击状态栏图标时执行的一些操作 ------ // + +core.openBook(fromUserAction) +尝试打开怪物手册。fromUserAction标志是否是从用户的行为触发,如按键或点击状态栏。(下同) +不建议复写此函数,否则【呼出怪物手册】事件会出问题。 + + +core.useFly(fromUserAction) +尝试使用楼传器。可以安全的复写此函数,参见文档-个性化-覆盖楼传事件。 + + +core.flyTo(toId, callback) +尝试飞行到某个楼层,被转发到了脚本编辑中。 +如果此函数返回true代表成功进行了飞行,false代表不能进行飞行。 + + +core.openEquipbox(fromUserAction) / core.openToolbox(fromUserAction) +尝试打开道具栏和装备栏。可以安全复写这两个函数。 + + +core.openQuickShop(fromUserAction) / core.openKeyBoard(fromUserAction) +尝试打开快捷商店和虚拟键盘。可以安全复写这两个函数。 + + +core.save(fromUserAction) / core.load(fromUserAction) +尝试打开存读档页面。 +不建议复写这两个函数,否则【呼出存读档页面】事件会出问题。 + + +core.openSettings(fromUserAction) +尝试打开系统菜单。不建议复写此函数。 + + +// ------ 一些具体事件的执行内容 ------ // + +core.hasAsync() +当前是否存在未执行完毕的异步事件。请注意正在播放的动画也算异步事件。 + + +core.follow(name) / core.unfollow(name) +跟随勇士/取消跟随。name为行走图名称。 +在取消跟随时如果指定了name,则会从跟随列表中选取一个该行走图取消,否则取消所有跟随。 +跟随和取消跟随都会调用core.gatherFollowers()来聚集所有的跟随者。 + + +core.setValue(name, value, prefix) / core.addValue(name, value, prefix) +设置/增减某个数值。name可以是status:xxx,item:xxx或flag:xxx。 +value可以是一个表达式,将调用core.calValue()计算。prefix为前缀,独立开关使用。 + + +core.doEffect(effect, need, times) +执行一个effect操作。该函数目前仅被全局商店的status:xxx+=yyy所调用。 + + +core.setFloorInfo(name, values, floorId, prefix) +设置某层楼的楼层属性。 + + +core.setGlobalAttribute(name, value) +设置一个全局属性,如边框颜色等。 + + +core.setGlobalFlag(name, value) +设置一个全局开关,如enableXXX等。 +如果需要设置一个全局数值如红宝石数值,可以直接简单的修改core.values,因此没有单独列出函数。 + + +core.closeDoor(x, y, id, callback) +执行一个关门事件。如果不是一个合法的门,或者该点不为空地,则会忽略本事件。 + + +core.showImage(code, image, sloc, loc, opacityVal, time, callback) +显示一张图片。code为图片编号,image为图片内容或图片名。 +sloc为[x,y,w,h]形式,表示在原始图片上裁剪的区域,也可直接设为null表示整张图片。 +loc为[x,y,w,h]形式,表示在界面上绘制的位置和大小,w和h可忽略表示使用绘制大小。 +opacityVal为绘制的不透明度,time为淡入时间。 +此函数将创建一个画布,其z-index是100+code,即图片编号为1则是101,编号50则是150。 +请注意,curtain层的z-index是125,UI层的z-index是140;因此可以通过图片编号来调整覆盖关系。 + + +core.hideImage(code, time, callback) +隐藏一张图片。code为图片编号,time为淡出时间。 + + +core.moveImage(code, to, opacityVal, time, callback) +移动一张图片。code为图片编号,to为[x,y]表示目标位置,opacityVal目标不透明度,time为移动时间。 + + +core.showGif(name, x, y) +绘制一张gif图片或取消所有绘制内容。如果name不设置则视为取消。x和y为左上角像素坐标。 + + +core.setVolume(value, time, callback) +设置音量。value为目标音量大小,在0到1之间。time为音量渐变的时间。 + + +core.vibrate(time, callback) +画面震动。time为震动时间。 +请注意,画面震动时间必须是500的倍数,系统也会自动把time调整为上整的500倍数值。 + + +core.eventMoveHero(steps, time, callback) +使用事件移动勇士。time为每步的移动时间。 +steps为移动数组,可以接受'up','down','left','right','forward'和'backward'项。 +使用事件移动勇士将不会触发任何地图上的事件。 + + +core.jumpHero(ex, ey, time, callback) +跳跃勇士。ex和ey为目标点的坐标,可以为null表示原地跳跃。time为总跳跃时间。 + + +core.openShop(shopId, needVisited) +打开一个全局商店。needVisited表示是否需要该商店原本就是启用状态。 +如果该商店对应的实际上是一个全局事件,则会直接插入并执行。 + + +core.disableQuickShop(shopId) +禁用一个全局商店,即把一个商店从启用变成禁用状态。 + + +core.canUseQuickShop(shopId) +当前能否使用某个全局商店,实际被转发到了脚本编辑中。 +如果此函数返回null则表示可以使用,返回一个字符串表示不可以,该字符串表示不可以的原因。 + + +core.setHeroIcon(name, noDraw) +设置勇士的行走图。 +name为行走图名称,noDraw如果为真则不会调用core.drawHero()函数进行刷新。 + + +core.checkLvUp() +检查升级事件。该函数将判定当前是否升级(或连续升级),然后执行升级事件。 + + +core.tryUseItem(itemId) +尝试使用一个道具。 +对于怪物手册和楼传器,将分别调用core.openBook()和core.useFly()函数。 +对于中心对称飞行器,则会调用core.drawCenterFly()函数。 +对于其他的道具,将检查是否拥有,能否使用,并且进行使用。 + + +core.afterUseBomb() +使用炸弹或圣锤后的事件。实际被转发到了脚本编辑中。 ``` - ### icons.js +icons.js主要是负责素材相关信息,比如某个素材在对应的图片上的位置。 + +```js +core.getClsFromId(id) +根据某个素材的ID获得该素材的cls + + +core.getTilesetOffset(id) +根据某个素材来获得对应的tileset和坐标信息。 +如果该素材不是tileset,则返回null。 +``` + ### items.js +items.js主要负责一切和道具相关的内容。 + +```js +core.getItemEffect(itemId, itemNum) +即捡即用类的道具获得时的效果。实际对应道具图块属性中的itemEffect框。 + + +core.getItemEffectTip(itemId) +即捡即用类的道具获得时的额外提示,比如“,攻击+100”。 +实际对应道具图块属性中的itemEffectTip框。 + + +core.useItem(itemId, noRoute, callback) +尝试使用一个道具。实际对应道具图块属性中的useItemEffect框。 +此函数也会调用一遍core.canUseItem(),如果无法使用将直接返回。 +noRoute如果为真,则这次使用道具的过程不会被计入录像。 +使用道具完毕后,对于消耗道具将自动扣除,永久道具不会扣除。 + + +core.canUseItem(itemId) +当前能否使用某个道具。 +有些系统道具如破炸和上下楼器等,会在计算出目标点的坐标后存入core.status.event.ui。 +使用道具时将直接从core.status.event.ui调用,不会重新计算。 + + +core.itemCount(itemId) +获得某个道具的个数。 + + +core.hasItem(itemId) +当前是否拥有某个道具。等价于 core.itemCount(itemId) > 0 +请注意,装备上的装备不视为拥有该道具,即core.hasEquip()和core.hasItem()是完全不同的。 + + +core.hasEquip(itemId) +当前是否装备上某个装备。 +请注意,装备上的装备不视为拥有该道具,即core.hasEquip()和core.hasItem()是完全不同的。 + + +core.getEquip(equipType) +获得某个装备位的当前装备。equipType为装备类型,从0开始。 +如果该装备位没有装备则返回null,否则返回当前装备的ID。 + + +core.setItem(itemId, itemNum) +设置某个道具的个数。 + + +core.addItem(itemId, itemNum) +增减某个道具的个数,itemNum可不填默认为1。 + + +core.getEquipTypeByName(name) +根据装备位名称来找到一个空的装备孔,适用于多重装备。 +如果没有一个装备孔是该装备名称,则返回-1。 + + +core.getEquipTypeById(equipId) +获得某个装备的装备类型。 +如果其type写的是装备名(多重装备),则调用core.getEquipTypeByName()函数。 + + +core.canEquip(equipId, hint) +当前能否穿上某个装备。如果hint为真,则不可装备时会气泡提示原因。 + + +core.loadEquip(equipId, callback) +穿上某个装备。 + + +core.unloadEquip(equipType, callback) +脱下某个装备孔的装备。 + + +core.compareEquipment(compareEquipId, beComparedEquipId) +比较两个套装的差异。 +此函数将对所有的勇士属性包括生命魔力攻防魔防金币等进行比较。 +如果存在差异的,将作为一个对象返回其差异内容。 + + +core.quickSaveEquip(index) +保存当前套装。index为保存的套装编号。 + + +core.quickLoadEquip() +读取当前套装。index为读取的套装编号。 +``` + ### loader.js +loader.js主要负责资源加载相关的内容。 + +```js +core.loadImage(imgName, callback) +从 project/images/ 中加载一张图片。imgName为图片名。 +callback为执行完毕的回调函数,接收(imgName, image)即图片名和图片内容作为参数。 +如果图片不存在或加载失败则会在控制台打出一条错误日志,不会执行回调。 + + +core.loadImages(names, toSave, callback) +从 project/images/ 中加载若干张图片。 +names为一个图片名的列表,toSave为加载并存到的对象。 +callback为全部加载完毕执行的回调。 + + +core.loadOneMusic(name) +从 project/sounds/ 或第三方中加载一个音乐,并存入core.material.bgms中。name为音乐名。 + + +core.loadOneSound(name) +从 project/sounds/ 中加载一个音效,并存入core.material.sounds中。name为音效名。 + + +core.loadBgm(name) +预加载一个bgm并加入缓存列表core.musicStatus.cachedBgms。 +此函数将会检查bgm的缓存,预加载和静音播放。 +如果缓存列表溢出(core.musicStatus.cacheBgmCount)则通过LRU算法选择一个bgm并调用core.freeBgm()。 + + +core.freeBgm(name) +释放一个bgm的内存并移出缓存列表。如果该bgm正在播放则也会立刻停止。 +``` + ### map.js +maps.js负责一切和地图相关的处理内容,包括如下几个方面: +- 地图的初始化,保存和读取,地图数组的生成 +- 是否可移动或瞬间移动的判定 +- 地图的绘制 +- 获得某个点的图块信息 +- 启用和禁用图块,改变图块 +- 移动/跳跃图块,淡入淡出图块 +- 全局动画控制,动画的绘制 + +```js +// ------ 地图的初始化,保存和读取,地图数组的生成 ------ // + +core.loadFloor(floorId, map) +从楼层或者存档中生成core.status.maps的内容。 +map为存档信息,如果某项在map中不存在则会从core.floors中读取。 + + +core.getNumberById(id) +给定一个图块ID,找到对应的数字。 + + +core.initBlock(x, y, id, addInfo, eventFloor) +给定一个数字,初始化一个图块信息。 +x和y为坐标,id为数字或者可以:t或:f结尾表示初始是启用还是禁用状态。 +addInfo如果为true则会填充上图块的默认信息,比如给怪物添加battle触发器。 +eventFloor如果设置为某个楼层信息,则会填充上该点的自定义或楼层切换事件。 + + +core.compressMap(mapArr, floorId) +压缩地图。mapArr为要压缩的二维数组,floorId为对应的楼层。 +此函数将把mapArr和对应的楼层中的数组进行比较,并只取差异值进行存储。 +通过这种压缩地图的方式,不仅节省了存档空间,还支持了任意修改地图的接档。 + + +core.decompressMap(mapArr, floorId) +解压缩地图。mapArr为压缩后的地图,floorId为对应的楼层。 +此函数返回解压后的二维数组。 + + +core.saveMap(floorId) +将某层楼的数据生成存档所保存的内容。在core.saveData()中被调用。 + + +core.loadMap(data, floorId) +从data中读取楼层数据,并调用core.loadFloor()进行初始化。 + + +core.resizeMap(floorId) +根据某层楼的地图大小来调整大地图的画布大小。floorId可为null表示当前层。 + + +core.getMapArray(floorId, showDisable) +生成某层楼的二维数组。floorId可不填代表当前楼层。 +showDisable若为真,则对于禁用的点会加上:f表示,否则视为0。 + + +core.getMapBlocksObj(floorId, showDisable) +以x,y的形式返回每个点的图块信息。floorId可不填表示当前楼层。 +此函数将返回 {"0,0": {...}, "0,1": {...}} 这样的结构,其中内部为对应点的block信息。 + + +core.getBgMapArray(floorId, noCache) +获得某层楼的背景层的二维数组。floorId可不填表示当前楼层。 +如果noCache为真则重新从剧本中读取而不使用缓存数据。 + + +core.getFgMapArray(floorId, noCache) +获得某层楼的前景层的二维数组。floorId可不填表示当前楼层。 +如果noCache为真则重新从剧本中读取而不使用缓存数据。 + + +core.getBgNumber(x, y, floorId, noCache) +获得某层楼的背景层中某个点的数字。floorId可不填表示当前楼层。 +如果noCache为真则重新从剧本中读取而不使用缓存数据。 +本函数实际等价于 core.getBgMapArray(floorId, noCache)[y][x] + + +core.getBgNumber(x, y, floorId, noCache) +获得某层楼的前景层中某个点的数字。参数和方法同上。 + +// ------ 是否可移动或瞬间移动的判定 ------ // + +core.generateMovableArray(floorId, x, y, direction) +生成全图或某个点的可通行方向数组。floorId为楼层Id,可不填默认为当前点。 +这里的可通行方向数组,指的是["up","down","left","right"]中的一个或多个组成的数组。 + - 如果不设置x和y,则会返回一个三维数组,其中每个点都是一个该点可通行方向的数组。 + - 如果设置了x和y但没有设置direction,则只会返回该点的可通行方向数组, + - 如果设置了x和y以及direction,则会判定direction是否在该点可通行方向数组中,并返回true或false。 +可以使用core.inArray()来判定某个方向是否在可通行方向数组中。 + + +core.canMoveHero(x, y, direction, floorId) +某个点是否可朝某个方向移动。x和y可选,不填或为null则默认为勇士当前点。 +direction可选,不填或为null则默认勇士当前朝向。floorId不填则默认为当前楼层。 +此函数将直接调用 core.generateMovableArray() 进行判定。 + + +core.canMoveDirectly(destX, destY) +当前能否瞬间移动到某个点。 +如果可以瞬移则返回非负数,其值为该次瞬移所少走的步数;如果不能瞬移则返回-1。 + + +core.automaticRoute(destX, destY) +找寻到目标点的一条自动寻路路径。 + +// ------ 绘制地图相关 ------ // + +core.drawBlock(block, animate) +重新绘制一个图块,block为图块信息。 +如果animate不为null则代表是通过全局动画的绘制,其值为当前的帧数。 + + +core.generateGroundPattern(floorId) +生成某个楼层的地板信息。floorId不填默认为当前楼层。 +该函数可被怪物手册、对话框帧动画等地方使用。 + + +core.drawMap(floorId, callback) +绘制某层楼的地图。floorId为目标楼层ID,可不填表示当前楼层。 +此函数会将core.status.floorId设置为floorId,并设置core.status.thisMap。 +将依次调用core.drawBg(), core.drawEvents()和core.drawFg()函数,最后绘制勇士和更新地图显伤。 + + +core.drawBg(floorId, ctx) +绘制背景层。floorId为目标楼层ID,可不填表示当前楼层。 +如果ctx不为null,则背景层将绘制在该画布上而不是bg层上(drawThumbnail使用)。 +可以通过复写该函数,调整_drawFloorImages和_drawBgFgMap的顺序来调整背景图块和贴图的遮挡顺序。 + + +core.drawEvents(floorId, blocks, ctx) +绘制事件层。floorId为目标楼层ID,可不填表示当前楼层。 +block表示要绘制的图块列表,可不填使用当前楼层的图块列表。 +如果ctx不为null,则背景层将绘制在该画布上而不是event层上(drawThumbnail使用)。 + + +core.drawFg(floorId, ctx) +绘制前景层。floorId为目标楼层ID,可不填表示当前楼层。 +如果ctx不为null,则背景层将绘制在该画布上而不是fg层上(drawThumbnail使用)。 +可以通过复写该函数,调整_drawFloorImages和_drawBgFgMap的顺序来调整前景图块和贴图的遮挡顺序。 + + +core.drawThumbnail(floorId, blocks, options, toDraw) +绘制一个楼层的缩略图。floorId为目标楼层ID,可不填表示当前楼层。 +block表示要绘制的图块列表,可不填使用当前楼层的图块列表。 +options为绘制选项(可为null),包括: + heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤; + flags:当前的flags(在存读档时使用) +toDraw为要绘制到的信息(可为null,或为一个画布名),包括: + ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:绘制大小(默认416/480); + all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心) + +// ------ 获得某个点的图块信息 ------ // + +core.noPass(x, y, floorId) +判定某个点是否有noPass的图块。 + + +core.npcExists(x, y, floorId) +判定某个点是否有NPC的存在。 + + +core.terrainExists(x, y, id, floorId) +判定某个点是否有(指定的)地形存在。 +如果id为null,则只要存在terrains即为真,否则还会判定对应点的ID。 + + +core.stairExists(x, y, floorId) +判定某个点是否存在楼梯。 + + +core.nearStair() +判定当前勇士是否在楼梯上或旁边(距离不超过1)。 + + +core.enemyExists(x, y, id, floorId) +判定某个点是否有(指定的)怪物存在。 +如果id为null,则只要存在怪物即为真,否则还会判定对应点的怪物ID。 +请注意,如果需要判定某个楼层是否存在怪物请使用core.hasEnemyLeft()函数。 + + +core.getBlock(x, y, floorId, showDisable) +获得某个点的当前图块信息。x和y为坐标;floorId为楼层ID,可忽略或null表示当前楼层。 +showDisable如果为true,则对于禁用的点和事件也会进行返回。 +如果该点不存在图块,则返回null。 +否则,返回值如下: {"index": xxx, "block": xxx} +其中index为该点在该楼层blocks数组中的索引,block为该图块实际内容。 + + +core.getBlockId(x, y, floorId, showDisable) +获得某个点的图块ID。如果该点不存在图块则返回null。 + + +core.getBlockCls(x, y, floorId, showDisable) +获得某个点的图块类型。如果该点不存在图块则返回null。 + + +core.getBlockInfo(block) +根据某个的图块信息获得其详细的素材信息。 +如果参数block为字符串,则视为图块ID;如果参数为数字,则视为图块的数字。 +此函数将返回一个非常详尽的素材信息,目前包括如下几项: +number:素材数字;id:素材id;cls:素材类型;image:素材所在的素材图片;animate:素材的帧数。 +posX, posY:素材在该素材图片上的位置;height:素材的高度;faceIds:NPC朝向记录。 + + +core.searchBlock(id, floorId, showDisable) +搜索一个图块出现过的所有位置。id为图块ID,也可以传入图块的数字。 +floorId为要搜索的楼层,可以是一个楼层ID,或者一个楼层数组。如果floorId不填则只搜索当前楼层。 +showDisable如果为真,则对于禁用的图块也会返回。 +此函数将返回一个数组,每一项为一个搜索到的结果: +{"floorId": ..., "index": ..., "block": {...}, "x": ..., "y": ...} +即包含该图块所在的楼层ID,在该楼层的blocks数组的索引,图块内容,和横纵坐标。 + + +// ------ 启用和禁用图块,改变图块 ------ // + +core.showBlock(x, y, floorId) +将某个点从禁用变成启用状态。floorId可不填或null表示当前楼层。 + + +core.hideBlock(x, y, floorId) +将某个点从启用变成禁用状态,但不会对其进行删除。floorId可不填或null表示当前楼层。 +此函数不会实际将该块从地图中进行删除,而是将该点设置为禁用,以供以后可能的启用事件。 + + +core.removeBlock(x, y, floorId) +将从启用变成禁用状态,并尽可能将其从地图上删除。 +和hideBlock相比,如果该点不存在自定义事件(比如门或普通的怪物),则将直接从地图中删除。 +如果存在自定义事件,则简单的禁用它,以供以后可能的启用事件。 + + +core.removeBlockById(index, floorId) +根据索引从地图的block数组中尽可能删除一个图块。floorId可不填或null表示当前楼层。 + + +core.removeBlockByIds(floorId, ids) +根据索引数组从地图的block数组中尽可能删除一系列图块。floorId可不填或null表示当前楼层。 + + +core.canRemoveBlock(block, floorId) +判定当前能否完全删除某个图块。floorId可不填或null表示当前楼层。 +如果该点存在自定义事件,或者是重生怪,则不可进行删除。 + + +core.showBgFgMap(name, loc, floorId, callback) +显示某层楼中某个背景/前景层的图块。name只能为'bg'或'fg'表示背景或前景层。 +loc为该点坐标,floorId可不填默认为当前楼层。callback为执行完毕的回调。 + + +core.hideBgFgMap(name, loc, floorId, callback) +隐藏某层楼中某个背景/前景层的图块。name只能为'bg'或'fg'表示背景或前景层。 +loc为该点坐标,floorId可不填默认为当前楼层。callback为执行完毕的回调。 + + +core.showFloorImage(loc, floorId, callback) +显示某层楼中的某个楼层贴图。loc为该贴图的左上角坐标。floorId可省略表示当前楼层。 + + +core.hideFloorImage(loc, floorId, callback) +隐藏某层楼中的某个楼层贴图。loc为该贴图的左上角坐标。floorId可省略表示当前楼层。 + + +core.setBlock(number, x, y, floorId) +改变某个楼层的某个图块。 +number为要改变到的数字,也可以传入图块id(将调用core.getNumberById()来获得数字)。 +x,y和floorId为目标点坐标和楼层,可忽略为当前点和当前楼层。 + + +core.replaceBlock(fromNumber, toNumber, floorId) +将某个或某些楼层中的所有某个图块替换成另一个图块 +fromNumber和toNumber为要被替换和替换到的数字。 +floorId可为某个楼层ID,或者一个楼层数组;如果不填只视为当前楼层。 +值得注意的是,使用此函数转了的点上的自定义事件可能无法被执行。 +如有需要,再对那些存在事件的点执行core.setBlock()即可 + + +core.setBgFgBlock(name, number, x, y, floorId) +设置前景/背景层的某个图块。name只能为'bg'或'fg'表示前景或背景层。 +number为要设置到的图块数字,x,y和floorId为目标点坐标和楼层,可忽略为当前点和当前楼层。 + + +core.resetMap(floorId) +重置某层或若干层的地图和楼层属性。 +floorId可为某个楼层ID,或者一个楼层数组(同时重置若干层);如果不填则只重置当前楼层。 + +// ------ 移动/跳跃图块,淡入淡出图块 ------ // + +core.moveBlock(x, y, steps, time, keep, callback) +移动一个图块,x和y为图块的坐标。 +steps为移动的数组,每一项只能是"up","down","left","right"之一。 +time为每一步的移动时间,不填默认为500ms。 +如果keep为真,则在移动完毕后将自动调用一个setBlock事件,改变目标点的图块(即不消失), +否则会按照time时间来淡出消失。callback会执行完毕后的回调。 + + +core.jumpBlock(sx, sy, ex, ey, time, keep, callback) +跳跃一个图块,sx和sy为图块的坐标,ex和ey为目标坐标。time为整个跳跃过程中的全程用时,不填默认500。 +如果keep为真,则在移动完毕后将自动调用一个setBlock事件,改变目标点的图块(即不消失), +否则会按照time时间来淡出消失。callback会执行完毕后的回调。 + + +core.animateBlock(loc, type, time, callback) +淡入/淡出一个或多个图块。 +loc为一个图块坐标,或者一个二维数组表示一系列图块坐标(将同时显示和隐藏)。 +type只能为'show'或'hide'表示是淡入但是淡出。time为动画时间,callback为执行完毕的回调。 + +// ------ 全局动画控制,动画的绘制 ------ // + +core.addGlobalAnimate(block) +添加一个全局帧动画。 + + +core.removeGlobalAnimate(x, y, name) +删除一个或全部的全局帧动画。name可为'bg',null或'fg'表示某个图层。 +x和y如果为null,则会删除全部的全局帧动画,否则只会删除该点的该层的帧动画。 + + +core.drawBoxAnimate() +绘制UI层的box动画,如怪物手册和对话框中的帧动画等。 + + +core.drawAnimate(name, x, y, callback) +绘制一个动画。name为动画名,x和y为绘制的基准坐标,callback为绘制完毕的回调函数。 +此函数将播放动画音效,并异步开始绘制该动画。 +此函数会返回一个动画id,可以通过core.stopAnimate()立刻停止该动画的播放。 + + +core.stopAnimate(id, doCallback) +立刻停止某个动画的播放。id为上面core.drawAnimate的返回值。 +如果doCallback为真,则会执行该动画所对应的回调函数。 +``` + ### ui.js + + ### utils.js diff --git a/libs/actions.js b/libs/actions.js index e6f3aff0..dfc55820 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1920,7 +1920,7 @@ actions.prototype._clickSettings = function (x, y) { core.ui.drawGameInfo(); break; case 6: - return core.confirmRestart(true); + return core.confirmRestart(); case 7: core.ui.closePanel(); break; diff --git a/libs/control.js b/libs/control.js index b932169b..d97498d8 100644 --- a/libs/control.js +++ b/libs/control.js @@ -349,29 +349,6 @@ control.prototype.isPlaying = function() { return core.status.played; } -////// 重新开始游戏;此函数将回到标题页面 ////// -control.prototype.restart = function() { - this.showStartAnimate(); - core.playBgm(main.startBgm); -} - -////// 询问是否需要重新开始 ////// -control.prototype.confirmRestart = function (fromSettings) { - core.status.event.selection = 1; - core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () { - core.ui.closePanel(); - core.restart(); - }, function () { - if (fromSettings) { - core.status.event.selection = 3; - core.ui.drawSettings(); - } - else { - core.ui.closePanel(); - } - }); -} - ////// 清除游戏状态和数据 ////// control.prototype.clearStatus = function() { // 停止各个Timeout和Interval diff --git a/libs/core.js b/libs/core.js index c3040df4..7a42dc4f 100644 --- a/libs/core.js +++ b/libs/core.js @@ -341,7 +341,7 @@ core.prototype._init_others = function () { core.prototype._afterLoadResources = function (callback) { // 初始化地图 - core.initStatus.maps = core.maps.initMaps(core.floorIds); + core.initStatus.maps = core.maps._initMaps(); core.control._setRequestAnimationFrame(); core._initPlugins(); core.showStartAnimate(); diff --git a/libs/events.js b/libs/events.js index 5b7ff3b9..9917f4df 100644 --- a/libs/events.js +++ b/libs/events.js @@ -234,6 +234,23 @@ events.prototype._gameOver_askRate = function (ending) { }); } +////// 重新开始游戏;此函数将回到标题页面 ////// +events.prototype.restart = function() { + core.showStartAnimate(); + core.playBgm(main.startBgm); +} + +////// 询问是否需要重新开始 ////// +events.prototype.confirmRestart = function () { + core.status.event.selection = 1; + core.ui.drawConfirmBox("你确定要返回标题页面吗?", function () { + core.ui.closePanel(); + core.restart(); + }, function () { + core.ui.closePanel(); + }); +} + // ------ 系统事件的处理 ------ // ////// 注册一个系统事件 ////// @@ -279,10 +296,7 @@ events.prototype._trigger = function (x, y) { if (trigger == 'changeFloor' && !noPass && this._trigger_ignoreChangeFloor(block)) return; core.status.automaticRoute.moveDirectly = false; - this.doSystemEvent(trigger, block, function () { - if (trigger == 'openDoor' || trigger == 'changeFloor') - core.replay(); - }) + this.doSystemEvent(trigger, block); } } @@ -341,16 +355,20 @@ events.prototype.afterBattle = function (enemyId, x, y, callback) { } events.prototype._sys_openDoor = function (data, callback) { - this.openDoor(data.event.id, data.x, data.y, true, callback); + this.openDoor(data.x, data.y, true, function () { + core.replay(); + if (callback) callback(); + }); } ////// 开门 ////// -events.prototype.openDoor = function (id, x, y, needKey, callback) { - id = id || core.getBlockId(x, y); +events.prototype.openDoor = function (x, y, needKey, callback) { + var id = core.getBlockId(x, y); core.saveAndStopAutomaticRoute(); if (!this._openDoor_check(id, x, y, needKey)) { + var locked = core.status.lockControl; core.waitHeroToStop(function () { - core.unLockControl(); + if (!locked) core.unLockControl(); if (callback) callback(); }); return; @@ -376,7 +394,7 @@ events.prototype._openDoor_check = function (id, x, y, needKey) { core.clearContinueAutomaticRoute(); return false; } - core.autosave(true); + if (!core.status.event.id) core.autosave(true); core.removeItem(key); } return true; @@ -386,6 +404,7 @@ events.prototype._openDoor_animate = function (id, x, y, callback) { var door = core.material.icons.animates[id]; var speed = id.endsWith("Door") ? 30 : 70; + var locked = core.status.lockControl; core.lockControl(); core.status.replay.animate = true; var state = 0; @@ -394,7 +413,7 @@ events.prototype._openDoor_animate = function (id, x, y, callback) { if (state == 4) { clearInterval(animate); core.removeBlock(x, y); - core.unLockControl(); + if (!locked) core.unLockControl(); core.status.replay.animate = false; core.events.afterOpenDoor(id, x, y, callback); return; @@ -414,29 +433,33 @@ events.prototype._sys_getItem = function (data, callback) { } ////// 获得某个物品 ////// -events.prototype.getItem = function (itemId, itemNum, itemX, itemY, callback) { - itemNum = itemNum || 1; - var itemCls = core.material.items[itemId].cls; - core.items.getItemEffect(itemId, itemNum); - core.removeBlock(itemX, itemY); - var text = '获得 ' + core.material.items[itemId].name; - if (itemNum > 1) text += "x" + itemNum; - if (itemCls === 'items') text += core.items.getItemEffectTip(itemId); - core.drawTip(text, core.material.icons.items[itemId]); +events.prototype.getItem = function (id, num, x, y, callback) { + num = num || 1; + var itemCls = core.material.items[id].cls; + core.items.getItemEffect(id, num); + core.removeBlock(x, y); + var text = '获得 ' + core.material.items[id].name; + if (num > 1) text += "x" + num; + if (itemCls === 'items') text += core.items.getItemEffectTip(id); + core.drawTip(text, core.material.icons.items[id]); core.updateStatusBar(); - this.eventdata.afterGetItem(itemId, itemX, itemY, callback); + this.afterGetItem(id, x, y, callback); +} + +events.prototype.afterGetItem = function (id, x, y, callback) { + this.eventdata.afterGetItem(id, x, y, callback); } ////// 获得面前的物品(轻按) ////// -events.prototype.getNextItem = function () { +events.prototype.getNextItem = function (noRoute) { if (core.isMoving() || !core.canMoveHero() || !core.flags.enableGentleClick) return false; var nextX = core.nextX(), nextY = core.nextY(); var block = core.getBlock(nextX, nextY); if (block == null) return false; if (block.block.event.trigger == 'getItem') { - core.status.route.push("getNext"); + if (!noRoute) core.status.route.push("getNext"); this.getItem(block.block.event.id, 1, nextX, nextY); return true; } @@ -449,7 +472,10 @@ events.prototype._sys_changeFloor = function (data, callback) { if (data.loc) heroLoc = {'x': data.loc[0], 'y': data.loc[1]}; if (data.direction) heroLoc.direction = data.direction; if (core.status.event.id != 'action') core.status.event.id = null; - core.changeFloor(data.floorId, data.stair, heroLoc, data.time, callback); + core.changeFloor(data.floorId, data.stair, heroLoc, data.time, function () { + core.replay(); + if (callback) callback(); + }); } ////// 楼层切换 ////// @@ -461,6 +487,7 @@ events.prototype.changeFloor = function (floorId, stair, heroLoc, time, callback } info.fromLoad = fromLoad; floorId = info.floorId; + info.locked = core.status.lockControl; core.dom.floorNameLabel.innerHTML = core.status.maps[floorId].title; core.lockControl(); @@ -553,7 +580,7 @@ events.prototype._changeFloor_changing = function (info, callback) { } events.prototype._changeFloor_afterChange = function (info, callback) { - core.unLockControl(); + if (!info.locked) core.unLockControl(); core.status.replay.animate = false; core.events.afterChangeFloor(info.floorId, info.fromLoad); @@ -661,11 +688,6 @@ events.prototype._sys_changeLight = function (data, callback) { events.prototype.changeLight = function (id, x, y) { if (id != null && id != 'light') return; core.setBlock(core.getNumberById('darkLight'), x, y); - this.afterChangeLight(x, y); -} - -////// 改变亮灯之后,可以触发的事件 ////// -events.prototype.afterChangeLight = function (x, y) { return this.eventdata.afterChangeLight(x, y); } @@ -724,8 +746,19 @@ events.prototype.doEvent = function (data, x, y, prefix) { core.doAction(); } +events.prototype.setEvents = function (list, x, y, callback) { + var data = core.status.event.data || {}; + if (list) + data.list = [{todo: core.clone(list), total: core.clone(list), condition: "false"}]; + if (x != null) data.x = x; + if (y != null) data.y = y; + if (callback) data.callback = callback; + core.status.event.id = 'action'; + core.status.event.data = data; +} + ////// 开始执行一系列自定义事件 ////// -events.prototype.doEvents = function (list, x, y, callback) { +events.prototype.startEvents = function (list, x, y, callback) { if (!list) return; if (!(list instanceof Array)) { list = [list]; @@ -738,17 +771,6 @@ events.prototype.doEvents = function (list, x, y, callback) { }); } -events.prototype.setEvents = function (list, x, y, callback) { - var data = core.status.event.data || {}; - if (list) - data.list = [{todo: core.clone(list), total: core.clone(list), condition: "false"}]; - if (x != null) data.x = x; - if (y != null) data.y = y; - if (callback) data.callback = callback; - core.status.event.id = 'action'; - core.status.event.data = data; -} - ////// 执行当前自定义事件列表中的下一个事件 ////// events.prototype.doAction = function () { // 清空boxAnimate和UI层 @@ -799,7 +821,7 @@ events.prototype._popEvents = function (current, prefix) { return false; } -////// 往当前事件列表之前添加一个或多个事件 ////// +////// 往当前事件列表之前或之后添加一个或多个事件 ////// events.prototype.insertAction = function (action, x, y, callback, addToLast) { if (core.hasFlag("__statistics__")) return; if (core.status.gameOver) return; @@ -810,7 +832,7 @@ events.prototype.insertAction = function (action, x, y, callback, addToLast) { if (!action) return; if (core.status.event.id != 'action') { - this.doEvents(action, x, y, callback); + this.startEvents(action, x, y, callback); } else { if (addToLast) @@ -1022,10 +1044,7 @@ events.prototype._action_jumpHero = function (data, x, y, prefix) { events.prototype._action_changeFloor = function (data, x, y, prefix) { var loc = this.__action_getHeroLoc(data.loc, prefix); var heroLoc = {x: loc[0], y: loc[1], direction: data.direction}; - core.changeFloor(data.floorId || core.status.floorId, null, heroLoc, data.time, function () { - core.lockControl(); - core.doAction(); - }); + core.changeFloor(data.floorId || core.status.floorId, null, heroLoc, data.time, core.doAction); } events.prototype._action_changePos = function (data, x, y, prefix) { @@ -1101,10 +1120,7 @@ events.prototype._action_openDoor = function (data, x, y, prefix) { var loc = this.__action_getLoc(data.loc, x, y, prefix); var floorId = data.floorId || core.status.floorId; if (floorId == core.status.floorId) { - core.openDoor(null, loc[0], loc[1], data.needKey, function () { - core.lockControl(); - core.doAction(); - }); + core.openDoor(loc[0], loc[1], data.needKey, core.doAction); } else { core.removeBlock(loc[0], loc[1], floorId); @@ -1152,14 +1168,10 @@ events.prototype._action_trigger = function (data, x, y, prefix) { if (block != null && block.block.event.trigger) { block = block.block; this.setEvents([], block.x, block.y); - var _callback = function () { - core.lockControl(); - core.doAction(); - } if (block.event.trigger == 'action') this.setEvents(block.event.data); else { - core.doSystemEvent(block.event.trigger, block, _callback); + core.doSystemEvent(block.event.trigger, block, core.doAction); return; } } @@ -1703,24 +1715,6 @@ events.prototype.unfollow = function (name) { core.drawHero(); } -////// 绘制或取消一张gif图片 ////// -events.prototype.showGif = function (name, x, y) { - var image = core.material.images.images[name]; - if (image) { - var gif = new Image(); - gif.src = image.src; - gif.style.position = 'absolute'; - gif.style.left = x * core.domStyle.scale + "px"; - gif.style.top = y * core.domStyle.scale + "px"; - gif.style.width = image.width * core.domStyle.scale + "px"; - gif.style.height = image.height * core.domStyle.scale + "px"; - core.dom.gif2.appendChild(gif); - } - else { - core.dom.gif2.innerHTML = ""; - } -} - ////// 数值操作 ////// events.prototype.setValue = function (name, value, prefix, add) { var value = core.calValue(value, prefix); @@ -1924,6 +1918,24 @@ events.prototype._moveImage_moving = function (name, moveInfo, callback) { core.animateFrame.asyncId[animate] = true; } +////// 绘制或取消一张gif图片 ////// +events.prototype.showGif = function (name, x, y) { + var image = core.material.images.images[name]; + if (image) { + var gif = new Image(); + gif.src = image.src; + gif.style.position = 'absolute'; + gif.style.left = x * core.domStyle.scale + "px"; + gif.style.top = y * core.domStyle.scale + "px"; + gif.style.width = image.width * core.domStyle.scale + "px"; + gif.style.height = image.height * core.domStyle.scale + "px"; + core.dom.gif2.appendChild(gif); + } + else { + core.dom.gif2.innerHTML = ""; + } +} + ////// 淡入淡出音乐 ////// events.prototype.setVolume = function (value, time, callback) { var set = function (value) { @@ -2214,7 +2226,7 @@ events.prototype.afterUseBomb = function () { } ////// 上传当前数据 ////// -events.prototype.uploadCurrent = function (username) { +events.prototype._uploadCurrent = function (username) { var formData = new FormData(); formData.append('type', 'score'); diff --git a/libs/items.js b/libs/items.js index 23056d8d..8a89e7a7 100644 --- a/libs/items.js +++ b/libs/items.js @@ -196,20 +196,6 @@ items.prototype.setItem = function (itemId, itemNum) { core.updateStatusBar(); } -////// 删除某个物品 ////// -items.prototype.removeItem = function (itemId, itemNum) { - if (itemNum == null) itemNum = 1; - if (!core.hasItem(itemId)) return false; - var itemCls = core.material.items[itemId].cls; - core.status.hero.items[itemCls][itemId] -= itemNum; - if (core.status.hero.items[itemCls][itemId] <= 0) { - if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; - else core.status.hero.items[itemCls][itemId] = 0; - } - core.updateStatusBar(); - return true; -} - ////// 增加某个物品的个数 ////// items.prototype.addItem = function (itemId, itemNum) { if (itemNum == null) itemNum = 1; @@ -230,15 +216,22 @@ items.prototype.addItem = function (itemId, itemNum) { core.updateStatusBar(); } -// ---------- 装备相关 ------------ // - -items.prototype.getEquipTypeById = function (equipId) { - var type = core.material.items[equipId].equip.type; - if (typeof type == 'string') - type = this.getEquipTypeByName(type); - return type; +////// 删除某个物品 ////// +items.prototype.removeItem = function (itemId, itemNum) { + if (itemNum == null) itemNum = 1; + if (!core.hasItem(itemId)) return false; + var itemCls = core.material.items[itemId].cls; + core.status.hero.items[itemCls][itemId] -= itemNum; + if (core.status.hero.items[itemCls][itemId] <= 0) { + if (itemCls != 'keys') delete core.status.hero.items[itemCls][itemId]; + else core.status.hero.items[itemCls][itemId] = 0; + } + core.updateStatusBar(); + return true; } +// ---------- 装备相关 ------------ // + items.prototype.getEquipTypeByName = function (name) { var names = core.status.globalAttribute.equipName; for (var i = 0; i < names.length; ++i) { @@ -249,6 +242,13 @@ items.prototype.getEquipTypeByName = function (name) { return -1; } +items.prototype.getEquipTypeById = function (equipId) { + var type = core.material.items[equipId].equip.type; + if (typeof type == 'string') + type = this.getEquipTypeByName(type); + return type; +} + // 当前能否撞上某装备 items.prototype.canEquip = function (equipId, hint) { // 装备是否合法 diff --git a/libs/maps.js b/libs/maps.js index 4a974ced..f03bfe60 100644 --- a/libs/maps.js +++ b/libs/maps.js @@ -155,7 +155,8 @@ maps.prototype._addEvent = function (block, x, y, event) { } ////// 初始化所有地图 ////// -maps.prototype.initMaps = function (floorIds) { +maps.prototype._initMaps = function () { + var floorIds = core.floorIds; var maps = {}; for (var i = 0; i < floorIds.length; i++) { var floorId = floorIds[i]; @@ -242,7 +243,7 @@ maps.prototype.saveMap = function (floorId) { return map; } var map = maps[floorId], floor = core.floors[floorId]; - var blocks = this.getMapArray(map.blocks, floor.width, floor.height, true); + var blocks = this._getMapArrayFromBlocks(map.blocks, floor.width, floor.height, true); if (main.mode == 'editor') return blocks; var thisFloor = this._compressFloorData(map, floor); @@ -297,7 +298,13 @@ maps.prototype.resizeMap = function (floorId) { } ////// 将当前地图重新变成二维数组形式 ////// -maps.prototype.getMapArray = function (blockArray, width, height, checkDisable) { +maps.prototype.getMapArray = function (floorId, showDisable) { + floorId = floorId || core.status.floorId; + return this._getMapArrayFromBlocks(core.status.maps[floorId].blocks, + core.floors[floorId].width, core.floors[floorId].height, showDisable); +} + +maps.prototype._getMapArrayFromBlocks = function (blockArray, width, height, showDisable) { if (typeof blockArray == 'string') { var floorId = blockArray; blockArray = core.status.maps[floorId].blocks; @@ -313,11 +320,11 @@ maps.prototype.getMapArray = function (blockArray, width, height, checkDisable) blockArray.forEach(function (block) { var x = block.x, y = block.y; if (block.disable) { - if (checkDisable) blocks[y][x] = block.id + ":f"; + if (showDisable) blocks[y][x] = block.id + ":f"; } else { blocks[y][x] = block.id; - if (checkDisable && block.disable === false) + if (showDisable && block.disable === false) blocks[y][x] = block.id + ":t"; } }); @@ -336,7 +343,7 @@ maps.prototype.getMapBlocksObj = function (floorId, showDisable) { } ////// 将背景前景层变成二维数组的形式 ////// -maps.prototype.getBgFgMapArray = function (name, floorId, noCache) { +maps.prototype._getBgFgMapArray = function (name, floorId, noCache) { floorId = floorId || core.status.floorId; if (!floorId) return []; var width = core.floors[floorId].width; @@ -363,25 +370,25 @@ maps.prototype.getBgFgMapArray = function (name, floorId, noCache) { } maps.prototype.getBgMapArray = function (floorId, noCache) { - return this.getBgFgMapArray('bg', floorId, noCache); + return this._getBgFgMapArray('bg', floorId, noCache); } maps.prototype.getFgMapArray = function (floorId, noCache) { - return this.getBgFgMapArray('fg', floorId, noCache); + return this._getBgFgMapArray('fg', floorId, noCache); } -maps.prototype.getBgFgNumber = function (name, x, y, floorId, noCache) { +maps.prototype._getBgFgNumber = function (name, x, y, floorId, noCache) { 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, noCache)[y][x]; } maps.prototype.getBgNumber = function (x, y, floorId, noCache) { - return this.getBgFgNumber('bg', x, y, floorId, noCache); + return this._getBgFgNumber('bg', x, y, floorId, noCache); } maps.prototype.getFgNumber = function (x, y, floorId, noCache) { - return this.getBgFgNumber('fg', x, y, floorId, noCache); + return this._getBgFgNumber('fg', x, y, floorId, noCache); } // ------ 当前能否朝某方向移动,能否瞬间移动 ------ // @@ -701,7 +708,7 @@ maps.prototype._drawMap_drawAll = function (floorId) { maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, onMap) { if (blockInfo == null) return; if (blockInfo.cls == 'autotile') { // Autotile单独处理 - this.drawAutotile(ctx, arr, block, 32, 0, 0); + this._drawAutotile(ctx, arr, block, 32, 0, 0); if (onMap) this.addGlobalAnimate(block); return; } @@ -716,15 +723,16 @@ maps.prototype._drawMap_drawBlockInfo = function (ctx, block, blockInfo, arr, on ////// 绘制背景层 ////// maps.prototype.drawBg = function (floorId, ctx) { + floorId = floorId || core.status.floorId; var onMap = ctx == null; if (onMap) { ctx = core.canvas.bg; core.clearMap(ctx); } - this._drawBg_drawBackground(floorId, ctx); + core.maps._drawBg_drawBackground(floorId, ctx); // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 - this._drawFloorImages(floorId, ctx, 'bg'); - this._drawBgFgMap(floorId, ctx, 'bg', onMap); + core.maps._drawFloorImages(floorId, ctx, 'bg'); + core.maps._drawBgFgMap(floorId, ctx, 'bg', onMap); } maps.prototype._drawBg_drawBackground = function (floorId, ctx) { @@ -744,7 +752,7 @@ maps.prototype._drawBg_drawBackground = function (floorId, ctx) { maps.prototype.drawEvents = function (floorId, blocks, ctx) { floorId = floorId || core.status.floorId; if (!blocks) blocks = core.status.maps[floorId].blocks; - var arr = this.getMapArray(blocks, core.floors[floorId].width, core.floors[floorId].height); + var arr = this._getMapArrayFromBlocks(blocks, core.floors[floorId].width, core.floors[floorId].height); var onMap = ctx == null; if (onMap) ctx = core.canvas.event; blocks.filter(function (block) { @@ -757,6 +765,7 @@ maps.prototype.drawEvents = function (floorId, blocks, ctx) { ////// 绘制前景层 ////// maps.prototype.drawFg = function (floorId, ctx) { + floorId = floorId || core.status.floorId; var onMap = ctx == null; if (onMap) ctx = core.canvas.fg; // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 @@ -774,7 +783,7 @@ 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 arr = this._getBgFgMapArray(name, floorId, true); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var block = this.initBlock(x, y, arr[y][x], true); @@ -866,7 +875,7 @@ maps.prototype._drawFloorImage = function (ctx, name, type, image, offsetX, widt } ////// 绘制Autotile ////// -maps.prototype.drawAutotile = function (ctx, mapArr, block, size, left, top, status) { +maps.prototype._drawAutotile = function (ctx, mapArr, block, size, left, top, status) { var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块 // +----+----+----+----+----+----+ [10, 9, 4, 3], //0 bin:0000 | 1 | 2 | 3 | 4 | 5 | 6 | @@ -1231,7 +1240,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 (block.event.id == id && (showDisable || !block.disable)) - result.push({floorId: floorId, index: i, block: block}); + result.push({floorId: floorId, index: i, block: block, x: block.x, y: block.y}); } return result; } @@ -1317,19 +1326,6 @@ maps.prototype.removeBlockById = function (index, floorId) { } } -////// 能否彻底从地图中删除一个图块 ////// -maps.prototype.canRemoveBlock = function (block, floorId) { - var x = block.x, y = block.y; - // 检查该点是否存在事件 - if (core.floors[floorId].events[x + "," + y] || core.floors[floorId].changeFloor[x + "," + y]) - return false; - // 检查是否存在重生 - if (block.event && block.event.cls.indexOf('enemy') == 0 && core.hasSpecial(block.event.id, 23)) - return false; - - return true; -} - ////// 一次性删除多个block ////// maps.prototype.removeBlockByIds = function (floorId, ids) { floorId = floorId || core.status.floorId; @@ -1341,24 +1337,17 @@ maps.prototype.removeBlockByIds = function (floorId, ids) { }); } -////// 将地图中所有某个图块替换成另一个图块 ////// -maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) { - floorId = floorId || core.status.floorId; - if (floorId instanceof Array) { - floorId.forEach(function (floorId) { - core.replaceBlock(fromNumber, toNumber, floorId); - }); - return; - } - var toBlock = this.initBlock(0, 0, toNumber, true); - core.status.maps[floorId].blocks.forEach(function (block) { - if (block.id == fromNumber) { - block.id = toNumber; - for (var one in toBlock.event) { - block.event[one] = core.clone(toBlock.event[one]); - } - } - }); +////// 能否彻底从地图中删除一个图块 ////// +maps.prototype.canRemoveBlock = function (block, floorId) { + var x = block.x, y = block.y; + // 检查该点是否存在事件 + if (core.floors[floorId].events[x + "," + y] || core.floors[floorId].changeFloor[x + "," + y]) + return false; + // 检查是否存在重生 + if (block.event && block.event.cls.indexOf('enemy') == 0 && core.hasSpecial(block.event.id, 23)) + return false; + + return true; } ////// 显示前景/背景地图 ////// @@ -1436,6 +1425,7 @@ maps.prototype.setBlock = function (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 (typeof number == 'string') number = core.getNumberById(number); var originBlock = core.getBlock(x, y, floorId, true); var block = this.initBlock(x, y, number, true, core.floors[floorId]); @@ -1463,6 +1453,26 @@ maps.prototype.setBlock = function (number, x, y, floorId) { } } +////// 将地图中所有某个图块替换成另一个图块 ////// +maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) { + floorId = floorId || core.status.floorId; + if (floorId instanceof Array) { + floorId.forEach(function (floorId) { + core.replaceBlock(fromNumber, toNumber, floorId); + }); + return; + } + var toBlock = this.initBlock(0, 0, toNumber, true); + core.status.maps[floorId].blocks.forEach(function (block) { + if (block.id == fromNumber) { + block.id = toNumber; + for (var one in toBlock.event) { + block.event[one] = core.clone(toBlock.event[one]); + } + } + }); +} + ////// 改变前景背景的图块 ////// maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) { floorId = floorId || core.status.floorId; @@ -1776,16 +1786,16 @@ maps.prototype._animateBlock_drawList = function (list, opacity) { // ------ 全局动画控制,动画绘制 ------ // ////// 添加一个全局动画 ////// -maps.prototype.addGlobalAnimate = function (b) { - if (!b.event || b.event.animate == null) return; - if (b.event.cls == 'autotile') { - var id = b.event.id, img = core.material.images.autotile[id]; +maps.prototype.addGlobalAnimate = function (block) { + if (!block.event || block.event.animate == null) return; + 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(b); + core.status.autotileAnimateObjs.blocks.push(block); } else { - if (!b.event.animate || b.event.animate == 1) return; - core.status.globalAnimateObjs.push(b); + if (!block.event.animate || block.event.animate == 1) return; + core.status.globalAnimateObjs.push(block); } } diff --git a/libs/utils.js b/libs/utils.js index 26c8b8e2..d1a9f0c7 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -1080,7 +1080,7 @@ utils.prototype._export = function (floorIds) { // map var content = floorIds.length + "\n" + core.__SIZE__ + " " + core.__SIZE__ + "\n\n"; floorIds.forEach(function (floorId) { - var arr = core.maps.getMapArray(core.status.maps[floorId].blocks); + var arr = core.maps._getMapArrayFromBlocks(core.status.maps[floorId].blocks); content += arr.map(function (x) { // check monster x.forEach(function (t) { From b91e40c03763a9ab8a3db04e7f57818dc4aa8c38 Mon Sep 17 00:00:00 2001 From: oc Date: Wed, 3 Apr 2019 22:33:30 +0800 Subject: [PATCH 145/153] initPlugins & musicBtn & clearStatus --- libs/control.js | 5 ++--- libs/core.js | 2 +- libs/events.js | 5 ----- project/functions.js | 1 + 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libs/control.js b/libs/control.js index d97498d8..c4b93ffa 100644 --- a/libs/control.js +++ b/libs/control.js @@ -323,8 +323,6 @@ control.prototype._showStartAnimate_resetDom = function () { core.dom.levelChooseButtons.style.display = 'none'; core.status.played = false; core.clearStatus(); - core.clearMap('all'); - core.deleteAllCanvas(); core.dom.musicBtn.style.display = 'block'; core.setMusicBtn(); // 重置音量 @@ -362,6 +360,7 @@ control.prototype.clearStatus = function() { } core.status = {}; core.clearStatusBar(); + core.clearMap('all'); core.deleteAllCanvas(); core.status.played = false; } @@ -2524,7 +2523,7 @@ control.prototype._resize_gameGroup = function (obj) { floorMsgGroup.style.color = obj.globalAttribute.floorChangingTextColor; // musicBtn if (core.domStyle.isVertical || core.domStyle.scale < 1) { - core.dom.musicBtn.style.right = core.dom.musicBtn.style.height = "3px"; + core.dom.musicBtn.style.right = core.dom.musicBtn.style.bottom = "3px"; } else { core.dom.musicBtn.style.right = (obj.clientWidth - totalWidth) / 2 + "px"; diff --git a/libs/core.js b/libs/core.js index 7a42dc4f..97069384 100644 --- a/libs/core.js +++ b/libs/core.js @@ -219,6 +219,7 @@ core.prototype.init = function (coreData, callback) { this._init_flags(); this._init_platform(); this._init_others(); + this._initPlugins(); core.loader._load(function () { core._afterLoadResources(callback); @@ -343,7 +344,6 @@ core.prototype._afterLoadResources = function (callback) { // 初始化地图 core.initStatus.maps = core.maps._initMaps(); core.control._setRequestAnimationFrame(); - core._initPlugins(); core.showStartAnimate(); if (callback) callback(); } diff --git a/libs/events.js b/libs/events.js index 9917f4df..63438d3a 100644 --- a/libs/events.js +++ b/libs/events.js @@ -52,9 +52,6 @@ events.prototype._startGame_start = function (hard, seed, route, callback) { } else core.utils.__init_seed(); this.setInitData(); - - core.clearMap('all'); - core.deleteAllCanvas(); core.clearStatusBar(); var todo = []; @@ -1657,8 +1654,6 @@ events.prototype.load = function (fromUserAction) { if (!core.isPlaying()) { core.dom.startPanel.style.display = 'none'; core.clearStatus(); - core.clearMap('all'); - core.deleteAllCanvas(); core.status.event = {'id': 'load', 'data': null}; core.status.lockControl = true; core.ui.drawSLPanel(10*page+offset); diff --git a/project/functions.js b/project/functions.js index 07507e3d..4e4c0762 100644 --- a/project/functions.js +++ b/project/functions.js @@ -6,6 +6,7 @@ var functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a = // hero:勇士信息;hard:难度;floorId:当前楼层ID;maps:地图信息;values:全局数值信息 // 清除游戏数据 + // 这一步会清空状态栏和全部画布内容,并删除所有动态创建的画布 core.clearStatus(); // 初始化status core.status = core.clone(core.initStatus); From 7fd843bf44389fb3e3d3a689d9d687f10c8480c7 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 4 Apr 2019 01:50:50 +0800 Subject: [PATCH 146/153] api docs --- _docs/api.md | 493 ++++++++++++++++++++++++++++++++++++++++++++- libs/actions.js | 10 +- libs/control.js | 4 +- libs/core.js | 2 + libs/events.js | 11 +- libs/items.js | 4 +- libs/ui.js | 121 ++++++----- libs/utils.js | 82 +++----- project/plugins.js | 22 +- 9 files changed, 625 insertions(+), 124 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index 8d085971..efe18684 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -215,7 +215,7 @@ core.events._changeFloor_beforeChange = function (info, callback) { if (info.time == 0) core.events._changeFloor_changing(info, callback); else - core.show(core.dom.floorMsgGroup, info.time / 2, function () { + core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () { core.events._changeFloor_changing(info, callback); }); }, 25) @@ -724,6 +724,8 @@ name:自定义名称,可用户注销使用。 func:具体执行录像的函数,是一个函数体或者插件中的函数名。 func需要接受action参数,代表录像回放时的当前操作行为。 如果func返回true,则代表成功处理了此次操作,返回false代表没有进行处理。 +自己添加的录像项只能由数字、大小写、下划线线、冒号等符号组成,否则无法正常压缩和解压缩。 +对于自定义内容(比如中文文本或数组)请使用JSON.stringify再core.encodeBase64处理。 请注意回放录像时的二次记录问题(即回放时录像会重新记录路线)。 @@ -1842,6 +1844,495 @@ core.stopAnimate(id, doCallback) ### ui.js +ui.js负责一切UI界面的绘制。主要包括三个部分: +- 设置某个画布的属性的相关API +- 具体的某个UI界面的绘制 +- 动态创建画布相关的API +```js +// ------ 设置某个画布的属性的相关API ------// +这系列函数的name一般都是画布名,可以是系统画布或动态创建的画布。 +但也同时也允许直接传画布的context本身,将返回自身。 + + +core.getContextByName(name) +根据画布名找到一个画布的context;支持系统画布和自定义画布。 +如果不存在画布此函数返回null。 +该参数也可以直接传画布的context自身,则返回自己。 + + +core.clearMap(name) +清空某个画布图层。 +该函数的name也可以是'all',若为'all'则为清空所有系统画布。 + + +core.fillText(name, text, x, y, style, font) +在某个画布上绘制一段文字。 +text为要绘制的文本,x,y为要绘制的坐标,style可选为绘制的样式,font可选为绘制的字体。(下同) +请注意textAlign和textBaseline将决定绘制的左右对齐和上下对齐方式。 +具体可详见core.setTextAlign()和core.setTextBaseline()函数。 + + +core.fillBoldText(name, text, x, y, style, font) +在某个画布上绘制一个描黑边的文字。 + + +core.fillRect(name, x, y, width, height, style) +绘制一个矩形。style可选为绘制样式。如果设置将调用core.setFillStyle()。(下同) + + +core.strokeRect(name, x, y, width, height, style, lineWidth) +绘制一个矩形的边框。style可选为绘制样式,如果设置将调用core.setStrokeStyle()。 +lineWidth如果设置将调用core.setLineWidth()。(下同) + + +core.drawLine(name, x1, y1, x2, y2, style, lineWidth) +绘制一条线。 + + +core.drawArrow(name, x1, y1, x2, y2, style, lineWidth) +绘制一个箭头。 + + +core.setFont(name, font) / core.setLineWidth(name, lineWidth) +设置一个画布的字体/线宽。 + + +core.setAlpha(name, font) / core.setOpacity(name, font) +设置一个画布的绘制不透明度和画布本身的不透明度。 +两者区别如下: + - setAlpha是设置"接下来绘制的内容的不透明度",不会对已经绘制的内容产生影响。 + > 比如setAlpha('ui', 0.5)则会在接下来的绘制中使用0.5的不透明度。 + - setOpacity是设置"画布本身的不透明度",已经绘制的内容也会产生影响。 + > 比如我已经在UI层绘制了一段文字,再setOpacity则也会让已经绘制的文字变得透明。 +尽量不要对系统画布使用setOpacity(因为会对已经绘制的内容产生影响),自定义创建的画布则不受此限制。 + + +core.setFillStyle(name, style) / core.setStrokeStyle(name, style) +设置一个画布的填充样式/描边样式。 + + +core.setTextAlign(name, align) +设置一个画布的文字横向对齐模式,这里的align只能为'left', 'right'和'center'。 +默认为'left'。 + + +core.setTextBaseline(name, baseline) +设置一个画布的纵向对齐模式。有关textBaseline的说明可参见如下资料: +http://www.runoob.com/tags/canvas-textbaseline.html +默认值是'alphabetic'。 +请注意,系统画布在绘制前都是没有设置过textBaseline的,都是按照alphabetic进行坐标绘制。 +因此,如果你修改了系统画布的textBaseline来绘图,记得再绘制完毕后修改回来。 + + +core.calWidth(name, text, font) +计算一段文字在某个画布上的绘制宽度,此函数其实是ctx.measureText()的包装。 +font可选,如果存在则会先设置该画布上的字体。 +此函数不会对文字进行换行,如需换行版本请使用core.splitLines()函数。 + + +core.splitLines(name, text, maxWidth, font) +计算一段文字在某画布上换行分割的结果。 +text为文字内容,maxWidth为最大宽度,可为null表示不自动换行。 +font可选,如果存在则会先设置该画布上的字体。 +此函数将返回一个换行完毕的文本列表。 + + +core.drawImage(name, image, x, y, w, h, x1, y1, w1, h1) +在一张画布上绘制一张图片,此函数其实是ctx.drawImage()的包装。 +可以查看下面的文档以了解各项参数的信息: +http://www.w3school.com.cn/html5/canvas_drawimage.asp +这里的image允许传一个图片,画布。也允许传递图片名,将从你导入的图片中获取图片内容。 + +// ------ 具体的某个UI界面的绘制 ------ // +core.closePanel() +结束一切事件和UI绘制,关闭UI窗口,返回游戏。 +此函数将以此调用core.clearUI(),core.unlockControl(),并清空core.status.event里面的内容。 + + +core.clearUI() +重置UI窗口。此函数将清掉所有的UI帧动画和光标,清空UI画布,并将alpha设为1。 + + +core.drawTip(text, id) +在左上角以气泡的形式绘制一段提示。 +text为文字内容,仅支持${}的表达式计算,不支持换行和变色。 +id可选,为同时绘制的图标ID,如果不为null则会同时绘制该图标(仅对32x32的素材有效)。 + + +core.drawText(content, callback) +绘制一段文字。contents为一个字符串或一个字符串数组,callback为全部绘制完毕的回调。 +支持所有的文字效果(如\n,${},\r,\\i等),也支持\t和\b的语法。 +如果当前在事件处理中或录像回放中,则会自动转成core.insertAction处理。 +不建议使用该函数,如有绘制文字的需求请尽量使用core.insertAction()插入剧情文本事件。 + + +core.drawWindowSelector(background, x, y, w, h) +绘制一个WindowSkin的闪烁光标。background可为winskin的图片名或图片本身。 +x,y,w,h为绘制的左上角位置和宽高,都是像素为单位。 + + +core.drawWindowSkin(background, ctx, x, y, w, h, direction, px, py) +绘制一个WindowSkin。background可为winskin的图片名或图片本身。 +ctx为画布名或画布本身,x,y,w,h为左上角位置和宽高,都是像素为单位。 +direction, px, py可选,如果设置则会绘制一个对话框箭头。 + + +core.drawBackground(left, top, right, bottom, posInfo) +绘制一个背景图。此函数将使用你在【剧情文本设置】中设置的背景,即用纯色或WindowSkin来绘制。 +left, top, right, bottom为你要绘制的左上角和右下角的坐标。 +posInfo如果不为null则是一个含position, px和py的对象,表示一个对话框箭头的绘制。 + + +core.drawTextContent(ctx, content, config) +根据配置在某个画布上绘制一段文字。此函数会被core.drawTextBox()所调用。 +ctx为画布名或画布本身,如果不设置则会忽略该函数。 +content为要绘制的文字内容,支持所有的文字效果(如\n,${},\r,\\i等),但不支持支持\t和\b的语法。 +config为绘制的配置项,目前可以包括如下几项: + - left, top:在该画布上绘制的左上角像素位置,不设置默认为(0,0)。 + > 该函数绘制时会将textBaseline设置为'top',因此只需要考虑第一个字的左上角位置。 + - maxWidth:单行最大宽度,超过此宽度将自动换行,不设置不会自动换行。 + - color:默认颜色,为#XXXXXX形式。如果不设置则使用剧情文本设置中的正文颜色。 + - bold:是否粗体。如果不设置默认为false。 + - align:文字对齐方式,仅在maxWidth设置时有效,默认为'left'。 + - fontSize:字体大小,如果不设置则使用剧情文本设置中的正文字体大小。 + - lineHeight:绘制的行距值,如果不设置则使用fontSize*1.3(即1.3被行距)。 + - time:打字机效果。如果此项不为0,则会用打字机效果逐个字进行绘制,并设置core.status.event.interval定时器。 + + +core.drawTextBox(content, showAll) +绘制一个对话框。content为一个字符串或一个字符串数组。 +支持所有的文字效果(如\n,${},\r,\\i等),也支持\t和\b的语法。 +该函数将使用用户在剧情文本设置中的配置项进行绘制。 +实际执行时,会计算文本框宽度并绘制背景,绘制标题和头像,再调用core.drawTextContent()绘制正文内容。 +showAll可选,如果为true则不会使用打字机效果而全部显示,主要用于打字机效果的点击显示全部。 + + +core.drawScrollText(content, time, lineHeight, callback) +绘制一个滚动字幕。content为绘制内容,time为总滚动时间(默认为5000),lineHeight为行距比例(默认为1.4)。 +滚动字幕将绘制在UI上,支持所有的文字效果(如\n,${},\r,\\i等),但不支持\t和\b效果。 +可以通过剧情文本设置中的align控制是否居中绘制,offset控制其距离左边的偏移量。 + + +core.textImage(content, lineHeight) +将文本图片化。content为绘制内容,lineHeight为行距比例(默认为1.4)。 +可以通过剧情文本设置中的align控制是否居中绘制。 +此函数将返回一个临时画布的canvas,供转绘到其他画布上使用。 + + +core.drawChoices(content, choices) +绘制一个选项框。 +content可选,为选项上方的提示文字,支持所有的文字效果(如\n,${},\r,\\i等),也支持\t效果。 +choices必选,为要绘制的选项内容,是一个列表。其中的每一项: + - 可以是一个字符串,表示选项文字,将使用剧情文本设置中的正文颜色来绘制,仅支持${}表达式计算。 + - 或者是一个包含text, color和icon的对象。 + > text必选,为要绘制的文字内容,仅支持${}的表达式计算, + > color为要绘制的选项颜色,可以是#XXXXXX的格式或RGBA数组。不设置则使用正文颜色。 + > icon为要绘制的图标ID,支持使用素材的ID,或者系统图标。 + + +core.drawConfirmBox(text, yesCallback, noCallback) +绘制一个确认框。text为确认文字,支持\n换行(但不支持自动换行)和${}表达式计算。 +yesCallback和noCallback分别为确定和取消的回调函数。 +可以在调用此函数前设置core.status.event.selection来控制默认的选中项(0确定1取消)。 +此函数和core.myconfirm的区别主要在于: + - 此函数会清掉UI层原有的绘制信息,core.myconfirm不会清除。 + - 此函数可以用键盘进行操作,core.myconfirm必须用鼠标点击。 +另外请注意:本函数和事件流的执行不兼容,选择也不会进录像。 +如果需要在事件流中调用请使用提供选择项。 + + +core.drawWaiting(text) +绘制一个等待界面,一般用于同步存档之类的操作。 +调用此函数后,需要再调用core.closePanel()才会恢复游戏。 + + +core.drawPagination(page, totalPage, y) +绘制一个分页。y如果不设置则绘制在最后一行。 + + +core.drawBook(index) / core.drawBookDetail(index) +绘制怪物手册,绘制怪物的详细信息。 + + +core.drawFly(page) / core.drawCenterFly() / core.drawShop(shopId) +绘制楼传页面,中心对称飞行器,绘制商店 + + +core.drawToolbox(index) / core.drawEquipbox(index) / core.drawKeyBoard() +绘制道具栏,绘制装备栏,绘制虚拟键盘。 + + +core.drawMaps(index, x, y) / core.drawSLPanel(index, refresh) +绘制浏览地图,绘制存读档界面。 + + +core.drawStatusBar() +自定义绘制状态栏,仅在状态栏canvas化开启时有效,实际被转发到了脚本编辑中。 + + +core.drawStatistics() +绘制数据统计。将从脚本编辑中获得要统计的数据列表,再遍历所有地图进行统计。 + + +core.drawAbout() / core.drawPaint() / core.drawHelp() +绘制关于界面,绘图模式,帮助界面。 + +// ------ 动态创建画布相关的API ------ // + + +core.ui.createCanvas(name, x, y, width, height, z) +动态创建一个自定义画布。name为要创建的画布名,如果已存在则会直接取用当前存在的。 +x,y为创建的画布相对窗口左上角的像素坐标,width,height为创建的长宽。 +z值为创建的纵向高度(关系到画布之间的覆盖),z值高的将覆盖z值低的;系统画布的z值可在个性化中查看。 +返回创建的画布的context,也可以通过core.dymCanvas[name]或core.getContextByName获得。 + + +core.ui.relocateCanvas(name, x, y) +重新定位一个自定义画布。x和y为画布的左上角坐标。 + + +core.ui.resizeCanvas(name, width, height) +重新设置一个自定义画布的大小。width和height为新设置的宽高。此操作会清空画布。 + + +core.ui.deleteCanvas(name) +删除一个自定义画布。 + + +core.ui.deleteAllCanvas() +删除所有的自定义画布。 +``` ### utils.js + +utils.js是一个工具函数库,里面有各个样板中使用到的工具函数。 + +```js +core.replayText(text, need, times) +将一段文字中的${}(表达式)进行替换。need和time一般可以直接忽略。 + + +core.calValue(value, prefix, need, time) +计算一个表达式的值,支持status:xxx等的计算。 +prefix为前缀(switch:xxx的独立开关使用),need和time一般可以直接忽略。 + + +core.unshift(a, b) / core.push(a, b) +将b插入到列表a之前或之后。b可以是一个元素或者一个数组。 + + +core.decompress(value) +解压缩一个字符串并进行JSON解析。value可能会被LZString或LZW算法进行压缩。 +返回解压后的JSON格式内容,如果无法解压则返回null。 + + +core.setLocalStorage(key, value) +将一个键值对存入localStorage中,会立刻返回结果。 +此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。 +value为要存储的内容,存储前会被JSON转成字符串形式,并LZW算法进行压缩。 +如果value为null,则实际会调用core.removeLocalStorage()函数清除该key。 +localStorage为浏览器的默认存储,和存档无关,只有5M的空间大小。 +此函数立刻返回true或false,如果为false则代表存储失败,一般指的是空间满了。 + + +core.getLocalStorage(key, defaultValue) +从localStorage中获得一个键的值,会立刻返回结果。 +此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。 +如果对应的键值不存在或为null,则会返回defaultValue。 +返回的结果会被调用core.decompress进行解压缩和JSON解析。 + + +core.removeLocalStorage(key) +从localStorage中删除一个键的值,会立刻返回。 +此函数会自动给key加上它的name作为前缀,以便于不同塔之间的区分。 + + +core.setLocalForage(key, value, successCallback, errorCallback) +将一个键值对存入localForage中,异步返回结果。 +如果用户没有开启【新版存档】开关,则仍然会使用core.setLocalStorage()。 +localForage为一个开源库,项目地址 https://github.com/localForage/localForage +一般存入的是indexedDB,这是一个浏览器的自带数据库,没有空间限制。 +successCallback和errorCallback均可选,表示该次存储成功或失败的回调, +此函数为异步的,只能通过回调函数来获得存储的成功或失败信息。 + + +core.getLocalForage(key, defaultValue, successCallback, errorCallback) +从localForage中获得一个键的值,异步返回结果。 +如果对应的键值不存在,则会使用defaultValue。 +如果获得成功,则会将core.decompress后的结果传入successCallback回调函数执行。 +errorCallback可选,如果失败,则会将错误信息传入errorCallback()。 +此函数是异步的,只能通过回调函数来获得读取的结果或错误信息。 + + +core.clone(data) +深拷贝一个对象。有关浅拷贝,深拷贝,基本类型和引用类型等相关知识可参见: +https://zhuanlan.zhihu.com/p/26282765 + + +core.splitImage(image, width, height) +等比例切分一张图片。width和height为每张子图片的宽高。 +请确保原始图片的宽度和高度都是是width和height的倍数。 +此函数将返回一个一维数组,每一项都是一张切分好的图片,横向再纵向排列。 +例如4x3的图片按1x1切分得到一个长度为12的数组,按如下方式进行排列: +0 1 2 3 +4 5 6 7 +8 9 10 11 +可以将很多需要的图片拼在一张大图上,然后在插件的_afterLoadResources中切分。 +切分好的图片再存入core.material.images.images中,这样可以少很多IO请求。 + + +core.formatDate(date) / core.formatDate2(date) / core.formatTime(time) +格式化日期和时间。 + + +core.setTwoDigits(x) +将x变成两位数。其实就是 parseInt(x) < 10 ? "0" + x : x + + +core.formatBigNumber(x, onMap) +大数据格式化。x为要格式化的内容,如果不合法会返回???。 +onMap标记是否在地图上调用,如果为真则尝试格式化成六位,否则五位。 + + +core.arrayToRGB(color) / core.arrayToRGBA(color) +将一个颜色数组,例如[255,0,0,1]转成#FF0000或rgba(255,0,0,1)的形式。 + + +core.encodeRoute(route) +录像压缩和解压缩。route为要压缩的路线数组。 +此函数将尽可能对录像进行压缩。对于无法识别的项目(比如自己添加的),将不压缩而原样放入。 +例如,["up","up","left","move:3:5","test:2333","getNext","item:bomb","down"] +将被压缩成"U2LM3:5(test:2333)GIbomb:D"。 +自己添加的录像项只能由数字、大小写、下划线线、冒号等符号组成,否则无法正常压缩和解压缩。 +对于自定义内容(比如中文文本或数组)请使用JSON.stringify再core.encodeBase64处理。 +压缩的结果将再次进行LZString.compressToBase64()的压缩以进一步节省空间。 + + +core.decodeRoute(route) +解压缩一个录像,返回解压完毕的路线数组。 + + +core.isset(v) +判定v是不是null, undefined或NaN。 +请尽量避免使用此函数,而是直接判定 v == null (请注意 null==undefined !) + + +core.subarray(a, b) +判定数组b是不是数组a的一个前缀子数组。 +如果是,则返回a中除去b后的剩余数组,否则返回null。 + + +core.inArray(array, element) +判定array是不是一个数组,以及element是否在该数组中。 + + +core.clamp(x, a, b) +将x限定在[a,b]区间内。 + + +core.getCookie(name) +获得一个cookie值,如果不存在该cookie则返回null。 + + +core.setStatusBarInnerHTML(name, value, css) +设置一个状态栏的innerHTML。此函数会自动设置状态栏的文字放缩和斜体等效果。 +name为状态栏的名称,如atk, def等。需要是core.statusBar中的一个合法项。 +value为要设置到的数值,如果是数字则会先core.formatBigNumber()进行格式化。 +css可选,为增添的额外css内容,比如可以设定颜色等。 + + +core.strlen(str) +计算某个字符串的实际长度。每个字符的长度,ASCII码视为1,中文等视为2。 + + +core.reverseDirection(direction) +翻转方向,即"up"转成"down", "left"转成"right"等。 + + +core.encodeBase64(str) / core.decodeBase64(str) +将字符串进行base64加密或解密。 + + +core.convertBase(str, fromBase, toBase) +任意进制转换。此函数可能执行的非常慢,慎用。 + + +core.rand(num) +使用伪种子生成伪随机数。该随机函数能被录像支持。 +num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到1之间的浮点数。 +此函数为伪随机算法,SL大法无效。(即多次SL后调用的该函数返回的值都是相同的。) + + +core.rand2(num) +使用系统的随机数算法得到的随机数。该随机函数能被录像支持。 +num如果设置大于0,则生成一个[0, num-1]之间的数;否则生成一个0到2147483647之间的整数。 +此函数使用了系统的Math.random()函数,支持SL大法。 +但是,此函数会将生成的随机数值存入录像,因此如果调用次数太多则会导致录像文件过大。 +对于需要大量生成随机数,但又想使用真随机支持SL大法的(例如随机生成地图等),可以采用如下方式: + var x = core.rand2(100); for (var i = 0; i < x; i++) core.rand() +即先生成一个真随机数,根据该数来推进伪随机的种子,这样就可以放心调用core.rand()啦。 + + +core.readFile(success, error) +读取一个本地文件内容。success和error分别为读取成功或失败的回调函数。 +iOS平台暂不支持读取文件操作。 + + +core.readFileContent(content) +读取到的文件内容。此函数会被APP等调用,来传递文件的具体内容。 + + +core.download(filename, content) +生成一个文件并下载。filename为文件名,content为具体的文件内容。 +iOS平台暂不支持下载文件操作。 + + +core.copy(data) +将一段内容拷贝到剪切板。 + + +core.myconfirm(hint, yesCallback, noCallback) +弹窗绘制一段提示信息并让用户确认。hint为提示信息。 +yesCallback和noCallback分别为确定和取消的回调函数。 +此函数和core.drawConfirmBox的区别主要在于: + - drawConfirmBox会清掉UI层原有的绘制信息,此函数不会清除。 + - drawConfirmBox可以用键盘进行操作,此函数必须用鼠标点击。 +另外请注意:本函数的选择也不会进录像,一般用于全局的提示。 +如果需要在事件流中调用请使用显示确认框或显示选择项。 + + +core.myprompt(hint, value, callback) +弹窗让用户输入一段内容。hint为提示信息,value为框内的默认填写内容。 +callback为用户点击确认或取消后的回调。 +如果用户点击了确认,则会把框内的内容(可能是空串)传递给callback,否则把null传递给callback。 + + +core.showWithAnimate(obj, speed, callback) / core.hideWithAnimate(obj, speed, callback) +动画淡入或淡出一个对象。 + + +core.consoleOpened() +检测当前的控制台是否处于开启状态。仅在全塔属性中的检查控制台开关开启时有效。 +此函数有可能会存在误伤行为,即没开过控制台仍认为开启过。 + + +core.hashCode(obj) +计算一个对象的哈希值。 + + +core.same(a, b) +判定a和b是否相同,包括类型相同和值相同。 +如果a和b都是数组,则会递归依次比较数组中的值;如果都是对象亦然。 + + +core.utils.http(type, url, formData, success, error, mimeType, responseType) +发送一个异步HTTP请求。 +type为'GET'或者'POST';url为目标地址;formData如果是POST请求则为表单数据。 +success为成功后的回调,error为失败后的回调。 +mimeType和responseType如果设置将会覆盖默认值。 + + +lzw_encode(s) / lzw_decode(s) +LZW压缩算法,来自https://gist.github.com/revolunet/843889 +``` diff --git a/libs/actions.js b/libs/actions.js index dfc55820..2d516b52 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -1904,11 +1904,11 @@ actions.prototype._clickSettings = function (x, y) { core.ui.drawKeyBoard(); break; case 2: - core.clearSelector(); + core.clearUI(); core.ui.drawMaps(); break; case 3: - core.clearSelector(); + core.clearUI(); core.ui.drawPaint(); break; case 4: @@ -2211,7 +2211,7 @@ actions.prototype._clickReplay_fromBeginning = function () { actions.prototype._clickReplay_fromLoad = function () { core.status.event.id = 'replayLoad'; core.status.event.selection = null; - core.ui.clearSelector(); + core.clearUI(); var saveIndex = core.saves.saveIndex; var page = parseInt((saveIndex - 1) / 5), offset = saveIndex - 5 * page; core.ui.drawSLPanel(10 * page + offset); @@ -2450,7 +2450,7 @@ actions.prototype._onupPaint = function () { core.status.event.data.x = null; core.status.event.data.y = null; // 保存 - core.paint[core.status.floorId] = lzw_encode(core.utils.encodeCanvas(core.dymCanvas.paint).join(",")); + core.paint[core.status.floorId] = lzw_encode(core.utils._encodeCanvas(core.dymCanvas.paint).join(",")); } actions.prototype.setPaintMode = function (mode) { @@ -2498,7 +2498,7 @@ actions.prototype.loadPaint = function () { core.clearMap('paint'); var value = core.paint[core.status.floorId]; if (value) value = lzw_decode(value).split(","); - core.utils.decodeCanvas(value, 32 * core.bigmap.width, 32 * core.bigmap.height); + core.utils._decodeCanvas(value, 32 * core.bigmap.width, 32 * core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); core.drawTip("读取绘图文件成功"); diff --git a/libs/control.js b/libs/control.js index c4b93ffa..f0de8ee1 100644 --- a/libs/control.js +++ b/libs/control.js @@ -308,7 +308,7 @@ control.prototype.showStartAnimate = function (noAnimate, callback) { this._showStartAnimate_resetDom(); if (core.flags.startUsingCanvas || noAnimate) return this._showStartAnimate_finished(core.flags.startUsingCanvas, callback); - core.hide(core.dom.startTop, 20, function () { + core.hideWithAnimate(core.dom.startTop, 20, function () { core.control._showStartAnimate_finished(false, callback); }); } @@ -339,7 +339,7 @@ control.prototype._showStartAnimate_finished = function (start, callback) { ////// 隐藏游戏开始界面 ////// control.prototype.hideStartAnimate = function (callback) { - core.hide(core.dom.startPanel, 20, callback); + core.hideWithAnimate(core.dom.startPanel, 20, callback); } ////// 游戏是否已经开始 ////// diff --git a/libs/core.js b/libs/core.js index 97069384..3f1165b6 100644 --- a/libs/core.js +++ b/libs/core.js @@ -344,6 +344,8 @@ core.prototype._afterLoadResources = function (callback) { // 初始化地图 core.initStatus.maps = core.maps._initMaps(); core.control._setRequestAnimationFrame(); + if (core.plugin._afterLoadResources) + core.plugin._afterLoadResources(); core.showStartAnimate(); if (callback) callback(); } diff --git a/libs/events.js b/libs/events.js index 63438d3a..6b3d5beb 100644 --- a/libs/events.js +++ b/libs/events.js @@ -438,7 +438,7 @@ events.prototype.getItem = function (id, num, x, y, callback) { var text = '获得 ' + core.material.items[id].name; if (num > 1) text += "x" + num; if (itemCls === 'items') text += core.items.getItemEffectTip(id); - core.drawTip(text, core.material.icons.items[id]); + core.drawTip(text, id); core.updateStatusBar(); this.afterGetItem(id, x, y, callback); @@ -559,7 +559,7 @@ events.prototype._changeFloor_beforeChange = function (info, callback) { if (info.time == 0) core.events._changeFloor_changing(info, callback); else - core.show(core.dom.floorMsgGroup, info.time / 2, function () { + core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () { core.events._changeFloor_changing(info, callback); }); }, 25) @@ -571,7 +571,7 @@ events.prototype._changeFloor_changing = function (info, callback) { if (info.time == 0) this._changeFloor_afterChange(info, callback); else - core.hide(core.dom.floorMsgGroup, info.time / 4, function () { + core.hideWithAnimate(core.dom.floorMsgGroup, info.time / 4, function () { core.events._changeFloor_afterChange(info, callback); }); } @@ -771,10 +771,7 @@ events.prototype.startEvents = function (list, x, y, callback) { ////// 执行当前自定义事件列表中的下一个事件 ////// events.prototype.doAction = function () { // 清空boxAnimate和UI层 - core.status.boxAnimateObjs = []; - clearInterval(core.status.event.interval); - core.status.event.interval = null; - core.clearSelector(); + core.clearUI(); // 判定是否执行完毕 if (this._doAction_finishEvents()) return; // 当前点坐标和前缀 diff --git a/libs/items.js b/libs/items.js index 8a89e7a7..6c13e824 100644 --- a/libs/items.js +++ b/libs/items.js @@ -365,8 +365,8 @@ items.prototype._realLoadEquip = function (type, loadId, unloadId, callback) { core.status.hero.equipment[type] = loadId || null; // --- 提示 - if (loadId) core.drawTip("已装备上" + loadEquip.name, core.material.icons.items[loadId]); - else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, core.material.icons.items[unloadId]); + if (loadId) core.drawTip("已装备上" + loadEquip.name, loadId); + else if (unloadId) core.drawTip("已卸下" + unloadEquip.name, unloadId); if (callback) callback(); } diff --git a/libs/ui.js b/libs/ui.js index 6c887f92..6c4501e2 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -23,12 +23,13 @@ ui.prototype._init = function () { ////////////////// 地图设置 -ui.prototype.getContextByName = function (canvas) { - if (typeof canvas == 'string') { - if (core.canvas[canvas]) - canvas = core.canvas[canvas]; - else if (core.dymCanvas[canvas]) - canvas = core.dymCanvas[canvas]; +ui.prototype.getContextByName = function (name) { + var canvas = name; + if (typeof name == 'string') { + if (core.canvas[name]) + canvas = core.canvas[name]; + else if (core.dymCanvas[name]) + canvas = core.dymCanvas[name]; } if (canvas && canvas.canvas) { return canvas; @@ -190,6 +191,36 @@ ui.prototype.calWidth = function (name, text, font) { return 0; } +////// 字符串自动换行的分割 ////// +ui.prototype.splitLines = function (name, text, maxWidth, font) { + var ctx = this.getContextByName(name); + if (!ctx) return; + if (font) core.setFont(name, font); + + var contents = []; + var last = 0; + for (var i = 0; i < text.length; i++) { + if (text.charAt(i) == '\n') { + contents.push(text.substring(last, i)); + last = i + 1; + } + else if (text.charAt(i) == '\\' && text.charAt(i + 1) == 'n') { + contents.push(text.substring(last, i)); + last = i + 2; + } + else { + var toAdd = text.substring(last, i + 1); + var width = core.calWidth(name, toAdd); + if (maxWidth && width > maxWidth) { + contents.push(text.substring(last, i)); + last = i; + } + } + } + contents.push(text.substring(last)); + return contents; +} + ////// 绘制一张图片 ////// ui.prototype.drawImage = function (name, image, x, y, w, h, x1, y1, w1, h1) { var ctx = this.getContextByName(name); @@ -233,25 +264,23 @@ ui.prototype.clearUI = function () { clearInterval(core.status.event.interval); core.status.event.interval = null; core.status.boxAnimateObjs = []; - core.clearSelector(); - core.clearMap('ui'); - core.setAlpha('ui', 1); -} - -////// 清除光标 ////// -ui.prototype.clearSelector = function () { if (core.dymCanvas._selector) core.deleteCanvas("_selector"); core.clearMap('ui'); core.setAlpha('ui', 1); } ////// 左上角绘制一段提示 ////// -ui.prototype.drawTip = function (text, itemIcon) { +ui.prototype.drawTip = function (text, id) { var textX, textY, width, height; clearInterval(core.interval.tipAnimate); core.setFont('data', "16px Arial"); core.setTextAlign('data', 'left'); - if (!itemIcon) { + if (id != null) { + var info = core.getBlockInfo(id); + if (info == null || !info.image || info.height != 32) id = null; + else id = info; + } + if (!id) { textX = 16; textY = 18; width = textX + core.calWidth('data', text) + 16; @@ -263,10 +292,10 @@ ui.prototype.drawTip = function (text, itemIcon) { width = textX + core.calWidth('data', text) + 8; height = 42; } - this._drawTip_animate(text, itemIcon, textX, textY, width, height); + this._drawTip_animate(text, id, textX, textY, width, height); } -ui.prototype._drawTip_animate = function (text, itemIcon, textX, textY, width, height) { +ui.prototype._drawTip_animate = function (text, info, textX, textY, width, height) { var alpha = 0, hide = false; core.interval.tipAnimate = window.setInterval(function () { if (hide) alpha -= 0.1; @@ -274,8 +303,8 @@ ui.prototype._drawTip_animate = function (text, itemIcon, textX, textY, width, h core.clearMap('data', 5, 5, core.ui.PIXEL, height); core.setAlpha('data', alpha); core.fillRect('data', 5, 5, width, height, '#000'); - if (itemIcon) - core.drawImage('data', core.material.images.items, 0, itemIcon * 32, 32, 32, 10, 8, 32, 32); + if (info) + core.drawImage('data', info.image, info.posX * 32, info.posY * 32, 32, 32, 10, 8, 32, 32); core.fillText('data', text, textX + 5, textY + 15, '#fff'); core.setAlpha('data', 1); if (alpha > 0.6 || alpha < 0) { @@ -507,13 +536,13 @@ ui.prototype.drawBackground = function (left, top, right, bottom, posInfo) { } ////// 计算有效文本框的宽度 -ui.prototype.calTextBoxWidth = function (ctx, content, min_width, max_width, font) { +ui.prototype._calTextBoxWidth = function (ctx, content, min_width, max_width, font) { // 无限长度自动换行 var allLines = core.splitLines(ctx, content, null, font); // 如果不存在手动换行,尽量调成半行形式 if (allLines.length == 1) { - var w = core.calWidth(ctx, allLines[0]); + var w = core.calWidth(ctx, allLines[0]) + 5; if (w 1) - core.fillText('ui', '上一页', this.HPIXEL - 80, top*32+19); + core.fillText('ui', '上一页', this.HPIXEL - 80, y*32+19); if (page < totalPage) - core.fillText('ui', '下一页', this.HPIXEL + 80, top*32+19); + core.fillText('ui', '下一页', this.HPIXEL + 80, y*32+19); } ////// 绘制键盘光标 ////// @@ -1633,7 +1662,7 @@ ui.prototype.drawMaps = function (index, x, y) { var offsetX = 32 * (data.x - this.HSIZE), offsetY = 32 * (data.y - this.HSIZE); var value = core.paint[data.floorId]; if (value) value = lzw_decode(value).split(","); - core.utils.decodeCanvas(value, 32 * data.mw, 32 * data.mh); + core.utils._decodeCanvas(value, 32 * data.mw, 32 * data.mh); core.drawImage('ui', core.bigmap.tempCanvas.canvas, offsetX * 32, offsetY * 32, this.PIXEL, this.PIXEL, 0, 0, this.PIXEL, this.PIXEL); } @@ -2359,13 +2388,13 @@ ui.prototype._drawPaint_draw = function () { core.status.event.id = 'paint'; core.status.event.data = {"x": null, "y": null, "erase": false}; - core.clearSelector(); + core.clearUI(); core.createCanvas('paint', -core.bigmap.offsetX, -core.bigmap.offsetY, 32*core.bigmap.width, 32*core.bigmap.height, 95); // 将已有的内容绘制到route上 var value = core.paint[core.status.floorId]; if (core.isset(value)) value = lzw_decode(value).split(","); - core.utils.decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); + core.utils._decodeCanvas(value, 32*core.bigmap.width, 32*core.bigmap.height); core.drawImage('paint', core.bigmap.tempCanvas.canvas, 0, 0); core.setLineWidth('paint', 3); @@ -2384,7 +2413,7 @@ ui.prototype._drawPaint_draw = function () { ////// 绘制帮助页面 ////// ui.prototype.drawHelp = function () { - core.clearSelector(); + core.clearUI(); if (core.material.images.keyboard) { core.status.event.id = 'help'; core.lockControl(); diff --git a/libs/utils.js b/libs/utils.js index d1a9f0c7..d491197e 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -75,35 +75,6 @@ utils.prototype.calValue = function (value, prefix, need, times) { return value; } -////// 字符串自动换行的分割 ////// -utils.prototype.splitLines = function (canvas, text, maxLength, font) { - if (font) core.setFont(canvas, font); - - var contents = []; - var last = 0; - for (var i = 0; i < text.length; i++) { - - if (text.charAt(i) == '\n') { - contents.push(text.substring(last, i)); - last = i + 1; - } - else if (text.charAt(i) == '\\' && text.charAt(i + 1) == 'n') { - contents.push(text.substring(last, i)); - last = i + 2; - } - else { - var toAdd = text.substring(last, i + 1); - var width = core.calWidth(canvas, toAdd); - if (maxLength && width > maxLength) { - contents.push(text.substring(last, i)); - last = i; - } - } - } - contents.push(text.substring(last)); - return contents; -} - ////// 向某个数组前插入另一个数组或元素 ////// utils.prototype.unshift = function (a, b) { if (!(a instanceof Array) || b == null) return; @@ -128,6 +99,28 @@ utils.prototype.push = function (a, b) { return a; } +utils.prototype.decompress = function (value) { + try { + var output = lzw_decode(value); + if (output) return JSON.parse(output); + } + catch (e) { + } + try { + var output = LZString.decompress(value); + if (output) return JSON.parse(output); + } + catch (e) { + } + try { + return JSON.parse(value); + } + catch (e) { + main.log(e); + } + return null; +} + ////// 设置本地存储 ////// utils.prototype.setLocalStorage = function (key, value) { try { @@ -163,28 +156,6 @@ utils.prototype.setLocalStorage = function (key, value) { } } -utils.prototype.decompress = function (value) { - try { - var output = lzw_decode(value); - if (output) return JSON.parse(output); - } - catch (e) { - } - try { - var output = LZString.decompress(value); - if (output) return JSON.parse(output); - } - catch (e) { - } - try { - return JSON.parse(value); - } - catch (e) { - main.log(e); - } - return null; -} - ////// 获得本地存储 ////// utils.prototype.getLocalStorage = function (key, defaultValue) { var res = this.decompress(localStorage.getItem(core.firstData.name + "_" + key)); @@ -628,6 +599,7 @@ utils.prototype.getCookie = function (name) { ////// 设置statusBar的innerHTML,会自动斜体和放缩,也可以增加自定义css ////// utils.prototype.setStatusBarInnerHTML = function (name, value, css) { + if (!core.statusBar[name]) return; if (typeof value == 'number') value = this.formatBigNumber(value); // 判定是否斜体 var italic = /^[-a-zA-Z0-9`~!@#$%^&*()_=+\[{\]}\\|;:'",<.>\/?]*$/.test(value); @@ -931,7 +903,7 @@ utils.prototype.myprompt = function (hint, value, callback) { } ////// 动画显示某对象 ////// -utils.prototype.show = function (obj, speed, callback) { +utils.prototype.showWithAnimate = function (obj, speed, callback) { obj.style.display = 'block'; if (!speed && main.mode != 'play') { obj.style.opacity = 1; @@ -951,7 +923,7 @@ utils.prototype.show = function (obj, speed, callback) { } ////// 动画使某对象消失 ////// -utils.prototype.hide = function (obj, speed, callback) { +utils.prototype.hideWithAnimate = function (obj, speed, callback) { if (!speed || main.mode != 'play') { obj.style.display = 'none'; if (callback) callback(); @@ -970,7 +942,7 @@ utils.prototype.hide = function (obj, speed, callback) { }, speed); } -utils.prototype.encodeCanvas = function (ctx) { +utils.prototype._encodeCanvas = function (ctx) { var list = []; var width = ctx.canvas.width, height = ctx.canvas.height; ctx.mozImageSmoothingEnabled = false; @@ -997,7 +969,7 @@ utils.prototype.encodeCanvas = function (ctx) { } ////// 解析arr数组,并绘制到tempCanvas上 ////// -utils.prototype.decodeCanvas = function (arr, width, height) { +utils.prototype._decodeCanvas = function (arr, width, height) { // 清空tempCanvas var tempCanvas = core.bigmap.tempCanvas; tempCanvas.canvas.width = width; diff --git a/project/plugins.js b/project/plugins.js index 3f0afa16..85ca3bfa 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -1,18 +1,28 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { "init": function () { - // 在这里写的代码,在所有模块加载完毕后,游戏开始前会被执行 + console.log("插件编写测试"); - // 可以写一些其他的被直接执行的代码 + // 可以写一些直接执行的代码 + // 在这里写的代码将会在【资源加载前】被执行,此时图片等资源尚未被加载。 + // 请勿在这里对包括bgm,图片等资源进行操作。 - this.test = function () { - console.log("插件函数执行测试"); - console.log(this); + this._afterLoadResources = function () { + // 本函数将在所有资源加载完毕后,游戏开启前被执行 + // 可以在这个函数里面对资源进行一些操作,比如切分图片等。 + + // 这是一个将assets.png拆分成若干个32x32像素的小图片并保存的样例。 + // var arr = core.splitImage("assets.png", 32, 32); + // for (var i = 0; i < arr.length; i++) { + // core.material.images.images["asset"+i+".png", arr[i]); + // } + } - // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); + // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); + // 从V2.6开始,插件中用this.XXX方式定义的函数也会被转发到core中,详见文档-脚本-函数的转发。 }, "drawLight": function () { From bfa3f3e075c57e9bc109d75116de91fbb1b557e8 Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Wed, 3 Apr 2019 13:54:19 -0400 Subject: [PATCH 147/153] confirm_s --- _server/MotaAction.g4 | 22 ++++++++++++++++++++++ _server/editor_blockly.js | 2 ++ 2 files changed, 24 insertions(+) diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index bb3e0f44..9fd002f3 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -331,6 +331,7 @@ action | input_s | input2_s | choices_s + | confirm_s | callBook_s | callSave_s | callLoad_s @@ -1658,6 +1659,20 @@ var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\ return code; */; +confirm_s + : '显示确认框' ':' EvalString BGNL? '确定' ':' BGNL? Newline action+ '取消' ':' BGNL? Newline action+ BEND Newline + +/* confirm_s +tooltip : 弹出确认框 +helpUrl : https://h5mota.com/games/template/docs/#/ +default : ["确认要???吗?"] +var code = ['{"type": "confirm", "text": "',EvalString_0,'",\n', + '"yes": [\n',action_0,'],\n', + '"no": [\n',action_1,']\n', +'},\n'].join(''); +return code; +*/; + while_s : '循环处理' ':' '当' expression '时' BGNL? Newline action+ BEND Newline @@ -2570,6 +2585,13 @@ ActionParser.prototype.parseAction = function() { this.insertActionList(data["false"]), this.next]); break; + case "confirm": // 显示确认框 + this.next = MotaActionBlocks['confirm_s'].xmlText([ + this.EvalString(data.text), + this.insertActionList(data["yes"]), + this.insertActionList(data["no"]), + this.next]); + break; case "switch": // 多重条件分歧 var case_caseList = null; for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) { diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 595a55ff..0f05135b 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -76,6 +76,7 @@ editor_blockly = function () { ]) ]) ]), + MotaActionBlocks['confirm_s'].xmlText(), ], '数据相关':[ MotaActionBlocks['setValue_s'].xmlText([ @@ -589,6 +590,7 @@ function omitedcheckUpdateFunction(event) { 'showTextImage_s': 'EvalString_0', 'function_s': 'RawEvalString_0', 'shopsub': 'EvalString_3', + 'confirm_s': 'EvalString_0', } var f = b ? textStringDict[b.type] : null; if (f) { From d9002596ab249120c5395f5fb17596967c3d646e Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 4 Apr 2019 01:59:31 +0800 Subject: [PATCH 148/153] Fix plugin --- project/plugins.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/plugins.js b/project/plugins.js index 85ca3bfa..d09e9944 100644 --- a/project/plugins.js +++ b/project/plugins.js @@ -16,7 +16,7 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = // 这是一个将assets.png拆分成若干个32x32像素的小图片并保存的样例。 // var arr = core.splitImage("assets.png", 32, 32); // for (var i = 0; i < arr.length; i++) { - // core.material.images.images["asset"+i+".png", arr[i]); + // core.material.images.images["asset"+i+".png"] = arr[i]; // } } From a46d322e0c55462fd46d6cce03a4c9b9fa3db6c3 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 4 Apr 2019 02:03:38 +0800 Subject: [PATCH 149/153] replace ```js --- _docs/api.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_docs/api.md b/_docs/api.md index efe18684..9703764b 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -425,7 +425,7 @@ core.doFunc(func, _this) actions.js主要是处理一些和用户交互相关的内容。 -``` js +```text core.registerAction(action, name, func, priority) 注册一个用户交互行为。 action:要注册的交互类型,如 ondown, onclick, keyDown 等等。 @@ -951,7 +951,7 @@ core.resize() enemys.js中定义了一系列和怪物相关的API函数。 -```js +```text core.hasSpecial(special, test) 判断是否含有某个特殊属性。test为要检查的特殊属性编号。 special为要测试的内容,允许接收如下类型参数: @@ -1043,7 +1043,7 @@ events.js将处理所有和事件相关的操作,主要分为五个部分: - 一些具体事件的执行内容 -```js +```text // ------ 游戏的开始和结束 ------ // core.resetGame(hero, hard, floorId, maps, values) @@ -1374,7 +1374,7 @@ core.afterUseBomb() icons.js主要是负责素材相关信息,比如某个素材在对应的图片上的位置。 -```js +```text core.getClsFromId(id) 根据某个素材的ID获得该素材的cls @@ -1388,7 +1388,7 @@ core.getTilesetOffset(id) items.js主要负责一切和道具相关的内容。 -```js +```text core.getItemEffect(itemId, itemNum) 即捡即用类的道具获得时的效果。实际对应道具图块属性中的itemEffect框。 @@ -1478,7 +1478,7 @@ core.quickLoadEquip() loader.js主要负责资源加载相关的内容。 -```js +```text core.loadImage(imgName, callback) 从 project/images/ 中加载一张图片。imgName为图片名。 callback为执行完毕的回调函数,接收(imgName, image)即图片名和图片内容作为参数。 @@ -1520,7 +1520,7 @@ maps.js负责一切和地图相关的处理内容,包括如下几个方面: - 移动/跳跃图块,淡入淡出图块 - 全局动画控制,动画的绘制 -```js +```text // ------ 地图的初始化,保存和读取,地图数组的生成 ------ // core.loadFloor(floorId, map) @@ -1849,7 +1849,7 @@ ui.js负责一切UI界面的绘制。主要包括三个部分: - 具体的某个UI界面的绘制 - 动态创建画布相关的API -```js +```text // ------ 设置某个画布的属性的相关API ------// 这系列函数的name一般都是画布名,可以是系统画布或动态创建的画布。 但也同时也允许直接传画布的context本身,将返回自身。 @@ -2108,7 +2108,7 @@ core.ui.deleteAllCanvas() utils.js是一个工具函数库,里面有各个样板中使用到的工具函数。 -```js +```text core.replayText(text, need, times) 将一段文字中的${}(表达式)进行替换。need和time一般可以直接忽略。 From 77e4e405b817c81725988deb8f95917a077291b1 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 4 Apr 2019 02:05:20 +0800 Subject: [PATCH 150/153] plugin --- _docs/api.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_docs/api.md b/_docs/api.md index 9703764b..4783aaaa 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -2,7 +2,7 @@ ?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * -在V2.6版本中,基本对整个项目代码进行了重写,更加方便 +在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。 ## 控制台的使用 From 9b5acbcdc4ef4b33fa16bbebbf531a679cb2c87a Mon Sep 17 00:00:00 2001 From: YouWei Zhao Date: Wed, 3 Apr 2019 18:21:48 -0400 Subject: [PATCH 151/153] nobreak --- _server/MotaAction.g4 | 9 +++++---- _server/editor_blockly.js | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index 9fd002f3..05014715 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -1639,13 +1639,13 @@ return code; */; choicesContext - : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour BGNL? Newline action+ + : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour '不跳出' Bool BGNL? Newline action+ /* choicesContext tooltip : 选项的选择 helpUrl : https://h5mota.com/games/template/docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9 -default : ["提示文字:红钥匙","",""] +default : ["提示文字:红钥匙","","",null,false] colour : this.subColor if (EvalString_1) { var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/; @@ -1655,7 +1655,8 @@ if (EvalString_1) { EvalString_1 = ', "color": "'+EvalString_1+'"'; } IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):''; -var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']},\n'; +var nobreak = Bool_0?', "nobreak": true':''; +var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']'+nobreak+'},\n'; return code; */; @@ -2607,7 +2608,7 @@ ActionParser.prototype.parseAction = function() { var text_choices = null; for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) { text_choices=MotaActionBlocks['choicesContext'].xmlText([ - choice.text,choice.icon,choice.color,'rgba('+choice.color+')',this.insertActionList(choice.action),text_choices]); + choice.text,choice.icon,choice.color,'rgba('+choice.color+')',choice.nobreak,this.insertActionList(choice.action),text_choices]); } this.next = MotaActionBlocks['choices_s'].xmlText([ this.isset(data.text)?this.EvalString(data.text):null,'','',text_choices,this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 0f05135b..6aaa3df7 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -70,9 +70,9 @@ editor_blockly = function () { MotaActionBlocks['lose_s'].xmlText(), MotaActionBlocks['choices_s'].xmlText([ '选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([ - '剑','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), + '剑','','',null,null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), MotaActionBlocks['choicesContext'].xmlText([ - '盾','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), + '盾','','',null,null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), ]) ]) ]), From 15bc4d1cef8cbd13282f6631eeb71ad00ff34004 Mon Sep 17 00:00:00 2001 From: oc Date: Thu, 4 Apr 2019 13:00:01 +0800 Subject: [PATCH 152/153] script & api docs --- _docs/_sidebar.md | 3 +- _docs/api.md | 278 ++-------------------------------- _docs/element.md | 2 +- _docs/event.md | 4 +- _docs/img/plugin.jpg | Bin 0 -> 32911 bytes _docs/personalization.md | 6 +- _docs/script.md | 313 +++++++++++++++++++++++++++++++++++++++ _docs/start.md | 2 +- libs/ui.js | 4 +- 9 files changed, 336 insertions(+), 276 deletions(-) create mode 100644 _docs/img/plugin.jpg create mode 100644 _docs/script.md diff --git a/_docs/_sidebar.md b/_docs/_sidebar.md index f7c5a0a1..914ee883 100644 --- a/_docs/_sidebar.md +++ b/_docs/_sidebar.md @@ -3,4 +3,5 @@ - [元件说明](element) - [事件](event) - [个性化](personalization) -- [脚本](api) +- [脚本](script) +- [附录:API列表](api) diff --git a/_docs/api.md b/_docs/api.md index 4783aaaa..346f4bd6 100644 --- a/_docs/api.md +++ b/_docs/api.md @@ -1,268 +1,14 @@ -# 脚本 +# 附录:API列表 ?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * -在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。 - -## 控制台的使用 - -在Chrome浏览器中,按(Ctrl+Shift+I)可打开控制台。 - -![](img/console.jpg) - -控制台中有很多的标签,最常用的是`Console`, `Sources`和`Elements`。 - -有关更详尽的控制台使用可自行搜索[Chrome开发者工具](https://www.baidu.com/s?wd=chrome%20%E5%BC%80%E5%8F%91%E8%80%85%E5%B7%A5%E5%85%B7)了解更多。 - -### Console:命令行 - -Console页为命令行。可以在这里输入一些命令进行调试。 - -比如,进入游戏后,输入`core.status.hero.atk`即可获得勇士的当前攻击力数值。`core.status.hero.atk=100`可以设置攻击力为100。 - -更多的API可参见[附录:API列表](#附录:API列表)。 - -除此以外,游戏中的报错等信息也是可以在Console中进行查看的。 - -![](img/console1.jpg) - -### Sources:断点调试 - -Sources页可以查看JS源代码,并进行断点调试等。 - -例如,如果相对脚本编辑中的伤害计算函数进行断点调试: -1. 在左边找到`project/functions.js`,单击打开文件 -2. 并找到对应的行(可以Ctrl+F搜索),比如搜索`getDamageInfo` -3. 在行号上点一下打断点,会出现一个蓝色标签 - -之后,当代码运行到你的断点处时,将自动停止运行。 - -![](img/sources.jpg) - -可以将鼠标移动到变量上,将弹窗形式显示这个变量的各项数值,从而查看变量值是否符合预期。 - -图中红色框内有几个按钮,从左到右分别是:**继续执行**,**执行到下一行**,**进入当前函数**,**跳出当前函数**,**单步执行**。 - -通过这几个按钮,可以一行一行的对代码进行执行,执行过程中能不断查看各个变量的数值变化,从而定位问题所在。 - -红圈下方是Call Stack,即当前的函数调用链(从哪些地方调用过来的)。 - -Sources还有更多有趣的功能,在此不做介绍,有兴趣的可自行网上搜索了解。 - -### Elements:网页元素查看 - -Elements页可以查看网页的源代码,调整css布局等。 - -![](img/elements.jpg) - -不过对魔塔样板来说,最重要的是红圈中的按钮。点击此按钮可以进入**手机模式**。 - -手机模式下,左边可以对屏幕分辨率进行调整和模拟。 - -这可以很有效的帮我们进行测试样板在手机端的表现。 - -## 整体项目架构 - -``` text -├── /_server/ # 为可视化地图编辑器提供一些支持的目录 -├── /libs/ # ---- 系统库目录 ---- -│ ├─ /thirdparty/ # 游戏所用到的第三方库文件 -│ ├─ actions.js # 用户交互处理 -│ ├─ core.js # 系统核心文件(游戏入口,接口&转发) -│ ├─ control.js # 游戏逻辑控制 -│ ├─ data.js # 全塔属性等 -│ ├─ enemys.js # 怪物相关处理 -│ ├─ events.js # 各个事件的执行 -│ ├─ icons.js # 图标和素材 -│ ├─ items.js # 道具效果 -│ ├─ loader.js # 各个资源加载 -│ ├─ maps.js # 地图数据和绘制 -│ ├─ ui.js # UI窗口绘制 -│ └─ utils.js # 工具类函数 -├── /project/ # ---- 项目目录 ---- -│ ├─ /animates/ # 动画目录 -│ ├─ /floors/ # 楼层文件 -│ ├─ /images/ # 图片素材 -│ ├─ /sounds/ # bgm和音效 -│ ├─ data.js # 全塔属性 -│ ├─ enemys.js # 怪物属性 -│ ├─ events.js # 公共事件 -│ ├─ functions.js # 脚本编辑 -│ ├─ icons.js # 素材和ID的对应关系定义 -│ ├─ items.js # 道具的定义和效果 -│ ├─ maps.js # 地图和数字的对应关系 -│ └─ plugins.js # 自定义插件 -├── /常用工具/ # 辅助造塔的小工具 -├── editor.html # 地图编辑器 -├── editor-mobile.html # 手机版的地图编辑器 -├── index.html # 主程序,游戏的入口 -├── main.js # JS程序的入口,将动态对所需JS进行加载 -├── style.css # 游戏所需要用到的样式表 -└── 启动服务.exe # 一个本地的HTTP服务器,通过它来运行游戏 -``` - -`_server`为**地图编辑器目录**,里面存放了地图编辑器相关的各项内容。 - -`libs`为**系统库目录**,里面存放了各个系统核心函数。 - -从V2.6开始,请勿直接修改libs下的代码,如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数)。 - -`project`为**项目目录**,你所造的塔的数据全部存放在project下。在不同样板之间接档也是直接迁移project目录即可。 - -## 函数的转发 - -在本样板中,`core.js`里面基本是没有定义什么函数的,所有的游戏内函数都在其他几个文件中实现。 - -例如,常见的获得某个变量值`getFlag`是定义在`control.js`中的: - -```js -////// 获得某个自定义变量或flag ////// -control.prototype.getFlag = function(name, defaultValue) { - if (!core.status.hero) return defaultValue; - var value = core.status.hero.flags[name]; - return value != null ? value : defaultValue; -} -``` - -也就是,我们可以通过`core.control.getFlag(name, value)`来调用此函数。 - -但是这样会十分不便,我们希望能直接调用`core.getFlag(name, value)`,而不需要中间的control。 - -为了达到这个目的,样板设置了**函数转发**,即**将其他文件中定义的函数,转发到core中执行**。 - -上述`getFlag`代码的转发实际上是增加了如下函数: - -```js -////// getFlag函数的转发 ////// -core.getFlag = function (name, defaultValue) { - return core.control.getFlag(name, defaultValue); -} -// 转发后,即可通过 core.getFlag() 来实际调用 core.control.getFlag() -``` - -转发是自动完成的,其满足如下两条规则: -- **在libs中其他文件定义的函数,如果不以下划线`_`开头,就会进行转发。** -- **如果core中已经存在同名函数,则会在控制台中打出一条报错信息,并不转发该函数。** - -具体函数的转发实现代码可参见`core.js`的`_forwardFunc`函数。 - -!> 除此以外,插件中以`this.xxx`来定义的函数也会被转发! - -例如,你可以直接调用`core.drawLight()`来实际调用插件中的`core.plugin.drawLight`。 - -## 复写函数 - -样板的功能毕竟是写死的,有时候我们也需要修改样板的一些行为。 - -在V2.6以前,需要直接打开libs目录下的对应文件并进行修改。但是开libs下的文件就会出现各种问题: -- 不容易随着新样板来接档迁移 -- 也不好找到自己改过什么,从而能整理成新的插件在别的塔使用 -- …… - -好消息的是,从V2.6开始,我们再也不需要开文件了,而是可以直接在插件中对原始函数进行复写。 - -如果我想对xxx文件中的yyy函数进行重写,其模式一般是:`core.xxx.yyy = function (参数列表) { ... }` - -下面是几个例子,从简单到复杂。 - -### 重写怪物手册的背景图绘制,使用winskin而不是默认的黑色 - -直接重写怪物手册的背景图绘制,使用`core.drawBackground`来用winskin绘制一个背景图。 - -```js -// 重写ui.js中的_drawBook_drawBackground函数 -core.ui._drawBook_drawBackground = function () { - // core.__PIXEL__为定义的一个宏,对于13x13的值是416,对于15x15的值是480 - core.drawBackground(0, 0, core.__PIXEL__, core.__PIXEL__); -} -``` - -### 重写点击楼传事件 - -重写点击楼传事件,使得点击楼传按钮时能使用一个道具(比如item:fly)。 - -```js -// 重写events.js的useFly函数,即点击楼传按钮时的事件 -core.events.useFly = function (fromUserAction) { - if (core.isMoving()) { - core.drawTip("请先停止勇士行动"); - return; - } - if (core.status.lockControl || core.status.event.id != null) return; - - if (core.canUseItem('fly')) core.useItem('fly'); - else core.drawTip("当前无法使用"+core.material.items.fly.name); -} -``` - -其他的几个按钮,如快捷商店`openQuickShop`,虚拟键盘`openKeyBoard`的重写也几乎完全一样。 - -### 楼层切换时根据flag来播放不同的音效 - -整体复制并重写整个楼传切换前的函数,将`core.playSound('floor.mp3')`替换成根据flag来判定。 - -```js -// 复制重写events.js中的_changeFloor_beforeChange,修改音效 -core.events._changeFloor_beforeChange = function (info, callback) { - // 直接替换原始函数中的 core.playSound('floor.mp3'); - if (core.getFlag("floorSound") == 0) core.playSound('floor0.mp3'); - if (core.getFlag("floorSound") == 1) core.playSound('floor1.mp3'); - if (core.getFlag("floorSound") == 2) core.playSound('floor2.mp3'); - // ... - - // 下面是原始函数中的剩余代码,保持不变 - window.setTimeout(function () { - if (info.time == 0) - core.events._changeFloor_changing(info, callback); - else - core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () { - core.events._changeFloor_changing(info, callback); - }); - }, 25) -} -``` - -### 每次打开全局商店时播放一个音效 - -打开全局商店是在`events.js`中的`openShop`函数,因此需要对其进行重写。 - -然而,我们只需要在这个函数执行之前插一句音效播放,所以并不需要重写整个函数,而是直接插入一行就行。 - -```js -var openShop = core.events.openShop; // 先把原始函数用一个变量记录下来 -core.events.openShop = function (shopId, needVisited) { - core.playSound("shop.mp3"); // 播放一个音效 - return openShop(shopId, needVisited); // 直接调用原始函数 -} -``` - -### 每次绘制地图前在控制台打出一条信息 - -绘制地图在`maps.js`的`drawMap`函数,因此需要对其进行重写。 - -由于只需要额外在函数执行前增加一句控制台输出,所以直接插入一行即可。 - -但是需要注意的是,`drawMap`中使用了`this._drawMap_drawAll()`,因此使用函数时需要用`call`或者`apply`来告知this是什么。 - -```js -var drawMap = core.maps.drawMap; // 先把原始函数用一个变量记录下来 -core.maps.drawMap = function (floorId, callback) { - console.log("drawMap..."); // 控制台打出一条信息 - drawMap.call(core.maps, floorId, callback); // 需要使用`call`来告知this是core.maps -} -``` - -详见[call和apply的用法](https://www.jianshu.com/p/80ea0d1c04f8)。 - -## 附录:API列表 - 这里将列出所有被转发到core的API,没有被转发的函数此处不会列出,请自行在代码中查看。 本附录量较大,如有什么需求请自行Ctrl+F进行搜索。 如有任何疑问,请联系小艾寻求帮助。 -### core.js +## core.js core.js中只有很少的几个函数,主要是游戏开始前的初始化等。 @@ -421,7 +167,7 @@ core.doFunc(func, _this) 此函数剩余参数将作为参数被传入func。 ``` -### actions.js +## actions.js actions.js主要是处理一些和用户交互相关的内容。 @@ -513,7 +259,7 @@ core.longClick() 如果全部返回false则将停止本次长按行为,直到手指离开屏幕并重新进行长按为止。 ``` -### control.js +## control.js control.js将负责整个游戏的核心控制系统,分为如下几个部分: - requestAnimationFrame相关 @@ -947,7 +693,7 @@ core.resize() 此函数将根据当前的屏幕分辨率信息,生成一个obj,并传入各个注册好的resize函数中执行。 ``` -### enemys.js +## enemys.js enemys.js中定义了一系列和怪物相关的API函数。 @@ -1033,7 +779,7 @@ core.hasEnemyLeft(floorId) 检查某个楼层是否还有剩余的怪物。等价于 core.getCurrentEnemys(floorId).length > 0 ``` -### events.js +## events.js events.js将处理所有和事件相关的操作,主要分为五个部分: - 游戏的开始和结束 @@ -1370,7 +1116,7 @@ core.afterUseBomb() 使用炸弹或圣锤后的事件。实际被转发到了脚本编辑中。 ``` -### icons.js +## icons.js icons.js主要是负责素材相关信息,比如某个素材在对应的图片上的位置。 @@ -1384,7 +1130,7 @@ core.getTilesetOffset(id) 如果该素材不是tileset,则返回null。 ``` -### items.js +## items.js items.js主要负责一切和道具相关的内容。 @@ -1474,7 +1220,7 @@ core.quickLoadEquip() 读取当前套装。index为读取的套装编号。 ``` -### loader.js +## loader.js loader.js主要负责资源加载相关的内容。 @@ -1509,7 +1255,7 @@ core.freeBgm(name) 释放一个bgm的内存并移出缓存列表。如果该bgm正在播放则也会立刻停止。 ``` -### map.js +## map.js maps.js负责一切和地图相关的处理内容,包括如下几个方面: - 地图的初始化,保存和读取,地图数组的生成 @@ -1842,7 +1588,7 @@ core.stopAnimate(id, doCallback) 如果doCallback为真,则会执行该动画所对应的回调函数。 ``` -### ui.js +## ui.js ui.js负责一切UI界面的绘制。主要包括三个部分: - 设置某个画布的属性的相关API @@ -2104,7 +1850,7 @@ core.ui.deleteAllCanvas() 删除所有的自定义画布。 ``` -### utils.js +## utils.js utils.js是一个工具函数库,里面有各个样板中使用到的工具函数。 diff --git a/_docs/element.md b/_docs/element.md index 6f4551d3..4fed9b92 100644 --- a/_docs/element.md +++ b/_docs/element.md @@ -85,7 +85,7 @@ percentage为该装备是否按比例增加属性。 使用`core.getEquip(equipType)`来获得某个装备类型的当前装备。 -更多相关API详见[附录:API列表](api#附录:API列表)。 +更多相关API详见[附录:API列表](api)。 ### 多重装备 diff --git a/_docs/event.md b/_docs/event.md index fbd0b094..9fd851a4 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1746,11 +1746,11 @@ icon是可选的,如果设置则会在选项前绘制图标,其可以是一 `{"type":"function"}`需要有一个`"function"`参数,它是一个JS函数,里面可以写任何自定义的JS脚本;系统将会执行它。 -系统常见可能会被造塔所用到的的API都在[API列表](api#附录:API列表)中给出,请进行参照。 +系统常见可能会被造塔所用到的的API都在[API列表](api)中给出,请进行参照。 **警告:自定义脚本中只能执行同步代码,不可执行任何异步代码,比如直接调用core.changeFloor(...)之类都是不行的。** -[API列表](api#附录:API列表)中的所有异步API都进行了标记;如果你不确定一个函数是同步的还是异步的,请向小艾咨询。 +[API列表](api)中的所有异步API都进行了标记;如果你不确定一个函数是同步的还是异步的,请向小艾咨询。 如果需要异步的代码都需要用事件(insertAction)来执行,这样事件处理过程和录像回放才不会出错。 diff --git a/_docs/img/plugin.jpg b/_docs/img/plugin.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d0d69befdce6b52593064bf9ac7cbca2206a66c8 GIT binary patch literal 32911 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 literal 0 HcmV?d00001 diff --git a/_docs/personalization.md b/_docs/personalization.md index 904b6e45..3341f2dd 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -51,7 +51,7 @@ core.fillText('test', '这是一段文字', 10, 30, '#FF0000', '16px Verdana'); `core.deleteAllCanvas()`可以删除所有动态创建的画布,`core.relocateCanvas(name, x, y)`和`core.resizeCanvas(name, x, y)`可以对画布的位置和大小进行改变。 -更多详细API请参见[API列表](api#附录:API列表)。 +更多详细API请参见[API列表](api)。 ## 自定义素材 @@ -339,7 +339,7 @@ function (enemy, hero_hp, hero_atk, hero_def, hero_mdef, x, y, floorId) { 要修改楼传事件,需要进行如下两步: -1. 重写楼传的点击事件。在插件中对`core.control.useFly进行重写`。详细代码参见[重写点击楼传事件](api#重写点击楼传事件)。 +1. 重写楼传的点击事件。在插件中对`core.control.useFly进行重写`。详细代码参见[重写点击楼传事件](script#重写点击楼传事件)。 2. 修改楼传的使用事件。和其他永久道具一样,在地图编辑器的图块属性中修改楼传的useItemEffect和canUseItemEffect两个内容。例如: ``` js "useItemEffect": "core.insertAction([...])" // 执行某段自定义事件,或者其他脚本 @@ -429,7 +429,7 @@ this.myfunc = function(x) { 从V2.6开始,在插件中用`this.xxx`定义的函数将会被转发到core中。例如上述的`myfunc`除了`core.plugin.myfunc`外也可以直接`core.myfunc`调用。 -详见[函数的转发](api#函数的转发)。 +详见[函数的转发](script#函数的转发)。 ## 标题界面事件化 diff --git a/_docs/script.md b/_docs/script.md new file mode 100644 index 00000000..817a68a6 --- /dev/null +++ b/_docs/script.md @@ -0,0 +1,313 @@ +# 脚本 + +?> 目前版本**v2.6**,上次更新时间:* {docsify-updated} * + +在V2.6版本中,基本对整个项目代码进行了重写,更加方便造塔者的使用和复写函数。 + +## 控制台的使用 + +在Chrome浏览器中,按(Ctrl+Shift+I)可打开控制台。 + +![](img/console.jpg) + +控制台中有很多的标签,最常用的是`Console`, `Sources`和`Elements`。 + +有关更详尽的控制台使用可自行搜索[Chrome开发者工具](https://www.baidu.com/s?wd=chrome%20%E5%BC%80%E5%8F%91%E8%80%85%E5%B7%A5%E5%85%B7)了解更多。 + +### Console:命令行 + +Console页为命令行。可以在这里输入一些命令进行调试。 + +比如,进入游戏后,输入`core.status.hero.atk`即可获得勇士的当前攻击力数值。`core.status.hero.atk=100`可以设置攻击力为100。 + +更多的API可参见[附录:API列表](#附录:API列表)。 + +除此以外,游戏中的报错等信息也是可以在Console中进行查看的。 + +![](img/console1.jpg) + +### Sources:断点调试 + +Sources页可以查看JS源代码,并进行断点调试等。 + +例如,如果相对脚本编辑中的伤害计算函数进行断点调试: +1. 在左边找到`project/functions.js`,单击打开文件 +2. 并找到对应的行(可以Ctrl+F搜索),比如搜索`getDamageInfo` +3. 在行号上点一下打断点,会出现一个蓝色标签 + +之后,当代码运行到你的断点处时,将自动停止运行。 + +![](img/sources.jpg) + +可以将鼠标移动到变量上,将弹窗形式显示这个变量的各项数值,从而查看变量值是否符合预期。 + +图中红色框内有几个按钮,从左到右分别是:**继续执行**,**执行到下一行**,**进入当前函数**,**跳出当前函数**,**单步执行**。 + +通过这几个按钮,可以一行一行的对代码进行执行,执行过程中能不断查看各个变量的数值变化,从而定位问题所在。 + +红圈下方是Call Stack,即当前的函数调用链(从哪些地方调用过来的)。 + +Sources还有更多有趣的功能,在此不做介绍,有兴趣的可自行网上搜索了解。 + +### Elements:网页元素查看 + +Elements页可以查看网页的源代码,调整css布局等。 + +![](img/elements.jpg) + +不过对魔塔样板来说,最重要的是红圈中的按钮。点击此按钮可以进入**手机模式**。 + +手机模式下,左边可以对屏幕分辨率进行调整和模拟。 + +这可以很有效的帮我们进行测试样板在手机端的表现。 + +## 整体项目架构 + +``` text +├── /_server/ # 为可视化地图编辑器提供一些支持的目录 +├── /libs/ # ---- 系统库目录 ---- +│ ├─ /thirdparty/ # 游戏所用到的第三方库文件 +│ ├─ actions.js # 用户交互处理 +│ ├─ core.js # 系统核心文件(游戏入口,接口&转发) +│ ├─ control.js # 游戏逻辑控制 +│ ├─ data.js # 全塔属性等 +│ ├─ enemys.js # 怪物相关处理 +│ ├─ events.js # 各个事件的执行 +│ ├─ icons.js # 图标和素材 +│ ├─ items.js # 道具效果 +│ ├─ loader.js # 各个资源加载 +│ ├─ maps.js # 地图数据和绘制 +│ ├─ ui.js # UI窗口绘制 +│ └─ utils.js # 工具类函数 +├── /project/ # ---- 项目目录 ---- +│ ├─ /animates/ # 动画目录 +│ ├─ /floors/ # 楼层文件 +│ ├─ /images/ # 图片素材 +│ ├─ /sounds/ # bgm和音效 +│ ├─ data.js # 全塔属性 +│ ├─ enemys.js # 怪物属性 +│ ├─ events.js # 公共事件 +│ ├─ functions.js # 脚本编辑 +│ ├─ icons.js # 素材和ID的对应关系定义 +│ ├─ items.js # 道具的定义和效果 +│ ├─ maps.js # 地图和数字的对应关系 +│ └─ plugins.js # 自定义插件 +├── /常用工具/ # 辅助造塔的小工具 +├── editor.html # 地图编辑器 +├── editor-mobile.html # 手机版的地图编辑器 +├── index.html # 主程序,游戏的入口 +├── main.js # JS程序的入口,将动态对所需JS进行加载 +├── style.css # 游戏所需要用到的样式表 +└── 启动服务.exe # 一个本地的HTTP服务器,通过它来运行游戏 +``` + +`_server`为**地图编辑器目录**,里面存放了地图编辑器相关的各项内容。 + +`libs`为**系统库目录**,里面存放了各个系统核心函数。 + +从V2.6开始,请勿直接修改libs下的代码,如有需要修改系统库函数请尝试在插件中[复写函数](#复写函数)。 + +`project`为**项目目录**,你所造的塔的数据全部存放在project下。在不同样板之间接档也是直接迁移project目录即可。 + +## 函数的转发 + +在本样板中,`core.js`里面基本是没有定义什么函数的,所有的游戏内函数都在其他几个文件中实现。 + +例如,常见的获得某个变量值`getFlag`是定义在`control.js`中的: + +```js +////// 获得某个自定义变量或flag ////// +control.prototype.getFlag = function(name, defaultValue) { + if (!core.status.hero) return defaultValue; + var value = core.status.hero.flags[name]; + return value != null ? value : defaultValue; +} +``` + +也就是,我们可以通过`core.control.getFlag(name, value)`来调用此函数。 + +但是这样会十分不便,我们希望能直接调用`core.getFlag(name, value)`,而不需要中间的control。 + +为了达到这个目的,样板设置了**函数转发**,即**将其他文件中定义的函数,转发到core中执行**。 + +上述`getFlag`代码的转发实际上是增加了如下函数: + +```js +////// getFlag函数的转发 ////// +core.getFlag = function (name, defaultValue) { + return core.control.getFlag(name, defaultValue); +} +// 转发后,即可通过 core.getFlag() 来实际调用 core.control.getFlag() +``` + +转发是自动完成的,其满足如下两条规则: +- **在libs中其他文件定义的函数,如果不以下划线`_`开头,就会进行转发。** +- **如果core中已经存在同名函数,则会在控制台中打出一条报错信息,并不转发该函数。** + +具体函数的转发实现代码可参见`core.js`的`_forwardFunc`函数。 + +!> 除此以外,插件中以`this.xxx`来定义的函数也会被转发! + +例如,你可以直接调用`core.drawLight()`来实际调用插件中的`core.plugin.drawLight`。 + +## 插件编写 + +插件编写是H5魔塔的一个重大特点,从V2.0.1引入,并逐渐发扬光大。 + +对于有一定脚本经验的人来说,可以编写插件来实现各种各样的功能,包括且不仅限于拓展功能的实现,系统代码的复写等等。 + +在V2.5.5以前,插件位置都在脚本编辑中;从V2.6开始则迁移到了新的下拉框中,并进行了切分。 + +你也可以创建自己的插件。 + +![](img/plugin.jpg) + +新的插件切分和原来的单插件使用方法完全一致,单纯进行了切分而已。可参见已有的`init`和`drawLight`的样例。 + +拆分的意义主要是将各个可能的功能独立出来,避免单个框内内容太长,过大和混杂等。 + +在V2.6中,应当每个独立的额外功能实现都新建一个自己的插件,这样也方便进行拓展,例如打包迁移到别的塔上,或发布在网页插件库中。 + +另外一点需要注意的是,所有插件的初始化都会在系统资源加载之前,此时图片等资源尚未进行加载。 + +在所有资源加载完毕时,将会执行init插件中的_afterLoadResources函数,可以在这里对资源进行一些操作,比如切分图片等。 + +```js +function () { + console.log("插件编写测试"); + + // 可以写一些直接执行的代码 + // 在这里写的代码将会在【资源加载前】被执行,此时图片等资源尚未被加载。 + // 请勿在这里对包括bgm,图片等资源进行操作。 + + + this._afterLoadResources = function () { + // 本函数将在所有资源加载完毕后,游戏开启前被执行 + // 可以在这个函数里面对资源进行一些操作,比如切分图片等。 + + // 这是一个将assets.png拆分成若干个32x32像素的小图片并保存的样例。 + // var arr = core.splitImage("assets.png", 32, 32); + // for (var i = 0; i < arr.length; i++) { + // core.material.images.images["asset"+i+".png"] = arr[i]; + // } + + } + + // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); + // 从V2.6开始,插件中用this.XXX方式定义的函数也会被转发到core中,详见文档-脚本-函数的转发。 +} +``` + +网站上提供了一个插件库,[https://h5mota.com/plugins/](https://h5mota.com/plugins/),上面有一些大家分享的插件,可供使用。 + +可以查看附录中的[API列表](api)来查看所有的系统API内容。 + +## 复写函数 + +样板的功能毕竟是写死的,有时候我们也需要修改样板的一些行为。 + +在V2.6以前,需要直接打开libs目录下的对应文件并进行修改。但是开libs下的文件就会出现各种问题: +- 不容易随着新样板接档进行迁移 +- 也不好找到自己改过什么,从而能整理成新的插件在别的塔使用 +- …… + +好消息的是,从V2.6开始,我们再也不需要开文件了,而是可以直接在插件中对原始函数进行复写。 + +如果我想对xxx文件中的yyy函数进行重写,其模式一般是:`core.xxx.yyy = function (参数列表) { ... }` + +下面是几个例子,从简单到复杂。 + +### 重写怪物手册的背景图绘制,使用winskin而不是默认的黑色 + +直接重写怪物手册的背景图绘制,使用`core.drawBackground`来用winskin绘制一个背景图。 + +```js +// 重写ui.js中的_drawBook_drawBackground函数 +core.ui._drawBook_drawBackground = function () { + // core.__PIXEL__为定义的一个宏,对于13x13的值是416,对于15x15的值是480 + core.drawBackground(0, 0, core.__PIXEL__, core.__PIXEL__); +} +``` + +### 重写点击楼传事件 + +重写点击楼传事件,使得点击楼传按钮时能使用一个道具(比如item:fly)。 + +```js +// 重写events.js的useFly函数,即点击楼传按钮时的事件 +core.events.useFly = function (fromUserAction) { + if (core.isMoving()) { + core.drawTip("请先停止勇士行动"); + return; + } + if (core.status.lockControl || core.status.event.id != null) return; + + if (core.canUseItem('fly')) core.useItem('fly'); + else core.drawTip("当前无法使用"+core.material.items.fly.name); +} +``` + +其他的几个按钮,如快捷商店`openQuickShop`,虚拟键盘`openKeyBoard`的重写也几乎完全一样。 + +### 楼层切换时根据flag来播放不同的音效 + +整体复制并重写整个楼传切换前的函数,将`core.playSound('floor.mp3')`替换成根据flag来判定。 + +```js +// 复制重写events.js中的_changeFloor_beforeChange,修改音效 +core.events._changeFloor_beforeChange = function (info, callback) { + // 直接替换原始函数中的 core.playSound('floor.mp3'); + if (core.getFlag("floorSound") == 0) core.playSound('floor0.mp3'); + if (core.getFlag("floorSound") == 1) core.playSound('floor1.mp3'); + if (core.getFlag("floorSound") == 2) core.playSound('floor2.mp3'); + // ... + + // 下面是原始函数中的剩余代码,保持不变 + window.setTimeout(function () { + if (info.time == 0) + core.events._changeFloor_changing(info, callback); + else + core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () { + core.events._changeFloor_changing(info, callback); + }); + }, 25) +} +``` + +### 每次打开全局商店时播放一个音效 + +打开全局商店是在`events.js`中的`openShop`函数,因此需要对其进行重写。 + +然而,我们只需要在这个函数执行之前插一句音效播放,所以并不需要重写整个函数,而是直接插入一行就行。 + +```js +var openShop = core.events.openShop; // 先把原始函数用一个变量记录下来 +core.events.openShop = function (shopId, needVisited) { + core.playSound("shop.mp3"); // 播放一个音效 + return openShop(shopId, needVisited); // 直接调用原始函数 +} +``` + +### 每次绘制地图前在控制台打出一条信息 + +绘制地图在`maps.js`的`drawMap`函数,因此需要对其进行重写。 + +由于只需要额外在函数执行前增加一句控制台输出,所以直接插入一行即可。 + +但是需要注意的是,`drawMap`中使用了`this._drawMap_drawAll()`,因此使用函数时需要用`call`或者`apply`来告知this是什么。 + +```js +var drawMap = core.maps.drawMap; // 先把原始函数用一个变量记录下来 +core.maps.drawMap = function (floorId, callback) { + console.log("drawMap..."); // 控制台打出一条信息 + drawMap.call(core.maps, floorId, callback); // 需要使用`call`来告知this是core.maps +} +``` + +详见[call和apply的用法](https://www.jianshu.com/p/80ea0d1c04f8)。 + +========================================================================================== + +[继续阅读下一章:API列表](api) + + diff --git a/_docs/start.md b/_docs/start.md index f5b4fa12..004ea21f 100644 --- a/_docs/start.md +++ b/_docs/start.md @@ -231,7 +231,7 @@ HTML5的塔都是可以进行控制台调试的。 - `core.resetMap()` 重置当前层地图。 - …… -更多API和详细参数介绍可参见[API列表](api#附录:API列表)。 +更多API和详细参数介绍可参见[API列表](api)。 ## 编辑器的基本操作 diff --git a/libs/ui.js b/libs/ui.js index 6c4501e2..54dbccc1 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -542,7 +542,7 @@ ui.prototype._calTextBoxWidth = function (ctx, content, min_width, max_width, fo // 如果不存在手动换行,尽量调成半行形式 if (allLines.length == 1) { - var w = core.calWidth(ctx, allLines[0]) + 5; + var w = core.calWidth(ctx, allLines[0]) + 10; if (w Date: Thu, 4 Apr 2019 23:15:24 +0800 Subject: [PATCH 153/153] type:confirm --- _docs/event.md | 32 ++++++++++++++++++++++++++++++-- _docs/personalization.md | 2 +- _server/MotaAction.g4 | 26 ++++++++++++++------------ _server/editor_blockly.js | 6 +++--- libs/actions.js | 26 ++++++++++++++++++++++++++ libs/events.js | 36 ++++++++++++++++++++++++++++++++++-- libs/ui.js | 9 ++++++--- 7 files changed, 114 insertions(+), 23 deletions(-) diff --git a/_docs/event.md b/_docs/event.md index 9fd851a4..e5a2b7b9 100644 --- a/_docs/event.md +++ b/_docs/event.md @@ -1502,7 +1502,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 {"case": "a", "action": [// 若表达式的值等于a则执行该处事件 ], - {"case": "b", "action": [// 若表达式的值等于b则执行该处事件 + {"case": "b", "nobreak": true, "action": [// 若表达式的值等于b则执行该处事件,不跳出 ], {"case": "default", "action": [ // 没有条件成立则执行该处里的事件 @@ -1519,6 +1519,8 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 如果没有符合的值,则将执行`default`中的列表事件内容。 +nobreak是可选的,如果设置,则在当前条件满足并插入事件后,不跳出多重分歧,而是继续判定下一个条件。 + 例如下面这个例子,将检查当前游戏难度并赠送不同属性。 ``` js @@ -1551,7 +1553,7 @@ text为提示文字,可以在这里给输入提示文字。这里同样可以 - 即使某个场合不执行事件,对应的action数组也需要存在,不过简单的留空就好。 - switch语句内的内容执行完毕后将接着其后面的语句继续执行。 -由于`case`中的内容是会被计算的,因此如下写法也是合法的 +另外由于`case`中的内容是会被计算的,因此如下写法也是合法的 ```js [ @@ -1614,6 +1616,32 @@ icon是可选的,如果设置则会在选项前绘制图标,其可以是一 选项可以有任意多个,但一般不要超过6个,否则屏幕可能塞不下。 +### confirm:显示确认框 + +`{"type": "confirm"}`将提供一个确认框供用户选择,其基本写法如下: + +```js +[ + {"type": "confirm", "text": "...", // 提示文字 + "default": false, // 是否默认选中【确定】 + "yes": [ + // 点击确定时执行的事件 + ], + "no": [ + // 点击取消时执行的事件 + ] + }, +] +``` + +text为必填项,代表提示的文字,支持${}的表达式计算和\n的手动换行。 + +text暂时不支持自动换行、变色\r、图标绘制\i等效果。如有需求请使用choices事件。 + +default可选,如果为true则显示选择项时默认选中【确定】,否则默认选中【取消】。 + +yes和no均为必填项,即用户点击确认或取消后执行的事件。 + ### while:循环处理 从2.2.1样板开始,我们提供了循环处理(while事件)。 diff --git a/_docs/personalization.md b/_docs/personalization.md index 3341f2dd..c8f517e6 100644 --- a/_docs/personalization.md +++ b/_docs/personalization.md @@ -714,4 +714,4 @@ if (core.flags.enableSkill) { ========================================================================================== -[继续阅读脚本](api) +[继续阅读脚本](script) diff --git a/_server/MotaAction.g4 b/_server/MotaAction.g4 index aee1ed18..a43d0c9a 100644 --- a/_server/MotaAction.g4 +++ b/_server/MotaAction.g4 @@ -1604,14 +1604,16 @@ return code; */; switchCase - : '如果是' expression '的场合' BGNL? Newline action+ + : '如果是' expression '的场合' '不跳出' Bool BGNL? Newline action+ /* switchCase tooltip : 选项的选择 helpUrl : https://h5mota.com/games/template/docs/#/event?id=switch%EF%BC%9A%E5%A4%9A%E9%87%8D%E6%9D%A1%E4%BB%B6%E5%88%86%E6%AD%A7 +default : ["", false] colour : this.subColor -var code = '{"case": "'+expression_0+'", "action": [\n'+action_0+']},\n'; +Bool_0 = Bool_0?', "nobreak": true':''; +var code = '{"case": "'+expression_0+'"'+Bool_0+', "action": [\n'+action_0+']},\n'; return code; */; @@ -1640,13 +1642,13 @@ return code; */; choicesContext - : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour '不跳出' Bool BGNL? Newline action+ + : '子选项' EvalString '图标' IdString? '颜色' EvalString? Colour BGNL? Newline action+ /* choicesContext tooltip : 选项的选择 helpUrl : https://h5mota.com/games/template/docs/#/event?id=choices%EF%BC%9A%E7%BB%99%E7%94%A8%E6%88%B7%E6%8F%90%E4%BE%9B%E9%80%89%E9%A1%B9 -default : ["提示文字:红钥匙","","",null,false] +default : ["提示文字:红钥匙","",""] colour : this.subColor if (EvalString_1) { var colorRe = /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d),(25[0-5]|2[0-4]\d|1\d\d|[1-9]\d|\d)(,0(\.\d+)?|,1)?$/; @@ -1656,19 +1658,19 @@ if (EvalString_1) { EvalString_1 = ', "color": "'+EvalString_1+'"'; } IdString_0 = IdString_0?(', "icon": "'+IdString_0+'"'):''; -var nobreak = Bool_0?', "nobreak": true':''; -var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']'+nobreak+'},\n'; +var code = '{"text": "'+EvalString_0+'"'+IdString_0+EvalString_1+', "action": [\n'+action_0+']},\n'; return code; */; confirm_s - : '显示确认框' ':' EvalString BGNL? '确定' ':' BGNL? Newline action+ '取消' ':' BGNL? Newline action+ BEND Newline + : '显示确认框' ':' EvalString BGNL? '确定的场合' ':' '(默认选中' Bool ')' BGNL? Newline action+ '取消的场合' ':' BGNL? Newline action+ BEND Newline /* confirm_s tooltip : 弹出确认框 helpUrl : https://h5mota.com/games/template/docs/#/ -default : ["确认要???吗?"] -var code = ['{"type": "confirm", "text": "',EvalString_0,'",\n', +default : ["确认要xxx吗?",false] +Bool_0 = Bool_0?', "default": true':'' +var code = ['{"type": "confirm"'+Bool_0+', "text": "',EvalString_0,'",\n', '"yes": [\n',action_0,'],\n', '"no": [\n',action_1,']\n', '},\n'].join(''); @@ -2590,7 +2592,7 @@ ActionParser.prototype.parseAction = function() { break; case "confirm": // 显示确认框 this.next = MotaActionBlocks['confirm_s'].xmlText([ - this.EvalString(data.text), + this.EvalString(data.text), data["default"], this.insertActionList(data["yes"]), this.insertActionList(data["no"]), this.next]); @@ -2599,7 +2601,7 @@ ActionParser.prototype.parseAction = function() { var case_caseList = null; for(var ii=data.caseList.length-1,caseNow;caseNow=data.caseList[ii];ii--) { case_caseList=MotaActionBlocks['switchCase'].xmlText([ - this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",this.insertActionList(caseNow.action),case_caseList]); + this.isset(caseNow.case)?MotaActionBlocks['evalString_e'].xmlText([caseNow.case]):"值",caseNow.nobreak,this.insertActionList(caseNow.action),case_caseList]); } this.next = MotaActionBlocks['switch_s'].xmlText([ // MotaActionBlocks['evalString_e'].xmlText([data.condition]), @@ -2610,7 +2612,7 @@ ActionParser.prototype.parseAction = function() { var text_choices = null; for(var ii=data.choices.length-1,choice;choice=data.choices[ii];ii--) { text_choices=MotaActionBlocks['choicesContext'].xmlText([ - choice.text,choice.icon,choice.color,'rgba('+choice.color+')',choice.nobreak,this.insertActionList(choice.action),text_choices]); + choice.text,choice.icon,choice.color,'rgba('+choice.color+')',this.insertActionList(choice.action),text_choices]); } this.next = MotaActionBlocks['choices_s'].xmlText([ this.isset(data.text)?this.EvalString(data.text):null,'','',text_choices,this.next]); diff --git a/_server/editor_blockly.js b/_server/editor_blockly.js index 09ba5f45..1c81e65c 100644 --- a/_server/editor_blockly.js +++ b/_server/editor_blockly.js @@ -70,9 +70,9 @@ editor_blockly = function () { MotaActionBlocks['lose_s'].xmlText(), MotaActionBlocks['choices_s'].xmlText([ '选择剑或者盾','流浪者','man',MotaActionBlocks['choicesContext'].xmlText([ - '剑','','',null,null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), + '剑','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [3,3]}]), MotaActionBlocks['choicesContext'].xmlText([ - '盾','','',null,null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), + '盾','','',null,MotaActionFunctions.actionParser.parseList([{"type": "openDoor", "loc": [9,3]}]), ]) ]) ]), @@ -113,7 +113,7 @@ editor_blockly = function () { MotaActionBlocks['if_s'].xmlText(), MotaActionFunctions.actionParser.parseList({"type": "switch", "condition": "判别值", "caseList": [ {"action": [{"type": "comment", "text": "当判别值是值的场合执行此事件"}]}, - {"action": []}, + {"action": [], "nobreak": true}, {"case": "default", "action": [{"type": "comment", "text": "当没有符合的值的场合执行default事件"}]}, ]}), MotaActionBlocks['while_s'].xmlText(), diff --git a/libs/actions.js b/libs/actions.js index 2d516b52..bb0cce1f 100644 --- a/libs/actions.js +++ b/libs/actions.js @@ -892,6 +892,19 @@ actions.prototype._clickAction = function (x, y) { } } } + + if (core.status.event.data.type == 'confirm') { + if ((x == this.HSIZE-2 || x == this.HSIZE-1) && y == this.HSIZE+1) { + core.status.route.push("choices:0"); + core.insertAction(core.status.event.ui.yes); + core.doAction(); + } + if ((x == this.HSIZE+2 || x == this.HSIZE+1) && y == this.HSIZE+1) { + core.status.route.push("choices:1"); + core.insertAction(core.status.event.ui.no); + core.doAction(); + } + } } ////// 自定义事件时,按下某个键的操作 ////// @@ -899,6 +912,10 @@ actions.prototype._keyDownAction = function (keycode) { if (core.status.event.data.type == 'choices') { this._keyDownChoices(keycode); } + if (core.status.event.data.type == 'confirm' && (keycode == 37 || keycode == 39)) { + core.status.event.selection = 1 - core.status.event.selection; + core.drawConfirmBox(core.status.event.ui.text); + } } ////// 自定义事件时,放开某个键的操作 ////// @@ -924,6 +941,15 @@ actions.prototype._keyUpAction = function (keycode) { if (choices.length > 0) { this._selectChoices(choices.length, keycode, this._clickAction); } + return; + } + if (core.status.event.data.type == 'confirm'&& (keycode == 13 || keycode == 32 || keycode == 67)) { + core.status.route.push("choices:" + core.status.event.selection); + if (core.status.event.selection == 0) + core.insertAction(core.status.event.ui.yes); + else core.insertAction(core.status.event.ui.no); + core.doAction(); + return; } } diff --git a/libs/events.js b/libs/events.js index 6b3d5beb..b5b1170f 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1329,13 +1329,16 @@ events.prototype._action_if = function (data, x, y, prefix) { events.prototype._action_switch = function (data, x, y, prefix) { var key = core.calValue(data.condition, prefix) + var list = []; for (var i = 0; i < data.caseList.length; i++) { var condition = data.caseList[i]["case"]; if (condition == "default" || core.calValue(condition, prefix) == key) { - this.insertAction(data.caseList[i].action); - break; + core.push(list, data.caseList[i].action); + if (!data.caseList[i].nobreak) + break; } } + core.insertAction(list); core.doAction(); } @@ -1363,6 +1366,35 @@ events.prototype._action_choices = function (data, x, y, prefix) { core.ui.drawChoices(data.text, data.choices); } +events.prototype._action_confirm = function (data, x, y, prefix) { + core.status.event.ui = {"text": data.text, "yes": data.yes, "no": data.no}; + if (core.isReplaying()) { + var action = core.status.replay.toReplay.shift(), index; + // --- 忽略可能的turn事件 + if (action == 'turn') action = core.status.replay.toReplay.shift(); + if (action.indexOf("choices:") == 0 && ((index = parseInt(action.substring(8))) >= 0) && index < 2) { + core.status.event.selection = index; + setTimeout(function () { + core.status.route.push("choices:" + index); + if (index == 0) core.insertAction(data.yes); + else core.insertAction(data.no); + core.doAction(); + }, 750 / Math.max(1, core.status.replay.speed)) + } + else { + main.log("录像文件出错!当前需要一个 choices: 项,实际为 " + action); + core.stopReplay(); + core.insertAction(["录像文件出错,请在控制台查看报错信息。", {"type": "exit"}]); + core.doAction(); + return; + } + } + else { + core.status.event.selection = data["default"] ? 0 : 1; + } + core.ui.drawConfirmBox(data.text); +} + events.prototype._action_while = function (data, x, y, prefix) { if (core.calValue(data.condition, prefix)) { core.unshift(core.status.event.data.list, diff --git a/libs/ui.js b/libs/ui.js index 54dbccc1..db1a09e9 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1081,9 +1081,12 @@ ui.prototype.drawConfirmBox = function (text, yesCallback, noCallback) { core.lockControl(); text = core.replaceText(text || ""); - core.status.event.id = 'confirmBox'; - core.status.event.data = {'yes': yesCallback, 'no': noCallback}; - core.status.event.ui = text; + // 处理自定义事件 + if (core.status.event.id != 'action') { + core.status.event.id = 'confirmBox'; + core.status.event.data = {'yes': yesCallback, 'no': noCallback}; + } + if (core.status.event.selection != 0) core.status.event.selection = 1; this.clearUI();