var plugins_bb40132b_638b_4a9f_b028_d3fe47acc8d1 = 
{
    "init": function () {

	console.log("插件编写测试");

	this._afterLoadResources = function () {
		// 本函数将在所有资源加载完毕后，游戏开启前被执行
		// 可以在这个函数里面对资源进行一些操作。
		// 若需要进行切分图片，可以使用 core.splitImage() 函数，或直接在全塔属性-图片切分中操作
		core.ui.statusBar.init();
		/*if (main.mode === 'play') {
			document.querySelectorAll('canvas').forEach(canvas => {
				if (canvas.id !== "damage")
					canvas.style.imageRendering = 'pixelated';
			});
		}
*/
	}

	this.splitArray = function (arr, n = 5) {
		if (arr.length <= n) {
			core.push(arr, {
				"text": "取消",
				"action": [{ "type": "exit" }]
			});
			return arr; // 如果数组长度小于等于n，直接返回
		}

		// 取出前n个元素，保留它们
		let head = arr.slice(0, n);
		// 剩下的元素递归调用 splitArray，生成对象
		core.push(head, {
			"text": "取消",
			"action": [{ "type": "exit" }]
		});
		let tail = {
			"text": "下一页",
			"action": [{
				type: "choices",
				text: "选择要到达的点",
				choices: core.plugin.splitArray(arr.slice(n), n) // 递归拆分剩余部分
			}]
		};

		// 返回前n个元素和包含剩余部分的对象
		return [...head, tail];
	}

	// 可以在任何地方（如afterXXX或自定义脚本事件）调用函数，方法为 core.plugin.xxx();
	// 从V2.6开始，插件中用this.XXX方式定义的函数也会被转发到core中，详见文档-脚本-函数的转发。
},
    "resizeTo11": function () {
	if (main.mode == 'editor') {
		return;
	}

	// 在不修改libs的情况下将页面适配为11x11
	core.__SIZE__ = 11;
	core.__PIXELS__ = core.__SIZE__ * 32;
	core.__HALF_SIZE__ = 5;
	// core.bigmap.width = core.__SIZE__;
	// core.bigmap.height = core.__SIZE__;
	core.actions.SIZE = core.__SIZE__;
	core.actions.HSIZE = core.__HALF_SIZE__;
	core.actions.LAST = core.__SIZE__ - 1;
	core.actions.CHOICES_LEFT = 3;
	core.actions.CHOICES_RIGHT = core.actions.LAST - core.actions.CHOICES_LEFT;
	core.ui.SIZE = core.__SIZE__;
	core.ui.HSIZE = core.__HALF_SIZE__;
	core.ui.LAST = core.__SIZE__ - 1;
	core.ui.PIXEL = core.__PIXELS__;
	core.ui.HPIXEL = core.__PIXELS__ / 2;
},
    "statusBar": function () {
	main.dom.floorMsgGroup.style.display = 'none';
	main.dom.statusBar.style.display = 'none';
	main.dom.toolBar.style.display = 'none';

	const GAMEVIEW_WIDTH = 640;
	const GAMEVIEW_HEIGHT = 422;

	const GAMEVIEW_WIDTH_VERTICAL = 388;
	const GAMEVIEW_HEIGHT_VERTICAL = 630;

	const BAR_WIDTH = 125;
	const BAR_HEIGHT_VERTICAL = 130;
	const BORDER_WIDTH = 18;
	const BORDER_HEIGHT = 24;

	const ITEM_BOX_LEFT = 13;
	const ITEM_BOX_TOP = 190;
	const ITEM_BOX_LEFT_VERTICAL = 8;
	const ITEM_BOX_TOP_VERTICAL = 538;

	const ITEM_ICON_OUTER_SIZE = 33;

	const EQUIP_BLOCK_LEFT = 525;
	const EQUIP_BLOCK_TOP = 40;
	const EQUIP_BLOCK_LEFT_VERTICAL = 108;
	const EQUIP_BLOCK_TOP_VERTICAL = 0;

	const KEY_BLOCK_LEFT = EQUIP_BLOCK_LEFT;
	const KEY_BLOCK_LEFT_VERTICAL = EQUIP_BLOCK_LEFT_VERTICAL;
	const KEY_BLOCK_TOP_VERTICAL = 86;

	const INFO_BLOCK_LEFT = EQUIP_BLOCK_LEFT;
	const INFO_BLOCK_TOP = 220;
	const INFO_BLOCK_LEFT_VERTICAL = 219;
	const INFO_BLOCK_TOP_VERTICAL = 10;

	const TOOL_BOX_LEFT = EQUIP_BLOCK_LEFT;
	const TOOL_BOX_TOP = 318;
	const TOOL_BOX_LEFT_VERTICAL = 278;
	const TOOL_BOX_TOP_VERTICAL = ITEM_BOX_TOP_VERTICAL;

	const TOOL_ICON_OUTER_SIZE = 34;

	const INFO_BAR_HEIGHT = 22;
	const INFO_BAR_HEIGHT_VERTICAL = 18;
	const INFO_BAR_TOP = GAMEVIEW_HEIGHT - INFO_BAR_HEIGHT;
	const INFO_BAR_TOP_VERTICAL = GAMEVIEW_HEIGHT_VERTICAL - INFO_BAR_HEIGHT_VERTICAL;

	const TEXT_COLOR = "#E1E1E1";

	const FORCE_COUNTABLE_ITEMS = ['centerFly'];

	const outerBackground = document.createElement('canvas');
	outerBackground.style.position = 'absolute';
	outerBackground.style.zIndex = 5;
	outerBackground.id = 'outerBackground';
	main.dom.outerBackground = outerBackground;
	main.dom.startPanel.insertAdjacentElement('afterend', outerBackground);

	const outerUI = document.createElement('canvas');
	outerUI.style.position = 'absolute';
	outerUI.style.zIndex = 165;
	outerUI.id = 'outerUI';
	main.dom.outerUI = outerUI;
	outerBackground.insertAdjacentElement('afterend', outerUI);
	setTimeout(function () {
		// Should be executed immediately after init()
		main.canvas.outerUI = outerUI.getContext('2d');
	});
	outerUI.onclick = function (e) {
		try {
			e.preventDefault();
			if (!core.isPlaying()) return false;
			const left = core.dom.gameGroup.offsetLeft;
			const top = core.dom.gameGroup.offsetTop;
			const px = parseInt((e.clientX - left) / core.domStyle.scale),
				py = parseInt((e.clientY - top) / core.domStyle.scale);
			core.ui.statusBar.onclick(px, py);
		} catch (ee) {
			main.log(ee);
		}
	};

	const _resize_gameGroup = function (obj) {
		const gameGroup = core.dom.gameGroup;
		gameGroup.style.width = obj.totalWidth + 'px';
		gameGroup.style.height = obj.totalHeight + 'px';
		gameGroup.style.left =
			(obj.clientWidth - obj.totalWidth) / 2 + 'px';
		gameGroup.style.top =
			(obj.clientHeight - obj.totalHeight) / 2 + 'px';

		core.dom.musicBtn.style.right =
			(obj.clientWidth - obj.totalWidth) / 2 + 'px';
		core.dom.musicBtn.style.bottom =
			(obj.clientHeight - obj.totalHeight) / 2 - 27 + 'px';
		core.dom.enlargeBtn.style.right =
			(obj.clientWidth - obj.totalWidth) / 2 + 31 + 'px';
		core.dom.enlargeBtn.style.bottom =
			(obj.clientHeight - obj.totalHeight) / 2 - 27 + 'px';

		main.dom.startBackground.src = main.styles.startBackground;
	};

	const _resize_canvas = function (obj) {
		main.dom.outerBackground.style.width = obj.totalWidth + 'px';
		main.dom.outerBackground.style.height = obj.totalHeight + 'px';
		main.dom.outerUI.style.width = obj.totalWidth + 'px';
		main.dom.outerUI.style.height = obj.totalHeight + 'px';

		// perf 8: HD compatibility.
		const innerSize = obj.canvasWidth * core.domStyle.scale + 'px';
		const ratio = core.plugin.getHDRatio();
		const hdSize = obj.canvasWidth * ratio;
		for (let i = 0; i < core.dom.gameCanvas.length; ++i) {
			core.dom.gameCanvas[i].style.width = innerSize;
			core.dom.gameCanvas[i].style.height = innerSize;
			if (!core.dom.gameCanvas[i].classList.contains('no-anti')) {
				//console.log(core.dom.gameCanvas[i]);
				//console.log(core.dom.gameCanvas[i].getContext('2d'));
				core.dom.gameCanvas[i].width = hdSize;
				core.dom.gameCanvas[i].height = hdSize;
				core.dom.gameCanvas[i].getContext('2d').scale(ratio, ratio);
			}
		}
		core.dom.gif.style.width = core.dom.gif.style.height = innerSize;
		core.dom.gif2.style.width = core.dom.gif2.style.height = innerSize;
		core.dom.gameDraw.style.width = core.dom.gameDraw.style.height =
			innerSize;
		core.dom.gameDraw.style.top =
			obj.gameDrawBox.top * core.domStyle.scale + 'px';
		core.dom.gameDraw.style.left =
			obj.gameDrawBox.left * core.domStyle.scale + 'px';

		// resize bigmap
		core.bigmap.canvas.forEach(function (cn) {
			const ratio = core.plugin.getHDRatio(core.canvas[cn].canvas);
			core.canvas[cn].canvas.style.width =
				(core.canvas[cn].canvas.width / ratio) *
				core.domStyle.scale +
				'px';
			core.canvas[cn].canvas.style.height =
				(core.canvas[cn].canvas.height / ratio) *
				core.domStyle.scale +
				'px';
		});
		// resize dynamic canvas
		for (const name in core.dymCanvas) {
			const ctx = core.dymCanvas[name],
				canvas = ctx.canvas;
			const ratio = core.plugin.getHDRatio(canvas);
			canvas.style.width =
				(canvas.width / ratio) * core.domStyle.scale + 'px';
			canvas.style.height =
				(canvas.height / ratio) * core.domStyle.scale + 'px';
			canvas.style.left =
				parseFloat(canvas.getAttribute('_left')) *
				core.domStyle.scale +
				'px';
			canvas.style.top =
				parseFloat(canvas.getAttribute('_top')) *
				core.domStyle.scale +
				'px';
		}
		// resize next
		main.dom.next.style.width = main.dom.next.style.height =
			5 * core.domStyle.scale + 'px';
		main.dom.next.style.borderBottomWidth =
			main.dom.next.style.borderRightWidth =
			4 * core.domStyle.scale + 'px';
	};

	core.control.resize = function () {
		if (main.mode == 'editor') return;

		const clientWidth = main.dom.body.clientWidth,
			clientHeight = main.dom.body.clientHeight;
		const canvasWidth = core.__PIXELS__;

		const isVertical = clientHeight > clientWidth;
		core.domStyle.isVertical = isVertical;

		const totalWidth = isVertical ?
			GAMEVIEW_WIDTH_VERTICAL :
			GAMEVIEW_WIDTH,
			totalHeight = isVertical ?
			GAMEVIEW_HEIGHT_VERTICAL :
			GAMEVIEW_HEIGHT;

		const maxRatio = Math.min(
			clientWidth / totalWidth,
			clientHeight / totalHeight
		);

		core.domStyle.availableScale = [];
		[1, 1.25, 1.5, 1.75, 2].forEach(function (v) {
			if (maxRatio >= v) {
				core.domStyle.availableScale.push(v);
			}
		});

		if (core.domStyle.availableScale.indexOf(core.domStyle.scale) < 0) {
			core.domStyle.scale = Math.min(1, maxRatio);
		} else if (
			core.getLocalStorage('scale') == null &&
			core.domStyle.availableScale.length >= 2
		) {
			core.domStyle.scale =
				core.domStyle.availableScale[
					core.domStyle.availableScale.length - 2
				];
			core.setLocalStorage('scale', core.domStyle.scale);
		}

		const totalWidthScaled = totalWidth * core.domStyle.scale,
			totalHeightScaled = totalHeight * core.domStyle.scale;

		const gameDrawBox = isVertical ? {
			left: BORDER_WIDTH,
			top: BAR_HEIGHT_VERTICAL + BORDER_HEIGHT
		} : { left: BAR_WIDTH + BORDER_WIDTH, top: BORDER_HEIGHT };

		const obj = {
			clientWidth: clientWidth,
			clientHeight: clientHeight,
			canvasWidth: canvasWidth,
			totalWidth: totalWidthScaled,
			totalHeight: totalHeightScaled,
			gameDrawBox: gameDrawBox,
			globalAttribute: core.status.globalAttribute ||
				core.initStatus.globalAttribute
		};

		_resize_gameGroup(obj);
		_resize_canvas(obj);

		if (core.status.automaticRoute == null)
			core.status.automaticRoute = {};
		core.control.setViewport(32, 32);
		if (core.canvas.outerUI) {
			core.ui.statusBar._update_background();
			core.ui.statusBar._update_toolBox();
		}
		core.drawMap();
	};

	class StatusBar {
		constructor() {
			this.infoText = undefined;
			this.infocnt = 0;
			this.itemMx = [
				["book", "wand", "fly"],
				["cross", "superPotion", "pickaxe"],
				["bomb", "centerFly", "upFly"],
				["downFly", "knife", "snow"],
				["bigKey", "earthquake", "coin"],
				["skill1"]
			];
			this.itemMxVertical = [
				["book", "wand", "fly", "cross", "superPotion", "pickaxe", "bomb", "centerFly"],
				["upFly", "downFly", "knife", "snow", "bigKey", "earthquake", "coin", "skill1"],
			];
		}
		init() {
			this.toolbarAction = [
				[
					main.core.openKeyBoard,
					main.core.openQuickShop,
					function () {
						core.insertAction([
							{ type: 'insert', name: '游戏说明' }
						]);
					}
				],
				[main.core.save, main.core.load, main.core.openSettings]
			];
			this.replayAction = [
				[core.triggerReplay, core.stopReplay, core.rewindReplay],
				[core.speedDownReplay, core.speedUpReplay, core.saveReplay]
			];
		}
		update() {
			//this._update_background();
			this._update_props();
			this._update_items();
			this._update_equips();
			this._update_keys();
			//this._update_infoWindow();
			this._update_infoBar();
		}
		_update_background(updatedFloorTitle) {
			const bgctx = main.dom.outerBackground.getContext('2d');
			const uictx = main.dom.outerUI.getContext('2d');
			if (bgctx && uictx) {
				const isVertical = core.domStyle.isVertical;
				const ratio = core.plugin.getHDRatio();

				const W = isVertical ? GAMEVIEW_WIDTH_VERTICAL : GAMEVIEW_WIDTH;
				const H = isVertical ? GAMEVIEW_HEIGHT_VERTICAL : GAMEVIEW_HEIGHT;
				const bgImg = core.material.images.images[
					isVertical ? 'statusBackground_vertical.png' : 'statusBackground.png'
				];

				// 设置 canvas 尺寸
				bgctx.canvas.width = W * ratio;
				bgctx.canvas.height = H * ratio;
				uictx.canvas.width = W * ratio;
				uictx.canvas.height = H * ratio;

				// 重置 transform 后再缩放
				bgctx.setTransform(1, 0, 0, 1, 0, 0);
				uictx.setTransform(1, 0, 0, 1, 0, 0);
				bgctx.scale(ratio, ratio);
				uictx.scale(ratio, ratio);
				bgctx.imageSmoothingEnabled = false;

				// 绘制背景图
				if (bgImg instanceof Image && bgImg.complete) {
					bgctx.drawImage(bgImg, 0, 0, W, isVertical ? H : (H - INFO_BAR_HEIGHT));
				} else {
					console.warn('[statusBar] 背景图未加载完成，跳过绘制');
				}

				// 绘制 infoBar 背景色（横屏专用）
				if (!isVertical) {
					bgctx.fillStyle = '#676767';
					bgctx.fillRect(0, INFO_BAR_TOP, W, INFO_BAR_HEIGHT);
				}
				core.setTextAlign('outerUI', 'center');
			}
		}
		// 更新属性
		_update_props(updatedFloorTitle) {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				const statusList = ['hp', 'atk', 'def', 'money'];
				const TEXT_COLOR = "#E1E1E1";

				const isVertical = core.domStyle.isVertical;
				const baseFontSize = isVertical ? 14 : 16;
				const font = `bold ${baseFontSize}px Verdana`;
				const titleX = isVertical ? 94 : 106;
				const titleY = isVertical ? 22 : 60;

				const startX = isVertical ? 96 : 110;
				const startY = isVertical ? 46 : 93.5;
				const lineHeight = 24;

				const clearX = isVertical ? 10 : 10;
				const clearY = isVertical ? 0 : 40;
				const clearW = 100;
				const clearH = 130;

				// 设置字体 & 对齐方式
				core.setFont('outerUI', font);
				core.setTextAlign('outerUI', 'right');
				ctx.textBaseline = 'alphabetic';

				if (!core.status.lastPropsDrawn) {
					core.status.lastPropsDrawn = {
						hp: null,
						atk: null,
						def: null,
						money: null,
						title: null
					};
				}

				if (!updatedFloorTitle && core.status.floorId) {
					updatedFloorTitle = core.status.maps[core.status.floorId].title;
				}

				// 更新楼层标题
				if (core.status.lastPropsDrawn.title !== updatedFloorTitle) {
					core.status.lastPropsDrawn.title = updatedFloorTitle;
					// 清理标题区域
					ctx.clearRect(clearX, clearY, clearW, lineHeight + 5);
					core.fillBoldText('outerUI', updatedFloorTitle, titleX, titleY, TEXT_COLOR, '#000000');
				}

				// 更新属性值
				statusList.forEach((item, i) => {
					let real = Math.round(core.status.hero[item]);
					let tempBonus = 0;

					if (item === 'atk') tempBonus = core.getFlag('临时攻击', 0);
					if (item === 'def') tempBonus = core.getFlag('临时防御', 0);

					const text = tempBonus > 0 ? `${real}+${tempBonus}` : `${real}`;
					const lastText = core.status.lastPropsDrawn[item];

					if (text !== lastText) {

						core.status.lastPropsDrawn[item] = text;

						const y = startY + i * lineHeight;

						// 清除对应行
						ctx.clearRect(clearX, y - 16, clearW, lineHeight + 4);

						//console.log(`[props] text=${text}, x=${startX}, y=${y}, baseline=${ctx.textBaseline}`);

						// 绘制
						core.fillBoldText('outerUI', text, startX, y, TEXT_COLOR, '#000000');
					}
				});
				core.setTextAlign('outerUI', 'center');
			}
		}
		_update_items() {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				const itemMx = core.domStyle.isVertical ? this.itemMxVertical : this.itemMx;
				const startX = core.domStyle.isVertical ? ITEM_BOX_LEFT_VERTICAL : ITEM_BOX_LEFT;
				const startY = core.domStyle.isVertical ? ITEM_BOX_TOP_VERTICAL : ITEM_BOX_TOP;

				if (!core.status.lastItemsDrawn) {
					core.status.lastItemsDrawn = {
						//[itemId]: { count: number, x: number, y: number }
					}
				}
				const last = core.status.lastItemsDrawn;
				const iconImage = core.material.images.items;

				const drawItem = (item, x, y) => {
					const posx = startX + x * 33,
						posy = startY + y * 32;
					const count = core.itemCount(item);
					const cache = last[item];

					if (count < 1) {
						// 如果不再拥有此道具，则清理并移除缓存
						if (cache) {
							ctx.clearRect(cache.x, cache.y, 32, 32);
							delete last[item];
						}
						if (item === 'book') core.clearMap('damage');
						return;
					}

					/*if (item === 'wand') {
						ctx.clearRect(posx, posy, 32, 32);
						core.drawImage('outerUI', iconImage, 0, 32 * core.material.icons.items[item], 32, 32, posx, posy, 32, 32);
						core.fillBoldText('outerUI', core.getFlag('间隔', 20) - core.getFlag('时间', 0), posx + 25, posy + 30, '#ffffff', '#000', 'bold 10px Verdana');
					} else*/
					if (!cache || cache.count !== count || cache.x !== posx || cache.y !== posy) {
						ctx.clearRect(posx, posy, 32, 32);
						core.drawImage('outerUI', iconImage, 0, 32 * core.material.icons.items[item], 32, 32, posx, posy, 32, 32);
						if ((core.items.items[item].cls === 'tools' && count > 1) || FORCE_COUNTABLE_ITEMS.includes(item))
							core.fillBoldText('outerUI', count, posx + 25, posy + 30, '#FFF', '#000', 'bold 10px Verdana');

						last[item] = { count, x: posx, y: posy };
					}
				};
				core.canvas.outerUI.imageSmoothingEnabled = false;
				for (let y = 0; y < itemMx.length; y++)
					for (let x = 0; x < itemMx[y].length; x++)
						drawItem(itemMx[y][x], x, y);
				core.canvas.outerUI.imageSmoothingEnabled = true;
			}
		}
		_update_equips() {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				const isVertical = core.domStyle.isVertical;
				const left = isVertical ? EQUIP_BLOCK_LEFT_VERTICAL : EQUIP_BLOCK_LEFT;
				const top = isVertical ? EQUIP_BLOCK_TOP_VERTICAL : EQUIP_BLOCK_TOP;

				const font = 'bold 16px Verdana';
				const iconImg = core.material.images.items;
				const iconMap = core.material.icons.items;

				const nowWeapon = core.getFlag('nowWeapon');
				const nowShield = core.getFlag('nowShield');

				if (!core.status.lastEquipsDrawn) {
					core.status.lastEquipsDrawn = { weapon: null, shield: null };
				}

				const cache = core.status.lastEquipsDrawn;

				core.setFont('outerUI', font);

				const drawEquip = (id, type, offsetY, color, emptyText) => {
					const key = type === 'weapon' ? 'weapon' : 'shield';
					if (cache[key] === id) return;

					const y = top + offsetY;
					const textX = left + 32;
					const iconX = left + 64;

					// 清除该装备栏区域
					ctx.clearRect(left, y, 105, 40);

					if (!id)
						core.fillBoldText('outerUI', emptyText, left + 50, y + 22, color, '#000');
					else {
						const icon = iconMap[id];
						const name = core.material.items[id].name;
						core.fillBoldText('outerUI', name, textX, y + 22, color, '#000');
						core.canvas.outerUI.imageSmoothingEnabled = false;
						core.drawImage('outerUI', iconImg, 0, 32 * icon, 32, 32, iconX, y, 32, 32);
						core.canvas.outerUI.imageSmoothingEnabled = true;
					}
					cache[key] = id;
				};
				drawEquip(nowWeapon, 'weapon', isVertical ? 9 : 8, '#FFCFAE', '无武器');
				drawEquip(nowShield, 'shield', isVertical ? 49 : 56, '#D1CEFF', '无防具');
			}
		}
		_update_keys() {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				const isVertical = core.domStyle.isVertical;
				const keyList = ['yellowKey', 'blueKey', 'redKey'];
				const counts = keyList.map(key => core.itemCount(key));

				if (!core.status.lastKeysDrawn) {
					core.status.lastKeysDrawn = [null, null, null]; // 黄、蓝、红
				}

				const cache = core.status.lastKeysDrawn;

				// 若无变化，直接返回
				if (counts[0] === cache[0] && counts[1] === cache[1] && counts[2] === cache[2]) return;

				// 更新缓存
				core.status.lastKeysDrawn = [...counts];

				// 重新绘制
				const baseX = isVertical ? KEY_BLOCK_LEFT_VERTICAL + 3 : KEY_BLOCK_LEFT + 3;
				const baseY = isVertical ? KEY_BLOCK_TOP_VERTICAL + 2 : 142;
				const lines = isVertical ? 2 : 3;
				const rows = 7;

				// 清除区域
				const clearX = isVertical ? KEY_BLOCK_LEFT_VERTICAL : KEY_BLOCK_LEFT;
				const clearY = isVertical ? KEY_BLOCK_TOP_VERTICAL : 140;
				ctx.clearRect(clearX, clearY, 105, 75);

				const drawKey = this.drawKey.bind(this);
				const total = counts.reduce((a, b) => a + b, 0);

				if (total > lines * rows) {
					// 压缩绘制模式
					for (let i = 0; i < 3; i++) {
						const x = isVertical ? i * 32 : 0;
						const y = isVertical ? parseInt((lines - 1) / 2 * 14) : 48 - i * 22;
						drawKey(keyList[i], baseX + x, baseY + y);
						core.setFont('outerUI', isVertical ? 'bold 10px Verdana' : '14px Verdana');
						core.setTextAlign('outerUI', 'left');
						core.canvas.outerUI.textBaseline = 'middle';
						core.fillBoldText('outerUI', counts[i], baseX + x + (isVertical ? 10 : 16), baseY + y + (isVertical ? 20 : 9), TEXT_COLOR, '#000');
					}
				} else {
					// 多枚堆叠绘制
					let dn = 2,
						dc = 0;
					core.canvas.outerUI.imageSmoothingEnabled = false;
					while (dn >= 0 && dc < lines * rows) {
						if (counts[dn]) {
							const x = baseX + (dc % rows) * 14;
							const y = baseY + parseInt(dc / rows) * 17;
							drawKey(keyList[dn], x, y);
							counts[dn]--, dc++;
						} else dn--;
					}
					core.canvas.outerUI.imageSmoothingEnabled = true;
				}
			}

		}
		drawKey(key, x, y) {
			let sx = 3,
				sy = 0;
			if (key === 'blueKey') sx += 16;
			else if (key === 'yellowKey') sy += 16;
			core.drawImage('outerUI', core.statusBar.icons.keys, sx, sy, 10, 16, x, y, 10, 16);
		}

		_update_infoWindow() {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				const itemId = this.selectedItem;
				if (core.status.lastInfoWindowItem === itemId) return;
				core.status.lastInfoWindowItem = itemId;
				if (core.domStyle.isVertical) {
					ctx.clearRect(INFO_BLOCK_LEFT_VERTICAL, INFO_BLOCK_TOP_VERTICAL, 200, 200);
					if (itemId) {
						const icon = core.material.icons.items[itemId];
						const item = core.material.items[itemId];
						core.fillText('outerUI', item.name, INFO_BLOCK_LEFT_VERTICAL + 48, INFO_BLOCK_TOP_VERTICAL + 22, '#D1CEFF');
						core.drawImage('outerUI', core.material.images.items, 0, 32 * icon, 32, 32, INFO_BLOCK_LEFT_VERTICAL + 80, INFO_BLOCK_TOP_VERTICAL + 2, 32, 32);
						core.ui.drawTextContent('outerUI', eval('`' + item.text + '`'), {
							left: INFO_BLOCK_LEFT_VERTICAL + 3,
							top: INFO_BLOCK_TOP_VERTICAL + 36,
							maxWidth: 150,
							color: '#D1CEFF'
						});
					}
				} else {
					ctx.clearRect(INFO_BLOCK_LEFT, INFO_BLOCK_TOP, 105, 100);
					if (itemId) {
						const icon = core.material.icons.items[itemId];
						const item = core.material.items[itemId];
						core.fillText('outerUI', item.name, INFO_BLOCK_LEFT + 32, INFO_BLOCK_TOP + 25, '#D1CEFF');
						core.drawImage('outerUI', core.material.images.items, 0, 32 * icon, 32, 32, INFO_BLOCK_LEFT + 64, INFO_BLOCK_TOP + 4, 32, 32);
						core.ui.drawTextContent('outerUI', eval('`' + item.text + '`'), {
							left: INFO_BLOCK_LEFT + 1,
							top: INFO_BLOCK_TOP + 36,
							maxWidth: 105,
							color: '#D1CEFF'
						});
					}
				}
			}
		};
		showItemInfo(itemId) {
			this.selectedItem = itemId;
			this._update_infoWindow();
		}
		clearItemInfo() {
			this.selectedItem = null;
			this._update_infoWindow();
		}
		_update_toolBox() {
			const ctx = core.getContextByName('outerUI');

			if (ctx) {
				const tools = core.isReplaying() ? [
					[core.status.replay.pausing ? 'play' : 'pause', 'stop', 'rewind'],
					['speedDown', 'speedUp', 'save']
				] : [
					['keyboard', 'shop', 'help'],
					['save', 'load', 'settings']
				];
				core.canvas.outerUI.imageSmoothingEnabled = false;
				if (core.domStyle.isVertical) {
					ctx.clearRect(TOOL_BOX_LEFT_VERTICAL, TOOL_BOX_TOP_VERTICAL, 115, 80);
					for (let i = 0; i < tools.length; i++) {
						for (let j = 0; j < tools[i].length; j++) {
							core.drawIcon('outerUI', tools[i][j], TOOL_BOX_LEFT_VERTICAL + j * 34, TOOL_BOX_TOP_VERTICAL + i * 34, 32, 32);
						}
					}
				} else {
					ctx.clearRect(TOOL_BOX_LEFT, TOOL_BOX_TOP, 115, 80);
					for (let i = 0; i < tools.length; i++) {
						for (let j = 0; j < tools[i].length; j++) {
							core.drawIcon('outerUI', tools[i][j], TOOL_BOX_LEFT + j * 34, TOOL_BOX_TOP + i * 34, 32, 32);
						}
					}
				}
				core.canvas.outerUI.imageSmoothingEnabled = true;
			}
		}
		onclick(x, y) {
			const pos = [x, y];
			const isVertical = core.domStyle.isVertical;

			const makeBox = ([x, y], [w, h]) => [
				[x, y],
				[x + w, y + h]
			];
			const gridify = ([x, y], [gw, gh]) => [Math.floor(x / gw), Math.floor(y / gh)];
			const inRect = ([x, y], [
				[sx, sy],
				[dx, dy]
			]) => sx <= x && x <= dx && sy <= y && y <= dy;
			const relativeTo = ([x, y], [ax, ay]) => [x - ax, y - ay];
			const sizeOfMX = (mx, gw = 32, gh = 33) => [gw * mx[0].length, gh * mx.length];

			const useItem = itemId => {
				if (!core.hasItem(itemId)) return;
				const cls = core.material.items[itemId].cls;
				if (cls === "constants") {
					switch (itemId) {
					case "book":
						core.openBook(true);
						break;
					case "fly":
						core.useFly(true);
						break;
					case "wand":
					case "snow":
					case "skill1":
						core.useItem(itemId);
						break;
					default:
						this.showItemInfo(itemId);
					}
				} else if (itemId !== this.selectedItem) {
					this.showItemInfo(itemId);
				} else {
					if (itemId === "centerFly") core.ui._drawCenterFly();
					else core.useItem(itemId);
				}
			};

			const handleItemClick = (itemMx, left, top, gw, gh) => {
				const itemBox = makeBox([left, top], sizeOfMX(itemMx, gw, gh));
				if (!inRect(pos, itemBox)) return false;

				const [gx, gy] = gridify(relativeTo(pos, itemBox[0]), [gw, gh]);
				if (!itemMx[gy] || !itemMx[gy][gx]) return false;

				const itemId = itemMx[gy][gx];
				if (itemId === "book") useItem(itemId);
				if (core.isReplaying() || core.status.lockControl || core.isMoving()) return true;

				useItem(itemId);
				this._update_items();
				return true;
			};

			const handleToolClick = (left, top) => {
				const toolBox = makeBox([left, top], [102, 68]);
				if (!inRect(pos, toolBox)) return false;

				const [gx, gy] = gridify(relativeTo(pos, toolBox[0]), [34, 34]); // gx = col, gy = row

				if (core.isReplaying()) {
					const action = this.replayAction && this.replayAction[gy] && this.replayAction[gy][gx];
					if (typeof action === 'function') action.call(core);
				} else if (core.isPlaying()) {
					const action = this.toolbarAction && this.toolbarAction[gy] && this.toolbarAction[gy][gx];
					if (typeof action === 'function') action.call(core, true);
				}
				return true;
			};

			if (isVertical) {
				if (handleItemClick(this.itemMxVertical, ITEM_BOX_LEFT_VERTICAL, ITEM_BOX_TOP_VERTICAL, 32, 33)) return;
				if (handleToolClick(TOOL_BOX_LEFT_VERTICAL, TOOL_BOX_TOP_VERTICAL)) return;
			} else {
				if (handleItemClick(this.itemMx, ITEM_BOX_LEFT, ITEM_BOX_TOP, 33, 32)) return;
				if (handleToolClick(TOOL_BOX_LEFT, TOOL_BOX_TOP)) return;
			}
		}

		_update_infoBar() {
			const ctx = core.getContextByName('outerUI');
			if (ctx) {
				core.setTextAlign('outerUI', 'left');
				const text = this.infoText;

				if (core.domStyle.isVertical) {
					ctx.clearRect(0, INFO_BAR_TOP_VERTICAL, GAMEVIEW_WIDTH, INFO_BAR_HEIGHT_VERTICAL);
					core.setFont('outerUI', 'bold 14px Verdana');
					if (text) core.fillText('outerUI', text, 10, INFO_BAR_TOP_VERTICAL + 14, TEXT_COLOR);
				} else {
					ctx.clearRect(0, INFO_BAR_TOP, GAMEVIEW_WIDTH, INFO_BAR_HEIGHT);
					core.setFont('outerUI', 'bold 16px Verdana');
					if (text) core.fillText('outerUI', text, 10, INFO_BAR_TOP + 16, TEXT_COLOR);
				}

				core.setTextAlign('outerUI', 'center');
			}
		}
		print(text, cnt = 1) {
			this.infoText = text;
			this.infocnt = cnt == null ? 1 : cnt;
			this._update_infoBar();
		}

		printEnvironmentInfo() {
			if (!this.infocnt) return;
			const ids = [];
			for (const block of core.status.thisMap.blocks) {
				if (!block.disable && core.nearHero(block.x, block.y))
					ids.push(block.event.id);
			}
			for (const infoRule of StatusBar.infoRules) {
				if (ids.indexOf(infoRule.id) >= 0) {
					this.print(infoRule.text);
					return;
				}
			}
		}
		clearInfo(etype) {
			this.clearItemInfo && this.clearItemInfo();
			if (this.infocnt === 1) {
				setTimeout(() => {
					if (this.infocnt === 0) {
						this.infoText = void 0;
						this._update_infoBar();
					}
				}, 200);
				this.infocnt = 0;
			} else if (this.infocnt > 1) {
				this.infocnt--;
			}
		}
	}
	StatusBar.infoRules = [
		{ id: 'lava', text: '岩浆好热啊!' },
		{ id: 'upFloor', text: '你看到了楼梯' },
		{ id: 'downFloor', text: '你看到了楼梯' },
		{ id: 'blueShop', text: '你看到了一个祭坛' },
		{ id: 'man', text: '你看到了一个老人' },
		{ id: 'woman', text: '你看到了一个商人' },
		{ id: 'fairy', text: '你看到了一个商人' },
		{ id: 'thief', text: '你看到了一个小偷' }
	];
	core.ui.statusBar = new StatusBar();

	core.control.clearStatusBar = function () {
		core.clearMap('outerUI');
	};
	// init() called in `afterLoadResources`.
},
    "override": function () {

	core.statusBar.icons = {
		'floor': 0,
		'name': null,
		'lv': 1,
		'hpmax': 2,
		'hp': 3,
		'atk': 4,
		'def': 5,
		'mdef': 6,
		'money': 7,
		'experience': 8,
		'up': 9,
		'book': 10,
		'fly': 11,
		'toolbox': 12,
		'keyboard': 13,
		'shop': 14,
		'save': 15,
		'load': 16,
		'settings': 17,
		'play': 18,
		'pause': 19,
		'stop': 20,
		'speedDown': 21,
		'speedUp': 22,
		'rewind': 23,
		'equipbox': 24,
		'mana': 25,
		'skill': 26,
		'paint': 27,
		'erase': 28,
		'empty': 29,
		'exit': 30,
		'btn1': 31,
		'btn2': 32,
		'btn3': 33,
		'btn4': 34,
		'btn5': 35,
		'btn6': 36,
		'btn7': 37,
		'btn8': 38,
		'keys': 39,
		'help': 40,
		'battle': 41
	};

	core.actions._clickCenterFly = function (x, y) {
		var posX = core.status.event.data.posX,
			posY = core.status.event.data.posY;
		core.ui.closePanel();
		if (x == posX && y == posY) {
			if (core.canUseItem('centerFly')) {
				core.useItem('centerFly');
			} else {
				core.drawTip('当前不能使用中心对称飞行器');
			}
		} else core.drawTip('取消使用');
	}

	var _clickSL = core.actions._clickSL;
	core.actions._clickSL = function (x, y) {
		var page = core.status.event.data.page,
			offset = core.status.event.data.offset;
		var index = page * 10 + offset;

		// 上一页
		if ((x == this.HSIZE - 1 || x == this.HSIZE - 2) && y == this.LAST) {
			core.ui._drawSLPanel(10 * (page - 1) + offset);
			return;
		}
		// 下一页
		if ((x == this.HSIZE + 1 || x == this.HSIZE + 2) && y == this.LAST) {
			core.ui._drawSLPanel(10 * (page + 1) + offset);
			return;
		}
		if ((x == this.HSIZE - 3 || x == this.HSIZE + 3) && y == this.LAST) {
			return;
		}
		_clickSL.call(this, x, y);
	}

	var _sys_longClick_lockControl = core.actions._sys_longClick_lockControl;
	core.actions._sys_longClick_lockControl = function (x, y) {
		if (!core.status.lockControl) return false;

		// 长按SL上下页快速翻页
		if (["save", "load", "replayLoad", "replayRemain"].indexOf(core.status.event.id) >= 0) {
			if (y == this.LAST && x <= this.HSIZE + 3 && x >= this.HSIZE - 3) {
				core.actions._clickSL(x, y);
				return true;
			}
		}
		return _sys_longClick_lockControl.call(this, x, y);
	}
	core.registerAction('longClick', '_sys_longClick_lockControl', core.actions._sys_longClick_lockControl, 50);

	core.control._moveHero_moving = function () {
		core.status.heroStop = false;
		core.status.automaticRoute.moveDirectly = false;
		var move = function () {
			if (!core.status.heroStop) {
				if (core.hasFlag('debug') && core.status.ctrlDown) {
					if (core.status.heroMoving != 0) return;
					// 检测是否穿出去
					var nx = core.nextX(),
						ny = core.nextY();
					if (nx < 1 || nx >= core.bigmap.width - 1 || ny < 1 || ny >= core.bigmap.height - 1) return;
					core.eventMoveHero([core.getHeroLoc('direction')], core.values.moveSpeed, move);
				} else {
					core.moveAction();
					setTimeout(move, 50);
				}
			}
		}
		move();
	}

	core.control._drawHero_updateViewport = function (x, y, offset) {}

	var _drawThumbnail_drawTempCanvas = core.maps._drawThumbnail_drawTempCanvas;
	core.maps._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) {
		if (main.mode == 'editor') {
			_drawThumbnail_drawTempCanvas.call(this, floorId, blocks, options);
			return;
		}

		var width = core.floors[floorId].width;
		var height = core.floors[floorId].height;
		// 绘制到tempCanvas上面
		var tempCanvas = core.bigmap.tempCanvas;
		options.v2 = false;
		tempCanvas.canvas.width = width * 32;
		tempCanvas.canvas.height = height * 32;
		options.ctx = tempCanvas;

		var hasHero = core.status.hero != null,
			flags = null;
		if (options.flags) {
			if (!hasHero) core.status.hero = {};
			flags = core.status.hero.flags;
			core.status.hero.flags = options.flags;
		}
		this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options);

		if (!hasHero) delete core.status.hero;
		else if (flags != null) core.status.hero.flags = flags;
		tempCanvas.setTransform(1, 0, 0, 1, 0, 0);
	}

	var _drawThumbnail_drawToTarget = core.maps._drawThumbnail_drawToTarget;
	core.maps._drawThumbnail_drawToTarget = function (floorId, options) {
		if (main.mode == 'editor') {
			_drawThumbnail_drawToTarget.call(this, floorId, options);
			return;
		}

		var ctx = core.getContextByName(options.ctx);
		if (ctx == null) return;
		var x = options.x || 0,
			y = options.y || 0,
			size = options.size || core.__PIXELS__;
		var tempCanvas = core.bigmap.tempCanvas;
		core.drawImage(ctx, tempCanvas.canvas, 32, 32, core.__PIXELS__, core.__PIXELS__, x, y, size, size);
	}

	var _drawWindowSkin = core.ui.drawWindowSkin;
	core.ui.drawWindowSkin = function (background, ctx, x, y, w, h, direction, px, py) {
		_drawWindowSkin.call(this, background, ctx, x, y, w, h, direction, px, py);

		var c = parseInt(w / 2);
		core.drawImage(ctx, background, 160, 90, 16, 6, x + c - 8, y, 16, 6);
	}

	var _drawPagination = ui.prototype.drawPagination;
	core.ui.drawPagination = function (page, totalPage, y) {
		if (["save", "load", "replayLoad", "replayRemain", "replaySince"].indexOf(core.status.event.id) >= 0) {
			if (totalPage <= 1) return;
			if (y == null) y = this.LAST;

			core.setFillStyle('ui', '#DDDDDD');
			var length = core.calWidth('ui', page, this._buildFont(15, true));

			core.setTextAlign('ui', 'left');
			core.fillText('ui', page, parseInt((this.PIXEL - length) / 2), y * 32 + 19);

			core.setTextAlign('ui', 'center');
			if (page > 1)
				core.fillText('ui', '上一页', this.HPIXEL - 48, y * 32 + 19);
			if (page < totalPage)
				core.fillText('ui', '下一页', this.HPIXEL + 48, y * 32 + 19);
			return;
		}
		_drawPagination.call(this, page, totalPage, y);
	}

	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 - 1 - core.getHeroLoc('y');
		this.clearUI();
		core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000');
		core.drawThumbnail(null, null, { heroLoc: core.status.hero.loc, heroIcon: core.status.hero.image, ctx: 'ui', centerX: toX, centerY: toY });
		var offsetX = 1,
			offsetY = 1;
		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.ui.drawHelp = function () {
		core.clearUI();
		core.status.event.id = 'help';
		core.lockControl();
		core.setAlpha('ui', 1);
		core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#FFFFFF');
		core.drawImage('ui', core.material.images.keyboard, 0, 0, 416, 416, 0, 0, 352, 352);
	}

	core.actions._getClickLoc = function (x, y) {
		var size = 32 * core.domStyle.scale;
		var left = main.dom.gameDraw.offsetLeft + main.dom.gameGroup.offsetLeft;
		var top = main.dom.gameDraw.offsetTop + main.dom.gameGroup.offsetTop;
		var loc = { 'x': Math.max(x - left, 0), 'y': Math.max(y - top, 0), 'size': size };
		return loc;
	}

	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 (core.hasFlag('addhp')) {
				if (damage < core.status.hero.hp) color = '#11FF11';
				else color = '#FF2222';
			} else if (damage <= 0) color = '#11FF11';
			else if (damage < core.status.hero.hp / 3) color = '#FFFFFF';
			else if (damage < core.status.hero.hp * 2 / 3) color = '#FFFF00';
			else if (damage < core.status.hero.hp) 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_drawDamage = function (index, enemy, offset, position) {
		core.setTextAlign('ui', 'center');
		var damage = enemy.damage,
			color = '#FFFF00';
		if (damage == null) {
			damage = '不可攻击';
			color = '#FF2222';
		}
		if (damage == 0) {
			damage = '无危险';
			color = '#11FF11';
		} else {
			if (damage >= core.status.hero.hp) color = '#FF2222';
			else if (damage >= core.status.hero.hp * 2 / 3) color = '#FF9933';
			else if (damage <= 0) color = '#11FF11';
			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));
	}

	core.control.checkBlock = function () {
		var x = core.getHeroLoc('x'),
			y = core.getHeroLoc('y'),
			loc = x + "," + y;
		var damage = core.status.checkBlock.damage[loc];
		if (damage) {
			core.status.hero.hp -= damage;
			core.drawTip("你没有神圣盾不能防御，受到 " + damage + " 点魔法伤害");
			core.playSound('阻激夹域');
			this._checkBlock_disableQuickShop();
			core.status.hero.statistics.extraDamage += damage;
			if (core.status.hero.hp <= 0) {
				core.status.hero.hp = 0;
				core.updateStatusBar();
				core.events.lose();
				return;
			} else {
				core.updateStatusBar();
			}
		}
		this._checkBlock_ambush(core.status.checkBlock.ambush[loc]);
		this._checkBlock_repulse(core.status.checkBlock.repulse[loc]);
	}

	core.registerSystemEvent("man", function (data, callback) {
		var a = parseInt(core.status.floorId.substring(2));
		var b = data.x;
		var c = data.y;
		core.insertAction([
			{ "type": "insert", "name": "对话", "args": [a, b, c, 0] },
		]);
		//console.log(data);
		if (callback) callback();
	});

	core.registerSystemEvent("woman", function (data, callback) {
		var name = core.status.floorId + '@' + data.x + '@' + data.y + '@' + 'A';
		var a = parseInt(core.status.floorId.substring(2));
		var b = data.x;
		var c = data.y;
		if (core.getFlag(name, 0) == 1) {
			core.insertAction([
				{ "type": "insert", "name": "对话", "args": [a, b, c, 1] },
			]);
		} else {
			core.insertAction([
				{ "type": "insert", "name": "商人", "args": [b, c] },
			]);
		}
		//console.log(data);
		if (callback) callback();
	});

	core.registerSystemEvent("specialwall", function (data, callback) {
		if (data.event.id == 'whiteWall' || core.getFlag('talking') > 0) {
			core.insertAction({ 'type': 'openDoor', loc: [data.x, data.y] });
			if (data.event.id != 'whiteWall') {
				core.setFlag('end', 1);
			}
			core.setFlag('talking', 0); //穿墙之后不能再次穿墙
		}
		//console.log(data);
		if (callback) callback();
	});

	core.registerSystemEvent("fakeWall", function (data, callback) {
		if (data.event.id == 'blueWall') {
			core.insertAction([
				{ "type": "openDoor", loc: [data.x, data.y] },
			]);
		}
		//console.log(data);
		if (callback) callback();
	});

	core.ui._drawWindowSelector = function (background, x, y, w, h) {
		w = Math.round(w) + 48;
		h = Math.round(h);
		var ctx = core.ui.createCanvas("_selector", x - 24, y, w, h, 165);
		ctx.canvas.id = '';
		this._drawSelector(ctx, background, w, h);
	}

	core.ui._drawSelector = function (ctx, background, w, h, left, top) {
		left = left || 0;
		top = top || 0;
		ctx = this.getContextByName(ctx);
		if (!ctx) return;
		if (typeof background == 'string')
			background = core.material.images.images[background];
		if (!(background instanceof Image)) return;
		// badge
		ctx.drawImage(background, 132, 68, 24, 24, left + 4, top + 4, 24, 24);
		ctx.drawImage(background, 132, 68, 24, 24, w - left - 28, top + 4, 24, 24);
	}

	core.ui.drawTip = function (text, id, clear) {
		core.ui.statusBar.print(text);
	}

	core.ui.clearMap = function (name, x, y, width, height) {
		if (name == 'all') {
			for (var m in core.canvas) {
				core.canvas[m].clearRect(0, 0, core.bigmap.width * 32, core.bigmap.height * 32);
			}
			core.clearMap("outerUI");
			core.dom.gif.innerHTML = "";
			core.removeGlobalAnimate();
			core.deleteCanvas(function (one) { return one.startsWith('_bigImage_'); });
		} else {
			var ctx = this.getContextByName(name);
			if (ctx) ctx.clearRect(x || 0, y || 0, width || ctx.canvas.width, height || ctx.canvas.height);
		}
	}

	core.control._updateStatusBar_setToolboxIcon = function () {
		core.ui.statusBar._update_toolBox();
	}

	var _changeFloor_getInfo = core.events._changeFloor_getInfo;
	core.events._changeFloor_getInfo = function (floorId, stair, heroLoc, time) {
		var info = _changeFloor_getInfo.call(this, floorId, stair, heroLoc, time);
		if (info == null) return null;
		info.time = 0;
		info.origin = floorId;
		return info;
	}

	core.events._changeFloor_afterChange = function (info, callback) {
		if (!info.locked) core.unlockControl();
		core.status.replay.animate = false;
		core.events.afterChangeFloor(info.floorId);

		if (info.origin == ':before') core.ui.statusBar.print('走下了楼梯')
		else if (info.origin == ':next') core.ui.statusBar.print('登上了楼梯')
		if (callback) callback();
	}

	if (window.jsinterface && window.jsinterface.requestLandscape) {
		window.jsinterface.requestLandscape();
	}
},
    "shop": function () {
	// 【全局商店】相关的功能
	// 
	// 打开一个全局商店
	// shopId：要打开的商店id；noRoute：是否不计入录像
	this.openShop = function (shopId, noRoute) {
		var shop = core.status.shops[shopId];
		// Step 1: 检查能否打开此商店
		if (!this.canOpenShop(shopId)) {
			core.drawTip("该商店尚未开启");
			return false;
		}

		// Step 2: （如有必要）记录打开商店的脚本事件
		if (!noRoute) {
			core.status.route.push("shop:" + shopId);
		}

		// Step 3: 检查道具商店 or 公共事件
		if (shop.item) {
			if (core.openItemShop) {
				core.openItemShop(shopId);
			} else {
				core.playSound('操作失败');
				core.insertAction("道具商店插件不存在！请检查是否存在该插件！");
			}
			return;
		}
		if (shop.commonEvent) {
			core.insertCommonEvent(shop.commonEvent, shop.args);
			return;
		}

		_shouldProcessKeyUp = true;

		// Step 4: 执行标准公共商店    
		core.insertAction(this._convertShop(shop));
		return true;
	}

	////// 将一个全局商店转变成可预览的公共事件 //////
	this._convertShop = function (shop) {
		return [
			{ "type": "function", "function": "function() {core.addFlag('@temp@shop', 1);}" },
			{
				"type": "while",
				"condition": "true",
				"data": [
					// 检测能否访问该商店
					{
						"type": "if",
						"condition": "core.isShopVisited('" + shop.id + "')",
						"true": [
							// 可以访问，直接插入执行效果
							{ "type": "function", "function": "function() { core.plugin._convertShop_replaceChoices('" + shop.id + "', false) }" },
						],
						"false": [
							// 不能访问的情况下：检测能否预览
							{
								"type": "if",
								"condition": shop.disablePreview,
								"true": [
									// 不可预览，提示并退出
									{ "type": "playSound", "name": "操作失败" },
									"当前无法访问该商店！",
									{ "type": "break" },
								],
								"false": [
									// 可以预览：将商店全部内容进行替换
									{ "type": "tip", "text": "当前处于预览模式，不可购买" },
									{ "type": "function", "function": "function() { core.plugin._convertShop_replaceChoices('" + shop.id + "', true) }" },
								]
							}
						]
					}
				]
			},
			{ "type": "function", "function": "function() {core.addFlag('@temp@shop', -1);}" }
		];
	}

	this._convertShop_replaceChoices = function (shopId, previewMode) {
		var shop = core.status.shops[shopId];
		var choices = (shop.choices || []).filter(function (choice) {
			if (choice.condition == null || choice.condition == '') return true;
			try { return core.calValue(choice.condition); } catch (e) { return true; }
		}).map(function (choice) {
			var ableToBuy = core.calValue(choice.need);
			return {
				"text": choice.text,
				"icon": choice.icon,
				"color": ableToBuy && !previewMode ? choice.color : [153, 153, 153, 1],
				"action": ableToBuy && !previewMode ? [{ "type": "playSound", "name": "商店" }].concat(choice.action) : [
					{ "type": "playSound", "name": "操作失败" },
					{ "type": "tip", "text": previewMode ? "预览模式下不可购买" : "购买条件不足" }
				]
			};
		}).concat({ "text": "离开", "action": [{ "type": "playSound", "name": "取消" }, { "type": "break" }] });
		core.insertAction({ "type": "choices", "text": shop.text, "choices": choices });
	}

	/// 是否访问过某个快捷商店
	this.isShopVisited = function (id) {
		if (!core.hasFlag("__shops__")) core.setFlag("__shops__", {});
		var shops = core.getFlag("__shops__");
		if (!shops[id]) shops[id] = {};
		return shops[id].visited;
	}

	/// 当前应当显示的快捷商店列表
	this.listShopIds = function () {
		return Object.keys(core.status.shops).filter(function (id) {
			return core.isShopVisited(id) || !core.status.shops[id].mustEnable;
		});
	}

	/// 是否能够打开某个商店
	this.canOpenShop = function (id) {
		if (this.isShopVisited(id)) return true;
		var shop = core.status.shops[id];
		if (shop.item || shop.commonEvent || shop.mustEnable) return false;
		return true;
	}

	/// 启用或禁用某个快捷商店
	this.setShopVisited = function (id, visited) {
		if (!core.hasFlag("__shops__")) core.setFlag("__shops__", {});
		var shops = core.getFlag("__shops__");
		if (!shops[id]) shops[id] = {};
		if (visited) shops[id].visited = true;
		else delete shops[id].visited;
	}

	/// 能否使用快捷商店
	this.canUseQuickShop = function (id) {
		// 如果返回一个字符串，表示不能，字符串为不能使用的提示
		// 返回null代表可以使用

		// 检查当前楼层的canUseQuickShop选项是否为false
		if (core.status.thisMap.canUseQuickShop === false)
			return '当前楼层不能使用快捷商店。';
		return null;
	}

	var _shouldProcessKeyUp = true;

	/// 允许商店X键退出
	core.registerAction('keyUp', 'shops', function (keycode) {
		if (!core.status.lockControl || core.status.event.id != 'action') return false;
		if ((keycode == 13 || keycode == 32) && !_shouldProcessKeyUp) {
			_shouldProcessKeyUp = true;
			return true;
		}

		if (!core.hasFlag("@temp@shop") || core.status.event.data.type != 'choices') return false;
		var data = core.status.event.data.current;
		var choices = data.choices;
		var topIndex = core.actions._getChoicesTopIndex(choices.length);
		if (keycode == 88 || keycode == 27) { // X, ESC
			core.actions._clickAction(core.actions.HSIZE, 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;
		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.actions.HSIZE, 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 (x >= core.actions.CHOICES_LEFT && x <= core.actions.CHOICES_RIGHT && y >= topIndex && y < topIndex + choices.length) {
			core.actions._clickAction(x, y);
			return true;
		}
		return false;
	}, 60);
},
    "宝石血瓶显示": function () {
	/* 宝石血瓶左下角显示数值
	 * 需要将 变量：itemDetail改为true才可正常运行
	 * 请尽量减少勇士的属性数量，否则可能会出现严重卡顿（划掉，现在你放一万个属性也不会卡）
	 * 注意：这里的属性必须是core.status.hero里面的，flag无法显示
	 * 如果不想显示，可以core.setFlag("itemDetail", false);
	 * 然后再core.getItemDetail();
	 * 如有bug在大群或造塔群@古祠
	 */

	const ignore = ['superPotion'];

	// 取消注释下面这句可以减少超大地图的判定。
	// 如果地图宝石过多，可能会略有卡顿，可以尝试取消注释下面这句话来解决。
	// core.bigmap.threshold = 256;
	const origin = core.control.updateStatusBar;
	core.updateStatusBar = core.control.updateStatusBar = function () {
		if (core.getFlag('__statistics__')) return;
		else return origin.apply(core.control, arguments);
	}

	core.control.updateDamage = function (floorId, ctx) {
		floorId = floorId || core.status.floorId;
		if (!floorId || core.status.gameOver || main.mode != 'play') return;
		const onMap = ctx == null;

		// 没有怪物手册
		if (!core.hasItem('book')) return;
		core.status.damage.posX = core.bigmap.posX;
		core.status.damage.posY = core.bigmap.posY;
		if (!onMap) {
			const 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); // 宝石血瓶详细信息
		//core.drawDoorDetail(floorId); // 门详细信息
		this.drawDamage(ctx);
	};
	// 获取宝石信息 并绘制
	this.getItemDetail = function (floorId) {
		//if (!core.getFlag('itemDetail')) return;
		floorId = floorId === void 0 || floorId === null ? core.status.thisMap.floorId : floorId;
		if (!core.status.thisMap)
			return;
		const beforeRatio = core.status.thisMap.ratio;
		core.status.thisMap.ratio = core.status.maps[floorId].ratio;
		let diff = {};
		const before = core.status.hero;
		const hero = core.clone(core.status.hero);
		const handler = {
			set: function (target, key, v) {
				diff[key] = v - (target[key] || 0);
				if (!diff[key]) diff[key] = void 0;
				return true;
			}
		};
		core.status.hero = new Proxy(hero, handler);
		core.status.maps[floorId].blocks.forEach(function (block) {
			if (block.disable) return;
			const x = block.x,
				y = block.y;
			// v2优化，只绘制范围内的部分
			if (core.bigmap.v2) {
				if (
					x < core.bigmap.posX - core.bigmap.extend ||
					x > core.bigmap.posX + core._WIDTH_ + core.bigmap.extend ||
					y < core.bigmap.posY - core.bigmap.extend ||
					y > core.bigmap.posY + core._HEIGHT_ + core.bigmap.extend
				) {
					return;
				}
			}
			diff = {};
			const id = block.event.id;
			const item = core.material.items[id];
			if (block.event.cls === 'items') {
				if (item.cls === 'equips') {
					// 装备也显示
					const diff = item.equip.value === void 0 || item.equip.value === null ? {} : item.equip.value;

					const per = item.equip.percentage === void 0 || item.equip.percentage === null ? {} : item.equip.percentage;
					for (const name in per) {
						diff[name + 'per'] = per[name].toString() + '%';
					}
					drawItemDetail(diff, x, y);
					return;
				}
				// 跟数据统计原理一样 执行效果 前后比较
				core.setFlag('__statistics__', true);
				try {
					eval(item.itemEffect);
				} catch (error) {}
				drawItemDetail(diff, x, y);
			} else {
				if (block.event.cls === 'enemys' && !core.getFlag(floorId + '@' + x + '@' + y + '替命', false)) {
					core.status.damage.data.push({
						text: '替',
						px: 32 * x + 20,
						py: 32 * y + 12,
						color: '#FF0000'
					});
				}
			}

		});
		core.status.thisMap.ratio = beforeRatio;
		core.status.hero = before;
		window.hero = before;
		window.flags = before.flags;
	};


	this.drawDoorDetail = function (floorId) {
		//if (!core.getFlag('doorDetail')) return;
		floorId = floorId === void 0 || floorId === null ? core.status.thisMap.floorId : floorId;
		let diff = {};
		const before = core.status.hero;
		const hero = core.clone(core.status.hero);
		const handler = {
			set: function (target, key, v) {
				diff[key] = v - (target[key] || 0);
				if (!diff[key]) diff[key] = void 0;
				return true;
			}
		};
		core.status.hero = new Proxy(hero, handler);
		core.status.maps[floorId].blocks.forEach(function (block) {
			if ((block.id < 81) || (block.id > 83))
				return;
			const 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;
				}
			}
			core.setFlag('__statistics__', true);
			core.status.damage.data.push({
				text: block.id,
				px: 32 * x + 2,
				py: 32 * y + 30,
				color: '#FFFFFF'
			});
		});
		core.status.hero = before;
		window.hero = before;
		window.flags = before.flags;
	};

	// 绘制
	function drawItemDetail(diff, x, y) {
		const px = 32 * x + 2,
			py = 32 * y + 30;
		let content = '';
		// 获得数据和颜色
		let i = 0;
		for (const name in diff) {
			if (!diff[name]) continue;
			let color = '#fff';

			if (typeof diff[name] === 'number')
				content = core.formatBigNumber(diff[name], true);
			else content = diff[name];
			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 = '#c66';
				break;
			}
			// 绘制
			core.status.damage.data.push({
				text: content,
				px: px,
				py: py - 10 * i,
				color: color
			});
			i++;
		}
	}


},
    "HD": function () {
	this.getHDRatio = function (config) {
		let maxRatio = core.getFlag('maxHDRatio', 2);
		const isMobile = /Android|iPhone|iPad|iPod|Mobile|Windows Phone/i.test(navigator.userAgent);
		const ratio = core.domStyle.ratio * devicePixelRatio;

		let isHD = true; // 默认当作是HD的

		if (config) {
			if (config instanceof HTMLElement && config.hasAttribute('isHD')) {
				isHD = true;
			} else if (config instanceof HTMLElement) {
				isHD = false;
			} else if (config.isHD !== undefined) {
				isHD = config.isHD;
			}
		}

		if (!isHD) return 1;

		return isMobile ? Math.min(ratio, maxRatio) : ratio;
	};
	// 在此增加新插件
	ui.prototype._drawTextContent_draw = function (ctx, tempCtx, content, config) {
		// Step 1: 绘制到tempCtx上，并记录下图块信息
		while (this._drawTextContent_next(tempCtx, content, config));

		if (ctx == null) return config;

		// Step 2: 从tempCtx绘制到画布上
		config.index = 0;
		var _drawNext = function () {
			if (config.index >= config.blocks.length) return false;
			var block = config.blocks[config.index++];
			if (block != null) {
				// perf -1: HD compatibility.
				//var ratio = config.isHD ? core.domStyle.ratio * devicePixelRatio : 1;
				var ratio = core.plugin.getHDRatio();
				core.drawImage(ctx, tempCtx.canvas, block.left * ratio, block.top * ratio, block.width * ratio, block.height * ratio,
					config.left + block.left + block.marginLeft, config.top + block.top + block.marginTop,
					block.width, block.height);
			}
			return true;
		}
		if (config.time == 0) {
			while (_drawNext());
		} else {
			core.status.event.interval = setInterval(function () {
				if (!_drawNext()) {
					clearInterval(core.status.event.interval);
					core.status.event.interval = null;
				}
			}, config.time);
		}

		return config;
	}
	ui.prototype.drawTextContent = function (ctx, content, config) {
		ctx = core.getContextByName(ctx);
		// 设置默认配置项
		var textAttribute = core.status.textAttribute || core.initStatus.textAttribute;
		var globalAttribute = core.status.globalAttribute || core.initStatus.globalAttribute;
		config = core.clone(config || {});
		config.left = config.left || 0;
		config.right = config.left + (config.maxWidth == null ? core.__PIXELS__ : config.maxWidth)
		config.top = config.top || 0;
		config.color = core.arrayToRGBA(config.color || textAttribute.text);
		if (config.bold == null) config.bold = textAttribute.bold;
		config.italic = false;
		config.align = config.align || textAttribute.align || "left";
		config.fontSize = config.fontSize || textAttribute.textfont;
		config.lineHeight = config.lineHeight || (config.fontSize * 1.3);
		config.defaultFont = config.font = config.font || globalAttribute.font;
		config.time = config.time || 0;
		config.letterSpacing = config.letterSpacing == null ? (textAttribute.letterSpacing || 0) : config.letterSpacing;

		config.index = 0;
		config.currcolor = config.color;
		config.currfont = config.fontSize;
		config.lineMargin = Math.max(Math.round(config.fontSize / 4), config.lineHeight - config.fontSize);
		config.topMargin = parseInt(config.lineMargin / 2);
		config.lineMaxHeight = config.lineMargin + config.fontSize;
		config.offsetX = 0;
		config.offsetY = 0;
		config.line = 0;
		config.blocks = [];
		config.isHD = ctx != null && ctx.canvas.hasAttribute('isHD');

		core.createCanvas('ui_text', 0, 0, 352, 352, 0);
		var tempCtx = core.getContextByName('ui_text');
		/*
		if (config.isHD) {
			
			//core.maps._setHDCanvasSize(tempCtx, ctx.canvas.width, ctx.canvas.height);
		} else {
			var tempCtx = document.createElement('canvas').getContext('2d');
			tempCtx.canvas.width = ctx == null ? 1 : ctx.canvas.width;
			tempCtx.canvas.height = ctx == null ? 1 : ctx.canvas.height;
		}*/
		tempCtx.textBaseline = 'top';
		tempCtx.font = this._buildFont(config.fontSize, config.bold, config.italic, config.font);
		tempCtx.fillStyle = config.color;
		config = this._drawTextContent_draw(ctx, tempCtx, content, config);
		core.clearMap('ui_text');
		return config;
	}
	maps.prototype._setHDCanvasSize = function (ctx, width, height) {
		const ratio = core.plugin.getHDRatio();

		const targetW = width * ratio;
		const targetH = height * ratio;

		// 若尺寸未改变，则不需要重复设置
		if (ctx.canvas.width === targetW && ctx.canvas.height === targetH) {
			return;
		}

		ctx.setTransform(1, 0, 0, 1, 0, 0);
		if (targetW) ctx.canvas.width = targetW;
		if (targetH) ctx.canvas.height = targetH;
		ctx.scale(ratio, ratio);
		ctx.canvas.setAttribute("isHD", 1);
	}
	ui.prototype.drawImage = function (name, image, x, y, w, h, x1, y1, w1, h1, angle, reverse) {
		// 检测文件名以 :x, :y, :o 结尾，表示左右翻转，上下翻转和中心翻转
		var ctx = this.getContextByName(name);
		if (!ctx) return;

		ctx.mozImageSmoothingEnabled = false;
		ctx.webkitImageSmoothingEnabled = false;
		ctx.msImageSmoothingEnabled = false;
		ctx.imageSmoothingEnabled = false;

		// var reverse = null;
		if (typeof image == 'string') {
			if (image.endsWith(':x') || image.endsWith(':y') || image.endsWith(':o')) {
				reverse = image.charAt(image.length - 1);
				image = image.substring(0, image.length - 2);
			}
			image = core.getMappedName(image);
			image = core.material.images.images[image];
			if (!image) return;
		}

		var scale = {
			'x': [-1, 1],
			'y': [1, -1],
			'o': [-1, -1]
		};

		// 只能接受2, 4, 8个参数
		if (x != null && y != null) {
			if (w == null || h == null) {
				// 两个参数变成四个参数
				w = image.width;
				h = image.height;
			}
			if (x1 != null && y1 != null && w1 != null && h1 != null) {
				if (!reverse && !angle) {
					ctx.drawImage(image, x, y, w, h, x1, y1, w1, h1);
				} else {
					ctx.save();
					ctx.translate(x1 + w1 / 2, y1 + h1 / 2);
					if (reverse) ctx.scale(scale[reverse][0], scale[reverse][1]);
					if (angle) ctx.rotate(angle);
					ctx.drawImage(image, x, y, w, h, -w1 / 2, -h1 / 2, w1, h1);
					ctx.restore();
				}
				return;
			}
			if (!reverse && !angle) {
				ctx.drawImage(image, x, y, w, h);
			} else {
				ctx.save();
				ctx.translate(x + w / 2, y + h / 2);
				if (reverse) ctx.scale(scale[reverse][0], scale[reverse][1]);
				if (angle) ctx.rotate(angle);
				ctx.drawImage(image, -w / 2, -h / 2, w, h);
				ctx.restore();
			}
			return;
		}
	}
},
    "小游戏": function () {
	// 在此增加新插件
	control.prototype._replayAction_game = function (action) {
		if (!(action && action.startsWith('game:'))) return false;
		const match = action.match(/^game:(.+)$/);
		if (match) {
			const x = Number(match[1]);
			core.addStatus('money', x);
			core.setFlag('玩小游戏', true);
			core.replay();
			return true;
		}
		core.control._replay_error(action);
	}

	core.control.registerReplayAction("game", control.prototype._replayAction_game);
},
    "录像验证": function () {
	// 在此增加新插件
	control.prototype._replayAction_verify = function (action) {
		if (!(action && action.startsWith('R'))) return false;
		if (!core.getFlag('调试模式')) {
			core.replay();
			return true;
		}
		const parts = action.substring(1).split(/[,&]/); // 去掉 'R' 并拆分
		const p = parts.slice(0, -1).map(Number); // 提取数值部分
		const f = parts[parts.length - 1]; // 获取最后一个元素
		const x = core.getStatus('x'),
			y = core.getStatus('y'),
			hp = core.getStatus('hp'),
			atk = core.getStatus('atk'),
			def = core.getStatus('def'),
			money = core.getStatus('money'),
			floorId = core.status.floorId;
		if (p[0] !== hp || p[1] !== atk || p[2] !== def || p[3] !== money) {
			core.ui.closePanel();
			core.status.replay.replaying = false;
			core.status.replay.failed = true;
			var len = core.status.replay.toReplay.length;
			var prevList = core.status.replay.totalList.slice(-len - 11, -len - 1);
			var nextList = core.status.replay.toReplay.slice(0, 10);
			main.log(`录像文件出错，\n录像属性为：(${p[0]}, ${p[1]}, ${p[2]}, ${p[3]})，\n而当前属性为(${hp}, ${atk}, ${def}, ${money})`);
			main.log("之前的10个操作是：\n" + prevList.toString());
			main.log("接下来10个操作是：\n" + nextList.toString());
			core.ui.drawConfirmBox(`录像文件出错，\n录像属性为：(${p[0]}, ${p[1]}, ${p[2]}, ${p[3]})，\n而当前属性为(${hp}, ${atk}, ${def}, ${money})`, function () {
				core.status.replay.failed = false;
				core.ui.closePanel();
				if (core.status.replay.save.length > 0) {
					core.status.replay.replaying = true;
					core.status.replay.pausing = true;
					core.rewindReplay();
				} else {
					core.playSound('操作失败');
					core.stopReplay(true);
					core.drawTip("无法回到上一个节点");
					//if (callback) callback();
				}
			}, function () {
				core.status.replay.failed = false;
				core.ui.closePanel();
				core.stopReplay(true);
				//if (callback) callback();
			});
		}
		if (p[4] !== x || p[5] !== y || f !== floorId) {
			core.ui.closePanel();
			core.status.replay.replaying = false;
			core.status.replay.failed = true;
			var len = core.status.replay.toReplay.length;
			var prevList = core.status.replay.totalList.slice(-len - 11, -len - 1);
			var nextList = core.status.replay.toReplay.slice(0, 10);
			main.log(`录像文件出错，\n录像坐标为：(${p[4]}, ${p[5]}, ${f})，\n而当前坐标为(${x}, ${y}, ${floorId})`);
			main.log("之前的10个操作是：\n" + prevList.toString());
			main.log("接下来10个操作是：\n" + nextList.toString());
			core.ui.drawConfirmBox(`录像文件出错，\n录像坐标为：(${p[4]}, ${p[5]}, ${f})，\n而当前坐标为(${x}, ${y}, ${floorId})`, function () {
				core.status.replay.failed = false;
				core.ui.closePanel();
				if (core.status.replay.save.length > 0) {
					core.status.replay.replaying = true;
					core.status.replay.pausing = true;
					core.rewindReplay();
				} else {
					core.playSound('操作失败');
					core.stopReplay(true);
					core.drawTip("无法回到上一个节点");
					//if (callback) callback();
				}
			}, function () {
				core.status.replay.failed = false;
				core.ui.closePanel();
				core.stopReplay(true);
				//if (callback) callback();
			});
		}
		core.replay();
		return true;
	}


	core.control.registerReplayAction("verify", control.prototype._replayAction_verify);


	events.prototype.doAction = function () {
		if (core.getFlag('调试模式', false) && core.status.floorId) {
			while (true) {
				var p = core.status.route.pop();
				if (!p) break;
				if (!p.startsWith('R')) {
					core.status.route.push(p);
					break;
				}
			}
			//console.log(core.status.route);
			core.status.route.push('R' + core.status.hero.hp + ',' + core.status.hero.atk + ',' + core.status.hero.def + ',' + core.status.hero.money + '&' + core.getStatus('x') + ',' + core.getStatus('y') + ',' + core.status.floorId);
		}
		// 清空boxAnimate和UI层
		clearInterval(core.status.event.interval);
		clearTimeout(core.status.event.interval);
		clearInterval(core.status.event.animateUI);
		core.status.event.interval = null;
		delete core.status.event.aniamteUI;
		if (core.status.gameOver || core.status.replay.failed) return;
		// 判定是否执行完毕
		if (this._doAction_finishEvents()) return;
		core.clearUI();
		var floorId = core.status.event.data.floorId || core.status.floorId;
		// 当前点坐标和前缀
		var x = core.status.event.data.x,
			y = core.status.event.data.y;
		var prefix = [floorId || ":f", x != null ? x : "x", y != null ? y : "y"].join("@");
		var current = core.status.event.data.list[0];
		if (this._popEvents(current, prefix)) return;
		// 当前要执行的事件
		var data = current.todo.shift();
		core.status.event.data.current = data;
		if (typeof data == "string")
			data = { "type": "text", "text": data };
		// 该事件块已经被禁用
		if (data._disabled) return core.doAction();
		data.floorId = data.floorId || floorId;
		core.status.event.data.type = data.type;
		this.doEvent(data, x, y, prefix);
		return;
	}

	events.prototype._action_choices = function (data, x, y, prefix) {
		data.choices = data.choices.filter(function (x) {
			if (x._disabled) return false;
			if (x.condition == null || x.condition == '') return true;
			try { return core.calValue(x.condition, prefix); } catch (e) { return true; }
		})
		if (data.choices.length == 0) return this.doAction();
		if (core.isReplaying()) {
			var action = core.status.replay.toReplay.shift();
			if (action.startsWith('R')) {
				control.prototype._replayAction_verify(action);
				action = core.status.replay.toReplay.shift();
			}
			if (action.indexOf('choices:') == 0 && !(action == 'choices:none' && !data.timeout)) {
				var index = action.substring(8);
				if (!this.__action_choices_replaying(data, index)) {
					core.control._replay_error(action);
					return;
				}
			} else {
				// 容错录像

				if (main.replayChecking) {
					// 录像验证系统中选择第一项
					if (action != 'choices:none') core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
					core.events.__action_choices_replaying(data, 0)
				} else {
					// 正常游戏中弹窗选择
					core.myprompt('录像回放出错！当前需要执行选择项但录像中未记录。\n如需修复请输入您要选的项（从0起），点击取消将不会修复。', 0, function (value) {
						if (value == null) {
							core.control._replay_error(action);
							return;
						}
						if (action != 'choices:none') core.status.replay.toReplay.unshift(action); // 首先归还刚才读出的下一步操作
						core.events.__action_choices_replaying(data, ((parseInt(value) || 0) + data.choices.length) % data.choices.length);
					});
				}
			}
		} else {
			if (data.timeout) {
				core.status.event.interval = setTimeout(function () {
					core.status.route.push("choices:none");
					core.setFlag('timeout', 0);
					core.doAction();
				}, data.timeout);
			}
			core.status.event.timeout = new Date().getTime() + (data.timeout || 0);
		}
		for (var i = 0; i < data.choices.length; i++) {
			if (typeof data.choices[i] === 'string')
				data.choices[i] = { "text": data.choices[i] };
			data.choices[i].text = core.replaceText(data.choices[i].text, prefix);
		}
		core.ui.drawChoices(core.replaceText(data.text, prefix), data.choices, data.width);
	}

	utils.prototype.decodeRoute = function (route) {
		if (!route) return route;

		// 解压缩
		try {
			var v = LZString.decompressFromBase64(route);
			if (v != null) {
				if (v != "" || route.length < 8)
					route = v;
			}
		} catch (e) {}

		var decodeObj = { route: route, index: 0, ans: [] };
		while (decodeObj.index < decodeObj.route.length) {
			this._decodeRoute_decodeOne(decodeObj, decodeObj.route.charAt(decodeObj.index++));
		}
		return decodeObj.ans;
	}

	core.registerEvent("superAutoSave", function (data, x, y, prefix) {
		var forbidSave = core.hasFlag('__forbidSave__');
		core.removeFlag('__forbidSave__');
		let d = core.clone(core.status.event.data);
		core.unshift(d.list[0].todo, { "type": "superAutoSave" });
		core.setFlag("__events__", d);
		if (core.saves.autosave.data == null) {
			core.saves.autosave.data = [];
		}
		core.saves.autosave.data.splice(core.saves.autosave.now, 0, core.saveData());
		core.saves.autosave.now += 1;
		if (core.saves.autosave.data.length > core.saves.autosave.max) {
			if (core.saves.autosave.now < core.saves.autosave.max / 2)
				core.saves.autosave.data.pop();
			else {
				core.saves.autosave.data.shift();
				core.saves.autosave.now = core.saves.autosave.now - 1;
			}
		}
		core.saves.autosave.updated = true;
		core.saves.ids[0] = true;
		core.removeFlag("__events__");
		if (forbidSave) core.setFlag('__forbidSave__', true);
		if (!data.nohint) core.drawTip("已自动存档");
		core.doAction();
	})
},
    "图块彻底移除": function () {
	// 在此增加新插件
	maps.prototype.removeBlockByIndex = function (index, floorId) {
		floorId = floorId || core.status.floorId;
		if (!floorId) return;
		core.extractBlocks(floorId);
		var blocks = core.status.maps[floorId].blocks,
			block = blocks[index];
		blocks.splice(index, 1);
		if (core.status.mapBlockObjs[floorId])
			delete core.status.mapBlockObjs[floorId][block.x + "," + block.y];
		if (core.floors[floorId].events && core.floors[floorId].events[block.x + "," + block.y]) {
			core.setFlag('R' + floorId + "," + block.x + "," + block.y, true);
		}
		core.setMapBlockDisabled(floorId, block.x, block.y, true);
		this._updateMapArray(floorId, block.x, block.y);
	}
	maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) {
		var disable = null;
		var opacity = null;
		var filter = null;
		if (eventFloor != null) {
			disable = this.isMapBlockDisabled(eventFloor.floorId, x, y);
			opacity = this._getBlockOpacityFromFlag(eventFloor.floorId, x, y);
			filter = this._getBlockFilterFromFlag(eventFloor.floorId, x, y);
		}
		var block = { 'x': x, 'y': y, 'id': id };
		if (disable != null) block.disable = disable;
		if (opacity != null) block.opacity = opacity;
		if (filter != null) block.filter = filter;

		if (id == 17) block.event = { "cls": "terrains", "id": "airwall", "cannotIn": ["up", "down", "left", "right"] };
		else if (id in this.blocksInfo) block.event = JSON.parse(JSON.stringify(this.blocksInfo[id]));
		else if (core.icons.getTilesetOffset(id)) block.event = { "cls": "tileset", "id": "X" + id };
		else block.event = { 'cls': 'terrains', 'id': 'none', 'noPass': false };

		if (block.event.noPass == null) {
			if (block.event.canPass == null) {
				block.event.noPass = block.event.cls != 'items';
			} else {
				block.event.noPass = !block.event.canPass;
			}
		}
		delete block.event.canPass;

		// 增加怪物的faceIds
		if (block.event.cls.indexOf("enemy") == 0) {
			var enemy = core.material.enemys[block.event.id];
			if (enemy && enemy.faceIds) {
				block.event.faceIds = enemy.faceIds;
			}
		}

		if (addInfo) this._addInfo(block);
		if (eventFloor) {
			if (core.getFlag('R' + eventFloor.floorId + "," + block.x + "," + block.y, false) !== true) {
				this._addEvent(block, x, y, (eventFloor.events || {})[x + "," + y]);
				var changeFloor = (eventFloor.changeFloor || {})[x + "," + y];
				if (changeFloor) this._addEvent(block, x, y, { "trigger": "changeFloor", "data": changeFloor });
			}
		}
		if (main.mode == 'editor') delete block.disable;
		return block;
	}
},
    "便利功能": function () {
	//战斗函数修复，避免与不存在的敌人战斗导致卡死
	events.prototype.battle = function (id, x, y, force, callback) {
		core.saveAndStopAutomaticRoute();
		id = id || core.getBlockId(x, y);
		if (!id || !core.material.enemys[id]) return core.clearContinueAutomaticRoute(callback);
		// 非强制战斗
		if (!core.enemys.canBattle(id, x, y) && !force && !core.status.event.id) {
			core.stopSound();
			core.playSound('操作失败');
			core.drawTip("你打不过此怪物！", id);
			return core.clearContinueAutomaticRoute(callback);
		}
		// 自动存档
		if (!core.status.event.id) core.autosave(true);
		// 战前事件
		if (!this.beforeBattle(id, x, y))
			return core.clearContinueAutomaticRoute(callback);
		// 战后事件
		this.afterBattle(id, x, y);
		if (callback) callback();
	}
	//临界函数修复，现在会计入敌人的额外属性加成
	enemys.prototype._nextCriticals_overAtk = function (enemy, x, y, floorId) {
		var enemyInfo = core.enemys.getEnemyInfo(enemy, null, x, y, floorId);
		var calNext = function (currAtk, maxAtk) {
			var start = currAtk,
				end = maxAtk;
			if (start > end) return null;

			while (start < end) {
				var mid = Math.floor((start + end) / 2);
				if (mid - start > end - mid) mid--;
				var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": mid }, x, y, floorId);
				if (nextInfo != null) end = mid;
				else start = mid + 1;
			}
			var nextInfo = core.enemys.getDamageInfo(enemy, { "atk": start }, x, y, floorId);
			return nextInfo == null ? null : [start - core.status.hero.atk, nextInfo];
		}
		return calNext(core.status.hero.atk + 1,
			enemyInfo.hp + enemyInfo.def);
	}
	//自动寻路会智能避开楼梯
	maps.prototype._automaticRoute_bfs = function (startX, startY, destX, destY) {
		var route = {},
			canMoveArray = this.generateMovableArray();
		// 使用优先队列
		var queue = new PriorityQueue({ comparator: function (a, b) { return a.depth - b.depth; } });
		route[startX + "," + startY] = '';
		queue.queue({ depth: 0, x: startX, y: startY });
		var blocks = core.getMapBlocksObj();
		while (queue.length != 0) {
			var curr = queue.dequeue(),
				deep = curr.depth,
				nowX = curr.x,
				nowY = curr.y;
			for (var direction in core.utils.scan) {
				if (!core.inArray(canMoveArray[nowX][nowY], direction)) continue;
				var nx = nowX + core.utils.scan[direction].x;
				var ny = nowY + core.utils.scan[direction].y;
				if (nx < 0 || nx >= core.bigmap.width || ny < 0 || ny >= core.bigmap.height || route[nx + "," + ny] != null) continue;
				// 重点
				if (nx == destX && ny == destY) {
					route[nx + "," + ny] = direction;
					break;
				}
				// 不可通行
				if (core.noPass(nx, ny)) continue;
				let block = core.getBlock(nx, ny);
				if (block && block.event.trigger === 'changeFloor') {
					var ignore = core.flags.ignoreChangeFloor;
					if (block.event.data && block.event.data.ignoreChangeFloor != null)
						ignore = block.event.data.ignoreChangeFloor;
					if (!ignore) continue;
				}
				route[nx + "," + ny] = direction;
				queue.queue({ depth: deep + this._automaticRoute_deepAdd(nx, ny, blocks), x: nx, y: ny });
			}
			if (route[destX + "," + destY] != null) break;
		}
		return route;
	}
	//楼传操作页面按钮加大
	actions.prototype._sys_longClick_lockControl = function (x, y, px, py) {
		if (!core.status.lockControl) return false;
		if (core.status.event.id == 'text') {
			core.drawText();
			return true;
		}
		if (core.status.event.id == 'action' && core.status.event.data.type == 'text') {
			core.doAction();
			return true;
		}
		// 长按楼传器的箭头可以快速翻页
		if (core.status.event.id == 'fly') {
			if ((x >= this.SIZE - 4 && x <= this.SIZE - 1) && ((y >= this.HSIZE - 1 && y <= this.HSIZE) || (y >= this.HSIZE + 2 && y <= this.HSIZE + 3))) {
				this._clickFly(x, y);
				return true;
			}
		}
		// 长按SL上下页快速翻页
		if (["save", "load", "replayLoad", "replayRemain", "replaySince"].indexOf(core.status.event.id) >= 0) {
			if ([this.HSIZE - 2, this.HSIZE - 3, this.HSIZE + 2, this.HSIZE + 3].indexOf(x) >= 0 && y == this.LAST) {
				this._clickSL(x, y);
				return true;
			}
		}
		// 长按可以跳过等待事件
		if (core.status.event.id == 'action' && core.status.event.data.type == 'sleep' &&
			!core.status.event.data.current.noSkip) {
			if (core.timeout.sleepTimeout && !core.hasAsync()) {
				clearTimeout(core.timeout.sleepTimeout);
				core.timeout.sleepTimeout = null;
				core.doAction();
				return true;
			}
		}
		return false;
	}
	//楼传操作页面按钮加大
	actions.prototype._clickFly = function (x, y) {
		if ((x >= this.SIZE - 4 && x <= this.SIZE - 1) && (y >= this.HSIZE + 2 && y <= this.HSIZE + 3)) {
			core.playSound('光标移动');
			core.ui.drawFly(this._getNextFlyFloor(-1));
		} else if ((x >= this.SIZE - 4 && x <= this.SIZE - 1) && (y >= this.HSIZE - 1 && y <= this.HSIZE)) {
			core.playSound('光标移动');
			core.ui.drawFly(this._getNextFlyFloor(1));
		} else if ((x >= this.SIZE - 4 && x <= this.SIZE - 1) && (y >= this.HSIZE + 4 && y <= this.HSIZE + 5)) {
			core.playSound('光标移动');
			core.ui.drawFly(this._getNextFlyFloor(-10));
		} else if ((x >= this.SIZE - 4 && x <= this.SIZE - 1) && (y >= this.HSIZE - 3 && y <= this.HSIZE - 2)) {
			core.playSound('光标移动');
			core.ui.drawFly(this._getNextFlyFloor(10));
		} else if (x >= this.HSIZE - 1 && x <= this.HSIZE + 1 && y == this.LAST) {
			core.playSound('取消');
			core.ui.closePanel();
		} else if (x >= 0 && x <= this.HSIZE + 3 && y >= 3 && y <= this.LAST - 1)
			core.flyTo(core.floorIds[core.status.event.data]);
		return;
	}

},
    "性能优化": function () {
	core.ui.clearMap = function (name, x, y, width, height) {
		if (name == 'all') {
			for (var m in core.canvas) {
				core.canvas[m].clearRect(0, 0, core.bigmap.width * 32, core.bigmap.height * 32);
			}
			core.clearMap("outerUI");
			core.dom.gif.innerHTML = "";
			core.removeGlobalAnimate();
			core.deleteCanvas(function (one) { return one.startsWith('_bigImage_'); });

		} else {
			var ctx = this.getContextByName(name);
			if (ctx) ctx.clearRect(x || 0, y || 0, width || ctx.canvas.width, height || ctx.canvas.height);
			if (name === 'outerUI') {
				delete core.status.lastPropsDrawn;
				delete core.status.lastItemsDrawn;
				delete core.status.lastItemGridCache;
				delete core.status.lastEquipsDrawn;
				delete core.status.lastKeysDrawn;
			}
		}
	}
	control.prototype.updateStatusBar = function (doNotCheckAutoEvents) {
		if (!core.isPlaying() || core.hasFlag('__statistics__')) return;
		this.controldata.updateStatusBar();
		if (!doNotCheckAutoEvents) core.checkAutoEvents();
		this._updateStatusBar_setToolboxIcon();
		core.clearRouteFolding();
	}
	//顺带关闭预览模式
	actions.prototype._sys_ondown = function (x, y, px, py) {
		if (core.status.lockControl) return false;
		core.status.downTime = new Date();
		core.clearMap('route', 0, 0, 352, 352);
		var pos = { 'x': parseInt((px + core.bigmap.offsetX) / 32), 'y': parseInt((py + core.bigmap.offsetY) / 32) };
		core.status.stepPostfix = [];
		core.status.stepPostfix.push(pos);
		core.fillRect('ui', pos.x * 32 + 12 - core.bigmap.offsetX, pos.y * 32 + 12 - core.bigmap.offsetY, 8, 8, '#bfbfbf');

		clearTimeout(core.timeout.onDownTimeout);
		core.timeout.onDownTimeout = null;
		core.status.preview.prepareDragging = false;
		/*if (!core.hasFlag('__lockViewport__') && (core.status.thisMap.width > core.__SIZE__ || core.status.thisMap.height > core.__SIZE__)) {
		    core.status.preview.prepareDragging = true;
		    core.status.preview.px = px;
		    core.status.preview.py = py;
		    core.timeout.onDownTimeout = setTimeout(function () {
		        core.clearMap('ui');
		        core.status.preview.prepareDragging = false;
		        core.status.preview.enabled = true;
		        core.status.preview.dragging = true;
		        core.drawTip('已进入预览模式，可直接拖动大地图');
		        core.status.stepPostfix = [];
		    }, 500);
		} */
	}
	control.prototype.clearAutomaticRouteNode = function (x, y) {
		core.clearMap('route', x * 32 + 5 - core.status.automaticRoute.offsetX, y * 32 + 5 - core.status.automaticRoute.offsetY, 27, 27);
	}
	control.prototype.stopAutomaticRoute = function () {
		if (!core.status.played) return;
		core.status.automaticRoute.autoHeroMove = false;
		core.status.automaticRoute.autoStep = 0;
		core.status.automaticRoute.destStep = 0;
		core.status.automaticRoute.movedStep = 0;
		core.status.automaticRoute.autoStepRoutes = [];
		core.status.automaticRoute.destX = null;
		core.status.automaticRoute.destY = null;
		core.status.automaticRoute.lastDirection = null;
		core.status.heroStop = true;
		if (core.status.automaticRoute.moveStepBeforeStop.length == 0)
			core.clearMap('route', 0, 0, 352, 352);
	}
	control.prototype._setAutomaticRoute_drawRoute = function (moveStep) {
		// 计算绘制区域的宽高，并尽可能小的创建route层
		var sx = core.bigmap.width * 32,
			sy = core.bigmap.height * 32,
			dx = 0,
			dy = 0;
		moveStep.forEach(function (t) {
			sx = Math.min(sx, t.x * 32);
			dx = Math.max(dx, t.x * 32);
			sy = Math.min(sy, t.y * 32);
			dy = Math.max(dy, t.y * 32);
		});
		core.status.automaticRoute.offsetX = sx;
		core.status.automaticRoute.offsetY = sy;
		var ctx = core.createCanvas('route', sx - core.bigmap.offsetX, sy - core.bigmap.offsetY, dx - sx + 32, dy - sy + 32, 95);
		ctx.fillStyle = '#bfbfbf';
		ctx.strokeStyle = '#bfbfbf';
		ctx.lineWidth = 8;
		for (var m = 0; m < moveStep.length; m++) {
			if (m == moveStep.length - 1) {
				ctx.fillRect(moveStep[m].x * 32 + 10 - sx, moveStep[m].y * 32 + 10 - sy, 12, 12);
			} else {
				ctx.beginPath();
				var cx = moveStep[m].x * 32 + 16 - sx,
					cy = moveStep[m].y * 32 + 16 - sy;
				var currDir = moveStep[m].direction,
					nextDir = moveStep[m + 1].direction;
				ctx.moveTo(cx - core.utils.scan[currDir].x * 11, cy - core.utils.scan[currDir].y * 11);
				ctx.lineTo(cx, cy);
				ctx.lineTo(cx + core.utils.scan[nextDir].x * 11, cy + core.utils.scan[nextDir].y * 11);
				ctx.stroke();
			}
		}
	}
	events.prototype._openDoor_check = function (block, x, y, needKey) {
		var clearAndReturn = function () {
			core.clearContinueAutomaticRoute();
			return false;
		}

		if (block == null || block.event == null) return clearAndReturn();
		var id = block.event.id;

		// 是否存在门或暗墙
		if (core.material.icons.animates[id] == null && core.material.icons.npc48[id] == null) {
			return clearAndReturn();
		}

		if (id == 'steelDoor' && core.flags.steelDoorWithoutKey)
			needKey = false;
		var doorInfo = block.event.doorInfo;
		if (doorInfo == null) return clearAndReturn();
		// Check all keys
		var keyInfo = doorInfo.keys || {};
		if (needKey) {
			for (var keyName in keyInfo) {
				var keyValue = keyInfo[keyName];
				if (keyName.endsWith(':o')) keyName = keyName.substring(0, keyName.length - 2);

				// --- 如果是一个不存在的道具，则直接认为无法开启
				if (!core.material.items[keyName]) {
					core.stopSound();
					core.playSound('操作失败');
					core.drawTip("无法开启此门");
					return clearAndReturn();
				}
				if (core.itemCount(keyName) < keyValue) {
					core.stopSound();
					core.playSound('操作失败');
					core.drawTip("你的" + ((core.material.items[keyName] || {}).name || "钥匙") + "不足！", null, true);
					return false;
				}
			}
			if (!core.status.event.id) core.autosave(true);
			for (var keyName in keyInfo) {
				if (!keyName.endsWith(':o'))
					core.status.hero.items[core.material.items[keyName].cls][keyName] -= keyInfo[keyName];
			}
		}
		core.playSound(doorInfo.openSound);
		return true;
	}

},
    "键盘操作优化": function () {

	actions.prototype._clickSwitchs_action_moveSpeed = function (delta) {
		core.values.moveSpeed = core.clamp(core.values.moveSpeed + delta, 1, 200);
		core.setLocalStorage("moveSpeed", core.values.moveSpeed);
		core.ui._drawSwitchs_action();
	}

	core.control._moveHero_moving = function () {
		core.status.heroStop = false;
		core.status.automaticRoute.moveDirectly = false;

		if (!core.status.automaticRoute.autoStepRoutes.length) {
			// 手动移动，只执行一次
			core.moveAction();
			core.status.heroStop = true;
			return;
		}

		var move = function () {
			if (!core.status.heroStop) {
				if (core.hasFlag('debug') && core.status.ctrlDown) {
					if (core.status.heroMoving != 0) return;
					// 检测是否穿出去
					var nx = core.nextX(),
						ny = core.nextY();
					if (nx < 1 || nx >= core.bigmap.width - 1 || ny < 1 || ny >= core.bigmap.height - 1) return;
					core.eventMoveHero([core.getHeroLoc('direction')], core.values.moveSpeed, move);
				} else {
					core.moveAction();
					setTimeout(move, 50);
				}
			}
		}
		move();
	}

	// 改成新的方向键处理逻辑
	actions.prototype._sys_onkeyDown = function (e) {
		core.status.holdingKeys = core.status.holdingKeys || [];
		var isArrow = { 37: true, 38: true, 39: true, 40: true } [e.keyCode];

		if (isArrow && !core.status.lockControl) {
			if (e.preventDefault) e.preventDefault();

			if (!core.status.holdingKeys.includes(e.keyCode)) {
				core.status.holdingKeys.push(e.keyCode);
			}

			if (!core.status._pressTimer) {
				core.status._pressTimer = setInterval(() => {
					if (!core.status.holdingKeys.length) {
						clearInterval(core.status._pressTimer);
						core.status._pressTimer = null;
						return;
					}
					var keyCode = core.status.holdingKeys.slice(-1)[0];
					this.keyDown(keyCode);
				}, 50);
			}
		} else {
			if (e.keyCode === 17) core.status.ctrlDown = true;
			this.keyDown(e.keyCode, e.altKey);
		}
	};

	actions.prototype._sys_onkeyUp = function (e) {
		var isArrow = { 37: true, 38: true, 39: true, 40: true } [e.keyCode];
		if (isArrow && !core.status.lockControl) {
			var idx = core.status.holdingKeys.indexOf(e.keyCode);
			if (idx >= 0) core.status.holdingKeys.splice(idx, 1);

			if (e.preventDefault) e.preventDefault();

			this.keyUp(e.keyCode, e.altKey);
		} else {
			if (e.keyCode === 17) core.status.ctrlDown = false;
			this.keyUp(e.keyCode, e.altKey);
		}
	};

	// 删除了 _sys_fastPressLoop，不再需要！

	// 注册（注意：这里不再注册 _sys_fastPressLoop 了）
	core.actions.registerAction('onkeyDown', '_sys_onkeyDown', core.actions._sys_onkeyDown, 0);
	core.actions.registerAction('pressKey', '_sys_pressKey', core.actions._sys_pressKey, 0);
	core.actions.registerAction('onkeyUp', '_sys_onkeyUp', core.actions._sys_onkeyUp, 0);

},
    "缩略图优化": function () {
	// —— 初始化 tempCanvas，只需一次 —— 
	core.bigmap.tempCanvas = (function () {
		const canvas = document.createElement('canvas');
		const ctx = canvas.getContext('2d');
		return ctx;
	})();

	// —— 重写 drawThumbnail 绘制到临时小画布 —— 
	core.maps._drawThumbnail_drawTempCanvas = function (floorId, blocks, options) {
		if (main.mode == 'editor') {
			_drawThumbnail_drawTempCanvas.call(this, floorId, blocks, options);
			return;
		}

		const width = 11,
			height = 11;
		const tempCanvas = core.bigmap.tempCanvas;
		const dpr = core.plugin.getHDRatio();

		// 设置临时画布的物理尺寸
		tempCanvas.canvas.width = width * 32 * dpr;
		tempCanvas.canvas.height = height * 32 * dpr;
		tempCanvas.canvas.style.width = width * 32 + "px";
		tempCanvas.canvas.style.height = height * 32 + "px";

		// 设置高清缩放比例
		tempCanvas.setTransform(dpr, 0, 0, dpr, 0, 0);
		//tempCanvas.imageSmoothingEnabled = false;

		options.v2 = false;
		options.ctx = tempCanvas;

		// 绘制时平移坐标到(1,1)格位置
		tempCanvas.save();
		tempCanvas.translate(-32, -32); // 注意这里已经是缩放后的坐标

		this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options);

		tempCanvas.restore();
	}

	// —— 重写 drawThumbnail 绘制到目标 ctx —— 
	core.maps._drawThumbnail_drawToTarget = function (floorId, options) {
		if (main.mode == 'editor') {
			_drawThumbnail_drawToTarget.call(this, floorId, options);
			return;
		}

		const ctx = core.getContextByName(options.ctx);
		if (!ctx) return;

		const tempCanvas = core.bigmap.tempCanvas;
		const dpr = window.devicePixelRatio || 1;

		const srcW = tempCanvas.canvas.width;
		const srcH = tempCanvas.canvas.height;

		const dstX = options.x || 0;
		const dstY = options.y || 0;
		const dstW = options.width || options.size || core.__PIXELS__;
		const dstH = options.height || options.size || core.__PIXELS__;

		ctx.imageSmoothingEnabled = false;

		ctx.drawImage(
			tempCanvas.canvas,
			0, 0, srcW, srcH, // 源画布
			dstX, dstY, dstW, dstH // 目标画布
		);
	};

}
}