var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = { "init": function () { this._afterLoadResources = function () { // 本函数将在所有资源加载完毕后,游戏开启前被执行 } if (!core.platform.isPC) { try { window.screen.orientation.lock("landscape-primary"); } catch (e) {} } core.dom.playGame.setAttribute('selected', true); ////游戏第一次打开进入到标题界面时要将光标设置为到playGame core.control.hideStatusBar(); core.control.resize = function () { if (main.mode == 'editor') return; var clientWidth = main.dom.body.clientWidth, clientHeight = main.dom.body.clientHeight; var BORDER = 0; var extendToolbar = core.flags.extendToolbar; var BAR_WIDTH = extendToolbar ? 0 : Math.round(core._PY_ / 3); var horizontalMaxRatio = (clientHeight - 2 * BORDER - (extendToolbar ? BORDER : 0)) / (core._PY_ + (extendToolbar ? 38 : 0)); //////强制横屏插件 //////// // 横屏 core.domStyle.availableScale = []; [1, 1.25, 1.5, 1.75, 2, 2.25, 2.5].forEach(function (v) { if (clientWidth - 3 * BORDER >= v * (core._PX_ + BAR_WIDTH) && horizontalMaxRatio >= v) { core.domStyle.availableScale.push(v); } }); if (core.domStyle.availableScale.indexOf(core.domStyle.scale) < 0) { core.domStyle.scale = Math.min(1, horizontalMaxRatio); } if (clientWidth - 3 * BORDER >= core._PX_ + BAR_WIDTH || (clientWidth > clientHeight && horizontalMaxRatio < 1)) { core.domStyle.isVertical = false; core.clearMap('Vertical'); } else { // 竖屏 core.domStyle.isVertical = true; core.createCanvas('Vertical', 0, 0, 480, 480, 200); core.drawWindowSkin('winskin.png', 'Vertical', 30, 150, 400, 100); core.drawTextContent('Vertical', '\r[#ff8080]强烈建议建议使用最新版浏览器\n开启手机自动旋转功能进行横屏游戏', { left: 50, top: 180, maxWidth: 400, fontSize: 20, lineHeight: 20, bold: true, }); // core.domStyle.scale = Math.min((clientWidth - 2 * BORDER) / core._PX_); // core.domStyle.availableScale = []; // extendToolbar = false; // BAR_WIDTH = Math.round(core._PX_ * 0.3); } var statusDisplayArr = this._shouldDisplayStatus(), count = statusDisplayArr.length; var statusCanvas = core.flags.statusCanvas, statusCanvasRows = core.values.statusCanvasRowsOnMobile || 3; var col = statusCanvas ? statusCanvasRows : Math.ceil(count / 3); if (col > 5) { if (statusCanvas) alert("自绘状态栏的在竖屏下的行数应不超过5!"); else alert("当前状态栏数目(" + count + ")大于15,请调整到不超过15以避免手机端出现显示问题。"); } var globalAttribute = core.status.globalAttribute || core.initStatus.globalAttribute; var obj = { clientWidth: clientWidth, clientHeight: clientHeight, BORDER: BORDER, BAR_WIDTH: BAR_WIDTH, TOOLBAR_HEIGHT: 38, outerWidth: core._PX_ * core.domStyle.scale + 2 * BORDER, outerHeight: core._PY_ * core.domStyle.scale + 2 * BORDER, globalAttribute: globalAttribute, border: '0px ' + core.arrayToRGBA(globalAttribute.borderColor) + ' solid', statusDisplayArr: statusDisplayArr, count: count, col: col, statusBarHeightInVertical: core.domStyle.isVertical ? (32 * col + 6) * core.domStyle.scale + 2 * BORDER : 0, toolbarHeightInVertical: core.domStyle.isVertical ? 38 * core.domStyle.scale + 2 * BORDER : 0, extendToolbar: extendToolbar, is15x15: false }; this._doResize(obj); this.setToolbarButton(); core.updateStatusBar(); } core.control._resize_statusBar = function (obj) { // statusBar var statusBar = core.dom.statusBar; if (core.domStyle.isVertical) { statusBar.style.width = obj.outerWidth + "px"; statusBar.style.height = obj.statusBarHeightInVertical + "px"; statusBar.style.background = obj.globalAttribute.statusTopBackground; statusBar.style.fontSize = 16 * core.domStyle.scale + "px"; } else { statusBar.style.width = (obj.BAR_WIDTH * core.domStyle.scale + obj.BORDER) + "px"; statusBar.style.height = obj.outerHeight + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0) + "px"; statusBar.style.background = obj.globalAttribute.statusLeftBackground; // --- 计算文字大小 if (obj.extendToolbar) { statusBar.style.fontSize = 16 * core.domStyle.scale + "px"; } else { statusBar.style.fontSize = 16 * Math.min(1, (core._HEIGHT_ - 4) / obj.count) * core.domStyle.scale + "px"; } } statusBar.style.display = obj.extendToolbar ? 'none' : 'block'; statusBar.style.borderTop = statusBar.style.borderLeft = obj.border; statusBar.style.borderRight = core.domStyle.isVertical ? obj.border : ''; statusBar.style.borderBottom = core.domStyle.isVertical ? '' : obj.border; // 自绘状态栏 if (core.domStyle.isVertical) { core.dom.statusCanvas.style.width = core._PX_ * core.domStyle.scale + "px"; core.dom.statusCanvas.style.height = obj.statusBarHeightInVertical - 3 + "px"; core.maps._setHDCanvasSize(core.dom.statusCanvasCtx, core._PX_, obj.col * 32 + 9); } else { core.dom.statusCanvas.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px"; core.dom.statusCanvas.style.height = obj.outerHeight - 2 * obj.BORDER + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0) + "px"; core.maps._setHDCanvasSize(core.dom.statusCanvasCtx, obj.BAR_WIDTH, core._PY_ + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT + obj.BORDER : 0)); } if (core.domStyle.isVertical) { core.dom.caidan1.style.width = core._PX_ * core.domStyle.scale + "px"; core.dom.caidan1.style.height = obj.statusBarHeightInVertical - 3 + "px"; core.maps._setHDCanvasSize(core.dom.caidan1Ctx, core._PX_, obj.col * 32 + 9); } else { core.dom.caidan1.style.width = obj.BAR_WIDTH * core.domStyle.scale + "px"; core.dom.caidan1.style.height = obj.outerHeight - 2 * obj.BORDER + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0) + "px"; core.maps._setHDCanvasSize(core.dom.caidan1Ctx, obj.BAR_WIDTH, core._PY_ + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT + obj.BORDER : 0)); } core.dom.statusCanvas.style.display = core.flags.statusCanvas && !obj.extendToolbar ? "block" : "none"; } core.registerResize("statusBar", core.control._resize_statusBar); core.control._resize_gameGroup = function (obj) { var startBackground = core.domStyle.isVertical ? (main.styles.startVerticalBackground || main.styles.startBackground) : main.styles.startBackground; if (main.dom.startBackground.getAttribute('__src__') != startBackground) { main.dom.startBackground.setAttribute('__src__', startBackground); main.dom.startBackground.src = startBackground; } var gameGroup = core.dom.gameGroup; var totalWidth, totalHeight; if (core.domStyle.isVertical) { totalWidth = obj.outerWidth; totalHeight = obj.outerHeight + obj.statusBarHeightInVertical + obj.toolbarHeightInVertical } else { totalWidth = obj.outerWidth + obj.BAR_WIDTH * core.domStyle.scale + (obj.extendToolbar ? 0 : obj.BORDER); totalHeight = obj.outerHeight + (obj.extendToolbar ? obj.TOOLBAR_HEIGHT * core.domStyle.scale + obj.BORDER : 0); } gameGroup.style.width = totalWidth + "px"; gameGroup.style.height = totalHeight + "px"; gameGroup.style.left = (obj.clientWidth - totalWidth) / 2 + "px"; gameGroup.style.top = (obj.clientHeight - totalHeight) / 2 + "px"; gameGroup.style.overflow = "hidden"; var whole = core.dom.whole; whole.style.width = totalWidth + "px"; whole.style.height = totalHeight + "px"; // floorMsgGroup var floorMsgGroup = core.dom.floorMsgGroup; floorMsgGroup.style = obj.globalAttribute.floorChangingStyle; floorMsgGroup.style.width = obj.outerWidth - 2 * obj.BORDER + "px"; floorMsgGroup.style.height = totalHeight - 2 * obj.BORDER + "px"; floorMsgGroup.style.fontSize = 16 * core.domStyle.scale + "px"; // startPanel core.dom.startPanel.style.fontSize = 16 * core.domStyle.scale + "px"; // musicBtn if (core.domStyle.isVertical || core.domStyle.scale < 1) { core.dom.musicBtn.style.right = core.dom.musicBtn.style.bottom = "3px"; } else { core.dom.musicBtn.style.right = (obj.clientWidth - totalWidth) / 2 + "px"; core.dom.musicBtn.style.bottom = (obj.clientHeight - totalHeight) / 2 - 27 + "px"; } } core.registerResize("gameGroup", core.control._resize_gameGroup); core.maps._drawThumbnail_realDrawTempCanvas = function (floorId, blocks, options) { // 缩略图:背景 this.drawBg(floorId, options); // 缩略图:事件 this.drawEvents(floorId, blocks, options); // 缩略图:勇士 if (options.heroLoc) { options.heroIcon = options.heroIcon || core.status.hero.image || 'hero.png'; options.heroIcon = core.getMappedName(options.heroIcon); var icon = core.material.icons.hero[options.heroLoc.direction]; var height = core.material.images.images[options.heroIcon].height / 4; var width = (core.material.images.images[options.heroIcon].width || 128) / 4; core.drawImage(options.ctx, core.material.images.images[options.heroIcon], icon.stop * width, icon.loc * height, width, height, 32 * options.heroLoc.x + 32 - width, 32 * options.heroLoc.y + 32 - height, width, height); } // 缩略图:卷轴 if (floorId != 'nandu') core.drawImage(options.ctx, 'caidan.png', -161, 0); // 缩略图:前景 this.drawFg(floorId, options); // 缩略图:显伤 if (options.damage && core.hasItem('book')) { core.updateCheckBlock(floorId); core.control.updateDamage(floorId, options.ctx); } } core.maps._drawMap_drawAll = function (floorId, config) { floorId = floorId || core.status.floorId; this.drawBg(floorId, config); this.drawEvents(floorId); this.drawFg(floorId, config); if (floorId == "nandu") { core.maps._drawFloorImages(floorId, core.dom.wholeCtx, 'whole', null, null, (config || {}).onMap); } else core.dom.wholeCtx.clearRect(0, 0, core.dom.whole.width, core.dom.whole.height); } core.control._animationFrame_globalAnimate = function (timestamp) { if (timestamp - core.animateFrame.globalTime <= core.values.animateSpeed) return; core.status.globalAnimateStatus++; if (core.status.floorId) { // Global Animate core.status.globalAnimateObjs.forEach(function (block) { core.drawBlock(block, core.status.globalAnimateStatus); }); // Global floor images core.maps._drawFloorImages(core.status.floorId, core.canvas.bg, 'bg', core.status.floorAnimateObjs || [], core.status.globalAnimateStatus); core.maps._drawFloorImages(core.status.floorId, core.canvas.fg, 'fg', core.status.floorAnimateObjs || [], core.status.globalAnimateStatus); core.maps._drawFloorImages(core.status.floorId, core.dom.wholeCtx, 'whole', core.status.floorAnimateObjs || [], core.status.globalAnimateStatus); // Global Autotile Animate core.status.autotileAnimateObjs.forEach(function (block) { core.maps._drawAutotileAnimate(block, core.status.globalAnimateStatus); }); // Global hero animate if ((core.status.hero || {}).animate && core.status.heroMoving == 0 && main.mode == 'play' && !core.status.preview.enabled) { core.drawHero('stop', null, core.status.globalAnimateStatus); } } // Box animate core.drawBoxAnimate(); core.animateFrame.globalTime = timestamp; } core.control.registerAnimationFrame("globalAnimate", true, core.control._animationFrame_globalAnimate); core.ui.createCanvas2 = function (name, x, y, width, height, z) { // 如果画布已存在则直接调用 if (core.dymCanvas[name]) { core.deleteCanvas(name); } var newCanvas = document.createElement("canvas"); newCanvas.id = name; newCanvas.style.display = 'block'; newCanvas.setAttribute("_left", x); newCanvas.setAttribute("_top", y); newCanvas.style.width = width * core.domStyle.scale + 'px'; newCanvas.style.height = height * core.domStyle.scale + 'px'; newCanvas.style.left = x * core.domStyle.scale + 'px'; newCanvas.style.top = y * core.domStyle.scale + 'px'; newCanvas.style.zIndex = z; newCanvas.style.position = 'absolute'; newCanvas.style.pointerEvents = 'none'; core.dymCanvas[name] = newCanvas.getContext('2d'); core.maps._setHDCanvasSize(core.dymCanvas[name], width, height); core.dom.gameGroup.appendChild(newCanvas); return core.dymCanvas[name]; } core.ui.deleteCanvas = function (name) { if (name instanceof Function) { Object.keys(core.dymCanvas).forEach(function (one) { if (name(one)) core.deleteCanvas(one); }); return; } if (!core.dymCanvas[name]) return null; var temp = core.dymCanvas[name].canvas.parentElement.id; if (temp == "gameDraw") core.dom.gameDraw.removeChild(core.dymCanvas[name].canvas); if (temp == "gameGroup") core.dom.gameGroup.removeChild(core.dymCanvas[name].canvas); delete core.dymCanvas[name]; } core.events.showImage2 = function (code, image, sloc, loc, opacityVal, time, callback) { var imageName = null; if (typeof image == 'string') { imageName = image; if (image.endsWith(':x') || image.endsWith(':y') || image.endsWith(':o')) { image = image.substring(0, image.length - 2); } image = core.getMappedName(image); image = core.material.images.images[image]; } if (!image) { if (callback) callback(); return; } sloc = sloc || []; var sx = core.calValue(sloc[0]) || 0, sy = core.calValue(sloc[1]) || 0; var sw = core.calValue(sloc[2]), sh = core.calValue(sloc[3]); if (sw == null) sw = image.width; if (sh == null) sh = image.height; loc = loc || []; var x = core.calValue(loc[0]) || 0, y = core.calValue(loc[1]) || 0; var w = core.calValue(loc[2]), h = core.calValue(loc[3]); if (w == null) w = sw; if (h == null) h = sh; var zIndex = code + 100; time = time || 0; var name = "image" + zIndex; var ctx = core.ui.createCanvas2(name, x, y, w, h, zIndex); core.drawImage(ctx, imageName == null ? image : imageName, sx, sy, sw, sh, 0, 0, w, h); if (time == 0) { core.setOpacity(name, opacityVal); if (callback) callback(); return; } core.setOpacity(name, 0); this.moveImage(code, null, opacityVal, null, time, callback); } core.events._action_showImage2 = function (data, x, y, prefix) { if (core.isReplaying()) data.time = 0; this.__action_doAsyncFunc(data.async || data.time == 0, core.events.showImage2, data.code, data.image + (data.reverse || ''), data.sloc, data.loc, data.opacity, data.time); } core.ui._drawCenterFly = function () { core.lockControl(); core.status.event.id = 'centerFly'; var fillstyle = 'rgba(255,0,0,0.5)'; if (core.canUseItem('centerFly')) fillstyle = 'rgba(0,255,0,0.5)'; var toX = core.bigmap.width - 1 - core.getHeroLoc('x'), toY = core.bigmap.height - 3 - core.getHeroLoc('y'); this.clearUI(); core.fillRect('ui', 0, 0, core._PX_, core._PY_, '#000000'); core.drawThumbnail(null, null, { heroLoc: core.status.hero.loc, heroIcon: core.status.hero.image, ctx: 'ui', centerX: toX, centerY: toY }); var offsetX = core.clamp(toX - core._HALF_WIDTH_, 0, core.bigmap.width - core._WIDTH_), offsetY = core.clamp(toY - core._HALF_HEIGHT_, 0, core.bigmap.height - core._HEIGHT_); core.fillRect('ui', (toX - offsetX) * 32, (toY - offsetY) * 32, 32, 32, fillstyle); core.status.event.data = { "x": toX, "y": toY, "posX": toX - offsetX, "posY": toY - offsetY }; core.playSound('打开界面'); core.drawTip("请确认当前" + core.material.items['centerFly'].name + "的位置", 'centerFly'); return; } core.control.setAutomaticRoute = function (destX, destY, stepPostfix) { if (!core.status.played || core.status.lockControl) return; if (this._setAutomaticRoute_isMoving(destX, destY)) return; if (this._setAutomaticRoute_isTurning(destX, destY, stepPostfix)) return; if (this._setAutomaticRoute_clickMoveDirectly(destX, destY, stepPostfix)) return; // 找寻自动寻路路线 if (destY == 13 || destY == 14) { if (destX == 2 || destX == 3) { destY == 13 ? core.openBook(true) : core.ui._drawHelp(); } if (destX == 4 || destX == 5) { destY == 13 ? core.useFly(true) : core.turnHero(); } if (destX == 6 || destX == 7 || destX == 8) { destY == 13 ? core.openToolbox(true) : core.openQuickShop(true); } if (destX == 9 || destX == 10) { destY == 13 ? core.save(true) : core.openSettings(true); } if (destX == 11 || destX == 12) { destY == 13 ? core.load(true) : core.openSettings(true); } return; } var moveStep = core.automaticRoute(destX, destY); if (moveStep.length == 0 && (destX != core.status.hero.loc.x || destY != core.status.hero.loc.y || stepPostfix.length == 0)) return; moveStep = moveStep.concat(stepPostfix); core.status.automaticRoute.destX = destX; core.status.automaticRoute.destY = destY; this._setAutomaticRoute_drawRoute(moveStep); this._setAutomaticRoute_setAutoSteps(moveStep); // 立刻移动 core.setAutoHeroMove(); } ////// 绘制一个对话框 ////// core.ui.drawTextBox = function (content, config) { config = config || {}; this.clearUI(); content = core.replaceText(content); let ctx = core.getContextByName(config.ctx || 'ui'); if (ctx && main.mode == 'play') { core.createCanvas(ctx, 0, 0, core._PX_, core._PY_, 141); ctx = core.getContextByName(ctx); } // Step 1: 获得标题信息和位置信息 var textAttribute = core.status.textAttribute; var titleInfo = this._getTitleAndIcon(content); var posInfo = this._getPosition(titleInfo.content); if (posInfo.position != 'up' && posInfo.position != 'down') posInfo.px = posInfo.py = null; if (!posInfo.position) posInfo.position = textAttribute.position; content = this._drawTextBox_drawImages(posInfo.content, config.ctx); if (config.pos) { delete posInfo.px; delete posInfo.py; posInfo.pos = config.pos; } posInfo.ctx = ctx; // Step 2: 计算对话框的矩形位置 var hPos = this._drawTextBox_getHorizontalPosition(content, titleInfo, posInfo); var vPos = this._drawTextBox_getVerticalPosition(content, titleInfo, posInfo, hPos.validWidth); posInfo.xoffset = hPos.xoffset; posInfo.yoffset = vPos.yoffset - 4; if (ctx && main.mode == 'play') { ctx.canvas.setAttribute('_text_left', hPos.left); ctx.canvas.setAttribute('_text_top', vPos.top); } // Step 3: 绘制背景图 var isWindowSkin = this.drawBackground(hPos.left, vPos.top, hPos.right, vPos.bottom, posInfo); if (titleInfo.title) { let titlefont = core.status.textAttribute.titlefont, titleStyle = core.arrayToRGBA(core.status.textAttribute.title); let tf = this._buildFont(titlefont, true), width = this.calWidth(ctx, titleInfo.title, tf); this.drawBackground(hPos.left, vPos.top - titlefont - 12, hPos.left + width + 30, vPos.top, posInfo); ctx.save(); ctx.textAlign = 'center'; ctx.textBaseline = 'middle'; core.fillText(ctx, titleInfo.title, hPos.left + (width + 30) / 2, vPos.top - (titlefont + 12) / 2, titleStyle, tf); ctx.restore(); } titleInfo.title = null; var alpha = isWindowSkin ? this._drawWindowSkin_getOpacity() : textAttribute.background[3]; // Step 4: 绘制标题、头像、动画 var content_top = this._drawTextBox_drawTitleAndIcon(titleInfo, hPos, vPos, alpha, config.ctx); // Step 5: 绘制正文 var config = this.drawTextContent(config.ctx || 'ui', content, { left: hPos.content_left, top: content_top, maxWidth: hPos.validWidth, lineHeight: vPos.lineHeight, time: (config.showAll || config.async || textAttribute.time <= 0 || core.status.event.id != 'action') ? 0 : textAttribute.time }); // Step 6: 绘制光标 if (main.mode == 'play') { main.dom.next.style.display = 'block'; main.dom.next.style.borderRightColor = main.dom.next.style.borderBottomColor = core.arrayToRGB(textAttribute.text); main.dom.next.style.top = (vPos.bottom - 20) * core.domStyle.scale + "px"; var left = (hPos.left + hPos.right) / 2; if (posInfo.position == 'up' && !posInfo.noPeak && posInfo.px != null && Math.abs(posInfo.px * 32 + 16 - left) < 50) left = hPos.right - 64; main.dom.next.style.left = left * core.domStyle.scale + "px"; } return config; } core.ui._drawSettings = function () { core.status.event.id = 'settings'; this.drawChoices(null, [ "系统设置", "虚拟键盘", "浏览地图", "存档笔记", "同步存档", "游戏信息", "返回标题", "返回游戏", "数值显示: " + (core.getFlag("itemDetail") ? "[ON]" : "[OFF]"), "RM样式楼传: " + (core.getFlag("isRmFly") ? "[ON]" : "[OFF]") ]); } core.actions._clickSettings = function (x, y) { if (this._out(x)) return; var choices = core.status.event.ui.choices; var topIndex = this._getChoicesTopIndex(choices.length); if (y >= topIndex && y < topIndex + choices.length) { var selection = y - topIndex; core.status.event.selection = selection; switch (selection) { case 0: core.status.event.selection = 0; core.playSound('确定'); core.ui._drawSwitchs(); break; case 1: // core.playSound('确定'); core.ui._drawKeyBoard(); break; case 2: // core.playSound('确定'); core.clearUI(); core.ui._drawViewMaps(); break; case 3: core.status.event.selection = 0; core.playSound('确定'); core.ui._drawNotes(); break; case 4: core.status.event.selection = 0; core.playSound('确定'); core.ui._drawSyncSave(); break; case 5: core.status.event.selection = 0; core.playSound('确定'); core.ui._drawGameInfo(); break; case 6: return core.confirmRestart(); case 7: core.playSound('取消'); core.ui.closePanel(); break; case 8: core.playSound('确定'); core.setFlag("itemDetail", !core.getFlag("itemDetail")); core.getItemDetail(); core.ui.closePanel(); break; case 9: core.playSound('确定'); core.setFlag("isRmFly", !core.getFlag("isRmFly")); core.ui.closePanel(); break; } } return; } ////// 获得某个物品 ////// core.events.getItem = function (id, num, x, y, isGentleClick, callback) { if (num == null) num = 1; var itemCls = core.material.items[id].cls; core.removeBlock(x, y); core.items.getItemEffect(id, num); var text = '获得 ' + core.material.items[id].name; if (num > 1) text += "x" + num; if (itemCls === 'items' && num == 1) text += core.items.getItemEffectTip(id); core.drawTip(text, id); // --- 首次获得道具的提示 if (!core.hasFlag("__itemHint__")) core.setFlag("__itemHint__", []); var itemHint = core.getFlag("__itemHint__"); if (core.flags.itemFirstText && itemHint.indexOf(id) < 0 && itemCls != 'items') { var hint = core.material.items[id].text || "该道具暂无描述"; try { hint = core.replaceText(hint); } catch (e) {} if (!core.status.event.id || core.status.event.id == 'action') { //core.insertAction("\t[" + core.material.items[id].name + "," + id + "]\b[center]" + hint + "\n" //+ // (id.endsWith('Key') ? "(钥匙类道具,遇到对应的门时自动打开)" : // itemCls == 'tools' ? "(消耗类道具,请按T在道具栏使用)" : // itemCls == 'constants' ? "(永久类道具,请按T在道具栏使用)" : // itemCls == 'equips' ? "(装备类道具,请按Q在装备栏进行装备)" : "")); core.insertAction("\b[center]\\c[32]\\i[" + id + "]\\c[22]" + core.material.items[id].name + '\n\n' + hint + "\n"); } itemHint.push(id); } this.afterGetItem(id, x, y, isGentleClick); if (callback) callback(); } core.enemys.getDamageString = function (enemy, x, y, floorId) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; var damage = this.getDamage(enemy, x, y, floorId); var color = '#000000'; if (damage == null) { damage = "???"; color = '#FF2222'; } else { if (damage < 0) color = '#11FF11'; else if (damage == 0) color = '#FFFFFF'; else if (damage < core.status.hero.hp / 3) color = '#FFFF00'; else if (damage < core.status.hero.hp * 2 / 3) color = '#FF9933'; 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 += "^"; } return { "damage": damage, "color": color }; } core.ui._drawBook_drawBackground = function () { core.setAlpha('ui', 1); //core.setFillStyle('ui', '#000000'); //core.fillRect('ui', 0, 0, core._PX_, core._PY_);删除绘制的黑底 core.createCanvas('bookBg', 0, 0, 480, 480, 138); ///创建一个动态画布用于绘制手册bg core.drawWindowSkin('winskin.png', 'bookBg', 0, 0, core._PX_, core._PY_); } ui.prototype._drawBook_drawOne = function (floorId, index, enemy, pageinfo, selected) { var top = pageinfo.per_height * index + pageinfo.padding_top; // 最上面margin默认是12px enemy.floorId = floorId; // 横向规划: // 22 + 42 = 64 是头像框 this._drawBook_drawBox(index, enemy, top, pageinfo); var left = 64, total_width = core._PX_ - left; var name_width = total_width * 10 / 35; this._drawBook_drawName(index, enemy, top, left, name_width); this._drawBook_drawContent(index, enemy, top, left + name_width); if (selected) core.drawUIEventSelector(1, 'winskin.png', 10, top + 1, core._PX_ - 10 * 2, pageinfo.per_height, 139); ////绘制光标 //core.strokeRoundRect('ui', 10, top + 1, core._PX_ - 10 * 2, pageinfo.per_height, 10, core.status.globalAttribute.selectColor);取消原本的黄色框框 } ui.prototype._drawBook_drawBox = function (index, enemy, top, pageinfo) { // 横向:22+42;纵向:10 + 42 + 10(正好居中);内部图像 32x32 var border_top = top + (pageinfo.per_height - 42) / 2, border_left = 22; var img_top = border_top + 5, img_left = border_left + 5; //core.strokeRect('ui', 22, border_top, 42, 42, '#DDDDDD', 2); //删除怪物边框 var blockInfo = core.getBlockInfo(enemy.id); core.drawIcon('ui', enemy.id, 22 + 5, border_top + 5, 32, 32) ///取消用动画的绘制,改用图标绘制 } ui.prototype._drawBook_drawName = function (index, enemy, top, left, width) { // 绘制第零列(名称和特殊属性) // 如果需要添加自己的比如怪物的称号等,也可以在这里绘制 core.setTextAlign('ui', 'center'); if (enemy.specialText.length == 0) { core.fillText('ui', enemy.name, left + width / 2, top + 35, '#ffffff', this._buildFont(enemy.name.length >= 5 ? 18 : 20, false), width); /////修改怪物名字的颜色,取消加粗 } else { core.fillText('ui', enemy.name, left + width / 2, top + 28, '#ffffff', this._buildFont(enemy.name.length >= 5 ? 18 : 20, false), width); /////修改怪物名字颜色,取消加粗 switch (enemy.specialText.length) { case 1: core.fillText('ui', enemy.specialText[0][0] + ' ' + enemy.specialText[0][1], left + width / 2, ////单属性两个字中间空一格 top + 50, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A'), this._buildFont(20, false), width); ////调大怪物字号,取消加粗 break; case 2: // Step 1: 计算字体 var text = enemy.specialText[0] + "" + enemy.specialText[1]; ///减少空格 core.setFontForMaxWidth('ui', text, width, this._buildFont(20, false)); ////调大怪物属性的字号,取消加粗 // Step 2: 计算总宽度 var totalWidth = core.calWidth('ui', text); var leftWidth = core.calWidth('ui', enemy.specialText[0]); var rightWidth = core.calWidth('ui', enemy.specialText[1]); // Step 3: 绘制 core.fillText('ui', enemy.specialText[0], left + (width + leftWidth - totalWidth) / 2, top + 50, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A')); core.fillText('ui', enemy.specialText[1], left + (width + totalWidth - rightWidth) / 2, top + 50, core.arrayToRGBA((enemy.specialColor || [])[1] || '#FF6A6A')); break; default: core.fillText('ui', '多属性...', left + width / 2, top + 50, '#FF6A6A', this._buildFont(15, true), width); } } } ui.prototype._drawBook_drawRow1 = function (index, enemy, top, left, width, position) { // 绘制第一行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; var colour = '#80ffff'; ////单数行颜色 if (index % 2 === 0) colour = '#80ff80'; ////双数行颜色 core.fillText('ui', core.getStatusLabel('hp'), col1, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.hp || 0), col1 + 30, position, null, b13); core.fillText('ui', core.getStatusLabel('atk'), col2, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.atk || 0), col2 + 30, position, null, b13); core.fillText('ui', core.getStatusLabel('def'), col3, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.def || 0), col3 + 30, position, null, b13); } ui.prototype._drawBook_drawRow2 = function (index, enemy, top, left, width, position) { // 绘制第二行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; var colour = '#80ffff'; ////单数行颜色 if (index % 2 === 0) colour = '#80ff80'; ////双数行颜色 // 获得第二行绘制的内容 var second_line = []; if (core.flags.statusBarItems.indexOf('enableMoney') >= 0) second_line.push([core.getStatusLabel('money'), core.formatBigNumber(enemy.money || 0)]); if (core.flags.enableAddPoint) second_line.push([core.getStatusLabel('point'), core.formatBigNumber(enemy.point || 0)]); if (core.flags.statusBarItems.indexOf('enableExp') >= 0) second_line.push([core.getStatusLabel('exp'), core.formatBigNumber(enemy.exp || 0)]); var damage_offset = col1 + (core._PX_ - col1) / 2 - 12; // 第一列 if (second_line.length > 0) { var one = second_line.shift(); core.fillText('ui', one[0], col1, position, colour, f13); core.fillText('ui', one[1], col1 + 30, position, colour, b13); damage_offset = col2 + (core._PX_ - col2) / 2 - 12; } // 第二列 if (second_line.length > 0) { var one = second_line.shift(); core.fillText('ui', one[0], col2, position, colour, f13); core.fillText('ui', one[1], col2 + 30, position, colour, b13); damage_offset = col3 + (core._PX_ - col3) / 2 - 12; } // 忽略第三列,直接绘制伤害 core.fillText('ui', '伤害', col3, position, colour, f13); ////增加绘制伤害两字 this._drawBook_drawDamage(index, enemy, damage_offset, position); } ui.prototype._drawBook_drawRow3 = function (index, enemy, top, left, width, position) { // 绘制第三行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; var colour = '#80ffff'; ////单数行颜色 if (index % 2 === 0) colour = '#80ff80'; ////双数行颜色 core.fillText('ui', '临界', col1, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.critical || 0), col1 + 30, position, colour, b13); core.fillText('ui', '减伤', col2, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.criticalDamage || 0), col2 + 30, position, colour, b13); core.fillText('ui', '加防', col3, position, colour, f13); core.fillText('ui', core.formatBigNumber(enemy.defDamage || 0), col3 + 30, position, colour, b13); } ui.prototype._drawBook_drawDamage = function (index, enemy, offset, position) { //////修改了颜色 offset -= 5; //往左移5像素 //core.setTextAlign('ui', 'center');取消居中对齐 var damage = enemy.damage, color = '#e6de0d'; if (damage == null) { damage = '????'; ////////无法战斗怪物手册中改为????显示 color = '#ff8080'; } else { if (damage >= core.status.hero.hp) color = '#ff8080'; else if (damage >= core.status.hero.hp * 2 / 3) color = '#ffc080'; else if (damage <= 0) color = '#ffffff'; damage = core.formatBigNumber(damage); if (core.enemys.hasSpecial(enemy, 19)) damage += "+"; if (core.enemys.hasSpecial(enemy, 21)) damage += "-"; if (core.enemys.hasSpecial(enemy, 11)) damage += "^"; } if (enemy.notBomb) damage += "[b]"; core.fillText('ui', damage, offset, position, color, this._buildFont(13, true)); } ////// 绘制怪物属性的详细信息 ////// ui.prototype._drawBookDetail = function (index) { var info = this._drawBookDetail_getInfo(index), enemy = info[0]; if (!enemy) return; var content = info[1].join("\n"); core.status.event.id = 'book-detail'; core.animateFrame.tip = null; core.clearMap('data'); var left = 10, width = core._PX_ - 2 * left, right = left + width; var content_left = left + 25, validWidth = right - content_left - 13; var height = Math.max(this.getTextContentHeight(content, { fontSize: 16, lineHeight: 24, maxWidth: validWidth }) + 58, 80), top = (core._PY_ - height) / 2, bottom = top + height; core.drawWindowSkin('winskin.png', 'data', left, top, width, height); ////用winskin绘制一个对话框 /// core.setAlpha('data', 0.9);///注销原本的黑底边框 ///core.fillRect('data', left, top, width, height, '#000000'); // core.setAlpha('data', 1); // core.strokeRect('data', left - 1, top - 1, width + 1, height + 1, // core.arrayToRGBA(core.status.globalAttribute.borderColor), 2); core.playSound('确定'); this._drawBookDetail_drawContent(enemy, content, { top: top, content_left: content_left, bottom: bottom, validWidth: validWidth }); } ////// 结束一切事件和绘制,关闭UI窗口,返回游戏进程 ////// ui.prototype.closePanel = function () { core.clearMap('bookBg'); ////清空手册Bg core.clearMap('itemBg'); ////清空道具栏Bg core.clearMap('flyText'); ////清空fly对话框 core.clearUIEventSelector(1); ////清除绘制的光标 core.clearUIEventSelector(2); if (core.status.hero && core.status.hero.flags) { // 清除全部临时变量 Object.keys(core.status.hero.flags).forEach(function (name) { if (name.startsWith("@temp@") || /^arg\d+$/.test(name)) { delete core.status.hero.flags[name]; } }); } this.clearUI(); core.maps.generateGroundPattern(); core.updateStatusBar(true); core.unlockControl(); core.status.event.data = null; core.status.event.id = null; core.status.event.selection = null; core.status.event.ui = null; core.status.event.interval = null; // 清除onDownInterval clearInterval(core.interval.onDownInterval); core.interval.onDownInterval = 'tmp'; } ui.prototype._drawToolbox_drawBackground = function () { // 绘制 core.clearMap('ui'); /// core.setAlpha('ui', 0.85); /// core.fillRect('ui', 0, 0, core._PX_, core._PY_, '#000000'); core.createCanvas('itemBg', 0, 0, 480, 480, 138); ///创建一个动态画布用于绘制道具栏bg core.drawWindowSkin('winskin.png', 'itemBg', 0, 0, core._PX_, core._PY_ - 306); ///道具栏背景用winskin绘制 core.drawWindowSkin('winskin.png', 'itemBg', 0, core._PY_ - 306 - 20, core._PX_, core._PY_ - 306); core.drawWindowSkin('winskin.png', 'itemBg', 0, core._PY_ - 146 - 30, core._PX_, core._PY_ - 306); } ////// 绘制道具栏 ////// ui.prototype._drawToolbox = function (index) { var info = this._drawToolbox_getInfo(index); this._drawToolbox_drawBackground(); // 绘制线 core.setAlpha('ui', 1); core.setStrokeStyle('ui', '#DDDDDD'); core.canvas.ui.lineWidth = 2; core.canvas.ui.strokeWidth = 2; core.setTextAlign('ui', 'right'); var line1 = core._PY_ - 306; // this._drawToolbox_drawLine(line1, "消耗道具"); var line2 = core._PY_ - 146; // this._drawToolbox_drawLine(line2, "永久道具"); this._drawToolbox_drawDescription(info, line1); this._drawToolbox_drawContent(info, line1, info.tools, info.toolsPage, true); this.drawPagination(info.toolsPage, info.toolsTotalPage, core._HEIGHT_ - 6); this._drawToolbox_drawContent(info, line2, info.constants, info.constantsPage); this.drawPagination(info.constantsPage, info.constantsTotalPage); core.setTextAlign('ui', 'center'); core.fillText('ui', '[装备栏]', core._PX_ - 46, 25, '#DDDDDD', this._buildFont(15, true)); core.fillText('ui', '返回游戏', core._PX_ - 46, core._PY_ - 13); } ui.prototype._drawToolbox_drawDescription = function (info, max_height) { core.setTextAlign('ui', 'left'); if (!info.selectId) return; var item = core.material.items[info.selectId]; var name = item.name || "未知道具"; try { name = core.replaceText(name); } catch (e) {} core.fillText('ui', name, 10 + 10, 32 + 10, "#ffffff", this._buildFont(20, true)); core.drawUIEventSelector(2, 'winskin.png', 15, 32 - 10, 25 * name.length || 0, 30, 139); var text = item.text || "该道具暂无描述。"; try { text = core.replaceText(text); } catch (e) {} var height = null; for (var fontSize = 20; fontSize >= 9; fontSize -= 2) { var config = { left: 10 + 10, top: 46 + 20, fontSize: fontSize, maxWidth: core._PX_ - 15, bold: true, color: "white" }; height = 42 + core.getTextContentHeight(text, config); if (height < max_height || fontSize == 9) { core.drawTextContent('ui', text, config); break; } } if (height < max_height - 33) { core.fillText('ui', '<继续点击该道具即可进行使用>', 10 + 10, max_height - 15 - 10, '#CCCCCC', this._buildFont(14, false)); } } ////// 点击工具栏时的打开操作 ////// events.prototype.openToolbox = function (fromUserAction) { if (core.isReplaying()) return; if (!this._checkStatus('toolbox', fromUserAction)) return; core.playSound('打开界面'); core.updateStatusBar(); ///更新状态栏以绘制工具栏时的状态栏背景 core.ui._drawToolbox(); } ui.prototype._drawToolbox_drawContent = function (info, line, items, page, drawCount) { var n = core._HALF_WIDTH_; core.setTextAlign('ui', 'right'); for (var i = 0; i < core._WIDTH_ - 1; i++) { var item = items[(core._WIDTH_ - 1) * (page - 1) + i]; if (!item) continue; var yoffset = line + 54 * Math.floor(i / n) + 19; var icon = core.material.icons.items[item], image = core.material.images.items; core.drawImage('ui', image, 0, 32 * icon, 32, 32, 64 * (i % n) + 21, yoffset, 32, 32); if (drawCount) core.fillText('ui', core.itemCount(item), 64 * (i % n) + 56, yoffset + 33, '#FFFFFF', this._buildFont(14, true)); if (info.selectId == item) core.drawUIEventSelector(1, 'winskin.png', 64 * (i % n) + 17, yoffset - 4, 40, 40, 139); ////绘制光标 //core.strokeRoundRect('ui', 64 * (i % n) + 17, yoffset - 4, 40, 40, 6, core.status.globalAttribute.selectColor);删除原本绘制的黄色边框 } } /*core.ui.drawFly = function (page) {/////已在别处(仿RM楼传)复写 core.status.event.data = page; var floorId = core.floorIds[page]; var title = core.status.maps[floorId].title; core.clearMap('ui'); core.setAlpha('ui', 0.85); core.fillRect('ui', 0, 0, core._PX_, core._PY_, '#000000'); core.setAlpha('ui', 1); core.setTextAlign('ui', 'center'); core.fillText('ui', '楼层跳跃', core._PX_ / 2, 48, '#FFFFFF', this._buildFont(28, true)); core.fillText('ui', '返回游戏', core._PX_ / 2, core._PY_ - 13, null, this._buildFont(15, true)) core.setTextAlign('ui', 'right'); core.fillText('ui', '浏览地图时也', core._PX_ - 10, core._PY_ - 23, '#aaaaaa', this._buildFont(10, false)); core.fillText('ui', '可楼层跳跃!', core._PX_ - 10, core._PY_ - 11, null, this._buildFont(10, false)); core.setTextAlign('ui', 'center'); var middle = core._PY_ / 2 + 39; // 换行 var lines = core.splitLines('ui', title, 120, this._buildFont(19, true)); var start_y = middle - (lines.length - 1) * 11; for (var i in lines) { core.fillText('ui', lines[i], core._PX_ - 53, start_y, '#FFFFFF', this._buildFont(17, true)); start_y += 22; } if (core.actions._getNextFlyFloor(1) != page) { core.fillText('ui', '▲', core._PX_ - 60, middle - 64, null, this._buildFont(17, false)); core.fillText('ui', '▲', core._PX_ - 60, middle - 96); core.fillText('ui', '▲', core._PX_ - 60, middle - 96 - 7); } if (core.actions._getNextFlyFloor(-1) != page) { core.fillText('ui', '▼', core._PX_ - 60, middle + 64, null, this._buildFont(17, false)); core.fillText('ui', '▼', core._PX_ - 60, middle + 96); core.fillText('ui', '▼', core._PX_ - 60, middle + 96 + 7); } var size = 0.75; core.strokeRect('ui', 16, 64, size * core._PX_, size * core._PY_, '#FFFFFF', 2); core.drawThumbnail(floorId, null, { ctx: 'ui', x: 16, y: 64, size: size, damage: true, all: true }); }*/ }, "drawLight": function () { // 绘制灯光/漆黑层效果。调用方式 core.plugin.drawLight(...) // 【参数说明】 // name:必填,要绘制到的画布名;可以是一个系统画布,或者是个自定义画布;如果不存在则创建 // color:可选,只能是一个0~1之间的数,为不透明度的值。不填则默认为0.9。 // lights:可选,一个数组,定义了每个独立的灯光。 // 其中每一项是三元组 [x,y,r] x和y分别为该灯光的横纵坐标,r为该灯光的半径。 // lightDec:可选,0到1之间,光从多少百分比才开始衰减(在此范围内保持全亮),不设置默认为0。 // 比如lightDec为0.5代表,每个灯光部分内圈50%的范围全亮,50%以后才开始快速衰减。 // 【调用样例】 // core.plugin.drawLight('curtain'); // 在curtain层绘制全图不透明度0.9,等价于更改画面色调为[0,0,0,0.9]。 // core.plugin.drawLight('ui', 0.95, [[25,11,46]]); // 在ui层绘制全图不透明度0.95,其中在(25,11)点存在一个半径为46的灯光效果。 // core.plugin.drawLight('test', 0.2, [[25,11,46,0.1]]); // 创建一个test图层,不透明度0.2,其中在(25,11)点存在一个半径为46的灯光效果,灯光中心不透明度0.1。 // core.plugin.drawLight('test2', 0.9, [[25,11,46],[105,121,88],[301,221,106]]); // 创建test2图层,且存在三个灯光效果,分别是中心(25,11)半径46,中心(105,121)半径88,中心(301,221)半径106。 // core.plugin.drawLight('xxx', 0.3, [[25,11,46],[105,121,88,0.2]], 0.4); // 存在两个灯光效果,它们在内圈40%范围内保持全亮,40%后才开始衰减。 this.drawLight = function (name, color, lights, lightDec) { // 清空色调层;也可以修改成其它层比如animate/weather层,或者用自己创建的canvas var ctx = core.getContextByName(name); if (ctx == null) { if (typeof name == 'string') ctx = core.createCanvas(name, 0, 0, core._PX_ || core.__PIXELS__, core._PY_ || core.__PIXELS__, 98); else return; } ctx.mozImageSmoothingEnabled = false; ctx.webkitImageSmoothingEnabled = false; ctx.msImageSmoothingEnabled = false; ctx.imageSmoothingEnabled = false; core.clearMap(name); // 绘制色调层,默认不透明度 if (color == null) color = 0.9; ctx.fillStyle = "rgba(0,0,0," + color + ")"; ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height); lightDec = core.clamp(lightDec, 0, 1); // 绘制每个灯光效果 ctx.globalCompositeOperation = 'destination-out'; lights.forEach(function (light) { // 坐标,半径,中心不透明度 var x = light[0], y = light[1], r = light[2]; // 计算衰减距离 var decDistance = parseInt(r * lightDec); // 正方形区域的直径和左上角坐标 var grd = ctx.createRadialGradient(x, y, decDistance, x, y, r); grd.addColorStop(0, "rgba(0,0,0,1)"); grd.addColorStop(1, "rgba(0,0,0,0)"); ctx.beginPath(); ctx.fillStyle = grd; ctx.arc(x, y, r, 0, 2 * Math.PI); ctx.fill(); }); ctx.globalCompositeOperation = 'source-over'; // 可以在任何地方(如afterXXX或自定义脚本事件)调用函数,方法为 core.plugin.xxx(); } }, "shop": function () { // 【全局商店】相关的功能 // // 打开一个全局商店 // shopId:要打开的商店id;noRoute:是否不计入录像 this.openShop = function (shopId, noRoute) { var shop = core.status.shops[shopId]; // Step 1: 检查能否打开此商店 if (!this.canOpenShop(shopId)) { core.drawTip("该商店尚未开启"); return false; } // Step 2: (如有必要)记录打开商店的脚本事件 if (!noRoute) { core.status.route.push("shop:" + shopId); } // Step 3: 检查道具商店 or 公共事件 if (shop.item) { if (core.openItemShop) { core.openItemShop(shopId); } else { core.playSound('操作失败'); core.insertAction("道具商店插件不存在!请检查是否存在该插件!"); } return; } if (shop.commonEvent) { core.insertCommonEvent(shop.commonEvent, shop.args); return; } _shouldProcessKeyUp = true; // Step 4: 执行标准公共商店 core.insertAction(this._convertShop(shop)); return true; } ////// 将一个全局商店转变成可预览的公共事件 ////// this._convertShop = function (shop) { return [ { "type": "function", "function": "function() {core.addFlag('@temp@shop', 1);}" }, { "type": "while", "condition": "true", "data": [ // 检测能否访问该商店 { "type": "if", "condition": "core.isShopVisited('" + shop.id + "')", "true": [ // 可以访问,直接插入执行效果 { "type": "function", "function": "function() { core.plugin._convertShop_replaceChoices('" + shop.id + "', false) }" }, ], "false": [ // 不能访问的情况下:检测能否预览 { "type": "if", "condition": shop.disablePreview, "true": [ // 不可预览,提示并退出 { "type": "playSound", "name": "操作失败" }, "当前无法访问该商店!", { "type": "break" }, ], "false": [ // 可以预览:将商店全部内容进行替换 { "type": "tip", "text": "当前处于预览模式,不可购买" }, { "type": "function", "function": "function() { core.plugin._convertShop_replaceChoices('" + shop.id + "', true) }" }, ] } ] } ] }, { "type": "function", "function": "function() {core.addFlag('@temp@shop', -1);}" } ]; } this._convertShop_replaceChoices = function (shopId, previewMode) { var shop = core.status.shops[shopId]; var choices = (shop.choices || []).filter(function (choice) { if (choice.condition == null || choice.condition == '') return true; try { return core.calValue(choice.condition); } catch (e) { return true; } }).map(function (choice) { var ableToBuy = core.calValue(choice.need); return { "text": choice.text, "icon": choice.icon, "color": ableToBuy && !previewMode ? choice.color : [153, 153, 153, 1], "action": ableToBuy && !previewMode ? [{ "type": "playSound", "name": "商店" }].concat(choice.action) : [ { "type": "playSound", "name": "操作失败" }, { "type": "tip", "text": previewMode ? "预览模式下不可购买" : "购买条件不足" } ] }; }).concat({ "text": "离开", "action": [{ "type": "playSound", "name": "取消" }, { "type": "break" }] }); core.insertAction({ "type": "choices", "text": shop.text, "choices": choices }); } /// 是否访问过某个快捷商店 this.isShopVisited = function (id) { if (!core.hasFlag("__shops__")) core.setFlag("__shops__", {}); var shops = core.getFlag("__shops__"); if (!shops[id]) shops[id] = {}; return shops[id].visited; } /// 当前应当显示的快捷商店列表 this.listShopIds = function () { return Object.keys(core.status.shops).filter(function (id) { return core.isShopVisited(id) || !core.status.shops[id].mustEnable; }); } /// 是否能够打开某个商店 this.canOpenShop = function (id) { if (this.isShopVisited(id)) return true; var shop = core.status.shops[id]; if (shop.item || shop.commonEvent || shop.mustEnable) return false; return true; } /// 启用或禁用某个快捷商店 this.setShopVisited = function (id, visited) { if (!core.hasFlag("__shops__")) core.setFlag("__shops__", {}); var shops = core.getFlag("__shops__"); if (!shops[id]) shops[id] = {}; if (visited) shops[id].visited = true; else delete shops[id].visited; } /// 能否使用快捷商店 this.canUseQuickShop = function (id) { // 如果返回一个字符串,表示不能,字符串为不能使用的提示 // 返回null代表可以使用 // 检查当前楼层的canUseQuickShop选项是否为false if (core.status.thisMap.canUseQuickShop === false) return '当前楼层不能使用快捷商店。'; return null; } var _shouldProcessKeyUp = true; /// 允许商店X键退出 core.registerAction('keyUp', 'shops', function (keycode) { if (!core.status.lockControl || core.status.event.id != 'action') return false; if ((keycode == 13 || keycode == 32) && !_shouldProcessKeyUp) { _shouldProcessKeyUp = true; return true; } if (!core.hasFlag("@temp@shop") || core.status.event.data.type != 'choices') return false; var data = core.status.event.data.current; var choices = data.choices; var topIndex = core.actions._getChoicesTopIndex(choices.length); if (keycode == 88 || keycode == 27) { // X, ESC core.actions._clickAction(core._HALF_WIDTH_ || core.__HALF_SIZE__, topIndex + choices.length - 1); return true; } return false; }, 60); /// 允许长按空格或回车连续执行操作 core.registerAction('keyDown', 'shops', function (keycode) { if (!core.status.lockControl || !core.hasFlag("@temp@shop") || core.status.event.id != 'action') return false; if (core.status.event.data.type != 'choices') return false; core.status.onShopLongDown = true; var data = core.status.event.data.current; var choices = data.choices; var topIndex = core.actions._getChoicesTopIndex(choices.length); if (keycode == 13 || keycode == 32) { // Space, Enter core.actions._clickAction(core._HALF_WIDTH_ || core.__HALF_SIZE__, topIndex + core.status.event.selection); _shouldProcessKeyUp = false; return true; } return false; }, 60); // 允许长按屏幕连续执行操作 core.registerAction('longClick', 'shops', function (x, y, px, py) { if (!core.status.lockControl || !core.hasFlag("@temp@shop") || core.status.event.id != 'action') return false; if (core.status.event.data.type != 'choices') return false; var data = core.status.event.data.current; var choices = data.choices; var topIndex = core.actions._getChoicesTopIndex(choices.length); if (Math.abs(x - (core._HALF_WIDTH_ || core.__HALF_SIZE__)) <= 2 && y >= topIndex && y < topIndex + choices.length) { core.actions._clickAction(x, y); return true; } return false; }, 60); }, "removeMap": function () { // 高层塔砍层插件,删除后不会存入存档,不可浏览地图也不可飞到。 // 推荐用法: // 对于超高层或分区域塔,当在1区时将2区以后的地图删除;1区结束时恢复2区,进二区时删除1区地图,以此类推 // 这样可以大幅减少存档空间,以及加快存读档速度 // 删除楼层 // core.removeMaps("MT1", "MT300") 删除MT1~MT300之间的全部层 // core.removeMaps("MT10") 只删除MT10层 this.removeMaps = function (fromId, toId) { toId = toId || fromId; var fromIndex = core.floorIds.indexOf(fromId), toIndex = core.floorIds.indexOf(toId); if (toIndex < 0) toIndex = core.floorIds.length - 1; flags.__visited__ = flags.__visited__ || {}; flags.__removed__ = flags.__removed__ || []; flags.__disabled__ = flags.__disabled__ || {}; flags.__leaveLoc__ = flags.__leaveLoc__ || {}; for (var i = fromIndex; i <= toIndex; ++i) { var floorId = core.floorIds[i]; if (core.status.maps[floorId].deleted) continue; delete flags.__visited__[floorId]; flags.__removed__.push(floorId); delete flags.__disabled__[floorId]; delete flags.__leaveLoc__[floorId]; (core.status.autoEvents || []).forEach(function (event) { if (event.floorId == floorId && event.currentFloor) { core.autoEventExecuting(event.symbol, false); core.autoEventExecuted(event.symbol, false); } }); core.status.maps[floorId].deleted = true; core.status.maps[floorId].canFlyTo = false; core.status.maps[floorId].canFlyFrom = false; core.status.maps[floorId].cannotViewMap = true; } } // 恢复楼层 // core.resumeMaps("MT1", "MT300") 恢复MT1~MT300之间的全部层 // core.resumeMaps("MT10") 只恢复MT10层 this.resumeMaps = function (fromId, toId) { toId = toId || fromId; var fromIndex = core.floorIds.indexOf(fromId), toIndex = core.floorIds.indexOf(toId); if (toIndex < 0) toIndex = core.floorIds.length - 1; flags.__removed__ = flags.__removed__ || []; for (var i = fromIndex; i <= toIndex; ++i) { var floorId = core.floorIds[i]; if (!core.status.maps[floorId].deleted) continue; flags.__removed__ = flags.__removed__.filter(function (f) { return f != floorId; }); core.status.maps[floorId] = core.loadFloor(floorId); } } // 分区砍层相关 var inAnyPartition = function (floorId) { var inPartition = false; (core.floorPartitions || []).forEach(function (floor) { var fromIndex = core.floorIds.indexOf(floor[0]); var toIndex = core.floorIds.indexOf(floor[1]); var index = core.floorIds.indexOf(floorId); if (fromIndex < 0 || index < 0) return; if (toIndex < 0) toIndex = core.floorIds.length - 1; if (index >= fromIndex && index <= toIndex) inPartition = true; }); return inPartition; } // 分区砍层 this.autoRemoveMaps = function (floorId) { if (main.mode != 'play' || !inAnyPartition(floorId)) return; // 根据分区信息自动砍层与恢复 (core.floorPartitions || []).forEach(function (floor) { var fromIndex = core.floorIds.indexOf(floor[0]); var toIndex = core.floorIds.indexOf(floor[1]); var index = core.floorIds.indexOf(floorId); if (fromIndex < 0 || index < 0) return; if (toIndex < 0) toIndex = core.floorIds.length - 1; if (index >= fromIndex && index <= toIndex) { core.resumeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]); } else { core.removeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]); } }); } }, "fiveLayers": function () { // 是否启用五图层(增加背景2层和前景2层) 将__enable置为true即会启用;启用后请保存后刷新编辑器 // 背景层2将会覆盖背景层 被事件层覆盖 前景层2将会覆盖前景层 // 另外 请注意加入两个新图层 会让大地图的性能降低一些 // 插件作者:ad var __enable = false; if (!__enable) return; // 创建新图层 function createCanvas (name, zIndex) { if (!name) return; var canvas = document.createElement('canvas'); canvas.id = name; canvas.className = 'gameCanvas'; // 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高 if (main.mode != "editor") canvas.style.zIndex = zIndex || 0; // 将图层插入进游戏内容 document.getElementById('gameDraw').appendChild(canvas); var ctx = canvas.getContext('2d'); core.canvas[name] = ctx; canvas.width = core._PX_ || core.__PIXELS__; canvas.height = core._PY_ || core.__PIXELS__; return canvas; } var bg2Canvas = createCanvas('bg2', 20); var fg2Canvas = createCanvas('fg2', 63); // 大地图适配 core.bigmap.canvas = ["bg2", "fg2", "bg", "event", "event2", "fg", "damage"]; core.initStatus.bg2maps = {}; core.initStatus.fg2maps = {}; if (main.mode == 'editor') { /*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/ // 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层) // 背景层2(bg2) 插入事件层(event)之前(即bg与event之间) document.getElementById('mapEdit').insertBefore(bg2Canvas, document.getElementById('event')); // 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后) document.getElementById('mapEdit').insertBefore(fg2Canvas, document.getElementById('ebm')); // 原本有三个图层 从4开始添加 var num = 4; // 新增图层存入editor.dom中 editor.dom.bg2c = core.canvas.bg2.canvas; editor.dom.bg2Ctx = core.canvas.bg2; editor.dom.fg2c = core.canvas.fg2.canvas; editor.dom.fg2Ctx = core.canvas.fg2; editor.dom.maps.push('bg2map', 'fg2map'); editor.dom.canvas.push('bg2', 'fg2'); // 创建编辑器上的按钮 var createCanvasBtn = function (name) { // 电脑端创建按钮 var input = document.createElement('input'); // layerMod4/layerMod5 var id = 'layerMod' + num++; // bg2map/fg2map var value = name + 'map'; input.type = 'radio'; input.name = 'layerMod'; input.id = id; input.value = value; editor.dom[id] = input; input.onchange = function () { editor.uifunctions.setLayerMod(value); } return input; }; var createCanvasBtn_mobile = function (name) { // 手机端往选择列表中添加子选项 var input = document.createElement('option'); var id = 'layerMod' + num++; var value = name + 'map'; input.name = 'layerMod'; input.value = value; editor.dom[id] = input; return input; }; if (!editor.isMobile) { var input = createCanvasBtn('bg2'); var input2 = createCanvasBtn('fg2'); // 获取事件层及其父节点 var child = document.getElementById('layerMod'), parent = child.parentNode; // 背景层2插入事件层前 parent.insertBefore(input, child); // 不能直接更改背景层2的innerText 所以创建文本节点 var txt = document.createTextNode('bg2'); // 插入事件层前(即新插入的背景层2前) parent.insertBefore(txt, child); // 向最后插入前景层2(即插入前景层后) parent.appendChild(input2); var txt2 = document.createTextNode('fg2'); parent.appendChild(txt2); parent.childNodes[2].replaceWith("bg"); parent.childNodes[6].replaceWith("事件"); parent.childNodes[8].replaceWith("fg"); } else { var input = createCanvasBtn_mobile('bg2'); var input2 = createCanvasBtn_mobile('fg2'); // 手机端因为是选项 所以可以直接改innerText input.innerText = '背景层2'; input2.innerText = '前景层2'; var parent = document.getElementById('layerMod'); parent.insertBefore(input, parent.children[1]); parent.appendChild(input2); } } var _loadFloor_doNotCopy = core.maps._loadFloor_doNotCopy; core.maps._loadFloor_doNotCopy = function () { return ["bg2map", "fg2map"].concat(_loadFloor_doNotCopy()); } ////// 绘制背景和前景层 ////// core.maps._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) { config.ctx = cacheCtx; core.maps._drawBg_drawBackground(floorId, config); // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。 core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap); core.maps._drawBgFgMap(floorId, 'bg', config); if (config.onMap) { core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); core.clearMap('bg2'); core.clearMap(cacheCtx); } core.maps._drawBgFgMap(floorId, 'bg2', config); if (config.onMap) core.drawImage('bg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); config.ctx = toDrawCtx; } core.maps._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) { config.ctx = cacheCtx; // ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。 core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap); core.maps._drawBgFgMap(floorId, 'fg', config); if (config.onMap) { core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); core.clearMap('fg2'); core.clearMap(cacheCtx); } core.maps._drawBgFgMap(floorId, 'fg2', config); if (config.onMap) core.drawImage('fg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0); config.ctx = toDrawCtx; } ////// 移动判定 ////// core.maps._generateMovableArray_arrays = function (floorId) { return { bgArray: this.getBgMapArray(floorId), fgArray: this.getFgMapArray(floorId), eventArray: this.getMapArray(floorId), bg2Array: this._getBgFgMapArray('bg2', floorId), fg2Array: this._getBgFgMapArray('fg2', floorId) }; } }, "itemShop": function () { // 道具商店相关的插件 // 可在全塔属性-全局商店中使用「道具商店」事件块进行编辑(如果找不到可以在入口方块中找) var shopId = null; // 当前商店ID var type = 0; // 当前正在选中的类型,0买入1卖出 var selectItem = 0; // 当前正在选中的道具 var selectCount = 0; // 当前已经选中的数量 var page = 0; var totalPage = 0; var totalMoney = 0; var list = []; var shopInfo = null; // 商店信息 var choices = []; // 商店选项 var use = 'money'; var useText = '金币'; var bigFont = core.ui._buildFont(20, false), middleFont = core.ui._buildFont(18, false); this._drawItemShop = function () { // 绘制道具商店 // Step 1: 背景和固定的几个文字 core.ui._createUIEvent(); core.clearMap('uievent'); core.ui.clearUIEventSelector(); core.setTextAlign('uievent', 'left'); core.setTextBaseline('uievent', 'top'); core.fillRect('uievent', 0, 0, 480, 480, 'black'); core.drawWindowSkin('winskin.png', 'uievent', 0, 0, 480, 64); core.drawWindowSkin('winskin.png', 'uievent', 0, 64, 360, 64); core.drawWindowSkin('winskin.png', 'uievent', 0, 128, 360, 352); core.drawWindowSkin('winskin.png', 'uievent', 360, 64, 120, 64); core.drawWindowSkin('winskin.png', 'uievent', 360, 128, 120, 352); core.setFillStyle('uievent', 'white'); core.setStrokeStyle('uievent', 'white'); core.fillText("uievent", "购买", 32, 84, 'white', bigFont); core.fillText("uievent", "卖出", 152, 84); core.fillText("uievent", "离开", 272, 84); core.fillText("uievent", "当前" + useText, 374, 75, null, middleFont); core.setTextAlign("uievent", "right"); core.fillText("uievent", core.formatBigNumber(core.status.hero.money), 466, 100); core.setTextAlign("uievent", "left"); core.ui.drawUIEventSelector(1, "winskin.png", 22 + 120 * type, 76, 60, 33); if (selectItem != null) { core.setTextAlign('uievent', 'center'); core.fillText("uievent", type == 0 ? "买入个数" : "卖出个数", 420, 360, null, bigFont); core.fillText("uievent", "< " + selectCount + " >", 420, 390); core.fillText("uievent", "确定", 420, 420); } // Step 2:获得列表并展示 list = choices.filter(function (one) { if (one.condition != null && one.condition != '') { try { if (!core.calValue(one.condition)) return false; } catch (e) {} } return (type == 0 && one.money != null) || (type == 1 && one.sell != null); }); var per_page = 7; totalPage = Math.ceil(list.length / per_page); page = Math.floor((selectItem || 0) / per_page) + 1; // 绘制分页 if (totalPage > 1) { var half = 180; core.setTextAlign('uievent', 'center'); core.fillText('uievent', page + " / " + totalPage, half, 450, null, middleFont); if (page > 1) core.fillText('uievent', '上一页', half - 80, 450); if (page < totalPage) core.fillText('uievent', '下一页', half + 80, 450); } core.setTextAlign('uievent', 'left'); // 绘制每一项 var start = (page - 1) * per_page; for (var i = 0; i < per_page; ++i) { var curr = start + i; if (curr >= list.length) break; var item = list[curr]; core.drawIcon('uievent', item.id, 10, 141 + i * 40); core.setTextAlign('uievent', 'left'); core.fillText('uievent', core.material.items[item.id].name, 50, 148 + i * 40, null, bigFont); core.setTextAlign('uievent', 'right'); core.fillText('uievent', (type == 0 ? core.calValue(item.money) : core.calValue(item.sell)) + useText + "/个", 340, 149 + i * 40, null, middleFont); core.setTextAlign("uievent", "left"); if (curr == selectItem) { // 绘制描述,文字自动放缩 var text = core.material.items[item.id].text || "该道具暂无描述"; try { text = core.replaceText(text); } catch (e) {} for (var fontSize = 20; fontSize >= 8; fontSize -= 2) { var config = { left: 10, fontSize: fontSize, maxWidth: 467 }; var height = core.getTextContentHeight(text, config); if (height <= 60) { config.top = (64 - height) / 2; core.drawTextContent("uievent", text, config); break; } } core.ui.drawUIEventSelector(2, "winskin.png", 8, 137 + i * 40, 343, 40); if (type == 0 && item.number != null) { core.fillText("uievent", "存货", 370, 152, null, bigFont); core.setTextAlign("uievent", "right"); core.fillText("uievent", item.number, 470, 152, null, null, 60); } else if (type == 1) { core.fillText("uievent", "数量", 370, 152, null, bigFont); core.setTextAlign("uievent", "right"); core.fillText("uievent", core.itemCount(item.id), 470, 152, null, null, 40); } core.setTextAlign("uievent", "left"); core.fillText("uievent", "预计" + useText, 370, 280); core.setTextAlign("uievent", "right"); totalMoney = selectCount * (type == 0 ? core.calValue(item.money) : core.calValue(item.sell)); core.fillText("uievent", core.formatBigNumber(totalMoney), 470, 310); core.setTextAlign("uievent", "left"); core.fillText("uievent", type == 0 ? "已购次数" : "已卖次数", 370, 190); core.setTextAlign("uievent", "right"); core.fillText("uievent", (type == 0 ? item.money_count : item.sell_count) || 0, 470, 220); } } core.setTextAlign('uievent', 'left'); core.setTextBaseline('uievent', 'alphabetic'); } var _add = function (item, delta) { if (item == null) return; selectCount = core.clamp( selectCount + delta, 0, Math.min(type == 0 ? Math.floor(core.status.hero[use] / core.calValue(item.money)) : core.itemCount(item.id), type == 0 && item.number != null ? item.number : Number.MAX_SAFE_INTEGER) ); } var _confirm = function (item) { if (item == null || selectCount == 0) return; if (type == 0) { core.status.hero[use] -= totalMoney; core.getItem(item.id, selectCount); core.stopSound(); core.playSound('确定'); if (item.number != null) item.number -= selectCount; item.money_count = (item.money_count || 0) + selectCount; } else { core.status.hero[use] += totalMoney; core.removeItem(item.id, selectCount); core.playSound('确定'); core.drawTip("成功卖出" + selectCount + "个" + core.material.items[item.id].name, item.id); if (item.number != null) item.number += selectCount; item.sell_count = (item.sell_count || 0) + selectCount; } selectCount = 0; } this._performItemShopKeyBoard = function (keycode) { var item = list[selectItem] || null; // 键盘操作 switch (keycode) { case 38: // up if (selectItem == null) break; if (selectItem == 0) selectItem = null; else selectItem--; selectCount = 0; break; case 37: // left if (selectItem == null) { if (type > 0) type--; break; } _add(item, -1); break; case 39: // right if (selectItem == null) { if (type < 2) type++; break; } _add(item, 1); break; case 40: // down if (selectItem == null) { if (list.length > 0) selectItem = 0; break; } if (list.length == 0) break; selectItem = Math.min(selectItem + 1, list.length - 1); selectCount = 0; break; case 13: case 32: // Enter/Space if (selectItem == null) { if (type == 2) core.insertAction({ "type": "break" }); else if (list.length > 0) selectItem = 0; break; } _confirm(item); break; case 27: // ESC if (selectItem == null) { core.insertAction({ "type": "break" }); break; } selectItem = null; break; } } this._performItemShopClick = function (px, py) { var item = list[selectItem] || null; // 鼠标操作 if (px >= 22 && px <= 82 && py >= 81 && py <= 112) { // 买 if (type != 0) { type = 0; selectItem = null; selectCount = 0; } return; } if (px >= 142 && px <= 202 && py >= 81 && py <= 112) { // 卖 if (type != 1) { type = 1; selectItem = null; selectCount = 0; } return; } if (px >= 262 && px <= 322 && py >= 81 && py <= 112) // 离开 return core.insertAction({ "type": "break" }); // <,> if (px >= 370 && px <= 395 && py >= 392 && py <= 415) return _add(item, -1); if (px >= 445 && px <= 470 && py >= 302 && py <= 415) return _add(item, 1); // 确定 if (px >= 392 && px <= 443 && py >= 421 && py <= 446) return _confirm(item); // 上一页/下一页 if (px >= 70 && px <= 130 && py >= 450) { if (page > 1) { selectItem -= 7; selectCount = 0; } return; } if (px >= 230 && px <= 290 && py >= 450) { if (page < totalPage) { selectItem = Math.min(selectItem + 7, list.length - 1); selectCount = 0; } return; } // 实际区域 if (px >= 9 && px <= 351 && py >= 142 && py < 422) { if (list.length == 0) return; var index = parseInt((py - 142) / 40); var newItem = 7 * (page - 1) + index; if (newItem >= list.length) newItem = list.length - 1; if (newItem != selectItem) { selectItem = newItem; selectCount = 0; } return; } } this._performItemShopAction = function () { if (flags.type == 0) return this._performItemShopKeyBoard(flags.keycode); else return this._performItemShopClick(flags.px, flags.py); } this.openItemShop = function (itemShopId) { shopId = itemShopId; type = 0; page = 0; selectItem = null; selectCount = 0; core.isShopVisited(itemShopId); shopInfo = flags.__shops__[shopId]; if (shopInfo.choices == null) shopInfo.choices = core.clone(core.status.shops[shopId].choices); choices = shopInfo.choices; use = core.status.shops[shopId].use; if (use != 'exp') use = 'money'; useText = use == 'money' ? '金币' : '经验'; core.insertAction([{ "type": "while", "condition": "true", "data": [ { "type": "function", "function": "function () { core.plugin._drawItemShop(); }" }, { "type": "wait" }, { "type": "function", "function": "function() { core.plugin._performItemShopAction(); }" } ] }, { "type": "function", "function": "function () { core.deleteCanvas('uievent'); core.ui.clearUIEventSelector(); }" } ]); } }, "enemyLevel": function () { // 此插件将提供怪物手册中的怪物境界显示 // 使用此插件需要先给每个怪物定义境界,方法如下: // 点击怪物的【配置表格】,找到“【怪物】相关的表格配置”,然后在【名称】仿照增加境界定义: /* "level": { "_leaf": true, "_type": "textarea", "_string": true, "_data": "境界" }, */ // 然后保存刷新,可以看到怪物的属性定义中出现了【境界】。再开启本插件即可。 // 是否开启本插件,默认禁用;将此改成 true 将启用本插件。 var __enable = false; if (!__enable) return; // 这里定义每个境界的显示颜色;可以写'red', '#RRGGBB' 或者[r,g,b,a]四元数组 var levelToColors = { "萌新一阶": "red", "萌新二阶": "#FF0000", "萌新三阶": [255, 0, 0, 1], }; // 复写 _drawBook_drawName var originDrawBook = core.ui._drawBook_drawName; core.ui._drawBook_drawName = function (index, enemy, top, left, width) { // 如果没有境界,则直接调用原始代码绘制 if (!enemy.level) return originDrawBook.call(core.ui, index, enemy, top, left, width); // 存在境界,则额外进行绘制 core.setTextAlign('ui', 'center'); if (enemy.specialText.length == 0) { core.fillText('ui', enemy.name, left + width / 2, top + 27, '#DDDDDD', this._buildFont(17, true)); core.fillText('ui', enemy.level, left + width / 2, top + 51, core.arrayToRGBA(levelToColors[enemy.level] || '#DDDDDD'), this._buildFont(14, true)); } else { core.fillText('ui', enemy.name, left + width / 2, top + 20, '#DDDDDD', this._buildFont(17, true), width); switch (enemy.specialText.length) { case 1: core.fillText('ui', enemy.specialText[0], left + width / 2, top + 38, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A'), this._buildFont(14, true), width); break; case 2: // Step 1: 计算字体 var text = enemy.specialText[0] + " " + enemy.specialText[1]; core.setFontForMaxWidth('ui', text, width, this._buildFont(14, true)); // Step 2: 计算总宽度 var totalWidth = core.calWidth('ui', text); var leftWidth = core.calWidth('ui', enemy.specialText[0]); var rightWidth = core.calWidth('ui', enemy.specialText[1]); // Step 3: 绘制 core.fillText('ui', enemy.specialText[0], left + (width + leftWidth - totalWidth) / 2, top + 38, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A')); core.fillText('ui', enemy.specialText[1], left + (width + totalWidth - rightWidth) / 2, top + 38, core.arrayToRGBA((enemy.specialColor || [])[1] || '#FF6A6A')); break; default: core.fillText('ui', '多属性...', left + width / 2, top + 38, '#FF6A6A', this._buildFont(14, true), width); } core.fillText('ui', enemy.level, left + width / 2, top + 56, core.arrayToRGBA(levelToColors[enemy.level] || '#DDDDDD'), this._buildFont(14, true)); } } // 也可以复写其他的属性颜色如怪物攻防等,具体参见下面的例子的注释部分 core.ui._drawBook_drawRow1 = function (index, enemy, top, left, width, position) { // 绘制第一行 core.setTextAlign('ui', 'left'); var b13 = this._buildFont(13, true), f13 = this._buildFont(13, false); var col1 = left, col2 = left + width * 9 / 25, col3 = left + width * 17 / 25; core.fillText('ui', '生命', col1, position, '#DDDDDD', f13); core.fillText('ui', core.formatBigNumber(enemy.hp || 0), col1 + 30, position, /*'red' */ null, b13); core.fillText('ui', '攻击', col2, position, null, f13); core.fillText('ui', core.formatBigNumber(enemy.atk || 0), col2 + 30, position, /* '#FF0000' */ null, b13); core.fillText('ui', '防御', col3, position, null, f13); core.fillText('ui', core.formatBigNumber(enemy.def || 0), col3 + 30, position, /* [255, 0, 0, 1] */ null, b13); } }, "multiHeros": function () { // 多角色插件 // Step 1: 启用本插件 // Step 2: 定义每个新的角色各项初始数据(参见下方注释) // Step 3: 在游戏中的任何地方都可以调用 `core.changeHero()` 进行切换;也可以 `core.changeHero(1)` 来切换到某个具体的角色上 // 是否开启本插件,默认禁用;将此改成 true 将启用本插件。 var __enable = false; if (!__enable) return; // 在这里定义全部的新角色属性 // 请注意,在这里定义的内容不会多角色共用,在切换时会进行恢复。 // 你也可以自行新增或删除,比如不共用金币则可以加上"money"的初始化,不共用道具则可以加上"items"的初始化, // 多角色共用hp的话则删除hp,等等。总之,不共用的属性都在这里进行定义就好。 var hero1 = { "floorId": "MT0", // 该角色初始楼层ID;如果共用楼层可以注释此项 "image": "brave.png", // 角色的行走图名称;此项必填不然会报错 "name": "1号角色", "lv": 1, "hp": 10000, // 如果HP共用可注释此项 "atk": 1000, "def": 1000, "mdef": 0, // "money": 0, // 如果要不共用金币则取消此项注释 // "exp": 0, // 如果要不共用经验则取消此项注释 "loc": { "x": 0, "y": 0, "direction": "up" }, // 该角色初始位置;如果共用位置可注释此项 "items": { "tools": {}, // 如果共用消耗道具(含钥匙)则可注释此项 // "constants": {}, // 如果不共用永久道具(如手册)可取消注释此项 "equips": {}, // 如果共用在背包的装备可注释此项 }, "equipment": [], // 如果共用装备可注释此项;此项和上面的「共用在背包的装备」需要拥有相同状态,不然可能出现问题 }; // 也可以类似新增其他角色 // 新增的角色,各项属性共用与不共用的选择必须和上面完全相同,否则可能出现问题。 // var hero2 = { ... var heroCount = 2; // 包含默认角色在内总共多少个角色,该值需手动修改。 this.initHeros = function () { core.setFlag("hero1", core.clone(hero1)); // 将属性值存到变量中 // core.setFlag("hero2", core.clone(hero2)); // 更多的角色也存入变量中;每个定义的角色都需要新增一行 // 检测是否存在装备 if (hero1.equipment) { if (!hero1.items || !hero1.items.equips) { alert('多角色插件的equipment和道具中的equips必须拥有相同状态!'); } // 存99号套装为全空 var saveEquips = core.getFlag("saveEquips", []); saveEquips[99] = []; core.setFlag("saveEquips", saveEquips); } else { if (hero1.items && hero1.items.equips) { alert('多角色插件的equipment和道具中的equips必须拥有相同状态!'); } } } // 在游戏开始注入initHeros var _startGame_setHard = core.events._startGame_setHard; core.events._startGame_setHard = function () { _startGame_setHard.call(core.events); core.initHeros(); } // 切换角色 // 可以使用 core.changeHero() 来切换到下一个角色 // 也可以 core.changeHero(1) 来切换到某个角色(默认角色为0) this.changeHero = function (toHeroId) { var currHeroId = core.getFlag("heroId", 0); // 获得当前角色ID if (toHeroId == null) { toHeroId = (currHeroId + 1) % heroCount; } if (currHeroId == toHeroId) return; var saveList = Object.keys(hero1); // 保存当前内容 var toSave = {}; // 暂时干掉 drawTip 和 音效,避免切装时的提示 var _drawTip = core.ui.drawTip; core.ui.drawTip = function () { }; var _playSound = core.control.playSound; core.control.playSound = function () { } // 记录当前录像,因为可能存在换装问题 core.clearRouteFolding(); var routeLength = core.status.route.length; // 优先判定装备 if (hero1.equipment) { core.items.quickSaveEquip(100 + currHeroId); core.items.quickLoadEquip(99); } saveList.forEach(function (name) { if (name == 'floorId') toSave[name] = core.status.floorId; // 楼层单独设置 else if (name == 'items') { toSave.items = core.clone(core.status.hero.items); Object.keys(toSave.items).forEach(function (one) { if (!hero1.items[one]) delete toSave.items[one]; }); } else toSave[name] = core.clone(core.status.hero[name]); // 使用core.clone()来创建新对象 }); core.setFlag("hero" + currHeroId, toSave); // 将当前角色信息进行保存 var data = core.getFlag("hero" + toHeroId); // 获得要切换的角色保存内容 // 设置角色的属性值 saveList.forEach(function (name) { if (name == "floorId"); else if (name == "items") { Object.keys(core.status.hero.items).forEach(function (one) { if (data.items[one]) core.status.hero.items[one] = core.clone(data.items[one]); }); } else { core.status.hero[name] = core.clone(data[name]); } }); // 最后装上装备 if (hero1.equipment) { core.items.quickLoadEquip(100 + toHeroId); } core.ui.drawTip = _drawTip; core.control.playSound = _playSound; core.status.route = core.status.route.slice(0, routeLength); core.control._bindRoutePush(); // 插入事件:改变角色行走图并进行楼层切换 var toFloorId = data.floorId || core.status.floorId; var toLoc = data.loc || core.status.hero.loc; core.insertAction([ { "type": "setHeroIcon", "name": data.image || "hero.png" }, // 改变行走图 // 同层则用changePos,不同层则用changeFloor;这是为了避免共用楼层造成触发eachArrive toFloorId != core.status.floorId ? { "type": "changeFloor", "floorId": toFloorId, "loc": [toLoc.x, toLoc.y], "direction": toLoc.direction, "time": 0 // 可以在这里设置切换时间 } : { "type": "changePos", "loc": [toLoc.x, toLoc.y], "direction": toLoc.direction } // 你还可以在这里执行其他事件,比如增加或取消跟随效果 ]); core.setFlag("heroId", toHeroId); // 保存切换到的角色ID } }, "heroFourFrames": function () { // 样板的勇士/跟随者移动时只使用2、4两帧,观感较差。本插件可以将四帧全用上。 // 是否启用本插件 var __enable = true; if (!__enable) return; ["up", "down", "left", "right"].forEach(function (one) { // 指定中间帧动画 core.material.icons.hero[one].midFoot = 2; }); var heroMoving = function (timestamp) { if (core.status.heroMoving <= 0) return; if (timestamp - core.animateFrame.moveTime > core.values.moveSpeed) { core.animateFrame.leftLeg++; core.animateFrame.moveTime = timestamp; } core.drawHero(['stop', 'leftFoot', 'midFoot', 'rightFoot'][core.animateFrame.leftLeg % 4], 4 * core.status.heroMoving); } core.registerAnimationFrame('heroMoving', true, heroMoving); core.events._eventMoveHero_moving = function (step, moveSteps) { var curr = moveSteps[0]; var direction = curr[0], x = core.getHeroLoc('x'), y = core.getHeroLoc('y'); // ------ 前进/后退 var o = direction == 'backward' ? -1 : 1; if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction'); var faceDirection = direction; if (direction == 'leftup' || direction == 'leftdown') faceDirection = 'left'; if (direction == 'rightup' || direction == 'rightdown') faceDirection = 'right'; core.setHeroLoc('direction', direction); if (curr[1] <= 0) { core.setHeroLoc('direction', faceDirection); moveSteps.shift(); return true; } if (step <= 4) core.drawHero('stop', 4 * o * step); else if (step <= 8) core.drawHero('leftFoot', 4 * o * step); else if (step <= 12) core.drawHero('midFoot', 4 * o * (step - 8)); else if (step <= 16) core.drawHero('rightFoot', 4 * o * (step - 8)); // if (step == 8) { if (step == 8 || step == 16) { core.setHeroLoc('x', x + o * core.utils.scan2[direction].x, true); core.setHeroLoc('y', y + o * core.utils.scan2[direction].y, true); core.updateFollowers(); curr[1]--; if (curr[1] <= 0) moveSteps.shift(); core.setHeroLoc('direction', faceDirection); return step == 16; } return false; } }, "routeFixing": function () { // 是否开启本插件,true 表示启用,false 表示禁用。 var __enable = true; if (!__enable) return; /* 使用说明:启用本插件后,录像回放时您可以用数字键1或6分别切换到原速或24倍速, 暂停播放时按数字键7(电脑按N)可以单步播放。(手机端可以点击难度单词切换出数字键) 数字键2-5可以进行录像自助精修,具体描述见下(实际弹窗请求您输入时不要带有任何空格): up down left right 勇士向某个方向「行走一步或撞击」 item:ID 使用某件道具,如 item:bomb 表示使用炸弹 unEquip:n 卸掉身上第(n+1)件装备(n从0开始),如 unEquip:1 默认表示卸掉盾牌 equip:ID 穿上某件装备,如 equip:sword1 表示装上铁剑 saveEquip:n 将身上的当前套装保存到第n套快捷套装(n从0开始) loadEquip:n 快捷换上之前保存好的第n套套装 fly:ID 使用楼传飞到某一层,如 fly:MT10 表示飞到主塔10层 choices:none 确认框/选择项「超时」(作者未设置超时时间则此项视为缺失) choices:n 确认框/选择项选择第(n+1)项(选择项n从0开始,确认框n为0表示「确定」,1表示「取消」) 选择项n为负数时表示选择倒数第 -n 项,如 -1 表示最后一项(V2.8.2起标准全局商店的「离开」项) 此项缺失的话,确认框将选择作者指定的默认项(初始光标位置),选择项将弹窗请求补选(后台录像验证中选最后一项,可以复写函数来修改) shop:ID 打开某个全局商店,如 shop:itemShop 表示打开道具商店。因此连载塔千万不要中途修改商店ID! turn 单击勇士(Z键)转身,core.turnHero() 会产生此项,因此通过事件等方式强制让勇士转向应该用 core.setHeroLoc() turn:dir 勇士转向某个方向,dir 可以为 up down left right(此项一般是读取自动存档产生的,属于样板的不良特性,请勿滥用) getNext 轻按获得身边道具,优先获得面前的(面前没有则按上下左右顺序依次获得),身边如果没有道具则此项会被跳过 input:none “等待用户操作事件”中超时(作者未设置超时时间则此项会导致报错) input:xxx 可能表示“等待用户操作事件”的一个操作(如按键操作将直接记录 input:keycode ), 也可能表示一个“接受用户输入数字”的输入,后者的情况下 xxx 为输入的整数。此项缺失的话前者将直接报错,后者将用0代替(后者现在支持负数了) input2:xxx 可能表示“读取全局存储(core.getGlobal)”读取到的值,也可能表示一个“接受用户输入文本”的输入, 两种情况下 xxx 都为 base64 编码。此项缺失的话前者将重新现场读取,后者将用空字符串代替 no 走到可穿透的楼梯上不触发楼层切换事件,通过本插件可以让勇士停在旁边没有障碍物的楼梯上哦~ move:x:y 尝试瞬移到 [x,y] 点(不改变朝向),该点甚至可以和勇士相邻或者位于视野外 key:n 松开键值为n的键,如 key:49 表示松开大键盘数字键1,默认会触发使用破墙镐 click:n:px:py 点击自绘状态栏,n为0表示横屏1表示竖屏,[px,py] 为点击的像素坐标 random:n 生成了随机数n,即 core.rand2(num) 的返回结果,n必须在 [0,num-1] 范围,num必须为正整数。此项缺失将导致现场重新随机生成数值,可能导致回放结果不一致! 作者自定义的新项(一般为js对象,可以先JSON.stringify()再core.encodeBase64()得到纯英文数字的内容)需要用(半角圆括弧)括起来。 当您使用数字键5将一些项追加到即将播放内容的开头时,请注意要逆序逐项追加,或者每追加一项就按下数字键7或字母键N单步播放一步。 但是【input input2 random choices】是被动读取的,单步播放如果触发了相应的事件就会连续读取,这时候只能提前逐项追加好。 电脑端熟练以后推荐直接在控制台操作 core.status.route 和 core.status.replay.toReplay(后者录像回放时才有),配合 core.push() 和 core.unshift() 更加灵活自由哦! */ core.actions.registerAction('onkeyUp', '_sys_onkeyUp_replay', function (e) { if (this._checkReplaying()) { if (e.keyCode == 27) // ESCAPE core.stopReplay(); else if (e.keyCode == 90) // Z core.speedDownReplay(); else if (e.keyCode == 67) // C core.speedUpReplay(); else if (e.keyCode == 32) // SPACE core.triggerReplay(); else if (e.keyCode == 65) // A core.rewindReplay(); else if (e.keyCode == 83) // S core.control._replay_SL(); else if (e.keyCode == 88) // X core.control._replay_book(); else if (e.keyCode == 33 || e.keyCode == 34) // PgUp/PgDn core.control._replay_viewMap(); else if (e.keyCode == 78) // N core.stepReplay(); else if (e.keyCode == 84) // T core.control._replay_toolbox(); else if (e.keyCode == 81) // Q core.control._replay_equipbox(); else if (e.keyCode == 66) // B core.ui._drawStatistics(); else if (e.keyCode == 49 || e.keyCode == 54) // 1/6,原速/24倍速播放 core.setReplaySpeed(e.keyCode == 49 ? 1 : 24); else if (e.keyCode > 49 && e.keyCode < 54) { // 2-5,录像精修 switch (e.keyCode - 48) { case 2: // pop alert("您已移除已录制内容的最后一项:" + core.status.route.pop()); break; case 3: // push core.utils.myprompt("请输入您要追加到已录制内容末尾的项:", "", function (value) { if (value != null) core.status.route.push(value); }); break; case 4: // shift alert("您已移除即将播放内容的第一项:" + core.status.replay.toReplay.shift()); break; case 5: // unshift core.utils.myprompt("请输入您要追加到即将播放内容开头的项:", "", function (value) { if (value != null) core.status.replay.toReplay.unshift(value); }); } } return true; } }, 100); }, "numpad": function () { // 样板自带的整数输入事件为白屏弹窗且可以误输入任意非法内容但不支持负整数,观感较差。本插件可以将其美化成仿RM样式,使其支持负整数同时带有音效 // 另一方面,4399等第三方平台不允许使用包括 core.myprompt() 和 core.myconfirm() 在内的弹窗,因此也需要此插件来替代,不然类似生命魔杖的道具就不好实现了 // 关于负整数输入,V2.8.2原生支持其录像的压缩和解压,只是默认的 core.events._action_input() 函数将负数取了绝对值,可以只复写下面的 core.isReplaying() 部分来取消 // 是否启用本插件,false表示禁用,true表示启用 var __enable = true; if (!__enable) return; core.events._action_input = function (data, x, y, prefix) { // 复写整数输入事件 if (core.isReplaying()) { // 录像回放时,处理方式不变,但增加负整数支持 core.events.__action_getInput(core.replaceText(data.text, prefix), false, function (value) { value = parseInt(value) || 0; // 去掉了取绝对值的步骤 core.status.route.push("input:" + value); core.setFlag("input", value); core.doAction(); }); } else { // 正常游戏中,采用暂停录制的方式然后用事件流循环“绘制-等待-变量操作”三板斧实现(按照13*13适配的)。 // 您可以自行修改循环内的内容来适配15*15或其他需求,或干脆作为公共事件编辑。 core.insertAction([ // 记录当前录像长度,下面的循环结束后裁剪。达到“暂停录制”的效果 { "type": "function", "function": "function(){flags['@temp@length']=core.status.route.length}" }, { "type": "setValue", "name": "flag:input", "value": "0" }, { "type": "while", "condition": "true", "data": [ { "type": "drawBackground", "background": "winskin.png", "x": 16, "y": 16, "width": 384, "height": 384 }, { "type": "drawIcon", "id": "X10181", "x": 32, "y": 288 }, { "type": "drawIcon", "id": "X10185", "x": 64, "y": 288 }, { "type": "drawIcon", "id": "X10186", "x": 96, "y": 288 }, { "type": "drawIcon", "id": "X10187", "x": 128, "y": 288 }, { "type": "drawIcon", "id": "X10188", "x": 160, "y": 288 }, { "type": "drawIcon", "id": "X10189", "x": 192, "y": 288 }, { "type": "drawIcon", "id": "X10193", "x": 224, "y": 288 }, { "type": "drawIcon", "id": "X10194", "x": 256, "y": 288 }, { "type": "drawIcon", "id": "X10195", "x": 288, "y": 288 }, { "type": "drawIcon", "id": "X10196", "x": 320, "y": 288 }, { "type": "drawIcon", "id": "X10197", "x": 352, "y": 288 }, { "type": "drawIcon", "id": "X10286", "x": 32, "y": 352 }, { "type": "drawIcon", "id": "X10169", "x": 96, "y": 352 }, { "type": "drawIcon", "id": "X10232", "x": 128, "y": 352 }, { "type": "drawIcon", "id": "X10185", "x": 320, "y": 352 }, { "type": "drawIcon", "id": "X10242", "x": 352, "y": 352 }, { "type": "fillBoldText", "x": 48, "y": 256, "style": [255, 255, 255, 1], "font": "bold 32px Consolas", "text": "${flag:input}" }, { "type": "fillBoldText", "x": 32, "y": 48, "style": [255, 255, 255, 1], "font": "16px Consolas", "text": core.replaceText(data.text, prefix) }, { "type": "wait", "forceChild": true, "data": [{ "case": "keyboard", "keycode": "48,49,50,51,52,53,54,55,56,57", "action": [ // 按下数字键,追加到已输入内容的末尾,但禁止越界。变量:keycode-48就是末位数字 { "type": "playSound", "name": "光标移动" }, { "type": "if", "condition": "(flag:input<0)", "true": [ { "type": "setValue", "name": "flag:input", "value": "10*flag:input-(flag:keycode-48)" }, ], "false": [ { "type": "setValue", "name": "flag:input", "value": "10*flag:input+(flag:keycode-48)" }, ] }, { "type": "setValue", "name": "flag:input", "value": "core.clamp(flag:input,-9e15,9e15)" }, ] }, { "case": "keyboard", "keycode": "189", "action": [ // 按下减号键,变更已输入内容的符号 { "type": "playSound", "name": "跳跃" }, { "type": "setValue", "name": "flag:input", "value": "-flag:input" }, ] }, { "case": "keyboard", "keycode": "8", "action": [ // 按下退格键,从已输入内容的末尾删除一位 { "type": "playSound", "name": "取消" }, { "type": "setValue", "name": "flag:input", "operator": "//=", "value": "10" }, ] }, { "case": "keyboard", "keycode": "27", "action": [ // 按下ESC键,清空已输入内容 { "type": "playSound", "name": "读档" }, { "type": "setValue", "name": "flag:input", "value": "0" }, ] }, { "case": "keyboard", "keycode": "13", "action": [ // 按下回车键,确定 { "type": "break", "n": 1 }, ] }, { "case": "mouse", "px": [32, 63], "py": [288, 320], "action": [ // 点击减号,变号。右边界写63防止和下面重叠 { "type": "playSound", "name": "跳跃" }, { "type": "setValue", "name": "flag:input", "value": "-flag:input" }, ] }, { "case": "mouse", "px": [64, 384], "py": [288, 320], "action": [ // 点击数字,追加到已输入内容的末尾,但禁止越界。变量:x-2就是末位数字 { "type": "playSound", "name": "光标移动" }, { "type": "if", "condition": "(flag:input<0)", "true": [ { "type": "setValue", "name": "flag:input", "value": "10*flag:input-(flag:x-2)" }, ], "false": [ { "type": "setValue", "name": "flag:input", "value": "10*flag:input+(flag:x-2)" }, ] }, { "type": "setValue", "name": "flag:input", "value": "core.clamp(flag:input,-9e15,9e15)" }, ] }, { "case": "mouse", "px": [32, 64], "py": [352, 384], "action": [ // 点击左箭头,退格 { "type": "playSound", "name": "取消" }, { "type": "setValue", "name": "flag:input", "operator": "//=", "value": "10" }, ] }, { "case": "mouse", "px": [96, 160], "py": [352, 384], "action": [ // 点击CE,清空 { "type": "playSound", "name": "读档" }, { "type": "setValue", "name": "flag:input", "value": "0" }, ] }, { "case": "mouse", "px": [320, 384], "py": [352, 384], "action": [ // 点击OK,确定 { "type": "break", "n": 1 }, ] } ] } ] }, { "type": "clearMap" }, // 裁剪录像,只保留'input:n',然后继续录制 { "type": "function", "function": "function(){core.status.route.splice(flags['@temp@length']);core.status.route.push('input:'+core.getFlag('input',0))}" } ], x, y); core.events.doAction(); } } }, "sprites": function () { // 基于canvas的sprite化,摘编整理自万宁魔塔 // // ---------------------------------------- 第一部分 js代码 (必装) --------------------------------------- // /* ---------------- 用法说明 ---------------- * * 1. 创建sprite: var sprite = new Sprite(x, y, w, h, z, reference, name); * 其中x y w h为画布的横纵坐标及长宽,reference为参考系,只能填game(相对于游戏画面)和window(相对于窗口) * 且当为相对游戏画面时,长宽与坐标将会乘以放缩比例(相当于用createCanvas创建) * z为纵深,表示不同元素之间的覆盖关系,大的覆盖小的 * name为自定义名称,可以不填 * 2. 删除: sprite.destroy(); * 3. 设置css特效: sprite.setCss(css); * 其中css直接填 box-shadow: 0px 0px 10px black;的形式即可,与style标签与css文件内写法相同 * 对于已设置的特效,如果之后不需要再次设置,可以不填 * 4. 添加事件监听器: sprite.addEventListener(); 用法与html元素的addEventListener完全一致 * 5. 移除事件监听器: sprite.removeEventListener(); 用法与html元素的removeEventListener完全一致 * 6. 属性列表 * (1) sprite.x | sprite.y | sprite.width | sprite.height | sprite.zIndex | sprite.reference 顾名思义 * (2) sprite.canvas 该sprite的画布 * (3) sprite.context 该画布的CanvasRenderingContext2d对象,即样板中常见的ctx * (4) sprite.count 不要改这个玩意 * 7. 使用样板api进行绘制 * 示例: * var ctx = sprite.context; * core.fillText(ctx, 'xxx', 100, 100); * core.fillRect(ctx, 0, 0, 50, 50); * 当然也可以使用原生js * ctx.moveTo(0, 0); * ctx.bezierCurveTo(50, 50, 100, 0, 100, 50); * ctx.stroke(); * ---------------- 用法说明 ---------------- */ var count = 0; /** 创建一个sprite画布 * @param {number} x * @param {number} y * @param {number} w * @param {number} h * @param {number} z * @param {'game' | 'window'} reference 参考系,游戏画面或者窗口 * @param {string} name 可选,sprite的名称,方便通过core.dymCanvas获取 */ function Sprite (x, y, w, h, z, reference, name) { this.x = x; this.y = y; this.width = w; this.height = h; this.zIndex = z; this.reference = reference; this.canvas = null; this.context = null; this.count = 0; this.name = name || '_sprite_' + count; this.style = null; /** 初始化 */ this.init = function () { if (reference === 'window') { var canvas = document.createElement('canvas'); this.canvas = canvas; this.context = canvas.getContext('2d'); canvas.width = w; canvas.height = h; canvas.style.width = w + 'px'; canvas.style.height = h + 'px'; canvas.style.position = 'absolute'; canvas.style.top = y + 'px'; canvas.style.left = x + 'px'; canvas.style.zIndex = z.toString(); document.body.appendChild(canvas); this.style = canvas.style; } else { this.context = core.createCanvas(this.name || '_sprite_' + count, x, y, w, h, z); this.canvas = this.context.canvas; this.canvas.style.pointerEvents = 'auto'; this.style = this.canvas.style; } this.count = count; count++; } this.init(); /** 设置css特效 * @param {string} css */ this.setCss = function (css) { css = css.replace('\n', ';').replace(';;', ';'); var effects = css.split(';'); var self = this; effects.forEach(function (v) { var content = v.split(':'); var name = content[0]; var value = content[1]; name = name.trim().split('-').reduce(function (pre, curr, i, a) { if (i === 0 && curr !== '') return curr; if (a[0] === '' && i === 1) return curr; return pre + curr.toUpperCase()[0] + curr.slice(1); }, ''); var canvas = self.canvas; if (name in canvas.style) canvas.style[name] = value; }); return this; } /** * 移动sprite * @param {boolean} isDelta 是否是相对位置,如果是,那么sprite会相对于原先的位置进行移动 */ this.move = function (x, y, isDelta) { if (x !== undefined && x !== null) this.x = x; if (y !== undefined && y !== null) this.y = y; if (this.reference === 'window') { var ele = this.canvas; ele.style.left = x + (isDelta ? parseFloat(ele.style.left) : 0) + 'px'; ele.style.top = y + (isDelta ? parseFloat(ele.style.top) : 0) + 'px'; } else core.relocateCanvas(this.context, x, y, isDelta); return this; } /** * 重新设置sprite的大小 * @param {boolean} styleOnly 是否只修改css效果,如果是,那么将会不高清,如果不是,那么会清空画布 */ this.resize = function (w, h, styleOnly) { if (w !== undefined && w !== null) this.w = w; if (h !== undefined && h !== null) this.h = h; if (reference === 'window') { var ele = this.canvas; ele.style.width = w + 'px'; ele.style.height = h + 'px'; if (!styleOnly) { ele.width = w; ele.height = h; } } else core.resizeCanvas(this.context, w, h, styleOnly); return this; } /** * 旋转画布 */ this.rotate = function (angle, cx, cy) { if (this.reference === 'window') { var left = this.x; var top = this.y; this.canvas.style.transformOrigin = (cx - left) + 'px ' + (cy - top) + 'px'; if (angle === 0) { canvas.style.transform = ''; } else { canvas.style.transform = 'rotate(' + angle + 'deg)'; } } else { core.rotateCanvas(this.context, angle, cx, cy); } return this; } /** * 清除sprite */ this.clear = function (x, y, w, h) { if (this.reference === 'window') { this.context.clearRect(x, y, w, h); } else { core.clearMap(this.context, x, y, w, h); } return this; } /** 删除 */ this.destroy = function () { if (this.reference === 'window') { if (this.canvas) document.body.removeChild(this.canvas); } else { core.deleteCanvas(this.name || '_sprite_' + this.count); } } /** 添加事件监听器 */ this.addEventListener = function () { this.canvas.addEventListener.apply(this.canvas, arguments); } /** 移除事件监听器 */ this.removeEventListener = function () { this.canvas.removeEventListener.apply(this.canvas, arguments); } } window.Sprite = Sprite; }, "跳字": function () { // 在此增加新插件 this.tiaozi1 = function (neirong, yanse) { //跳字一 if (core.status.replay.replaying) {} else { core.createCanvas('tiaozi', 0, 0, 416, 416, 77); core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) + 1); var tiaozihao = core.getFlag("tiaozizhong"); var shangsheng = 1; var gaodu = 0; var herox = core.status.hero.loc.x, heroy = core.status.hero.loc.y; var fade = setInterval(function () { core.clearMap('tiaozi', 0, 0, 416, 416); if (gaodu >= -6 && shangsheng == 1) { gaodu = gaodu - 1; if (gaodu == -6) { shangsheng = 0 } } else if (gaodu <= 12) { gaodu = gaodu + 1; if (gaodu == 12) { var tiaozizhong = 1 } }; core.fillText('tiaozi', neirong, herox * 32 - 13, heroy * 32 + gaodu, yanse, "bold 17px Verdana"); if (tiaozizhong == 1 || core.getFlag("tiaozizhong") > tiaozihao) { core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) - 1); core.clearMap('tiaozi', 0, 0, 416, 416); clearInterval(fade); } }, 16); } } this.tiaozi2 = function (neirong1, neirong2, yanse1, yanse2) { //二段跳字 if (core.status.replay.replaying) {} else { core.createCanvas('tiaozi', 0, 0, 416, 416, 77); core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) + 1); var tiaozihao = core.getFlag("tiaozizhong"); var shangsheng = 1; var gaodu = 0; var huanzi = 0; var herox = core.status.hero.loc.x, heroy = core.status.hero.loc.y; var fade = setInterval(function () { core.clearMap('tiaozi', 0, 0, 416, 416); if (gaodu >= -6 && shangsheng == 1) { gaodu = gaodu - 1; if (gaodu == -6) { shangsheng = 0 } } else if (gaodu <= 12) { gaodu = gaodu + 1; if (gaodu == 12) { if (huanzi == 1) { var tiaozizhong = 1 } else { huanzi = 1; gaodu = 0; shangsheng = 1; } } }; if (huanzi == 0) core.fillText('tiaozi', neirong1, herox * 32 - 13, heroy * 32 + gaodu, yanse1, "bold 17px Verdana"); else core.fillText('tiaozi', neirong2, herox * 32 - 13, heroy * 32 + gaodu, yanse2, "bold 17px Verdana"); if (tiaozizhong == 1 || core.getFlag("tiaozizhong") > tiaozihao) { core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) - 1); core.clearMap('tiaozi', 0, 0, 416, 416); clearInterval(fade); } }, 16); } } this.tiaozi3 = function (neirong1, neirong2, neirong3, yanse1, yanse2, yanse3) { //三段跳字 if (core.status.replay.replaying) {} else { core.createCanvas('tiaozi', 0, 0, 416, 416, 77); core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) + 1); var tiaozihao = core.getFlag("tiaozizhong"); var shangsheng = 1; var gaodu = 0; var huanzi = 0; var herox = core.status.hero.loc.x, heroy = core.status.hero.loc.y; var fade = setInterval(function () { core.clearMap('tiaozi', 0, 0, 416, 416); if (gaodu >= -6 && shangsheng == 1) { gaodu = gaodu - 1; if (gaodu == -6) { shangsheng = 0 } } else if (gaodu <= 12) { gaodu = gaodu + 1; if (gaodu == 12) { switch (huanzi) { case 0: { huanzi = 1; gaodu = 0; shangsheng = 1; }; break; case 1: { huanzi = 2; gaodu = 0; shangsheng = 1; }; break; case 2: var tiaozizhong = 1; break; } } } switch (huanzi) { case 0: core.fillText('tiaozi', neirong1, herox * 32 - 13, heroy * 32 + gaodu, yanse1, "bold 17px Verdana"); break; case 1: core.fillText('tiaozi', neirong2, herox * 32 - 13, heroy * 32 + gaodu, yanse2, "bold 17px Verdana"); break; case 2: core.fillText('tiaozi', neirong3, herox * 32 - 13, heroy * 32 + gaodu, yanse3, "bold 17px Verdana"); break; } if (tiaozizhong == 1 || core.getFlag("tiaozizhong") > tiaozihao) { core.setFlag("tiaozizhong", core.getFlag("tiaozizhong", 0) - 1); core.clearMap('tiaozi', 0, 0, 416, 416); clearInterval(fade); } }, 16); } } this.donghuas = function () { core.plugin.donghua(); for (var i = 1; i <= 20; i++) if (core.plugin['donghua' + i]) core.plugin['donghua' + i](); } this.donghua = function () { if (core.status.floorId == "MT0") { if (core.isReplaying()) {setTimeout(core.plugin.donghua, 100); return;} core.setFlag("linshi", core.drawAnimate("jingu", 10, 10, false, function () { core.plugin.donghua(); })); } else core.stopAnimate(core.getFlag("linshi", 0), false); } this.donghua1 = function () { if (core.status.floorId == "MT14") { core.setFlag("linshi1", core.drawAnimate("dianji", 4, 5, false, function () { core.plugin.donghua1(); })); } else core.stopAnimate(core.getFlag("linshi1", 0), false); } this.donghua2 = function () { if (core.status.floorId == "MT14") { core.setFlag("linshi2", core.drawAnimate("dianji", 10, 5, false, function () { core.plugin.donghua2(); })); } else core.stopAnimate(core.getFlag("linshi2", 0), false); } this.donghua3 = function () { if (core.getFlag("poison")) { core.setFlag("linshi3", core.drawHeroAnimate("dufa", function () { core.plugin.donghua3(); })); } else core.stopAnimate(core.getFlag("linshi3", 0), false); } this.donghua4 = function () { if (core.getFlag("bofang", 0) == 1) { core.setFlag("linshi4", core.drawHeroAnimate("STruoli", function () { core.plugin.donghua4(); })); } else core.stopAnimate(core.getFlag("linshi4", 0), false); } this.donghua5 = function () { if (core.getFlag("bofang", 0) == 1) { core.setFlag("linshi5", core.drawHeroAnimate("lansebaofa", function () { core.plugin.donghua5(); })); } else core.stopAnimate(core.getFlag("linshi5", 0), false); } this.donghua6 = function () { if (core.getFlag("bofang", 0) == 1) { if (core.status.floorId == "MT81") { core.setFlag("linshi6", core.drawAnimate("shenlanbaofa", 7, 5, false, function () { core.plugin.donghua6(); })); } else core.stopAnimate(core.getFlag("linshi6", 0), false); } } this.donghua7 = function () { if (core.status.floorId == "MT64") { if (core.getPlayingAnimates().includes(core.getFlag("linshi7", 0))) return; core.setFlag("linshi7", core.drawAnimate("jingu", 7, 1, false, function () { core.plugin.donghua7(); })); } else core.stopAnimate(core.getFlag("linshi7", 0), false); } this.donghua8 = function () { if (core.getFlag("bofang8", 0) == 1) { if (core.status.floorId == "jiange") { core.setFlag("linshi8", core.drawAnimate("lvbaofa", 9, 8, false, function () { core.plugin.donghua8(); })); } else core.stopAnimate(core.getFlag("linshi8", 0), false); } } this.donghua9 = function () { if (core.getFlag("bofang9", 0) == 1) { core.setFlag("linshi9", core.drawHeroAnimate("lansebaofa", function () { core.plugin.donghua9(); })); } else core.stopAnimate(core.getFlag("linshi9", 0), false); } }, "楼层切换": function () { // 在此增加新插件 ////// 楼层切换 ////// core.events.changeFloor = function (floorId, stair, heroLoc, time, callback) { var info = this._changeFloor_getInfo(floorId, stair, heroLoc, time); var tempCanvas = {}; core.createCanvas("first", 0, 0, core.__PIXELS__, core.__PIXELS__, 61); if (!core.isReplaying()) { tempCanvas = core.createCanvas("_save_", 0, 0, core.__PIXELS__, core.__PIXELS__); core.clearMap("_save_"); core.drawImage(tempCanvas, core.dom.gameCanvas.bg, 0, 0, core.__PIXELS__, core.__PIXELS__); core.drawImage(tempCanvas, core.dom.gameCanvas.event, 0, 0, core.__PIXELS__, core.__PIXELS__); core.drawImage(tempCanvas, core.dom.gameCanvas.event2, 0, 0, core.__PIXELS__, core.__PIXELS__); core.drawImage(tempCanvas, core.dom.gameCanvas.fg, 0, 0, core.__PIXELS__, core.__PIXELS__); } info.tempCanvas = tempCanvas.canvas; if (info == null) { if (callback) callback(); return; } floorId = info.floorId; info.locked = core.status.lockControl; core.dom.floorNameLabel.innerText = core.status.maps[floorId].title; core.lockControl(); core.stopAutomaticRoute(); core.clearContinueAutomaticRoute(); core.status.replay.animate = true; clearInterval(core.interval.onDownInterval); core.interval.onDownInterval = 'tmp'; this._changeFloor_beforeChange(info, callback); } core.events._changeFloor_beforeChange = function (info, callback) { this._changeFloor_playSound(); // 需要 setTimeout 执行,不然会出错 window.setTimeout(function () { core.events._changeFloor_changing(info, callback); /*if (info.time == 0) core.events._changeFloor_changing(info, callback); else core.showWithAnimate(core.dom.floorMsgGroup, info.time / 2, function () { core.events._changeFloor_changing(info, callback); });*/ }, 25) } core.events._changeFloor_changing = function (info, callback) { this.changingFloor(info.floorId, info.heroLoc); // 回归视角 var __lockViewport__ = flags.__lockViewport__; core.setFlag('__lockViewport__', null); core.drawHero(); core.setFlag('__lockViewport__', __lockViewport__); var obj = core.getContextByName("first").canvas; var end = function () { clearInterval(core.__floor); core.clearMap("first"); obj.style.opacity = 1; obj.style.display = "block"; core.__floor = null; } var deleteCanvas = function () { core.deleteCanvas("_save_"); info.tempCanvas = null; } if (info.time == 0 || main.mode != 'play') { end(); deleteCanvas(); } else { if (core.__floor) end(); core.drawImage("first", info.tempCanvas, 0, 0, core.__PIXELS__, core.__PIXELS__); obj.style.opacity = 1; var opacityVal = 1; core.__floor = window.setInterval(function () { opacityVal -= 0.03; obj.style.opacity = opacityVal; if (opacityVal < 0) { end(); deleteCanvas(); } }, info.time / 1.7); } core.events._changeFloor_afterChange(info, callback); /*core.hideWithAnimate(core.dom.floorMsgGroup, info.time / 4, function () { core.events._changeFloor_afterChange(info, callback); });*/ } }, "标题动画": function () { var start = document.getElementById('startPanel'); var list = []; var id = 0; /* // 标题 var title = document.getElementById('startTitle'); core.registerResize('startTitle', function () { title.style.width = 300 * core.domStyle.scale + 'px'; title.style.height = 187 * core.domStyle.scale + 'px'; }); */ // 星星动画,使用sprite化方法 function draw() { if (start.style.display === 'none') return; // 每帧有10%的概率出 if (Math.random() < 0.1) { var config = { x: Math.random() * 450 * core.domStyle.scale, y: -187 * core.domStyle.scale, id: id++ }; if (id > 100) id -= 100; list.push(config); // 追加新的ele var img = document.createElement('img'); img.src = './project/images/Title_starlong.png'; img.style.position = 'absolute'; img.style.zIndex = '280'; img.style.left = config.x + 'px'; img.style.top = '0px'; img.style.transform = 'scale(' + core.domStyle.scale * 100 + '%)' img.id = id + '_star'; list[list.length - 1].ele = img; start.appendChild(img); } update(); } // 每帧更新动画 function update() { for (var i = 0; i < list.length; i++) { // 一定要匀速运动 var one = list[i]; if (one.x < -154 * core.domStyle.scale) { list.splice(i, 1); i--; one.ele.remove(); continue; } one.x -= 3 * core.domStyle.scale; one.y += 3 * core.domStyle.scale; one.ele.style.top = one.y + 'px'; one.ele.style.left = one.x + 'px'; } } core.registerAnimationFrame('startAnimation', false, draw); }, "showValue": function () { /* 宝石血瓶左下角显示数值 * 需要将 变量:itemDetail改为true才可正常运行 * 请尽量减少勇士的属性数量,否则可能会出现严重卡顿 * 注意:这里的属性必须是core.status.hero里面的,flag无法显示 * 如果不想显示,可以core.setFlag("itemDetail", false); * 然后再core.getItemDetail(); * 如有bug在大群或造塔群@古祠 */ // 谁tm在即捡即用效果里面调用带有含刷新状态栏的函数 var origin = core.control.updateStatusBar; core.updateStatusBar = core.control.updateStatusBar = function () { if (core.getFlag('__statistics__')) return; else return origin.apply(core.control, arguments); } core.bigmap.threshold = 256; core.control.updateDamage = function (floorId, ctx) { floorId = floorId || core.status.floorId; if (!floorId || core.status.gameOver || main.mode != 'play') return; var onMap = ctx == null; // 没有怪物手册 if (!core.hasItem('book')) return; core.status.damage.posX = core.bigmap.posX; core.status.damage.posY = core.bigmap.posY; if (!onMap) { var width = core.floors[floorId].width, height = core.floors[floorId].height; // 地图过大的缩略图不绘制显伤 if (width * height > core.bigmap.threshold) return; } this._updateDamage_damage(floorId, onMap); this._updateDamage_extraDamage(floorId, onMap); core.getItemDetail(floorId); // 宝石血瓶详细信息 this.drawDamage(ctx); }; // 绘制地图显示 control.prototype._drawDamage_draw = function (ctx, onMap) { if (!core.hasItem('book')) return; // *** 下一句话可以更改你想要的显示字体 core.setFont(ctx, "bold 11px Arial"); // *** core.setTextAlign(ctx, 'left'); core.status.damage.data.forEach(function (one) { var px = one.px, py = one.py; if (onMap && core.bigmap.v2) { px -= core.bigmap.posX * 32; py -= core.bigmap.posY * 32; if (px < -32 * 2 || px > core.__PX__ + 32 || py < -32 || py > core.__PY__ + 32) return; } core.fillBoldText(ctx, one.text, px, py, one.color); }); core.setTextAlign(ctx, 'center'); core.status.damage.extraData.forEach(function (one) { var px = one.px, py = one.py; if (onMap && core.bigmap.v2) { px -= core.bigmap.posX * 32; py -= core.bigmap.posY * 32; if (px < -32 || px > core.__PX__ + 32 || py < -32 || py > core.__PY__ + 32) return; } core.fillBoldText(ctx, one.text, px, py, one.color); }); }; // 获取宝石信息 并绘制 this.getItemDetail = function (floorId) { if (!core.getFlag("itemDetail")) return; floorId = floorId || core.status.thisMap.floorId; core.status.maps[floorId].blocks.forEach(function (block) { if (block.event.cls !== 'items' || block.event.id === 'superPotion') return; var x = block.x, y = block.y; // v2优化,只绘制范围内的部分 if (core.bigmap.v2) { if (x < core.bigmap.posX - core.bigmap.extend || x > core.bigmap.posX + core.__SIZE__ + core.bigmap.extend || y < core.bigmap.posY - core.bigmap.extend || y > core.bigmap.posY + core.__SIZE__ + core.bigmap.extend) { return; } } var id = block.event.id; var item = core.material.items[id]; if (item.cls === 'equips') { // 装备也显示 var diff = core.clone(item.equip.value || {}); var per = item.equip.percentage; for (var name in per) { diff[name + 'per'] = per[name].toString() + '%'; } drawItemDetail(diff, x, y); return; } var before = core.clone(core.status.hero); // 跟数据统计原理一样 执行效果 前后比较 core.setFlag("__statistics__", true); try { eval(item.itemEffect); } catch (error) {} var diff = compareObject(before, core.status.hero); core.status.hero = hero = before; flags = core.status.hero.flags; drawItemDetail(diff, x, y); }); }; // 比较两个对象之间每一项的数值差异(弱等于) 返回数值差异 function compareObject(a, b) { a = a || {}; b = b || {}; var diff = {}; // 差异 for (var name in a) { diff[name] = b[name] - (a[name] || 0); if (!diff[name]) diff[name] = void 0; } return diff; }; // 绘制 function drawItemDetail(diff, x, y) { var px = 32 * x + 2, py = 32 * y + 30; var content = ""; // 获得数据和颜色 var i = 0; for (var name in diff) { if (!diff[name]) continue; var color = "#ffffff"; if (typeof diff[name] === 'number') diff[name] = core.formatBigNumber(diff[name], true); switch (name) { case 'atk': case 'atkper': color = "#FF7A7A"; break; case 'def': case 'defper': color = "#00E6F1"; break; case 'mdef': case 'mdefper': color = "#6EFF83"; break; case 'hp': color = "#A4FF00"; break; case 'hpmax': case 'hpmaxper': color = "#F9FF00"; break; case 'mana': color = "#cc6666"; break; } content = diff[name]; // 绘制 core.status.damage.data.push({ text: content, px: px, py: py - 10 * i, color: color }); i++; } } }, "autoBattle": function () { /** * --------------- 安装说明 --------------- * * 复制到插件编写里面即可 * * --------------- 使用说明 --------------- * * 把变量 __autoBattle__ 设置成true开启,设置成false关闭,然后在想要清的时刻,比如战后,每步后等加上core.autoBattle()即可 * * --------------- 自定义说明 --------------- * * 可以更改canBattle函数自定义某个怪物是否应该被清 */ /** * 是否清这个怪,可以修改这里来实现对不同怪的不同操作 * @param {string} enemy * @param {number} x * @param {number} y */ function canBattle(enemy, x, y) { const loc = `${x},${y}`; const floor = core.floors[core.status.floorId]; const e = core.material.enemys[enemy]; const hasEvent = has(floor.afterBattle[loc]) || has(floor.beforeBattle[loc]) || has(e.beforeBattle) || has(e.afterBattle) || has(floor.events[loc]); // 有事件,不清 if (hasEvent) return false; const damage = core.getDamageInfo(enemy, void 0, x, y); // 0伤或负伤,清 if (has(damage) && has(damage.damage) && damage.damage <= 0) return true; return false; } /** * @template T * @param {T} v * @returns {v is NonNullable} */ function has(v) { return v !== null && v !== undefined; } /** * 广搜,搜索可以到达的需要清的怪 * @param {string} floorId */ function bfs(floorId, deep = Infinity) { core.extractBlocks(floorId); const objs = core.getMapBlocksObj(floorId); const { x, y } = core.status.hero.loc; /** @type {[direction, number, number][]} */ const dir = Object.entries(core.utils.scan).map(v => [ v[0], v[1].x, v[1].y ]); /** @type {[number, number][]} */ const queue = [ [x, y] ]; const mapped = { [`${x},${y}`]: true }; while (queue.length > 0 && deep > 0) { const [nx, ny] = queue.shift(); dir.forEach(v => { const [tx, ty] = [nx + v[1], ny + v[2]]; const loc = `${tx},${ty}`; if (mapped[loc]) return; const block = objs[loc]; mapped[loc] = true; const isEnemy = has(block) && block.event.cls.startsWith('enemy'); const changeFloor = core.floors[floorId].changeFloor[loc]; if ( (!core.canMoveHero(nx, ny, v[0]) && !isEnemy) || (has(block) && block.event.cls === 'items') || (core.noPass(tx, ty) && !isEnemy) || has(core.floors[floorId].events[loc]) || (has(changeFloor) && changeFloor.ignoreChangeFloor === false) ) return; if (isEnemy) { if (canBattle(block.event.id, tx, ty) && !block.disable) { console.log(block.event.id, tx, ty); // 能打且没有事件就直接干他丫的 core.battle(block.event.id, tx, ty); } else return; } // 然后判断目标点是否有地图伤害等,没有就直接添加到队列 const damage = core.status.checkBlock.damage[loc]; const ambush = core.status.checkBlock.ambush[loc]; const repulse = core.status.checkBlock.repulse[loc]; if ( (!has(damage) || (has(damage) && damage <= 0)) && !has(ambush) && !has(repulse) ) queue.push([tx, ty]); }); deep--; } } this.autoBattle = function () { if (!flags.__autoBattle__) return; // 如果勇士当前点有地图伤害,只清周围 const { x, y } = core.status.hero.loc; const floor = core.floors[core.status.floorId]; const hasEvent = has(floor.events[`${x},${y}`]); if (hasEvent) return; const damage = core.status.checkBlock.damage[`${x},${y}`]; let deep = Infinity; if (has(damage) && damage > 0) { deep = 1; } bfs(core.status.floorId, deep); }; }, "autoGet": function () { var enable = true; if (!enable) return; // // var noUpdate = false; ////// 更新状态栏 ////// 不建议状态栏刷新后触发 容易导致录像不一致的问题 //control.prototype.updateStatusBar = function (doNotCheckAutoEvents) { // if (!core.isPlaying()) return; // if (noUpdate) return; // noUpdate = true; // core.autoGetItem(); // noUpdate = false; // this.controldata.updateStatusBar(); // if (!doNotCheckAutoEvents) core.checkAutoEvents(); // this._updateStatusBar_setToolboxIcon(); // core.clearRouteFolding(); //} ////// 每移动一格后执行的事件 ////// control.prototype.moveOneStep = function (callback) { core.autoGetItem(); core.autoBattle(); return this.controldata.moveOneStep(callback); } function bfsFlood(sx, sy, blockfn) { var canMoveArray = core.generateMovableArray(); var blocksObj = core.getMapBlocksObj(); var bgMap = core.getBgMapArray(); var visited = [], queue = []; visited[sx + "," + sy] = 0; queue.push(sx + "," + sy); while (queue.length > 0) { var now = queue.shift().split(","), x = ~~now[0], y = ~~now[1]; for (var direction in core.utils.scan) { if (!core.inArray(canMoveArray[x][y], direction)) continue; var nx = x + core.utils.scan[direction].x, ny = y + core.utils.scan[direction].y, nindex = nx + "," + ny; if (visited[nindex]) continue; if (core.onSki(bgMap[ny][nx])) continue; if (blockfn && !blockfn(blocksObj, nx, ny)) continue; visited[nindex] = visited[now] + 1; queue.push(nindex); } } } function attractAnimate() { var name = 'attractAnimate'; var isPlaying = false; this.nodes = []; this.add = function (id, x, y, callback) { this.nodes.push({ id: id, x: x, y: y, callback: callback }); } this.start = function () { if (isPlaying) return; isPlaying = true; core.registerAnimationFrame(name, true, this.update); this.ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 120); } this.remove = function () { core.unregisterAnimationFrame(name); core.deleteCanvas(name); isPlaying = false; } this.clear = function () { this.nodes = []; this.remove(); } var lastTime = -1; var self = this; this.update = function (timeStamp) { if (lastTime < 0) lastTime = timeStamp; if (timeStamp - lastTime < 20) return; lastTime = timeStamp; core.clearMap(name); var cx = core.status.heroCenter.px - 16, cy = core.status.heroCenter.py - 16; var thr = 5; //缓动比例倒数 越大移动越慢 self.nodes.forEach(function (n) { var dx = cx - n.x, dy = cy - n.y; if (Math.abs(dx) <= thr && Math.abs(dy) <= thr) { n.dead = true; } else { n.x += ~~(dx / thr); n.y += ~~(dy / thr); } core.drawIcon(name, n.id, n.x, n.y, 32, 32); }); self.nodes = self.nodes.filter(function (n) { if (n.dead && n.callback) { n.callback(); } return !n.dead; }); if (self.nodes.length == 0) self.remove(); } } var animateHwnd = new attractAnimate(); this.stopAttractAnimate = function () { animateHwnd.clear(); } this.autoGetItem = function () { if (!flags.__autoGetItem__) return; var canGetItems = {}; if (!core.status.floorId || !core.status.checkBlock.damage || core.status.event.id == 'action' || core.status.lockControl) return; bfsFlood(core.getHeroLoc('x'), core.getHeroLoc('y'), function (blockMap, x, y) { var idx = x + ',' + y; if (idx in canGetItems) return false; var blk = blockMap[idx]; if (blk && !blk.disable && blk.event.cls == 'items' && !core.isMapBlockDisabled(core.status.floorId, blk.x, blk.y) && blk.event.trigger == 'getItem') { canGetItems[idx] = { x: x, y: y, id: blk.event.id }; return !core.status.checkBlock.damage[idx] && !core.status.checkBlock.ambush[idx]; } return core.maps._canMoveDirectly_checkNextPoint(blockMap, x, y); }); for (var k in canGetItems) { var x = canGetItems[k].x, y = canGetItems[k].y, id = canGetItems[k].id; core.trigger(x, y); animateHwnd.add(id, x * 32, y * 32); } animateHwnd.start(); } }, "怪物手册和显伤": function () { // 在此增加新插件 ////// 获得所有特殊属性的名称 ///// core.enemys.getSpecialText = function (enemy) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (!enemy) return []; var special = enemy.special; var text = []; var specials = this.getSpecials(); if (specials) { for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(special, specials[i][0])) text.push(this._calSpecialContent(enemy, specials[i][1])); } } if (special === 0) { text.push('普通'); ///////无特殊属性时增加“普通”属性显示 } return text; } ////// 获得所有特殊属性的颜色 ////// core.enemys.getSpecialColor = function (enemy) { if (typeof enemy == 'string') enemy = core.material.enemys[enemy]; if (!enemy) return []; var special = enemy.special; var colors = []; var specials = this.getSpecials(); if (specials) { for (var i = 0; i < specials.length; i++) { if (this.hasSpecial(special, specials[i][0])) colors.push(specials[i][3] || null); } } if (special === 0) { colors.push("#ffffff"); ////“普通”属性显示为白色 } return colors; } }, "仿RM渐变效果": function () { // 在此增加新插件 // 准备渐变 this.maskPrepare = function () { // 执行后画面将凝固 core.createCanvas("mask", 0, 0, core.__PIXELS__, core.__PIXELS__, 155); for (var m in core.canvas) { core.dymCanvas.mask.drawImage(core.canvas[m].canvas, 0, 0); }; } // 执行渐变 this.maskFliter = function (time, sample) { // sample为渐变图名称,渐变图需要在全塔属性注册 var tempCanvas = core.bigmap.tempCanvas; var tempWidth = core.__PIXELS__, tempHeight = core.__PIXELS__; tempCanvas.canvas.width = tempWidth; tempCanvas.canvas.height = tempHeight; tempCanvas.clearRect(0, 0, tempWidth, tempHeight); tempCanvas.drawImage(core.material.images.images[sample], 0, 0, tempWidth, tempHeight); // 读取渐变图开始处理 var sampleData = tempCanvas.getImageData(0, 0, tempWidth, tempHeight); var processData = core.dymCanvas.mask.getImageData(0, 0, tempWidth, tempHeight); tempCanvas.clearRect(0, 0, tempWidth, tempHeight); var timer = 0; var animate = setInterval(function () { timer++; for (var i = 0; i < sampleData.data.length; i += 4) { if (sampleData.data[i] < timer) { processData.data[i] = 0; processData.data[i + 1] = 0; processData.data[i + 2] = 0; processData.data[i + 3] = 0; } } core.dymCanvas.mask.putImageData(processData, 0, 0); if (timer == 255) { delete core.animateFrame.asyncId[animate]; clearInterval(animate); core.deleteCanvas("mask"); } }, time / 256); core.animateFrame.asyncId[animate] = true; } }, "标题界面监听按钮": function () { // 在此增加新插件 //////用于监听标题界面的键盘操作和鼠标移动操作,然后高亮显示当前选择的光标 if (main.replayChecking) return; ////录像过程中 if (core.status.played) return; ////游戏开始后 var i = 1; if (core.dom.playGame.getAttribute('selected')) i = 1; ////第一项,开始游戏 else if (core.dom.loadGame.getAttribute('selected')) i = 2; ////第二项,继续游戏 else if (core.dom.replayGame.getAttribute('selected')) i = 3; /////第三项,录像回放 ////当鼠标离开某个选项 document.getElementById("playGame").addEventListener("mouseleave", function () { core.dom.playGame.setAttribute('selected', true); core.dom.loadGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); i = 1; }); document.getElementById("loadGame").addEventListener("mouseleave", function () { core.dom.loadGame.setAttribute('selected', true); core.dom.playGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); i = 2; }); document.getElementById("replayGame").addEventListener("mouseleave", function () { core.dom.replayGame.setAttribute('selected', true); core.dom.playGame.setAttribute('selected', false); core.dom.loadGame.setAttribute('selected', false); i = 3; }); ////当鼠标移动到某个选项 document.getElementById("playGame").addEventListener("mouseenter", function () { core.dom.playGame.setAttribute('selected', true); core.dom.loadGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); i = 1; }); document.getElementById("loadGame").addEventListener("mouseenter", function () { core.dom.loadGame.setAttribute('selected', true); core.dom.playGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); i = 2; }); document.getElementById("loadGame").addEventListener("click", function () { core.dom.playGame.setAttribute('selected', true); core.dom.loadGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); i = 1; }); document.getElementById("replayGame").addEventListener("mouseenter", function () { core.dom.replayGame.setAttribute('selected', true); core.dom.playGame.setAttribute('selected', false); core.dom.loadGame.setAttribute('selected', false); i = 3; }); /////按键操作 document.body.addEventListener('keyup', e => { if (e.keyCode === 38) { i = (i - 1) || 3; // 上。。。 } else if (e.keyCode === 40) { i = (i + 1) % 4 || 1; // 下。。。 } else if (i !== 3 && (e.keyCode === 32 || e.keyCode === 13 || e.keyCode === 67)) { i = 1; /////确认键,且不是录像回放 } core.dom.playGame.setAttribute('selected', false); core.dom.loadGame.setAttribute('selected', false); core.dom.replayGame.setAttribute('selected', false); if (i === 1) core.dom.playGame.setAttribute('selected', true); else if (i === 2) core.dom.loadGame.setAttribute('selected', true); else if (i === 3) core.dom.replayGame.setAttribute('selected', true); }) }, "仿RM楼传": function () { // 在此增加新插件 core.ui.drawFly = function (page) { if (!core.getFlag("isRmFly")) { ///////H5版楼传 core.status.event.data = page; var floorId = core.floorIds[page]; var title = core.status.maps[floorId].title; core.clearMap('ui'); core.setAlpha('ui', 0.85); core.fillRect('ui', 0, 0, core._PX_, core._PY_, '#000000'); core.setAlpha('ui', 1); core.setTextAlign('ui', 'center'); core.fillText('ui', '楼层跳跃', core._PX_ / 2, 48, '#FFFFFF', this._buildFont(28, true)); core.fillText('ui', '返回游戏', core._PX_ / 2, core._PY_ - 13, null, this._buildFont(15, true)) core.setTextAlign('ui', 'right'); core.fillText('ui', '浏览地图时也', core._PX_ - 10, core._PY_ - 23, '#aaaaaa', this._buildFont(10, false)); core.fillText('ui', '可楼层跳跃!', core._PX_ - 10, core._PY_ - 11, null, this._buildFont(10, false)); core.setTextAlign('ui', 'center'); var middle = core._PY_ / 2 + 39; // 换行 var lines = core.splitLines('ui', title, 120, this._buildFont(19, true)); var start_y = middle - (lines.length - 1) * 11; for (var i in lines) { core.fillText('ui', lines[i], core._PX_ - 53, start_y, '#FFFFFF', this._buildFont(17, true)); start_y += 22; } if (core.actions._getNextFlyFloor(1) != page) { core.fillText('ui', '▲', core._PX_ - 60, middle - 64, null, this._buildFont(17, false)); core.fillText('ui', '▲', core._PX_ - 60, middle - 96); core.fillText('ui', '▲', core._PX_ - 60, middle - 96 - 7); } if (core.actions._getNextFlyFloor(-1) != page) { core.fillText('ui', '▼', core._PX_ - 60, middle + 64, null, this._buildFont(17, false)); core.fillText('ui', '▼', core._PX_ - 60, middle + 96); core.fillText('ui', '▼', core._PX_ - 60, middle + 96 + 7); } var size = 0.75; core.strokeRect('ui', 16, 64, size * core._PX_, size * core._PY_, '#FFFFFF', 2); core.drawThumbnail(floorId, null, { ctx: 'ui', x: 16, y: 64, size: size, damage: true, all: true }); } else { //////RM版楼传 core.status.event.data = page; var floorId = core.floorIds[page]; var title = core.status.maps[floorId].title; var maxFloorId = 81; var minFloorId = 49; if (core.status.played) { if (!core.status.thisMap.underGround) while (core.hasVisitedFloor('MT' + maxFloorId) === false && maxFloorId >= 0) { maxFloorId-- } else while (core.hasVisitedFloor('UT' + minFloorId) === false && minFloorId >= 1) { minFloorId-- } } core.clearMap('ui'); core.createCanvas('flyText', 0, 0, 480, 480, 141); core.setOpacity("flyText", 0.7); core.drawThumbnail(floorId, null, { ctx: 'ui', x: 0, y: 0, size: 1, damage: true, all: true }); core.drawWindowSkin('winskin2.png', 'flyText', 0, 304, core._PX_ - 10, 160); core.setTextAlign('flyText', 'left'); if (!core.status.thisMap.underGround) core.fillText('flyText', '请输入您要去的楼层(0~' + maxFloorId + '):', 20, 304 + 40, '#FFFFFF', this._buildFont(22, false)); else { core.fillText('flyText', '请输入您要去的', 20, 304 + 40, '#FFFFFF', this._buildFont(22, false)); core.fillText('flyText', '地下楼层', 20 + 154, 304 + 40, '#aaaaaa', this._buildFont(22, false)); core.fillText('flyText', '(1~' + minFloorId + '):', 20 + 242, 304 + 40, '#FFFFFF', this._buildFont(22, false)); } core.fillText('flyText', title, 20, 304 + 72, '#FFFFFF', this._buildFont(22, false)); core.setTextAlign('ui', 'right'); core.fillText('ui', '浏览地图时也', core._PX_ - 10, core._PY_ - 23, '#aaaaaa', this._buildFont(10, false)); core.fillText('ui', '可楼层跳跃!', core._PX_ - 10, core._PY_ - 11, null, this._buildFont(10, false)); core.setTextAlign('flyText', 'center'); var middle = core._PY_ / 2 + 39; if (core.actions._getNextFlyFloor(1) != page) { core.fillText('flyText', '▲', core._PX_ - 112, middle + 64, null, this._buildFont(24, false)); core.fillText('flyText', '◀', core._PX_ - 144, middle + 96); } if (core.actions._getNextFlyFloor(-1) != page) { core.fillText('flyText', '▼', core._PX_ - 112, middle + 128, null, this._buildFont(24, false)); core.fillText('flyText', '▶', core._PX_ - 80, middle + 96); } } } ////// 楼层传送器界面时的点击操作 ////// actions.prototype._clickFly = function (x, y) { if (!core.getFlag("isRmFly")) { ///H5版 if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ + 3) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-1)); } if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ - 1) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(1)); } if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ + 4) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-10)); } if ((x == core._WIDTH_ - 2 || x == core._WIDTH_ - 3) && y == this._HY_ - 2) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(10)); } if (x >= this._HX_ - 1 && x <= this._HX_ + 1 && y === core._HEIGHT_ - 1) { core.playSound('取消'); core.ui.closePanel(); } if (x >= 0 && x <= this._HX_ + 3 && y >= 3 && y <= core._HEIGHT_ - 1 - 1) core.flyTo(core.floorIds[core.status.event.data]); return; } else { ////RM版 if ((x == core._WIDTH_ - 4) && y == this._HY_ + 5) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-1)); } else if ((x == core._WIDTH_ - 4) && y == this._HY_ + 3) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(1)); } else if ((x == core._WIDTH_ - 5) && y == this._HY_ + 4) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(-10)); } else if ((x == core._WIDTH_ - 3) && y == this._HY_ + 4) { core.playSound('光标移动'); core.ui.drawFly(this._getNextFlyFloor(10)); } else if (x >= this._HX_ - 1 && x <= this._HX_ + 1 && y === core._HEIGHT_ - 1) { core.playSound('取消'); core.ui.closePanel(); } else if (x >= 0 && x <= this._HX_ + 3 && y >= 3 && y <= core._HEIGHT_ - 1 - 1) core.flyTo(core.floorIds[core.status.event.data]); return; } } }, "按S跳过剧情": function () { // 在此增加新插件 if (core.status.played) return; ////游戏开始后 core.registerAction('keyDown', "useS_PASS", function (keycode) { /////按下某个键 if (!core.getFlag('useS_PASS')) return false; }, 100); var _my_useS_PASS = function (keycode) { ////放开某个键 if (!core.getFlag('useS_PASS')) return false; if (keycode == 83) { ////按下S时 core.Confirmskip(); } }; core.registerAction('keyUp', 'useS_PASS', _my_useS_PASS, 100); core.registerAction('ondown', 'useS_PASS', function (x, y, px, py) { if (!core.getFlag('useS_PASS')) return false; if (x >= 7 && y <= 2) { core.Confirmskip(); } }, 100); core.Confirmskip = function () { ////跳过剧情确认框 core.status.hero.flags.useS_PASS = false; ////禁用按S跳过 core.status.hero.flags.Confirmskip = true; core.status.hero.flags.ConfirmskipChoose = 0; core.createCanvas('Confirmskip', 0, 0, 480, 480, 200); core.createCanvas('Confirmskip_text', 0, 0, 480, 480, 202); core.drawWindowSkin('winskin.png', 'Confirmskip', 48, 182, 176, 96); core.fillText('Confirmskip_text', '不跳过剧情', 70, 222, "#ffffff", ui.prototype._buildFont(22, false)) core.fillText('Confirmskip_text', '跳过剧情', 70, 248, "#ffffff", ui.prototype._buildFont(22, false)) core.drawUIEventSelector(1, 'winskin.png', 70, 202, 120, 24, 201); ////绘制光标 } core.registerAction('keyDown', "Confirmskip", function (keycode) { /////按下某个键 if (!core.getFlag('Confirmskip')) return false; return true; ///全部拦截 }, 100); var _my_Confirmskip = function (keycode) { ////放开某个键 if (!core.getFlag('Confirmskip')) return false; if ((keycode == 13 || keycode == 32 || keycode == 67)) { ////按下空格\回车\C时 if (core.status.hero.flags.ConfirmskipChoose === 1) { ///选择为跳过剧情 core.ConfirmskipOK(); } else { ///选择为不跳过剧情 core.status.hero.flags.useS_PASS = true; ////允许按S的开关 core.status.hero.flags.Confirmskip = false; core.clearMap('Confirmskip') /////清除画布 core.clearMap('Confirmskip_text') core.clearUIEventSelector(1); ////清除光标 } } else if (keycode == 38 || keycode == 40) ///上下切换 { core.setFlag('ConfirmskipChoose', 1 ^ (core.getFlag('ConfirmskipChoose') || 0)); if (core.status.hero.flags.ConfirmskipChoose === 0) core.drawUIEventSelector(1, 'winskin.png', 70, 202, 120, 24, 201); ////绘制光标 else core.drawUIEventSelector(1, 'winskin.png', 70, 229, 120, 24, 201); ////绘制光标 } return true; ///全部拦截 }; core.registerAction('keyUp', 'Confirmskip', _my_Confirmskip, 100); core.registerAction('ondown', 'Confirmskip', function (x, y, px, py) { if (!core.getFlag('Confirmskip')) return false; if (x >= 3 && x <= 6 && y === 6) { if (core.status.hero.flags.ConfirmskipChoose === 0) { ///选择为不跳过剧情 core.status.hero.flags.useS_PASS = true; ////允许按S的开关 core.status.hero.flags.Confirmskip = false; core.clearMap('Confirmskip') /////清除画布 core.clearMap('Confirmskip_text') core.clearUIEventSelector(1); ////清除光标 } else { core.status.hero.flags.ConfirmskipChoose = 0; core.drawUIEventSelector(1, 'winskin.png', 70, 202, 120, 24, 201); ////绘制光标 } } else if (x >= 3 && x <= 6 && y === 7) { if (core.status.hero.flags.ConfirmskipChoose === 1) { core.ConfirmskipOK(); } else { core.status.hero.flags.ConfirmskipChoose = 1; core.drawUIEventSelector(1, 'winskin.png', 70, 229, 120, 24, 201); ////绘制光标 } } return true; ///全部拦截 }, 100); core.ConfirmskipOK = function () { ////决定跳过剧情 core.status.hero.flags.Confirmskip = false; core.clearMap('Confirmskip') /////清除画布 core.clearMap('Confirmskip_text') core.clearUIEventSelector(1); ////清除光标 core.deleteAllCanvas(); ///清空画布 core.status.hero.flags.SkipThePlot = true; ////跳过事件开关开启 core.insertAction({ "type": "exit" }); if (core.hasAsync()) core.insertAction({ "type": "stopAsync" }); ///结束异步 core.insertAction({ "type": "insert" }); ///重新触发当前事件 core.doAction(); ///执行下一个事件 core.status.hero.flags.tiaojuqing_black = 0; ///闪烁开关归0 } core.Confirmskip_On = function () { core.status.hero.flags.useS_PASS = true; core.insertCommonEvent('跳过事件图片'); core.createCanvas('tiaojuqing_black', 0, 0, 480, 480, 151); /// core.setFilter('tiaojuqing_black', 'brightness(0%)'); core.setOpacity('tiaojuqing_black', 0); core.drawImage('tiaojuqing_black', 'tiaojuqing.png', 0, 0, 324, 95, 240, 0, 243, 71); core.status.hero.flags.tiaojuqing_black = 100; ///闪烁开关,此数值也影响闪烁的明暗,为100时刚刚开始闪烁 } core.Confirmskip_Off = function () { core.status.hero.flags.useS_PASS = false; core.insertCommonEvent('跳过事件图片'); core.status.hero.flags.tiaojuqing_black = 0; ///闪烁开关归0 } } }