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

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

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


	this._afterLoadResources = function () {
		// 本函数将在所有资源加载完毕后，游戏开启前被执行
		// 可以在这个函数里面对资源进行一些操作。
		// 若需要进行切分图片，可以使用 core.splitImage() 函数，或直接在全塔属性-图片切分中操作
	}

	// 可以在任何地方（如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.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);
},
    "removeMap": function () {
	// 高层塔砍层插件，删除后不会存入存档，不可浏览地图也不可飞到。
	// 推荐用法：
	// 对于超高层或分区域塔，当在1区时将2区以后的地图删除；1区结束时恢复2区，进二区时删除1区地图，以此类推
	// 这样可以大幅减少存档空间，以及加快存读档速度

	// 删除楼层
	// core.removeMaps("MT1", "MT300") 删除MT1~MT300之间的全部层
	// core.removeMaps("MT10") 只删除MT10层
	this.removeMaps = function (fromId, toId) {
		toId = toId || fromId;
		var fromIndex = core.floorIds.indexOf(fromId),
			toIndex = core.floorIds.indexOf(toId);
		if (toIndex < 0) toIndex = core.floorIds.length - 1;
		flags.__visited__ = flags.__visited__ || {};
		flags.__removed__ = flags.__removed__ || [];
		flags.__disabled__ = flags.__disabled__ || {};
		flags.__leaveLoc__ = flags.__leaveLoc__ || {};
		for (var i = fromIndex; i <= toIndex; ++i) {
			var floorId = core.floorIds[i];
			if (core.status.maps[floorId].deleted) continue;
			delete flags.__visited__[floorId];
			flags.__removed__.push(floorId);
			delete flags.__disabled__[floorId];
			delete flags.__leaveLoc__[floorId];
			(core.status.autoEvents || []).forEach(function (event) {
				if (event.floorId == floorId && event.currentFloor) {
					core.autoEventExecuting(event.symbol, false);
					core.autoEventExecuted(event.symbol, false);
				} 
			});
			core.status.maps[floorId].deleted = true;
			core.status.maps[floorId].canFlyTo = false;
			core.status.maps[floorId].canFlyFrom = false;
			core.status.maps[floorId].cannotViewMap = true;
		}
	}

	// 恢复楼层
	// core.resumeMaps("MT1", "MT300") 恢复MT1~MT300之间的全部层
	// core.resumeMaps("MT10") 只恢复MT10层
	this.resumeMaps = function (fromId, toId) {
		toId = toId || fromId;
		var fromIndex = core.floorIds.indexOf(fromId),
			toIndex = core.floorIds.indexOf(toId);
		if (toIndex < 0) toIndex = core.floorIds.length - 1;
		flags.__removed__ = flags.__removed__ || [];
		for (var i = fromIndex; i <= toIndex; ++i) {
			var floorId = core.floorIds[i];
			if (!core.status.maps[floorId].deleted) continue;
			flags.__removed__ = flags.__removed__.filter(function (f) { return f != floorId; });
			core.status.maps[floorId] = core.loadFloor(floorId);
		}
	}

	// 分区砍层相关
	var inAnyPartition = function (floorId) {
		var inPartition = false;
		(core.floorPartitions || []).forEach(function (floor) {
			var fromIndex = core.floorIds.indexOf(floor[0]);
			var toIndex = core.floorIds.indexOf(floor[1]);
			var index = core.floorIds.indexOf(floorId);
			if (fromIndex < 0 || index < 0) return;
			if (toIndex < 0) toIndex = core.floorIds.length - 1;
			if (index >= fromIndex && index <= toIndex) inPartition = true;
		});
		return inPartition;
	}

	// 分区砍层
	this.autoRemoveMaps = function (floorId) {
		if (main.mode != 'play' || !inAnyPartition(floorId)) return;
		// 根据分区信息自动砍层与恢复
		(core.floorPartitions || []).forEach(function (floor) {
			var fromIndex = core.floorIds.indexOf(floor[0]);
			var toIndex = core.floorIds.indexOf(floor[1]);
			var index = core.floorIds.indexOf(floorId);
			if (fromIndex < 0 || index < 0) return;
			if (toIndex < 0) toIndex = core.floorIds.length - 1;
			if (index >= fromIndex && index <= toIndex) {
				core.resumeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]);
			} else {
				core.removeMaps(core.floorIds[fromIndex], core.floorIds[toIndex]);
			}
		});
	}
},
    "fiveLayers": function () {
	// 是否启用五图层（增加背景2层和前景2层） 将__enable置为true即会启用；启用后请保存后刷新编辑器
	// 背景层2将会覆盖背景层 被事件层覆盖 前景层2将会覆盖前景层
	// 另外 请注意加入两个新图层 会让大地图的性能降低一些
	// 插件作者：ad
	var __enable = true;
	if (!__enable) return;

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

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

	if (main.mode == 'editor') {
		/*插入编辑器的图层 不做此步新增图层无法在编辑器显示*/
		// 编辑器图层覆盖优先级 eui > efg > fg(前景层) > event2(48*32图块的事件层) > event(事件层) > bg(背景层)
		// 背景层2(bg2) 插入事件层(event)之前(即bg与event之间)
		document.getElementById('mapEdit').insertBefore(bg2Canvas, document.getElementById('event'));
		// 前景层2(fg2) 插入编辑器前景(efg)之前(即fg之后)
		document.getElementById('mapEdit').insertBefore(fg2Canvas, document.getElementById('ebm'));
		// 原本有三个图层 从4开始添加
		var num = 4;
		// 新增图层存入editor.dom中
		editor.dom.bg2c = core.canvas.bg2.canvas;
		editor.dom.bg2Ctx = core.canvas.bg2;
		editor.dom.fg2c = core.canvas.fg2.canvas;
		editor.dom.fg2Ctx = core.canvas.fg2;
		editor.dom.maps.push('bg2map', 'fg2map');
		editor.dom.canvas.push('bg2', 'fg2');

		// 创建编辑器上的按钮
		var createCanvasBtn = function (name) {
			// 电脑端创建按钮
			var input = document.createElement('input');
			// layerMod4/layerMod5
			var id = 'layerMod' + num++;
			// bg2map/fg2map
			var value = name + 'map';
			input.type = 'radio';
			input.name = 'layerMod';
			input.id = id;
			input.value = value;
			editor.dom[id] = input;
			input.onchange = function () {
				editor.uifunctions.setLayerMod(value);
			}
			return input;
		};

		var createCanvasBtn_mobile = function (name) {
			// 手机端往选择列表中添加子选项
			var input = document.createElement('option');
			var id = 'layerMod' + num++;
			var value = name + 'map';
			input.name = 'layerMod';
			input.value = value;
			editor.dom[id] = input;
			return input;
		};
		if (!editor.isMobile) {
			var input = createCanvasBtn('bg2');
			var input2 = createCanvasBtn('fg2');
			// 获取事件层及其父节点
			var child = document.getElementById('layerMod'),
				parent = child.parentNode;
			// 背景层2插入事件层前
			parent.insertBefore(input, child);
			// 不能直接更改背景层2的innerText 所以创建文本节点
			var txt = document.createTextNode('bg2');
			// 插入事件层前(即新插入的背景层2前)
			parent.insertBefore(txt, child);
			// 向最后插入前景层2(即插入前景层后)
			parent.appendChild(input2);
			var txt2 = document.createTextNode('fg2');
			parent.appendChild(txt2);
			parent.childNodes[2].replaceWith("bg");
			parent.childNodes[6].replaceWith("事件");
			parent.childNodes[8].replaceWith("fg");
		} else {
			var input = createCanvasBtn_mobile('bg2');
			var input2 = createCanvasBtn_mobile('fg2');
			// 手机端因为是选项 所以可以直接改innerText
			input.innerText = '背景层2';
			input2.innerText = '前景层2';
			var parent = document.getElementById('layerMod');
			parent.insertBefore(input, parent.children[1]);
			parent.appendChild(input2);
		}
	}

	var _loadFloor_doNotCopy = core.maps._loadFloor_doNotCopy;
	core.maps._loadFloor_doNotCopy = function () {
		return ["bg2map", "fg2map"].concat(_loadFloor_doNotCopy());
	}
	////// 绘制背景和前景层 //////
	core.maps._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
		config.ctx = cacheCtx;
		core.maps._drawBg_drawBackground(floorId, config);
		// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块；后绘制的覆盖先绘制的。
		core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap);
		core.maps._drawBgFgMap(floorId, 'bg', config);
		if (config.onMap) {
			core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
			core.clearMap('bg2');
			core.clearMap(cacheCtx);
		}
		core.maps._drawBgFgMap(floorId, 'bg2', config);
		if (config.onMap) core.drawImage('bg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
		config.ctx = toDrawCtx;
	}
	core.maps._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
		config.ctx = cacheCtx;
		// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块；后绘制的覆盖先绘制的。
		core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap);
		core.maps._drawBgFgMap(floorId, 'fg', config);
		if (config.onMap) {
			core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
			core.clearMap('fg2');
			core.clearMap(cacheCtx);
		}
		core.maps._drawBgFgMap(floorId, 'fg2', config);
		if (config.onMap) core.drawImage('fg2', cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
		config.ctx = toDrawCtx;
	}
	////// 移动判定 //////
	core.maps._generateMovableArray_arrays = function (floorId) {
		return {
			bgArray: this.getBgMapArray(floorId),
			fgArray: this.getFgMapArray(floorId),
			eventArray: this.getMapArray(floorId),
			bg2Array: this._getBgFgMapArray('bg2', floorId),
			fg2Array: this._getBgFgMapArray('fg2', floorId)
		};
	}
},
    "itemShop": function () {
	// 道具商店相关的插件
	// 可在全塔属性-全局商店中使用「道具商店」事件块进行编辑（如果找不到可以在入口方块中找）

	var shopId = null; // 当前商店ID
	var type = 0; // 当前正在选中的类型，0买入1卖出
	var selectItem = 0; // 当前正在选中的道具
	var selectCount = 0; // 当前已经选中的数量
	var page = 0;
	var totalPage = 0;
	var totalMoney = 0;
	var list = [];
	var shopInfo = null; // 商店信息
	var choices = []; // 商店选项
	var use = 'money';
	var useText = '金币';

	var bigFont = core.ui._buildFont(20, false),
		middleFont = core.ui._buildFont(18, false);

	this._drawItemShop = function () {
		// 绘制道具商店

		// Step 1: 背景和固定的几个文字
		core.ui._createUIEvent();
		core.clearMap('uievent');
		core.ui.clearUIEventSelector();
		core.setTextAlign('uievent', 'left');
		core.setTextBaseline('uievent', 'top');
		core.fillRect('uievent', 0, 0, 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", "当前" + useText, 324, 66, null, middleFont);
		core.setTextAlign("uievent", "right");
		core.fillText("uievent", core.formatBigNumber(core.status.hero[use]), 405, 89);
		core.setTextAlign("uievent", "left");
		core.ui.drawUIEventSelector(1, "winskin.png", 22 + 100 * type, 66, 60, 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)) + useText + "/个", 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.drawUIEventSelector(2, "winskin.png", 8, 120 + i * 40, 295, 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", "预计" + useText, 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[use] / core.calValue(item.money)) : core.itemCount(item.id),
				type == 0 && item.number != null ? item.number : Number.MAX_SAFE_INTEGER)
		);
	}

	var _confirm = function (item) {
		if (item == null || selectCount == 0) return;
		if (type == 0) {
			core.status.hero[use] -= totalMoney;
			core.getItem(item.id, selectCount);
			core.stopSound();
			core.playSound('确定');
			if (item.number != null) item.number -= selectCount;
			item.money_count = (item.money_count || 0) + selectCount;
		} else {
			core.status.hero[use] += totalMoney;
			core.removeItem(item.id, selectCount);
			core.playSound('确定');
			core.drawTip("成功卖出" + selectCount + "个" + core.material.items[item.id].name, item.id);
			if (item.number != null) item.number += selectCount;
			item.sell_count = (item.sell_count || 0) + selectCount;
		}
		selectCount = 0;
	}

	this._performItemShopKeyBoard = function (keycode) {
		var item = list[selectItem] || null;
		// 键盘操作
		switch (keycode) {
		case 38: // up
			if (selectItem == null) break;
			if (selectItem == 0) selectItem = null;
			else selectItem--;
			selectCount = 0;
			break;
		case 37: // left
			if (selectItem == null) {
				if (type > 0) type--;
				break;
			}
			_add(item, -1);
			break;
		case 39: // right
			if (selectItem == null) {
				if (type < 2) type++;
				break;
			}
			_add(item, 1);
			break;
		case 40: // down
			if (selectItem == null) {
				if (list.length > 0) selectItem = 0;
				break;
			}
			if (list.length == 0) break;
			selectItem = Math.min(selectItem + 1, list.length - 1);
			selectCount = 0;
			break;
		case 13:
		case 32: // Enter/Space
			if (selectItem == null) {
				if (type == 2)
					core.insertAction({ "type": "break" });
				else if (list.length > 0)
					selectItem = 0;
				break;
			}
			_confirm(item);
			break;
		case 27: // ESC
			if (selectItem == null) {
				core.insertAction({ "type": "break" });
				break;
			}
			selectItem = null;
			break;
		}
	}

	this._performItemShopClick = function (px, py) {
		var item = list[selectItem] || null;
		// 鼠标操作
		if (px >= 22 && px <= 82 && py >= 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;
		core.isShopVisited(itemShopId);
		shopInfo = flags.__shops__[shopId];
		if (shopInfo.choices == null) shopInfo.choices = core.clone(core.status.shops[shopId].choices);
		choices = shopInfo.choices;
		use = core.status.shops[shopId].use;
		if (use != 'exp') use = 'money';
		useText = use == 'money' ? '金币' : '经验';

		core.insertAction([{
				"type": "while",
				"condition": "true",
				"data": [
					{ "type": "function", "function": "function () { core.plugin._drawItemShop(); }" },
					{ "type": "wait" },
					{ "type": "function", "function": "function() { core.plugin._performItemShopAction(); }" }
				]
			},
			{
				"type": "function",
				"function": "function () { core.deleteCanvas('uievent'); core.ui.clearUIEventSelector(); }"
			}
		]);
	}

},
    "enemyLevel": function () {
	// 此插件将提供怪物手册中的怪物境界显示
	// 使用此插件需要先给每个怪物定义境界，方法如下：
	// 点击怪物的【配置表格】，找到“【怪物】相关的表格配置”，然后在【名称】仿照增加境界定义：
	/*
	 "level": {
	 	"_leaf": true,
	 	"_type": "textarea",
	 	"_string": true,
	 	"_data": "境界"
	 },
	 */
	// 然后保存刷新，可以看到怪物的属性定义中出现了【境界】。再开启本插件即可。

	// 是否开启本插件，默认禁用；将此改成 true 将启用本插件。
	var __enable = true;
	if (!__enable) return;

	// 这里定义每个境界的显示颜色；可以写'red', '#RRGGBB' 或者[r,g,b,a]四元数组
	var levelToColors = {
		"宗师初成": "#0080FF",
		"宗师中成": "#0080FF",
		"宗师大成": "#0080FF",
		"宗师圆满": "#0080FF",
		"肉身成圣": "#F9F900",
		"意志化圣": "#F9F900",
		"初始圣者": "#F9F900",
		"天地圣者": "#F9F900",
		"虚空圣者": "#F9F900",
		"混沌圣者": "#F9F900",
		"伪尊皇": "#FF8000",
		"尊皇初成": "#FF8000",
		"尊皇中成": "#FF8000",
		"尊皇大成": "#FF8000",
		"尊皇巅峰": "#FF8000",
		"伪仙下位": "#AE00AE",
		"伪仙中位": "#AE00AE",
		"伪仙上位": "#AE00AE",
		"伪仙巅峰": "#AE00AE",
		"真仙下位": "#AE00AE",
		"真仙中位": "#AE00AE",
		"真仙上位": "#AE00AE",
		"真仙巅峰": "#AE00AE",
		"仙尊下位": "#FF5809",
		"仙尊中位": "#FF5809",
		"仙尊上位": "#FF5809",
		"仙尊巅峰": "#FF5809",
		"仙王下位": "#FF5809",
		"仙王中位": "#FF5809",
		"仙王上位": "#FF5809",
		"仙王巅峰": "#FF5809",
		"准帝": "#FF5809",
		"铸体之阶": "#DF013A",
		"蕴神之阶": "#DF013A",
		"破虚之阶": "#DF013A",
		"融道之阶": "#DF013A",
		"永生之阶": "#DF013A",
		"开天之阶": "#DF013A",
		"创生之阶": "#DF013A",
		"超越之阶": "#DF013A",
		"至尊之阶": "#DF013A",
		"初始仙帝": "gold",
		"镇界仙帝": "gold",
		"极道仙帝": "gold", //堪比概念之主战力，最强的勉强能碰一碰伪概念神明
		"概念之主": "gold",
		"伪概念神明": "gold",
		"概念神明": "gold",

		//新体系
		"现实扭曲Ⅱ": "#0080FF",
		"现实扭曲Ⅲ": "#F9F900",
		"现实扭曲Ⅳ": "#FF8000",
		"规则掌控Ⅰ": "#AE00AE",
		"规则掌控Ⅱ": "#AE00AE",
		"规则掌控Ⅲ": "#FF5809",
		"规则掌控Ⅳ": "#FF5809",
		"规则掌控Ⅴ": "#FF5809",
		"概念抹除Ⅰ": "gold",
		"概念抹除Ⅱ": "gold",
		"概念抹除Ⅲ": "gold",

		//阶位
		"精英": "#0080FF",
		"领主": "#AE00AE",
		"封王": "#FF5809",
		"绝巅": "#FF8000",
		"帝储": "gold",
		"仙王战将": "gold",

		//仙界版阶位，细化
		//凡阶-地阶是凡俗，但是伪仙以上至少地阶Ⅰ，修行者基本都地阶Ⅱ起步
		"天阶Ⅰ": "#0080FF",
		"天阶Ⅱ": "#0080FF",
		"天阶Ⅲ": "#0080FF", //大致对应精英
		"圣阶Ⅰ": "#AE00AE",
		"圣阶Ⅱ": "#AE00AE",
		"圣阶Ⅲ": "#AE00AE", //领主
		//后续封王绝巅都一样

		//混沌虚空
		"混沌生物": "gray",
		"虚空行者": "gray",

		//登迪9
		"人尊境": "#DF013A",
		"地尊境": "#DF013A",
		"天尊境": "#DF013A",
		"圣尊境": "#DF013A",
		"无上极境": "#DF013A",

		//神道体系
		"虚空神初成": "#DF013A",
		"虚空神中成": "#DF013A",
		"虚空神大成": "#DF013A",
		"虚空神圆满": "#DF013A",
		"半步世界神": "#DF013A",
		"世界神初成": "#DF013A",
		"世界神中成": "#DF013A",
		"世界神大成": "#DF013A",
		"世界神圆满": "#DF013A", //登迪1-9
		"神王一重": "#DF013A",
		"神王二重": "#DF013A",
		"神王三重": "#DF013A",
		"神王四重": "#DF013A",
		"神王五重": "#DF013A", //登迪9细分
		"半步神帝": "gold",
		"诸天神帝": "gold",
		"永恒神帝": "gold",


		//仙帝
		"混沌巨头": "gold", //初始仙帝
		"圣地之主": "gold", //镇界仙帝
		"源界帝王": "gold", //概念之主
		"上古神灵": "gold", //伪概念神明
		"混沌主宰": "gold", //极道仙帝
		"全知全能": "gold", //概念神明
	};

	// 复写 _drawBook_drawName
	var originDrawBook = core.ui._drawBook_drawName;
	core.ui._drawBook_drawName = function (index, enemy, top, left, width) {
		// 如果没有境界，则直接调用原始代码绘制
		if (!enemy.level) return originDrawBook.call(core.ui, index, enemy, top, left, width);
		// 存在境界，则额外进行绘制
		core.setTextAlign('ui', 'center');
		if (enemy.specialText.length == 0) {
			core.fillText('ui', enemy.name, left + width / 2,
				top + 20, '#DDDDDD', this._buildFont(17, true));
			core.fillText('ui', enemy.level, left + width / 2,
				top + 40, core.arrayToRGBA(levelToColors[enemy.level] || '#DDDDDD'), this._buildFont(14, true));
			core.fillText('ui', enemy.jiewei, left + width / 2,
				top + 55, core.arrayToRGBA(levelToColors[enemy.jiewei] || '#DDDDDD'), this._buildFont(12, true));
		} else {
			core.fillText('ui', enemy.name, left + width / 2,
				top + 18, '#DDDDDD', this._buildFont(15, true), width);
			switch (enemy.specialText.length) {
			case 1:
				core.fillText('ui', enemy.specialText[0], left + width / 2,
					top + 33, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A'),
					this._buildFont(12, true), width);
				break;
			case 2:
				// Step 1: 计算字体
				var text = enemy.specialText[0] + "  " + enemy.specialText[1];
				core.setFontForMaxWidth('ui', text, width, this._buildFont(12, true));
				// Step 2: 计算总宽度
				var totalWidth = core.calWidth('ui', text);
				var leftWidth = core.calWidth('ui', enemy.specialText[0]);
				var rightWidth = core.calWidth('ui', enemy.specialText[1]);
				// Step 3: 绘制
				core.fillText('ui', enemy.specialText[0], left + (width + leftWidth - totalWidth) / 2,
					top + 33, core.arrayToRGBA((enemy.specialColor || [])[0] || '#FF6A6A'));
				core.fillText('ui', enemy.specialText[1], left + (width + totalWidth - rightWidth) / 2,
					top + 33, core.arrayToRGBA((enemy.specialColor || [])[1] || '#FF6A6A'));
				break;
			default:
				core.fillText('ui', '多属性...', left + width / 2,
					top + 33, '#FF6A6A', this._buildFont(12, true), width);
			}
			core.fillText('ui', enemy.level, left + width / 2,
				top + 48, core.arrayToRGBA(levelToColors[enemy.level] || '#DDDDDD'), this._buildFont(14, true));
			core.fillText('ui', enemy.jiewei, left + width / 2,
				top + 60, core.arrayToRGBA(levelToColors[enemy.jiewei] || '#DDDDDD'), this._buildFont(12, true));
		}
	}


	// 也可以复写其他的属性颜色如怪物攻防等，具体参见下面的例子的注释部分
	core.ui._drawBook_drawRow1 = function (index, enemy, top, left, width, position) {
		// 绘制第一行
		core.setTextAlign('ui', 'left');
		var b13 = this._buildFont(13, true),
			f13 = this._buildFont(13, false);
		var col1 = left,
			col2 = left + width * 9 / 25,
			col3 = left + width * 17 / 25;
		core.fillText('ui', '生命', col1, position, '#DDDDDD', f13);
		core.fillText('ui', core.formatBigNumber(enemy.hp || 0), col1 + 30, position, /*'red' */ null, b13);
		core.fillText('ui', '攻击', col2, position, null, f13);
		core.fillText('ui', core.formatBigNumber(enemy.atk || 0), col2 + 30, position, /* '#FF0000' */ null, b13);
		core.fillText('ui', '防御', col3, position, null, f13);
		core.fillText('ui', core.formatBigNumber(enemy.def || 0), col3 + 30, position, /* [255, 0, 0, 1] */ null, b13);
	}


},
    "dynamicHp": function () {
	// 此插件允许人物血量动态进行变化
	// 原作：Fux2（老黄鸡）

	// 是否开启本插件，默认禁用；将此改成 true 将启用本插件。
	var __enable = false;
	if (!__enable) return;

	var speed = 0.05; // 动态血量变化速度，越大越快。

	var _currentHp = null;
	var _lastStatus = null;
	var _check = function () {
		if (_lastStatus != core.status.hero) {
			_lastStatus = core.status.hero;
			_currentHp = core.status.hero.hp;
		}
	}

	core.registerAnimationFrame('dynamicHp', true, function () {
		_check();
		if (core.status.hero.hp != _currentHp) {
			var dis = (_currentHp - core.status.hero.hp) * speed;
			if (Math.abs(dis) < 2) {
				_currentHp = core.status.hero.hp;
			} else {
				_currentHp -= dis;
			}
			core.setStatusBarInnerHTML('hp', _currentHp);
		}
	});
},
    "multiHeros": function () {
	// 多角色插件
	// Step 1: 启用本插件
	// Step 2: 定义每个新的角色各项初始数据（参见下方注释）
	// Step 3: 在游戏中的任何地方都可以调用 `core.changeHero()` 进行切换；也可以 `core.changeHero(1)` 来切换到某个具体的角色上

	// 是否开启本插件，默认禁用；将此改成 true 将启用本插件。
	var __enable = false;
	if (!__enable) return;

	// 在这里定义全部的新角色属性
	// 请注意，在这里定义的内容不会多角色共用，在切换时会进行恢复。
	// 你也可以自行新增或删除，比如不共用金币则可以加上"money"的初始化，不共用道具则可以加上"items"的初始化，
	// 多角色共用hp的话则删除hp，等等。总之，不共用的属性都在这里进行定义就好。
	var hero1 = {
		"floorId": "MT0", // 该角色初始楼层ID；如果共用楼层可以注释此项
		"image": "brave.png", // 角色的行走图名称；此项必填不然会报错
		"name": "1号角色",
		"lv": 1,
		"hp": 10000, // 如果HP共用可注释此项
		"atk": 1000,
		"def": 1000,
		"mdef": 0,
		// "money": 0, // 如果要不共用金币则取消此项注释
		// "exp": 0, // 如果要不共用经验则取消此项注释
		"loc": { "x": 0, "y": 0, "direction": "up" }, // 该角色初始位置；如果共用位置可注释此项
		"items": {
			"tools": {}, // 如果共用消耗道具（含钥匙）则可注释此项
			// "constants": {}, // 如果不共用永久道具（如手册）可取消注释此项
			"equips": {}, // 如果共用在背包的装备可注释此项
		},
		"equipment": [], // 如果共用装备可注释此项；此项和上面的「共用在背包的装备」需要拥有相同状态，不然可能出现问题
	};
	// 也可以类似新增其他角色
	// 新增的角色，各项属性共用与不共用的选择必须和上面完全相同，否则可能出现问题。
	// var hero2 = { ...

	var heroCount = 2; // 包含默认角色在内总共多少个角色，该值需手动修改。

	this.initHeros = function () {
		core.setFlag("hero1", core.clone(hero1)); // 将属性值存到变量中
		// core.setFlag("hero2", core.clone(hero2)); // 更多的角色也存入变量中；每个定义的角色都需要新增一行

		// 检测是否存在装备
		if (hero1.equipment) {
			if (!hero1.items || !hero1.items.equips) {
				alert('多角色插件的equipment和道具中的equips必须拥有相同状态！');
			}
			// 存99号套装为全空
			var saveEquips = core.getFlag("saveEquips", []);
			saveEquips[99] = [];
			core.setFlag("saveEquips", saveEquips);
		} else {
			if (hero1.items && hero1.items.equips) {
				alert('多角色插件的equipment和道具中的equips必须拥有相同状态！');
			}
		}
	}

	// 在游戏开始注入initHeros
	var _startGame_setHard = core.events._startGame_setHard;
	core.events._startGame_setHard = function () {
		_startGame_setHard.call(core.events);
		core.initHeros();
	}

	// 切换角色
	// 可以使用 core.changeHero() 来切换到下一个角色
	// 也可以 core.changeHero(1) 来切换到某个角色（默认角色为0）
	this.changeHero = function (toHeroId) {
		var currHeroId = core.getFlag("heroId", 0); // 获得当前角色ID
		if (toHeroId == null) {
			toHeroId = (currHeroId + 1) % heroCount;
		}
		if (currHeroId == toHeroId) return;

		var saveList = Object.keys(hero1);

		// 保存当前内容
		var toSave = {};
		// 暂时干掉 drawTip 和 音效，避免切装时的提示
		var _drawTip = core.ui.drawTip;
		core.ui.drawTip = function () {};
		var _playSound = core.control.playSound;
		core.control.playSound = function () {}
		// 记录当前录像，因为可能存在换装问题
		core.clearRouteFolding();
		var routeLength = core.status.route.length;
		// 优先判定装备
		if (hero1.equipment) {
			core.items.quickSaveEquip(100 + currHeroId);
			core.items.quickLoadEquip(99);
		}

		saveList.forEach(function (name) {
			if (name == 'floorId') toSave[name] = core.status.floorId; // 楼层单独设置
			else if (name == 'items') {
				toSave.items = core.clone(core.status.hero.items);
				Object.keys(toSave.items).forEach(function (one) {
					if (!hero1.items[one]) delete toSave.items[one];
				});
			} else toSave[name] = core.clone(core.status.hero[name]); // 使用core.clone()来创建新对象
		});

		core.setFlag("hero" + currHeroId, toSave); // 将当前角色信息进行保存
		var data = core.getFlag("hero" + toHeroId); // 获得要切换的角色保存内容

		// 设置角色的属性值
		saveList.forEach(function (name) {
			if (name == "floorId");
			else if (name == "items") {
				Object.keys(core.status.hero.items).forEach(function (one) {
					if (data.items[one]) core.status.hero.items[one] = core.clone(data.items[one]);
				});
			} else {
				core.status.hero[name] = core.clone(data[name]);
			}
		});
		// 最后装上装备
		if (hero1.equipment) {
			core.items.quickLoadEquip(100 + toHeroId);
		}

		core.ui.drawTip = _drawTip;
		core.control.playSound = _playSound;
		core.status.route = core.status.route.slice(0, routeLength);
		core.control._bindRoutePush();

		// 插入事件：改变角色行走图并进行楼层切换
		var toFloorId = data.floorId || core.status.floorId;
		var toLoc = data.loc || core.status.hero.loc;
		core.insertAction([
			{ "type": "setHeroIcon", "name": data.image || "hero.png" }, // 改变行走图
			// 同层则用changePos，不同层则用changeFloor；这是为了避免共用楼层造成触发eachArrive
			toFloorId != core.status.floorId ? {
				"type": "changeFloor",
				"floorId": toFloorId,
				"loc": [toLoc.x, toLoc.y],
				"direction": toLoc.direction,
				"time": 0 // 可以在这里设置切换时间
			} : { "type": "changePos", "loc": [toLoc.x, toLoc.y], "direction": toLoc.direction }
			// 你还可以在这里执行其他事件，比如增加或取消跟随效果
		]);
		core.setFlag("heroId", toHeroId); // 保存切换到的角色ID
	}
},
    "itemCategory": function () {
	// 物品分类插件。此插件允许你对消耗道具和永久道具进行分类，比如标记「宝物类」「剧情道具」「药品」等等。
	// 使用方法：
	// 1. 启用本插件
	// 2. 在下方数组中定义全部的物品分类类型
	// 3. 点击道具的【配置表格】，找到“【道具】相关的表格配置”，然后在【道具描述】之后仿照增加道具的分类：
	/*
	 "category": {
	 	"_leaf": true,
	 	"_type": "textarea",
	 	"_string": true,
	 	"_data": "道具分类"
	 },
	 */
	// （你也可以选择使用下拉框的方式定义每个道具的分类，写法参见上面的cls）
	// 然后刷新编辑器，就可以对每个物品进行分类了

	// 是否开启本插件，默认禁用；将此改成 true 将启用本插件。
	var __enable = false;
	if (!__enable) return;

	// 在这里定义所有的道具分类类型，一行一个
	var categories = [
		"宝物类",
		"辅助类",
		"技能类",
		"剧情道具",
		"增益道具",
	];
	// 当前选中的道具类别
	var currentCategory = null;

	// 重写 core.ui._drawToolbox 以绘制分类类别
	var _drawToolbox = core.ui._drawToolbox;
	core.ui._drawToolbox = function (index) {
		_drawToolbox.call(this, index);
		core.setTextAlign('ui', 'left');
		core.fillText('ui', '类别[E]：' + (currentCategory || "全部"), 15, this.PIXEL - 13);
	}

	// 获得所有应该在道具栏显示的某个类型道具
	core.ui.getToolboxItems = function (cls) {
		// 检查类别
		return Object.keys(core.status.hero.items[cls])
			.filter(function (id) {
				return !core.material.items[id].hideInToolbox &&
					(currentCategory == null || core.material.items[id].category == currentCategory);
			}).sort();
	}

	// 注入道具栏的点击事件（点击类别）
	var _clickToolbox = core.actions._clickToolbox;
	core.actions._clickToolbox = function (x, y) {
		if (x >= 0 && x <= this.HSIZE - 4 && y == this.LAST) {
			drawToolboxCategory();
			return;
		}
		return _clickToolbox.call(core.actions, x, y);
	}

	// 注入道具栏的按键事件（E键）
	var _keyUpToolbox = core.actions._keyUpToolbox;
	core.actions._keyUpToolbox = function (keyCode) {
		if (keyCode == 69) {
			// 按E键则打开分类类别选择
			drawToolboxCategory();
			return;
		}
		return _keyUpToolbox.call(core.actions, keyCode);
	}

	// ------ 以下为选择道具分类的相关代码 ------ //

	// 关闭窗口时清除分类选择项
	var _closePanel = core.ui.closePanel;
	core.ui.closePanel = function () {
		currentCategory = null;
		_closePanel.call(core.ui);
	}

	// 弹出菜单以选择具体哪个分类
	// 直接使用 core.drawChoices 进行绘制
	var drawToolboxCategory = function () {
		if (core.status.event.id != 'toolbox') return;
		var selection = categories.indexOf(currentCategory) + 1;
		core.ui.closePanel();
		core.status.event.id = 'toolbox-category';
		core.status.event.selection = selection;
		core.lockControl();
		// 给第一项插入「全部」
		core.drawChoices('请选择道具类别', ["全部"].concat(categories));
	}

	// 选择某一项
	var _selectCategory = function (index) {
		core.ui.closePanel();
		if (index <= 0 || index > categories.length) currentCategory = null;
		else currentCategory = categories[index - 1];
		core.openToolbox();
	}

	var _clickToolBoxCategory = function (x, y) {
		if (!core.status.lockControl || core.status.event.id != 'toolbox-category') return false;

		if (x < core.actions.CHOICES_LEFT || x > core.actions.CHOICES_RIGHT) return false;
		var choices = core.status.event.ui.choices;
		var topIndex = core.actions._getChoicesTopIndex(choices.length);
		if (y >= topIndex && y < topIndex + choices.length) {
			_selectCategory(y - topIndex);
		}
		return true;
	}

	// 注入点击事件
	core.registerAction('onclick', 'toolbox-category', _clickToolBoxCategory, 100);

	// 注入光标跟随事件
	core.registerAction('onmove', 'toolbox-category', function (x, y) {
		if (!core.status.lockControl || core.status.event.id != 'toolbox-category') return false;
		core.actions._onMoveChoices(x, y);
		return true;
	}, 100);

	// 注入键盘光标事件
	core.registerAction('keyDown', 'toolbox-category', function (keyCode) {
		if (!core.status.lockControl || core.status.event.id != 'toolbox-category') return false;
		core.actions._keyDownChoices(keyCode);
		return true;
	}, 100);

	// 注入键盘按键事件
	core.registerAction('keyUp', 'toolbox-category', function (keyCode) {
		if (!core.status.lockControl || core.status.event.id != 'toolbox-category') return false;
		core.actions._selectChoices(core.status.event.ui.choices.length, keyCode, _clickToolBoxCategory);
		return true;
	}, 100);

},
    "heroFourFrames": function () {
	// 样板的勇士/跟随者移动时只使用2、4两帧，观感较差。本插件可以将四帧全用上。

	// 是否启用本插件
	var __enable = true;
	if (!__enable) return;

	["up", "down", "left", "right"].forEach(function (one) {
		// 指定中间帧动画
		core.material.icons.hero[one].midFoot = 2;
	});

	var heroMoving = function (timestamp) {
		if (core.status.heroMoving <= 0) return;
		if (timestamp - core.animateFrame.moveTime > core.values.moveSpeed) {
			core.animateFrame.leftLeg++;
			core.animateFrame.moveTime = timestamp;
		}
		core.drawHero(['stop', 'leftFoot', 'midFoot', 'rightFoot'][core.animateFrame.leftLeg % 4], 4 * core.status.heroMoving);
	}
	core.registerAnimationFrame('heroMoving', true, heroMoving);

	core.events._eventMoveHero_moving = function (step, moveSteps) {
		var curr = moveSteps[0];
		var direction = curr[0],
			x = core.getHeroLoc('x'),
			y = core.getHeroLoc('y');
		// ------ 前进/后退
		var o = direction == 'backward' ? -1 : 1;
		if (direction == 'forward' || direction == 'backward') direction = core.getHeroLoc('direction');
		var faceDirection = direction;
		if (direction == 'leftup' || direction == 'leftdown') faceDirection = 'left';
		if (direction == 'rightup' || direction == 'rightdown') faceDirection = 'right';
		core.setHeroLoc('direction', direction);
		if (curr[1] <= 0) {
			core.setHeroLoc('direction', faceDirection);
			moveSteps.shift();
			return true;
		}
		if (step <= 4) core.drawHero('stop', 4 * o * step);
		else if (step <= 8) core.drawHero('leftFoot', 4 * o * step);
		else if (step <= 12) core.drawHero('midFoot', 4 * o * (step - 8));
		else if (step <= 16) core.drawHero('rightFoot', 4 * o * (step - 8)); // if (step == 8) {
		if (step == 8 || step == 16) {
			core.setHeroLoc('x', x + o * core.utils.scan2[direction].x, true);
			core.setHeroLoc('y', y + o * core.utils.scan2[direction].y, true);
			core.updateFollowers();
			curr[1]--;
			if (curr[1] <= 0) moveSteps.shift();
			core.setHeroLoc('direction', faceDirection);
			return step == 16;
		}
		return false;
	}
},
    "startCanvas": function () {
	// 使用本插件可以将自绘的标题界面居中。仅在【标题开启事件化】后才有效。
	// 由于一些技术性的原因，标题界面事件化无法应用到覆盖状态栏的整个界面。
	// 这是一个较为妥协的插件，会在自绘标题界面时隐藏状态栏、工具栏和边框，并将画布进行居中。
	// 本插件仅在全塔属性的 "startCanvas" 生效；进入 "startText" 时将会离开居中状态，回归正常界面。

	// 是否开启本插件，默认禁用；将此改成 true 将启用本插件。
	var __enable = false;
	if (!__enable) return;

	// 检查【标题开启事件化】是否开启
	if (!core.flags.startUsingCanvas || main.mode != 'play') return;

	var _isTitleCanvasEnabled = false;
	var _getClickLoc = core.actions._getClickLoc;
	this._setTitleCanvas = function () {
		if (_isTitleCanvasEnabled) return;
		_isTitleCanvasEnabled = true;

		// 禁用窗口resize
		window.onresize = function () {};
		core.resize = function () {}

		// 隐藏状态栏
		core.dom.statusBar.style.display = 'none';
		core.dom.statusCanvas.style.display = 'none';
		core.dom.toolBar.style.display = 'none';
		// 居中画布
		if (core.domStyle.isVertical) {
			core.dom.gameDraw.style.top =
				(parseInt(core.dom.gameGroup.style.height) - parseInt(core.dom.gameDraw.style.height)) / 2 + "px";
		} else {
			core.dom.gameDraw.style.right =
				(parseInt(core.dom.gameGroup.style.width) - parseInt(core.dom.gameDraw.style.width)) / 2 + "px";
		}
		core.dom.gameDraw.style.border = '3px transparent solid';
		core.actions._getClickLoc = function (x, y) {
			var left = core.dom.gameGroup.offsetLeft + core.dom.gameDraw.offsetLeft + 3;
			var top = core.dom.gameGroup.offsetTop + core.dom.gameDraw.offsetTop + 3;
			var loc = { 'x': Math.max(x - left, 0), 'y': Math.max(y - top, 0), 'size': 32 * core.domStyle.scale };
			return loc;
		}
	}

	this._resetTitleCanvas = function () {
		if (!_isTitleCanvasEnabled) return;
		_isTitleCanvasEnabled = false;
		window.onresize = function () { try { main.core.resize(); } catch (e) { main.log(e); } }
		core.resize = function () { return core.control.resize(); }
		core.resize();
		core.actions._getClickLoc = _getClickLoc;
	}

	// 复写“开始游戏”
	core.events._startGame_start = function (hard, seed, route, callback) {
		console.log('开始游戏');
		core.resetGame(core.firstData.hero, hard, null, core.cloneArray(core.initStatus.maps));
		core.setHeroLoc('x', -1);
		core.setHeroLoc('y', -1);

		if (seed != null) {
			core.setFlag('__seed__', seed);
			core.setFlag('__rand__', seed);
		} else core.utils.__init_seed();

		core.clearStatusBar();
		core.plugin._setTitleCanvas();

		var todo = [];
		core.hideStatusBar();
		core.push(todo, core.firstData.startCanvas);
		core.push(todo, { "type": "function", "function": "function() { core.plugin._resetTitleCanvas(); core.events._startGame_setHard(); }" })
		core.push(todo, core.firstData.startText);
		this.insertAction(todo, null, null, function () {
			core.events._startGame_afterStart(callback);
		});

		if (route != null) core.startReplay(route);
	}

	var _loadData = core.control.loadData;
	core.control.loadData = function (data, callback) {
		core.plugin._resetTitleCanvas();
		_loadData.call(core.control, data, callback);
	}
},
    "xpbs": function () {
	// 在此增加新插件
	/* 宝石血瓶左下角显示数值
	 * 需要将 变量：itemDetail改为true才可正常运行
	 * 请尽量减少勇士的属性数量，否则可能会出现严重卡顿
	 * 注意：这里的属性必须是core.status.hero里面的，flag无法显示
	 * 如果不想显示，可以core.setFlag("itemDetail", false);
	 * 然后再core.getItemDetail();
	 * 2021.6.23更新：加快运行速度
	 * 2021.7.23更新：现在支持大地图了！！！！！同时把显伤清晰度调高了，现在负值（减属性）也可以正常显示了
	 * 2021.7.24更新：去掉了一些没用的代码
	 * 2021.7.26更新：解决超大地图卡顿问题（用的样板的v2优化，样板nb！！）
	 * 2021.7.30更新：注释更详细了，可以自己修改了，用// ***包住的区域是可修改区域，其余不可修改
	 * 2021.8.18更新：艾佬帮忙优化了一下，艾佬太强了！
	 * 如有bug在大群或造塔群@古祠
	 */
	core.control.updateDamage = function (floorId, ctx) {
		floorId = floorId || core.status.floorId;
		if (!floorId || core.status.gameOver || main.mode != 'play') return;
		var onMap = ctx == null;

		// 没有怪物手册
		if (!core.hasItem('book')) return;
		core.status.damage.posX = core.bigmap.posX;
		core.status.damage.posY = core.bigmap.posY;
		if (!onMap) {
			var width = core.floors[floorId].width,
				height = core.floors[floorId].height;
			// 地图过大的缩略图不绘制显伤
			if (width * height > core.bigmap.threshold) return;
		}
		this._updateDamage_damage(floorId, onMap);
		this._updateDamage_extraDamage(floorId, onMap);
		core.getItemDetail(floorId); // 宝石血瓶详细信息
		this.drawDamage(ctx);
	};
	// 绘制地图显示
	control.prototype._drawDamage_draw = function (ctx, onMap) {
		if (!core.hasItem('book')) return;
		// *** 下一句话可以更改你想要的显示字体
		core.setFont(ctx, "bold 11px Arial");
		// ***
		core.setTextAlign(ctx, 'left');
		core.status.damage.data.forEach(function (one) {
			var px = one.px,
				py = one.py;
			if (onMap && core.bigmap.v2) {
				px -= core.bigmap.posX * 32;
				py -= core.bigmap.posY * 32;
				if (px < -32 * 2 || px > core.__PIXELS__ + 32 || py < -32 || py > core.__PIXELS__ + 32)
					return;
			}
			core.fillBoldText(ctx, one.text, px, py, one.color);
		});
		core.setTextAlign(ctx, 'center');
		core.status.damage.extraData.forEach(function (one) {
			var px = one.px,
				py = one.py;
			if (onMap && core.bigmap.v2) {
				px -= core.bigmap.posX * 32;
				py -= core.bigmap.posY * 32;
				if (px < -32 || px > core.__PIXELS__ + 32 || py < -32 || py > core.__PIXELS__ + 32)
					return;
			}
			core.fillBoldText(ctx, one.text, px, py, one.color);
		});
	};
	////// 更改地图画布的尺寸 //////
	maps.prototype.resizeMap = function (floorId) {
		floorId = floorId || core.status.floorId;
		if (!floorId) return;
		core.bigmap.width = core.floors[floorId].width;
		core.bigmap.height = core.floors[floorId].height;
		core.bigmap.posX = core.bigmap.posY = 0;
		// *** 下一句话可以更改超大地图的定义，core.bigmap.threshold为1024，这里/4 说明地图面积超过256即为超大地图，使用v2优化
		core.bigmap.v2 = core.bigmap.width * core.bigmap.height > core.bigmap.threshold / 4;
		// ***
		var width = core.bigmap.v2 ? core.__PIXELS__ + 64 : core.bigmap.width * 32;
		var height = core.bigmap.v2 ? core.__PIXELS__ + 64 : core.bigmap.height * 32;

		core.bigmap.canvas.forEach(function (cn) {
			if (core.domStyle.hdCanvas.indexOf(cn) >= 0)
				core.maps._setHDCanvasSize(core.canvas[cn], width, height);
			else {
				core.canvas[cn].canvas.width = width;
				core.canvas[cn].canvas.height = height;
			}
			core.canvas[cn].canvas.style.width = width * core.domStyle.scale + "px";
			core.canvas[cn].canvas.style.height = height * core.domStyle.scale + "px";
			core.canvas[cn].translate(core.bigmap.v2 ? 32 : 0, core.bigmap.v2 ? 32 : 0);
			if (main.mode === 'editor' && editor.isMobile) {
				core.canvas[cn].canvas.style.width = width / core.__PIXELS__ * 96 + "vw";
				core.canvas[cn].canvas.style.height = height / core.__PIXELS__ * 96 + "vw";
			}
		});
	};
	// 获取宝石信息 并绘制
	this.getItemDetail = function (floorId) {
		if (!core.getFlag("itemDetail")) return;
		floorId = floorId || core.status.thisMap.floorId;
		core.status.maps[floorId].blocks.forEach(function (block) {
			var x = block.x,
				y = block.y;
			// v2优化，只绘制范围内的部分
			if (core.bigmap.v2) {
				if (x < core.bigmap.posX - core.bigmap.extend || x > core.bigmap.posX + core.__SIZE__ + core.bigmap.extend ||
					y < core.bigmap.posY - core.bigmap.extend || y > core.bigmap.posY + core.__SIZE__ + core.bigmap.extend) {
					return;
				}
			}
			if (block.event.cls == "items") {
				var before = core.clone(core.status.hero),
					id = block.event.id;

				// *** 可以加一些不检测的道具，比如屏蔽圣水可以这么写：
				// if (id == "superPotion") return;
				// ***

				// 跟数据统计原理一样 执行效果 前后比较
				core.setFlag("__statistics__", true);
				try {
					eval(core.material.items[id].itemEffect);
				} catch (error) {}
				var diff = core.compareObject(before, core.status.hero);
				core.status.hero = before;
				window.hero = core.status.hero;
				window.flags = core.status.hero.flags;
				core.drawItemDetail(diff, block.x, block.y, floorId, id);
			}
		});
	};
	// 比较两个对象之间每一项的数值差异（弱等于）返回数值差异
	this.compareObject = function (a, b) {
		a = a || {};
		b = b || {};
		var diff = {}; // 差异
		for (var name in a) {
			if (a[name] != b[name]) { // a != b
				try {
					diff[name] = b[name] - (a[name] || 0);
				} catch (error) {}
				if (isNaN(diff[name])) delete diff[name];
				if (diff[name] == 0) delete diff[name];
			}
		}
		return diff;
	};
	// 绘制
	this.drawItemDetail = function (diff, x, y, floorId, id) {
		if (core.same(diff, {}) || !diff) return;
		var px = 32 * x + 2,
			py = 32 * y + 30;
		var content = "";
		// 获得数据和颜色
		var i = 0;
		for (var name in diff) {
			var color = "#ffffff"
			diff[name] = core.formatBigNumber(diff[name], true);
			// *** 这里可以改不同属性对应的颜色
			switch (name) {
			case 'atk':
				color = "#FF7A7A";
				break;
			case 'def':
				color = "#00E6F1";
				break;
			case 'mdef':
				color = "#6EFF83";
				break;
			case 'hp':
				color = "#A4FF00";
				break;
			case 'hpmax':
				color = "#F9FF00";
				break;
			case 'mana':
				color = "#001CFF";
				break;
			}
			// ***
			content = diff[name];
			// 绘制
			core.status.damage.data.push({ text: content, px: px, py: py - 10 * i, color: color });
			i++;
		}
	}
},
    "装备": function () {
	// 注：///// *** 裹起来的区域： 该区域内参数可以随意更改调整ui绘制 不会影响总体布局
	// 请尽量修改该区域而不是其他区域 修改的时候最好可以对照现有ui修改

	///// *** 道具类型
	// cls对应name
	var itemClsName = {
		"constants": "永久道具",
		"tools": "消耗道具",
	}
	// 一页最大放的道具数量 将把整个道具左栏分成num份 每份是一个道具项
	var itemNum = 12;
	///// ***

	// 背景设置
	this.drawBoxBackground = function (ctx) {
		core.setTextAlign(ctx, "left");
		core.clearMap(ctx);
		core.deleteCanvas("_selector");
		var info = core.status.thisUIEventInfo || {};

		///// *** 背景设置
		var max = core.__PIXELS__;
		var x = 2,
			y = x,
			w = max - x * 2,
			h = w;
		var borderWidth = 2,
			borderRadius = 5, // radius:圆角矩形的圆角半径
			borderStyle = "#fff";
		var backgroundColor = "gray";
		// 设置背景不透明度(0.85)
		var backgroundAlpha = 0.85;
		///// ***

		var start_x = x + borderWidth / 2,
			start_y = y + borderWidth / 2,
			width = max - start_x * 2,
			height = max - start_y * 2;

		// 渐变色背景的一个例子(黑色渐变白色)：
		// 有关渐变色的具体知识请网上搜索canvas createGradient了解
		/*
		   var grd = ctx.createLinearGradient(x, y, x + w, y);
		   grd.addColorStop(0, "black");
		   grd.addColorStop(1, "white");
		   backgroundColor = grd;
		*/
		// 使用图片背景要注释掉下面的strokeRect和fillRoundRect
		// 图片背景的一个例子：
		/*
		   core.drawImage(ctx, "xxx.png", x, y, w, h);
		   core.strokeRect(ctx, x, y, w, h, borderStyle, borderWidth);
		*/
		core.setAlpha(ctx, backgroundAlpha);
		core.strokeRoundRect(ctx, x, y, w, h, borderRadius, borderStyle, borderWidth);
		core.fillRoundRect(ctx, start_x, start_y, width, height, borderRadius, backgroundColor);
		core.setAlpha(ctx, 1);

		///// *** 左栏配置
		var leftbar_height = height;
		// 左边栏宽度(width*0.6) 本身仅为坐标使用 需要与底下的rightbar_width(width*0.4)同时更改
		var leftbar_width = width * 0.6;
		///// ***

		// xxx_right参数 代表最右侧坐标
		var leftbar_right = start_x + leftbar_width - borderWidth / 2;
		var leftbar_bottom = start_y + leftbar_height;
		var leftbar_x = start_x;
		var leftbar_y = start_y;

		///// *** 道具栏配置
		var boxName_color = "#fff";
		var boxName_fontSize = 15;
		var boxName_font = core.ui._buildFont(boxName_fontSize, true);
		var arrow_x = 10 + start_x;
		var arrow_y = 10 + start_y;
		var arrow_width = 20;
		var arrow_style = "white";
		// 暂时只能是1 否则不太行 等待新样板(2.7.3)之后对drawArrow做优化
		var arrow_lineWidth = 1;
		// 右箭头
		var rightArrow_right = leftbar_right - 10;
		// 道具内栏顶部坐标 本质是通过该项 控制(道具栏顶部文字和箭头)与道具内栏顶部的间隔
		var itembar_top = arrow_y + 15;
		///// ***

		var itembar_right = rightArrow_right;
		var boxName = core.status.event.id == "toolbox" ? "\r[yellow]道具栏\r | 装备栏" : "道具栏 | \r[yellow]装备栏\r";
		core.drawArrow(ctx, arrow_x + arrow_width, arrow_y, arrow_x, arrow_y, arrow_style, arrow_lineWidth);
		core.drawArrow(ctx, rightArrow_right - arrow_width, arrow_y, rightArrow_right, arrow_y, arrow_style, arrow_lineWidth);
		core.setTextAlign(ctx, "center");
		core.setTextBaseline(ctx, "middle");
		var changeBox = function () {
			var id = core.status.event.id;
			core.closePanel();
			if (id == "toolbox") core.openEquipbox();
			else core.openToolbox();
		}
		core.fillText(ctx, boxName, (leftbar_right + leftbar_x) / 2, arrow_y + 2, boxName_color, boxName_font);

		///// *** 底栏按钮
		var pageBtn_radius = 8;
		// xxx_left 最左侧坐标
		var pageBtn_left = leftbar_x + 3;
		var pageBtn_right = leftbar_right - 3;
		// xxx_bottom 最底部坐标
		var pageBtn_bottom = leftbar_bottom - 2;
		var pageBtn_borderStyle = "#fff";
		var pageBtn_borderWidth = 2;
		var pageText_color = "#fff";
		// 底部按钮与上面的道具内栏的间隔大小
		var bottomSpace = 8;
		///// ***

		core.drawItemListbox_setPageBtn(ctx, pageBtn_left, pageBtn_right, pageBtn_bottom, pageBtn_radius, pageBtn_borderStyle, pageBtn_borderWidth);
		var page = info.page || 1;
		var pageFontSize = pageBtn_radius * 2 - 4;
		var pageFont = core.ui._buildFont(pageFontSize);
		core.setPageItems(page);
		var num = itemNum;
		if (core.status.event.id == "equipbox") num -= 5;
		var maxPage = info.maxPage;
		var pageText = page + " / " + maxPage;
		core.setTextAlign(ctx, "center");
		core.setTextBaseline(ctx, "bottom");
		core.fillText(ctx, pageText, (leftbar_x + leftbar_right) / 2, pageBtn_bottom, pageText_color, pageFont);
		core.addUIEventListener(start_x, start_y, leftbar_right - start_x, arrow_y - start_y + 13, changeBox);
		var itembar_height = Math.ceil(pageBtn_bottom - pageBtn_radius * 2 - pageBtn_borderWidth / 2 - bottomSpace - itembar_top);
		var oneItemHeight = (itembar_height - 4) / itemNum;
		return {
			x: start_x,
			y: start_y,
			width: width,
			height: height,
			leftbar_right: leftbar_right,
			obj: {
				x: arrow_x,
				y: itembar_top,
				width: itembar_right - arrow_x,
				height: itembar_height,
				oneItemHeight: oneItemHeight
			}
		}
	}

	this.drawItemListbox = function (ctx, obj) {
		ctx = ctx || core.canvas.ui;
		var itembar_x = obj.x,
			itembar_y = obj.y,
			itembar_width = obj.width,
			itembar_height = obj.height,
			itemNum = obj.itemNum,
			oneItemHeight = obj.oneItemHeight;
		var itembar_right = itembar_x + itembar_width;
		var info = core.status.thisUIEventInfo || {};
		var obj = {};
		var page = info.page || 1,
			index = info.index,
			select = info.select || {};

		///// *** 道具栏内栏配置
		var itembar_style = "black";
		var itembar_alpha = 0.7;
		// 一个竖屏下减少道具显示的例子:
		// if (core.domStyle.isVertical) itemNum = 10;
		// 每个道具项的上下空隙占总高度的比例
		var itembar_marginHeightRatio = 0.2;
		// 左右间隔空隙
		var item_marginLeft = 2;
		var item_x = itembar_x + 2,
			item_y = itembar_y + 2,
			item_right = itembar_right - 2,
			itemName_color = "#fff";
		// 修改此项以更换闪烁光标
		var item_selector = "winskin.png";
		///// ***

		core.setAlpha(ctx, itembar_alpha);
		core.fillRect(ctx, itembar_x, itembar_y, itembar_width, itembar_height, itembar_style);
		core.setAlpha(ctx, 1);
		var pageItems = core.setPageItems(page);
		var marginHeight = itembar_marginHeightRatio * oneItemHeight;
		core.setTextBaseline(ctx, "middle");
		var originColor = itemName_color;
		for (var i = 0; i < pageItems.length; i++) {
			itemName_color = originColor;
			var item = pageItems[i];
			// 设置某个的字体颜色的一个例子
			// if (item.id == "xxx") itemName_color = "green";
			core.drawItemListbox_drawItem(ctx, item_x, item_right, item_y, oneItemHeight, item_marginLeft, marginHeight, itemName_color, pageItems[i]);
			if (index == i + 1) core.ui._drawWindowSelector(item_selector, item_x + 1, item_y - 1, item_right - item_x - 2, oneItemHeight - 2);
			item_y += oneItemHeight;
		}
	}

	this.drawToolboxRightbar = function (ctx, obj) {
		ctx = ctx || core.canvas.ui;
		var info = core.status.thisUIEventInfo || {};
		var page = info.page || 1,
			index = info.index || 1,
			select = info.select || {};
		var start_x = obj.x,
			start_y = obj.y,
			width = obj.width,
			height = obj.height;
		var toolboxRight = start_x + width,
			toolboxBottom = start_y + height;


		///// *** 侧边栏(rightbar)背景设置(物品介绍)
		var rightbar_width = width * 0.4;
		var rightbar_height = height;
		var rightbar_lineWidth = 2;
		var rightbar_lineStyle = "#fff";
		///// ***

		var rightbar_x = toolboxRight - rightbar_width - rightbar_lineWidth / 2;
		var rightbar_y = start_y;
		core.drawLine(ctx, rightbar_x, rightbar_y, rightbar_x, rightbar_y + rightbar_height, rightbar_lineStyle, rightbar_lineWidth);

		// 获取道具id(有可能为null)
		var itemId = select.id;
		var item = core.material.items[itemId];

		///// *** 侧边栏物品Icon信息
		var iconRect_y = rightbar_y + 10;
		// space：间距
		// 这里布局设定iconRect与侧边栏左边框 itemName与工具栏右边框 itemRect与itemName的间距均为space
		var space = 15;
		var iconRect_x = rightbar_x + space;
		var iconRect_radius = 2,
			iconRect_width = 32,
			iconRect_height = 32,
			iconRect_style = "#fff",
			iconRect_lineWidth = 2;
		///// ***

		var iconRect_bottom = iconRect_y + iconRect_height,
			iconRect_right = iconRect_x + iconRect_width;

		///// *** 侧边栏各项信息
		var itemTextFontSize = 15,
			itemText_x = iconRect_x - 4,
			itemText_y = Math.floor(start_y + rightbar_height * 0.25), // 坐标取整防止模糊
			itemClsFontSize = 15,
			itemClsFont = core.ui._buildFont(itemClsFontSize),
			itemClsColor = "#fff",
			itemCls_x = itemText_x - itemClsFontSize / 2,
			itemCls_middle = (iconRect_bottom + itemText_y) / 2, //_middle代表文字的中心y坐标
			itemNameFontSize = 18,
			itemNameColor = "#fff",
			itemNameFont = core.ui._buildFont(itemNameFontSize, true);
		var itemName_x = iconRect_right + space;
		var itemName_middle = iconRect_y + iconRect_height / 2 + iconRect_lineWidth;
		// 修改这里可以编辑未选中道具时的默认值
		var defaultItem = {
			cls: "constants",
			name: "未知道具",
			text: "没有道具最永久"
		}
		var defaultEquip = {
			cls: "equips",
			name: "未知装备",
			text: "一无所有，又何尝不是一种装备",
			equip: {
				type: "装备"
			}
		}
		///// ***

		var originItem = item;
		if (core.status.event.id == "equipbox") item = item || defaultEquip;
		item = item || defaultItem;
		var itemCls = item.cls,
			itemName = item.name,
			itemText = item.text;
		/* 一个根据道具id修改道具名字(右栏)的例子
		 * if (item.id == "xxx") itemNameColor = "red";
		 */
		var itemClsName = core.getItemClsName(item);
		var itemNameMaxWidth = rightbar_width - iconRect_width - iconRect_lineWidth * 2 - space * 2;
		core.strokeRoundRect(ctx, iconRect_x, iconRect_y, iconRect_width, iconRect_height, iconRect_radius, iconRect_style, iconRect_lineWidth);
		if (item.id)
			core.drawIcon(ctx, item.id, iconRect_x + iconRect_lineWidth / 2, iconRect_y + iconRect_lineWidth / 2, iconRect_width - iconRect_lineWidth, iconRect_height - iconRect_lineWidth);
		core.setTextAlign(ctx, "left");
		core.setTextBaseline(ctx, "middle");
		core.fillText(ctx, itemName, itemName_x, itemName_middle, itemNameColor, itemNameFont, itemNameMaxWidth);
		core.fillText(ctx, "【" + itemClsName + "】", itemCls_x, itemCls_middle, itemClsColor, itemClsFont);
		var statusText = "";
		if (core.status.event.id == "equipbox") {
			var type = item.equip.type;
			if (typeof type == "string") type = core.getEquipTypeByName(type);
			var compare = core.compareEquipment(item.id, core.getEquip(type));
			if (info.select.action == "unload") compare = core.compareEquipment(null, item.id);
			// --- 变化值...
			for (var name in core.status.hero) {
				if (typeof core.status.hero[name] != 'number') continue;
				var nowValue = core.getRealStatus(name);
				// 查询新值
				var newValue = Math.floor((core.getStatus(name) + (compare.value[name] || 0)) *
					(core.getBuff(name) * 100 + (compare.percentage[name] || 0)) / 100);
				if (nowValue == newValue) continue;
				var color = newValue > nowValue ? '#00FF00' : '#FF0000';
				nowValue = core.formatBigNumber(nowValue);
				newValue = core.formatBigNumber(newValue);
				statusText += core.getStatusLabel(name) + " " + nowValue + "->\r[" + color + "]" + newValue + "\r\n";
			}
		}
		itemText = statusText + itemText;
		core.drawTextContent(ctx, itemText, {
			left: itemText_x,
			top: itemText_y,
			bold: false,
			color: "white",
			align: "left",
			fontSize: itemTextFontSize,
			maxWidth: rightbar_width - (itemText_x - rightbar_x) * 2 + itemTextFontSize / 2
		});

		///// *** 退出按钮设置
		var btnRadius = 10;
		var btnBorderWidth = 2;
		var btnRight = toolboxRight - 2;
		var btnBottom = toolboxBottom - 2;
		var btnBorderStyle = "#fff";
		///// ***

		// 获取圆心位置
		var btn_x = btnRight - btnRadius - btnBorderWidth / 2;
		btn_y = btnBottom - btnRadius - btnBorderWidth / 2;
		core.drawToolbox_setExitBtn(ctx, btn_x, btn_y, btnRadius, btnBorderStyle, btnBorderWidth);

		///// *** 使用按钮设置
		var useBtnHeight = btnRadius * 2;
		// 这里不设置useBtnWidth而是根据各项数据自动得出width
		var useBtnRadius = useBtnHeight / 2;
		var useBtn_x = rightbar_x + 4,
			useBtn_y = btnBottom - useBtnHeight;
		var useBtnBorderStyle = "#fff";
		var useBtnBorderWidth = btnBorderWidth;
		///// ***

		core.drawToolbox_setUseBtn(ctx, useBtn_x, useBtn_y, useBtnRadius, useBtnHeight, useBtnBorderStyle, useBtnBorderWidth);
	}

	this.drawEquipbox_drawOthers = function (ctx, obj) {
		var info = core.status.thisUIEventInfo;

		///// *** 装备格设置
		var equipList_lineWidth = 2;
		var equipList_boxSize = 32;
		var equipList_borderWidth = 2;
		var equipList_borderStyle = "#fff";
		var equipList_nameColor = "#fff";
		///// ***

		var equipList_x = obj.x + 4,
			equipList_bottom = obj.obj.y - equipList_lineWidth,
			equipList_y = equipList_bottom - obj.obj.oneItemHeight * reduceItem - 2,
			equipList_height = equipList_bottom - equipList_y;
		var equipList_right = obj.leftbar_right,
			equipList_width = equipList_right - equipList_x;
		core.drawLine(ctx, obj.x, equipList_bottom + equipList_lineWidth / 2, equipList_right, equipList_bottom + equipList_lineWidth / 2, equipList_borderStyle, equipList_lineWidth);
		var toDrawList = core.status.globalAttribute.equipName,
			len = toDrawList.length;

		///// *** 装备格设置
		var maxItem = 4;
		var box_width = 32,
			box_height = 32,
			box_borderStyle = "#fff",
			box_selectBorderStyle = "gold", // 选中的装备格的颜色
			box_borderWidth = 2;
		var boxName_fontSize = 14,
			boxName_space = 2,
			boxName_color = "#fff"; // 装备格名称与上面的装备格框的距离
		var maxLine = Math.ceil(len / maxItem);
		///// ***
		var l = Math.sqrt(len)
		if (Math.pow(l) == len && len != 4) {
			if (l <= maxItem) maxItem = l;
		}
		maxItem = Math.min(toDrawList.length, maxItem);
		info.equips = maxItem;

		var boxName_font = core.ui._buildFont(boxName_fontSize);
		// 总宽高减去所有装备格宽高得到空隙大小
		var oneBoxWidth = box_width + box_borderWidth * 2;
		var oneBoxHeight = box_height + boxName_fontSize + boxName_space + 2 * box_borderWidth;
		var space_y = (equipList_height - maxLine * oneBoxHeight) / (1 + maxLine),
			space_x = (equipList_width - maxItem * oneBoxWidth) / (1 + maxItem);
		var box_x = equipList_x + space_x,
			box_y = equipList_y + space_y;
		for (var i = 0; i < len; i++) {
			var id = core.getEquip(i),
				name = toDrawList[i];
			var selectBorder = false;
			if (core.status.thisUIEventInfo.select.type == i) selectBorder = true;
			var borderStyle = selectBorder ? box_selectBorderStyle : box_borderStyle;
			core.drawEquipbox_drawOne(ctx, name, id, box_x, box_y, box_width, box_height, boxName_space, boxName_font, boxName_color, borderStyle, box_borderWidth);
			var todo = new Function("core.clickOneEquipbox('" + id + "'," + i + ")");
			core.addUIEventListener(box_x - box_borderWidth / 2, box_y - box_borderWidth / 2, oneBoxWidth, oneBoxHeight, todo);
			box_x += space_x + oneBoxWidth;
			if ((i + 1) % maxItem == 0) {
				box_x = equipList_x + space_x;
				box_y += space_y + oneBoxHeight;
			}
		}
	}

	this.drawToolbox = function (ctx) {
		ctx = ctx || core.canvas.ui;
		core.status.thisEventClickArea = [];

		var info = core.drawBoxBackground(ctx);
		info.itemNum = itemNum;
		core.drawItemListbox(ctx, info.obj);
		core.drawToolboxRightbar(ctx, info);
		core.setTextBaseline(ctx, "alphabetic");
		core.setTextAlign("left");
	}

	var reduceItem = 4;
	this.drawEquipbox = function (ctx) {
		ctx = ctx || core.canvas.ui;
		core.status.thisEventClickArea = [];
		var info = core.drawBoxBackground(ctx);
		info.itemNum = itemNum - reduceItem;
		info.obj.y += info.obj.oneItemHeight * reduceItem;
		info.obj.height -= info.obj.oneItemHeight * reduceItem;
		core.drawItemListbox(ctx, info.obj);
		core.drawEquipbox_drawOthers(ctx, info);
		core.drawToolboxRightbar(ctx, info);
		core.setTextBaseline(ctx, "alphabetic");
		core.setTextAlign("left");
	}


	this.drawEquipbox_drawOne = function (ctx, name, id, x, y, width, height, space, font, color, style, lineWidth) {
		if (id) core.drawIcon(ctx, id, x + lineWidth / 2, y + lineWidth / 2, width, height);
		core.strokeRect(ctx, x, y, width + lineWidth, height + lineWidth, style, lineWidth);
		core.setTextAlign(ctx, "center");
		core.setTextBaseline(ctx, "top");
		var tx = (x + x + lineWidth / 2 + width) / 2,
			ty = y + height + lineWidth / 2 * 3 + space;
		core.fillText(ctx, name, tx, ty, color, font);
		core.setTextBaseline(ctx, "alphabetic");
		core.setTextAlign("left");
	}

	this.drawItemListbox_drawItem = function (ctx, left, right, top, height, marginLeft, marginHeight, style, id) {
		var info = core.status.thisUIEventInfo;
		var nowClick = info.index;
		var item = core.material.items[id] || {};
		var name = item.name || "???";
		var num = core.itemCount(id) || 0;
		var fontSize = Math.floor(height - marginHeight * 2);
		core.setTextAlign(ctx, "right");
		var numText = "x" + num;
		core.fillText(ctx, numText, right - marginLeft, top + height / 2, style, core.ui._buildFont(fontSize));
		if (name != "???") core.drawIcon(ctx, id, left + marginLeft, top + marginHeight, fontSize, fontSize);
		var text_x = left + marginLeft + fontSize + 2;
		var maxWidth = right - core.calWidth(ctx, numText) - text_x;
		core.setTextAlign(ctx, "left");
		core.fillText(ctx, name, text_x, top + height / 2, style, core.ui._buildFont(fontSize), maxWidth);
		var todo = new Function("var id = '" + id + "';\ncore.clickItemFunc(id)");
		core.addUIEventListener(left, top, right - left, height, todo);
	}

	this.setPageItems = function (page) {
		var num = itemNum;
		if (core.status.event.id == "equipbox") num -= reduceItem;
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		page = page || info.page;
		var items = core.getToolboxItems(core.status.event.id == "toolbox" ? "all" : "equips");
		info.allItems = items;
		var maxPage = Math.ceil(items.length / num);
		info.maxPage = maxPage;
		var pageItems = items.slice((page - 1) * num, page * num);
		info.pageItems = pageItems;
		info.maxItem = pageItems.length;
		if (items.length == 0 && pageItems.length == 0) info.index = null;
		if (pageItems.length == 0 && info.page > 1) {
			info.page = Math.max(1, info.page - 1);
			return core.setPageItems(info.page);
		}
		return pageItems;
	}

	this.drawToolbox_setExitBtn = function (ctx, x, y, r, style, lineWidth) {
		core.strokeCircle(ctx, x, y, r, style, lineWidth);
		ctx.textAlign = "center";
		ctx.textBaseline = "middle";
		var textSize = Math.sqrt(2) * r;
		core.fillText(ctx, "x", x, y, style, core.ui._buildFont(textSize), textSize);
		core.setTextAlign(ctx, "start");
		core.setTextBaseline(ctx, "top");

		var todo = function () {
			core.closePanel();
		}
		core.addUIEventListener(x - r, y - r, r * 2, r * 2, todo);
	}

	this.drawToolbox_setUseBtn = function (ctx, x, y, r, h, style, lineWidth) {
		core.setTextAlign(ctx, "left");
		core.setTextBaseline(ctx, "top");
		var fontSize = h - 4;
		var font = core.ui._buildFont(fontSize);
		var text = core.status.event.id == "toolbox" ? "使用" : "装备";
		if (core.status.thisUIEventInfo.select.action == "unload") text = "卸下";
		var w = core.calWidth(ctx, text, font) + 2 * r + lineWidth / 2;

		core.strokeRoundRect(ctx, x, y, w, h, r, style, lineWidth);
		core.fillText(ctx, text, x + r, y + lineWidth / 2 + 2, style, font);

		var todo = function () {
			core.useSelectItemInBox();
		}
		core.addUIEventListener(x, y, w, h, todo);
	}

	this.drawItemListbox_setPageBtn = function (ctx, left, right, bottom, r, style, lineWidth) {
		var offset = lineWidth / 2 + r;

		var x = left + offset;
		var y = bottom - offset;
		var pos = Math.sqrt(2) / 2 * (r - lineWidth / 2);
		core.fillPolygon(ctx, [
			[x - pos, y],
			[x + pos - 2, y - pos],
			[x + pos - 2, y + pos]
		], style);
		core.strokeCircle(ctx, x, y, r, style, lineWidth);
		var todo = function () {
			core.addItemListboxPage(-1);
		}
		core.addUIEventListener(x - r - 2, y - r - 2, r * 2 + 4, r * 2 + 4, todo);

		x = right - offset;
		core.fillPolygon(ctx, [
			[x + pos, y],
			[x - pos + 2, y - pos],
			[x - pos + 2, y + pos]
		], style);
		core.strokeCircle(ctx, x, y, r, style, lineWidth);
		var todo = function () {
			core.addItemListboxPage(1);
		}
		core.addUIEventListener(x - r - 2, y - r - 2, r * 2 + 4, r * 2 + 4, todo);
	}

	this.clickItemFunc = function (id) {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		if (info.select.id == id) return core.useSelectItemInBox();
		info.select = {};
		info.select.id = id;
		core.setIndexAndSelect('index');
		core.refreshBox();
	}

	this.clickOneEquipbox = function (id, type) {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		if (info.select.id == id && info.select.type == type) core.useSelectItemInBox();
		else core.status.thisUIEventInfo.select = {
			id: id,
			type: type,
			action: "unload"
		}
		return core.refreshBox();
	}

	core.ui.getToolboxItems = function (cls) {
		var list = Object.keys(core.status.hero.items[cls] || {});
		if (cls == "all") {
			for (var name in core.status.hero.items) {
				if (name == "equips") continue;
				list = list.concat(Object.keys(core.status.hero.items[name]));
			}
			return list.filter(function (id) {
				return !core.material.items[id].hideInToolbox;
			}).sort();
		}

		if (this.uidata.getToolboxItems) {
			return this.uidata.getToolboxItems(cls);
		}
		return list.filter(function (id) {
			return !core.material.items[id].hideInToolbox;
		}).sort();
	}

	this.useSelectItemInBox = function () {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		if (!info.select.id) return;
		var id = info.select.id;
		if (core.status.event.id == "toolbox") {
			core.events.tryUseItem(id);
			// core.closePanel();
		} else if (core.status.event.id == "equipbox") {
			var action = info.select.action || "load";
			info.index = 1;
			if (action == "load") {
				var type = core.getEquipTypeById(id);
				core.loadEquip(id, function () {
					core.status.route.push("equip:" + id);
					info.select.type = type;
					core.setIndexAndSelect("select");
					core.drawEquipbox();
					core.updateStatusBar()
				});
			} else {
				var type = info.select.type;
				core.unloadEquip(type, function () {
					core.status.route.push("unEquip:" + type);
					core.setIndexAndSelect("select");
					core.drawEquipbox();
					core.updateStatusBar()
				});
			}
		}
	}

	this.setIndexAndSelect = function (toChange) {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		core.setPageItems(info.page);
		var index = info.index || 1;
		var items = info.pageItems;
		if (info.select.type) {
			var type = info.select.type;
			id = core.getEquip(type);
			info.index = null;
			info.select = {
				id: id,
				action: "unload",
				type: type
			};
			return;
		} else {
			info.select.type = null;
		}
		if (toChange == "index") info.index = items.indexOf(info.select.id) + 1;
		else {
			var id = info.pageItems[index - 1];
			info.select.id = id;
		}
	}

	this.addItemListboxPage = function (num) {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		var maxPage = info.maxPage || 1;
		info.page = info.page || 1;
		info.page += num;
		if (info.page <= 0) info.page = maxPage;
		if (info.page > maxPage) info.page = 1;
		info.index = 1;
		core.setPageItems(info.page);
		core.setIndexAndSelect("select");
		core.refreshBox();
	}
	core.updateStatusBar()

	this.addItemListboxIndex = function (num) {
		var info = core.status.thisUIEventInfo;
		if (!info) return;
		var maxItem = info.maxItem || 0;
		info.index = info.index || 0;
		info.index += num;
		if (info.index <= 0) info.index = 1;
		if (info.index > maxItem) info.index = maxItem;
		core.setIndexAndSelect("select");
		core.refreshBox();
	}

	this.addEquipboxType = function (num) {
		var info = core.status.thisUIEventInfo;
		var type = info.select.type;
		if (type == null && num > 0) info.select.type = 0;
		else info.select.type = type + num;
		var max = core.status.globalAttribute.equipName.length;
		if (info.select.type >= max) {
			info.select = {};
			return core.addItemListboxPage(0);
		} else {
			var m = Math.abs(info.select.type);
			if (info.select.type < 0) info.select.type = max - m;
			core.refreshBox();
			return;
		}
	}

	core.actions._keyDownToolbox = function (keycode) {
		if (!core.status.thisEventClickArea) return;
		if (keycode == 37) { // left
			core.addItemListboxPage(-1);
			return;
		}
		if (keycode == 38) { // up
			core.addItemListboxIndex(-1);
			return;
		}
		if (keycode == 39) { // right
			core.addItemListboxPage(1);
			return;
		}
		if (keycode == 40) { // down
			core.addItemListboxIndex(1);
			return;
		}
	}

	////// 工具栏界面时，放开某个键的操作 //////
	core.actions._keyUpToolbox = function (keycode) {
		if (keycode == 81) {
			core.ui.closePanel();
			if (core.isReplaying())
				core.control._replay_equipbox();
			else
				core.openEquipbox();
			return;
		}
		if (keycode == 84 || keycode == 27 || keycode == 88) {
			core.closePanel();
			return;
		}
		if (keycode == 13 || keycode == 32 || keycode == 67) {
			var info = core.status.thisUIEventInfo;
			if (info.select) {
				core.useSelectItemInBox();
			}
			return;
		}
	}

	core.actions._keyDownEquipbox = function (keycode) {
		if (!core.status.thisEventClickArea) return;
		if (keycode == 37) { // left
			var info = core.status.thisUIEventInfo;
			if (info.index != null) return core.addItemListboxPage(-1);
			return core.addEquipboxType(-1);
		}
		if (keycode == 38) { // up
			var info = core.status.thisUIEventInfo;
			if (info.index == 1) {
				info.select.type = core.status.globalAttribute.equipName.length - 1;
				core.setIndexAndSelect();
				return core.refreshBox();
			}
			if (info.index) return core.addItemListboxIndex(-1);
			return core.addEquipboxType(-1 * info.equips);
		}
		if (keycode == 39) { // right
			var info = core.status.thisUIEventInfo;
			if (info.index != null) return core.addItemListboxPage(1);
			return core.addEquipboxType(1);
		}
		if (keycode == 40) { // down
			var info = core.status.thisUIEventInfo;
			if (info.index) return core.addItemListboxIndex(1);
			return core.addEquipboxType(info.equips);
		}
	}

	core.actions._keyUpEquipbox = function (keycode, altKey) {
		if (altKey && keycode >= 48 && keycode <= 57) {
			core.items.quickSaveEquip(keycode - 48);
			return;
		}
		if (keycode == 84) {
			core.ui.closePanel();
			if (core.isReplaying())
				core.control._replay_toolbox();
			else
				core.openToolbox();
			return;
		}
		if (keycode == 81 || keycode == 27 || keycode == 88) {
			core.closePanel();
			return;
		}
		if (keycode == 13 || keycode == 32 || keycode == 67) {
			var info = core.status.thisUIEventInfo;
			if (info.select) core.useSelectItemInBox();
			return;
		}
	}

	core.registerAction("ondown", "inEventClickAction", function (x, y, px, py) {
		if (!core.status.thisEventClickArea) return false;
		// console.log(px + "," + py);
		var info = core.status.thisEventClickArea;
		for (var i = 0; i < info.length; i++) {
			var obj = info[i];
			if (px >= obj.x && px <= obj.x + obj.width && py > obj.y && py < obj.y + obj.height) {
				if (obj.todo) obj.todo();
				break;
			}
		}
		return true;
	}, 51);
	core.registerAction("onclick", "stopClick", function () {
		if (core.status.thisEventClickArea) return true;
	}, 51);

	this.addUIEventListener = function (x, y, width, height, todo) {
		if (!core.status.thisEventClickArea) return;
		var obj = {
			x: x,
			y: y,
			width: width,
			height: height,
			todo: todo
		}
		core.status.thisEventClickArea.push(obj);
	}

	this.initThisEventInfo = function () {
		core.status.thisUIEventInfo = {
			page: 1,
			select: {}
		};
		core.status.thisEventClickArea = [];
	}

	this.refreshBox = function () {
		if (!core.status.event.id) return;
		if (core.status.event.id == "toolbox") core.drawToolbox();
		else core.drawEquipbox();
	}

	core.ui.closePanel = function () {
		if (core.status.hero && core.status.hero.flags) {
			// 清除全部临时变量
			Object.keys(core.status.hero.flags).forEach(function (name) {
				if (name.startsWith("@temp@") || /^arg\d+$/.test(name)) {
					delete core.status.hero.flags[name];
				}
			});
		}
		this.clearUI();
		core.maps.generateGroundPattern();
		core.updateStatusBar(true);
		core.unlockControl();
		core.status.event.data = null;
		core.status.event.id = null;
		core.status.event.selection = null;
		core.status.event.ui = null;
		core.status.event.interval = null;
		core.status.thisUIEventInfo = null;
		core.status.thisEventClickArea = null
	}

	this.getItemClsName = function (item) {
		if (item == null) return itemClsName;
		if (item.cls == "equips") {
			if (typeof item.equip.type == "string") return item.equip.type;
			var type = core.getEquipTypeById(item.id);
			return core.status.globalAttribute.equipName[type];
		} else return itemClsName[item.cls] || item.cls;
	}

	core.events.openToolbox = function (fromUserAction) {
		if (core.isReplaying()) return;
		if (!this._checkStatus('toolbox', fromUserAction)) return;
		core.initThisEventInfo();
		core.drawToolbox();
	}

	core.events.openEquipbox = function (fromUserAction) {
		if (core.isReplaying()) return;
		if (!this._checkStatus('equipbox', fromUserAction)) return;
		core.initThisEventInfo();
		core.drawEquipbox();
	}

	core.control._replay_toolbox = function () {
		if (!core.isPlaying() || !core.isReplaying()) return;
		if (!core.status.replay.pausing) return core.drawTip("请先暂停录像");
		if (core.isMoving() || core.status.replay.animate || core.status.event.id)
			return core.drawTip("请等待当前事件的处理结束");

		core.lockControl();
		core.status.event.id = 'toolbox';
		core.drawToolbox();
	}

	core.control._replay_equipbox = function () {
		if (!core.isPlaying() || !core.isReplaying()) return;
		if (!core.status.replay.pausing) return core.drawTip("请先暂停录像");
		if (core.isMoving() || core.status.replay.animate || core.status.event.id)
			return core.drawTip("请等待当前事件的处理结束");

		core.lockControl();
		core.status.event.id = 'equipbox';
		core.drawEquipbox();
	}

	core.control._replayAction_item = function (action) {
		if (action.indexOf("item:") != 0) return false;
		var itemId = action.substring(5);
		if (!core.canUseItem(itemId)) return false;
		if (core.material.items[itemId].hideInReplay || core.status.replay.speed == 24) {
			core.useItem(itemId, false, core.replay);
			return true;
		}
		core.status.event.id = "toolbox";
		core.initThisEventInfo();
		var info = core.status.thisUIEventInfo;
		var items = core.getToolboxItems("all");
		core.setPageItems(1);
		var index = items.indexOf(itemId) + 1;
		info.page = Math.ceil(index / info.maxItem);
		info.index = index % info.maxItem || info.maxItem;
		core.setIndexAndSelect("select");
		core.setPageItems(info.page);
		core.drawToolbox();
		setTimeout(function () {
			core.ui.closePanel();
			core.useItem(itemId, false, core.replay);
		}, core.control.__replay_getTimeout());
		return true;
	}

	core.control._replayAction_equip = function (action) {
		if (action.indexOf("equip:") != 0) return false;
		var itemId = action.substring(6);
		var items = core.getToolboxItems('equips');
		var index = items.indexOf(itemId) + 1;
		if (index < 1) return false;
		core.status.route.push(action);
		if (core.material.items[itemId].hideInReplay || core.status.replay.speed == 24) {
			core.loadEquip(itemId, core.replay);
			core.updateStatusBar()
			return true;
		}
		core.status.event.id = "equipbox";
		core.initThisEventInfo();
		var info = core.status.thisUIEventInfo;
		core.setPageItems(1);
		info.page = Math.ceil(index / info.maxItem);
		info.index = index % info.maxItem || info.maxItem;
		core.setIndexAndSelect("select");
		core.setPageItems(info.page);
		core.drawEquipbox();
		setTimeout(function () {
			core.ui.closePanel();
			core.loadEquip(itemId, core.replay);
		}, core.control.__replay_getTimeout());
		return true;
	}

	core.control._replayAction_unEquip = function (action) {
		if (action.indexOf("unEquip:") != 0) return false;
		var equipType = parseInt(action.substring(8));
		if (!core.isset(equipType)) return false;
		core.status.route.push(action);
		if (core.status.replay.speed == 24) {
			core.unloadEquip(equipType, core.replay);
			return true;
		}
		core.status.event.id = "equipbox";
		core.initThisEventInfo();
		var info = core.status.thisUIEventInfo;
		core.setPageItems(1);
		info.select.type = equipType;
		core.setIndexAndSelect();
		core.drawEquipbox();
		setTimeout(function () {
			core.ui.closePanel();
			core.unloadEquip(equipType, core.replay);
		}, core.control.__replay_getTimeout());
		return true;
	}
	core.registerReplayAction("item", core.control._replayAction_item);
	core.registerReplayAction("equip", core.control._replayAction_equip);
	core.registerReplayAction("unEquip", core.control._replayAction_unEquip);
},
    "漏怪检测": function () {
	// 检查漏怪
	this.checkEnemy = function (floorIds) {
		var enemys = [],
			result = "当前剩余怪物：\n",
			have = false,
			skipEnemy = [], // 略过怪物
			whetherSkip = false;
		switch (floorIds[0]) {
		case 1: // 第一章
			skipEnemy = ["E534", "E597", "E936", "E937", "E1047", "E1048", "E1049", "E845", "E1296"];
			break;
		}
		// 是否为略过怪物
		function skip(enemy) {
			for (var a = 0; a < skipEnemy.length; a++) {
				if (enemy.id == skipEnemy[a]) {
					whetherSkip = true;
				}
			}
			return whetherSkip;
		}
		// 检查漏怪
		for (var i = 1; i < floorIds.length; i++) {
			var floorId = floorIds[i];
			if (core.enemys.getCurrentEnemys(floorId).length > 0) {
				// 若当前地图的怪物数量大于0，则遍历每个图块
				core.status.maps[floorId].blocks.forEach(function (block) {
					if (core.isset(block.event) && !block.disable) {
						var id = block.event.id,
							enemy = core.material.enemys[id];
						if (enemy) { // 是否是怪物 是否略过
							if (!skip(enemy)) {
								if (enemys.length == 0) {
									enemys.push([enemy.id, enemy.name, 1, floorId]);
								} else {
									for (var j = 0; j < enemys.length; j++) { // 是否重复
										if (enemys[j][0] == enemy.id && enemys[j][3] == floorId) {
											enemys[j][2]++; // 重复则数量+1
											have = true;
											break;
										}
									}
									if (!have) { // 不重复新增一项
										enemys.push([enemy.id, enemy.name, 1, floorId]);
									}
									have = false; // 重置
								}
							}
							whetherSkip = false; // 重置
						}
					}
				});
			}
		}
		if (enemys.length > 0) { // 楼层名
			for (var i = 0; i < enemys.length; i++) {
				enemys[i][3] = core.floors[enemys[i][3]].title + "（" + enemys[i][3] + "）";
			}
		}
		if (enemys.length > 0 && enemys.length < 15) { // 输出结果 个数较少
			for (var i = 0; i < enemys.length; i++) {
				result += enemys[i][3] + ":" + enemys[i][1] + " × " + enemys[i][2];
				if (i != enemys.length - 1) result += "\n";
			}
		} else if (enemys.length == 0) { // 没有怪物
			result = "当前无剩余怪物！"
		} else { // 怪物较多
			var number = 0;
			for (var i = 0; i < enemys.length; i++) {
				number += enemys[i][2]; // 总个数
			}
			result = "当前剩余怪物较多，请手动检查，当前剩余" + number + "个\n分布楼层：\n";
			for (var j = 0; j < 100; j++) { // 除去重复楼层
				for (var i = 0; i < enemys.length - 1; i++) {
					if (enemys[i][3] == enemys[i + 1][3]) {
						enemys.splice(i, 1);
					}
				}
			}
			for (var i = 0; i < enemys.length; i++) { // 结果
				result += enemys[i][3];
				if (i != enemys.length - 1) result += "\n";
			}
		}
		core.setFlag("remainEnemy", result); // 赋给flag
		core.setFlag("enemyNumber", enemys.length);
		core.insertAction([{
			"type": "if",
			"condition": "(flag:enemyNumber == 0)",
			"true": [
				"${flag:remainEnemy}",
				"请搜刮地上物资，之后此区域无法返回",
				{ "type": "hide", "remove": true },
			],
			"false": [
				"${flag:remainEnemy}",
			]
		}, ]);
		return;
	}
},
    "platfly": function () {
	// 在此增加新插件
	/* 第一步：复制到插件
	 * 第二步：将flag:usePlatFly改为true可将带地图的楼传启用
	 * 第三步：将flag:__useMinimap__设为true可开启小地图，该操作需切换楼层
	 * 修改小地图的缩放可以修改flag:userScale，默认为1
	 * 注意：楼层转换必须使用楼层坐标，而不是前一楼、后一楼
	 * 关于操作：上楼和下楼操作为PgUp和PgDn，后退10层和前进10层操作为,（<）和.（>）
	 * 注意：请尽量保证地图传送的地方物理位置正好对准（即把地图拼接上箭头位置恰好对齐）否则连线的位置可能不准
	 * 分区说明：用普通事件的楼层转换（红点）代替楼层转换（绿点）即可
	 * 说明：紫色表示目前可以到达却没有到达过的地图（所以这是一个具有探索性的地图插件）
	 */
	// 录像验证直接干掉这个插件
	if (main.replayChecking) return;
	// *** --- 以下数据为用户可修改数据 修改后不影响该插件的基本功能 --- *** //
	// 检测楼层转换的图块id
	var leftPortal = "leftPortal", // 左
		rightPortal = "rightPortal", // 右
		upPortal = "upPortal", // 上
		downPortal = "downPortal", // 下
		upFloor = "upFloor", // 上楼
		downFloor = "downFloor"; // 下楼
	// 一些常用默认值
	var defaultScale = 1, // 默认缩放比率
		defaultLoop = 5, // 绘制地图时的循环检测地图路线次数，loop为5说明最远的地图可以用6步到达
		defaultOpacity = 0.6, // 默认不透明度
		defaultMinorAlpha = defaultOpacity / 2; // 3D绘图时，不与当前层处于同一高度层的默认初始不透明度，不透明度会随着层数的增加或减少而减少
	// *** --- 用户修改区 END --- *** //
	//  其余可自定义内容均用 //***--- 包裹着

	/* -----------------------------------下面是一些调用案例
	 * 
	 * 如果想在状态栏显示可以在状态栏自绘里这么写：
	 core.drawFlyMap(ctx, 你想要的左上角横坐标, 你想要的左上角纵坐标, 你想要的宽度, 你想要的高度, core.status.floorId, {fromUser: true, opacity: 1, loop: 3, use3D:false});
	 * 
	 * -----------------------------------以下为高深区域，如果不必要可以不看
	 * 
	 * 主要函数说明（这几个函数异常强大，善用可以有弄一些有意思的东西，既然作者都说强大了，那就是特别强大）
	 * core.drawFlyMap(ctx : string, x?: number, y?: number, width?:number, height?:number, floorId?:string, config?:any): void
	 * 参数说明：
	 * ctx:画布，如果不存在则会新建x,y,width,height参数的画布
	 * x,y,width,height:画布不存在时创建该数据的画布，如果存在，那么在画布的x,y位置绘制宽度为width，高度为height的地图
	 * floorId:以该楼层为中心绘制
	 * config:配制参数，包括以下内容（该参数为对象）
	 * 	 fromUser:是否循环绘制（为false时只绘制一层，否则绘制5层）
	 * 	 oriFloor:这个不用管就好，具体原理比较复杂，不填或者和floorId一样就行
	 * 	 scale:缩放比率，这个是绝对比率，与画布大小无关，默认为1
	 * 	 interval:地图间的间距，默认为width / 24
	 * 	 deltaH:3D地图的纵向高度差，默认为绘制高度（height）/ 4
	 * 	 noErase:是否不清空画布再绘制，默认为false
	 * 	 fromMini:是否是在小地图上绘制时调用的（无自动缩放和自动定位）
	 * 	 loop:绘制层数，fromUser为true时才有用，默认为5
	 * 	 opacity:不透明度，默认为0.6
	 * 	 minorAlpha:3D地图的不与当前层在同一高度的楼层的初始不透明度，默认为opacity/2
	 * 	 layer:平面模式下绘制的楼层高度，当前所在层为0，上楼则+1，下楼则-1，默认为0，只有当use3D为false且可以绘制3D地图时有效
	 * 	 use3D:是否启用3D绘图，前提是所有地图不都在同一高度，默认为false
	 * 	 reLeft:3D重新定位画布的左位置，默认为-240
	 * 	 reTop:3D重新定位画布的上位置，默认为-240
	 * 	 clearCache:是否清除缓存重算，默认为false
	 * 	 map:这个是最强大的功能了，可以将自定义地图插入，以绘制自定义地图
	 * 	 自定义地图格式：{"left_0_7":"MT1", "right_2_7":"MT2"}以此类推也可以"left_0_7,right_3_7,up_1_0"这种套娃，使用的前提是指定位置得有相应方向的箭头，不然会出错，注意楼层id是到往的楼层的id，如果想绘制3D地图，可以这么写：{"top_1_3,left_0_7": "1_MT1"}，前面的1_必须写，上楼为top，下楼为bottom
	 * 	 默认取自floorId地图
	 * 如有疑问可在造塔群@古祠
	 * 
	 * core.getFlyMap(floorId?:string, fromUser?:boolean, oriFloor?:string, loop?:number):Object
	 * 参数说明:floorId:以该楼层为中心绘制
	 * fromUser:是否循环绘制（为false时只绘制一层，否则绘制5层）
	 * oriFloor:这个不用管就好，具体原理比较复杂，填null或者和floorId一样就行
	 * loop:绘制层数，fromUser为true时才有用，默认为5
	 */

	////// 绘制楼层传送器 //////
	var originDrawFly = core.ui.drawFly;
	ui.prototype.drawFly = function (page) {
		if (!flags.usePlatFly || core.isReplaying()) return originDrawFly.call(core.ui, page);
		core.status.event.data = page;
		var floorId = core.floorIds[page];
		core.clearMap('ui');
		core.setAlpha('ui', 0.85);
		core.fillRect('ui', 0, 0, this.PIXEL, this.PIXEL, '#000000');
		core.setAlpha('ui', 1);
		var size = this.PIXEL;
		//***--- 楼传绘制 可根据自己的需求更改 更改之后注意更改点击操作的函数
		// 背景
		core.drawThumbnail(floorId, null, { ctx: 'ui', x: 0, y: 0, size: size, damage: true, fromFly: true });
		core.fillRect("ui", 0, 65, 32, size - 130, [0, 0, 0, 0.7]);
		core.fillRect("ui", size, 65, -32, size - 130, [0, 0, 0, 0.7]);
		core.fillRect("ui", 65, 0, size / 2 - 114, 32, [0, 0, 0, 0.7]);
		core.fillRect("ui", 65, size, size / 2 - 114, -32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size / 2 + 49, 0, size / 2 - 114, 32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size / 2 + 49, size, size / 2 - 114, -32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size / 2 - 47, 0, 94, 32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size / 2 - 47, size, 94, -32, [0, 0, 0, 0.7]);
		core.fillRect("ui", 0, 0, 63, 32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size, 0, -63, 32, [0, 0, 0, 0.7]);
		core.fillRect("ui", 0, 32, 32, 31, [0, 0, 0, 0.7]);
		core.fillRect("ui", 0, size - 32, 32, -31, [0, 0, 0, 0.7]);
		core.fillRect("ui", 0, size, 63, -32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size, size, -63, -32, [0, 0, 0, 0.7]);
		core.fillRect("ui", size, size - 32, -32, -31, [0, 0, 0, 0.7]);
		core.fillRect("ui", size, 32, -32, 31, [0, 0, 0, 0.7]);
		core.setTextAlign("ui", "center");
		// 文字
		if (core.getFloorByDirection("left", floorId))
			core.fillText("ui", "←", 16, size / 2 + 10, core.hasVisitedFloor(core.getFloorByDirection("left",
				floorId)) ? "#ffffff" : "#ff22ff", "26px Verdana");
		if (core.getFloorByDirection("right", floorId))
			core.fillText("ui", "→", size - 16, size / 2 + 10, core.hasVisitedFloor(core.getFloorByDirection("right",
				floorId)) ? "#ffffff" : "#ff22ff", "26px Verdana");
		if (core.getFloorByDirection("up", floorId))
			core.fillText("ui", "↑", size / 2, 28, core.hasVisitedFloor(core.getFloorByDirection("up",
				floorId)) ? "#ffffff" : "#ff22ff", "26px Verdana");
		if (core.getFloorByDirection("down", floorId))
			core.fillText("ui", "↓", size / 2, size - 4, core.hasVisitedFloor(core.getFloorByDirection("down",
				floorId)) ? "#ffffff" : "#ff22ff", "26px Verdana");
		if (core.getFloorByDirection("top", floorId))
			core.fillText("ui", "上楼", size / 4 + 8, 24, core.hasVisitedFloor(core.getFloorByDirection("top",
				floorId)) ? "#ffffff" : "#ff22ff", "22px " + core.status.globalAttribute.font);
		if (core.getFloorByDirection("bottom", floorId))
			core.fillText("ui", "下楼", size / 4 * 3 - 8, 24, core.hasVisitedFloor(core.getFloorByDirection("bottom",
				floorId)) ? "#ffffff" : "#ff22ff", "22px " + core.status.globalAttribute.font);
		core.fillText("ui", "退10层", size / 4 + 8, size - 8, core.actions._getNextFlyFloor(-1) == page ? "#ff22ff" : "#ffffff",
			"22px " + core.status.globalAttribute.font);
		core.fillText("ui", "进10层", size / 4 * 3 - 8, size - 8, core.actions._getNextFlyFloor(1) == page ? "#ff22ff" : "#ffffff",
			"22px " + core.status.globalAttribute.font);
		core.fillText("ui", "退出", 32, 24, "#ffffff", "22px " + core.status.globalAttribute.font);
		core.fillText("ui", "楼层名", 32, size - 8, "#ffffff", "22px " + core.status.globalAttribute.font);
		core.fillText("ui", "（B）", 16, size - 40, "#ffffff", "22px " + core.status.globalAttribute.font);
		core.createCanvas("mapOnUi", -240, -240, size + 480, size + 480, 150);
		core.drawFlyMap("mapOnUi", 240, 240, size, size, floorId, { fromUser: true, oriFloor: floorId, use3D: flags.use3D });
		if (core.can3D(floorId) && !flags.in3D)
			core.fillText("ui", "3D模式", size - 32, 24, "#ffffff", "20px " + core.status.globalAttribute.font);
		if (flags.in3D)
			core.fillText("ui", "2D模式", size - 32, 24, "#ffffff", "20px " + core.status.globalAttribute.font);
		if (core.can3D(floorId)) core.fillText("ui", "（Z）", size - 16, 56, "#ffffff", "20px " + core.status.globalAttribute.font);
		if (flags.flyTitle) {
			var style = document.getElementById("ui").getContext("2d");
			style.shadowColor = "rgba(0, 0, 0, 1)";
			style.shadowBlur = 5;
			core.fillRect("ui", size / 4, size / 4, size / 2, size / 8, [180, 180, 180, 0.7]);
			core.strokeRect("ui", size / 4, size / 4, size / 2, size / 8, [255, 255, 255, 0.7], 3);
			style.shadowOffsetX = 4;
			style.shadowOffsetY = 2;
			core.fillText("ui", (core.status.maps[floorId] || {}).title, size / 2, size / 16 * 5 + 11, "#ffffff",
				"32px " + core.status.globalAttribute.font);
			style.shadowColor = "none";
			style.shadowBlur = 0;
			style.shadowOffsetX = 0;
			style.shadowOffsetY = 0;
		}
		//***--- 楼传绘制
	};
	////// 楼层传送器界面时的点击操作 //////
	var originClickFly = core.actions._clickFly;
	actions.prototype._clickFly = function (x, y) {
		if (!flags.usePlatFly || core.isReplaying()) return originClickFly.call(core.actions, x, y);
		var page = core.status.event.data;
		var floorId = core.floorIds[page];
		//***--- 点击操作 可以修改的地方只有x,y坐标 其余不可修改
		if (x <= 2 && y <= 1) {
			core.playSound('取消');
			core.deleteCanvas("mapOnUi")
			core.ui.closePanel();
			return;
		}
		// 3D模式
		if (x >= core.__SIZE__ - 2 && y <= 1) {
			if (core.can3D(floorId) && !flags.in3D)
				flags.use3D = true;
			if (flags.in3D) flags.use3D = false;
			core.playSound('光标移动');
			core.ui.drawFly(page);
			return;
		}
		// 显示名称
		if (x <= 1 && y >= core.__SIZE__ - 2) {
			if (flags.flyTitle) flags.flyTitle = false;
			else flags.flyTitle = true;
			core.playSound('光标移动');
			core.ui.drawFly(page);
			return;
		}
		// 飞过去
		if (x > 1 && x < core.__SIZE__ - 1 && y > 1 && y < core.__SIZE__ - 1) {
			if (core.status.maps[core.status.floorId].canFlyFrom &&
				core.status.maps[core.floorIds[core.status.event.data]].canFlyTo &&
				core.hasVisitedFloor(core.floorIds[core.status.event.data])) {
				core.deleteCanvas("mapOnUi");
			}
			core.flyTo(core.floorIds[core.status.event.data]);
		}
		// 前进10层 后退10层
		if (y > core.__SIZE__ - 2 && core.actions._getNextFlyFloor(-1) != page &&
			x >= 2 && x <= Math.floor(core.__SIZE__ / 2) - 2) {
			core.ui.drawFly(this._getNextFlyFloor(-10));
			core.playSound("光标移动");
		}
		if (y > core.__SIZE__ - 2 && core.actions._getNextFlyFloor(1) != page &&
			x >= Math.ceil(core.__SIZE__ / 2) + 1 && x <= core.__SIZE__ - 3) {
			core.ui.drawFly(this._getNextFlyFloor(10));
			core.playSound("光标移动");
		}
		// 获取索引
		function getId(direction) {
			var id = core.getFloorByDirection(direction, floorId);
			for (var i in core.floorIds) {
				if (core.floorIds[i] == id) return parseInt(i);
			}
		}
		// 上下左右和上下楼
		if (x < 1 && core.getFloorByDirection("left", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("left", floorId)) && y >= 2 && y < core.__SIZE__ - 2) {
			core.playSound("光标移动");
			core.drawFly(getId("left"));
		}
		if (x > core.__SIZE__ - 2 && core.getFloorByDirection("right", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("right", floorId)) && y >= 2 && y < core.__SIZE__ - 2) {
			core.playSound("光标移动");
			core.drawFly(getId("right"));
		}
		if (y < 1 && core.getFloorByDirection("up", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("up", floorId)) &&
			x >= Math.floor(core.__SIZE__ / 2) - 1 && x <= Math.ceil(core.__SIZE__ / 2)) {
			core.playSound("光标移动");
			core.drawFly(getId("up"));
		}
		if (y > core.__SIZE__ - 2 && core.getFloorByDirection("down", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("down", floorId)) &&
			x >= Math.floor(core.__SIZE__ / 2) - 1 && x <= Math.ceil(core.__SIZE__ / 2)) {
			core.playSound("光标移动");
			core.drawFly(getId("down"));
		}
		if (y < 1 && x >= 2 && x <= Math.floor(core.__SIZE__ / 2) - 2 &&
			core.getFloorByDirection("top", floorId) && core.hasVisitedFloor(core.getFloorByDirection("top", floorId))) {
			core.playSound("光标移动");
			core.drawFly(getId("top"));
		}
		if (y < 1 && x >= Math.ceil(core.__SIZE__ / 2) + 1 && x <= core.__SIZE__ - 3 &&
			core.getFloorByDirection("bottom", floorId) && core.hasVisitedFloor(core.getFloorByDirection("bottom", floorId))) {
			core.playSound("光标移动");
			core.drawFly(getId("bottom"));
		}
		return;
		//***--- 点击操作
	};
	////// 楼层传送器界面时，按下某个键的操作 //////
	var originKeyDownFly = core.actions._keyDownFly;
	actions.prototype._keyDownFly = function (keycode) {
		if (!flags.usePlatFly || core.isReplaying()) return originKeyDownFly.call(core.actions, keycode);
		var page = core.status.event.data;
		var floorId = core.floorIds[page];
		// 获取索引
		function getId(direction) {
			var id = core.getFloorByDirection(direction, floorId);
			for (var i in core.floorIds) {
				if (core.floorIds[i] == id) return parseInt(i);
			}
		}
		//***--- 按键操作 只可以修改按键的keycode
		if (keycode == 37 && core.getFloorByDirection("left", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("left", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("left"));
		} else if (keycode == 38 && core.getFloorByDirection("up", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("up", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("up"));
		} else if (keycode == 39 && core.getFloorByDirection("right", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("right", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("right"));
		} else if (keycode == 40 && core.getFloorByDirection("down", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("down", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("down"));
		} else if (keycode == 33 && core.getFloorByDirection("top", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("top", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("top"));
		} else if (keycode == 34 && core.getFloorByDirection("bottom", floorId) &&
			core.hasVisitedFloor(core.getFloorByDirection("bottom", floorId))) {
			core.playSound('光标移动');
			core.ui.drawFly(getId("bottom"));
		} else if (keycode == 90) {
			if (core.can3D(floorId) && !flags.in3D)
				flags.use3D = true;
			if (flags.in3D) flags.use3D = false;
			core.playSound('光标移动');
			core.ui.drawFly(page);
		} else if (keycode == 66) { // 地图名
			if (flags.flyTitle) flags.flyTitle = false;
			else flags.flyTitle = true;
			core.playSound('光标移动');
			core.ui.drawFly(page);
		} else if (keycode == 188 && core.actions._getNextFlyFloor(-1) != page) { // 退10层
			core.ui.drawFly(this._getNextFlyFloor(-10));
			core.playSound("光标移动");
		} else if (keycode == 190 && core.actions._getNextFlyFloor(1) != page) { // 进10层
			core.ui.drawFly(this._getNextFlyFloor(10));
			core.playSound("光标移动");
		}
		return;
		//***--- 按键操作
	};
	////// 楼层传送器界面时，放开某个键的操作 //////
	var originKeyUpFly = core.actions._keyUpFly;
	actions.prototype._keyUpFly = function (keycode) {
		if (!flags.usePlatFly || core.isReplaying()) return originKeyUpFly.call(core.actions, keycode);
		if (keycode == 71 || keycode == 27 || keycode == 88) {
			core.playSound('取消');
			core.deleteCanvas("mapOnUi");
			core.ui.closePanel();
		}
		if (keycode == 13 || keycode == 32 || keycode == 67)
			this._clickFly(this.HSIZE - 1, this.HSIZE - 1);
		return;
	};
	////// 点击楼层传送器时的打开操作 //////
	events.prototype.useFly = function (fromUserAction) {
		if (core.isReplaying()) return;

		// 从“浏览地图”页面：尝试直接传送到该层
		if (core.status.event.id == 'viewMaps') {
			if (!core.hasItem('fly')) {
				core.playSound('操作失败');
				core.drawTip('你没有' + core.material.items['fly'].name, 'fly');
			} else if (!core.canUseItem('fly')) {
				core.playSound('操作失败');
				core.drawTip('无法传送到当前层', 'fly');
			} else {
				core.flyTo(core.status.event.data.floorId);
			}
			return;
		}
		if (!this._checkStatus('fly', fromUserAction, true)) {
			core.deleteCanvas('mapOnUi');
			return;
		}
		if (core.flags.flyNearStair && !core.nearStair()) {
			core.playSound('操作失败');
			core.drawTip("只有在楼梯边才能使用" + core.material.items['fly'].name, 'fly');
			core.unlockControl();
			core.status.event.data = null;
			core.status.event.id = null;
			return;
		}
		if (!core.canUseItem('fly')) {
			core.playSound('操作失败');
			core.drawTip(core.material.items['fly'].name + "好像失效了", 'fly');
			core.unlockControl();
			core.status.event.data = null;
			core.status.event.id = null;
			return;
		}
		core.playSound('打开界面');
		core.useItem('fly', true);
		return;
	};
	// 获取区域平面地图
	this.getFlyMap = function (floorId, fromUser, oriFloor, loop, clearCache) {
		floorId = floorId || core.status.floorId;
		if (floorId == oriFloor && !fromUser) return;
		oriFloor = oriFloor || core.status.floorId;
		if (!floorId) return;
		// 判断是否需要缓存
		function needCache(fromUser) {
			if (fromUser && !core.status.flyMap[floorId]) return true;
			if (!fromUser && !core.status.flyMap.cache[floorId]) return true;
			return false;
		}
		// 缓存，加快运行速率
		if (!core.status.flyMap) core.status.flyMap = {};
		if (!core.status.flyMap.cache) core.status.flyMap.cache = {};
		if (!core.status.layer) core.status.layer = {};
		if (!core.status.layer[floorId]) core.status.layer[floorId] = {};
		if (core.status.flyMap.cache[floorId] && fromUser) delete core.status.flyMap.cache[floorId]
		if (core.status.flyMap[floorId] && !fromUser) delete core.status.flyMap[floorId]
		if (needCache(fromUser) || clearCache) {
			// 初始化
			core.status.flyMap[floorId] = {};
			core.status.flyMap[floorId].thisMap = {};
			core.extractBlocks(floorId);
			core.status.maps[floorId].blocks.forEach(function (block) {
				var id = block.event.id;
				var x = block.x,
					y = block.y;
				var trigger = block.event.trigger;
				if (trigger != "changeFloor" && trigger != "upFloor" && trigger != "downFloor") return;
				// 是箭头且可以切换地图
				var toFloor = block.event.data.floorId;
				// 加入相应位置
				// 箭头
				if (id == leftPortal) {
					core.status.flyMap[floorId].thisMap["left_" + x + "_" + y] = toFloor;
				}
				if (id == upPortal) {
					core.status.flyMap[floorId].thisMap["up_" + x + "_" + y] = toFloor;
				}
				if (id == rightPortal) {
					core.status.flyMap[floorId].thisMap["right_" + x + "_" + y] = toFloor;
				}
				if (id == downPortal) {
					core.status.flyMap[floorId].thisMap["down_" + x + "_" + y] = toFloor;
				}
				// 上下楼
				if (id == upFloor) {
					core.status.flyMap[floorId].thisMap["top_" + x + "_" + y] = toFloor;
					core.status.layer[floorId].top = true;
				}
				if (id == downFloor) {
					core.status.flyMap[floorId].thisMap["bottom_" + x + "_" + y] = toFloor;
					core.status.layer[floorId].bottom = true;
				}
			});
			// 把下几层接着检测出来
			if (fromUser) {
				var usedId = {};
				for (var c = 1; c <= loop; c++) {
					for (var i in core.status.flyMap[floorId].thisMap) {
						var link = core.status.flyMap[floorId].thisMap;
						if (!core.hasVisitedFloor(link[i]) || link[i] instanceof Object || usedId[link[i]]) continue;
						usedId[link[i]] = true;
						var next = core.getFlyMap(link[i], false, oriFloor);
						for (var to in next) {
							if (!core.status.layer[next[to]]) core.status.layer[next[to]] = {};
							core.status.flyMap[floorId].thisMap[i + ',' + to] = next[to];
						}
					}
				}
			}
			// 把先上再下之类的去掉
			if (fromUser) {
				for (var i in core.status.flyMap[floorId].thisMap) {
					var route = i.split(",");
					for (var one = 0; one <= route.length - 2; one++) {
						var step = route[one],
							next = route[one + 1];
						if ((step.startsWith("up") && next.startsWith("down")) ||
							(step.startsWith("down") && next.startsWith("up")) ||
							(step.startsWith("left") && next.startsWith("right")) ||
							(step.startsWith("right") && next.startsWith("left")) ||
							(step.startsWith("top") && next.startsWith("bottom")) ||
							(step.startsWith("bottom") && next.startsWith("top"))) {
							delete core.status.flyMap[floorId].thisMap[i];
						}
					}
				}
			}
			// 非当前层不能存此类缓存
			if (!fromUser) {
				core.status.flyMap.cache = {};
				core.status.flyMap.cache[floorId] = {};
				core.status.flyMap.cache[floorId].thisMap = core.status.flyMap[floorId].thisMap;
				delete core.status.flyMap[floorId];
			}
			return fromUser ? core.status.flyMap[floorId].thisMap : core.status.flyMap.cache[floorId].thisMap;
		} else { // 直接使用缓存
			return fromUser ? core.status.flyMap[floorId].thisMap : core.status.flyMap.cache[floorId].thisMap;
		}
	};
	this.can3D = function (floorId) {
		var map = core.getFlyMap(floorId, true, floorId);
		for (var route in map) {
			if (route.indexOf("top") >= 0 || route.indexOf("bottom") >= 0)
				return true;
		}
		return false;
	};
	// 绘制地图
	this.drawFlyMap = function (ctx, x, y, width, height, floorId, config) {
		// 初始化配置项
		//***--- 初始化 可以修改 || 后的默认值 参数说明在开头的高深区域中
		var fromUser = config.fromUser || false,
			oriFloor = config.oriFloor || core.status.floorId,
			scale = config.scale || null,
			interval = config.interval || (width / 24),
			noErase = config.noErase || false,
			fromMini = config.fromMini || false,
			loop = config.loop || defaultLoop,
			opacity = config.opacity || defaultOpacity,
			layer = config.layer || 0,
			use3D = config.use3D || false,
			clearCache = config.clearCache || false,
			map = config.map || null;
		//***--- 初始化
		map = map || core.getFlyMap(floorId, fromUser, oriFloor, loop, clearCache);
		floorId = floorId || core.status.floorId;
		if (!floorId) return;
		// 检测是否需要3D绘图
		if (!fromMini && use3D) {
			for (var route in map) {
				if (route.indexOf("top") >= 0 || route.indexOf("bottom") >= 0) {
					config.map = map;
					return core.draw3DFlyMap(ctx, x, y, width, height, floorId, config);
				}
			}
		}
		if (layer != 0 && !use3D) {
			var canLayer = false
			for (var route in map) {
				if (route.indexOf("top") >= 0 || route.indexOf("bottom") >= 0) {
					canLayer = true;
					break;
				}
			}
			if (!canLayer) layer = 0;
		}
		flags.in3D = false;
		// 初始化
		var userScale = true;
		var newCreate = false;
		if (!scale) {
			userScale = false;
			scale = scale || defaultScale;
		}
		if (!core.dymCanvas[ctx]) {
			core.createCanvas(ctx, x, y, width, height, 140);
			newCreate = true;
		}
		x = x || 0;
		y = y || 0;
		// 获得canvas属性
		width = width || document.getElementById(ctx).width;
		height = height || document.getElementById(ctx).height;
		var oLeft = document.getElementById(ctx).offsetLeft / core.domStyle.scale,
			oTop = document.getElementById(ctx).offsetTop / core.domStyle.scale;
		// 重置大地图和楼传地图的canvas位置
		if (ctx == "mapOnUi") core.relocateCanvas("mapOnUi", -240, -240);
		if (!noErase)
			core.clearMap(ctx);
		var horCenter = Math.floor(width / 2),
			uprCenter = Math.floor(height / 2);
		if (!newCreate) {
			horCenter += x;
			uprCenter += y;
		}
		var centerX = horCenter,
			centerY = uprCenter;
		var left = centerX,
			right = centerX,
			up = centerY,
			down = centerY;
		var used = {};
		var haveLayer = {};
		var nx = horCenter,
			ny = uprCenter;
		// 先把所在楼层绘制了
		if (layer == 0) {
			var nw = core.status.maps[floorId].width * 2 * scale,
				nh = core.status.maps[floorId].height * 2 * scale;
			core.setAlpha(ctx, 1);
			core.fillRect(ctx, centerX - nw / 2, centerY - nh / 2, nw, nh, "#000000");
			core.strokeRect(ctx, centerX - nw / 2, centerY - nh / 2, nw, nh, "#ffff22", 3 * scale);
			// 当前层上下楼显示
			if (!haveLayer[floorId]) {
				core.setAlpha(ctx, 1);
				var needLayer = core.status.layer[floorId];
				if (needLayer.top && needLayer.bottom) {
					core.drawIcon(ctx, "upFloor", centerX - core.__SIZE__ * scale,
						centerY - core.__SIZE__ * scale, core.__SIZE__ * scale, core.__SIZE__ * scale);
					core.drawIcon(ctx, "downFloor", centerX - nw / 2 + core.__SIZE__ * scale,
						centerY - nh / 2 + core.__SIZE__ * scale, core.__SIZE__ * scale, core.__SIZE__ * scale);
				}
				if (needLayer.top && !needLayer.bottom) {
					core.drawIcon(ctx, "upFloor", centerX - Math.min(nw, nh) / 2, centerY - Math.min(nw, nh) / 2,
						Math.min(nw, nh), Math.min(nw, nh));
				}
				if (!needLayer.top && needLayer.bottom) {
					core.drawIcon(ctx, "downFloor", centerX - Math.min(nw, nh) / 2, centerY - Math.min(nw, nh) / 2,
						Math.min(nw, nh), Math.min(nw, nh));
				}
				haveLayer[floorId] = true;
			}
			// 四侧最远位置
			if (left > centerX - nw / 2) left = centerX - nw / 2;
			if (right < centerX + nw / 2) right = centerX + nw / 2;
			if (down < centerY + nh / 2) down = centerY + nh / 2;
			if (up > centerY - nh / 2) up = centerY - nh / 2;
		}
		core.setAlpha(ctx, opacity);
		for (var route in map) { // 绘制楼层和线条
			var rouArr = route.split(",");
			// 检索路线及画线
			// 初始化
			centerX = nx;
			centerY = ny;
			var nowFloor = floorId || core.status.floorId;
			var nowLayer = 0;
			for (var one in rouArr) { // 一个一个检测
				var step = rouArr[one].split("_");
				var cx = step[1],
					cy = step[2];
				// 获得当前图块
				core.getMapBlocksObj(nowFloor, true);
				var nowBlock = core.status.mapBlockObjs[nowFloor][cx + ',' + cy];
				if (!nowBlock) continue;
				var toLoc = nowBlock.event.data.loc,
					toFloor = nowBlock.event.data.floorId;
				var needLayer = core.status.layer[toFloor];
				// 当前层宽度和高度
				var nw = core.status.maps[nowFloor].width * 2 * scale,
					nh = core.status.maps[nowFloor].height * 2 * scale;
				// 目标层宽度和高度
				var tw = core.status.maps[toFloor].width * 2 * scale,
					th = core.status.maps[toFloor].height * 2 * scale;
				// 将当前层变为toFloor
				nowFloor = toFloor;
				// 超范围不画
				if ((centerX > oLeft + x + width || centerX < oLeft + x || centerY > oTop + y + height ||
						centerY < oTop + y) && userScale && !fromMini && ctx != "mapOnUi") continue;
				// 绘制toFloor层
				core.setAlpha(ctx, opacity);
				// 确定center 根据箭头自适配 同时绘制线条 我已经看不懂了
				if (!use3D && (step[0] == "top" || step[0] == "bottom") && layer == 0) break;
				if (step[0] == "top") nowLayer++;
				if (step[0] == "bottom") nowLayer--;
				if (step[0] == 'left') {
					var shouldTo = th / 2,
						realTo = toLoc[1] * 2 * scale;
					var shouldFrom = nh / 2,
						realFrom = step[2] * 2 * scale;
					if (nowLayer == layer) {
						core.drawLine(ctx, centerX - nw / 2, centerY + realFrom - shouldFrom,
							centerX - nw / 2 - interval, centerY + realFrom - shouldFrom, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX - nw / 2, centerY + realFrom - shouldFrom,
							centerX - nw / 2 - interval, centerY + realFrom - shouldFrom, "#000000", 2 * scale);
					}
					centerX -= nw / 2 + tw / 2 + interval;
					centerY += shouldTo - realTo + realFrom - shouldFrom;
				}
				if (step[0] == 'right') {
					var shouldTo = th / 2,
						realTo = toLoc[1] * 2 * scale;
					var shouldFrom = nh / 2,
						realFrom = step[2] * 2 * scale;
					if (nowLayer == layer) {
						core.drawLine(ctx, centerX + nw / 2, centerY + realFrom - shouldFrom,
							centerX + nw / 2 + interval, centerY + realFrom - shouldFrom, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX + nw / 2, centerY + realFrom - shouldFrom,
							centerX + nw / 2 + interval, centerY + realFrom - shouldFrom, "#000000", 2 * scale);
					}
					centerX += nw / 2 + tw / 2 + interval;
					centerY += shouldTo - realTo + realFrom - shouldFrom;
				}
				if (step[0] == 'up') {
					var shouldTo = tw / 2,
						realTo = toLoc[0] * 2 * scale;
					var shouldFrom = nw / 2,
						realFrom = step[1] * 2 * scale;
					if (nowLayer == layer) {
						core.drawLine(ctx, centerX + realFrom - shouldFrom, centerY - nh / 2,
							centerX + realFrom - shouldFrom, centerY - nh / 2 - interval, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX + realFrom - shouldFrom, centerY - nh / 2,
							centerX + realFrom - shouldFrom, centerY - nh / 2 - interval, "#000000", 2 * scale);
					}
					centerY -= nh / 2 + th / 2 + interval;
					centerX += shouldTo - realTo + realFrom - shouldFrom;
				}
				if (step[0] == 'down') {
					var shouldTo = tw / 2,
						realTo = toLoc[0] * 2 * scale;
					var shouldFrom = nw / 2,
						realFrom = step[1] * 2 * scale;
					if (nowLayer == layer) {
						core.drawLine(ctx, centerX + realFrom - shouldFrom, centerY + nh / 2,
							centerX + realFrom - shouldFrom, centerY + nh / 2 + interval, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX + realFrom - shouldFrom, centerY + nh / 2,
							centerX + realFrom - shouldFrom, centerY + nh / 2 + interval, "#000000", 2 * scale);
					}
					centerY += nh / 2 + th / 2 + interval;
					centerX += shouldTo - realTo + realFrom - shouldFrom;
				}
				// 只有和目标层高度相同时才绘制
				if (nowLayer != layer) continue;
				// 超范围的不画
				if ((centerX > oLeft + x + width || centerX < oLeft + x || centerY > oTop + y + height ||
						centerY < oTop + y) && userScale && !fromMini && ctx != "mapOnUi") continue;
				// 四侧最远位置
				if (left > centerX - tw / 2) left = centerX - tw / 2;
				if (right < centerX + tw / 2) right = centerX + tw / 2;
				if (down < centerY + th / 2) down = centerY + th / 2;
				if (up > centerY - th / 2) up = centerY - th / 2;
				// 画过了不画
				if (used[toFloor]) continue;
				used[toFloor] = true;
				// 画地图格
				if (core.hasVisitedFloor(toFloor)) {
					core.fillRect(ctx, centerX - tw / 2, centerY - th / 2, tw, th, "#000000");
					core.strokeRect(ctx, centerX - tw / 2, centerY - th / 2, tw, th, "#ffffff", 3 * scale);
				} else {
					core.fillRect(ctx, centerX - tw / 2, centerY - th / 2, tw, th, "#ff22ff");
					core.strokeRect(ctx, centerX - tw / 2, centerY - th / 2, tw, th, "#ffffff", 3 * scale);
					break;
				}
				// 上下楼显示
				if (haveLayer[toFloor]) continue;
				core.setAlpha(ctx, opacity);
				if (needLayer.top && needLayer.bottom) {
					core.drawIcon(ctx, "upFloor", centerX - core.__SIZE__ * scale,
						centerY - core.__SIZE__ * scale, core.__SIZE__ * scale, core.__SIZE__ * scale);
					core.drawIcon(ctx, "downFloor", centerX - tw / 2 + core.__SIZE__ * scale,
						centerY - th / 2 + core.__SIZE__ * scale, core.__SIZE__ * scale, core.__SIZE__ * scale);
				}
				if (needLayer.top && !needLayer.bottom) {
					core.drawIcon(ctx, "upFloor", centerX - Math.min(tw, th) / 2, centerY - Math.min(tw, th) / 2,
						Math.min(tw, th), Math.min(tw, th));
				}
				if (!needLayer.top && needLayer.bottom) {
					core.drawIcon(ctx, "downFloor", centerX - Math.min(tw, th) / 2, centerY - Math.min(tw, th) / 2,
						Math.min(tw, th), Math.min(tw, th));
				}
				haveLayer[toFloor] = true;
			}
		}
		// 自动缩放
		if ((right - left > core.__PIXELS__ - 64 || down - up > core.__PIXELS__ - 64) && !userScale && !fromMini) {
			scale = 1 / (Math.max(right - left, down - up) / (core.__PIXELS__ - 64));
			var con = { fromUser: fromUser, oriFloor: oriFloor, scale: scale, interval: interval * scale, layer: layer, opacity: opacity, loop: loop };
			return core.drawFlyMap(ctx, x, y, width, height, floorId, con);
		}
		// 大地图和楼层地图自适配定位
		if (ctx == "mapOnUi" && !fromMini && (left - nx < -128 || right - nx > 128 ||
				up - ny < -128 || down - ny > 128)) {
			core.relocateCanvas("mapOnUi", -240 + (-left - right + 2 * nx) / 2, -240 + (-up - down + 2 * ny) / 2);
		}
	};
	// 3D绘图
	this.draw3DFlyMap = function (ctx, x, y, width, height, floorId, config) {
		// 初始化配置项
		//***--- 初始化 同上一个初始化
		var fromUser = config.fromUser || false,
			oriFloor = config.oriFloor || core.status.floorId,
			scale = config.scale || null,
			interval = config.interval || (width / 24),
			deltaH = config.deltaH || (height / 8),
			noErase = config.noErase || false,
			fromMini = config.fromMini || false,
			loop = config.loop || defaultLoop,
			opacity = config.opacity || defaultOpacity,
			minorAlpha = config.minorAlpha || defaultMinorAlpha,
			reLeft = config.reLeft || -240,
			reTop = config.reTop || -240,
			clearCache = config.clearCache || false,
			map = config.map || null;
		//***--- 初始化
		map = map || core.getFlyMap(floorId, fromUser, oriFloor, loop, clearCache);
		// 当前层是否一个人在一层
		var alone = true;
		for (var route in map) {
			if (route.startsWith("left") || route.startsWith("right") ||
				route.startsWith("up") || route.startsWith("down")) {
				alone = false;
				break;
			}
		}
		// 是则增加一个先上再下的路径
		if (alone) {
			for (var route in map) {
				if (route.startsWith("top")) {
					var first = route.split(",")[0].split("_");
					break;
				}
			}
			var success = false;
			core.getMapBlocksObj(nowFloor, true);
			var nowBlock = core.status.mapBlockObjs[floorId][first[1] + "," + first[2]];
			var toFloor = nowBlock.event.data.floorId;
			core.extractBlocks(toFloor);
			core.status.maps[toFloor].blocks.forEach(function (block) {
				var id = block.event.id;
				var x = block.x,
					y = block.y;
				var trigger = block.event.trigger;
				if (trigger != "changeFloor") return;
				if (id == "downFloor") {
					map["top_" + first[1] + "_" + first[2] + "," + "bottom_" + x + "_" + y] = floorId;
					success = true;
					return;
				}
			});
			// 添加先上再下失败 尝试先下再上
			if (!success) {
				for (var route in map) {
					if (route.startsWith("bottom")) {
						var first = route.split(",")[0].split("_");
						break;
					}
				}
				var nowBlock = core.status.mapBlockObjs[floorId][first[1] + "," + first[2]];
				var toFloor = nowBlock.event.data.floorId;
				core.extractBlocks(toFloor);
				core.status.maps[toFloor].blocks.forEach(function (block) {
					var id = block.event.id;
					var x = block.x,
						y = block.y;
					var trigger = block.event.trigger;
					if (trigger != "changeFloor") return;
					if (id == "upFloor") {
						map["bottom_" + first[1] + "_" + first[2] + "," + "top_" + x + "_" + y] = floorId;
						success = true;
						return;
					}
				});
			}
		}
		floorId = floorId || core.status.floorId;
		if (!floorId) return;
		flags.in3D = true;
		// 初始化
		// 获得排序过的楼层路径
		map = core.sortFloor(map);
		map = map.map;
		var userScale = true;
		var newCreate = false;
		if (!scale) {
			userScale = false;
			scale = scale || defaultScale;
		}
		if (!core.dymCanvas[ctx]) {
			core.createCanvas(ctx, x, y, width, height, 140);
			newCreate = true;
		}
		x = x || 0;
		y = y || 0;
		// 获得canvas属性
		width = width || document.getElementById(ctx).width;
		height = height || document.getElementById(ctx).height;
		// 重置canvas位置
		core.relocateCanvas(ctx, reLeft, reTop);
		if (!noErase)
			core.clearMap(ctx);
		var horCenter = Math.floor(width / 2),
			uprCenter = Math.floor(height / 2);
		if (!newCreate) {
			horCenter += x;
			uprCenter += y;
		}
		// 单元格的中心点 即水平线中点处
		var centerX = horCenter,
			centerY = uprCenter;
		var left = centerX,
			right = centerX,
			up = centerY,
			down = centerY;
		var used = {};
		var nx = horCenter,
			ny = uprCenter;
		// 开始绘制
		for (var i = 0; i < map.length; i++) {
			var route = map[i][0];
			var nowLayer = map[i][1];
			var everyLayer = 0;
			route = route.split(",");
			// 每条路线初始化
			centerX = horCenter;
			centerY = uprCenter;
			centerX += core.status.maps[floorId].height * scale * Math.SQRT2 / 4;
			if (flags.viewingLayer) {
				centerY += deltaH * flags.viewingLayer;
			}
			var nowFloor = floorId || core.status.floorId;
			for (var one = 0; one < route.length; one++) {
				var step = route[one].split("_");
				var cx = step[1],
					cy = step[2];
				// 检测高度，是否与nowLayer一致 不一致在处理完center以后不绘制
				if (step[0] == "top") everyLayer++;
				if (step[0] == "bottom") everyLayer--;
				// 获得当前图块
				core.getMapBlocksObj(nowFloor, true);
				var nowBlock = core.status.mapBlockObjs[nowFloor][cx + ',' + cy];
				if (!nowBlock) continue;
				var toLoc = nowBlock.event.data.loc,
					toFloor = nowBlock.event.data.floorId;
				// 当前层宽度和高度
				// 斜二测画法
				var nw = core.status.maps[nowFloor].width * 2 * scale,
					nh = core.status.maps[nowFloor].height * scale * Math.SQRT2 / 2;
				// 目标层宽度和高度
				var tw = core.status.maps[toFloor].width * 2 * scale,
					th = core.status.maps[toFloor].height * scale * Math.SQRT2 / 2;
				if (!(toLoc instanceof Array)) {
					toLoc = [Math.floor(tw / 4 / scale), Math.floor(th / 4 / scale)];
				}
				// 绘制当前层
				if (nowLayer == 0 && !used[floorId]) {
					core.setAlpha(ctx, 1);
					used[floorId] = true;
					var nowW = core.status.maps[floorId].width * 2 * scale;
					var nowH = core.status.maps[floorId].height * scale * Math.SQRT2 / 2;
					var nodes = [
						[centerX - nowW / 2 - nowH / 2, centerY + nowH / 2],
						[centerX + nowW / 2 - nowH / 2, centerY + nowH / 2],
						[centerX + nowW / 2 + nowH / 2, centerY - nowH / 2],
						[centerX - nowW / 2 + nowH / 2, centerY - nowH / 2]
					];
					core.fillPolygon(ctx, nodes, "#000000");
					core.strokePolygon(ctx, nodes, "#ffff22", 1.5 * scale);
					// 四侧最远位置
					if (left > centerX - nw / 2 - nh / 2 && nowLayer == (flags.viewingLayer || 0)) left = centerX - nw / 2 - nh / 2;
					if (right < centerX + nw / 2 + nh / 2 && nowLayer == (flags.viewingLayer || 0)) right = centerX + nw / 2 + nh / 2;
				}
				// 将当前层变为toFloor
				var fromFloor = nowFloor;
				nowFloor = toFloor;
				// 计算center 画同层间的线 我已经看不懂了
				// 设置不透明度
				if (nowLayer == (flags.viewingLayer || 0)) {
					core.setAlpha(ctx, opacity);
				} else {
					core.setAlpha(ctx, minorAlpha * Math.max(0, 1 - 0.34 * Math.abs(nowLayer - (flags.viewingLayer || 0))));
				}
				if (step[0] == "left") {
					var shouldFrom = nh / 2,
						realFrom = cy * scale * Math.SQRT2 / 2;
					var shouldTo = th / 2,
						realTo = toLoc[1] * scale * Math.SQRT2 / 2;
					if (everyLayer == nowLayer && !used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy])
						core.drawLine(ctx, centerX - nw / 2 + nh / 2 - realFrom, centerY + realFrom - shouldFrom,
							centerX - nw / 2 - interval + nh / 2 - realFrom, centerY + realFrom - shouldFrom, "#ffffff", 2 * scale);
					centerX -= nw / 2 + tw / 2 + interval + shouldTo - realTo + realFrom - shouldFrom;
					centerY += shouldTo - realTo + realFrom - shouldFrom;
				}
				if (step[0] == "right") {
					var shouldFrom = nh / 2,
						realFrom = cy * scale * Math.SQRT2 / 2;
					var shouldTo = th / 2,
						realTo = toLoc[1] * scale * Math.SQRT2 / 2;
					if (nowLayer == everyLayer && !used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy])
						core.drawLine(ctx, centerX + nw / 2 + nh / 2 - realFrom, centerY + realFrom - shouldFrom,
							centerX + nw / 2 + interval + nh / 2 - realFrom, centerY + realFrom - shouldFrom, "#ffffff", 2 * scale);
					centerX += nw / 2 + tw / 2 + interval - (shouldTo - realTo + realFrom - shouldFrom);
					centerY += shouldTo - realTo + realFrom - shouldFrom;
				}
				if (step[0] == "up") {
					var shouldTo = tw / 2,
						realTo = toLoc[0] * scale * 2;
					var shouldFrom = nw / 2,
						realFrom = cx * scale * 2;
					if (nowLayer == everyLayer && !used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy])
						core.drawLine(ctx, centerX + realFrom - shouldFrom + nh / 2, centerY - nh / 2, centerX + realFrom -
							shouldFrom + interval * Math.SQRT2 / 4 + nh / 2, centerY - nh / 2 - interval * Math.SQRT2 / 4, "#ffffff", 2 * scale);
					centerY -= nh / 2 + th / 2 + interval * Math.SQRT2 / 4;
					centerX += shouldTo - realTo + realFrom - shouldFrom + (nh / 2 + th / 2 + interval * Math.SQRT2 / 4);
				}
				if (step[0] == "down") {
					var shouldTo = tw / 2,
						realTo = toLoc[0] * scale * 2;
					var shouldFrom = nw / 2,
						realFrom = cx * scale * 2;
					if (nowLayer == everyLayer && !used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy])
						core.drawLine(ctx, centerX + realFrom - shouldFrom - nh / 2, centerY + nh / 2, centerX + realFrom -
							shouldFrom - interval * Math.SQRT2 / 4 - nh / 2, centerY + nh / 2 + interval * Math.SQRT2 / 4, "#ffffff", 2 * scale);
					centerY += nh / 2 + th / 2 + interval * Math.SQRT2 / 4;
					centerX += shouldTo - realTo + realFrom - shouldFrom - (nh / 2 + th / 2 + interval * Math.SQRT2 / 4);
				}
				if (step[0] == "top") {
					centerY -= deltaH;
				}
				if (step[0] == "bottom") {
					centerY += deltaH;
				}
				if (everyLayer == nowLayer && step[0] != "top" && step[0] != "bottom") {
					used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy] = true;
					used[toFloor + "_" + fromFloor + "_" + toLoc[0] + "_" + toLoc[1]] = true;
				}
				if (everyLayer != nowLayer) continue;
				// 四侧最远位置
				if (!flags.viewingLayer) {
					if (left > centerX - tw / 2 - th / 2 && nowLayer == (flags.viewingLayer || 0)) left = centerX - tw / 2 - th / 2;
					if (right < centerX + tw / 2 + th / 2 && nowLayer == (flags.viewingLayer || 0)) right = centerX + tw / 2 + th / 2;
					if (down < centerY + th / 2 && nowLayer == (flags.viewingLayer || 0)) down = centerY + th / 2;
					if (up > centerY - th / 2 && nowLayer == (flags.viewingLayer || 0)) up = centerY - th / 2;
				}
				// 不同高度层之间的连线
				if (!used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy]) {
					core.setAlpha(ctx, opacity * Math.max(0, 1 - 0.34 * Math.abs(nowLayer - (flags.viewingLayer || 0))));
					if (step[0] == "top") {
						core.drawLine(ctx, centerX, centerY + deltaH, centerX, centerY, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX, centerY + deltaH, centerX, centerY, "#000000", 2 * scale);
						used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy] = true;
						used[toFloor + "_" + fromFloor + "_" + toLoc[0] + "_" + toLoc[1]] = true;
					}
				}
				if (!used[toFloor]) {
					used[toFloor] = true;
					// 设置不透明度
					if (nowLayer == (flags.viewingLayer || 0)) {
						core.setAlpha(ctx, opacity);
					} else {
						core.setAlpha(ctx, minorAlpha * Math.max(0, 1 - 0.34 * Math.abs(nowLayer - (flags.viewingLayer || 0))));
					}
					// 画地图
					var nodes = [
						[centerX - tw / 2 - th / 2, centerY + th / 2], // 左下
						[centerX + tw / 2 - th / 2, centerY + th / 2], // 右下
						[centerX + tw / 2 + th / 2, centerY - th / 2], // 右上
						[centerX - tw / 2 + th / 2, centerY - th / 2] // 左上
					];
					if (core.hasVisitedFloor(toFloor)) {
						core.fillPolygon(ctx, nodes, "#000000");
					} else {
						core.fillPolygon(ctx, nodes, "#ff22ff");
					}
					core.strokePolygon(ctx, nodes, "#ffffff", 1.5 * scale);
				}
				// 不同高度层之间的连线
				if (!used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy]) {
					if (step[0] == "bottom") {
						core.drawLine(ctx, centerX, centerY, centerX, centerY - deltaH, "#ffffff", 5 * scale);
						core.drawLine(ctx, centerX, centerY, centerX, centerY - deltaH, "#000000", 2 * scale);
						used[fromFloor + "_" + toFloor + "_" + cx + "_" + cy] = true;
						used[toFloor + "_" + fromFloor + "_" + toLoc[0] + "_" + toLoc[1]] = true;
					}
				}
			}
		}
		// 自动缩放
		if ((right - left > core.__PIXELS__ - 64 || down - up > core.__PIXELS__ - 64) && !userScale && !fromMini) {
			scale = 1 / (Math.max(right - left, down - up) / (core.__PIXELS__ - 64));
			var con = { fromUser: fromUser, oriFloor: oriFloor, scale: scale, interval: interval * scale, opacity: opacity, loop: loop, use3D: true };
			return core.draw3DFlyMap(ctx, x, y, width, height, floorId, con);
		}
		// 大地图和楼层地图自适配定位
		if (ctx == "mapOnUi")
			core.relocateCanvas("mapOnUi", -240 + (-left - right + 2 * nx) / 2, -240 + (-up - down + 2 * ny) / 2);
	};
	// 不同高度楼层排序
	this.sortFloor = function (map) {
		map = map || core.getFlyMap(null, true);
		var totalLayer = 1,
			topLayer = 0,
			bottomLayer = 0,
			nowLayer = 0;
		// 拆分map
		for (var i in map) {
			var route = i.split(",");
			nowLayer = 0;
			for (var one in route) {
				var step = route[one].split("_");
				// 层数处理 并记录每一层的层数
				if (step[0] == "top") {
					nowLayer++;
					map[i] = nowLayer + "_" + map[i];
					if (nowLayer > topLayer) topLayer = nowLayer;
				}
				if (step[0] == "bottom") {
					nowLayer--;
					map[i] = nowLayer + "_" + map[i];
					if (nowLayer < bottomLayer) bottomLayer = nowLayer;
				}
			}
		}
		// 总层数
		totalLayer = topLayer - bottomLayer + 1;
		// 按楼层高度由低到高排序
		// 先变成数组
		var mapArr = [];
		for (var one in map) {
			mapArr.push([one, parseInt(map[one]) || 0]);
		}
		// 再sort
		mapArr.sort(function (a, b) { return a[1] - b[1]; });
		return { map: mapArr, totalLayer: totalLayer, top: topLayer, bottom: bottomLayer };
	};
	// 由方向获得楼层坐标
	this.getFloorByDirection = function (direction, floorId) {
		floorId = floorId || core.status.floorId;
		var route = core.getFlyMap(floorId);
		for (var step in route) {
			if (step.indexOf(direction) >= 0) {
				return route[step];
			}
		}
		return null;
	};
	////// 转换楼层结束的事件 检查小地图 //////
	var originAfterChangeFloor = core.events.afterChangeFloor;
	events.prototype.afterChangeFloor = function (floorId) {
		if (!flags.__useMinimap__ || core.isReplaying()) {
			core.deleteCanvas("minimap");
			core.deleteCanvas("mapArrow");
			core.unregisterAction("ondown", "closeMinimap");
			core.unregisterAction("ondown", "openMinimap");
			return originAfterChangeFloor.call(core.events, floorId);
		}
		if (main.mode != 'play') return;
		this.eventdata.afterChangeFloor(floorId);
		// 防止小地图出问题
		core.unregisterAction("ondown", "closeMinimap");
		core.unregisterAction("ondown", "openMinimap");
		// 切换小地图
		core.checkMinimap(true, true);
		return;
	};
	////// 瞬间移动 检查小地图 //////
	var originMoveDirectly = core.control.moveDirectly;
	control.prototype.moveDirectly = function (destX, destY, ignoreSteps) {
		if (!flags.__useMinimap__ || core.isReplaying())
			return originMoveDirectly.call(core.control, destX, destY, ignoreSteps);
		var canMoveDirectly = this.controldata.moveDirectly(destX, destY, ignoreSteps);
		if (canMoveDirectly) core.checkMinimap();
		return canMoveDirectly;
	};
	////// 每移动一格后执行的事件 检查小地图 //////
	var originMoveOneStep = core.control.moveOneStep;
	control.prototype.moveOneStep = function (callback) {
		if (!flags.__useMinimap__ || core.isReplaying())
			return originMoveOneStep.call(core.control, callback);
		this.controldata.moveOneStep(callback);
		core.checkMinimap();
	};
	// 检查小地图开闭情况 改变小地图位置
	this.checkMinimap = function (fromUser, reDraw) {
		if (!flags.__useMinimap__ || core.isReplaying()) {
			core.unregisterAction("ondown", "closeMinimap");
			core.unregisterAction("ondown", "openMinimap");
			core.deleteCanvas("mapArrow");
			core.deleteCanvas("minimap");
			return;
		}
		reDraw = reDraw || false;
		// 是否重绘
		if (reDraw) {
			if (flags.minimap) core.drawMinimap(flags.__onLeft__);
			else core.drawClosedMap(flags.__onLeft__);
		}
		var hx = core.status.hero.loc.x;
		var opened = flags.minimap;
		var onLeft = hx >= Math.ceil(core.__SIZE__ / 3 * 2);
		fromUser = fromUser || false; // 开关小地图相关
		if (!flags.__onLeft__) flags.__onLeft__ = false;
		// 如果地图上没有小地图 画到右边
		if (!core.dymCanvas.mapArrow && !core.dymCanvas.minimap && !reDraw) {
			if (flags.minimap) core.drawMinimap();
			else core.drawClosedMap();
			flags.__onLeft__ = false;
		}
		// 人物在中间 不执行
		if (hx >= Math.ceil(core.__SIZE__ / 3 + core.bigmap.offsetX / 32) &&
			hx <= Math.floor(core.__SIZE__ / 3 * 2 + core.bigmap.offsetX / 32)) return;
		// 重定位画布 和 翻转
		// 挪到右边
		if (!onLeft && (flags.__onLeft__ || fromUser)) {
			flags.__onLeft__ = false;
			if (opened) {
				core.relocateCanvas("minimap", core.__PIXELS__ - 120, 0);
				core.relocateCanvas("mapArrow", core.__PIXELS__ - 140, 0);
				document.getElementById('mapArrow').style.transform = 'none';
			} else {
				core.relocateCanvas("minimap", core.__PIXELS__, 0);
				core.relocateCanvas("mapArrow", core.__PIXELS__ - 20, 0);
				document.getElementById('mapArrow').style.transform = 'none';
			}
		}
		// 挪到左边
		if (onLeft && (!flags.__onLeft__ || fromUser)) {
			flags.__onLeft__ = true;
			if (opened) {
				core.relocateCanvas("minimap", 0, 0);
				core.relocateCanvas("mapArrow", 120, 0);
				document.getElementById('mapArrow').style.transform = 'rotateY(180deg)';
			} else {
				core.relocateCanvas("minimap", -120, 0);
				core.relocateCanvas("mapArrow", 0, 0);
				document.getElementById('mapArrow').style.transform = 'rotateY(180deg)';
			}
		}
	};
	// 点击小地图的action
	this.registerMinimapAction = function (open) {
		if (!open) {
			core.registerAction("ondown", "closeMinimap", function (x, y, px, py) {
				if (!flags.__onLeft__) {
					if (px >= core.__PIXELS__ - 140 && px <= core.__PIXELS__ - 120 &&
						py >= 0 && py <= 120) {
						core.closeMinimap();
						core.unregisterAction("ondown", "closeMinimap");
						return true;
					}
					if (px >= core.__PIXELS__ - 120 && py <= 120) {
						core.playSound("打开界面");
						core.drawTotalMap();
						return true;
					}
				} else {
					if (px >= 120 && px <= 140 && py >= 0 && py <= 120) {
						core.closeMinimap();
						core.unregisterAction("ondown", "closeMinimap");
						return true;
					}
					if (px <= 120 && py <= 120) {
						core.playSound("打开界面");
						core.drawTotalMap();
						return true;
					}
				}
			}, 10);
		} else {
			core.registerAction("ondown", "openMinimap", function (x, y, px, py) {
				if (!flags.__onLeft__) {
					if (px >= core.__PIXELS__ - 20 && py <= 120) {
						core.openMinimap();
						core.unregisterAction("ondown", "openMinimap");
						return true;
					}
				} else {
					if (px <= 20 && py <= 120) {
						core.openMinimap();
						core.unregisterAction("ondown", "openMinimap");
						return true;
					}
				}
			}, 10);
		}
	};
	// 地图上的小地图
	this.drawMinimap = function (toLeft) {
		if (!flags.__useMinimap__) {
			core.deleteCanvas("mapArrow");
			core.deleteCanvas("minimap");
			return;
		}
		var scale = 1.3 / core.status.thisMap.width * 15 * (flags.userScale || 1);
		if (1.3 / core.status.thisMap.height * 15 * (flags.userScale || 1) < scale)
			scale = 1.3 / core.status.thisMap.height * 15 * (flags.userScale || 1);
		// 绘制
		core.createCanvas("minimap", core.__PIXELS__ - 120, 0, 120, 120, 100);
		core.createCanvas("mapArrow", core.__PIXELS__ - 140, 0, 20, 120, 100);
		if (toLeft) {
			core.relocateCanvas("minimap", 0, 0);
			core.relocateCanvas("mapArrow", 120, 0);
			document.getElementById('mapArrow').style.transform = 'rotateY(180deg)';
		}
		core.clearMap("minimap");
		core.clearMap("mapArrow");
		// 黑色底
		core.fillRect("minimap", 0, 0, 120, 120, [0, 0, 0, 0.6]);
		var config = { fromUser: true, oriFloor: core.status.floorId, scale: scale, interval: 10, noErase: true, fromMini: true };
		core.drawFlyMap("minimap", 0, 0, 120, 120, core.status.floorId, config);
		// 向右箭头
		core.fillRect("mapArrow", 0, 0, 20, 120, [230, 230, 230, 0.9]);
		core.drawLine("mapArrow", 0, 20, 20, 20, [100, 100, 100, 0.9], 2);
		core.drawLine("mapArrow", 0, 100, 20, 100, [100, 100, 100, 0.9], 2);
		core.setTextAlign("mapArrow", "center");
		core.fillText("mapArrow", ">", 10, 67, [100, 100, 100, 0.9], "20px Verdana");
		core.registerMinimapAction(false);
	};
	// 关闭小地图
	this.closeMinimap = function () {
		if (!flags.__useMinimap__) {
			core.deleteCanvas("mapArrow");
			core.deleteCanvas("minimap");
			return;
		}
		var onLeft = flags.__onLeft__;
		var frame = 0;
		var x = core.__PIXELS__,
			a = 0.096,
			speed = 4.8;
		if (onLeft) {
			x = 260;
			a = -a;
			speed = -speed;
		}
		var interval = setInterval(function () {
			core.relocateCanvas("mapArrow", x - 140, 0);
			if (!onLeft)
				core.relocateCanvas("minimap", x - 120, 0);
			else core.relocateCanvas("minimap", x - 260, 0);
			speed -= a;
			x += speed;
			if (frame == 50) {
				flags.minimap = false;
				clearInterval(interval);
				core.drawClosedMap(onLeft);
				core.checkMinimap(true);
			}
			frame++;
		}, 20);
	};
	// 合上的小地图
	this.drawClosedMap = function (toLeft) {
		if (!flags.__useMinimap__) {
			core.deleteCanvas("mapArrow");
			core.deleteCanvas("minimap");
			return;
		}
		var scale = 1.3 / core.status.thisMap.width * 15 * (flags.userScale || 1);
		if (1.3 / core.status.thisMap.height * 15 * (flags.userScale || 1) < scale)
			scale = 1.3 / core.status.thisMap.height * 15 * (flags.userScale || 1);
		// 绘制
		core.createCanvas("minimap", core.__PIXELS__, 0, 120, 120, 100);
		core.createCanvas("mapArrow", core.__PIXELS__ - 20, 0, 20, 120, 100);
		core.clearMap("minimap");
		core.clearMap("mapArrow");
		if (toLeft) {
			core.relocateCanvas("minimap", -120, 0);
			core.relocateCanvas("mapArrow", 0, 0);
			document.getElementById('mapArrow').style.transform = 'rotateY(180deg)';
		}
		// 黑色底
		core.fillRect("minimap", 0, 0, 120, 120, [0, 0, 0, 0.6]);
		var config = { fromUser: true, oriFloor: core.status.floorId, scale: scale, interval: 10, noErase: true, fromMini: true };
		core.drawFlyMap("minimap", 0, 0, 120, 120, core.status.floorId, config);
		// 向左箭头
		core.fillRect("mapArrow", 0, 0, 20, 120, [230, 230, 230, 0.9]);
		core.drawLine("mapArrow", 0, 20, 20, 20, [100, 100, 100, 0.9], 2);
		core.drawLine("mapArrow", 0, 100, 20, 100, [100, 100, 100, 0.9], 2);
		core.setTextAlign("mapArrow", "center");
		core.fillText("mapArrow", "<", 10, 67, [100, 100, 100, 0.9], "20px Verdana");
		core.registerMinimapAction(true);
	};
	// 打开小地图
	this.openMinimap = function () {
		if (!flags.__useMinimap__) {
			core.deleteCanvas("mapArrow");
			core.deleteCanvas("minimap");
			return;
		}
		var onLeft = flags.__onLeft__;
		var frame = 0;
		var x = 120 + core.__PIXELS__,
			a = 0.096,
			speed = 4.8;
		if (onLeft) {
			x = 140;
			a = -a;
			speed = -speed;
		}
		var interval = setInterval(function () {
			core.relocateCanvas("mapArrow", x - 140, 0);
			if (!flags.__onLeft__)
				core.relocateCanvas("minimap", x - 120, 0);
			else core.relocateCanvas("minimap", x - 260, 0);
			speed -= a;
			x -= speed;
			if (frame == 50) {
				flags.minimap = true;
				clearInterval(interval);
				core.drawMinimap(onLeft);
				core.checkMinimap(true);
			}
			frame++;
		}, 20);
	};
	// 大地图
	this.drawTotalMap = function (floorId) {
		floorId = floorId || core.status.floorId;
		core.status.event.id = "totalMap";
		core.lockControl();
		if (!flags.viewingLayer) flags.viewingLayer = 0;
		var loop = 5;
		if (flags.worldMap) loop = core.floorIds.length;
		// 大地图时点击和键盘操作
		core.registerAction("ondown", "onDownTmap", function (x, y) {
			if (core.status.event.id == "totalMap") {
				if (y < 1 && x <= Math.floor(core.__SIZE__ / 2) - 2) { // 上移一层
					if (flags.viewingLayer < core.sortFloor().top) {
						flags.viewingLayer++;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				if (y < 1 && x >= Math.ceil(core.__SIZE__ / 2) + 1) { // 下移一层
					if (flags.viewingLayer > core.sortFloor().bottom) {
						flags.viewingLayer--;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				if (y < 1 && x < Math.ceil(core.__SIZE__ / 2) + 1 && x > Math.floor(core.__SIZE__ / 2) - 2) {
					// 区域地图
					if (flags.worldMap) {
						flags.worldMap = false;
						flags.viewingLayer = 0;
					} else flags.worldMap = true;
					core.playSound('光标移动');
					core.drawTotalMap();
					return true;
				}
				if (y >= core.__SIZE__ - 1 && x <= Math.floor(core.__SIZE__ / 2)) { // 3D
					if (core.can3D(floorId) && !flags.in3D) flags.use3D = true;
					if (flags.in3D) flags.use3D = false;
					flags.mapHint = false;
					core.playSound('光标移动');
					core.drawTotalMap();
					return true;
				}
				if (y >= core.__SIZE__ - 1 && x >= Math.ceil(core.__SIZE__ / 2)) { // hint
					if (flags.in3D) {
						if (!flags.mapHint) flags.mapHint = true;
						else flags.mapHint = false;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				flags.viewingLayer = 0;
				core.playSound("取消")
				core.deleteCanvas("mapOnUi");
				core.deleteCanvas("back");
				core.deleteCanvas("tips");
				core.closePanel();
				core.unregisterAction("ondown", "onDownTmap");
				return true;
			}
		}, 110);
		core.registerAction("keyUp", "keyUpTmap", function (keycode) {
			if (core.status.event.id == "totalMap") {
				if (keycode == 33) { // PgUp
					if (flags.viewingLayer < core.sortFloor().top) {
						flags.viewingLayer++;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				if (keycode == 34) { // PgDn
					if (flags.viewingLayer > core.sortFloor().bottom) {
						flags.viewingLayer--;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				if (keycode == 90) { // Z
					if (core.can3D(floorId) && !flags.in3D) flags.use3D = true;
					if (flags.in3D) flags.use3D = false;
					flags.mapHint = false;
					core.playSound('光标移动');
					core.drawTotalMap();
					return true;
				}
				if (keycode == 84) { // T
					if (flags.in3D) {
						if (!flags.mapHint) flags.mapHint = true;
						else flags.mapHint = false;
						core.playSound('光标移动');
						core.drawTotalMap();
					}
					return true;
				}
				if (keycode == 87) { // W
					if (flags.worldMap) {
						flags.worldMap = false;
						flags.viewingLayer = 0;
					} else flags.worldMap = true;
					core.playSound('光标移动');
					core.drawTotalMap();
					return true;
				}
				flags.viewingLayer = 0;
				core.playSound("取消")
				core.deleteCanvas("mapOnUi");
				core.deleteCanvas("back");
				core.deleteCanvas("tips");
				core.closePanel();
				core.unregisterAction("keyUp", "keyUpTmap");
				return true;
			}
		}, 110);
		// 开始画
		core.createCanvas("mapOnUi", -240, -240, core.__PIXELS__ + 480, core.__PIXELS__ + 480, 150);
		core.createCanvas("back", -240, -240, core.__PIXELS__ + 480, core.__PIXELS__ + 480, 140);
		core.createCanvas("tips", 0, 0, core.__PIXELS__, core.__PIXELS__, 160);
		var ctx = document.getElementById("tips").getContext("2d");
		ctx.shadowOffsetX = 0;
		ctx.shadowOffsetY = 0;
		ctx.shadowBlur = 5;
		ctx.shadowColor = "rgba(100, 100, 255, 1)";
		core.fillRect("back", -240, -240, core.__PIXELS__ + 480, core.__PIXELS__ + 480, [0, 0, 0, 0.9]);
		core.fillRect("tips", 0, 0, core.__PIXELS__ / 2 - 50, 32, [200, 200, 200, 0.8]);
		core.fillRect("tips", core.__PIXELS__ / 2 + 50, 0, core.__PIXELS__ / 2 - 50, 32, [200, 200, 200, 0.8]);
		core.fillRect("tips", core.__PIXELS__ / 2 - 46, 0, 92, 32, [200, 200, 200, 0.8]);
		core.drawLine("tips", 0, 32, core.__PIXELS__ / 2 - 50, 32, [50, 50, 50, 0.8], 3);
		core.drawLine("tips", core.__PIXELS__ / 2 + 50, 32, core.__PIXELS__, 32, [50, 50, 50, 0.8], 3);
		core.drawLine("tips", core.__PIXELS__ / 2 - 46, 32, core.__PIXELS__ / 2 + 46, 32, [50, 50, 50, 0.8], 3);
		core.fillRect("tips", 0, core.__PIXELS__, core.__PIXELS__ / 2 - 5, -32, [200, 200, 200, 0.8]);
		core.fillRect("tips", core.__PIXELS__ / 2 + 5, core.__PIXELS__, core.__PIXELS__ / 2 - 5, -32, [200, 200, 200, 0.8]);
		core.drawLine("tips", 0, core.__PIXELS__ - 32, core.__PIXELS__ / 2 - 5, core.__PIXELS__ - 32, [50, 50, 50, 0.8], 3);
		core.drawLine("tips", core.__PIXELS__ / 2 + 5, core.__PIXELS__ - 32, core.__PIXELS__, core.__PIXELS__ - 32, [50, 50, 50, 0.8], 3);
		core.setTextAlign("tips", "center");
		core.fillText("tips", "上移一层", core.__PIXELS__ / 4 - 23, 24, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		core.fillText("tips", "下移一层", core.__PIXELS__ / 4 * 3 + 23, 24, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		core.fillText("tips", flags.worldMap ? "小地图" : "区域地图", core.__PIXELS__ / 2, 24, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		core.drawFlyMap("mapOnUi", 240, 240, core.__PIXELS__, core.__PIXELS__,
			floorId, { fromUser: true, opacity: 1, oriFloor: floorId, noErase: true, use3D: flags.use3D, layer: flags.viewingLayer, loop: loop, clearCache: true });
		if (flags.in3D)
			core.fillText("tips", "参考线（T）", core.__PIXELS__ / 4 * 3, core.__PIXELS__ - 8, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		if (core.can3D(floorId) && !flags.in3D)
			core.fillText("tips", "3D模式（Z）", core.__PIXELS__ / 4, core.__PIXELS__ - 8, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		if (flags.in3D)
			core.fillText("tips", "2D模式（Z）", core.__PIXELS__ / 4, core.__PIXELS__ - 8, [255, 255, 255, 0.8], "24px " + core.status.globalAttribute.font);
		if (flags.mapHint) {
			core.drawLine("back", 240, 240 + core.__PIXELS__, 240 + core.__PIXELS__, 240, [100, 100, 240, 0.4], 2);
			core.drawLine("back", 240 + core.__PIXELS__ / 2, 240, 240 + core.__PIXELS__ / 2, 240 + core.__PIXELS__, [100, 100, 240, 0.4], 2);
			core.drawLine("back", 240, 240 + core.__PIXELS__ / 2, 240 + core.__PIXELS__, 240 + core.__PIXELS__ / 2, [100, 100, 240, 0.4], 2);
		}
	};
},
    "合成": function () {
	// 在此增加新插件
	/* 第一步：把这个插件完整复制到插件里面
	 * 第二步：在道具里面添加prize和material属性（最好在配置表格里面加，一劳永逸，不想要价格可以在下面注释中写的地方把相应代码注释掉）
	 * 第三步：为道具加总价（prize）这个自己算，不能自动算
	 * 第四步：添加材料（material）格式：[[道具id, 个数],[道具id, 个数]]二维数组
	 * 第五步：在switch里面添加相应shopId对应的可合成装备列表
	 * 第六步：如果你使用的是13×13样板，可能需要自己调整一下ui，注释写得已经比较清楚了
	 * 第七步：调用：core.equipmentSynthesis(shopId);
	 */
	// 装备合成界面
	this.equipmentSynthesis = function (shopId) {
		var equipmentList = [], // 装备列表
			materialList = [], // 材料列表
			pages = 1, // 总页码
			select = 1, // 选择光标 1~7装备列表 8上一页 9下一页 10合成 11退出
			currentEquipment = 1, // 当前装备
			currentPage = 1; // 当前页码
		// 获得装备列表
		switch (shopId) {
		case 1: // 第一章
			equipmentList = ["I788", "I790", "I792"];
			break;
		case 2: // 第二章
			equipmentList = ["I450", "I445", "I416", "I477", "I886", "I934", "I1007"];
			break;
		}
		// 总页码数
		pages = Math.ceil(equipmentList.length / 7);
		// 获得材料列表
		for (var i = 0; i < equipmentList.length; i++) {
			materialList.push(core.material.items[equipmentList[i]].material);
		}
		// 绘制
		this.drawEquipment = function () {
			if (select <= 7) {
				currentEquipment = (currentPage - 1) * 7 + select;
			}
			// 创建及清空画布
			core.createCanvas("equipment", 0, 0, core.__PIXELS__, core.__PIXELS__, 130);
			core.clearMap("equipment");
			// 绘制界面
			core.setTextAlign('uievent', 'left');
			core.setTextBaseline('uievent', 'top');
			core.fillRect("equipment", 0, 0, core.__PIXELS__, core.__PIXELS__, "#000000");
			core.drawWindowSkin("winskin.png", "equipment", 0, 0, 160, core.__PIXELS__ - 160); // 装备窗口
			core.drawWindowSkin("winskin.png", "equipment", 160, 0, core.__PIXELS__ - 160, core.__PIXELS__ - 160); // 材料窗口
			core.drawWindowSkin("winskin.png", "equipment", 0, core.__PIXELS__ - 160, core.__PIXELS__, 160); // 说明窗口
			// 上一页 下一页
			if (pages > 1) {
				if (currentPage > 1) {
					core.fillText("equipment", "上一页", 16, core.__PIXELS__ - 168, "#FFFFFF", "16px " + core.status.globalAttribute.font);
				}
				if (currentPage < pages) {
					core.fillText("equipment", "下一页", 96, core.__PIXELS__ - 168, "#FFFFFF", "16px " + core.status.globalAttribute.font);
				}
			}
			// 合成 退出
			core.fillText("equipment", "合成", 270, core.__PIXELS__ - 168, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			core.fillText("equipment", "退出", 342, core.__PIXELS__ - 168, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			// 绘制装备列表
			if (currentPage != pages || equipmentList.length % 7 == 0) {
				for (var i = 0; i < 7; i++) {
					core.drawIcon("equipment", equipmentList[i + (currentPage - 1) * 7], 8, 40 * i + 8);
					core.fillText("equipment", core.material.items[equipmentList[i + (currentPage - 1) * 7]].name, 48, 40 * i + 31, "#FFFFFF", "18px " + core.status.globalAttribute.font);
				}
			} else {
				for (var i = 0; i < equipmentList.length % 7; i++) {
					core.drawIcon("equipment", equipmentList[i + (currentPage - 1) * 7], 8, 40 * i + 8);
					core.fillText("equipment", core.material.items[equipmentList[i + (currentPage - 1) * 7]].name, 48, 40 * i + 31, "#FFFFFF", "18px " + core.status.globalAttribute.font);
				}
			}
			// 绘制材料列表
			core.fillText("equipment", "材料", 236, 24, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			core.fillText("equipment", "个数", core.__PIXELS__ - 140, 24, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			core.fillText("equipment", "拥有", core.__PIXELS__ - 72, 24, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			for (var i = 0; i < materialList[currentEquipment - 1].length; i++) {
				core.drawIcon("equipment", materialList[currentEquipment - 1][i][0], 172, 40 * i + 40);
				core.fillText("equipment", core.material.items[materialList[currentEquipment - 1][i][0]].name, 212, 40 * i + 62, "#FFFFFF", "18px " + core.status.globalAttribute.font);
				core.fillText("equipment", materialList[currentEquipment - 1][i][1], core.__PIXELS__ - 130, 40 * i + 62, "#FFFFFF", "20px " + core.status.globalAttribute.font);
				core.fillText("equipment", (core.itemCount(materialList[currentEquipment - 1][i][0])),
					core.__PIXELS__ - 61, 40 * i + 61, "#FFFFFF", "20px " + core.status.globalAttribute.font);
			}
			// 绘制说明
			core.drawIcon("equipment", equipmentList[currentEquipment - 1], 8, core.__PIXELS__ - 152);
			core.fillText("equipment", core.material.items[equipmentList[currentEquipment - 1]].name, 50, core.__PIXELS__ - 130, "#FFFFFF", "20px " + core.status.globalAttribute.font);
			// 不想用价格可以把下面这一行注释掉
			core.fillText("equipment", "价格：" + core.material.items[equipmentList[currentEquipment - 1]].prize, core.__PIXELS__ - 128, core.__PIXELS__ - 130, "#FFFFFF", "16px " + core.status.globalAttribute.font);
			core.drawTextContent("equipment", core.material.items[equipmentList[currentEquipment - 1]].text, { left: 8, top: core.__PIXELS__ - 116, maxWidth: core.__PIXELS__ - 16, color: "#FFFFFF" });
			// 绘制选择光标
			if (select <= 7) {
				core.drawUIEventSelector(0, "winskin.png", 4, 40 * (select - 1) + 4, 152, 40, 135);
			} else if (select == 8) {
				core.drawUIEventSelector(0, "winskin.png", 12, core.__PIXELS__ - 184, 58, 20, 135);
			} else if (select == 9) {
				core.drawUIEventSelector(0, "winskin.png", 92, core.__PIXELS__ - 184, 58, 20, 135);
			} else if (select == 10) {
				core.drawUIEventSelector(0, "winskin.png", 266, core.__PIXELS__ - 184, 39, 20, 135);
			} else if (select == 11) {
				core.drawUIEventSelector(0, "winskin.png", 338, core.__PIXELS__ - 184, 39, 20, 135);
			}
		};
		// 键盘操作
		this.keyboardAction = function (keycode) {
			switch (keycode) {
			case 37: // Left
				if (select <= 8) break;
				if (select == 9) { // 下一页
					if (currentPage == 1) break;
					else select--;
					break;
				}
				if (select == 11) { // 退出
					select--;
					break;
				}
				if (select == 10) { // 合成
					select = currentEquipment % 7;
					if (currentEquipment % 7 == 0) {
						select = 7;
					}
					break;
				}
				break;
			case 38: // Up
				if (select == 1 || select == 10 || select == 11) break;
				if (select > 1 && select <= 7) { // 装备列表
					select--;
					break;
				}
				if (select == 8 || select == 9) { // 上一页 下一页
					select = 7;
					if ((currentPage - 1) * 7 + select > equipmentList.length) {
						select = equipmentList.length % 7;
					}
					break;
				}
				break;
			case 39: // Right
				if (select <= 7) { // 装备列表
					select = 10;
					break;
				}
				if (select == 9 || select == 10) { // 下一页 合成
					select++;
					break;
				}
				if (select == 8) { // 上一页
					if (currentPage == pages) {
						select += 2;
					} else {
						select++;
					}
					break;
				}
				if (select == 11) break;
				break;
			case 40: // Down
				if ((currentPage == pages && select < equipmentList.length % 7) ||
					(equipmentList.length % 7 == 0 && select < 7)) { // 装备列表
					select++;
					break;
				}
				if (currentPage == pages && select == equipmentList.length % 7) { // 最后一页最下面的装备选项
					if (currentPage > 1) {
						select = 8;
						break;
					}
					break;
				}
				if (currentPage < pages) { // 当前页小于总页数
					if (select == 7 && currentPage == 1) {
						select += 2;
						break;
					}
					if (select < 7) {
						select++;
						break;
					}
					if (select == 7 && currentPage != 1) {
						select++;
					}
				}
				if (select >= 8) break;
				break;
			case 33: // PageUp
				if (currentPage > 1) {
					currentPage--;
					break;
				}
				break;
			case 34: // PageDown
				if (currentPage < pages) {
					currentPage++;
					if (currentEquipment + 7 > equipmentList.length) {
						select = equipmentList.length % 7;
					}
					break;
				}
				break;
			case 32: // SpaceBar
				if (select == 8) { // 上一页
					currentPage--;
					if (currentPage == 1) {
						select = 7;
					}
					break;
				}
				if (select == 9) { // 下一页
					currentPage++;
					if ((currentPage - 1) * 7 + select > equipmentList.length) {
						select = equipmentList.length % 7;
					}
					break;
				}
				if (select == 10 || select <= 7) { // 合成
					this.synthesize();
					break;
				}
				if (select == 11) { // 退出
					core.insertAction({ "type": "break" });
					break;
				}
				break;
			case 13: // Enter
				if (select == 8) { // 上一页
					currentPage--;
					if (currentPage == 1) {
						select = 7;
					}
					break;
				}
				if (select == 9) { // 下一页
					currentPage++;
					if ((currentPage - 1) * 7 + select > equipmentList.length) {
						select = equipmentList.length % 7;
					}
					break;
				}
				if (select == 10 || select <= 7) { // 合成
					this.synthesize();
					break;
				}
				if (select == 11) { // 退出
					core.insertAction({ "type": "break" });
					break;
				}
				break;
			case 27: // Esc
				core.insertAction({ "type": "break" });
				break;
			case 88: // X
				core.insertAction({ "type": "break" });
				break;
			case 67: // C
				if (select == 8) { // 上一页
					currentPage--;
					if (currentPage == 1) {
						select = 7;
					}
					break;
				}
				if (select == 9) { // 下一页
					currentPage++;
					if ((currentPage - 1) * 7 + select > equipmentList.length) {
						select = equipmentList.length % 7;
					}
					break;
				}
				if (select == 10 || select <= 7) { // 合成
					this.synthesize();
					break;
				}
				if (select == 11) { // 退出
					core.insertAction({ "type": "break" });
					break;
				}
				break;
			}
		};
		// 点击操作
		this.clickAction = function (px, py) {
			// 装备栏
			if (px >= 4 && px <= 156 && py >= 4 && py <= core.__PIXELS__ - 196) {
				var sequence;
				sequence = Math.ceil((py - 4) / 40);
				if (sequence == select) {
					this.synthesize();
				} else {
					if (currentPage != pages || equipmentList.length % 7 == 0) {
						select = sequence;
					} else {
						if (sequence <= equipmentList.length % 7) {
							select = sequence;
						}
					}
				}
				return;
			}
			// 上一页
			if (px >= 12 && px <= 70 && py >= core.__PIXELS__ - 184 && py <= core.__PIXELS__ - 164 && currentPage != 1 && currentPage > 1) {
				currentPage--;
				if (currentPage == 1) select = 1;
				return;
			}
			// 下一页
			if (px >= 92 && px <= 150 && py >= core.__PIXELS__ - 184 && py <= core.__PIXELS__ - 164 && currentPage != pages && currentPage < pages) {
				currentPage++;
				if (currentPage == pages) select = 1;
				return;
			}
			// 合成
			if (px >= 266 && px <= 305 && py >= core.__PIXELS__ - 184 && py <= core.__PIXELS__ - 164) {
				this.synthesize();
				return;
			}
			// 退出
			if (px >= 338 && px <= 377 && py >= core.__PIXELS__ - 184 && py <= core.__PIXELS__ - 164) {
				core.insertAction({ "type": "break" });
				return;
			}
		};
		// 玩家操作
		this.equipmentShopAction = function () {
			if (flags.type == 0) return this.keyboardAction(flags.keycode);
			else return this.clickAction(flags.px, flags.py);
		};
		// 合成操作
		this.synthesize = function () {
			core.setFlag("canSynthesize", true); // 是否可以合成
			for (var i = 0; i < materialList[currentEquipment - 1].length; i++) {
				if (core.itemCount(materialList[currentEquipment - 1][i][0]) < materialList[currentEquipment - 1][i][1]) {
					core.setFlag("canSynthesize", false);
				}
			}
			// 获得合成后的装备
			this.getNewEquipment = function () {
				core.insertAction([
					"合成成功！请退出后按Q键在背包中查看",
				]);
				// 得到新装备
				core.addItem(equipmentList[currentEquipment - 1], 1);
				// 减去材料
				for (var i = 0; i < materialList[currentEquipment - 1].length; i++) {
					core.addItem(materialList[currentEquipment - 1][i][0], -materialList[currentEquipment - 1][i][1]);
				}
			};
			core.insertAction([{
				"type": "confirm",
				"text": "确认要合成吗?",
				"yes": [{
					"type": "if",
					"condition": "flag:canSynthesize == true",
					"true": [
						{ "type": "function", "function": "function() {core.plugin.getNewEquipment();}" },
						{ "type": "playSound", "name": "item.mp3" },
					],
					"false": [
						"材料不足，无法合成！"
					]
				}, ],
				"no": []
			}, ]);
		};
		// 插入事件
		core.insertAction([{
				"type": "while",
				"condition": "true",
				"data": [
					{ "type": "function", "function": "function () { core.plugin.drawEquipment(); }" },
					{ "type": "wait" },
					{ "type": "function", "function": "function() { core.plugin.equipmentShopAction(); }" }
				]
			},
			{
				"type": "function",
				"function": "function () { core.deleteCanvas('equipment'); core.ui.clearUIEventSelector(); }"
			}
		]);
	}
},
    "zdsq": function () {
	// 自動拾取
	var enable = true;
	if (!enable) return;

	// 
	// var noUpdate = false;
	////// 更新状态栏 ////// 不建议状态栏刷新后触发 容易导致录像不一致的问题
	//control.prototype.updateStatusBar = function (doNotCheckAutoEvents) {
	//	if (!core.isPlaying()) return;
	//	if (noUpdate) return;
	//	noUpdate = true;
	//	core.autoGetItem();
	//	noUpdate = false;
	//	this.controldata.updateStatusBar();
	//	if (!doNotCheckAutoEvents) core.checkAutoEvents();
	//	this._updateStatusBar_setToolboxIcon();
	//	core.clearRouteFolding();
	//}

	////// 每移动一格后执行的事件 //////
	/*
	control.prototype.moveOneStep = function (callback) {
		if (core.getBgNumber() != 6 || core.hasEquip('I932')) core.autoGetItem();
		return this.controldata.moveOneStep(callback);
	}
	*/

	function bfsFlood(sx, sy, blockfn) {
		var canMoveArray = core.generateMovableArray();
		var blocksObj = core.getMapBlocksObj();
		var bgMap = core.getBgMapArray();

		var visited = [],
			queue = [];
		visited[sx + "," + sy] = 0;
		queue.push(sx + "," + sy);

		while (queue.length > 0) {
			var now = queue.shift().split(","),
				x = ~~now[0],
				y = ~~now[1];
			for (var direction in core.utils.scan) {
				if (!core.inArray(canMoveArray[x][y], direction)) continue;
				var nx = x + core.utils.scan[direction].x,
					ny = y + core.utils.scan[direction].y,
					nindex = nx + "," + ny;
				if (visited[nindex]) continue;
				if (core.onSki(bgMap[ny][nx])) continue;
				if (blockfn && !blockfn(blocksObj, nx, ny)) continue;
				visited[nindex] = visited[now] + 1;
				queue.push(nindex);
			}
		}
	}

	function attractAnimate() {
		var name = 'attractAnimate';
		var isPlaying = false;
		this.nodes = [];

		this.add = function (id, x, y, callback) {
			this.nodes.push({ id: id, x: x, y: y, callback: callback });
		}
		this.start = function () {
			if (isPlaying) return;
			isPlaying = true;
			core.registerAnimationFrame(name, true, this.update);
			this.ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 120);
		}
		this.remove = function () {
			core.unregisterAnimationFrame(name);
			core.deleteCanvas(name);
			isPlaying = false;
		}
		this.clear = function () {
			this.nodes = [];
			this.remove();
		}
		var lastTime = -1;
		var self = this;
		this.update = function (timeStamp) {
			if (lastTime < 0) lastTime = timeStamp;
			if (timeStamp - lastTime < 20) return;
			lastTime = timeStamp;
			core.clearMap(name);
			var cx = core.status.heroCenter.px - 16,
				cy = core.status.heroCenter.py - 16;
			var thr = 5; //缓动比例倒数 越大移动越慢
			self.nodes.forEach(function (n) {
				var dx = cx - n.x,
					dy = cy - n.y;
				if (Math.abs(dx) <= thr && Math.abs(dy) <= thr) {
					n.dead = true;
				} else {
					n.x += ~~(dx / thr);
					n.y += ~~(dy / thr);
				}
				core.drawIcon(name, n.id, n.x, n.y, 32, 32);
			});
			self.nodes = self.nodes.filter(function (n) {
				if (n.dead && n.callback) {
					n.callback();
				}
				return !n.dead;
			});
			if (self.nodes.length == 0)
				self.remove();
		}
	}


	var animateHwnd = new attractAnimate();

	this.stopAttractAnimate = function () {
		animateHwnd.clear();
	}

	this.autoGetItem = function () {
		if (core.getFlag("zdsq", 0) == 0) return;
		//if () return;
		//core.setFlag("loopAutoGetItem", 1);
		var blockfn = function (blockMap, x, y) {
			var idx = x + ',' + y;
			if (idx in canGetItems) return false;
			var blk = blockMap[idx];
			if (blk && !blk.disable && blk.event.cls == 'items' && !core.isMapBlockDisabled(core.status.floorId, blk.x, blk.y) && blk.event.trigger == 'getItem') {
				canGetItems[idx] = { x: x, y: y, id: blk.event.id };
				return !core.status.checkBlock.damage[idx] && !core.status.checkBlock.ambush[idx] && !core.status.checkBlock.repulse[idx];
			}
			return core.maps._canMoveDirectly_checkNextPoint(blockMap, x, y);
		};
		core.setFlag("loopAutoGetItem", 1);
		//while (core.getFlag("loopAutoGetItem", 0) == 1) {
		//for (var i = 0; i < 2; i++) {
		var canGetItems = {};
		if (!core.status.floorId || !core.status.checkBlock.damage || core.status.event.id == 'action' || core.status.lockControl) return;
		// if (Object.keys(core.status.checkBlock.damage).indexOf(core.status.hero.loc.x + "," + core.status.hero.loc.y) != -1) return

		bfsFlood(core.getHeroLoc('x'), core.getHeroLoc('y'), blockfn);
		for (var k in canGetItems) {
			var x = canGetItems[k].x,
				y = canGetItems[k].y,
				id = canGetItems[k].id;
			core.trigger(x, y);
			//core.getItem(id, null, x, y);
			if (!core.isReplaying()) animateHwnd.add(id, x * 32, y * 32);
		}
		//bfsFlood(core.getHeroLoc('x'), core.getHeroLoc('y'), blockfn);
		//if (canGetItems == {}) core.setFlag("loopAutoGetItem", 0);
		if (!core.isReplaying()) animateHwnd.start();
		//if (canGetItems == {}) core.setFlag("loopAutoGetItem", 0);
		//}
	}
},
    "warning": function () {
	// warning
	// 初始化
	if (main.replayChecking) return;
	var defaultSound = 'warning.wav';
	this.startWarning = function (x, y, boss) {
		if (core.isReplaying()) return;
		core.playSound(defaultSound);
		x = x || 0;
		y = y || 0;
		// DANGER显示层
		core.createCanvas("DANGER", 32 * x + 240, 32 * y - 32, 480, 200, 100);
		var ctx = document.getElementById("DANGER").getContext("2d");
		ctx.shadowOffsetX = 0;
		ctx.shadowOffsetY = 0;
		ctx.shadowBlur = 10;
		ctx.shadowColor = "rgba(255, 50, 50, 1)";
		core.fillText("DANGER", "DANGER", 4, 32, "#ffffff", "40px normal");
		if (boss) core.fillText("DANGER", boss, 60, 80, "#ffffff", "30px normal")
		ctx.shadowOffsetX = 10;
		ctx.shadowOffsetY = 5;
		ctx.shadowColor = "rgba(255, 50, 50, 1)";
		core.fillText("DANGER", "DANGER", 4, 32, "#ffffff", "40px normal");
		if (boss) core.fillText("DANGER", boss, 60, 80, "#ffffff", "30px normal")
		ctx.shadowColor = "rgba(0, 0, 0, 1)";
		core.fillText("DANGER", "DANGER", 4, 32, "#ffffff", "40px normal");
		if (boss) core.fillText("DANGER", boss, 60, 80, "#ffffff", "30px normal")
		core.playSound("DANGER.mp3");
		core.updateWarning(x, y);
	};
	// 更新每一帧
	this.updateWarning = function (x, y) {
		var frame = 0,
			nx = 7 * 32 + 240,
			ny = 32 * 7 - 32,
			dx = 0,
			dy = 0,
			scale = 1;
		var interval = window.setInterval(function () {
			// 速度 双曲余弦
			var speed = core.hyperbolicCosine(frame / 20 - 3.25);
			nx -= speed;
			frame++;
			// DANGER定位
			core.relocateCanvas("DANGER", nx, ny);
			// 画布缩放
			for (var one in core.dom.gameCanvas) {
				var ctx = core.dom.gameCanvas[one].style;
				if (!ctx) continue;
				if (one >= 6 && one <= 9) continue;
				scale += frame > 75 ? (-core.hyperbolicCosine(frame / 1000 - 0.075) + 1) * 1.5 :
					(core.hyperbolicCosine(frame / 1000 - 0.075) - 1) * 1.5;
				ctx.transform = "scale(" + scale + ")";
				dx += frame > 75 ? (-core.hyperbolicCosine(frame / 1000 - 0.075) + 1) * 48 * (7 - x) :
					(core.hyperbolicCosine(frame / 1000 - 0.075) - 1) * 48 * (7 - x);
				dy += frame > 75 ? (-core.hyperbolicCosine(frame / 1000 - 0.075) + 1) * 48 * (7 - y) :
					(core.hyperbolicCosine(frame / 1000 - 0.075) - 1) * 48 * (7 - y);
				ctx.transform += "translate(" + dx + "px, " + dy + "px)";
			}
			if (frame == 150) {
				clearInterval(interval);
				core.deleteCanvas("DANGER");
			}
		}, 20);
	};
},
    "章节": function () {
	// 章节显示
	var chapter = "",
		description = "";
	// 显示章节
	this.displayChapter = function (index) {
		if (core.isReplaying()) return;
		var number = core.replaceNumberWithChinese(index);
		// 获取第几章
		chapter = "第" + number + "章";
		if (index == 0) chapter = "序章";
		// 获取描述
		switch (index) {
		case 0:
			description = "起源";
			break;
		case 1:
			description = "勇气";
			break;
		case 2:
			description = "智慧";
			break;
		}
		core.coreChapterAnimate(chapter, description);
	};
	// 替换数字大小写
	this.replaceNumberWithChinese = function (number) {
		if (number == 0) return "零";
		if (number == 1) return "一";
		if (number == 2) return "二";
		if (number == 3) return "三";
		if (number == 4) return "四";
		if (number == 5) return "五";
		if (number == 6) return "六";
		if (number == 7) return "七";
		if (number == 8) return "八";
		if (number == 9) return "九";
		if (number == 10) return "十";
	};
	// 核心动画运算
	this.coreChapterAnimate = function (chapter, description) {
		// 先建画布
		if (core.isReplaying()) return;
		core.createCanvas("chapter", 0, 0, 480, 480, 100);
		var frame = 0,
			speed = 0,
			left = -480,
			down = 240;
		// 一秒50帧
		core.lockControl();
		var interval = setInterval(function () {
			core.clearMap("chapter");
			speed = core.hyperbolicCosine((frame - 84) * 0.05);
			left += speed / 2;
			// 背景
			if (frame <= 110) {
				core.fillRect("chapter", 0, -240 - left, 480, left + 480, "#000000");
				core.fillRect("chapter", 0, 240, 480, left + 480, "#000000");
			} else {
				core.fillRect("chapter", 0, 0, 480, down, "#000000");
				core.fillRect("chapter", 0, 480 - down, 480, down, "#000000");
				down -= speed / 2;
			}
			// 中间矩形
			if (frame <= 100) {
				core.fillRect("chapter", 0, 240 - frame / 5, 480, frame / 2.5, [255, 255, 255, 0.5 + frame / 200]);
			} else {
				core.fillRect("chapter", 0, 240 - (2100 / (205 - frame)), 480, 4200 / (205 - frame), [255, 255, 255, (175 - frame) / 75]);
			}
			// 上下方线
			core.fillRect("chapter", left, 210, 300, 10, "#FF4D00");
			core.fillRect("chapter", 180 - left, 260, 300, 10, "#2DFFFC");
			core.fillRect("chapter", left + 310, 210, 10, 10, "#FF4D00");
			core.fillRect("chapter", 160 - left, 260, 10, 10, "#2DFFFC");
			core.fillPolygon("chapter", [
				[left + 330, 210],
				[left + 330, 220],
				[left + 340, 220]
			], "#FF4D00");
			core.fillPolygon("chapter", [
				[150 - left, 260],
				[140 - left, 260],
				[150 - left, 270]
			], "#2DFFFC");
			// 闪光条
			for (var i = 5; i > 0; i--) {
				if (frame <= 150) {
					core.drawLine("chapter", 0, 220, left + 320, 220, [255, 255, 255, 0.4], i);
					core.drawLine("chapter", 480, 260, 160 - left, 260, [255, 255, 255, 0.4], i);
				} else {
					core.drawLine("chapter", 0, 220, left + 320, 220, [255, 255, 255, 0.4 - (frame - 150) / 125], i);
					core.drawLine("chapter", 480, 260, 160 - left, 260, [255, 255, 255, 0.4 - (frame - 150) / 125], i);
				}
			}
			core.fillEllipse("chapter", left + 320, 220, 7, 3, 0, [255, 255, 255, 0.8]);
			core.fillEllipse("chapter", left + 320, 220, 2, 10, 0, [255, 255, 255, 0.8]);
			core.fillEllipse("chapter", 160 - left, 260, 7, 3, 0, [255, 255, 255, 0.8]);
			core.fillEllipse("chapter", 160 - left, 260, 2, 10, 0, [255, 255, 255, 0.8]);
			// 字
			core.setTextAlign("chapter", "center");
			core.fillBoldText("chapter", chapter + " " + description, left + 360, 250, "#ffffff", "#000000", "28px scroll");
			if (frame >= 200) {
				clearInterval(interval);
				core.deleteCanvas("chapter");
				core.unlockControl();
			}
			if (frame == 80) core.playSound("chapter.mp3");
			frame++;
		}, 20);
	};
	// 返回双曲余弦值
	this.hyperbolicCosine = function (number) {
		return 0.5 * (Math.pow(Math.E, number) + Math.pow(Math.E, -number));
	}
},
    "追猎": function () {
	// 追猎, 抄無敵咕工智障的
	////// 追击逻辑写在了阻击里面 //////
	core.control._checkBlock_repulse = function (repulse) {
		// t[0] == enemy.x, t[1] == enemy.y, t[2] == enemy.id, t[3] == direction
		if (!repulse || repulse.length == 0) return;
		var actions = [];
		var occupied_loc = []; // 已经被其他追击/阻击占据的位置，不让走
		var moved_enemy = [];
		repulse.forEach(function (t) {
			var hero_x = core.status.hero.loc.x,
				hero_y = core.status.hero.loc.y;
			var nextx = t[0],
				nexty = t[1];




			var should_battle = false;

			switch (t[3]) {
			case "right":
				nextx += 1;
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				//movedRight = true
				break;
			case "left":
				nextx -= 1;
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				//movedLeft = true
				break;
			case "up":
				nexty -= 1;
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				//movedUp = true
				break;
			case "down":
				nexty += 1;
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				//movedDown = true	
				break;
				// 8方阻擊
			case "leftup":
				nextx -= 1
				nexty -= 1
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				break;
			case "leftdown":
				nextx -= 1
				nexty += 1
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				break;
			case "rightup":
				nextx += 1
				nexty -= 1
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				break;
			case "rightdown":
				nextx += 1
				nexty += 1
				if (nextx == hero_x && nexty == hero_y) should_battle = true;
				break;
			}
			if (!core.hasSpecial(t[2], 29)) should_battle = false;



			if (should_battle) { // 追击强制战斗
				actions.push({
					"type": "function",
					"function": "function() { " +
						"core.battle('" + t[2] + "', " + t[0] + "," + t[1] + ", true, core.doAction); " +
						"}",
					"async": true
				});
			} else {
				if (occupied_loc.indexOf(nextx + "," + nexty) == -1 && core.getBlock(nextx, nexty) == null) { // 未被占据&&空地的格子才可以走上去
					occupied_loc.push(nextx + "," + nexty);
					// 移動時間為 1 (接近瞬移)
					actions.push({ "type": "move", "loc": [t[0], t[1]], "steps": [t[3]], "time": 1, "keep": true, "async": true });

					moved_enemy.push([t[0], t[1], t[2], t[3]])
				}
			}
		})



		if (moved_enemy.length != 0) actions.push({ "type": "waitAsync", "excludeAnimates": true });

		// 追猎後是否戰鬥

		for (var i = 0; i < moved_enemy.length; i++) {
			var hero_x = core.status.hero.loc.x,
				hero_y = core.status.hero.loc.y;
			var nextx = moved_enemy[i][0],
				nexty = moved_enemy[i][1];

			var should_battle = false;
			var moved = false

			switch (moved_enemy[i][3]) {
			case "right":
				nextx += 1
				break;
			case "left":
				nextx -= 1
				break;
			case "up":
				nexty -= 1
				break;
			case "down":
				nexty += 1
				break;
			case "leftup":
				nextx -= 1
				nexty -= 1

				break;
			case "leftdown":
				nextx -= 1
				nexty += 1

				break;
			case "rightup":
				nextx += 1
				nexty -= 1

				break;
			case "rightdown":
				nextx += 1
				nexty += 1

				break;
			}



			for (var j = -2; j < 2; j++) {
				for (var k = -2; k < 2; k++) {
					//	if (!core.material.enemys[moved_enemy[i][2]].zoneSquare) {
					if (Math.abs(j) + Math.abs(k) > 1) continue
					//	}
					var x = nextx + j
					var y = nexty + k
					if (x == hero_x && y == hero_y) should_battle = true
				}
			}

			if (!core.hasSpecial(moved_enemy[i][2], 55)) should_battle = false;
			if (should_battle) { // 追击强制战斗
				actions.push({
					"type": "function",
					"function": "function() { " +
						"core.battle('" + moved_enemy[i][2] + "', " + nextx + "," + nexty + ", true, core.doAction); " +
						"}",
					"async": true
				});
			}
		}


		//actions.push({ "type": "waitAsync" });
		core.insertAction(actions);
		console.log(actions)
	}
},
    "自动清-": function () {
	// 自動殺0傷怪
	var enable = true;
	if (!enable) return;

	// 
	// var noUpdate = false;
	////// 更新状态栏 ////// 不建议状态栏刷新后触发 容易导致录像不一致的问题
	//control.prototype.updateStatusBar = function (doNotCheckAutoEvents) {
	//	if (!core.isPlaying()) return;
	//	if (noUpdate) return;
	//	noUpdate = true;
	//	core.autoGetItem();
	//	noUpdate = false;
	//	this.controldata.updateStatusBar();
	//	if (!doNotCheckAutoEvents) core.checkAutoEvents();
	//	this._updateStatusBar_setToolboxIcon();
	//	core.clearRouteFolding();
	//}

	////// 每移动一格后执行的事件 //////
	/*
	control.prototype.moveOneStep = function (callback) {
		if (core.getBgNumber() != 6 || core.hasEquip('I932')) core.autoGetItem();
		return this.controldata.moveOneStep(callback);
	}
	*/

	function bfsFlood(sx, sy, blockfn) {
		var canMoveArray = core.generateMovableArray();
		var blocksObj = core.getMapBlocksObj();
		var bgMap = core.getBgMapArray();

		var visited = [],
			queue = [];
		visited[sx + "," + sy] = 0;
		queue.push(sx + "," + sy);

		while (queue.length > 0) {
			var now = queue.shift().split(","),
				x = ~~now[0],
				y = ~~now[1];
			for (var direction in core.utils.scan) {
				if (!core.inArray(canMoveArray[x][y], direction)) continue;
				var nx = x + core.utils.scan[direction].x,
					ny = y + core.utils.scan[direction].y,
					nindex = nx + "," + ny;
				if (visited[nindex]) continue;
				if (core.onSki(bgMap[ny][nx])) continue;
				if (blockfn && !blockfn(blocksObj, nx, ny)) continue;
				visited[nindex] = visited[now] + 1;
				queue.push(nindex);
			}
		}
	}

	function attractAnimate() {
		var name = 'attractAnimate';
		var isPlaying = false;
		this.nodes = [];

		this.add = function (id, x, y, callback) {
			this.nodes.push({ id: id, x: x, y: y, callback: callback });
		}
		this.start = function () {
			if (isPlaying) return;
			isPlaying = true;
			core.registerAnimationFrame(name, true, this.update);
			this.ctx = core.createCanvas(name, 0, 0, core.__PIXELS__, core.__PIXELS__, 120);
		}
		this.remove = function () {
			core.unregisterAnimationFrame(name);
			core.deleteCanvas(name);
			isPlaying = false;
		}
		this.clear = function () {
			this.nodes = [];
			this.remove();
		}
		var lastTime = -1;
		var self = this;
		this.update = function (timeStamp) {
			if (lastTime < 0) lastTime = timeStamp;
			if (timeStamp - lastTime < 20) return;
			lastTime = timeStamp;
			core.clearMap(name);
			var cx = core.status.heroCenter.px - 16,
				cy = core.status.heroCenter.py - 16;
			var thr = 5; //缓动比例倒数 越大移动越慢
			self.nodes.forEach(function (n) {
				var dx = cx - n.x,
					dy = cy - n.y;
				if (Math.abs(dx) <= thr && Math.abs(dy) <= thr) {
					n.dead = true;
				} else {
					n.x += ~~(dx / thr);
					n.y += ~~(dy / thr);
				}
				core.drawIcon(name, n.id, n.x, n.y, 32, 32);
			});
			self.nodes = self.nodes.filter(function (n) {
				if (n.dead && n.callback) {
					n.callback();
				}
				return !n.dead;
			});
			if (self.nodes.length == 0)
				self.remove();
		}
	}


	// var animateHwnd = new attractAnimate();

	this.stopAttractAnimate = function () {
		animateHwnd.clear();
	}

	this.autoBattle = function () {
		if (core.getFlag("autoBattle", 0) == 0) return;
		var blockfn = function (blockMap, x, y) {
			var idx = x + ',' + y;
			if (idx in canGetItems) return false;
			var blk = blockMap[idx];
			//if (blk && !blk.disable && blk.event.cls == 'items' && !core.isMapBlockDisabled(core.status.floorId, blk.x, blk.y) && blk.event.trigger == 'getItem') {
			if (blk && !blk.disable && (blk.event.cls == 'enemys' || blk.event.cls == 'enemy48') && !core.isMapBlockDisabled(core.status.floorId, blk.x, blk.y) && blk.event.trigger == 'battle' && (core.getDamage(core.getBlock(x, y).event.id, x, y) == 0 || core.getDamage(core.getBlock(x, y).event.id, x, y) < 0)) {
				canGetItems[idx] = { x: x, y: y, id: blk.event.id };
				return !core.status.checkBlock.damage[idx] && !core.status.checkBlock.ambush[idx] && !core.status.checkBlock.repulse[idx];
			}
			return core.maps._canMoveDirectly_checkNextPoint(blockMap, x, y);
		};
		var canGetItems = {};
		if (!core.status.floorId || !core.status.checkBlock.damage || core.status.event.id == 'action' || core.status.lockControl) return;
		// if (Object.keys(core.status.checkBlock.damage).indexOf(core.status.hero.loc.x + "," + core.status.hero.loc.y) != -1) return

		bfsFlood(core.getHeroLoc('x'), core.getHeroLoc('y'), blockfn);
		for (var k in canGetItems) {
			var x = canGetItems[k].x,
				y = canGetItems[k].y,
				id = canGetItems[k].id;
			core.trigger(x, y);
			//if (!core.isReplaying()) animateHwnd.add(id, x * 32, y * 32);
		}
		//if (!core.isReplaying()) animateHwnd.start();
	}
},
    "谔谔": function () {
	// 自動清0傷怪不會自動存檔
	events.prototype.battle = function (id, x, y, force, callback) {
		core.saveAndStopAutomaticRoute();
		id = id || core.getBlockId(x, y);
		if (!id) return core.clearContinueAutomaticRoute(callback);
		// 非强制战斗
		if (!core.enemys.canBattle(id, x, y) && !force && !core.status.event.id) {
			core.drawTip("你打不过此怪物！");
			return core.clearContinueAutomaticRoute(callback);
		}
		// 自动存档
		if (!core.status.event.id && ((core.getFlag('autoBattle', 0) == 1 && core.getDamage(id, x, y) > 0) || core.getFlag('autoBattle', 0) == 0)) {
			core.autosave(true);
			// console.log(114514)
		}
		// 战前事件
		if (!this.beforeBattle(id, x, y))
			return core.clearContinueAutomaticRoute(callback);
		// 战后事件
		this.afterBattle(id, x, y);
		if (callback) callback();
	}
}
}