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

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

	// 可以写一些直接执行的代码
	// 在这里写的代码将会在【资源加载前】被执行，此时图片等资源尚未被加载。
	// 请勿在这里对包括bgm，图片等资源进行操作。

	// 属性 -> 颜色 / 中文（怪物手册详情用；与技能面板同一套配色）
	var BOOK_TYPE_COLOR = {
		Normal: '#BBBBAA', Fire: '#FF4422', Water: '#77BBFF', Electric: '#FFCC33',
		Grass: '#77CC55', Ice: '#77DDFF', Fighting: '#BB5544', Poison: '#AA5599',
		Ground: '#DDBB55', Flying: '#6699FF', Psychic: '#FF5599', Bug: '#AABB22',
		Rock: '#BBAA66', Ghost: '#666688', Dragon: '#7766EE', Steel: '#AAAABB',
		Fairy: '#FFAAFF', Dark: '#775544'
	};
	var BOOK_TYPE_CN = {
		Normal: '一般', Fire: '火', Water: '水', Electric: '电', Grass: '草', Ice: '冰',
		Fighting: '格斗', Poison: '毒', Ground: '地面', Flying: '飞行', Psychic: '超能',
		Bug: '虫', Rock: '岩石', Ghost: '幽灵', Dragon: '龙', Steel: '钢', Fairy: '妖精', Dark: '恶'
	};
	// 在 data 画布上画一个属性圆角标签，返回其宽度
	var drawBookTypeBadge = function (type, x, y) {
		if (!type) return 0;
		var label = BOOK_TYPE_CN[type] || type;
		var font = core.ui._buildFont(14, true);
		var bw = core.calWidth('data', label, font) + 18;
		core.fillRoundRect('data', x, y, bw, 22, 6, BOOK_TYPE_COLOR[type] || '#888888');
		core.setTextAlign('data', 'center');
		core.fillText('data', label, x + bw / 2, y + 16, '#FFFFFF', font);
		core.setTextAlign('data', 'left');
		return bw;
	};

	// ===== 属性相克：弱点 / 抗性 =====
	var ALL_TYPES = ['Normal', 'Fire', 'Water', 'Electric', 'Grass', 'Ice', 'Fighting', 'Poison',
		'Ground', 'Flying', 'Psychic', 'Bug', 'Rock', 'Ghost', 'Dragon', 'Dark', 'Steel', 'Fairy'];
	var MULT_LABEL = { '4': '4×', '2': '2×', '0.5': '½×', '0.25': '¼×', '0': '0×' };
	// 攻击属性 atk 打这只怪的总倍率 = typeChart[atk][type1] × typeChart[atk][type2]
	var typeMul = function (enemy, atk) {
		var row = (core.flags.typeChart || {})[atk] || {}, m = 1;
		if (enemy.type1 && row[enemy.type1] != null) m *= row[enemy.type1];
		if (enemy.type2 && row[enemy.type2] != null) m *= row[enemy.type2];
		return m;
	};
	// 把 18 个攻击属性按倍率归类
	var computeEff = function (enemy) {
		var g = { '4': [], '2': [], '0.5': [], '0.25': [], '0': [] };
		ALL_TYPES.forEach(function (t) {
			var m = typeMul(enemy, t);
			if (g[m + ''] !== undefined && m != 1) g[m + ''].push(t);
		});
		return g;
	};
	// 绘制(doDraw=true)或测量(false)弱点/抗性区，返回占用高度
	var drawEffectiveness = function (enemy, x0, y0, maxRight, doDraw) {
		if (!enemy.type1) return 0;
		var g = computeEff(enemy), rowH = 28, lf = core.ui._buildFont(15, true), y = y0;
		var section = function (label, color, order) {
			var groups = order.filter(function (k) { return g[k].length; });
			var labelW = core.calWidth('data', label, lf);
			if (groups.length == 0) {
				if (doDraw) { core.setTextAlign('data', 'left'); core.fillText('data', label + '无', x0, y + 20, color, lf); }
				y += rowH; return;
			}
			var first = true;
			groups.forEach(function (k) {
				var lineX = x0 + labelW;
				if (doDraw) {
					core.setTextAlign('data', 'left');
					if (first) core.fillText('data', label, x0, y + 20, color, lf);
					core.fillText('data', '(' + MULT_LABEL[k] + ')', lineX, y + 20, '#DDDDDD', lf);
				}
				var baseBx = lineX + core.calWidth('data', '(' + MULT_LABEL[k] + ')', lf) + 6, bx = baseBx;
				g[k].forEach(function (t) {
					var bw = core.calWidth('data', BOOK_TYPE_CN[t] || t, core.ui._buildFont(14, true)) + 18;
					if (bx + bw > maxRight) { y += rowH; bx = baseBx; }
					if (doDraw) drawBookTypeBadge(t, bx, y + 4);
					bx += bw + 6;
				});
				y += rowH; first = false;
			});
		};
		section('弱点：', '#FF7766', ['4', '2']);
		section('抗性：', '#66CC99', ['0.5', '0.25', '0']);
		return y - y0;
	};

	core.ui._drawBookDetail_turnAndCriticals = function (enemy, floorId, texts) {
		// 属性用圆角标签显示（见 _drawBookDetail_drawContent）；速度/临界表已去除，仅保留战斗回合数
		var damageInfo = core.getDamageInfo(enemy.id, null, null, null, floorId);
		texts.push("\r[#FF6A6A]\\d战斗回合数：\\d\r[]"+((damageInfo||{}).turn||0));
	}

	core.ui._drawBookDetail_drawContent = function (enemy, content, pos) {
		// 名称
		core.setTextAlign('data', 'left');
		var tmp = enemy.name;
		if (enemy.level) {
			tmp += " Lv." + enemy.level;
		}
		core.fillText('data', tmp, pos.content_left, pos.top + 30, '#FFD700', this._buildFont(22, true));
		var content_top = pos.top + 44;
		// 属性圆角标签行（替代原来的文字"属性："行）
		if (enemy.type1) {
			var by = content_top;
			var bx = pos.content_left;
			bx += drawBookTypeBadge(enemy.type1, bx, by) + 8;
			drawBookTypeBadge(enemy.type2, bx, by);
			content_top = by + 30;
		}

		this.drawTextContent('data', content, {left: pos.content_left, top: content_top, maxWidth: pos.validWidth,
			fontSize: 16, lineHeight: 24});

		// 属性相克：弱点 / 抗性（接在正文之后）
		var textH = this.getTextContentHeight(content, {fontSize: 16, lineHeight: 24, maxWidth: pos.validWidth});
		drawEffectiveness(enemy, pos.content_left, content_top + textH + 8, pos.content_left + pos.validWidth, true);
	}

	// 覆写详情框：为属性标签行 + 弱点/抗性区额外预留高度，避免内容溢出边框
	core.ui.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.clearTip();
		core.clearMap('data');

		var left = 10, width = this.PIXEL - 2 * left, right = left + width;
		var content_left = left + 25, validWidth = right - content_left - 13;
		var extra = enemy.type1 ? 30 : 0;   // 属性标签行高度
		var effH = drawEffectiveness(enemy, content_left, 0, content_left + validWidth, false);   // 测量弱点/抗性区高度
		if (effH > 0) extra += effH + 8;
		var height = Math.max(this.getTextContentHeight(content, {fontSize: 16, lineHeight: 24, maxWidth: validWidth}) + 58 + extra, 80),
			top = (this.PIXEL - height) / 2, bottom = top + height;

		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);

		this._drawBookDetail_drawContent(enemy, content, {top: top, content_left: content_left, bottom: bottom, validWidth: validWidth});
	}

	// 怪物手册列表 第一行：生命 速度 等级
	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, null, b13);
		core.fillText('ui', '速度', col2, position, null, f13);
		core.fillText('ui', core.formatBigNumber(enemy.speed || 0), col2 + 30, position, null, b13);
		core.fillText('ui', '等级', col3, position, null, f13);
		core.fillText('ui', enemy.level != null ? enemy.level : '-', col3 + 30, position, null, b13);
	}

	// 怪物手册列表 第二行：攻击 防御 伤害
	core.ui._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;
		core.fillText('ui', '攻击', col1, position, '#DDDDDD', f13);
		core.fillText('ui', core.formatBigNumber(enemy.atk || 0), col1 + 30, position, null, b13);
		core.fillText('ui', '防御', col2, position, null, f13);
		core.fillText('ui', core.formatBigNumber(enemy.def || 0), col2 + 30, position, null, b13);
		// 伤害值（无标签，居中放在右列，沿用引擎配色/后缀逻辑）
		var damage_offset = col3 + (this.PIXEL - col3) / 2 - 12;
		this._drawBook_drawDamage(index, enemy, damage_offset, position);
	}

	// 怪物手册列表 第三行：金币 经验 （第三列留空）
	core.ui._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;
		core.fillText('ui', '金币', col1, position, '#DDDDDD', f13);
		core.fillText('ui', core.formatBigNumber(enemy.money || 0), col1 + 30, position, null, b13);
		core.fillText('ui', '经验', col2, position, null, f13);
		core.fillText('ui', core.formatBigNumber(enemy.exp || 0), col2 + 30, position, null, b13);
	}

	core.ui.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 = this.PIXEL - 306;
		this._drawToolbox_drawLine(line1, "消耗道具");
		var line2 = this.PIXEL - 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, this.LAST - 5);
		this._drawToolbox_drawContent(info, line2, info.constants, info.constantsPage);
		this.drawPagination(info.constantsPage, info.constantsTotalPage);
	
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '[装备栏]', this.PIXEL - 46, 25, '#DDDDDD', this._buildFont(15, true));
		core.fillText('ui', '返回游戏', this.PIXEL - 46, this.PIXEL - 13);
	}


	this._afterLoadResources = function () {
		// 本函数将在所有资源加载完毕后，游戏开启前被执行
		// 可以在这个函数里面对资源进行一些操作，比如切分图片等。

		// 手机端入口：点击左侧状态栏「技能」行 → 打开技能面板(等同 K 键)；
		// 面板里有「属性相克表」按钮可进相克表(等同 I 键)。桌面端也可点击。
		try {
			var skillEl = core.statusBar && core.statusBar.skill;
			var row = skillEl && (skillEl.parentNode || skillEl);
			if (row) {
				row.style.cursor = 'pointer';
				row.onclick = function () {
					if (!core.isPlaying() || core.status.lockControl || core.status.event.id) return;
					core.drawSkillBook();
				};
			}
		} catch (e) { main.log(e); }
	}

	// 可以在任何地方（如afterXXX或自定义脚本事件）调用函数，方法为 core.plugin.xxx();
	// 从V2.6开始，插件中用this.XXX方式定义的函数也会被转发到core中，详见文档-脚本-函数的转发。
},
    "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.__PIXELS__, core.__PIXELS__, 98);
			else return;
		}

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

		core.clearMap(name);
		// 绘制色调层，默认不透明度
		if (color == null) color = 0.9;
		ctx.fillStyle = "rgba(0,0,0," + color + ")";
		ctx.fillRect(0, 0, ctx.canvas.width, ctx.canvas.height);

		lightDec = core.clamp(lightDec, 0, 1);

		// 绘制每个灯光效果
		ctx.globalCompositeOperation = 'destination-out';
		lights.forEach(function (light) {
			// 坐标，半径，中心不透明度
			var x = light[0],
				y = light[1],
				r = light[2];
			// 计算衰减距离
			var decDistance = parseInt(r * lightDec);
			// 正方形区域的直径和左上角坐标
			var grd = ctx.createRadialGradient(x, y, decDistance, x, y, r);
			grd.addColorStop(0, "rgba(0,0,0,1)");
			grd.addColorStop(1, "rgba(0,0,0,0)");
			ctx.beginPath();
			ctx.fillStyle = grd;
			ctx.arc(x, y, r, 0, 2 * Math.PI);
			ctx.fill();
		});
		ctx.globalCompositeOperation = 'source-over';
		// 可以在任何地方（如afterXXX或自定义脚本事件）调用函数，方法为  core.plugin.xxx();
	}
},
    "shop": function () {
	// 【全局商店】相关的功能
	// 
	// 打开一个全局商店
	// shopId：要打开的商店id；noRoute：是否不计入录像
	this.openShop = function (shopId, noRoute) {
		var shop = core.status.shops[shopId];
		// Step 1: 检查能否打开此商店
		if (!this.canOpenShop(shopId)) {
			core.drawTip("该商店尚未开启");
			return false;
		}

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

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

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

	////// 将一个全局商店转变成可预览的公共事件 //////
	this._convertShop = function (shop) {
		return [
			{ "type": "function", "function": "function() {core.setFlag('@temp@shop', true);}" },
			{
				"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": "break" },
								],
								"false": [
									// 可以预览：将商店全部内容进行替换
									{ "type": "tip", "text": "当前处于预览模式，不可购买" },
									{ "type": "function", "function": "function() { core.plugin._convertShop_replaceChoices('" + shop.id + "', true) }" },
								]
							}
						]
					}
				]
			},
			{ "type": "function", "function": "function() {core.removeFlag('@temp@shop');}" }
		];
	}

	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 ? choice.action : [
					{ "type": "tip", "text": previewMode ? "预览模式下不可购买" : "购买条件不足" }
				]
			};
		}).concat({ "text": "离开", "action": [{ "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;
	}

	/// 允许商店X键退出
	core.registerAction('keyUp', '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.HSIZE - parseInt((choices.length - 1) / 2) + (core.status.event.ui.offset || 0);
		if (keycode == 88) { // X
			core.actions._clickAction(core.actions.HSIZE, topIndex + choices.length - 1);
			return true;
		}
	}, 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.__removed__ = flags.__removed__ || [];
		for (var i = fromIndex; i <= toIndex; ++i) {
			var floorId = core.floorIds[i];
			delete flags.__visited__[floorId];
			flags.__removed__.push(floorId);
			core.status.maps[floorId].deleted = true;
			core.status.maps[floorId].canFlyTo = 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];
			flags.__removed__ = flags.__removed__.filter(function (f) { return f != floorId; });
			if (core.status.maps[floorId].deleted) {
				core.status.maps[floorId] = core.loadFloor(floorId);
			}
		}
	}
},
    "fiveLayers": function () {
	// 是否启用五图层（增加背景2层和前景2层） 将__enableFiveLayers置为true即会启用；启用后请保存后刷新编辑器
	// 背景层2将会覆盖背景层 被事件层覆盖 前景层2将会覆盖前景层
	// 另外 请注意加入两个新图层 会让大地图的性能降低一些
	// 插件作者：ad
	var __enableFiveLayers = false;
	if (!__enableFiveLayers) return;

	// 创建新图层
	function createCanvas(name, zIndex) {
		if (!name) return;
		var canvas = document.createElement('canvas');
		canvas.id = name;
		canvas.className = 'gameCanvas';
		canvas.width = canvas.height = core.__PIXELS__;
		// 编辑器模式下设置zIndex会导致加入的图层覆盖优先级过高
		if (main.mode != "editor") canvas.style.zIndex = zIndex || 0;
		// 将图层插入进游戏内容
		document.getElementById('gameDraw').appendChild(canvas);
		var ctx = canvas.getContext('2d');
		core.canvas[name] = ctx;
		return canvas;
	}

	var bg2Canvas = createCanvas('bg2', 20);
	var fg2Canvas = createCanvas('fg2', 63);
	// 大地图适配
	core.bigmap.canvas = ["bg2", "fg2", "bg", "event", "event2", "fg", "damage"];

	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('efg'));
		// 原本有三个图层 从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 defaultMap = [];
		for (var i = 0; i < core.__SIZE__; ++i) {
			var row = [];
			for (var j = 0; j < core.__SIZE__; ++j) {
				row.push(0);
			}
			defaultMap.push(row);
		}

		// 创建编辑器上的按钮
		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);
			}
			editor[value] = editor[value] || defaultMap;
			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;
			editor[value] = editor[value] || defaultMap;
			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('背景层2');
			// 插入事件层前(即新插入的背景层2前)
			parent.insertBefore(txt, child);
			// 向最后插入前景层2(即插入前景层后)
			parent.appendChild(input2);
			var txt2 = document.createTextNode('前景层2');
			parent.appendChild(txt2);
		} 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);
		}
	}

	////// 绘制背景层 //////
	core.maps.drawBg = function (floorId, ctx) {
		floorId = floorId || core.status.floorId;
		var onMap = ctx == null;
		if (onMap) {
			ctx = core.canvas.bg;
			core.clearMap(ctx);
			core.status.floorAnimateObjs = this._getFloorImages(floorId);
		}
		core.maps._drawBg_drawBackground(floorId, ctx);
		// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块；后绘制的覆盖先绘制的。
		core.maps._drawFloorImages(floorId, ctx, 'bg');
		core.maps._drawBgFgMap(floorId, ctx, 'bg', onMap);
		// 绘制背景层2
		core.maps._drawBgFgMap(floorId, ctx, 'bg2', onMap);
	};

	////// 绘制前景层 //////
	core.maps.drawFg = function (floorId, ctx) {
		floorId = floorId || core.status.floorId;
		var onMap = ctx == null;
		if (onMap) {
			ctx = core.canvas.fg;
			core.status.floorAnimateObjs = this._getFloorImages(floorId);
		}
		// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块；后绘制的覆盖先绘制的。
		this._drawFloorImages(floorId, ctx, 'fg');
		this._drawBgFgMap(floorId, ctx, 'fg', onMap);
		// 绘制前景层2
		this._drawBgFgMap(floorId, ctx, 'fg2', onMap);
	};
	/* cannotIn/cannotOut适配 start*/
	core.maps.generateMovableArray = function (floorId, x, y, direction) {
		floorId = floorId || core.status.floorId;
		if (!floorId) return null;
		var width = core.floors[floorId].width,
			height = core.floors[floorId].height;
		var bgArray = this.getBgMapArray(floorId),
			bg2Array = this._getBgFgMapArray('bg2', floorId),
			fgArray = this.getFgMapArray(floorId),
			fg2Array = this._getBgFgMapArray('fg2', floorId),
			eventArray = this.getMapArray(floorId);

		var generate = function (x, y, direction) {
			if (direction != null) {
				return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, {
					bgArray: bgArray,
					fgArray: fgArray,
					bg2Array: bg2Array,
					fg2Array: fg2Array,
					eventArray: eventArray
				});
			}
			return ["left", "down", "up", "right"].filter(function (direction) {
				return core.maps._canMoveHero_checkPoint(x, y, direction, floorId, {
					bgArray: bgArray,
					fgArray: fgArray,
					bg2Array: bg2Array,
					fg2Array: fg2Array,
					eventArray: eventArray
				});
			});
		};

		if (x != null && y != null) return generate(x, y, direction);
		var array = [];
		for (var x = 0; x < width; x++) {
			array[x] = [];
			for (var y = 0; y < height; y++) {
				array[x][y] = generate(x, y);
			}
		}
		return array;
	};
	core.maps._canMoveHero_checkPoint = function (x, y, direction, floorId, extraData) {
		// 1. 检查该点 cannotMove
		if (core.inArray((core.floors[floorId].cannotMove || {})[x + "," + y], direction))
			return false;

		var nx = x + core.utils.scan[direction].x,
			ny = y + core.utils.scan[direction].y;
		if (nx < 0 || ny < 0 || nx >= core.floors[floorId].width || ny >= core.floors[floorId].height)
			return false;

		// 2. 检查该点素材的 cannotOut 和下一个点的 cannotIn
		if (this._canMoveHero_checkCannotInOut([
				extraData.bgArray[y][x], extraData.bg2Array[y][x], extraData.fgArray[y][x], extraData.fg2Array[y][x], extraData.eventArray[y][x]
			], "cannotOut", direction))
			return false;
		if (this._canMoveHero_checkCannotInOut([
				extraData.bgArray[ny][nx], extraData.bg2Array[ny][nx], extraData.fgArray[ny][nx], extraData.fg2Array[ny][nx], extraData.eventArray[ny][nx]
			], "cannotIn", direction))
			return false;

		// 3. 检查是否能进将死的领域
		if (floorId == core.status.floorId && !core.flags.canGoDeadZone &&
			core.status.hero.hp <= (core.status.checkBlock.damage[nx + "," + ny] || 0) &&
			extraData.eventArray[ny][nx] == 0)
			return false;

		return true;
	};
	/* cannotIn/cannotOut适配 end*/
	// 前景层2与背景层2的隐藏与显示适配
	// 比如:可以用core.hideBgFgMap("bg2",[x, y], floorId)隐藏当前楼层的背景层2图块
	core.maps._triggerBgFgMap = function (type, name, loc, floorId, callback) {
		if (type != 'show') type = 'hide';
		if (!name) name = 'bg';
		if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
			loc = [loc];
		floorId = floorId || core.status.floorId;
		if (!floorId) return;

		if (loc.length == 0) return;
		loc.forEach(function (t) {
			var x = t[0],
				y = t[1];
			var flag = [floorId, x, y, name + '_disable'].join('@');
			if (type == 'hide') core.setFlag(flag, true);
			else core.removeFlag(flag);
		});
		core.status[name + "maps"][floorId] = null;

		if (floorId == core.status.floorId) {
			core.drawMap(floorId, callback);
		} else {
			if (callback) callback();
		}
	};
	// 改变背景层2与前景层2图块 例:core.setBgFgBlock('fg2',312,core.nextX(),core.nextY())
	core.maps.setBgFgBlock = function (name, number, x, y, floorId) {
		floorId = floorId || core.status.floorId;
		if (!floorId || number == null || x == null || y == null) return;
		if (x < 0 || x >= core.floors[floorId].width || y < 0 || y >= core.floors[floorId].height) return;
		if (name != 'bg' && name != 'fg' && name != 'bg2' && name != 'fg2') return;
		if (typeof number == 'string') {
			if (/^\d+$/.test(number)) number = parseInt(number);
			else number = core.getNumberById(number);
		}

		var vFlag = [floorId, x, y, name + "_value"].join('@');
		core.setFlag(vFlag, number);
		core.status[name + "maps"][floorId] = null;

		if (floorId == core.status.floorId) {
			core.clearMap(name);
			if (name.startsWith('bg')) core.drawBg(floorId);
			else core.drawFg(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 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([1, 2]);
		core.setTextAlign('uievent', 'left');
		core.setTextBaseline('uievent', 'top');
		core.fillRect('uievent', 0, 0, 416, 416, 'black');
		core.drawWindowSkin('winskin.png', 'uievent', 0, 0, 416, 56);
		core.drawWindowSkin('winskin.png', 'uievent', 0, 56, 312, 56);
		core.drawWindowSkin('winskin.png', 'uievent', 0, 112, 312, 304);
		core.drawWindowSkin('winskin.png', 'uievent', 312, 56, 104, 56);
		core.drawWindowSkin('winskin.png', 'uievent', 312, 112, 104, 304);
		core.setFillStyle('uievent', 'white');
		core.setStrokeStyle('uievent', 'white');
		core.fillText("uievent", "购买", 32, 74, 'white', bigFont);
		core.fillText("uievent", "卖出", 132, 74);
		core.fillText("uievent", "离开", 232, 74);
		core.fillText("uievent", "当前金币", 324, 66, null, middleFont);
		core.setTextAlign("uievent", "right");
		core.fillText("uievent", core.formatBigNumber(core.status.hero.money), 405, 89);
		core.setTextAlign("uievent", "left");
		core.ui._uievent_drawSelector({
			"type": "drawSelector",
			"image": "winskin.png",
			"code": 2,
			"x": 22 + 100 * type,
			"y": 66,
			"width": 60,
			"height": 33
		});
		if (selectItem != null) {
			core.setTextAlign('uievent', 'center');
			core.fillText("uievent", type == 0 ? "买入个数" : "卖出个数", 364, 320, null, bigFont);
			core.fillText("uievent", "<   " + selectCount + "   >", 364, 350);
			core.fillText("uievent", "确定", 364, 380);
		}

		// 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 = 6;
		totalPage = Math.ceil(list.length / per_page);
		page = Math.floor((selectItem || 0) / per_page) + 1;

		// 绘制分页
		if (totalPage > 1) {
			var half = 156;
			core.setTextAlign('uievent', 'center');
			core.fillText('uievent', page + " / " + totalPage, half, 388, null, middleFont);
			if (page > 1) core.fillText('uievent', '上一页', half - 80, 388);
			if (page < totalPage) core.fillText('uievent', '下一页', half + 80, 388);
		}
		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, 125 + i * 40);
			core.setTextAlign('uievent', 'left');
			core.fillText('uievent', core.material.items[item.id].name, 50, 132 + i * 40, null, bigFont);
			core.setTextAlign('uievent', 'right');
			core.fillText('uievent', (type == 0 ? core.calValue(item.money) : core.calValue(item.sell)) + "金币/个", 300, 133 + 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: 403 };
					var height = core.getTextContentHeight(text, config);
					if (height <= 50) {
						config.top = (56 - height) / 2;
						core.drawTextContent("uievent", text, config);
						break;
					}
				}
				core.ui._uievent_drawSelector({ "type": "drawSelector", "image": "winskin.png", "code": 1, "x": 8, "y": 120 + i * 40, "width": 295, "height": 40 });
				if (type == 0 && item.number != null) {
					core.fillText("uievent", "存货", 324, 132, null, bigFont);
					core.setTextAlign("uievent", "right");
					core.fillText("uievent", item.number, 406, 132, null, null, 40);
				} else if (type == 1) {
					core.fillText("uievent", "数量", 324, 132, null, bigFont);
					core.setTextAlign("uievent", "right");
					core.fillText("uievent", core.itemCount(item.id), 406, 132, null, null, 40);
				}
				core.setTextAlign("uievent", "left");
				core.fillText("uievent", "预计金额", 324, 250);
				core.setTextAlign("uievent", "right");
				totalMoney = selectCount * (type == 0 ? core.calValue(item.money) : core.calValue(item.sell));
				core.fillText("uievent", core.formatBigNumber(totalMoney), 405, 280);

				core.setTextAlign("uievent", "left");
				core.fillText("uievent", type == 0 ? "已购次数" : "已卖次数", 324, 170);
				core.setTextAlign("uievent", "right");
				core.fillText("uievent", (type == 0 ? item.money_count : item.sell_count) || 0, 405, 200);
			}
		}

		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.money / 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.money -= totalMoney;
			core.getItem(item.id, selectCount);
			if (item.number != null) item.number -= selectCount;
			item.money_count = (item.money_count || 0) + selectCount;
		} else {
			core.status.hero.money += totalMoney;
			core.removeItem(item.id, selectCount);
			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 >= 71 && py <= 102) {
			// 买
			if (type != 0) {
				type = 0;
				selectItem = null;
				selectCount = 0;
			}
			return;
		}
		if (px >= 122 && px <= 182 && py >= 71 && py <= 102) {
			// 卖
			if (type != 1) {
				type = 1;
				selectItem = null;
				selectCount = 0;
			}
			return;
		}
		if (px >= 222 && px <= 282 && py >= 71 && py <= 102) // 离开
			return core.insertAction({ "type": "break" });
		// < >
		if (px >= 318 && px <= 341 && py >= 348 && py <= 376)
			return _add(item, -1);
		if (px >= 388 && px <= 416 && py >= 348 && py <= 376)
			return _add(item, 1);
		// 确定
		if (px >= 341 && px <= 387 && py >= 380 && py <= 407)
			return _confirm(item);

		// 上一页/下一页
		if (px >= 45 && px <= 105 && py >= 388) {
			if (page > 1) {
				selectItem -= 6;
				selectCount = 0;
			}
			return;
		}
		if (px >= 208 && px <= 268 && py >= 388) {
			if (page < totalPage) {
				selectItem = Math.min(selectItem + 6, list.length - 1);
				selectCount = 0;
			}
			return;
		}

		// 实际区域
		if (px >= 9 && px <= 300 && py >= 120 && py < 360) {
			if (list.length == 0) return;
			var index = parseInt((py - 120) / 40);
			var newItem = 6 * (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;
		shopInfo = flags.__shops__[shopId];
		if (shopInfo.choices == null) shopInfo.choices = core.clone(core.status.shops[shopId].choices);
		choices = shopInfo.choices;

		core.insertAction([{
				"type": "while",
				"condition": "true",
				"data": [
					{ "type": "function", "function": "function () { core.drawItemShop(); }" },
					{ "type": "wait" },
					{ "type": "function", "function": "function() { core.performItemShopAction(); }" }
				]
			},
			{
				"type": "function",
				"function": "function () { core.deleteCanvas('uievent'); core.ui._clearUIEventSelector([1, 2]); }"
			}
		]);
	}

},
    "smoothCamera": function () {
	// 此插件开启后，大地图的瞬间移动将开启平滑镜头移动，避免突兀感
	// 插件作者：老黄鸡

	// 是否启用本插件，默认不启用
	this.__enableSmoothCamera = false;
	if (!this.__enableSmoothCamera) return;

	this.Camera = function () {

		// 下面这个变量决定本插件的开关
		// 你可以在游戏中使用core.setFlag('smoothCamera',false)来关闭本插件的功能
		// 同时也可以core.setFlag('smoothCamera',true)重新开启
		// 此项默认为true
		// 
		this.__switchName = 'smoothCamera';

		// 初始化成员变量
		this._cameraNeedRefresh = true;
		this._nowOffsetX = 0;
		this._nowOffsetY = 0;
		this._targetOffsetX = 0;
		this._targetOffsetY = 0;
		this._currentFloorId = null;

		// 重置镜头，在楼层变更时使用
		this.resetCamera = function () {
			this._targetOffsetX = core.bigmap.offsetX;
			this._targetOffsetY = core.bigmap.offsetY;
			this._nowOffsetX = this._targetOffsetX;
			this._nowOffsetY = this._targetOffsetY;
			this._cameraNeedRefresh = true;
		};

		// 设置焦点坐标，目前没有用
		this.setTarget = function (x, y) {
			this._targetOffsetX = x;
			this._targetOffsetY = y;
		};

		// 请求镜头更新
		this.requestCameraUpdate = function () {
			this._cameraNeedRefresh = true;
		};

		// 更新焦点坐标，目前仅根据大地图偏移决定
		this.updateTargetPosition = function () {
			this._targetOffsetX = core.bigmap.offsetX;
			this._targetOffsetY = core.bigmap.offsetY;
		};

		// 更新额外的刷新条件，即镜头未指向焦点时
		this.updateRefreshFlag = function () {
			if (this._nowOffsetX != this._targetOffsetX || this._nowOffsetY != this._targetOffsetY) {
				this._cameraNeedRefresh = true;
			}
		};

		// 判断是否禁止了弹性滚动
		this.canDirectMove = function () {
			return !core.getFlag(this.__switchName, true);
		};

		// 更新镜头坐标
		this.updateCameraPosition = function () {
			if (this._cameraNeedRefresh) {
				this._cameraNeedRefresh = false;
				var disX = this._targetOffsetX - this._nowOffsetX;
				var disY = this._targetOffsetY - this._nowOffsetY;
				if (Math.abs(disX) <= 2 && Math.abs(disY) <= 2 || this.canDirectMove()) {
					this._nowOffsetX = this._targetOffsetX;
					this._nowOffsetY = this._targetOffsetY;
				} else {
					this._nowOffsetX += disX / 10;
					this._nowOffsetY += disY / 10;
				}
				var x = -Math.floor(this._nowOffsetX);
				var y = -Math.floor(this._nowOffsetY);
				core.bigmap.canvas.forEach(function (cn) {
					core.control.setGameCanvasTranslate(cn, x, y);
				});
				core.relocateCanvas('route', core.status.automaticRoute.offsetX + x, core.status.automaticRoute.offsetY + y);
				core.setGameCanvasTranslate('hero', x + this._targetOffsetX, y + this._targetOffsetY);
			}
		};

		// 更新逻辑主体
		this.update = function () {
			this.updateTargetPosition();
			this.updateRefreshFlag();
			this.updateCameraPosition();
		};
	};

	// 创建摄像机对象
	this.camera = new this.Camera();

	// 帧事件 更新摄像机
	this.updateCameraEx = function () {
		this.camera.update();
	};

	core.control._drawHero_updateViewport = function () {
		core.control.updateViewport();
	}

	// 代理原本的镜头事件
	core.control.updateViewport = function () {
		core.plugin.camera.requestCameraUpdate();
	};

	// 更变楼层的行为追加，重置镜头
	core.events.changingFloor = function (floorId, heroLoc) {
		this.eventdata.changingFloor(floorId, heroLoc);
		core.plugin.camera.resetCamera();
	};

	// 注册帧事件
	core.registerAnimationFrame('smoothCameraFlash', true, this.updateCameraEx.bind(this));
},
    "skillBook": function () {
	// 技能一览面板：显示当前掌握的所有技能及其效果
	// 调用方式 core.drawSkillBook()，已绑定到 K 键（见 functions.js 的 onKeyUp）

	// 属性 -> 颜色（沿用 getSpecials 里的配色；Dark 补一个深褐）
	var TYPE_COLOR = {
		Normal: '#BBBBAA', Fire: '#FF4422', Water: '#77BBFF', Electric: '#FFCC33',
		Grass: '#77CC55', Ice: '#77DDFF', Fighting: '#BB5544', Poison: '#AA5599',
		Ground: '#DDBB55', Flying: '#6699FF', Psychic: '#FF5599', Bug: '#AABB22',
		Rock: '#BBAA66', Ghost: '#666688', Dragon: '#7766EE', Steel: '#AAAABB',
		Fairy: '#FFAAFF', Dark: '#775544'
	};
	// 属性 -> 中文
	var TYPE_CN = {
		Normal: '一般', Fire: '火', Water: '水', Electric: '电', Grass: '草', Ice: '冰',
		Fighting: '格斗', Poison: '毒', Ground: '地面', Flying: '飞行', Psychic: '超能',
		Bug: '虫', Rock: '岩石', Ghost: '幽灵', Dragon: '龙', Steel: '钢', Fairy: '妖精', Dark: '恶'
	};
	// 异常状态 -> 中文
	var COND_CN = { Paralysis: '麻痹', Poison: '中毒', Burn: '灼伤' };

	// 把 feature 翻译成一排标签
	var featureLabels = function (f) {
		var arr = [];
		var lv = function (n) { return (n > 0 ? '+' : '') + n + '级'; };
		var pct = function (n) { return Math.round(n * 100) + '%'; };
		if (f.isStatusMove) arr.push('变化技能');
		else if (f.factor != null) arr.push('威力×' + f.factor);
		if (f.enemyAtk) arr.push('敌攻' + lv(f.enemyAtk));
		if (f.enemyDef) arr.push('敌防' + lv(f.enemyDef));
		if (f.enemySpd) arr.push('敌速' + lv(f.enemySpd));
		if (f.selfAtk) arr.push('自攻' + lv(f.selfAtk));
		if (f.selfDef) arr.push('自防' + lv(f.selfDef));
		if (f.selfSpd) arr.push('自速' + lv(f.selfSpd));
		if (f.enemyStatusCond) arr.push(COND_CN[f.enemyStatusCond] || f.enemyStatusCond);
		if (f.enemyConfusion) arr.push('混乱');
		if (f.enemyFlinch) arr.push('畏缩');
		if (f.recover > 0) arr.push('吸血' + pct(f.recover));
		if (f.recover < 0) arr.push('自爆反伤');
		if (f.maxHPrecover) arr.push('回复' + pct(f.maxHPrecover) + 'HP');
		if (f.priority) arr.push('先制' + (f.priority > 0 ? '+' : '') + f.priority);
		return arr;
	};

	// ===== 面板状态：当前选中格 / 视图模式(grid|detail) / 四个技能槽 =====
	var sbSel = 0, sbMode = 'grid', sbSlots = [];

	// 取四个技能槽：constants 中以空格(已学)或!(空槽)开头的，恒为 4 个
	var getSkillSlots = function () {
		var c = core.status.hero.items.constants || {};
		return Object.keys(c).filter(function (id) {
			return id[0] == ' ' || id[0] == '!';
		}).sort().slice(0, 4);
	};

	// 画一个属性圆角标签，返回其宽度
	var drawTypeBadge = function (type, x, y) {
		if (!type) return 0;
		var label = TYPE_CN[type] || type;
		var font = core.ui._buildFont(16, true);
		var bw = core.calWidth('ui', label, font) + 24;
		core.fillRoundRect('ui', x, y, bw, 28, 8, TYPE_COLOR[type] || '#888888');
		core.setTextAlign('ui', 'center');
		core.fillText('ui', label, x + bw / 2, y + 20, '#FFFFFF', font);
		core.setTextAlign('ui', 'left');
		return bw;
	};

	// 上半部分：头像 + 名字/等级 + 属性标签
	// 形态 -> 立绘
	var HERO_FACE = { '水跃鱼': 'heroFace1.png', '沼跃鱼': 'heroFace2.png' };
	var drawHeroHeader = function (L) {
		var hero = core.status.hero;
		// 头像：优先用立绘(按形态)，适配方框保持比例；找不到则回退行走图朝下帧
		var box = { x: 22, y: 30, s: 128 };
		var face = core.material.images.images[HERO_FACE[hero.name]];
		if (face) {
			var sc = Math.min(box.s / face.width, box.s / face.height);
			var dw = face.width * sc, dh = face.height * sc;
			core.drawImage('ui', face, 0, 0, face.width, face.height,
				box.x + (box.s - dw) / 2, box.y + (box.s - dh) / 2, dw, dh);
		} else {
			var img = core.material.images.images[hero.image] || core.material.images.hero;
			if (img) { var fw = img.width / 4, fh = img.height / 4, scale = 2.2; core.drawImage('ui', img, 0, 0, fw, fh, 30, 40, fw * scale, fh * scale); }
		}
		var infoX = 162;
		core.setTextAlign('ui', 'left');
		core.fillText('ui', hero.name, infoX, 78, '#FFFFFF', core.ui._buildFont(24, true));
		var nameW = core.calWidth('ui', hero.name, core.ui._buildFont(24, true));
		// 等级与状态栏一致：用 getLvName()（返回 levelUp 的 title，如 "Lv.16"）
		core.fillText('ui', core.getLvName(), infoX + nameW + 16, 78, '#FFD700', core.ui._buildFont(20, true));
		var bx = infoX;
		bx += drawTypeBadge(hero.type1, bx, 100) + 12;
		drawTypeBadge(hero.type2, bx, 100);
		core.fillRect('ui', 20, 172, L - 40, 2, '#555555');   // 分隔线
	};

	// 下半部分：2×2 技能格
	var SB = { w: 168, h: 60, x0: 28, x1: 216, y0: 200, y1: 282 };
	var cellRect = function (i) {
		return { x: i % 2 == 0 ? SB.x0 : SB.x1, y: i < 2 ? SB.y0 : SB.y1, w: SB.w, h: SB.h };
	};
	var inRect = function (px, py, r) { return px >= r.x && px <= r.x + r.w && py >= r.y && py <= r.y + r.h; };
	var sbBtns = function () {
		var L = core.__PIXELS__;
		return { close: { x: L - 44, y: 10, w: 32, h: 32 }, chart: { x: L / 2 - 72, y: 360, w: 144, h: 32 } };
	};
	var drawSkillGrid = function () {
		for (var i = 0; i < 4; i++) {
			var id = sbSlots[i], r = cellRect(i), learned = id && id[0] == ' ';
			if (learned) {
				var item = core.material.items[id], f = item.feature || {};
				core.fillRoundRect('ui', r.x, r.y, r.w, r.h, 12, TYPE_COLOR[f.type] || '#777777');
				core.setTextAlign('ui', 'center');
				core.fillText('ui', item.name, r.x + r.w / 2, r.y + r.h / 2 + 7, '#FFFFFF', core.ui._buildFont(20, true));
			} else {
				core.setAlpha('ui', 0.4);
				core.fillRoundRect('ui', r.x, r.y, r.w, r.h, 12, '#444444');
				core.setAlpha('ui', 1);
				core.setTextAlign('ui', 'center');
				core.fillText('ui', '—', r.x + r.w / 2, r.y + r.h / 2 + 8, '#888888', core.ui._buildFont(22, true));
			}
			if (i == sbSel)
				core.strokeRoundRect('ui', r.x - 2, r.y - 2, r.w + 4, r.h + 4, 13, '#FFD700', 3);
		}
		var b = sbBtns();
		core.fillRoundRect('ui', b.close.x, b.close.y, b.close.w, b.close.h, 8, '#883333');   // 右上角关闭
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '✕', b.close.x + b.close.w / 2, b.close.y + 23, '#FFFFFF', core.ui._buildFont(18, true));
		core.fillRoundRect('ui', b.chart.x, b.chart.y, b.chart.w, b.chart.h, 8, '#3A5A8A');   // 相克表按钮
		core.fillText('ui', '属性相克表', b.chart.x + b.chart.w / 2, b.chart.y + 21, '#FFFFFF', core.ui._buildFont(15, true));
		core.fillText('ui', '点技能查看详情 · 方向键/Enter · X/K关闭', core.__PIXELS__ / 2, 404, '#999999', core.ui._buildFont(12));
		core.setTextAlign('ui', 'left');
	};

	// 技能详情视图
	var drawSkillDetail = function (L) {
		var item = core.material.items[sbSlots[sbSel]], f = item.feature || {};
		var color = TYPE_COLOR[f.type] || '#FFFFFF';
		core.setTextAlign('ui', 'left');
		core.fillText('ui', item.name, 28, 72, color, core.ui._buildFont(26, true));
		var nameW = core.calWidth('ui', item.name, core.ui._buildFont(26, true));
		drawTypeBadge(f.type, 28 + nameW + 18, 52);
		core.fillRect('ui', 20, 92, L - 40, 2, '#555555');
		var labels = featureLabels(f);
		core.fillText('ui', labels.length ? labels.join('    ｜    ') : '（无特殊效果）',
			28, 128, '#FFD86A', core.ui._buildFont(16, true));
		core.drawTextContent('ui', item.text || '（暂无描述）',
			{ left: 28, top: 150, maxWidth: L - 56, fontSize: 17, lineHeight: 26 });
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '按任意键返回', L / 2, L - 16, '#999999', core.ui._buildFont(14));
		core.setTextAlign('ui', 'left');
	};

	// 统一渲染
	var renderSkillBook = function () {
		var L = core.__PIXELS__;
		core.clearMap('ui');
		core.setAlpha('ui', 0.92);
		core.fillRect('ui', 0, 0, L, L, '#101018');
		core.setAlpha('ui', 1);
		if (sbMode == 'detail') drawSkillDetail(L);
		else { drawHeroHeader(L); drawSkillGrid(); }
	};

	this.drawSkillBook = function () {
		core.ui.closePanel();          // 关掉其它面板
		core.lockControl();
		core.status.event.id = 'skillBook';
		sbSlots = getSkillSlots();
		sbSel = 0; sbMode = 'grid';
		renderSkillBook();
	};

	// 方向键 / Enter / X（优先级 100，先于默认处理拦下按键）
	core.registerAction('keyUp', 'skillBook', function (keycode) {
		if (core.status.event.id != 'skillBook') return false;
		if (sbMode == 'detail') { sbMode = 'grid'; renderSkillBook(); return true; }
		var col = sbSel % 2, row = sbSel < 2 ? 0 : 1;
		if (keycode == 37) col = 0;            // ←
		else if (keycode == 39) col = 1;       // →
		else if (keycode == 38) row = 0;       // ↑
		else if (keycode == 40) row = 1;       // ↓
		else if (keycode == 13 || keycode == 67 || keycode == 32) {   // Enter/C/Space
			var id = sbSlots[sbSel];
			if (id && id[0] == ' ') { sbMode = 'detail'; renderSkillBook(); }
			return true;
		}
		else if (keycode == 27 || keycode == 88 || keycode == 75) { core.ui.closePanel(); return true; }   // ESC/X/K 关闭
		else return true;
		sbSel = row * 2 + col;
		renderSkillBook();
		return true;
	}, 100);
	core.registerAction('ondown', 'skillBook', function (x, y, px, py) {
		if (core.status.event.id != 'skillBook') return false;
		if (sbMode == 'detail') { sbMode = 'grid'; renderSkillBook(); return true; }   // 详情页点击=返回
		var b = sbBtns();
		if (inRect(px, py, b.close)) { core.ui.closePanel(); return true; }             // ✕ 关闭
		if (inRect(px, py, b.chart)) { core.drawTypeChart(); return true; }             // 打开相克表
		for (var i = 0; i < 4; i++) {                                                   // 点技能格
			if (inRect(px, py, cellRect(i))) {
				sbSel = i;
				if (sbSlots[i] && sbSlots[i][0] == ' ') sbMode = 'detail';
				renderSkillBook();
				return true;
			}
		}
		return true;
	}, 100);
},
    "typeChartPanel": function () {
	// I 键：全屏显示属性相克表（images/typechart.png）
	this.drawTypeChart = function () {
		core.ui.closePanel();
		core.lockControl();
		core.status.event.id = 'typeChart';
		var L = core.__PIXELS__;
		core.clearMap('ui');
		core.setAlpha('ui', 1);
		core.fillRect('ui', 0, 0, L, L, '#FFFFFF');
		var img = core.material.images.images['typechart.png'];
		if (img) {
			// 等比缩放铺满，顶部留白，底部留出提示行
			var sc = Math.min(L / img.width, (L - 26) / img.height);
			var dw = img.width * sc, dh = img.height * sc;
			core.drawImage('ui', img, 0, 0, img.width, img.height, (L - dw) / 2, 4, dw, dh);
		} else {
			core.fillText('ui', '未找到 typechart.png', 20, L / 2, '#000000', core.ui._buildFont(18, true));
		}
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '按任意键 / 点击关闭', L / 2, L - 8, '#888888', core.ui._buildFont(13));
		core.setTextAlign('ui', 'left');
	};
	// 任意键 / 点击关闭（优先级 100，先拦下按键）
	core.registerAction('keyUp', 'typeChart', function () {
		if (core.status.event.id != 'typeChart') return false;
		core.ui.closePanel();
		return true;
	}, 100);
	core.registerAction('ondown', 'typeChart', function () {
		if (core.status.event.id != 'typeChart') return false;
		core.ui.closePanel();
		return true;
	}, 100);
},
    "learnReplacePanel": function () {
	// 学满4技能后再学第5个时的「忘记哪个技能」自定义面板
	var TYPE_COLOR = {
		Normal: '#BBBBAA', Fire: '#FF4422', Water: '#77BBFF', Electric: '#FFCC33',
		Grass: '#77CC55', Ice: '#77DDFF', Fighting: '#BB5544', Poison: '#AA5599',
		Ground: '#DDBB55', Flying: '#6699FF', Psychic: '#FF5599', Bug: '#AABB22',
		Rock: '#BBAA66', Ghost: '#666688', Dragon: '#7766EE', Steel: '#AAAABB',
		Fairy: '#FFAAFF', Dark: '#775544'
	};
	var TYPE_CN = {
		Normal: '一般', Fire: '火', Water: '水', Electric: '电', Grass: '草', Ice: '冰',
		Fighting: '格斗', Poison: '毒', Ground: '地面', Flying: '飞行', Psychic: '超能',
		Bug: '虫', Rock: '岩石', Ghost: '幽灵', Dragon: '龙', Steel: '钢', Fairy: '妖精', Dark: '恶'
	};
	var featureLabels = function (f) {
		var a = [], lv = function (n) { return (n > 0 ? '+' : '') + n + '级'; }, pct = function (n) { return Math.round(n * 100) + '%'; };
		if (f.isStatusMove) a.push('变化技能'); else if (f.factor != null) a.push('威力×' + f.factor);
		if (f.enemyAtk) a.push('敌攻' + lv(f.enemyAtk));
		if (f.enemyDef) a.push('敌防' + lv(f.enemyDef));
		if (f.enemySpd) a.push('敌速' + lv(f.enemySpd));
		if (f.selfAtk) a.push('自攻' + lv(f.selfAtk));
		if (f.selfDef) a.push('自防' + lv(f.selfDef));
		if (f.selfSpd) a.push('自速' + lv(f.selfSpd));
		if (f.enemyStatusCond) a.push({ Paralysis: '麻痹', Poison: '中毒', Burn: '灼伤' }[f.enemyStatusCond] || f.enemyStatusCond);
		if (f.enemyConfusion) a.push('混乱');
		if (f.enemyFlinch) a.push('畏缩');
		if (f.recover > 0) a.push('吸血' + pct(f.recover));
		if (f.recover < 0) a.push('自爆反伤');
		if (f.maxHPrecover) a.push('回复' + pct(f.maxHPrecover) + 'HP');
		if (f.priority) a.push('先制' + (f.priority > 0 ? '+' : '') + f.priority);
		return a;
	};
	var tag = function (type) { return '[' + (TYPE_CN[type] || '?') + '] '; };

	var active = false, newId = null, oldIds = [], sel = 0;

	// 布局几何（render 与 ondown 命中检测共用，保证一致）
	var GEOM = function () {
		var L = core.__PIXELS__;
		return {
			L: L, gw: L / 2 - 44, gh: 48, gx0: 40, gx1: L / 2 + 4, gy0: 152, gy1: 208,
			btnForget: { x: 36, y: 366, w: L / 2 - 46, h: 32 },
			btnCancel: { x: L / 2 + 10, y: 366, w: L / 2 - 46, h: 32 }
		};
	};
	var cardRect = function (g, i) { return { x: i % 2 == 0 ? g.gx0 : g.gx1, y: i < 2 ? g.gy0 : g.gy1, w: g.gw, h: g.gh }; };
	var inRect = function (px, py, r) { return px >= r.x && px <= r.x + r.w && py >= r.y && py <= r.y + r.h; };

	var render = function () {
		var g = GEOM(), L = g.L, bf = core.ui._buildFont;
		core.clearMap('ui');
		core.setAlpha('ui', 0.92); core.fillRect('ui', 0, 0, L, L, '#101018'); core.setAlpha('ui', 1);
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '技能已满 (4/4)', L / 2, 32, '#FFD700', bf(20, true));
		// 新技能卡片
		var nItem = core.material.items[newId], nf = nItem.feature || {};
		core.fillRoundRect('ui', 40, 48, L - 80, 42, 10, TYPE_COLOR[nf.type] || '#777777');
		core.setTextAlign('ui', 'left');
		core.fillText('ui', '学习  ' + tag(nf.type) + nItem.name, 52, 75, '#FFFFFF', bf(18, true));
		var nlab = featureLabels(nf);
		core.fillText('ui', nlab.length ? nlab.join('  ｜  ') : '无特殊效果', 52, 108, '#BBBBBB', bf(13));
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '选一个技能忘掉（点击卡片 / 方向键）：', L / 2, 138, '#DDDDDD', bf(14));
		// 2×2 当前技能
		for (var i = 0; i < oldIds.length; i++) {
			var r = cardRect(g, i);
			var it = core.material.items[oldIds[i]], f = it.feature || {};
			core.fillRoundRect('ui', r.x, r.y, r.w, r.h, 10, TYPE_COLOR[f.type] || '#777777');
			core.setTextAlign('ui', 'center');
			core.fillText('ui', tag(f.type) + it.name, r.x + r.w / 2, r.y + r.h / 2 + 6, '#FFFFFF', bf(16, true));
			if (i == sel) core.strokeRoundRect('ui', r.x - 2, r.y - 2, r.w + 4, r.h + 4, 11, '#FFD700', 3);
		}
		// 选中旧技能 vs 新技能 对比
		var sItem = core.material.items[oldIds[sel]], sf = sItem.feature || {};
		core.fillRect('ui', 30, 270, L - 60, 2, '#555555');
		core.setTextAlign('ui', 'left');
		core.fillText('ui', '忘掉  ' + tag(sf.type) + sItem.name, 32, 296, TYPE_COLOR[sf.type] || '#FFFFFF', bf(15, true));
		var slab = featureLabels(sf);
		core.fillText('ui', slab.length ? slab.join('  ｜  ') : '无特殊效果', 32, 318, '#BBBBBB', bf(12));
		core.fillText('ui', '换成  ' + tag(nf.type) + nItem.name, 32, 342, TYPE_COLOR[nf.type] || '#FFFFFF', bf(15, true));
		// 底部两个按钮（手机点击 / 也响应键盘 Enter·X）
		core.fillRoundRect('ui', g.btnForget.x, g.btnForget.y, g.btnForget.w, g.btnForget.h, 8, '#3A7D44');
		core.fillRoundRect('ui', g.btnCancel.x, g.btnCancel.y, g.btnCancel.w, g.btnCancel.h, 8, '#8A3A3A');
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '✓ 忘掉并学会', g.btnForget.x + g.btnForget.w / 2, g.btnForget.y + 21, '#FFFFFF', bf(15, true));
		core.fillText('ui', '✗ 放弃学习', g.btnCancel.x + g.btnCancel.w / 2, g.btnCancel.y + 21, '#FFFFFF', bf(15, true));
		core.setTextAlign('ui', 'left');
	};

	this.startLearnReplace = function (nid) {
		newId = nid;
		oldIds = Object.keys(core.status.hero.items.constants).filter(function (id) { return id[0] == ' ' && id != nid; });
		sel = 0;
		// 录像回放：从记录里直接读出当时的决策并自动执行，不等待按键（仿引擎 choices 事件）
		if (core.isReplaying()) {
			var action = core.status.replay.toReplay.shift();
			if (action == 'turn') action = core.status.replay.toReplay.shift();   // 忽略可能夹入的转向
			var deleteId;
			if (typeof action == 'string' && action.indexOf('learnSkill:') == 0) {
				var v = action.substring(11);
				if (v == 'cancel') deleteId = nid;
				else { var k = parseInt(v); sel = (k >= 0 && k < oldIds.length) ? k : 0; deleteId = oldIds[sel]; }
			} else { core.control._replay_error(action); return; }
			render();   // 回放时也画出面板便于观看
			setTimeout(function () {
				core.status.route.push(action);
				active = false;
				delete core.status.hero.items.constants[deleteId];
				core.updateStatusBar();
				core.doAction();
			}, core.status.replay.speed == 24 ? 1 : 750 / Math.max(1, core.status.replay.speed));
			return;
		}
		active = true;
		core.lockControl();
		render();
	};

	// record：写入 route 的决策串（'learnSkill:N' 忘第 N 个 / 'learnSkill:cancel' 放弃），供录像回放
	var resolve = function (deleteId, record) {
		active = false;
		core.status.route.push(record);
		delete core.status.hero.items.constants[deleteId];
		core.updateStatusBar();
		core.doAction();   // 清掉面板UI并恢复(结束)异步事件流
	};

	core.registerAction('keyUp', 'learnReplace', function (keycode) {
		if (!active) return false;
		var col = sel % 2, row = sel < 2 ? 0 : 1;
		if (keycode == 37) col = 0;
		else if (keycode == 39) col = 1;
		else if (keycode == 38) row = 0;
		else if (keycode == 40) row = 1;
		else if (keycode == 13 || keycode == 67 || keycode == 32) { resolve(oldIds[sel], 'learnSkill:' + sel); return true; }   // 忘掉所选、学会新技能
		else if (keycode == 27 || keycode == 88) { resolve(newId, 'learnSkill:cancel'); return true; }                          // 放弃学习
		else return true;
		var ns = row * 2 + col;
		if (ns < oldIds.length) sel = ns;
		render();
		return true;
	}, 100);
	core.registerAction('ondown', 'learnReplace', function (x, y, px, py) {
		if (!active) return false;
		var g = GEOM();
		for (var i = 0; i < oldIds.length; i++) {
			if (inRect(px, py, cardRect(g, i))) { sel = i; render(); return true; }   // 点卡片=选中
		}
		if (inRect(px, py, g.btnForget)) { resolve(oldIds[sel], 'learnSkill:' + sel); return true; }   // 忘掉并学会
		if (inRect(px, py, g.btnCancel)) { resolve(newId, 'learnSkill:cancel'); return true; }          // 放弃学习
		return true;   // 吃掉面板内其它点击
	}, 100);
},
    "debugMinDamage": function () {
	// =================== 调试工具（正式版删除整块即可） ===================
	// 功能：按 M 键，弹出当前楼层每种怪物在「所有技能两两组合」下的最低伤害及对应组合。
	// 移除方式：把本 "debugMinDamage" 整个插件块删掉；或将下面 ENABLE 改为 false。
	var ENABLE = false;   // ← 改回 true 即可恢复 M 键调试工具
	if (!ENABLE) return;

	// 滚动面板状态
	var lines = [];
	var scroll = 0;
	var PAGE = 18; // 每屏行数

	// 计算单只怪在所有技能两两组合下的最低伤害
	this.calcMinDamage = function (enemyId) {
		var enemy = core.material.enemys[enemyId];
		if (!enemy || !enemy.skill1) return null;
		var skills = Object.keys(core.status.hero.items.constants)
			.filter(function (id) { return id[0] == ' '; });
		if (skills.length == 0) return null;
		var s1 = core.getFlag('skill1', 0), s2 = core.getFlag('skill2', 0);
		var best = null, combo = null;
		skills.forEach(function (a) {
			skills.forEach(function (b) {
				core.setFlag('skill1', a);
				core.setFlag('skill2', b);
				var info = null;
				try { info = core.enemys.getDamageInfo(enemy, null, null, null, core.status.floorId); } catch (e) { info = null; }
				var d = (info == null) ? null : info.damage;
				if (d != null && (best == null || d < best)) { best = d; combo = [a, b]; }
			});
		});
		core.setFlag('skill1', s1);
		core.setFlag('skill2', s2);
		return (best == null) ? null : { damage: best, combo: combo };
	};

	// 绘制可滚动面板
	var drawPanel = function () {
		var L = core.__PIXELS__;
		core.clearMap('ui');
		core.fillRect('ui', 0, 0, L, L, '#000000');
		core.setTextAlign('ui', 'left');
		var total = lines.length, headTo = Math.min(scroll + PAGE, total);
		core.fillText('ui', '【调试】各怪最低伤害  (' + (total == 0 ? 0 : scroll + 1) + '-' + headTo + '/' + total + ')',
			12, 24, '#FFD700', core.ui._buildFont(15, true));
		var y = 48;
		for (var i = scroll; i < headTo; i++) {
			core.fillText('ui', lines[i], 12, y, '#DDDDDD', core.ui._buildFont(13, false));
			y += 19;
		}
		core.setTextAlign('ui', 'center');
		core.fillText('ui', '↑↓ 翻页　其它键/点击关闭　完整内容见 F12 控制台', L / 2, L - 10, '#999999', core.ui._buildFont(12));
	};

	// 汇总当前楼层所有（有招式的）怪物并弹出滚动面板
	var showMinDamage = function () {
		var seen = {}, order = [];
		(core.status.thisMap.blocks || []).forEach(function (b) {
			if (b.disable) return;
			if ((b.event.cls || '').indexOf('enemy') != 0) return;
			var enemy = core.material.enemys[b.event.id];
			if (!enemy || !enemy.skill1) return; // 跳过无招式的占位怪
			if (!seen[b.event.id]) { seen[b.event.id] = true; order.push(b.event.id); }
		});
		lines = [];
		order.forEach(function (id) {
			var enemy = core.material.enemys[id];
			var r = core.calcMinDamage(id);
			if (r == null) {
				lines.push(enemy.name + '：无法战斗');
			} else {
				lines.push(enemy.name + '：最低 ' + core.formatBigNumber(r.damage)
					+ '（' + core.material.items[r.combo[0]].name
					+ ' + ' + core.material.items[r.combo[1]].name + '）');
			}
		});
		if (lines.length == 0) lines.push('当前楼层没有可计算的怪物。');
		console.log('【调试】各怪最低伤害（遍历所有技能组合）\n' + lines.join('\n'));
		scroll = 0;
		core.lockControl();
		core.status.event.id = 'debugMinDamage';
		drawPanel();
	};
	this.showMinDamage = showMinDamage;

	// 绑定 M 键(77)；面板打开时 ↑↓ 翻页、其它键/点击关闭。删除本块即一并移除该快捷键
	core.registerAction('keyUp', 'debugMinDamage', function (keycode) {
		if (core.status.event.id == 'debugMinDamage') {
			if (keycode == 38) { scroll = Math.max(0, scroll - PAGE); drawPanel(); return true; }
			if (keycode == 40) { scroll = Math.min(Math.max(0, lines.length - PAGE), scroll + PAGE); drawPanel(); return true; }
			core.ui.closePanel();
			return true;
		}
		if (keycode != 77) return false;
		if (core.status.lockControl || core.isMoving() || !core.isPlaying()) return false;
		showMinDamage();
		return true;
	}, 80);
	core.registerAction('ondown', 'debugMinDamage', function () {
		if (core.status.event.id != 'debugMinDamage') return false;
		core.ui.closePanel();
		return true;
	}, 80);
}
}