From 9b159f045d2631e8931040b07f05e2a49bebc96c Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 26 Oct 2018 19:36:48 +0800 Subject: [PATCH 1/4] Console Opened & Save Hashcode --- libs/control.js | 30 ++++++++++++++++++++++++++---- libs/events.js | 5 +++++ libs/utils.js | 31 +++++++++++++++++++++++++++++-- 3 files changed, 60 insertions(+), 6 deletions(-) diff --git a/libs/control.js b/libs/control.js index c15c547c..c205e65c 100644 --- a/libs/control.js +++ b/libs/control.js @@ -190,6 +190,11 @@ control.prototype.setRequestAnimationFrame = function () { // 执行用户的并行事件处理内容 functions_d6ad677b_427a_4623_b50f_a445a3b0ef8a.plugins.parallelDo(timestamp); + // 检查控制台状态 + if (core.utils.consoleOpened()) { + core.setFlag('consoleOpened', true); + } + window.requestAnimationFrame(draw); } window.requestAnimationFrame(draw); @@ -2213,7 +2218,12 @@ control.prototype.doSL = function (id, type) { } }, function(err) { console.info(err); - core.drawTip("存档失败,请将控制台的报错信息反馈给管理员。"); + if (core.platform.useLocalForage) { + alert("存档失败,请将控制台的报错信息反馈给管理员。"); + } + else { + alert("存档空间不足,请先使用垃圾存档清理工具进行清理!"); + } }) return; } @@ -2222,7 +2232,11 @@ control.prototype.doSL = function (id, type) { core.getLocalForage(id=='autoSave'?id:"save"+id, null, function(data) { if (!core.isset(data)) { - core.drawTip("无效的存档"); + alert("无效的存档"); + return; + } + if (core.isset(data.hashCode) && data.hashCode != core.utils.hashCode(data.hero)) { + alert("存档校验失败,请勿修改存档文件!"); return; } if (data.version != core.firstData.version) { @@ -2250,7 +2264,7 @@ control.prototype.doSL = function (id, type) { }); }, function(err) { console.log(err); - core.drawTip("无效的存档"); + alert("无效的存档"); }) return; @@ -2270,6 +2284,10 @@ control.prototype.doSL = function (id, type) { 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("无法从此存档回放录像"); @@ -2389,6 +2407,9 @@ control.prototype.syncLoad = function () { ////// 存档到本地 ////// control.prototype.saveData = function() { + var hero = core.clone(core.status.hero); + var hashCode = core.utils.hashCode(hero); + var data = { 'floorId': core.status.floorId, 'hero': core.clone(core.status.hero), @@ -2398,7 +2419,8 @@ control.prototype.saveData = function() { 'values': core.clone(core.values), 'shops': {}, 'version': core.firstData.version, - "time": new Date().getTime() + "time": new Date().getTime(), + "hashCode": hashCode }; // set shop times for (var shop in core.status.shops) { diff --git a/libs/events.js b/libs/events.js index bfb5ba3f..b25f8c92 100644 --- a/libs/events.js +++ b/libs/events.js @@ -242,6 +242,11 @@ events.prototype.gameOver = function (ending, fromReplay, norank) { core.restart(); }) } + else if (core.hasFlag('consoleOpened')) { + core.drawText("\t[系统提示]本存档开启过控制台,无法上传成绩", function () { + core.restart(); + }) + } else { confirmUpload(); } diff --git a/libs/utils.js b/libs/utils.js index 9a05a0a1..ee7a845c 100644 --- a/libs/utils.js +++ b/libs/utils.js @@ -127,8 +127,12 @@ utils.prototype.removeLocalStorage = function (key) { utils.prototype.setLocalForage = function (key, value, successCallback, errorCallback) { if (!core.platform.useLocalForage) { - this.setLocalStorage(key, value); - if (core.isset(successCallback)) successCallback(); + if (this.setLocalStorage(key, value)) { + if (core.isset(successCallback)) successCallback(); + } + else { + if (core.isset(errorCallback)) errorCallback(); + } return; } @@ -722,6 +726,29 @@ utils.prototype.hide = function (obj, speed, callback) { }, speed); } +utils.prototype.consoleOpened = function () { + var threshold = 160; + var widthThreshold = window.outerWidth - window.innerWidth > threshold; + var heightThreshold = window.outerHeight - window.innerHeight > threshold; + return !(heightThreshold && widthThreshold) && + ((window.Firebug && window.Firebug.chrome && window.Firebug.chrome.isInitialized) + || widthThreshold || heightThreshold); +} + +utils.prototype.hashCode = function (obj) { + if (typeof obj == 'string') { + 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; + hash |= 0; + } + return hash; + } + return this.hashCode(JSON.stringify(obj).split("").sort().join("")); +} + utils.prototype._export = function (floorIds) { if (!core.isset(floorIds)) floorIds = [core.status.floorId]; else if (floorIds=='all') floorIds = core.clone(core.floorIds); From 06cb8cd64b35cf94a2359042948eaf8d39fea139 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 26 Oct 2018 19:50:23 +0800 Subject: [PATCH 2/4] moveImage speed --- libs/control.js | 2 +- libs/events.js | 9 +++++---- 更新说明.txt | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libs/control.js b/libs/control.js index c205e65c..f4cff9e7 100644 --- a/libs/control.js +++ b/libs/control.js @@ -2412,7 +2412,7 @@ control.prototype.saveData = function() { var data = { 'floorId': core.status.floorId, - 'hero': core.clone(core.status.hero), + 'hero': hero, 'hard': core.status.hard, 'maps': core.maps.save(core.status.maps), 'route': core.encodeRoute(core.status.route), diff --git a/libs/events.js b/libs/events.js index b25f8c92..2ef77f0b 100644 --- a/libs/events.js +++ b/libs/events.js @@ -1425,10 +1425,11 @@ events.prototype.moveImage = function (image, from, to, time, keep, callback) { var fromX = core.calValue(from[0]), fromY = core.calValue(from[1]), toX = core.calValue(to[0]), toY = core.calValue(to[1]); var step = 0; + var per_time = 10, steps = parseInt(time / per_time); var drawImage = function () { core.clearMap('data'); - var nowX = parseInt(fromX + (toX-fromX)*step/64); - var nowY = parseInt(fromY + (toY-fromY)*step/64); + var nowX = parseInt(fromX + (toX-fromX)*step/steps); + var nowY = parseInt(fromY + (toY-fromY)*step/steps); core.canvas.data.drawImage(image, nowX, nowY); } @@ -1436,14 +1437,14 @@ events.prototype.moveImage = function (image, from, to, time, keep, callback) { var animate = setInterval(function () { step++; drawImage(); - if (step>=64) { + if (step>=steps) { clearInterval(animate); core.clearMap('data'); core.status.replay.animate=false; if (keep) core.canvas.data.drawImage(image, toX, toY); if (core.isset(callback)) callback(); } - }, time / 64); + }, per_time); } ////// 淡入淡出音乐 ////// diff --git a/更新说明.txt b/更新说明.txt index d713bd0f..f15483f9 100644 --- a/更新说明.txt +++ b/更新说明.txt @@ -14,6 +14,7 @@ Autotile自动元件的新增和注册 可以设置剧情文本的字体大小 录像播放可以最高24倍速 1-6键快速设置录像播放速度;滚轮加减速 +进一步加强防作弊机制 部分其他细节优化 ----------------------------------------------------------------------- From 68065536da4f1b43e22c2b4890675eba55dd3195 Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 26 Oct 2018 19:59:04 +0800 Subject: [PATCH 3/4] Console Open red time --- libs/ui.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/ui.js b/libs/ui.js index 4744889b..fce7961b 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1989,7 +1989,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.strokeRect('ui', (2*i+1)*u-size/2, 50, 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.load(data.maps, data.floorId).blocks, (2*i+1)*u-size/2, 50, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 65+size, '#FFFFFF', '10px Verdana'); + core.fillText('ui', core.formatDate(new Date(data.time)), (2*i+1)*u, 65+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF', '10px Verdana'); } else { core.fillRect('ui', (2*i+1)*u-size/2, 50, size, size, '#333333', 2); @@ -2001,7 +2001,7 @@ ui.prototype.drawSLPanel = function(index, refresh) { core.strokeRect('ui', (2*i-5)*u-size/2, 245, 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.load(data.maps, data.floorId).blocks, (2*i-5)*u-size/2, 245, size, data.hero.loc.x, data.hero.loc.y, data.hero.loc, data.hero.flags.heroIcon||"hero.png"); - core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 260+size, '#FFFFFF', '10px Verdana'); + core.fillText('ui', core.formatDate(new Date(data.time)), (2*i-5)*u, 260+size, data.hero.flags.consoleOpened?'#FF6A6A':'#FFFFFF', '10px Verdana'); } else { core.fillRect('ui', (2*i-5)*u-size/2, 245, size, size, '#333333', 2); From 69374042c363d1540b32dc5f1de242e7d0ae7d9b Mon Sep 17 00:00:00 2001 From: oc Date: Fri, 26 Oct 2018 21:27:35 +0800 Subject: [PATCH 4/4] imitate criticals & canBreak --- _server/comment.js | 11 +++++++++ libs/enemys.js | 4 ++-- libs/ui.js | 37 +++++++++++++++++++++++++++++ project/items.js | 58 +++++++++++++++++++++++----------------------- project/maps.js | 6 ++--- 5 files changed, 82 insertions(+), 34 deletions(-) diff --git a/_server/comment.js b/_server/comment.js index f393526f..85f7b315 100644 --- a/_server/comment.js +++ b/_server/comment.js @@ -225,6 +225,17 @@ comment_c456ea59_6018_45ef_8bcc_211a24c627dc = ] }, "_data": "该图块是否不可通行;true代表不可通行,false代表可通行,null代表使用系统缺省值" + }, + "canBreak": { + "_leaf": true, + "_type": "select", + "_select": { + "values": [ + true, + false + ] + }, + "_data": "该图块是否可被破炸;true代表可以,false代表不可以" } } }, diff --git a/libs/enemys.js b/libs/enemys.js index efae6beb..c6350103 100644 --- a/libs/enemys.js +++ b/libs/enemys.js @@ -169,7 +169,7 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { if (nextAtk!=pre) { var nextInfo = this.getDamageInfo(enemy, core.status.hero.hp, nextAtk, core.status.hero.def, core.status.hero.mdef, x, y, floorId); if (nextInfo==null) break; - list.push([nextAtk-hero_atk,info.damage-nextInfo.damage]); + list.push([nextAtk-hero_atk,Math.floor(info.damage-nextInfo.damage)]); if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; pre = nextAtk; } @@ -184,7 +184,7 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { if (nextInfo==null) break; if (pre>nextInfo.damage) { pre = nextInfo.damage; - list.push([atk-hero_atk, info.damage-nextInfo.damage]); + list.push([atk-hero_atk, Math.floor(info.damage-nextInfo.damage)]); if (nextInfo.damage<=0 && !core.flags.enableNegativeDamage) break; if (list.length>=number) break; } diff --git a/libs/ui.js b/libs/ui.js index fce7961b..0acdb8dd 100644 --- a/libs/ui.js +++ b/libs/ui.js @@ -1443,6 +1443,43 @@ ui.prototype.drawBookDetail = function (index) { if (hints.length==0) hints.push("该怪物无特殊属性。"); + // 模仿临界计算器 + if (core.enemys.hasSpecial(core.material.enemys[enemyId].special, 10)) { + var hp = core.material.enemys[enemyId].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", - "pickaxe": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1\n\t\t&& (block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) // 能破哪些墙\n\t{\n\t\t// 四个方向\n\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\tids.push(i);\n\t\telse id2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", + "pickaxe": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1 && \n\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id=='whiteWall' || block.event.id=='blueWall')) { // 能破哪些墙\n\t\t// 四个方向\n\t\tif (core.flags.pickaxeFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\tids.push(i);\n\t\telse id2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", "icePickaxe": "var able=false;\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.x==core.nextX() && block.y==core.nextY() && block.event.id=='ice') {\n\t\tcore.status.event.data = [i];\n\t\table=true;\n\t}\n}\nable", - "bomb": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "hammer": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && \n\t\tMath.abs(block.x-core.status.hero.loc.x)+Math.abs(block.y-core.status.hero.loc.y)<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "earthquake": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !block.disable && (block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) // 能炸的墙壁\n ids.push(i);\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", + "bomb": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.getHeroLoc('x'))+Math.abs(block.y-core.getHeroLoc('y'))<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (core.flags.bombFourDirections || (block.x==core.nextX() && block.y==core.nextY()))\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", + "hammer": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.cls.indexOf('enemy')==0 && Math.abs(block.x-core.getHeroLoc('x'))+Math.abs(block.y-core.getHeroLoc('y'))<=1) {\n\t\tvar enemy = core.material.enemys[block.event.id];\n\t\tif (core.isset(enemy) && enemy.notBomb) continue;\n\t\tif (block.x==core.nextX() && block.y==core.nextY())\n\t\t\tids.push(i);\n\t\telse\n\t\t\tid2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", + "earthquake": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable &&\n\t\t(block.event.canBreak || block.event.id == 'yellowWall' || block.event.id == 'blueWall' || block.event.id == 'whiteWall')) { // 能炸的墙壁\n\t\tids.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nable", "centerFly": "var toX = (core.bigmap.width||13)-1-core.getHeroLoc('x'), toY = (core.bigmap.height||13)-1-core.getHeroLoc('y');\ncore.getBlockId(toX, toY) == null", "upFly": "var able=false;\nvar floorId = core.status.floorId, index = core.floorIds.indexOf(floorId);\nif (index=0 && toX=0 && toY0) {\n\tvar toId = core.floorIds[index-1], toX = core.getHeroLoc('x'), toY = core.getHeroLoc('y');\n\tvar mw = core.floors[toId].width||13, mh = core.floors[toId].height||13;\n\tif (toX>=0 && toX=0 && toY0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", - "bigKey": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n var block = core.status.thisMap.blocks[i];\n if (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n ids.push(i);\n }\n}\nif (ids.length>0) {\n core.status.event.data = ids;\n able=true;\n}\nable", + "snow": "var able=false;\nvar ids = [], id2s = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.id == 'lava' && Math.abs(block.x-core.getHeroLoc('x'))+Math.abs(block.y-core.getHeroLoc('y'))<=1) {\n\t\tif (core.flags.snowFourDirections || (block.x == core.nextX() && block.y == core.nextY()))\n\t\t\tids.push(i);\n\t\telse id2s.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nelse if (id2s.length==1) {\n\tcore.status.event.data = id2s;\n\table=true;\n}\nable", + "bigKey": "var able=false;\nvar ids = [];\nfor (var i in core.status.thisMap.blocks) {\n\tvar block = core.status.thisMap.blocks[i];\n\tif (core.isset(block.event) && !block.disable && block.event.id == 'yellowDoor') {\n\t\tids.push(i);\n\t}\n}\nif (ids.length>0) {\n\tcore.status.event.data = ids;\n\table=true;\n}\nable", "poisonWine": "core.hasFlag('poison')", "weakWine": "core.hasFlag('weak')", "curseWine": "core.hasFlag('curse')", diff --git a/project/maps.js b/project/maps.js index 7f6ca1f4..5823d190 100644 --- a/project/maps.js +++ b/project/maps.js @@ -3,9 +3,9 @@ maps_90f36752_8815_4be8_b32b_d7fad1d0542e = ////////////////////////// 地形部分 ////////////////////////// // 0-20 地形 - '1':{'cls': 'terrains', 'id': 'yellowWall'}, // 黄墙 - '2':{'cls': 'terrains', 'id': 'whiteWall'}, // 白墙 - '3':{'cls': 'terrains', 'id': 'blueWall'}, // 蓝墙 + '1':{'cls': 'terrains', 'id': 'yellowWall', 'canBreak': true}, // 黄墙 + '2':{'cls': 'terrains', 'id': 'whiteWall', 'canBreak': true}, // 白墙 + '3':{'cls': 'terrains', 'id': 'blueWall', 'canBreak': true}, // 蓝墙 '4':{'cls': 'animates', 'id': 'star', 'noPass': true}, // 星空 '5':{'cls': 'animates', 'id': 'lava', 'noPass': true}, // 岩浆 '6':{'cls': 'terrains', 'id': 'ice'}, // 冰面