tianta/project/plugins.js
Erdnase ad30bd4dda 新增一张内部完全透明的winskin图用于绘制
打开道具栏和手册时自绘状态栏效果改动
绘制道具栏改动
部分道具说明,以及是否在道具栏中显示改变(钥匙和手册)
2022-11-24 00:05:47 +13:00

3447 lines
130 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 =
{
"init": function () {
this._afterLoadResources = function () {
// 本函数将在所有资源加载完毕后,游戏开启前被执行
}
try {
window.screen.orientation.lock("landscape-primary");
} catch (e) {}
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]")
]);
}
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;
}
}
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) ///取消用动画的绘制,改用图标绘制
/*
// 检查大怪物
if (blockInfo.bigImage) {
core.status.boxAnimateObjs.push({
bigImage: blockInfo.bigImage,
face: blockInfo.face,
centerX: border_left + 21,
centerY: border_top + 21,
max_width: 60
});
} else if (blockInfo.height >= 42) {
var originEnemy = core.material.enemys[enemy.id] || {};
// 检查上半部分是不是纯透明的;取用原始值避免重复计算
if (originEnemy.is32x32 == null) {
originEnemy.is32x32 = this._drawBook_is32x32(blockInfo);
}
if (originEnemy.is32x32) {
core.status.boxAnimateObjs.push({
'bgx': border_left,
'bgy': border_top,
'bgWidth': 42,
'bgHeight': 42,
'x': img_left,
'y': img_top,
'height': 32,
'animate': blockInfo.animate,
'image': blockInfo.image,
'pos': blockInfo.posY * blockInfo.height + blockInfo.height - 32
});
} else {
var drawWidth = 42 * 32 / blockInfo.height;
core.status.boxAnimateObjs.push({
'bgx': border_left,
'bgy': border_top,
'bgWidth': 42,
'bgHeight': 42,
'x': img_left - 5 + (42 - drawWidth) / 2,
'y': img_top - 5,
'dw': drawWidth,
'dh': 42,
'height': blockInfo.height,
'animate': blockInfo.animate,
'image': blockInfo.image,
'pos': blockInfo.posY * blockInfo.height
});
}
} else {
core.status.boxAnimateObjs.push({
'bgx': border_left,
'bgy': border_top,
'bgWidth': 42,
'bgHeight': 42,
'x': img_left,
'y': img_top,
'height': 32,
'animate': blockInfo.animate,
'image': blockInfo.image,
'pos': blockInfo.posY * blockInfo.height
});
}
*/
}
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.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) {
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要打开的商店idnoRoute是否不计入录像
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<T>}
*/
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;
}
}
}