diff --git a/public/libs/actions.js b/public/libs/actions.js index 9e88113..0fbf59b 100644 --- a/public/libs/actions.js +++ b/public/libs/actions.js @@ -1,3 +1,5 @@ +/// + /* actions.js:用户交互的事件的处理 键盘、鼠标、触摸屏事件相关 diff --git a/public/libs/control.js b/public/libs/control.js index 68a7ab3..b33bf7d 100644 --- a/public/libs/control.js +++ b/public/libs/control.js @@ -1,3 +1,5 @@ +/// + /* control.js:游戏主要逻辑控制 主要负责status相关内容,以及各种变量获取/存储 diff --git a/public/libs/core.js b/public/libs/core.js index 55d0bd2..60b00e6 100644 --- a/public/libs/core.js +++ b/public/libs/core.js @@ -1,16 +1,17 @@ +/// /** * 初始化 start */ -"use strict"; +'use strict'; // /** // * @type {CoreMixin} // */ // const core = (() => { -function core () { +function core() { this._WIDTH_ = 15; this._HEIGHT_ = 15; this._PX_ = this._WIDTH_ * 32; @@ -22,99 +23,99 @@ function core () { this.__PIXELS__ = this.__SIZE__ * 32; this.__HALF_SIZE__ = Math.floor(this.__SIZE__ / 2); this.material = { - 'animates': {}, - 'images': {}, - 'bgms': {}, - 'sounds': {}, - 'items': {}, - 'enemys': {}, - 'icons': {}, - 'ground': null, - 'grundCanvas': null, - 'groundPattern': null, - 'autotileEdges': {}, - } + animates: {}, + images: {}, + bgms: {}, + sounds: {}, + items: {}, + enemys: {}, + icons: {}, + ground: null, + grundCanvas: null, + groundPattern: null, + autotileEdges: {} + }; this.timeout = { - 'turnHeroTimeout': null, - 'onDownTimeout': null, - 'sleepTimeout': null, - } + turnHeroTimeout: null, + onDownTimeout: null, + sleepTimeout: null + }; this.interval = { - 'heroMoveInterval': null, - 'onDownInterval': null, - } + heroMoveInterval: null, + onDownInterval: null + }; this.animateFrame = { - 'totalTime': 0, - 'totalTimeStart': 0, - 'globalAnimate': false, - 'globalTime': 0, - 'selectorTime': 0, - 'selectorUp': true, - 'animateTime': 0, - 'moveTime': 0, - 'lastLegTime': 0, - 'leftLeg': true, - 'weather': { - 'time': 0, - 'type': null, - 'level': 1, - 'nodes': [], - 'data': null, - 'fog': null, - 'cloud': null, - 'sun': null + totalTime: 0, + totalTimeStart: 0, + globalAnimate: false, + globalTime: 0, + selectorTime: 0, + selectorUp: true, + animateTime: 0, + moveTime: 0, + lastLegTime: 0, + leftLeg: true, + weather: { + time: 0, + type: null, + level: 1, + nodes: [], + data: null, + fog: null, + cloud: null, + sun: null }, - "tip": null, - "asyncId": {}, - "lastAsyncId": null - } + tip: null, + asyncId: {}, + lastAsyncId: null + }; this.musicStatus = { - 'audioContext': null, // WebAudioContext - 'bgmStatus': false, // 是否播放BGM - 'soundStatus': true, // 是否播放SE - 'playingBgm': null, // 正在播放的BGM - 'pauseTime': 0, // 上次暂停的时间 - 'lastBgm': null, // 上次播放的bgm - 'gainNode': null, - 'playingSounds': {}, // 正在播放的SE - 'userVolume': 1.0, // 用户音量 - 'designVolume': 1.0, //设计音量 - 'bgmSpeed': 100, // 背景音乐速度 - 'bgmUsePitch': null, // 是否同时修改音调 - 'cachedBgms': [], // 缓存BGM内容 - 'cachedBgmCount': 8, // 缓存的bgm数量 - } + audioContext: null, // WebAudioContext + bgmStatus: false, // 是否播放BGM + soundStatus: true, // 是否播放SE + playingBgm: null, // 正在播放的BGM + pauseTime: 0, // 上次暂停的时间 + lastBgm: null, // 上次播放的bgm + gainNode: null, + playingSounds: {}, // 正在播放的SE + userVolume: 1.0, // 用户音量 + designVolume: 1.0, //设计音量 + bgmSpeed: 100, // 背景音乐速度 + bgmUsePitch: null, // 是否同时修改音调 + cachedBgms: [], // 缓存BGM内容 + cachedBgmCount: 8 // 缓存的bgm数量 + }; this.platform = { - 'isOnline': true, // 是否http - 'isPC': true, // 是否是PC - 'isAndroid': false, // 是否是Android - 'isIOS': false, // 是否是iOS - 'string': 'PC', - 'isWeChat': false, // 是否是微信 - 'isQQ': false, // 是否是QQ - 'isChrome': false, // 是否是Chrome - 'supportCopy': false, // 是否支持复制到剪切板 + isOnline: true, // 是否http + isPC: true, // 是否是PC + isAndroid: false, // 是否是Android + isIOS: false, // 是否是iOS + string: 'PC', + isWeChat: false, // 是否是微信 + isQQ: false, // 是否是QQ + isChrome: false, // 是否是Chrome + supportCopy: false, // 是否支持复制到剪切板 - 'fileInput': null, // FileInput - 'fileReader': null, // 是否支持FileReader - 'successCallback': null, // 读取成功 - 'errorCallback': null, // 读取失败 - } + fileInput: null, // FileInput + fileReader: null, // 是否支持FileReader + successCallback: null, // 读取成功 + errorCallback: null // 读取失败 + }; // 样式 this.domStyle = { scale: 1.0, ratio: 1.0, - hdCanvas: ["damage", "ui", "data"], + hdCanvas: ['damage', 'ui', 'data'], availableScale: [], isVertical: false, showStatusBar: true, - toolbarBtn: false, - } + toolbarBtn: false + }; this.bigmap = { - canvas: ["bg", "event", "event2", "fg", "damage"], + canvas: ['bg', 'event', 'event2', 'fg', 'damage'], offsetX: 0, // in pixel offsetY: 0, - posX: 0, // + posX: 0, // posY: 0, width: main.mode == 'editor' ? this.__SIZE__ : this._WIDTH_, // map width and height height: main.mode == 'editor' ? this.__SIZE__ : this._HEIGHT_, @@ -123,140 +124,149 @@ function core () { extend: 10, scale: 1.0, tempCanvas: null, // A temp canvas for drawing - cacheCanvas: null, // A cache canvas - } + cacheCanvas: null // A cache canvas + }; this.saves = { - "saveIndex": null, - "ids": {}, - "autosave": { - "data": null, - "time": 0, - "updated": false, - "storage": true, // 是否把自动存档写入文件a - "max": 20, // 自动存档最大回退数 - "now": 0, + saveIndex: null, + ids: {}, + autosave: { + data: null, + time: 0, + updated: false, + storage: true, // 是否把自动存档写入文件a + max: 20, // 自动存档最大回退数 + now: 0 }, - "favorite": [], - "favoriteName": {}, - "cache": {} - } + favorite: [], + favoriteName: {}, + cache: {} + }; this.initStatus = { - 'played': false, - 'gameOver': false, + played: false, + gameOver: false, // 勇士属性 - 'hero': {}, - 'heroCenter': { 'px': null, 'py': null }, + hero: {}, + heroCenter: { px: null, py: null }, // 当前地图 - 'floorId': null, - 'thisMap': null, - 'maps': null, - 'bgmaps': {}, - 'fgmaps': {}, - 'mapBlockObjs': {}, - 'checkBlock': {}, // 每个点的阻激夹域信息 - 'damage': { // 每个点的显伤绘制 - 'posX': 0, - 'posY': 0, - 'data': [], - 'extraData': [], + floorId: null, + thisMap: null, + maps: null, + bgmaps: {}, + fgmaps: {}, + mapBlockObjs: {}, + checkBlock: {}, // 每个点的阻激夹域信息 + damage: { + // 每个点的显伤绘制 + posX: 0, + posY: 0, + data: [], + extraData: [] }, - 'lockControl': false, + lockControl: false, // 勇士移动状态 - 'heroMoving': 0, - 'heroStop': true, + heroMoving: 0, + heroStop: true, // 自动寻路相关 - 'automaticRoute': { - 'autoHeroMove': false, - 'autoStep': 0, - 'movedStep': 0, - 'destStep': 0, - 'destX': null, - 'destY': null, - 'offsetX': null, - 'offsetY': null, - 'autoStepRoutes': [], - 'moveStepBeforeStop': [], - 'lastDirection': null, - 'cursorX': 0, - 'cursorY': 0, - "moveDirectly": false, + automaticRoute: { + autoHeroMove: false, + autoStep: 0, + movedStep: 0, + destStep: 0, + destX: null, + destY: null, + offsetX: null, + offsetY: null, + autoStepRoutes: [], + moveStepBeforeStop: [], + lastDirection: null, + cursorX: 0, + cursorY: 0, + moveDirectly: false }, // 按下键的时间:为了判定双击 - 'downTime': null, - 'ctrlDown': false, - 'preview': { - 'enabled': false, - 'prepareDragging': false, - 'dragging': false, - 'px': 0, - 'py': 0, + downTime: null, + ctrlDown: false, + preview: { + enabled: false, + prepareDragging: false, + dragging: false, + px: 0, + py: 0 }, // 路线&回放 - 'route': [], - 'replay': { - 'replaying': false, - 'pausing': false, - 'animate': false, // 正在某段动画中 - 'failed': false, - 'toReplay': [], - 'totalList': [], - 'speed': 1.0, - 'steps': 0, - 'save': [], + route: [], + replay: { + replaying: false, + pausing: false, + animate: false, // 正在某段动画中 + failed: false, + toReplay: [], + totalList: [], + speed: 1.0, + steps: 0, + save: [] }, // 录像折叠 - 'routeFolding': {}, + routeFolding: {}, // event事件 - 'shops': {}, - 'event': { - 'id': null, - 'data': null, - 'selection': null, - 'ui': null, - 'interval': null, + shops: {}, + event: { + id: null, + data: null, + selection: null, + ui: null, + interval: null }, - 'autoEvents': [], - 'textAttribute': { - 'position': "center", - "offset": 0, - "title": [255, 215, 0, 1], - "background": [0, 0, 0, 0.85], - "text": [255, 255, 255, 1], - "titlefont": 22, - "textfont": 16, - "bold": false, - "time": 0, - "letterSpacing": 0, - "animateTime": 0, + autoEvents: [], + textAttribute: { + position: 'center', + offset: 0, + title: [255, 215, 0, 1], + background: [0, 0, 0, 0.85], + text: [255, 255, 255, 1], + titlefont: 22, + textfont: 16, + bold: false, + time: 0, + letterSpacing: 0, + animateTime: 0 }, - "globalAttribute": { - 'equipName': main.equipName || [], - "statusLeftBackground": main.styles.statusLeftBackground || "url(project/materials/ground.png) repeat", - "statusTopBackground": main.styles.statusTopBackground || "url(project/materials/ground.png) repeat", - "toolsBackground": main.styles.toolsBackground || "url(project/materials/ground.png) repeat", - "borderColor": main.styles.borderColor || [204, 204, 204, 1], - "statusBarColor": main.styles.statusBarColor || [255, 255, 255, 1], - "floorChangingStyle": main.styles.floorChangingStyle || "background-color: black; color: white", - "selectColor": main.styles.selectColor || [255, 215, 0, 1], - "font": main.styles.font || "Verdana" + globalAttribute: { + equipName: main.equipName || [], + statusLeftBackground: + main.styles.statusLeftBackground || + 'url(project/materials/ground.png) repeat', + statusTopBackground: + main.styles.statusTopBackground || + 'url(project/materials/ground.png) repeat', + toolsBackground: + main.styles.toolsBackground || + 'url(project/materials/ground.png) repeat', + borderColor: main.styles.borderColor || [204, 204, 204, 1], + statusBarColor: main.styles.statusBarColor || [255, 255, 255, 1], + floorChangingStyle: + main.styles.floorChangingStyle || + 'background-color: black; color: white', + selectColor: main.styles.selectColor || [255, 215, 0, 1], + font: main.styles.font || 'Verdana' }, - 'curtainColor': null, + curtainColor: null, // 动画 - 'globalAnimateObjs': [], - 'floorAnimateObjs': [], - 'boxAnimateObjs': [], - 'autotileAnimateObjs': [], - "globalAnimateStatus": 0, - 'animateObjs': [], + globalAnimateObjs: [], + floorAnimateObjs: [], + boxAnimateObjs: [], + autotileAnimateObjs: [], + globalAnimateStatus: 0, + animateObjs: [] }; // 标记的楼层列表,用于数据统计 this.markedFloorIds = {}; @@ -265,7 +275,10 @@ function core () { if (main.mode == 'editor') { document.documentElement.style.setProperty('--size', this.__SIZE__); - document.documentElement.style.setProperty('--pixel', this.__PIXELS__ + 'px'); + document.documentElement.style.setProperty( + '--pixel', + this.__PIXELS__ + 'px' + ); } } @@ -274,8 +287,7 @@ function core () { ////// 初始化 ////// core.prototype.init = function (coreData, callback) { this._forwardFuncs(); - for (var key in coreData) - core[key] = coreData[key]; + for (var key in coreData) core[key] = coreData[key]; this._init_flags(); this._init_platform(); this._init_others(); @@ -284,10 +296,14 @@ core.prototype.init = function (coreData, callback) { // 初始化画布 for (var name in core.canvas) { if (core.domStyle.hdCanvas.indexOf(name) >= 0) - core.maps._setHDCanvasSize(core.canvas[name], b ? core.__PIXELS__ : core._PX_, b ? core.__PIXELS__ : core._PY_); + core.maps._setHDCanvasSize( + core.canvas[name], + b ? core.__PIXELS__ : core._PX_, + b ? core.__PIXELS__ : core._PY_ + ); else { - core.canvas[name].canvas.width = (b ? core.__PIXELS__ : core._PX_); - core.canvas[name].canvas.height = (b ? core.__PIXELS__ : core._PY_); + core.canvas[name].canvas.width = b ? core.__PIXELS__ : core._PX_; + core.canvas[name].canvas.height = b ? core.__PIXELS__ : core._PY_; } } @@ -298,7 +314,7 @@ core.prototype.init = function (coreData, callback) { }); core.dom.musicBtn.style.display = 'block'; core.setMusicBtn(); -} +}; core.prototype._init_flags = function () { core.flags = core.clone(core.data.flags); @@ -314,9 +330,11 @@ core.prototype._init_flags = function () { core.dom.versionLabel.innerText = core.firstData.version; core.dom.logoLabel.innerText = core.firstData.title; - document.title = core.firstData.title + " - HTML5魔塔"; - document.getElementById("startLogo").innerText = core.firstData.title; - (core.firstData.shops || []).forEach(function (t) { core.initStatus.shops[t.id] = t; }); + document.title = core.firstData.title + ' - HTML5魔塔'; + document.getElementById('startLogo').innerText = core.firstData.title; + (core.firstData.shops || []).forEach(function (t) { + core.initStatus.shops[t.id] = t; + }); core.maps._initFloors(); // 初始化怪物、道具等 @@ -328,7 +346,9 @@ core.prototype._init_flags = function () { for (var floorId in core.floors) { var autoEvents = core.floors[floorId].autoEvent || {}; for (var loc in autoEvents) { - var locs = loc.split(","), x = parseInt(locs[0]), y = parseInt(locs[1]); + var locs = loc.split(','), + x = parseInt(locs[0]), + y = parseInt(locs[1]); for (var index in autoEvents[loc]) { var autoEvent = core.clone(autoEvents[loc][index]); if (autoEvent && autoEvent.condition && autoEvent.data) { @@ -336,8 +356,11 @@ core.prototype._init_flags = function () { autoEvent.x = x; autoEvent.y = y; autoEvent.index = index; - autoEvent.symbol = floorId + "@" + x + "@" + y + "@" + index; - autoEvent.condition = core.replaceValue(autoEvent.condition); + autoEvent.symbol = + floorId + '@' + x + '@' + y + '@' + index; + autoEvent.condition = core.replaceValue( + autoEvent.condition + ); autoEvent.data = core.precompile(autoEvent.data); core.initStatus.autoEvents.push(autoEvent); } @@ -351,18 +374,44 @@ core.prototype._init_flags = function () { if (!equip.equip.equipEvent && !equip.equip.unequipEvent) continue; var equipFlag = '_equipEvent_' + equipId; var autoEvent1 = { - symbol: "_equipEvent_" + equipId, + symbol: '_equipEvent_' + equipId, currentFloor: false, multiExecute: true, - condition: "core.hasEquip('" + equipId + "') && !core.hasFlag('" + equipFlag + "')", - data: core.precompile([{ "type": "setValue", "name": "flag:" + equipFlag, "value": "true" }].concat(equip.equip.equipEvent || [])), + condition: + "core.hasEquip('" + + equipId + + "') && !core.hasFlag('" + + equipFlag + + "')", + data: core.precompile( + [ + { + type: 'setValue', + name: 'flag:' + equipFlag, + value: 'true' + } + ].concat(equip.equip.equipEvent || []) + ) }; var autoEvent2 = { - symbol: "_unequipEvent_" + equipId, + symbol: '_unequipEvent_' + equipId, currentFloor: false, multiExecute: true, - condition: "!core.hasEquip('" + equipId + "') && core.hasFlag('" + equipFlag + "')", - data: core.precompile([{ "type": "setValue", "name": "flag:" + equipFlag, "value": "null" }].concat(equip.equip.unequipEvent || [])), + condition: + "!core.hasEquip('" + + equipId + + "') && core.hasFlag('" + + equipFlag + + "')", + data: core.precompile( + [ + { + type: 'setValue', + name: 'flag:' + equipFlag, + value: 'null' + } + ].concat(equip.equip.unequipEvent || []) + ) }; core.initStatus.autoEvents.push(autoEvent1); core.initStatus.autoEvents.push(autoEvent2); @@ -372,33 +421,53 @@ core.prototype._init_flags = function () { if (e1.floorId == null) return 1; if (e2.floorId == null) return -1; if (e1.priority != e2.priority) return e2.priority - e1.priority; - if (e1.floorId != e2.floorId) return core.floorIds.indexOf(e1.floorId) - core.floorIds.indexOf(e2.floorId); + if (e1.floorId != e2.floorId) + return ( + core.floorIds.indexOf(e1.floorId) - + core.floorIds.indexOf(e2.floorId) + ); if (e1.x != e2.x) return e1.x - e2.x; if (e1.y != e2.y) return e1.y - e2.y; return e1.index - e2.index; - }) - -} + }); +}; core.prototype._init_sys_flags = function () { if (core.flags.equipboxButton) core.flags.equipment = true; core.flags.displayEnemyDamage = core.getLocalStorage('enemyDamage', true); core.flags.displayCritical = core.getLocalStorage('critical', true); core.flags.displayExtraDamage = core.getLocalStorage('extraDamage', true); - core.flags.enableEnemyPoint = core.getLocalStorage('enableEnemyPoint', core.flags.enableEnemyPoint); + core.flags.enableEnemyPoint = core.getLocalStorage( + 'enableEnemyPoint', + core.flags.enableEnemyPoint + ); core.flags.leftHandPrefer = core.getLocalStorage('leftHandPrefer', false); core.flags.extraDamageType = core.getLocalStorage('extraDamageType', 2); // 行走速度 - core.values.moveSpeed = core.getLocalStorage('moveSpeed', core.values.moveSpeed || 100); - core.values.floorChangeTime = core.getLocalStorage('floorChangeTime', core.values.floorChangeTime); + core.values.moveSpeed = core.getLocalStorage( + 'moveSpeed', + core.values.moveSpeed || 100 + ); + core.values.floorChangeTime = core.getLocalStorage( + 'floorChangeTime', + core.values.floorChangeTime + ); if (core.values.floorChangeTime == null) core.values.floorChangeTime = 500; - core.flags.enableHDCanvas = core.getLocalStorage('enableHDCanvas', !core.platform.isIOS); -} + core.flags.enableHDCanvas = core.getLocalStorage( + 'enableHDCanvas', + !core.platform.isIOS + ); +}; core.prototype._init_platform = function () { - core.platform.isOnline = location.protocol.indexOf("http") == 0; - if (!core.platform.isOnline) alert("请勿直接打开html文件!使用启动服务或者APP进行离线游戏。"); - window.AudioContext = window.AudioContext || window.webkitAudioContext || window.mozAudioContext || window.msAudioContext; + core.platform.isOnline = location.protocol.indexOf('http') == 0; + if (!core.platform.isOnline) + alert('请勿直接打开html文件!使用启动服务或者APP进行离线游戏。'); + window.AudioContext = + window.AudioContext || + window.webkitAudioContext || + window.mozAudioContext || + window.msAudioContext; core.musicStatus.bgmStatus = core.getLocalStorage('bgmStatus', true); core.musicStatus.soundStatus = core.getLocalStorage('soundStatus', true); //新增 userVolume 默认值0.7 @@ -407,23 +476,38 @@ core.prototype._init_platform = function () { core.musicStatus.audioContext = new window.AudioContext(); core.musicStatus.gainNode = core.musicStatus.audioContext.createGain(); core.musicStatus.gainNode.gain.value = core.musicStatus.userVolume; - core.musicStatus.gainNode.connect(core.musicStatus.audioContext.destination); + core.musicStatus.gainNode.connect( + core.musicStatus.audioContext.destination + ); } catch (e) { - console.log("该浏览器不支持AudioContext"); + console.log('该浏览器不支持AudioContext'); core.musicStatus.audioContext = null; } - ["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; + ['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; + } } - }); - core.platform.string = core.platform.isPC ? "PC" : core.platform.isAndroid ? "Android" : core.platform.isIOS ? "iOS" : ""; - core.platform.supportCopy = document.queryCommandSupported && document.queryCommandSupported("copy"); + ); + 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; - core.platform.isSafari = /Safari/i.test(navigator.userAgent) && !/Chrome/i.test(navigator.userAgent); + 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); if (window.FileReader) { @@ -432,33 +516,55 @@ core.prototype._init_platform = function () { core.readFileContent(core.platform.fileReader.result); }; core.platform.fileReader.onerror = function () { - if (core.platform.errorCallback) - core.platform.errorCallback(); - } + if (core.platform.errorCallback) core.platform.errorCallback(); + }; } - core.flags.enableHDCanvas = core.getLocalStorage('enableHDCanvas', !core.platform.isIOS); + core.flags.enableHDCanvas = core.getLocalStorage( + 'enableHDCanvas', + !core.platform.isIOS + ); if (main.mode != 'editor') { core.domStyle.scale = core.getLocalStorage('scale', 1); - if (core.flags.enableHDCanvas) core.domStyle.ratio = Math.max(window.devicePixelRatio || 1, core.domStyle.scale); + if (core.flags.enableHDCanvas) + core.domStyle.ratio = Math.max( + window.devicePixelRatio || 1, + core.domStyle.scale + ); } -} +}; 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.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.bigmap.tempCanvas = document.createElement('canvas').getContext('2d'); core.bigmap.cacheCanvas = document.createElement('canvas').getContext('2d'); - core.loadImage("materials", 'fog', function (name, img) { core.animateFrame.weather.fog = img; }); - core.loadImage("materials", "cloud", function (name, img) { core.animateFrame.weather.cloud = img; }) - core.loadImage("materials", "sun", function (name, img) { core.animateFrame.weather.sun = img; }) - core.loadImage("materials", 'keyboard', function (name, img) { core.material.images.keyboard = img; }); + core.loadImage('materials', 'fog', function (name, img) { + core.animateFrame.weather.fog = img; + }); + core.loadImage('materials', 'cloud', function (name, img) { + core.animateFrame.weather.cloud = img; + }); + core.loadImage('materials', 'sun', function (name, img) { + core.animateFrame.weather.sun = img; + }); + core.loadImage('materials', '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.prototype._afterLoadResources = function (callback) { // 初始化地图 @@ -475,35 +581,43 @@ core.prototype._afterLoadResources = function (callback) { console.warn('无法裁剪非png格式图片:' + name); return; } - var arr = core.splitImage(core.material.images.images[name], one.width, one.height); + var arr = core.splitImage( + core.material.images.images[name], + one.width, + one.height + ); for (var i = 0; i < arr.length; ++i) { - core.material.images.images[(one.prefix || "") + i + '.png'] = arr[i]; + core.material.images.images[(one.prefix || '') + i + '.png'] = + arr[i]; } }); - if (core.plugin._afterLoadResources) - core.plugin._afterLoadResources(); + if (core.plugin._afterLoadResources) core.plugin._afterLoadResources(); core.showStartAnimate(); if (callback) callback(); -} +}; core.prototype._init_plugins = function () { - core.plugin = new function () { }; + core.plugin = new (function () {})(); for (var name in plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1) { - if (plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name] instanceof Function) { + if ( + plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name] instanceof + Function + ) { try { - plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name].apply(core.plugin); - } - catch (e) { + plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1[name].apply( + core.plugin + ); + } catch (e) { console.error(e); - console.error("无法初始化插件" + name); + console.error('无法初始化插件' + name); } } } - core._forwardFunc("plugin"); -} + core._forwardFunc('plugin'); +}; core.prototype._forwardFuncs = function () { for (var i = 0; i < main.loadList.length; ++i) { @@ -511,12 +625,15 @@ core.prototype._forwardFuncs = function () { if (name == 'core') continue; 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) { + if ( + funcname.charAt(0) != '_' && + core[name][funcname] instanceof Function + ) { this._forwardFunc(name, funcname); } } @@ -524,14 +641,36 @@ core.prototype._forwardFunc = function (name, funcname) { } if (core[funcname]) { - console.error("ERROR: 无法转发 " + name + " 中的函数 " + funcname + " 到 core 中!同名函数已存在。"); + 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, ', '); + 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 + ".apply(core." + name + ", arguments);\n}"); -} + eval( + 'core.' + + funcname + + ' = function (' + + parameters + + ') {\n\treturn core.' + + name + + '.' + + funcname + + '.apply(core.' + + name + + ', arguments);\n}' + ); +}; core.prototype.doFunc = function (func, _this) { if (typeof func == 'string') { @@ -539,7 +678,7 @@ core.prototype.doFunc = function (func, _this) { _this = core.plugin; } return func.apply(_this, Array.prototype.slice.call(arguments, 2)); -} +}; // return new Core(); diff --git a/public/libs/data.js b/public/libs/data.js index 8fbc63f..6df0a4c 100644 --- a/public/libs/data.js +++ b/public/libs/data.js @@ -1,7 +1,8 @@ +/// -"use strict"; +'use strict'; -function data () { +function data() { this._init(); } @@ -10,4 +11,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); -} \ No newline at end of file +}; diff --git a/public/libs/enemys.js b/public/libs/enemys.js index 122657a..ba40d73 100644 --- a/public/libs/enemys.js +++ b/public/libs/enemys.js @@ -1,7 +1,8 @@ +/// -"use strict"; +'use strict'; -function enemys () { +function enemys() { this._init(); } @@ -14,10 +15,10 @@ enemys.prototype._init = function () { } if (main.mode == 'play') { this.enemydata.hasSpecial = function (a, b) { - return core.enemys.hasSpecial(a, b) + return core.enemys.hasSpecial(a, b); }; } -} +}; enemys.prototype.getEnemys = function () { var enemys = core.clone(this.enemys); @@ -36,13 +37,20 @@ enemys.prototype.getEnemys = function () { if (downId != null && downId != id && enemys[downId]) { enemys[id] = { id: id }; for (var property in enemys[downId]) { - if (property != 'id' && enemys[downId].hasOwnProperty(property)) { + if ( + property != 'id' && + enemys[downId].hasOwnProperty(property) + ) { (function (id, downId, property) { Object.defineProperty(enemys[id], property, { - get: function () { return enemys[downId][property] }, - set: function (v) { enemys[downId][property] = v }, + get: function () { + return enemys[downId][property]; + }, + set: function (v) { + enemys[downId][property] = v; + }, enumerable: true - }) + }); })(id, downId, property); } } @@ -50,7 +58,7 @@ enemys.prototype.getEnemys = function () { } } return enemys; -} +}; ////// 判断是否含有某特殊属性 ////// enemys.prototype.hasSpecial = function (special, test) { @@ -73,11 +81,11 @@ enemys.prototype.hasSpecial = function (special, test) { } return false; -} +}; enemys.prototype.getSpecials = function () { return this.enemydata.getSpecials(); -} +}; ////// 获得所有特殊属性的名称 ////// enemys.prototype.getSpecialText = function (enemy) { @@ -94,7 +102,7 @@ enemys.prototype.getSpecialText = function (enemy) { } } return text; -} +}; ////// 获得所有特殊属性的颜色 ////// enemys.prototype.getSpecialColor = function (enemy) { @@ -111,8 +119,7 @@ enemys.prototype.getSpecialColor = function (enemy) { } } return colors; - -} +}; ////// 获得所有特殊属性的额外标记 ////// enemys.prototype.getSpecialFlag = function (enemy) { @@ -125,11 +132,11 @@ enemys.prototype.getSpecialFlag = function (enemy) { if (specials) { for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(special, specials[i][0])) - flag |= (specials[i][4] || 0); + flag |= specials[i][4] || 0; } } return flag; -} +}; ////// 获得每个特殊属性的说明 ////// enemys.prototype.getSpecialHint = function (enemy, special) { @@ -140,19 +147,30 @@ enemys.prototype.getSpecialHint = function (enemy, special) { var hints = []; for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(enemy, specials[i][0])) - hints.push("\r[" + core.arrayToRGBA(specials[i][3] || "#FF6A6A") + "]\\d" + this._calSpecialContent(enemy, specials[i][1]) + - ":\\d\r[]" + this._calSpecialContent(enemy, specials[i][2])); + hints.push( + '\r[' + + core.arrayToRGBA(specials[i][3] || '#FF6A6A') + + ']\\d' + + this._calSpecialContent(enemy, specials[i][1]) + + ':\\d\r[]' + + this._calSpecialContent(enemy, specials[i][2]) + ); } return hints; } - if (specials == null) return ""; + if (specials == null) return ''; for (var i = 0; i < specials.length; i++) { if (special == specials[i][0]) - return "\r[#FF6A6A]\\d" + this._calSpecialContent(enemy, specials[i][1]) + ":\\d\r[]" + this._calSpecialContent(enemy, specials[i][2]); + return ( + '\r[#FF6A6A]\\d' + + this._calSpecialContent(enemy, specials[i][1]) + + ':\\d\r[]' + + this._calSpecialContent(enemy, specials[i][2]) + ); } - return ""; -} + return ''; +}; enemys.prototype._calSpecialContent = function (enemy, content) { if (typeof content == 'string') return content; @@ -160,14 +178,18 @@ enemys.prototype._calSpecialContent = function (enemy, content) { if (content instanceof Function) { return content(enemy); } - return ""; -} + return ''; +}; ////// 获得某个点上某个怪物的某项属性 ////// enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) { floorId = floorId || core.status.floorId; - if ((((flags.enemyOnPoint || {})[floorId] || {})[x + "," + y] || {})[name] != null) { - return flags.enemyOnPoint[floorId][x + "," + y][name]; + if ( + (((flags.enemyOnPoint || {})[floorId] || {})[x + ',' + y] || {})[ + name + ] != null + ) { + return flags.enemyOnPoint[floorId][x + ',' + y][name]; } if (enemy == null) { var block = core.getBlock(x, y, floorId); @@ -177,14 +199,14 @@ enemys.prototype.getEnemyValue = function (enemy, name, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (enemy == null) return null; return enemy[name]; -} +}; ////// 能否获胜 ////// enemys.prototype.canBattle = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; var damage = this.getDamage(enemy, x, y, floorId); return damage != null && damage < core.status.hero.hp; -} +}; enemys.prototype.getDamageString = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; @@ -193,40 +215,43 @@ enemys.prototype.getDamageString = function (enemy, x, y, floorId) { var color = '#000000'; if (damage == null) { - damage = "???"; + damage = '???'; color = '#FF2222'; - } - else { + } else { if (damage <= 0) color = '#11FF11'; else if (damage < core.status.hero.hp / 3) color = '#FFFFFF'; - else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00'; + else if (damage < (core.status.hero.hp * 2) / 3) color = '#FFFF00'; else if (damage < core.status.hero.hp) color = '#FF9933'; else color = '#FF2222'; damage = core.formatBigNumber(damage, true); - if (core.enemys.hasSpecial(enemy, 19)) - damage += "+"; - if (core.enemys.hasSpecial(enemy, 21)) - damage += "-"; - if (core.enemys.hasSpecial(enemy, 11)) - damage += "^"; + if (core.enemys.hasSpecial(enemy, 19)) damage += '+'; + if (core.enemys.hasSpecial(enemy, 21)) damage += '-'; + if (core.enemys.hasSpecial(enemy, 11)) damage += '^'; } return { - "damage": damage, - "color": color + damage: damage, + color: color }; -} +}; ////// 接下来N个临界值和临界减伤计算 ////// enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; number = number || 1; - var specialCriticals = this._nextCriticals_special(enemy, number, x, y, floorId); + var specialCriticals = this._nextCriticals_special( + enemy, + number, + x, + y, + floorId + ); if (specialCriticals != null) return specialCriticals; var info = this.getDamageInfo(enemy, null, x, y, floorId); - if (info == null) { // 如果未破防... + if (info == null) { + // 如果未破防... var overAtk = this._nextCriticals_overAtk(enemy, x, y, floorId); if (overAtk == null) return []; if (typeof overAtk[1] == 'number') return [[overAtk[0], -overAtk[1]]]; @@ -242,45 +267,91 @@ enemys.prototype.nextCriticals = function (enemy, number, x, y, floorId) { if (core.flags.useLoop) { if (core.status.hero.atk <= (main.criticalUseLoop || 1)) { - return this._nextCriticals_useLoop(enemy, info, number, x, y, floorId); + 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_useBinarySearch(enemy, info, number, x, y, floorId); - } - } - else { + } else { return this._nextCriticals_useTurn(enemy, info, number, x, y, floorId); } -} +}; /// 未破防临界采用二分计算 enemys.prototype._nextCriticals_overAtk = function (enemy, x, y, floorId) { var calNext = function (currAtk, maxAtk) { - var start = currAtk, end = maxAtk; + var start = currAtk, + end = maxAtk; if (start > end) return null; while (start < end) { var mid = Math.floor((start + end) / 2); if (mid - start > end - mid) mid--; - var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": mid }, x, y, floorId); + var nextInfo = core.enemys.getDamageInfo( + enemy, + { atk: mid }, + x, + y, + floorId + ); if (nextInfo != null) end = mid; else start = mid + 1; } - var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": start }, x, y, floorId); - return nextInfo == null ? null : [start - core.status.hero.atk, nextInfo]; - } - return calNext(core.status.hero.atk + 1, - core.getEnemyValue(enemy, 'hp', x, y, floorId) + core.getEnemyValue(enemy, 'def', x, y, floorId)); -} + var nextInfo = core.enemys.getDamageInfo( + enemy, + { atk: start }, + x, + y, + floorId + ); + return nextInfo == null + ? null + : [start - core.status.hero.atk, nextInfo]; + }; + return calNext( + core.status.hero.atk + 1, + core.getEnemyValue(enemy, 'hp', x, y, floorId) + + core.getEnemyValue(enemy, 'def', x, y, floorId) + ); +}; -enemys.prototype._nextCriticals_special = function (enemy, number, x, y, floorId) { +enemys.prototype._nextCriticals_special = function ( + enemy, + number, + x, + y, + floorId +) { if (this.hasSpecial(enemy.special, 10) || this.hasSpecial(enemy.special, 3)) return []; // 模仿or坚固临界 return null; -} +}; -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; +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 = []; var start_atk = hero_atk; if (info.__over__) { @@ -288,8 +359,8 @@ enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, f list.push([info.__overAtk__, -info.damage]); } for (var atk = start_atk + 1; atk <= mon_hp + mon_def; atk++) { - var nextInfo = this.getDamageInfo(enemy, { "atk": atk }, x, y, floorId); - if (nextInfo == null || (typeof nextInfo == 'number')) break; + var nextInfo = this.getDamageInfo(enemy, { atk: atk }, x, y, floorId); + if (nextInfo == null || typeof nextInfo == 'number') break; if (pre > nextInfo.damage) { pre = nextInfo.damage; list.push([atk - hero_atk, info.damage - nextInfo.damage]); @@ -299,10 +370,20 @@ enemys.prototype._nextCriticals_useLoop = function (enemy, info, number, x, y, f } if (list.length == 0) list.push([0, 0]); return list; -} +}; -enemys.prototype._nextCriticals_useBinarySearch = 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; +enemys.prototype._nextCriticals_useBinarySearch = 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 = []; var start_atk = hero_atk; if (info.__over__) { @@ -310,20 +391,37 @@ enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, list.push([info.__overAtk__, -info.damage]); } var calNext = function (currAtk, maxAtk) { - var start = Math.floor(currAtk), end = Math.floor(maxAtk); + var start = Math.floor(currAtk), + end = Math.floor(maxAtk); if (start > end) return null; while (start < end) { var mid = Math.floor((start + end) / 2); if (mid - start > end - mid) mid--; - var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": mid }, x, y, floorId); - if (nextInfo == null || (typeof nextInfo == 'number')) return null; + var nextInfo = core.enemys.getDamageInfo( + enemy, + { atk: mid }, + x, + y, + floorId + ); + if (nextInfo == null || typeof nextInfo == 'number') return null; 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]; - } + var nextInfo = core.enemys.getDamageInfo( + enemy, + { atk: start }, + x, + y, + floorId + ); + return nextInfo == null || + typeof nextInfo == 'number' || + nextInfo.damage >= pre + ? null + : [start, nextInfo.damage]; + }; var currAtk = start_atk; while (true) { var next = calNext(currAtk + 1, mon_hp + mon_def, pre); @@ -336,16 +434,35 @@ enemys.prototype._nextCriticals_useBinarySearch = function (enemy, info, number, } 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; +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; // ------ 超大回合数强制使用二分算临界 // 以避免1攻10e回合,2攻5e回合导致下述循环卡死问题 - if (turn >= 1e6) { // 100w回合以上强制二分计算临界 - return this._nextCriticals_useBinarySearch(enemy, info, number, x, y, floorId); + if (turn >= 1e6) { + // 100w回合以上强制二分计算临界 + return this._nextCriticals_useBinarySearch( + enemy, + info, + number, + x, + y, + floorId + ); } - var list = [], pre = null; + var list = [], + pre = null; var start_atk = hero_atk; if (info.__over__) { start_atk += info.__overAtk__; @@ -357,34 +474,48 @@ enemys.prototype._nextCriticals_useTurn = function (enemy, info, number, x, y, f nextAtk = Math.ceil(nextAtk / core.getBuff('atk')); if (nextAtk <= start_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)]); + 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; pre = nextAtk; } - if (list.length >= number) - break; + if (list.length >= number) break; } if (list.length == 0) list.push([0, 0]); return list; -} +}; ////// N防减伤计算 ////// enemys.prototype.getDefDamage = function (enemy, k, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; k = k || 1; var nowDamage = this._getDamage(enemy, null, x, y, floorId); - var nextDamage = this._getDamage(enemy, { "def": core.status.hero.def + k }, x, y, floorId); - if (nowDamage == null || nextDamage == null) return "???"; + var nextDamage = this._getDamage( + enemy, + { def: core.status.hero.def + k }, + x, + y, + floorId + ); + if (nowDamage == null || nextDamage == null) return '???'; return nowDamage - nextDamage; -} +}; enemys.prototype.getEnemyInfo = function (enemy, hero, x, y, floorId) { if (enemy == null) return null; if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; - return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId) -} + return this.enemydata.getEnemyInfo(enemy, hero, x, y, floorId); +}; ////// 获得战斗伤害信息(实际伤害计算函数) ////// enemys.prototype.getDamageInfo = function (enemy, hero, x, y, floorId) { @@ -392,12 +523,12 @@ 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); -} +}; ////// 获得在某个勇士属性下怪物伤害 ////// enemys.prototype.getDamage = function (enemy, x, y, floorId) { return this._getDamage(enemy, null, x, y, floorId); -} +}; enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) { if (enemy == null) enemy = core.getBlockId(x, y, floorId); @@ -408,30 +539,49 @@ enemys.prototype._getDamage = function (enemy, hero, x, y, floorId) { if (info == null) return null; if (typeof info == 'number') return info; return info.damage; -} +}; ////// 获得当前楼层的怪物列表 ////// enemys.prototype.getCurrentEnemys = function (floorId) { floorId = floorId || core.status.floorId; - var enemys = [], used = {}; + var enemys = [], + used = {}; core.extractBlocks(floorId); core.status.maps[floorId].blocks.forEach(function (block) { if (!block.disable && block.event.cls.indexOf('enemy') == 0) { - this._getCurrentEnemys_addEnemy(block.event.id, enemys, used, block.x, block.y, floorId); + this._getCurrentEnemys_addEnemy( + block.event.id, + enemys, + used, + block.x, + block.y, + floorId + ); } }, this); return this._getCurrentEnemys_sort(enemys); -} +}; enemys.prototype._getCurrentEnemys_getEnemy = function (enemyId) { var enemy = core.material.enemys[enemyId]; if (!enemy) return null; // 检查朝向;displayIdInBook - return core.material.enemys[enemy.displayIdInBook] || core.material.enemys[(enemy.faceIds || {}).down] || enemy; -} + return ( + core.material.enemys[enemy.displayIdInBook] || + core.material.enemys[(enemy.faceIds || {}).down] || + enemy + ); +}; -enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, x, y, floorId) { +enemys.prototype._getCurrentEnemys_addEnemy = function ( + enemyId, + enemys, + used, + x, + y, + floorId +) { var enemy = this._getCurrentEnemys_getEnemy(enemyId); if (enemy == null) return; @@ -440,23 +590,32 @@ enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, x var enemyInfo = this.getEnemyInfo(enemy, null, null, null, floorId); var locEnemyInfo = this.getEnemyInfo(enemy, null, x, y, floorId); - if (!core.flags.enableEnemyPoint || - (locEnemyInfo.atk == enemyInfo.atk && locEnemyInfo.def == enemyInfo.def && locEnemyInfo.hp == enemyInfo.hp)) { + if ( + !core.flags.enableEnemyPoint || + (locEnemyInfo.atk == enemyInfo.atk && + locEnemyInfo.def == enemyInfo.def && + locEnemyInfo.hp == enemyInfo.hp) + ) { x = null; y = null; } else { // 检查enemys里面是否使用了存在的内容 for (var i = 0; i < enemys.length; ++i) { var one = enemys[i]; - if (id == one.id && one.locs != null && - locEnemyInfo.atk == one.atk && locEnemyInfo.def == one.def && locEnemyInfo.hp == one.hp) { + if ( + id == one.id && + one.locs != null && + locEnemyInfo.atk == one.atk && + locEnemyInfo.def == one.def && + locEnemyInfo.hp == one.hp + ) { one.locs.push([x, y]); return; } } enemyInfo = locEnemyInfo; } - var id = enemy.id + ":" + x + ":" + y; + var id = enemy.id + ':' + x + ':' + y; if (used[id]) return; used[id] = true; @@ -479,14 +638,24 @@ enemys.prototype._getCurrentEnemys_addEnemy = function (enemyId, enemys, used, x e.damage = this.getDamage(enemy, x, y, floorId); e.critical = critical[0]; e.criticalDamage = critical[1]; - e.defDamage = this._getCurrentEnemys_addEnemy_defDamage(enemy, x, y, floorId); + e.defDamage = this._getCurrentEnemys_addEnemy_defDamage( + enemy, + x, + y, + floorId + ); enemys.push(e); -} +}; -enemys.prototype._getCurrentEnemys_addEnemy_defDamage = function (enemy, x, y, floorId) { +enemys.prototype._getCurrentEnemys_addEnemy_defDamage = function ( + enemy, + x, + y, + floorId +) { var ratio = core.status.maps[floorId || core.status.floorId].ratio || 1; return this.getDefDamage(enemy, ratio, x, y, floorId); -} +}; enemys.prototype._getCurrentEnemys_sort = function (enemys) { return enemys.sort(function (a, b) { @@ -501,23 +670,33 @@ enemys.prototype._getCurrentEnemys_sort = function (enemys) { } return a.damage - b.damage; }); -} +}; enemys.prototype.hasEnemyLeft = function (enemyId, floorId) { if (floorId == null) floorId = core.status.floorId; if (!(floorId instanceof Array)) floorId = [floorId]; var enemyMap = {}; - if (enemyId instanceof Array) enemyId.forEach(function (v) { enemyMap[v] = true; }); + if (enemyId instanceof Array) + enemyId.forEach(function (v) { + enemyMap[v] = true; + }); else if (enemyId) enemyMap[enemyId] = true; else enemyMap = null; for (var i = 0; i < floorId.length; i++) { core.extractBlocks(floorId[i]); var mapBlocks = core.status.maps[floorId[i]].blocks; for (var b = 0; b < mapBlocks.length; b++) { - if (!mapBlocks[b].disable && mapBlocks[b].event.cls.indexOf('enemy') === 0) { - if (enemyMap === null || enemyMap[core.getFaceDownId(mapBlocks[b])]) return true; + if ( + !mapBlocks[b].disable && + mapBlocks[b].event.cls.indexOf('enemy') === 0 + ) { + if ( + enemyMap === null || + enemyMap[core.getFaceDownId(mapBlocks[b])] + ) + return true; } } } return false; -} +}; diff --git a/public/libs/events.js b/public/libs/events.js index 3d367fe..d18ec8a 100644 --- a/public/libs/events.js +++ b/public/libs/events.js @@ -1,3 +1,5 @@ +/// + 'use strict'; function events() { diff --git a/public/libs/extensions.js b/public/libs/extensions.js index 873e70d..a6b2eec 100644 --- a/public/libs/extensions.js +++ b/public/libs/extensions.js @@ -1,22 +1,25 @@ +/// /* extensions.js:负责拓展插件 */ -"use strict"; +'use strict'; -function extensions () { - -} +function extensions() {} extensions.prototype._load = function (callback) { if (main.replayChecking) return callback(); if (!window.fs) { - this._loadJs('_server/fs.js', function () { - core.extensions._listExtensions(callback); - }, callback); + this._loadJs( + '_server/fs.js', + function () { + core.extensions._listExtensions(callback); + }, + callback + ); } else this._listExtensions(callback); -} +}; extensions.prototype._loadJs = function (file, callback, onerror) { var script = document.createElement('script'); @@ -24,7 +27,7 @@ extensions.prototype._loadJs = function (file, callback, onerror) { script.onload = callback; script.onerror = onerror; main.dom.body.appendChild(script); -} +}; extensions.prototype._listExtensions = function (callback) { if (!window.fs) return callback(); @@ -39,13 +42,13 @@ extensions.prototype._listExtensions = function (callback) { list.sort(); core.extensions._loadExtensions(list, callback); }); -} +}; extensions.prototype._loadExtensions = function (list, callback) { var i = 0; var load = function () { if (i == list.length) return callback(); core.extensions._loadJs('extensions/' + list[i++], load, load); - } + }; load(); -} +}; diff --git a/public/libs/icons.js b/public/libs/icons.js index a764e30..d385aed 100644 --- a/public/libs/icons.js +++ b/public/libs/icons.js @@ -1,3 +1,5 @@ +/// + 'use strict'; function icons() { diff --git a/public/libs/items.js b/public/libs/items.js index 6cf36f7..28bc362 100644 --- a/public/libs/items.js +++ b/public/libs/items.js @@ -1,3 +1,5 @@ +/// + 'use strict'; function items() { diff --git a/public/libs/loader.js b/public/libs/loader.js index a2bad38..5081c43 100644 --- a/public/libs/loader.js +++ b/public/libs/loader.js @@ -1,3 +1,5 @@ +/// + /* loader.js:负责对资源的加载 diff --git a/public/libs/maps.js b/public/libs/maps.js index caf0b86..6e34b7d 100644 --- a/public/libs/maps.js +++ b/public/libs/maps.js @@ -1,3 +1,5 @@ +/// + 'use strict'; function maps() { diff --git a/public/libs/ui.js b/public/libs/ui.js index 3ee4947..10bc7c9 100644 --- a/public/libs/ui.js +++ b/public/libs/ui.js @@ -1,3 +1,5 @@ +/// + /** * ui.js:负责所有和UI界面相关的绘制 * 包括: diff --git a/public/libs/utils.js b/public/libs/utils.js index 32d444a..c36e80a 100644 --- a/public/libs/utils.js +++ b/public/libs/utils.js @@ -1,3 +1,5 @@ +/// + /* utils.js 工具类 diff --git a/public/project/plugins.js b/public/project/plugins.js index 96f6aa8..309d1c7 100644 --- a/public/project/plugins.js +++ b/public/project/plugins.js @@ -3,7 +3,9 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { init: function () { this._afterLoadResources = function () { - core.resetSettings(); + if (!main.replayChecking) { + core.resetSettings(); + } }; }, sprite: function () { @@ -1373,1995 +1375,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { return false; }; }, - minimap: function () { - // 该插件可自定义空间很大,自定义内容请看注释 - - // ------------------------- 安装说明 ------------------------- // - // 先安装基于canvas的sprite化插件(2.10.0以上自带) - // 确保自己的编辑器已安装造塔群内的编辑器升级压缩包(在HTML5魔塔样板文件夹内,2.10.1以上样板自带) - // 再将以下代码复制进插件中 - // 提供的api请看以this.xxx = function开头的函数,函数前会有函数说明及参数说明,调用时只需core.plugin.xxx(参数)即可 - - // ------------------------- 使用说明 ------------------------- // - /* - * 直接复制进插件中,然后添加一个快捷键或道具效果为core.plugin.drawFlyMap()即可使用,不需额外设置 - * 楼层id中不要出现下划线 - * 该插件具体功能有: - * 1.绘制区域内的地图 - * 2.可以拖动地图 - * 3.点击地图可直接传送至目标地图,同时降低背景的不透明度,方便观察 - * 4.滚轮或双指可以放缩绘制内容 - * 5.放缩较大时,绘制地图的缩略图,可能会比较卡,但移动不会卡 - * 6.整合漏怪检测,如果想忽略怪物,请在下方改动或用脚本修改core.plugin.ignoreEnemies,类型为数组 - * 7.整合区域显示,所有单独或连在一起的地图会被视为一个区域 - * 8.键盘操作,上下左右移动 - */ - - // ------------------------- 插件说明 ------------------------- // - /* - * 该插件注释极其详细,可以帮助那些想要提升代码力,但实力有不足的作者 - * 注意!!!该插件难度极大,没有代码底力的不建议研究 - * 该插件涉及部分较为高级的算法,如bfs - */ - - // 录像验证直接干掉这个插件 - if (main.replayChecking || main.mode === 'editor') return; - - // ----- 不可自定义 杂七杂八的变量 - /** @type {{[x: string]: BFSResult}} */ - let mapCache = {}; // 地图缓存 - let drawCache = {}; // 绘制信息缓存 - let status = 'none'; // 当前的绘制状态 - /** @type {{[x: string]: Sprite}} */ - let sprites = {}; // 当前所有的sprite - /** @type {{[x: string]: Sprite}} */ - let canDrag = {}; // 可以拖拽的sprite - /** @type {{[x: string]: Button}} */ - let areaSprite = {}; // 区域列表对应的sprite - let clicking = false; // 是否正在点击,用于拖拽判定 - let drawingMap = ''; // 正在绘制的中心楼层 - let nowScale = 0; // 当前绘制的放缩比例 - let lastTouch = {}; // 上一次的单点点击信息 - let lastLength = 0; // 手机端缩放时上一次的两指间距离 - let nowDepth = 0; // 当前的遍历深度 - let drawedThumbnail = {}; // 已经绘制过的缩略图 - let moved = false; // 鼠标按下后是否移动了 - let noBorder = false; // 是否是无边框拼接模式 - let lastScale = 0; // 上一次缩放,用于优化缩略图绘制 - let showEnemy = false; // 是否显示漏怪 - let areaPage = 0; // 区域显示的当前页数 - let nowArea = 0; // 当前区域index - let selecting = ''; // 选择时当前正在选择的地图 - - // ---- 不可自定义,常量 - /** @type {Area} */ - let areas = []; // 区域信息 - const perPage = Math.floor((core._PY_ - 60) / 30); // 区域的每页显示数量 - - // ---- 可自定义,默认的切换地图的图块id - const defaultChange = { - left: 'leftPortal', // 左箭头 - up: 'upPortal', // 上箭头 - right: 'rightPortal', // 右箭头 - down: 'downPortal', // 下箭头 - upFloor: 'upFloor', // 上楼 - downFloor: 'downFloor' // 下楼 - }; - // ---- 可自定义,默认数值 - const defaultValue = { - font: 'Verdana', // 默认字体 - scale: 3, // 默认地图缩放比例 - depth: Infinity // 默认的遍历深度 - }; - - // ---- 不可自定义,计算数据 - const dirData = { - up: [1, 0], - down: [-1, 0], - left: [0, 1], - right: [0, -1], - upFloor: [0, 0], - downFloor: [0, 0] - }; - - let ignoreEnemies = (this.ignoreEnemies = []); - - let allChangeEntries = Object.entries(defaultChange); - - const reset = core.events.resetGame; - core.events.resetGame = function () { - reset.apply(core.events, arguments); - areas = []; - // 获取所有分区,使用异步函数,保证不会卡顿 - // 原理是用bfs扫,将所有连在一起的地图合并成一个区域 - (async function () { - let all = core.floorIds.slice(); - const scanned = { [all[0]]: true }; - while (all.length > 0) { - let now = all.shift(); - if (core.status.maps[now].deleted) continue; - if (!now) return; - await new Promise(res => { - const result = bfsSearch(now, Infinity, true); - mapCache[`${now}_Infinity_false`] = result; - areas.push({ - name: core.floors[now].title, - maps: result.order - }); - for (const map of result.order) { - scanned[map] = true; - all = all.filter(v => !result.order.includes(v)); - } - res('success'); - }); - } - })(); - }; - - /** 工具按钮 */ - class Button extends Sprite { - constructor( - name, - x, - y, - w, - h, - text, - fontSize = '20px', - transition = true - ) { - const btn = super(x, y, w, h, 1050, 'game', name); - this.css(transition); - setTimeout(() => btn.setCss(`opacity: 1;`), 50); - const ctx = btn.context; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - core.fillText( - ctx, - text, - w / 2, - h / 2, - '#fff', - `${fontSize} normal`, - w - 10 - ); - sprites[name] = btn; - } - - css(transition) { - this.setCss( - 'transition: opacity 0.6s linear, transform 0.2s linear;' + - 'background-color: #aaa;' + - 'box-shadow: 0px 0px 0px black;' + - (transition ? 'opacity: 0;' : '') + - 'filter: drop-shadow(1px 1px 2px black);' + - 'box-shadow: 0px 0px 4px black;' + - 'cursor: pointer;' - ); - } - } - - /** 背景 */ - class Back extends Sprite { - constructor(name, x, y, w, h, z, color) { - const sprite = super(x, y, w, h, z, 'game', name); - sprites[name] = sprite; - this.setCss(`transition: all 0.6s linear;`); - setTimeout(() => { - this.setCss(`background-color: ${color};`); - }, 50); - } - } - - /** - * 获取绘制信息 - * @param {string?} center 中心地图id - * @param {number?} depth 搜索深度 - * @param {boolean?} noCache 是否不使用缓存 - * @returns {MapDrawInfo} - */ - this.getMapDrawInfo = function ( - center = core.status.floorId, - depth = defaultValue.depth, - noCache = false - ) { - nowDepth = depth; - drawingMap = center; - const id = `${center}_${depth}_${noBorder}`; - // 检查缓存 - if (drawCache[id] && !noCache) return drawCache[id]; - const map = bfsSearch(center, depth, noCache); - mapCache[id] = map; - const res = getDrawInfo(map.res, center, map.order); - res.upOrDown = map.upOrDown; - drawCache[id] = res; - return res; - }; - - /** - * 绘制大地图,可拖动、滚轮缩放、点击对应位置可以楼传等 - * @param {string} floorId 中心地图的id - * @param {number} depth 遍历深度 - * @param {boolean} noCache 是否不使用缓存 - * @param {number} scale 绘制的缩放比例 - */ - this.drawFlyMap = function ( - floorId = core.status.floorId, - depth = defaultValue.depth, - noCache = false, - scale = defaultValue.scale - ) { - if (core.isReplaying()) return; - - // 把区域页码归零 - nowArea = areas.findIndex(v => - v.maps.includes(core.status.floorId) - ); - areaPage = 0; - nowScale = scale; - selecting = floorId; - const info = this.getMapDrawInfo(floorId, depth, noCache); - if (status !== 'scale' && status !== 'border') { - drawBack(); - drawTools(); - } - drawMap(info, scale); - status = 'flyMap'; - core.lockControl(); - core.canvas.data.canvas.style.zIndex = '990'; - }; - - /** - * 获得某个区域的剩余怪物 - * @param {string} floorId 区域包含的地图或要扫描的地图 - * @param {boolean} area 是否扫描整个区域 - * @returns {RemainEnemy} 怪物总数、所在地图、位置 - * 返回值格式:{ - * rough: 每种怪物的数量及所有怪物的总数,为字符串,每个怪物独占一行 - * detail: 每个怪物的所在位置,每个怪物独占一行,以每20个整合成字符串,为字符串数组形式 - * data: 怪物数量的原始信息,格式为{ 楼层id: { 'x,y': 怪物id } } - * } - */ - this.getRemainEnemy = function ( - floorId = core.status.floorId, - area = false - ) { - const res = bfsSearch(floorId, Infinity, true); - // 整合怪物总数 - /** @type {{[x: string]: number}} */ - const category = {}; - const toShow = area ? res.order : [floorId]; - const strArr = []; - const add = (...num) => num.reduce((pre, cur) => pre + cur, 0); - const name = id => core.material.enemys[id].name; - const title = id => core.status.maps[id].title; - for (const id of toShow) { - const enemies = res.enemies[id]; - Object.values(enemies).forEach(v => { - // 编辑器不支持 ??=,悲 - category[v] = category[v] ?? 0; - category[v]++; - }); - // 每个怪物的信息 - strArr.push( - ...Object.entries(enemies).map( - v => - `${name(v[1])} 楼层:${title( - id - )},楼层id:${id},坐标:${v[0]}` - ) - ); - } - // 输出字符串 - const all = `当前${area ? '区域' : '地图'}中剩余怪物数量:${add( - ...Object.values(category) - )}`; - const classified = Object.entries(category).map( - v => `${name(v[0])} × ${v[1]}` - ).join`\n`; - const detail = []; - while (strArr.length > 0) { - detail.push(strArr.splice(0, 20).join`\n`); - } - return { - rough: `${all}\n${classified}`, - detail, - data: res.enemies - }; - }; - - /** - * 广度优先搜索搜索地图路径 - * @param {string} center 中心地图的id - * @param {number} depth 搜索深度 - * @param {boolean} noCache 是否不使用缓存 - * @returns {BFSResult} 格式:floorId_x_y_dir: floorId_x_y - */ - function bfsSearch(center, depth, noCache) { - // 检查缓存 - const id = `${center}_${depth}_${noBorder}`; - if (mapCache[id] && !noCache) return mapCache[id]; - const used = { [center]: true }; // 搜索过的楼层 - let queue = []; - let stack = [center]; // 当前栈 - let nowDepth = -1; - const mapOrder = [center]; // 遍历顺序,顺便还能记录遍历了哪些楼层 - - const res = {}; // 输出结果,格式:floorId_x_y_dir: floorId_x_y - const enemies = {}; - const upOrDown = {}; - - // 开始循环搜索 - while (nowDepth < depth && stack.length > 0) { - const now = stack.shift(); // 当前id - if (core.status.maps[now].deleted) continue; - const blocks = core.getMapBlocksObj(now); // 获取当前地图的每点的事件 - enemies[now] = {}; - // 遍历,获取可以传送的点,只检测绿点事件,因此可用红点事件进行传送来实现分区功能 - for (const i in blocks) { - const block = blocks[i]; - // 整合漏怪检测,所以要检测怪物 - if (block.event.trigger === 'battle') { - const id = block.event.id; - if (ignoreEnemies.includes(id)) continue; - else enemies[now][i] = block.event.id; - continue; - } - // 检测触发器是否为切换楼层,不是则直接跳过 - if (block.event.trigger !== 'changeFloor') continue; - const dirEntries = allChangeEntries.find( - v => v[1] === block.event.id - ); - // 如果不是那六种传送门,直接忽略 - if (!dirEntries) continue; - const data = block.event.data; - const dir = dirEntries[0]; - const route = `${now}_${i.replace(',', '_')}_${dir}`; - const target = `${data.floorId}_${data.loc.join('_')}`; - if (!used[data.floorId]) { - if (dir === 'upFloor' || dir === 'downFloor') { - upOrDown[now] = upOrDown[id] ?? []; - upOrDown[now].push(dir); - } - queue.push(data.floorId); // 没有搜索过,则加入栈中 - mapOrder.push(data.floorId); - used[data.floorId] = true; - } - res[route] = target; - } - if (stack.length === 0) { - stack = queue; - queue = []; - nowDepth++; - } - if (stack.length === 0 && queue.length === 0) break; - } - return { res, order: mapOrder, enemies, upOrDown }; - } - - /** - * 提供地图的绘制信息 - * @param {{[x: string]: string}} map 要绘制的地图,格式:floorId_x_y_dir: floorId_x_y - * @param {string} center 中心地图的id - * @param {string[]} order 遍历顺序 - * @returns {MapDrawInfo} 地图的绘制信息 - */ - function getDrawInfo(map, center, order) { - // 先根据地图id分类,从而确定每个地图连接哪些地图,同时方便处理 - const links = {}; - for (const i in map) { - const splitted = i.split('_'); - const id = splitted[0]; - if (!links[id]) links[id] = {}; - links[id][i] = map[i]; - } - // 分类完毕,然后根据连接点先计算出各个地图的坐标,然后再进行判断 - const centerFloor = core.status.maps[center]; - const visitedCenter = core.hasVisitedFloor(center); - const locs = { - // 格式:[中心x, 中心y, 宽, 高, 是否到达过] - [center]: [ - 0, - 0, - centerFloor.width, - centerFloor.height, - visitedCenter - ] - }; - const lines = {}; // 地图间的连线 - // 可以上楼下楼的地图 - const upOrDown = {}; - for (const id of order) { - const now = links[id]; - // 遍历每一个地图的连接情况 - for (const from in now) { - const to = now[from]; - // 先根据from to计算物理位置 - const fromData = from.split('_'), - toData = to.split('_'); - const dir = fromData[3]; - if (dir === 'upFloor' || dir === 'downFloor') continue; - if (!defaultChange[dir]) continue; - const v = dirData[dir][1], // 竖直数值 - h = dirData[dir][0], // 水平数值 - ha = Math.abs(h), - va = Math.abs(v); - const fx = parseInt(fromData[1]), // fromX - fy = parseInt(fromData[2]), // fromY - tx = parseInt(toData[1]), // toX - ty = parseInt(toData[2]), // toY - ff = id, // fromFloorId - tf = toData[0]; // toFloorId - const fromFloor = core.status.maps[ff], - toFloor = core.status.maps[tf]; - const fhw = Math.floor(fromFloor.width / 2), // fromFloorHalfWidth - fhh = Math.floor(fromFloor.height / 2), - thw = Math.floor(toFloor.width / 2), - thh = Math.floor(toFloor.height / 2); - const fLoc = locs[id] ?? [0, 0]; - if (!locs[ff]) continue; - let x, y; - const dis = noBorder ? 1 : 5; - if (locs && locs[tf]) { - x = locs[tf][0]; - y = locs[tf][1]; - } else { - // 计算坐标,公式可以通过画图推断出 - x = - fLoc[0] - - ha * (fhw - fx + tx - thw) - - v * (fhw + thw + dis); - y = - fLoc[1] - - va * (fhh - fy + ty - thh) - - h * (fhh + thh + dis); - } - locs[tf] = locs[tf] ?? [ - x, - y, - toFloor.width, - toFloor.height, - core.hasVisitedFloor(tf) - ]; - // 添加连线 - lines[`${from}_${to}`] = [ - [ - fx - fhw + locs[ff][0], - fy - fhh + locs[ff][1], - x + tx - thw, - y + ty - thh - ] - ]; - } - } - // 获取地图绘制需要的长宽 - let width = 0, - height = 0; - let left, right, up, down; - for (const id in locs) { - const [x, y, w, h] = locs[id]; - if (left === void 0) { - left = right = x; - up = down = y; - } - left = Math.min(x - w / 2 - 1, left); - right = Math.max(x + w / 2 + 1, right); - up = Math.min(y - h / 2 - 1, up); - down = Math.max(y + h / 2 + 1, down); - } - width = right - left; - height = down - up; - // 所有地图和连线向右下移动,避免绘制出现问题 - for (const id in locs) { - const loc = locs[id]; - loc[0] -= left; // 这时候left和up是负值,所以要减 - loc[1] -= up; - } - for (const route in lines) { - const line = lines[route]; - for (const node of line) { - node[0] -= left; - node[1] -= up; - node[2] -= left; - node[3] -= up; - } - } - - return { locs, lines, width, height, layer: upOrDown }; - } - - /** 绘制背景 */ - function drawBack() { - if (status !== 'none') return; - new Back( - '__map_back__', - 0, - 0, - core._PX_, - core._PY_, - 175, - 'rgba(0, 0, 0, 0.9)' - ); - const listen = new Sprite( - 0, - 0, - core._PX_, - core._PY_, - 1000, - 'game', - '__map_listen__' - ); - addDrag(listen); - const exit = new Button( - '__map_exit__', - core._PX_ - 64, - core._PY_ - 26, - 60, - 22, - '退出' - ); - exit.addEventListener('click', close); - sprites.listen = listen; - } - - /** 绘制工具栏 */ - function drawTools() { - new Back( - '__map_toolback__', - 0, - core._PY_ - 30, - core._PX_, - 30, - 600, - 'rgba(200, 200, 200, 0.9)' - ); - // 无边框 - const border = new Button( - '__map_border__', - core._PX_ - 150, - core._PY_ - 26, - 60, - 22, - '边框' - ); - border.addEventListener('click', changeBorder); - // 怪物数量 - const enemy = new Button( - '__map_enemy__', - core._PX_ - 240, - core._PY_ - 26, - 60, - 22, - '怪物' - ); - enemy.addEventListener('click', triggerEnemy); - // 区域显示 - const area = new Back( - '__map_areasback__', - core._PX_ - 80, - 0, - 80, - core._PY_ - 30, - 550, - 'rgba(200, 200, 200, 0.9)' - ); - drawAreaList(); - core.drawLine( - area.context, - 0, - core._PY_ - 30, - 80, - core._PY_ - 30, - '#222', - 2 - ); - } - - /** 绘制区域列表 */ - function drawAreaList(transition = true) { - const start = perPage * areaPage; - Object.values(areaSprite).forEach(v => v.destroy()); - areaSprite = {}; - for (let i = start; i < start + perPage && areas[i]; i++) { - const n = i % perPage; - const { name, maps } = areas[i]; - const btn = new Button( - `_area_${maps[0]}`, - core._PX_ - 75, - 4 + 30 * n, - 70, - 22, - name, - '16px', - transition - ); - areaSprite[maps[0]] = btn; - if (i === nowArea) btn.setCss(`border: 2px solid gold;`); - btn.addEventListener('click', e => { - if (i === nowArea) return; - changeArea(i); - }); - } - // 上一页下一页 - if (areaPage > 0) { - const last = new Button( - '_area_last_', - core._PX_ - 75, - core._PY_ - 50, - 30, - 16, - '上一页', - '14px', - transition - ); - areaSprite._area_last_ = last; - last.addEventListener('click', e => { - areaPage--; - drawAreaList(false); - }); - } - if (areaPage < Math.floor(areas.length / perPage)) { - const next = new Button( - '_area_next_', - core._PX_ - 35, - core._PY_ - 50, - 30, - 16, - '下一页', - '14px', - transition - ); - areaSprite._area_next_ = next; - next.addEventListener('click', e => { - areaPage++; - drawAreaList(false); - }); - } - } - - /** - * 绘制大地图 - * @param {MapDrawInfo} info 地图绘制信息 - * @param {number} scale 地图的绘制比例 - */ - function drawMap(info, scale = defaultValue.scale) { - if (status === 'flyMap') return; - const PX = core._PX_, - PY = core._PY_; - const w = info.width * scale, - h = info.height * scale; - const id = `__flyMap__`; - const cx = PX / 2 - w / 2, - cy = PY / 2 - h / 2; - const map = new Sprite(cx, cy, w, h, 500, 'game', id); - sprites[id] = map; - canDrag[id] = map; - map.canvas.className = 'fly-map'; - const ctx = map.context; - core.clearMap(ctx); - if (!noBorder) { - const drawed = {}; // 绘制过的线 - // 先绘制连线 - const lines = info.lines; - for (const route in lines) { - const line = lines[route]; - for (const node of line) { - const from = `${node[0]},${node[1]}`, - to = `${node[2]},${node[3]}`; - if (drawed[`${from}-${to}`] || drawed[`${to}-${from}`]) - continue; - drawed[`${from}-${to}`] = true; - let lineWidth = scale / 2; - core.drawLine( - ctx, - node[0] * scale, - node[1] * scale, - node[2] * scale, - node[3] * scale, - '#fff', - lineWidth - ); - } - } - // 再绘制楼层 - const locs = info.locs; - for (const id in locs) { - const loc = locs[id]; - let color = '#000'; - if (!loc[4]) color = '#f0f'; - const [x, y, w, h] = loc.map( - v => typeof v === 'number' && v * scale - ); - let dx = 0, - dy = 0; // 避免绘图误差 - if (loc[2] % 2 === 0) dx = 0.5 * scale; - if (loc[3] % 2 === 0) dy = 0.5 * scale; - const fx = x - w / 2 - dx, - fy = y - h / 2 - dy; - core.fillRect(ctx, fx, fy, w, h, color); - if (id === selecting) - core.strokeRect(ctx, fx, fy, w, h, 'gold', scale / 2); - else core.strokeRect(ctx, fx, fy, w, h, '#fff', scale / 2); - const layer = info.upOrDown[id]; - const min = Math.min(w, h); - if (layer?.includes('upFloor')) - core.drawIcon( - ctx, - defaultChange.upFloor, - fx, - fy, - min / 3, - min / 3 - ); - if (layer?.includes('downFloor')) - core.drawIcon( - ctx, - defaultChange.downFloor, - fx + w - min / 3, - fy + h - min / 3, - min / 3, - min / 3 - ); - // 显示漏怪数量 - if (showEnemy) { - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - const c = `${drawingMap}_${nowDepth}_${noBorder}`; - const n = Object.keys(mapCache[c].enemies[id]).length; - color = '#3f3'; - if (n > 0) color = '#fff'; - if (n > 10) color = '#fc3'; - if (n > 20) color = '#f22'; - ctx.shadowBlur = 0.6 * nowScale; - ctx.shadowColor = '#000'; - core.fillText( - ctx, - `怪物数量:${n}`, - x, - y, - color, - `${2 * nowScale}px normal` - ); - ctx.shadowBlur = 0; - } - } - } - checkThumbnail(); - } - - /** - * 重新绘制缩略图 - * @param {Sprite} sprite - * @param {string} floor - */ - function drawThumbnail(sprite, floor, x, y, w, h) { - const ctx = sprite.context; - const scale = nowScale; - core.drawThumbnail(floor, void 0, { - ctx: ctx, - x: x - w / 2, - y: y - h / 2, - damage: true, - all: true, - size: Math.max(w, h) / Math.max(core._PX_, core._PY_), - fromMap: true - }); - const color = floor === core.status.floorId ? 'gold' : '#fff'; - if (!noBorder) - core.strokeRect( - ctx, - x - w / 2, - y - h / 2, - w, - h, - color, - scale / 2 - ); - } - - /** 检查是否需要绘制缩略图 */ - function checkThumbnail() { - const id = `${drawingMap}_${nowDepth}_${noBorder}`; - const locs = drawCache[id].locs; - const map = canDrag[`__flyMap__`]; - for (const id in locs) { - const loc = locs[id]; - const scale = nowScale; - const [x, y, w, h] = loc.map( - v => typeof v === 'number' && v * scale - ); - let dx = 0, - dy = 0; // 避免绘图误差 - if (loc[2] % 2 === 0) dx = 0.5 * scale; - if (loc[3] % 2 === 0) dy = 0.5 * scale; - if ( - !drawedThumbnail[id] && - x + map.x > 0 && - x + map.x < core._PX_ && - y + map.y > 0 && - y + map.y < core._PY_ - ) { - if (!noBorder && core.hasVisitedFloor(id) && scale > 5) { - drawThumbnail(map, id, x - dx, y - dy, w, h); - drawedThumbnail[id] = true; - } - if (noBorder) { - drawThumbnail(map, id, x - dx, y - dy, w, h); - drawedThumbnail[id] = true; - if (!core.hasVisitedFloor(id)) - core.fillRect( - map.context, - x - dx - w / 2, - y - dy - h / 2, - w, - h, - 'rgba(255,0,255,0.2)' - ); - } - } - } - // 如果是无边框模式,那就只绘制当前地图的边框 - if (noBorder) { - const loc = locs[selecting]; - const scale = nowScale; - if (loc) { - const [x, y, w, h] = loc.map( - v => typeof v === 'number' && v * scale - ); - core.strokeRect( - map.context, - x - w / 2, - y - h / 2, - w, - h, - 'gold', - scale / 2 - ); - } - } - } - - /** 检查点击点是否在以x,y为中心的某一矩形中 */ - function inRect(x, y, w, h, px, py) { - x -= w / 2; - y -= h / 2; - return px > x && px < x + w && py > y && py < y + h; - } - - /** 测试画布是否超过上限,摘自https://github.com/jhildenbiddle/canvas-size */ - function canvasTest(size) { - const width = Math.max(Math.ceil(size[0]), 1); - const height = Math.max(Math.ceil(size[1]), 1); - if (width === 0 || height === 0) return true; - const fill = [width - 1, height - 1, 1, 1]; - let cropCvs, testCvs; - cropCvs = document.createElement('canvas'); - cropCvs.width = 1; - cropCvs.height = 1; - testCvs = document.createElement('canvas'); - testCvs.width = width; - testCvs.height = height; - const cropCtx = cropCvs.getContext('2d'); - const testCtx = testCvs.getContext('2d'); - if (testCtx) { - testCtx.fillRect.apply(testCtx, fill); - cropCtx.drawImage( - testCvs, - width - 1, - height - 1, - 1, - 1, - 0, - 0, - 1, - 1 - ); - } - const isTestPass = - cropCtx && cropCtx.getImageData(0, 0, 1, 1).data[3] !== 0; - return isTestPass; - } - - /** 检查浏览器限制 */ - function checkMaximum(before, scale) { - for (const id in canDrag) { - const sprite = canDrag[id]; - const rate = scale / before; - const w = sprite.width * rate * core.domStyle.scale, - h = sprite.height * rate * core.domStyle.scale; - const valid = canvasTest([w, h]); - if (!valid) { - core.drawTip('画布大小将超过浏览器限制!请勿继续放大!'); - return true; - } - } - return false; - } - - /** 关闭事件 */ - function close() { - document.body.removeEventListener('keyup', keyboard); - Object.values(sprites).forEach(v => { - v.setCss('transition: opacity 0.6s linear;'); - }); - setTimeout(() => { - Object.values(sprites).forEach(v => { - v.setCss('opacity: 0;'); - }); - }, 50); - setTimeout(() => { - core.unlockControl(); - Object.values(sprites).forEach(v => { - v.destroy(); - }); - drawedThumbnail = {}; - sprites = {}; - canDrag = {}; - status = 'none'; - core.canvas.data.canvas.style.zIndex = '170'; - }, 650); - } - - /** - * 点击地图事件,尝试楼层传送 - * @param {MouseEvent} e - */ - function clickMap(e) { - if (moved) return (moved = false); - const { x, y } = core.actions._getClickLoc(e.clientX, e.clientY); - let px = x / core.domStyle.scale, - py = y / core.domStyle.scale; - const scale = nowScale; - const id = `${drawingMap}_${nowDepth}_${noBorder}`; - const locs = drawCache[id].locs; - const sprite = canDrag.__flyMap__; - px -= sprite.x; - py -= sprite.y; - for (const id in locs) { - const loc = locs[id]; - const [x, y, w, h] = loc.map( - v => typeof v === 'number' && v * scale - ); - if (inRect(x, y, w, h, px, py)) { - return flyTo(id); - } - } - } - - /** 飞向某个楼层 */ - function flyTo(id) { - if (!core.hasItem('fly')) return core.drawTip('你没有楼层传送器'); - sprites.__map_back__.setCss('opacity: 0.2;'); - return core.flyTo(id, () => - setTimeout(() => { - if (sprites.__map_back__) core.lockControl(); - }, 100) - ); - } - - /** - * 拖拽事件 - * @param {MouseEvent} e - */ - function drag(e) { - if (!clicking) return; - const scale = core.domStyle.scale; - moveEle(e.movementX / scale, e.movementY / scale); - } - - /** - * 手机端点击拖动事件 - * @param {TouchEvent} e - * @this {HTMLCanvasElement} - */ - function touchDrag(e) { - moved = true; - const scale = core.domStyle.scale; - if (e.touches.length === 1) { - // 拖拽 - const info = e.touches[0]; - if (!lastTouch[this.id]) { - lastTouch[this.id] = [info.clientX, info.clientY]; - return; - } - const { clientX: x, clientY: y } = info; - const dx = x - lastTouch[this.id][0], - dy = y - lastTouch[this.id][1]; - moveEle(dx / scale, dy / scale); - lastTouch[this.id] = [info.clientX, info.clientY]; - } else if (e.touches.length >= 2) { - // 双指放缩 - const first = e.touches[0], - second = e.touches[1]; - const dx = first.clientX - second.clientX, - dy = first.clientY - second.clientY; - if (lastLength === 0) { - lastLength = Math.sqrt(dx * dx + dy * dy); - return; - } - let cx = (first.clientX + second.clientX) / 2, - cy = (first.clientY + second.clientY) / 2; - const { x, y } = core.actions._getClickLoc(cx, cy); - const mx = x / scale; - const my = y / scale; - const length = Math.sqrt(dx * dx + dy * dy); - const delta = (lastLength / length) ** (1 / 3); - const info = {}; - for (const id in canDrag) { - const sprite = canDrag[id]; - const sx = sprite.x + sprite.width / 2, - sy = sprite.y + sprite.height / 2; - const dx = sx - mx, - dy = sy - my; - info[id] = [mx + dx * delta, my + dy * delta]; - } - scaleMap(delta * nowScale, info); - } - } - - /** - * 滚轮缩放 - * @param {WheelEvent} e - */ - function wheel(e) { - const delta = 1 - Math.sign(e.deltaY) / 10; - const { x, y } = core.actions._getClickLoc(e.clientX, e.clientY); - const scale = core.domStyle.scale; - const mx = x / scale, - my = y / scale; - const info = {}; - for (const id in canDrag) { - const sprite = canDrag[id]; - const cx = sprite.x + sprite.width / 2, - cy = sprite.y + sprite.height / 2; - const dx = cx - mx, - dy = cy - my; - info[id] = [mx + dx * delta, my + dy * delta]; - } - scaleMap(delta * nowScale, info); - } - - /** 切换边框 */ - function changeBorder() { - noBorder = !noBorder; - redraw('border'); - } - - /** 切换是否显示漏怪数量 */ - function triggerEnemy() { - showEnemy = !showEnemy; - redraw('enemy'); - } - - /** 改变区域 */ - function changeArea(index) { - nowArea = index; - drawAreaList(false); - drawedThumbnail = {}; - status = 'area'; - nowScale = defaultValue.scale; - drawMap(core.plugin.getMapDrawInfo(areas[index].maps[0])); - } - - /** 重绘 */ - function redraw(id, px, py, move = true) { - const { x, y } = canDrag.__flyMap__; - status = id; - drawedThumbnail = {}; - drawMap( - core.plugin.getMapDrawInfo(drawingMap, nowDepth, true), - nowScale - ); - if (move) canDrag.__flyMap__.move(px ?? x, py ?? y); - checkThumbnail(); - } - - /** - * 拖拽时移动需要元素 - * @param {string} dx - * @param {string} dy - */ - function moveEle(dx, dy) { - moved = true; - for (const id in canDrag) { - const sprite = canDrag[id]; - const ctx = sprite.context; - sprite.x += dx; - sprite.y += dy; - core.relocateCanvas(ctx, dx, dy, true); - } - checkThumbnail(); - } - - /** - * 缩放绘制地图 - * @param {number} target 目标缩放比例 - * @param {{[x: string]: [number, number]}} info 缩放后的sprite位置数据 - */ - function scaleMap(target, info) { - // 检查浏览器限制 - if (checkMaximum(nowScale, target)) return; - clearTimeout(lastScale); - const [x, y] = info.__flyMap__; - // 先直接修改style,延迟200ms再绘制,进行性能优化 - const sprite = canDrag.__flyMap__; - const rate = target / nowScale; - nowScale = target; - sprite.resize(sprite.width * rate, sprite.height * rate, true); - sprite.move(x - sprite.width / 2, y - sprite.height / 2); - lastScale = setTimeout(() => { - redraw('scale', x - sprite.width / 2, y - sprite.height / 2); - }, 200); - } - - /** 键盘操作 - * @param {KeyboardEvent} e - */ - function keyboard(e) { - if ( - e.key === 'Enter' || - e.key === 'C' || - e.key === 'c' || - e.key === ' ' - ) { - return flyTo(selecting); - } else if (e.key === 'Escape' || e.key === 'x' || e.key === 'X') { - return close(); - } else if (e.key.startsWith('Arrow')) { - const dir = e.key.slice(5).toLowerCase(); - // 获取目标楼层 - const res = - mapCache[`${drawingMap}_${nowDepth}_${noBorder}`].res; - const key = Object.keys(res).find(v => { - const [floorId, x, y, d] = v.split('_'); - return floorId === selecting && d === dir; - }); - if (!key) return; - const target = res[key].split('_')[0]; - selecting = target; - redraw('key'); - } - } - - /** - * 给需要的元素添加拖拽等事件 - * @param {HTMLCanvasElement} ele - */ - function addDrag(ele) { - ele.addEventListener('wheel', wheel); - ele.addEventListener('mousemove', drag); - ele.addEventListener('touchmove', touchDrag); - ele.addEventListener('click', clickMap); - ele.addEventListener('mousedown', () => { - clicking = true; - }); - ele.addEventListener('mouseup', () => { - clicking = false; - }); - ele.addEventListener('touchend', () => { - lastTouch = {}; - lastLength = 0; - }); - document.body.addEventListener('keyup', keyboard); - } - - maps.prototype._drawThumbnail_drawToTarget = function ( - floorId, - options - ) { - const ctx = core.getContextByName(options.ctx); - if (ctx == null) return; - const x = options.x || 0, - y = options.y || 0, - size = options.size || 1; - // size的含义改为(0,1]范围的系数以适配长方形,默认为1,楼传为3/4,SL界面为0.3 - let w = Math.ceil(size * core._PX_), - h = Math.ceil(size * core._PY_); - // 特判是否为编辑器,编辑器中长宽均采用core.js的遗留正方形像素边长,以保证下面的绘制正常 - if (main.mode == 'editor') w = h = size * core.__PIXELS__; - const width = core.floors[floorId].width, - height = core.floors[floorId].height; - let centerX = options.centerX, - centerY = options.centerY; - if (centerX == null) centerX = Math.floor(width / 2); - if (centerY == null) centerY = Math.floor(height / 2); - const tempCanvas = core.bigmap.tempCanvas; - - if (options.all) { - const tempWidth = tempCanvas.canvas.width, - tempHeight = tempCanvas.canvas.height; - // 绘制全景图 - if (tempWidth <= tempHeight) { - const realHeight = h, - realWidth = (realHeight * tempWidth) / tempHeight; - const side = (w - realWidth) / 2; - if (options.fromMap) { - return core.drawImage( - ctx, - tempCanvas.canvas, - 0, - 0, - tempWidth, - tempHeight, - x, - y, - realWidth, - realHeight - ); - } - core.fillRect(ctx, x, y, side, realHeight, '#000000'); - core.fillRect(ctx, x + w - side, y, side, realHeight); - core.drawImage( - ctx, - tempCanvas.canvas, - 0, - 0, - tempWidth, - tempHeight, - x + side, - y, - realWidth, - realHeight - ); - } else { - const realWidth = w, - realHeight = (realWidth * tempHeight) / tempWidth; - const side = (h - realHeight) / 2; - if (options.fromMap) { - return core.drawImage( - ctx, - tempCanvas.canvas, - 0, - 0, - tempWidth, - tempHeight, - x, - y, - realWidth, - realHeight - ); - } - core.fillRect(ctx, x, y, realWidth, side, '#000000'); - core.fillRect(ctx, x, y + h - side, realWidth, side); - core.drawImage( - ctx, - tempCanvas.canvas, - 0, - 0, - tempWidth, - tempHeight, - x, - y + side, - realWidth, - realHeight - ); - } - } else { - // 只绘制可见窗口 - let pw = core._PX_, - ph = core._PY_, - hw = core._HALF_WIDTH_, - hh = core._HALF_HEIGHT_, - W = core._WIDTH_, - H = core._HEIGHT_; - const ratio = core.domStyle.isVertical - ? core.domStyle.ratio - : core.domStyle.scale; - if (main.mode == 'editor') { - pw = ph = core.__PIXELS__; - hw = hh = core.__HALF_SIZE__; - W = H = core.__SIZE__; - } - if (options.v2) { - core.drawImage( - ctx, - tempCanvas.canvas, - 0, - 0, - pw * ratio, - ph * ratio, - x, - y, - w, - h - ); - } else { - const offsetX = core.clamp(centerX - hw, 0, width - W), - offsetY = core.clamp(centerY - hh, 0, height - H); - if (options.noHD) { - core.drawImage( - ctx, - tempCanvas.canvas, - offsetX * 32, - offsetY * 32, - pw, - ph, - x, - y, - w, - h - ); - return; - } - core.drawImage( - ctx, - tempCanvas.canvas, - offsetX * 32 * ratio, - offsetY * 32 * ratio, - pw * ratio, - ph * ratio, - x, - y, - w, - h - ); - } - } - }; - }, - fixed: function () { - return; - // 该插件可自定义空间很大,可自定义内容请看注释 - - // -------------------- 安装说明 -------------------- // - /* 1.安装基于canvas的sprite化插件(2.10以上样板自带)和响应式变量插件(不要使用vue原生版) - * 2.确保自己的编辑器已安装造塔群内的编辑器升级压缩包(在HTML5魔塔样板文件夹内,2.10.1以上样板自带) - * 3.将以下代码复制进插件 - */ - // -------------------- 使用说明 -------------------- // - - // -------------------- 插件说明 -------------------- // - - // 录像验证忽略 - if (main.replayChecking || main.mode === 'editor') return; - - // ----- 不可自定义变量 - /** @type {{[x: string]: Sprite}} */ - let sprites = {}; // 所有的sprite - /** @type {{[x: string]: EnemyBox}} */ - let enemyBoxes = {}; // 所有的enemyBox - /** @type {{[x: string]: TextBox}} */ - let textBoxes = {}; // 所有的textBox - let timeout = 0; // 鼠标放到怪物上时setTimeout的id - let dblTimeout = 0; // 双击时判定双击的timeout的id - /** @type {EnemyCollection[]} */ - let enemies = []; // 所有的怪物信息 - - // ----- 不可自定义常量 - const specials = core.getSpecials(); // 所有怪物的属性 - const originClick = main.dom.data.onmouseup; - - // ----- 可自定义变量 - let allowMap = true; // 是否允许直接在地图上移动鼠标显示怪物信息 - let allowDbl = true; // 是否允许双击地图上的怪物显示其详细信息,当然在点击怪物时会发生约0.2s的卡顿,以判断双击 - let guardsFirst = false; // 先攻击支援怪还是后攻击支援怪,用于计算每个怪物的伤害和回合数,请保证与getDamageInfo中相同 - let nDefDamage = true; // 为true时,显示 当前地图宝石倍率 防减伤,为false时,显示1防减伤 - - // ----- 可自定义常量 - const showStatus = ['name', 'hp', 'atk', 'def', 'money', 'exp']; // 粗略信息显示的项,伤害与特殊属性必显示 - const font = 'normal'; // 默认字体 - const op = 'c'; // 信息框背景的不透明度,范围 0-f 十六进制 - - // 属性名对应的颜色 - const colorDict = { - name: '#fff', - hp: '#8f8', - atk: '#f88', - def: '#88f', - money: 'gold', - exp: '#7f7' - }; - - /** 背景 */ - class Back extends Sprite { - constructor(name, color, z, time = 0.6) { - super(0, 0, core._PX_, core._PY_, z, 'game', name); - sprites[name] = this; - this.setCss(` - background-color: ${color}; - opacity: 0; - transition: all ${time}s linear; - `); - setTimeout(() => this.setCss(`opacity: 1;`), 50); - } - - destroy() { - this.setCss(`opacity: 0;`); - setTimeout(() => super.destroy(), 600); - delete sprites[this.name]; - } - } - - /** 怪物 */ - class EnemyBox extends Sprite { - constructor(name, x, y, w, h, id, big, e) { - const scale = core.domStyle.scale; - const s = 1 / scale / 2; - super(x - s, y - s, w + 2 * s, h + 2 * s, 300, 'game', name); - this.id = id; - /** @type {EnemyCollection} */ - this.enemy = e; - this.setCss(` - border: 1px solid #ddd; - background-color: #222; - opacity: 0; - transition: all 0.6s ease-out, transform 0.2s linear; - `); - setTimeout(() => this.setCss(`opacity: 1;`), 50); - this.animate(big); - this.frame = 0; - enemyBoxes[this.name] = sprites[this.name] = this; - this.listen(); - } - - /** 播放动画 */ - animate(big) { - const ctx = this.context; - this.interval = setInterval(() => { - const size = big ? 32 : void 0; - this.frame++; - this.frame %= 2; - // 用drawBlock还不如用drawIcon呢 - core.clearMap(ctx); - core.drawIcon(ctx, this.id, 0, 0, size, size, this.frame); - }, core.values.animateSpeed); - } - - destroy() { - clearInterval(this.interval); - delete enemyBoxes[this.name]; - super.destroy(); - } - - /** 监听 */ - listen() { - this.addEventListener('mouseenter', () => { - this.setCss(`transform: scale(1.1);`); - drawRough(this.enemy); - }); - this.addEventListener('mouseleave', () => { - this.setCss(`transform: none;`); - textBoxes[ - `_text_${this.enemy.loc.x}_${this.enemy.loc.y}_` - ].destroy(); - }); - } - } - - /** 文字框 */ - class TextBox extends Sprite { - constructor(x, y, w, h, text, fontSize, ex, ey) { - const id = `_text_${ex}_${ey}_`; - super(x, y, w, h, 310, 'game', id); - this.setCss(` - opacity: 0; - border: thick double #32a1ce; - transition: opacity 0.2s linear; - background-color: #333${op}; - box-shadow: 0px 0px 3px #000; - `); - setTimeout(() => this.setCss(`opacity: 1;`), 50); - setTimeout(() => { - clearInterval(core.status.event.interval); - this.render(text, fontSize); - }, 250); - textBoxes[id] = sprites[id] = this; - this.ex = ex; - this.ey = ey; - } - - render(text, fontSize) { - /** @type {TextContentConfig} */ - const config = { - left: 10, - top: 10, - maxWidth: this.width - 20, - time: 10, - fontSize, - font - }; - core.drawTextContent(this.context, text, config); - } - - destroy() { - this.setCss(`opacity: 0;`); - setTimeout(() => super.destroy(), 200); - delete textBoxes[`_text_${this.ex}_${this.ey}_`]; - } - } - - /** 打开定点查看界面 */ - this.openFixed = function () { - if (core.isReplaying()) return; - const info = getEnemies(); - enemies = info; - drawFixed(info); - core.lockControl(); - }; - - // 监听 & 复写 - main.dom.data.addEventListener('mousemove', moveOnPlaying); - main.dom.data.addEventListener('dblclick', dblClick); - main.dom.data.onmouseup = e => { - if (allowDbl) { - clearTimeout(dblTimeout); - dblTimeout = setTimeout(() => { - originClick.call(main.dom.data, e); - }, 200); - } else { - originClick.call(main.dom.data, e); - } - }; - - /** - * 获取怪物位置和其属性 - * @param {string} floorId 地图id - * @returns {EnemyCollection[]} 怪物信息数组 - */ - function getEnemies(floorId = core.status.floorId) { - const res = []; - // 遍历所有图块,然后找出在显示范围内的怪物,异步执行, - core.extractBlocks(floorId); - const blocks = core.status.maps[floorId].blocks; - for (const block of blocks) { - const x = block.x, - y = block.y; - // 判断是否为怪物 - if (block.event.trigger !== 'battle') continue; - // 判断是否在范围内 - if (!inView(x, y)) continue; - res.push(generateCollection(block.event.id, x, y, floorId)); - } - return res; - } - - function generateCollection(id, x, y, floorId) { - const enemy = core.material.enemys[id]; - const info = core.getEnemyInfo(id, void 0, x, y, floorId); - const data = Object.assign({}, enemy); - for (const key in info) data[key] = info[key]; - return { loc: { x, y }, data }; - } - - /** - * 根据属性名获得颜色 - * @param {string} status - */ - function color(status) { - return colorDict[status] ?? 'white'; - } - - /** - * 根据伤害获得伤害颜色 - * @param {number} damage - */ - function colorDamage(damage) { - if (typeof damage === 'string' || !damage) return '#f00'; - const hp = core.status.hero.hp; - const n = ~~((damage / hp) * 255); - return `rgb(${n}, ${255 - n}, 0)`; - } - - /** - * 获取怪物的粗略信息 - * @param {Enemy} info - */ - function getRough(info, x, y) { - // 先获得常量中明确指定的 - const text = showStatus.map(v => { - return `\\r[${color(v)}]${core.getStatusLabel(v)}\\r[]:${ - info[v] - }`; - }); - // 特殊属性 - if (info.special?.length > 0) { - const names = core.getSpecialText(info); - const color = core.getSpecialColor(info); - const all = names.map((v, i) => `\\r[${color[i]}]${v}\\r[]`); - text.push(`\\r[#f8f]特殊属性\\r[]:${all.join` `}`); - } - // 伤害 - const damage = core.getDamageInfo(info, void 0, x, y)?.damage; - const d = core.formatBigNumber(damage); - text.push( - `\\r[#f44]伤害\\r[]:\\r[${colorDamage(damage)}]${ - d === '???' ? '无法战胜' : d - }\\r[]` - ); - // 支援 - if (info.guards?.length > 0) { - const guards = getGuards(info, x, y); - text.push( - `\\r[#3cf]支援\\r[]:${guards.map(v => `\\i[${v.id}]`) - .join` `}` - ); - text.push(`支援怪攻击顺序 -->`); - } - if (allowDbl) text.push('双击怪物查看详细信息'); - return text.join`\n`; - } - - /** - * 获得特殊属性说明、名称、颜色 - * @param {SpecialCollection} data - * @param {Enemy} enemy - */ - function executeSpecial(data, enemy) { - let name = ''; - if (typeof data[1] === 'string') name = data[1]; - else name = data[1](enemy); - let text = ''; - if (typeof data[2] === 'string') text = data[2]; - else text = data[2](enemy); - return { name, text, color: data[3] }; - } - - /** - * 获得某个怪物的详细信息,包括特殊属性说明、支援怪攻击顺序 - * @param {EnemyCollection} info getEnemies获取的怪物信息 - */ - function getDetail(info) { - // ----- status - const status = {}; - showStatus.forEach(v => { - status[v] = { - id: v, - name: core.getStatusLabel(v), - value: info.data[v] - }; - }); - // ----- special - const text = []; - const special = info.data.special; - if (special?.length > 0) { - for (const n of special) { - const data = specials.find(v => v[0] === n); - if (!data) - throw new ReferenceError( - `'${info.data.name}'拥有不存在的特殊属性'${n}'` - ); - const { - name, - text: desc, - color - } = executeSpecial(data, info.data); - text.push(`\\r[${color}]${name}\\r[]:${desc}`); - } - } - // ---- damage & turn - const damageInfo = core.getDamageInfo( - info.data, - void 0, - info.loc.x, - info.loc.y - ); - let damage = core.formatBigNumber(damageInfo?.damage); - if (damage === '???') damage = '无法战胜'; - const color = colorDamage(damageInfo?.damage); - const turn = damageInfo?.turn ?? 0; - // ----- 4 criticals & n def - const criticals = core.nextCriticals( - info.data, - 4, - info.loc.x, - info.loc.y - ); - const n = nDefDamage ? core.status.thisMap.ratio : 1; - const def = core.getDefDamage(info.data, n, info.loc.x, info.loc.y); - return { - status, - text, - damage: { damage, color, turn }, - criticals, - def - }; - } - - /** - * 获取支援怪信息,攻击顺序 - * @param {Enemy} info 怪物信息 - * @param {EnemyCollection[]} all 所有的怪物信息 - * @returns {GuardCollection[]} 支援怪的顺序信息 - */ - function getGuards(info, all) { - /** @type {[number, number, string][]} */ - const guards = info.guards; - if (!guards) return; - return guards.map(([x, y, id]) => { - const res = { - loc: { x, y }, - id - }; - // 寻找符合条件的怪物 - const enemy = all.find(v => v.loc.x === x && v.loc.y === y); - res.enemy = enemy; - return res; - }); - } - - /** - * 获取每个支援怪造成的伤害、回合数等 - * @param {EnemyCollection} info - */ - function getGuardsDetail(info) { - // 很神秘的一个功能 - const guards = getGuards(info, enemies); // 这时候获得的已经是按顺序排好的了 - const col = { enemy: info.data, loc: info.loc }; - if (guardsFirst) guards.push(col); - else guards.unshift(col); - const turn = ref(0); - const res = []; - watch(turn, v => (flags.__extraTurn__ = v)); // 使用样板的额外回合flag - const status = ['atk', 'def', 'hp'].map(v => ({ - [v]: core.getRealStatus(v) - })); - const hero = Object.assign({}, ...status, { mdef: 0 }); - for (let i = 0; i < guards.length; i++) { - const e = guards[i]; - const data = core.getDamageInfo( - e.enemy, - i === 0 ? void 0 : hero, - e.loc.x, - e.loc.y - ); - if (!data) { - res.push({ battlable: false }); - continue; - } - turn.value += data.turn; - res.push({ - battlable: true, - damage: data.damage, - turn: data.turn - }); - } - return res; - } - - /** - * 是否在视野范围内 - * @param {number} x 要判断的格子 - * @param {number} y - */ - function inView(x, y) { - const { x: hx, y: hy } = core.status.hero.loc; - const w = core._WIDTH_, - h = core._HEIGHT_; - return x <= hx + w && x >= hx - w && y <= hy + h && y >= hy - h; - } - - /** - * 计算像素位置 - * @param {number} x - * @param {number} y - * @param {number} w - * @param {number} h - */ - function calPixel(x, y, w, h) { - const px = x * 32 + 16 - w / 2, - py = (y + 1) * 32 - h; - return { px, py, w, h }; - } - - /** - * 根据鼠标位置获得矩形的绘制信息 - * @param {number} px - * @param {number} py - */ - function calRect(px, py, text) { - const onRight = px >= core._PX_ / 2; - let x = px + 32; - const width = Math.min( - core._PX_ / 2 - 32, - onRight ? px - 32 : core._PX_ - x - ); - if (onRight) x = px - width - 32; - const config = { - maxWidth: width - 20, - font, - fontSize: 19, - left: 10 - }; - let height = 500; - while (height > core._PY_ - 20) { - config.fontSize--; - height = core.getTextContentHeight(text, config) + 20; - } - const y = core.clamp(py - height / 2, 10, core._PY_ - 20 - height); - return { x, y, width, height, font: config.fontSize }; - } - - /** - * 绘制定点查看界面 - * @param {EnemyCollection[]} info 怪物信息 - */ - function drawFixed(info) { - // 绘制,当然还有动画 - new Back('_fixed_sback_', 'rgba(0, 0, 0, 0.9)', 200); - drawChoice(info); - const exit = new Sprite( - core._PX_ - 60, - 4, - 56, - 24, - 400, - 'game', - '_exit_' - ); - exit.setCss(` - background-color: #aaa; - box-shadow: 0px 0px 3px #000; - cursor: pointer; - transition: all 0.6s linear; - opacity: 0; - `); - setTimeout(() => exit.setCss(`opacity: 1;`), 50); - const ctx = exit.context; - ctx.shadowBlur = 3; - ctx.shadowColor = '#000'; - ctx.textAlign = 'center'; - ctx.textBaseline = 'middle'; - core.fillText(ctx, '退出', 28, 12, '#fff', '18px normal'); - exit.addEventListener('click', close); - sprites['_exit_'] = exit; - } - - /** - * 绘制每个怪物 - * @param {EnemyCollection[]} info - */ - function drawChoice(info) { - for (const e of info) { - const { x, y } = e.loc; - const data = e.data; - const { bigImage, height } = core.getBlockInfo(data.id); - const w = bigImage?.width ?? 32, - h = bigImage?.height ?? height; - const { px, py } = calPixel(x, y, w, h); - new EnemyBox( - `_enemybox_${x}_${y}_`, - px, - py, - w, - h, - data.id, - !!bigImage, - e - ); - } - } - - /** - * 绘制怪物的粗略信息 - * @param {EnemyCollection} info - */ - function drawRough(info) { - const { x, y } = info.loc; - const text = getRough(info.data, x, y); - const rect = calRect(x * 32 + 16, y * 32 + 16, text); - new TextBox( - rect.x, - rect.y, - rect.width, - rect.height, - text, - rect.font, - x, - y - ); - } - - /** - * 绘制详细信息的主界面 - * @param {EnemyCollection} info - * @param {EnemyBox} enemyBox - */ - function drawMain(info, enemyBox) { - const { bigImage, height } = core.getBlockInfo(info.data.id); - const w = bigImage?.width ?? 32, - h = bigImage?.height ?? height; - const box = - enemyBox ?? - new EnemyBox( - `_enemy_main_`, - 16, - 16, - w, - h, - info.data.id, - !!bigImage, - info - ); - box.move(16, 16); - box.setCss(` - border: 0; - background-color: transparent; - transform: none; - z-index: 1000; - `); - const { status, text, damage, criticals, def } = getDetail(info); - const back = new Back( - `_detail_back_`, - 'linear-gradient(to bottom, #333, #777)', - 600, - 0.2 - ); - // draw - const sv = Object.values(status); - sv.forEach(e => {}); - } - - /** - * 绘制怪物详细信息界面 - * @param {EnemyCollection} info 怪物的信息 - * @param {boolean} animate 是否要有动画 - */ - function drawDetail(info, animate) { - const { x, y } = info.loc; - const box = enemyBoxes[`_enemybox_${x}_${y}_`]; - if (!animate) box?.destroy(); - drawMain(info, box); - } - - /** 关闭界面 */ - function close() { - Object.values(sprites).forEach(v => v.destroy()); - setTimeout(core.unlockControl, 600); - } - - function getEnemy(px, py) { - const evenX = core._WIDTH_ % 2 === 0 ? 0.5 : 0, - evenY = core._HEIGHT_ % 2 === 0 ? 0.5 : 0; - const bx = Math.round( - ~~(px / 32) - core.bigmap.offsetX / 32 + evenX - ), - by = Math.round(~~(py / 32) - core.bigmap.offsetY / 32 + evenY); - const loc = `${bx},${by}`; - const blocks = core.getMapBlocksObj(); - const block = blocks[loc]; - if (!block) return; - if (block?.event?.trigger === 'battle') - return generateCollection(block.event.id, bx, by); - } - - /** - * 在游戏时移动鼠标,延迟500ms显示怪物信息 - * @param {MouseEvent} e - */ - function moveOnPlaying(e) { - if (!allowMap) return; - if (!core.isPlaying()) return; - const { x, y } = core.actions._getClickLoc(e.clientX, e.clientY); - const px = x / core.domStyle.scale, - py = y / core.domStyle.scale; - clearTimeout(timeout); - // 清空所有的信息栏 - Object.values(textBoxes).forEach(v => v.destroy()); - const enemy = getEnemy(px, py); - if (block?.event?.trigger !== 'battle') return; - lastLoc = loc; - timeout = setTimeout(() => { - drawRough(enemy); - }, 500); - } - - /** - * 双击鼠标时 - * @param {MouseEvent} e - */ - function dblClick(e) { - if (!allowDbl) return; - if (!core.isPlaying()) return; - if (e.detail !== 2) return; - clearTimeout(dblTimeout); - clearTimeout(timeout); - const { x, y } = core.actions._getClickLoc(e.clientX, e.clientY); - const px = x / core.domStyle.scale, - py = y / core.domStyle.scale; - const enemy = getEnemy(px, py); - drawDetail(enemy); - } - }, itemDetail: function () { /* 宝石血瓶左下角显示数值 * 需要将 变量:itemDetail改为true才可正常运行 @@ -5613,475 +3626,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { } }; }, - loopMap: function () { - // 循环式地图相关 - // 防止重开游戏出问题 - ////// 加载某个楼层(从剧本或存档中) ////// - maps.prototype.loadFloor = function (floorId, map, fromReset) { - var floor = fromReset ? main.floors[floorId] : core.floors[floorId]; - if (!map) map = floor.map; - if (map instanceof Array) { - map = { map: map }; - } - if (!map.map) map.map = core.clone(floor.map); - var content = {}; - var notCopy = this._loadFloor_doNotCopy(); - for (var name in floor) { - if (notCopy.indexOf(name) == -1 && floor[name] != null) - content[name] = core.clone(floor[name]); - } - for (var name in map) { - if (notCopy.indexOf(name) == -1 && map[name] != null) - content[name] = core.clone(map[name]); - } - content.map = map.map; - if (main.mode == 'editor') { - this.extractBlocks(content); - } - return content; - }; - ////// 自动存档 ////// - control.prototype.autosave = function (removeLast) { - if ( - core.hasFlag('__forbidSave__') || - core.status.floorId == 'tower6' - ) - return; - var x = null; - if (removeLast) { - x = core.status.route.pop(); - core.status.route.push('turn:' + core.getHeroLoc('direction')); - } - if (core.status.event.id == 'action') - // 事件中的自动存档 - core.setFlag('__events__', core.clone(core.status.event.data)); - if (core.saves.autosave.data == null) { - core.saves.autosave.data = []; - } - core.saves.autosave.data.splice( - core.saves.autosave.now, - 0, - core.saveData() - ); - core.saves.autosave.now += 1; - if (core.saves.autosave.data.length > core.saves.autosave.max) { - if (core.saves.autosave.now < core.saves.autosave.max / 2) - core.saves.autosave.data.pop(); - else { - core.saves.autosave.data.shift(); - core.saves.autosave.now = core.saves.autosave.now - 1; - } - } - core.saves.autosave.updated = true; - core.saves.ids[0] = true; - core.removeFlag('__events__'); - if (removeLast) { - core.status.route.pop(); - if (x) core.status.route.push(x); - } - }; - ////// 重置地图 ////// - maps.prototype.resetMap = function (floorId) { - floorId = floorId || core.status.floorId; - if (!floorId) return; - if (typeof floorId == 'string') floorId = [floorId]; - var needRefresh = false; - floorId.forEach(t => { - core.status.maps[t] = core.maps.loadFloor(t, null, true); - // 重置本层的全部独立事件 - Object.keys(core.status.hero.flags).forEach(one => { - if (one.startsWith(floorId + '@')) - delete core.status.hero.flags[one]; - }); - // 重置本层的图块删除信息 - delete (flags.__disabled__ || {})[t]; - delete (core.status.mapBlockObjs || {})[t]; - if (t == core.status.floorId) needRefresh = true; - ['bg', 'bg2', 'fg', 'fg2'].forEach(layer => { - core.floors[floorId] = main.floors[floorId]; - }); - }); - if (needRefresh) this.drawMap(); - core.drawTip('地图重置成功'); - }; - // 勇士不动图层动 - control.prototype._moveAction_moving = function (callback) { - core.setHeroMoveInterval(() => { - if (core.status.floorId != 'tower6') { - core.setHeroLoc('x', core.nextX(), true); - } else { - if ( - core.status.hero.loc.direction != 'down' && - core.status.hero.loc.direction != 'up' - ) { - core.setHeroLoc('x', 12, true); - var block = core.getMapBlocksObj(core.status.floorId)[ - core.nextX() + ',' + core.nextY - ]; - if (block) var trigger = block.event.trigger; - else var trigger = ''; - if (trigger != 'battle') { - core.changeEventsBgFg( - core.status.hero.loc.direction, - 'tower6', - ['tower1', 'tower2', 'tower4', 'tower5'] - ); - } - core.drawMap(); - } - } - core.setHeroLoc('y', core.nextY(), true); - var direction = core.getHeroLoc('direction'); - core.control._moveAction_popAutomaticRoute(); - core.status.route.push(direction); - core.moveOneStep(); - core.checkRouteFolding(); - if (callback) callback(); - }); - }; - ////// 设置行走的效果动画 ////// - control.prototype.setHeroMoveInterval = function (callback) { - if (core.status.heroMoving > 0) return; - if (core.status.replay.speed == 24) { - if (callback) callback(); - 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; - core.interval.heroMoveInterval = window.setInterval(() => { - core.status.heroMoving += toAdd; - if (core.status.floorId == 'tower6') - core.backgroundImage('tower6.jpeg'); - if (core.status.heroMoving >= 8) { - clearInterval(core.interval.heroMoveInterval); - core.status.heroMoving = 0; - if (callback) callback(); - } - }, ((core.values.moveSpeed / 8) * toAdd) / core.status.replay.speed); - }; - // 事件层前景层背景层平移 - this.changeEventsBgFg = function (direction, floorId, fromIds) { - if (direction == 'up' || direction == 'down') return; - var floor = core.floors[floorId]; - // 原始层楼层转换平移 - fromIds.forEach(id => { - var toChanges = {}; - for (var one in core.floors[id].changeFloor) { - var data = core.floors[id].changeFloor[one]; - var x = data.loc[0], - y = data.loc[1]; - var blocks = core.getMapBlocksObj(id); - var toFloor = data.floorId; - if (blocks[one] && !blocks[one].event.id.startsWith('A')) { - toChanges[one] = { floorId: toFloor, loc: [x, y] }; - continue; - } else { - if (direction == 'left') - x = x >= floor.width - 1 ? 0 : x + 1; - else x = x <= 0 ? floor.width - 1 : x - 1; - toChanges[one] = { floorId: toFloor, loc: [x, y] }; - } - } - // 转换 - delete core.floors[id].changeFloor; - core.floors[id].changeFloor = toChanges; - delete core.status.maps[id].blocks; - core.extractBlocks(id); - core.getMapBlocksObj(id, true); - }); - var list = ['events', 'changeFloor']; - list.forEach(name => { - var toEvents = {}; - // 获得事件并删除原事件 - for (var one in floor[name]) { - var loc = one.split(','); - var x = parseInt(loc[0]), - y = parseInt(loc[1]); - if (direction == 'left') { - var toX = x == floor.width - 1 ? 0 : x + 1; - toEvents[toX + ',' + y] = floor[name][one]; - } else { - var toX = x == 0 ? floor.width - 1 : x - 1; - toEvents[toX + ',' + y] = floor[name][one]; - } - delete core.floors[floorId][name][one]; - } - // 转换 - core.floors[floorId][name] = toEvents; - }); - // 前景事件背景层图块平移 - list = ['bgmap', 'bg2map', 'map', 'fgmap', 'fg2map']; - list.forEach(one => { - if (one == 'map') { - var toBlocks = core.clone(core.status.maps[floorId].map); - } else { - var toBlocks = core.clone(floor[one]); - } - if (toBlocks.length == 0) return; - for (var y = 0; y < toBlocks.length; y++) { - for (var x = 0; x < toBlocks[y].length; x++) { - if (direction == 'left') { - if (one != 'map') - floor[one][y][x] = - toBlocks[y][ - x == 0 ? floor.width - 1 : x - 1 - ]; - else - core.status.maps[floorId].map[y][x] = - toBlocks[y][ - x == 0 ? floor.width - 1 : x - 1 - ]; - } else { - if (one != 'map') - floor[one][y][x] = - toBlocks[y][ - x == floor.width - 1 ? 0 : x + 1 - ]; - else - core.status.maps[floorId].map[y][x] = - toBlocks[y][ - x == floor.width - 1 ? 0 : x + 1 - ]; - } - } - } - }); - delete core.status.maps[floorId].blocks; - core.setMapBlockDisabled( - floorId, - core.nextX(), - core.nextY(), - false - ); - core.extractBlocks(floorId); - core.getMapBlocksObj(floorId, true); - }; - // 背景图 - this.backgroundImage = function (image) { - if (typeof image == 'string') { - image = core.getMappedName(image); - image = core.material.images.images[image]; - if (!image) return; - } - var h = image.height, - w = image.width; - // 裁剪 - var sx = w / 2 - 240, - sy = - (core.bigmap.offsetY / - (core.status.thisMap.height * 32 - 480)) * - (h - 480); - // 背景层遮挡 - core.createCanvas('bImage', 0, 0, 480, 480, 25); - // 事件层遮挡 - core.createCanvas('eImage', 0, 0, 480, 480, 70); - core.clearMap('bImage'); - // 左半边 - core.drawImage('bImage', image, sx, sy, 96, 480, 0, 0, 96, 480); - core.drawImage('eImage', image, sx, sy, 64, 480, 0, 0, 64, 480); - // 右半边 - sx = w / 2 + 144; - core.drawImage('bImage', image, sx, sy, 96, 480, 384, 0, 96, 480); - core.drawImage( - 'eImage', - image, - sx + 32, - sy, - 64, - 480, - 416, - 0, - 64, - 480 - ); - }; - // 到达地图重定位 - this.relocateLoopMap = function (floorId, heroLoc, fromIds) { - var floor = core.floors[floorId]; - var nowX = heroLoc.x; - var toX = Math.floor(floor.width / 2); - if (nowX == toX) return; - // 设置勇士位置 - core.setHeroLoc('x', 12); - // 计算偏移量 - var dx = toX - nowX; - // 转换 - // 原始层楼层转换平移 - if (floorId == 'tower6') - fromIds = ['tower1', 'tower2', 'tower4', 'tower5']; - fromIds.forEach(id => { - var toChanges = {}; - for (var one in core.floors[id].changeFloor) { - var data = core.floors[id].changeFloor[one]; - var x = data.loc[0], - y = data.loc[1]; - var blocks = core.getMapBlocksObj(id); - var toFloor = data.floorId; - if (blocks[one] && !blocks[one].event.id.startsWith('A')) { - toChanges[one] = { floorId: toFloor, loc: [x, y] }; - continue; - } - if (dx > 0) - x = - x + dx > floor.width - 1 - ? dx + x - floor.width - : dx + x; - else x = x + dx < 0 ? dx + x + floor.width : dx + x; - toChanges[one] = { floorId: toFloor, loc: [x, y] }; - } - // 转换 - delete core.floors[id].changeFloor; - core.floors[id].changeFloor = toChanges; - delete core.status.maps[id].blocks; - core.extractBlocks(id); - core.getMapBlocksObj(id, true); - }); - var list = ['events', 'changeFloor']; - list.forEach(name => { - var toEvents = {}; - // 获得事件并删除原事件 - for (var one in floor[name]) { - var loc = one.split(','); - var x = parseInt(loc[0]), - y = parseInt(loc[1]); - if (x + dx > floor.width - 1) { - x = dx + x - floor.width; - } else if (x + dx < 0) { - x = x + dx + floor.width; - } else { - x += dx; - } - toEvents[x + ',' + y] = floor[name][one]; - delete core.floors[floorId][name][one]; - } - // 转换 - core.floors[floorId][name] = toEvents; - }); - dx = -dx; - // 前景事件背景层图块平移 - list = ['bgmap', 'bg2map', 'map', 'fgmap', 'fg2map']; - list.forEach(one => { - if (one == 'map') { - var toBlocks = core.clone(core.status.maps[floorId].map); - } else { - var toBlocks = core.clone(floor[one]); - } - if (toBlocks.length == 0) return; - for (var y = 0; y < toBlocks.length; y++) { - for (var x = 0; x < toBlocks[y].length; x++) { - if (dx > 0) { - if (one != 'map') - floor[one][y][x] = - toBlocks[y][ - x + dx > floor.width - 1 - ? dx + x - floor.width - : dx + x - ]; - else - core.status.maps[floorId].map[y][x] = - toBlocks[y][ - x + dx > floor.width - 1 - ? dx + x - floor.width - : dx + x - ]; - } else { - if (one != 'map') - floor[one][y][x] = - toBlocks[y][ - x + dx < 0 - ? dx + x + floor.width - : dx + x - ]; - else - core.status.maps[floorId].map[y][x] = - toBlocks[y][ - x + dx < 0 - ? dx + x + floor.width - : dx + x - ]; - } - } - } - }); - delete core.status.maps[floorId].blocks; - core.extractBlocks(floorId); - core.getMapBlocksObj(floorId, true); - }; - ////// 将当前地图重新变成数字,以便于存档 ////// - maps.prototype.saveMap = function (floorId) { - if (floorId == 'tower6') return; - var maps = core.status.maps; - if (!floorId) { - var map = {}; - for (var id in maps) { - if (id == 'tower6') continue; - var obj = this.saveMap(id); - if (Object.keys(obj).length > 0) map[id] = obj; - } - return map; - } - // 砍层状态:直接返回 - if ((flags.__removed__ || []).indexOf(floorId) >= 0) { - return {}; - } - - var map = maps[floorId]; - var thisFloor = this._compressFloorData(map, core.floors[floorId]); - var mapArr = this.compressMap( - map.blocks - ? this._getMapArrayFromBlocks( - map.blocks, - map.width, - map.height, - true - ) - : map.map, - floorId - ); - if (mapArr != null) thisFloor.map = mapArr; - return thisFloor; - }; - // 存档问题 - this.saveLoopMap = function (floorId, fromIds) { - // 当前层 - var data = {}; - ['bg2map', 'bgmap', 'changeFloor', 'fgmap', 'fg2map'].forEach( - one => { - data[one] = core.floors[floorId][one]; - } - ); - // 可以到达该层的楼层转换 - data.map = core.status.maps[floorId].map; - data.changes = {}; - fromIds.forEach(id => { - data.changes[id] = core.floors[id].changeFloor; - }); - return data; - }; - // 读档 - this.loadLoopMap = function (data, floorId) { - if (!data) return; - for (var one in data) { - // 非楼层转换 - if (one != 'changes') { - core.floors[floorId][one] = data[one]; - } else { - // 楼层转换 - for (var id in data.changes) { - core.floors[id].changeFloor = data.changes[id]; - } - } - } - // 解析图块 - if (data.changes) - for (var id in data.changes) { - core.extractBlocks(id); - } - }; - }, towerBoss: function () { // 智慧boss // 变量们 @@ -7773,7 +5317,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { } }; }, - weatherSuperimpose: function () {}, popupDamage: function () { // 伤害弹出 // 复写阻激夹域检测 @@ -7783,7 +5326,14 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { loc = x + ',' + y; var damage = core.status.checkBlock.damage[loc]; if (damage) { - core.addPop(x * 32 + 12, y * 32 + 20, damage, '#f00', '#000'); + if (!main.replayChecking) + core.addPop( + x * 32 + 12, + y * 32 + 20, + damage, + '#f00', + '#000' + ); core.status.hero.hp -= damage; var text = Object.keys(core.status.checkBlock.type[loc] || {}).join( @@ -8645,128 +6195,6 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { } })(); }, - hide: function () { - if (main.mode === 'editor' || main.replayChecking) return; - /** - * 所有的会被视为房间的墙 - */ - const WALLS = [ - 'yellowWall', - 'yellowDoor', - 'blueDoor', - 'redDoor', - 'greenDoor' - ]; - /** - * 房间的最大大小 - */ - const MAX_AREA = 25; - /** - * 要隐藏的点 - */ - const HIDE_POS = [ - ['MT1', 2, 3], - ['MT2', 4, 5], - ['MT3', 7, 1] - ]; - - let showed = {}; - - /// 初始化游戏 - events.prototype.resetGame = function ( - hero, - hard, - floorId, - maps, - values - ) { - this.eventdata.resetGame(hero, hard, floorId, maps, values); - showed = core.getFlag('__showed__', {}); - flags.__showed__ = flags.__showed__ ?? {}; - hide(); - }; - - /** - * 显示一个区域 - * @param {string} floor - * @param {number} x - * @param {number} y - */ - this.showHidden = function (floor, x, y) { - const pos = bfs(floor, x, y); - for (const [x, y] of pos) { - core.setBgFgBlock('fg', 0, x, y, floor); - const id = `${floor}_${x}_${y}`; - showed[id] = true; - flags.__showed__[id] = true; - } - }; - - /** - * 隐藏 - */ - function hide() { - for (const pos of HIDE_POS) { - const id = pos.join('_'); - if (showed[id]) continue; - const p = bfs(...pos); - if (p.length >= MAX_AREA) continue; - for (const [x, y] of p) { - core.setBgFgBlock('fg', 4, x, y, pos[0]); - const id = `${pos[0]}_${x}_${y}`; - showed[id] = true; - flags.__showed__[id] = false; - } - } - } - - /** - * @returns {[number, number][]} - */ - function bfs(floorId, x, y) { - core.extractBlocks(floorId); - const blocks = core.getMapBlocksObj(floorId); - const mapped = { - [`${x},${y}`]: true - }; - const queue = [[x, y]]; - /** @type {[direction, number, number][]} */ - const dir = Object.entries(core.utils.scan).map(v => [ - v[0], - v[1].x, - v[1].y - ]); - const res = [[x, y]]; - - while (queue.length > 0) { - const [nx, ny] = queue.shift(); - dir.forEach(v => { - const [tx, ty] = [nx + v[1], ny + v[2]]; - const floor = core.status.maps[floorId]; - if ( - tx < 0 || - ty < 0 || - tx >= floor.width || - ty >= floor.height - ) - return; - const loc = `${tx},${ty}`; - if (mapped[loc]) return; - const block = blocks[loc]; - mapped[loc] = true; - if (!block) { - queue.push([tx, ty]); - res.push([tx, ty]); - return; - } - if (WALLS.includes(block.event.id)) return; - queue.push([tx, ty]); - res.push([tx, ty]); - }); - } - return res; - } - }, uiChange: function () { if (main.replayChecking) return; @@ -8836,5 +6264,12 @@ var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { core.plugin.chapterContent.value = chapter; core.plugin.chapterShowed.value = true; }; + }, + remainEnemy: function () { + /** + * 检查漏怪 + * @param {FloorIds[]} floorIds + */ + this.checkRemainEnemy = function(floorIds) {} } };