mirror of
				https://github.com/unanmed/HumanBreak.git
				synced 2025-10-31 20:32:58 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			4460 lines
		
	
	
		
			133 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			4460 lines
		
	
	
		
			133 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| ///<reference path="../../src/types/declaration/core.d.ts" />
 | ||
| 
 | ||
| 'use strict';
 | ||
| 
 | ||
| function maps() {
 | ||
|     this._init();
 | ||
| }
 | ||
| 
 | ||
| maps.prototype._init = function () {
 | ||
|     this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
 | ||
|     //delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._initFloors = function (floorId) {
 | ||
|     if (!floorId) {
 | ||
|         core.floorIds.forEach(function (floorId) {
 | ||
|             core.maps._initFloors(floorId);
 | ||
|         });
 | ||
|         return;
 | ||
|     }
 | ||
|     // 战前事件兼容性
 | ||
|     if (!core.floors[floorId].beforeBattle)
 | ||
|         core.floors[floorId].beforeBattle = {};
 | ||
|     // cannotMoveIn兼容性
 | ||
|     if (!core.floors[floorId].cannotMoveIn)
 | ||
|         core.floors[floorId].cannotMoveIn = {};
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._resetFloorImages = function () {
 | ||
|     for (var floorId in core.status.maps) {
 | ||
|         (core.status.maps[floorId].images || []).forEach(function (one) {
 | ||
|             var flag = '__floorImg__' + floorId + '_' + one.x + '_' + one.y;
 | ||
|             if (core.getFlag(flag) == null) {
 | ||
|                 if (one.disabled) core.setFlag(flag, true);
 | ||
|             }
 | ||
|         });
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._setHDCanvasSize = function (ctx, width, height) {
 | ||
|     ctx.setTransform(1, 0, 0, 1, 0, 0);
 | ||
|     var ratio = core.domStyle.scale;
 | ||
|     ratio *= devicePixelRatio;
 | ||
|     if (width != null) ctx.canvas.width = width * ratio;
 | ||
|     if (height != null) ctx.canvas.height = height * ratio;
 | ||
|     ctx.scale(ratio, ratio);
 | ||
|     ctx.canvas.setAttribute('isHD', 1);
 | ||
| };
 | ||
| 
 | ||
| // ------ 加载地图与地图的存档读档(压缩与解压缩) ------ //
 | ||
| 
 | ||
| ////// 加载某个楼层(从剧本或存档中) //////
 | ||
| maps.prototype.loadFloor = function (floorId, map) {
 | ||
|     var floor = core.floors[floorId];
 | ||
|     if (!map) map = core.cloneArray(floor.map);
 | ||
|     if (map instanceof Array) {
 | ||
|         map = { map: map };
 | ||
|     }
 | ||
|     if (!map.map) map.map = core.cloneArray(floor.map);
 | ||
|     var content = {};
 | ||
|     var notCopy = this._loadFloor_doNotCopy();
 | ||
|     for (var name in floor) {
 | ||
|         if (notCopy.indexOf(name) == -1 && floor[name] != null)
 | ||
|             content[name] = core.clone(floor[name]);
 | ||
|     }
 | ||
|     for (var name in map) {
 | ||
|         if (notCopy.indexOf(name) == -1 && map[name] != null)
 | ||
|             content[name] = core.clone(map[name]);
 | ||
|     }
 | ||
|     content.map = map.map;
 | ||
|     if (main.mode == 'editor') {
 | ||
|         this.extractBlocks(content);
 | ||
|     }
 | ||
|     return content;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._loadFloor_doNotCopy = function () {
 | ||
|     // see src/plugin/game/fiveLayer.js
 | ||
|     return [
 | ||
|         'firstArrive',
 | ||
|         'eachArrive',
 | ||
|         'blocks',
 | ||
|         'parallelDo',
 | ||
|         'map',
 | ||
|         'bgmap',
 | ||
|         'fgmap',
 | ||
|         'bg2map',
 | ||
|         'fg2map',
 | ||
|         'events',
 | ||
|         'changeFloor',
 | ||
|         'afterBattle',
 | ||
|         'afterGetItem',
 | ||
|         'afterOpenDoor',
 | ||
|         'cannotMove',
 | ||
|         'enemy'
 | ||
|     ];
 | ||
| };
 | ||
| 
 | ||
| /// 根据需求解析出blocks
 | ||
| maps.prototype.extractBlocks = function (map) {
 | ||
|     map = map || core.status.floorId;
 | ||
|     if (typeof map == 'string') map = (core.status.maps || {})[map];
 | ||
|     if (!map) return;
 | ||
|     if (map.blocks) return;
 | ||
|     if (map.deleted) {
 | ||
|         map.blocks = [];
 | ||
|         return;
 | ||
|     }
 | ||
|     var floorId = map.floorId;
 | ||
|     map.blocks = this._mapIntoBlocks(
 | ||
|         this.decompressMap(map.map, floorId),
 | ||
|         core.floors[floorId],
 | ||
|         floorId
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._mapIntoBlocks = function (map, floor, floorId) {
 | ||
|     var blocks = [];
 | ||
|     var mw = core.floors[floorId].width;
 | ||
|     var mh = core.floors[floorId].height;
 | ||
|     for (var i = 0; i < mh; i++) {
 | ||
|         for (var j = 0; j < mw; j++) {
 | ||
|             var number = (map[i] || [])[j] || 0,
 | ||
|                 block;
 | ||
|             if (main.mode == 'editor') {
 | ||
|                 if (!number) continue;
 | ||
|                 block = {
 | ||
|                     x: j,
 | ||
|                     y: i,
 | ||
|                     id: number,
 | ||
|                     event: this.getBlockByNumber(number).event
 | ||
|                 };
 | ||
|             } else {
 | ||
|                 block = this.initBlock(j, i, number, true, floor);
 | ||
|             }
 | ||
|             if (block.id != 0 || block.event.trigger) blocks.push(block);
 | ||
|         }
 | ||
|     }
 | ||
|     return blocks;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.extractBlocksForUI = function (map, flags) {
 | ||
|     if (!map || map.blocks) return;
 | ||
|     if (map.deleted) return (map.blocks = []);
 | ||
|     var floorId = map.floorId;
 | ||
|     var decompressed = this.decompressMap(map.map, floorId);
 | ||
|     map.blocks = [];
 | ||
|     var floor = core.floors[floorId];
 | ||
|     var mw = floor.width;
 | ||
|     var mh = floor.height;
 | ||
|     for (var i = 0; i < mh; i++) {
 | ||
|         for (var j = 0; j < mw; j++) {
 | ||
|             var number = (decompressed[i] || [])[j] || 0;
 | ||
|             if (!number || number == 17) continue;
 | ||
|             var isDisabled = this.isMapBlockDisabled(floorId, j, i, flags);
 | ||
|             if (isDisabled) continue;
 | ||
|             if (isDisabled == null) {
 | ||
|                 // 检查是否初始禁用
 | ||
|                 var event = (floor.events || {})[j + ',' + i];
 | ||
|                 if (event != null && event.enable === false) continue;
 | ||
|             }
 | ||
|             var opacity = this._getBlockOpacityFromFlag(floorId, j, i, flags);
 | ||
|             if (opacity == null) {
 | ||
|                 // 检查初始不透明度
 | ||
|                 var event = (floor.events || {})[j + ',' + i];
 | ||
|                 if (event != null && event.opacity != null)
 | ||
|                     opacity = event.opacity;
 | ||
|             }
 | ||
|             var filter = this._getBlockFilterFromFlag(floorId, j, i, flags);
 | ||
|             if (filter == null) {
 | ||
|                 // 检查初始filter
 | ||
|                 var event = (floor.events || {})[j + ',' + i];
 | ||
|                 if (event != null && event.filter != null)
 | ||
|                     filter = core.clone(event.filter);
 | ||
|             }
 | ||
|             map.blocks.push(
 | ||
|                 Object.assign({}, this.getBlockByNumber(number), {
 | ||
|                     x: j,
 | ||
|                     y: i,
 | ||
|                     opacity: opacity,
 | ||
|                     filter: filter
 | ||
|                 })
 | ||
|             );
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 从ID获得数字 //////
 | ||
| maps.prototype.getNumberById = function (id) {
 | ||
|     id = this.getIdOfThis(id);
 | ||
|     core.status.id2number ??= {};
 | ||
|     if (core.status.id2number[id] != null) return core.status.id2number[id];
 | ||
|     return (core.status.id2number[id] = this._getNumberById(id));
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getNumberById = function (id) {
 | ||
|     for (var number in this.blocksInfo) {
 | ||
|         if ((this.blocksInfo[number] || {}).id === id)
 | ||
|             return Number(number) || 0;
 | ||
|     }
 | ||
|     // tilesets
 | ||
|     if (id[0] === 'X' && !isNaN(Number(id.slice(1)))) {
 | ||
|         if (core.icons.getTilesetOffset(id)) return Number(id.slice(1));
 | ||
|     }
 | ||
|     // 特殊ID
 | ||
|     if (id === 'none') return 0;
 | ||
|     else if (id === 'airwall') return 17;
 | ||
|     else return 0;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getBlockByNumber = function (number) {
 | ||
|     core.status.number2Block = core.status.number2Block || {};
 | ||
|     if (core.status.number2Block[number] != null)
 | ||
|         return core.status.number2Block[number];
 | ||
|     return (core.status.number2Block[number] = this.initBlock(
 | ||
|         null,
 | ||
|         null,
 | ||
|         number,
 | ||
|         true
 | ||
|     ));
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getBlockById = function (id) {
 | ||
|     return this.getBlockByNumber(this.getNumberById(id));
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getIdOfThis = function (id) {
 | ||
|     if (id != 'this') return id;
 | ||
|     if (core.status.event.id != 'action') return id;
 | ||
|     if (
 | ||
|         !core.status.event.data ||
 | ||
|         core.status.event.data.x == null ||
 | ||
|         core.status.event.data.y == null
 | ||
|     )
 | ||
|         return id;
 | ||
|     return (
 | ||
|         core.getBlockId(core.status.event.data.x, core.status.event.data.y) ||
 | ||
|         id
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 数字和ID的对应关系 //////
 | ||
| maps.prototype.initBlock = function (x, y, id, addInfo, eventFloor) {
 | ||
|     var disable = null;
 | ||
|     var opacity = null;
 | ||
|     var filter = null;
 | ||
|     if (eventFloor != null) {
 | ||
|         disable = this.isMapBlockDisabled(eventFloor.floorId, x, y);
 | ||
|         opacity = this._getBlockOpacityFromFlag(eventFloor.floorId, x, y);
 | ||
|         filter = this._getBlockFilterFromFlag(eventFloor.floorId, x, y);
 | ||
|     }
 | ||
|     var block = { x: x, y: y, id: id };
 | ||
|     if (disable != null) block.disable = disable;
 | ||
|     if (opacity != null) block.opacity = opacity;
 | ||
|     if (filter != null) block.filter = filter;
 | ||
| 
 | ||
|     if (id == 17)
 | ||
|         block.event = {
 | ||
|             cls: 'terrains',
 | ||
|             id: 'airwall',
 | ||
|             cannotIn: ['up', 'down', 'left', 'right']
 | ||
|         };
 | ||
|     else if (id in this.blocksInfo)
 | ||
|         block.event = JSON.parse(JSON.stringify(this.blocksInfo[id]));
 | ||
|     else if (core.icons.getTilesetOffset(id))
 | ||
|         block.event = { cls: 'tileset', id: 'X' + id };
 | ||
|     else block.event = { cls: 'terrains', id: 'none', noPass: false };
 | ||
| 
 | ||
|     if (block.event.noPass == null) {
 | ||
|         if (block.event.canPass == null) {
 | ||
|             block.event.noPass = block.event.cls != 'items';
 | ||
|         } else {
 | ||
|             block.event.noPass = !block.event.canPass;
 | ||
|         }
 | ||
|     }
 | ||
|     delete block.event.canPass;
 | ||
| 
 | ||
|     // 增加怪物的faceIds
 | ||
|     if (block.event.cls.indexOf('enemy') == 0) {
 | ||
|         var enemy = core.material.enemys[block.event.id];
 | ||
|         if (enemy && enemy.faceIds) {
 | ||
|             block.event.faceIds = enemy.faceIds;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     if (addInfo) this._addInfo(block);
 | ||
|     if (eventFloor) {
 | ||
|         this._addEvent(block, x, y, (eventFloor.events || {})[x + ',' + y]);
 | ||
|         var changeFloor = (eventFloor.changeFloor || {})[x + ',' + y];
 | ||
|         if (changeFloor)
 | ||
|             this._addEvent(block, x, y, {
 | ||
|                 trigger: 'changeFloor',
 | ||
|                 data: changeFloor
 | ||
|             });
 | ||
|     }
 | ||
|     if (main.mode == 'editor') delete block.disable;
 | ||
|     return block;
 | ||
| };
 | ||
| 
 | ||
| ////// 添加一些信息到block上 //////
 | ||
| maps.prototype._addInfo = function (block) {
 | ||
|     if (block.event.cls.indexOf('enemy') == 0 && !block.event.trigger) {
 | ||
|         block.event.trigger = 'battle';
 | ||
|     }
 | ||
|     if (block.event.cls == 'items' && !block.event.trigger) {
 | ||
|         block.event.trigger = 'getItem';
 | ||
|     }
 | ||
|     if (block.event.animate == null) {
 | ||
|         block.event.animate = core.icons.getAnimateFrames(block.event.cls);
 | ||
|     }
 | ||
|     block.event.height = 32;
 | ||
|     if (block.event.cls == 'enemy48' || block.event.cls == 'npc48')
 | ||
|         block.event.height = 48;
 | ||
| };
 | ||
| 
 | ||
| ////// 向该楼层添加剧本的自定义事件 //////
 | ||
| maps.prototype._addEvent = function (block, x, y, event) {
 | ||
|     if (!event) return;
 | ||
|     // event是字符串或数组?
 | ||
|     if (typeof event == 'string') {
 | ||
|         event = { data: [event] };
 | ||
|     } else if (event instanceof Array) {
 | ||
|         event = { data: event };
 | ||
|     }
 | ||
|     event.data = event.data || [];
 | ||
| 
 | ||
|     // 覆盖enable
 | ||
|     if (block.disable == null && event.enable != null) {
 | ||
|         block.disable = !event.enable;
 | ||
|     }
 | ||
|     // 覆盖opacity
 | ||
|     if (block.opacity == null && event.opacity != null) {
 | ||
|         block.opacity = event.opacity;
 | ||
|     }
 | ||
|     if (block.filter == null && event.filter != null) {
 | ||
|         block.filter = core.clone(event.filter);
 | ||
|     }
 | ||
|     // 覆盖animate
 | ||
|     if (event.animate === false) {
 | ||
|         block.event.animate = 1;
 | ||
|     }
 | ||
|     // 覆盖所有属性
 | ||
|     for (var key in event) {
 | ||
|         if (
 | ||
|             key != 'enable' &&
 | ||
|             key != 'animate' &&
 | ||
|             key != 'opacity' &&
 | ||
|             key != 'filter' &&
 | ||
|             event[key] != null
 | ||
|         ) {
 | ||
|             block.event[key] = core.clone(event[key]);
 | ||
|         }
 | ||
|     }
 | ||
|     // 给无trigger的增加trigger:action
 | ||
|     if (!block.event.trigger) {
 | ||
|         block.event.trigger = 'action';
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 初始化所有地图 //////
 | ||
| maps.prototype._initMaps = function () {
 | ||
|     var floorIds = core.floorIds;
 | ||
|     var maps = {};
 | ||
|     for (var i = 0; i < floorIds.length; i++) {
 | ||
|         var floorId = floorIds[i];
 | ||
|         maps[floorId] = this.loadFloor(floorId);
 | ||
|     }
 | ||
|     return maps;
 | ||
| };
 | ||
| 
 | ||
| ////// 压缩地图
 | ||
| maps.prototype.compressMap = function (mapArr, floorId) {
 | ||
|     var floorMap = core.floors[floorId].map;
 | ||
|     if (core.utils.same(mapArr, floorMap)) return null;
 | ||
| 
 | ||
|     var mw = core.floors[floorId].width;
 | ||
|     var mh = core.floors[floorId].height;
 | ||
|     for (var x = 0; x < mh; x++) {
 | ||
|         if (core.utils.same(mapArr[x], floorMap[x])) {
 | ||
|             // 没有改变的行直接删掉记成0
 | ||
|             mapArr[x] = 0;
 | ||
|         } else {
 | ||
|             for (var y = 0; y < mw; y++) {
 | ||
|                 if (mapArr[x][y] === floorMap[x][y]) {
 | ||
|                     // 没有改变的数据记成-1
 | ||
|                     mapArr[x][y] = -1;
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     return mapArr;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._processInvalidMap = function (mapArr, width, height) {
 | ||
|     if (mapArr.length == height && mapArr[0].length == width) return mapArr;
 | ||
|     var map = [];
 | ||
|     for (var i = 0; i < height; ++i) {
 | ||
|         map.push(Array(width).fill(0));
 | ||
|     }
 | ||
|     for (var j = 0; j < height; ++j) {
 | ||
|         for (var i = 0; i < width; ++i) {
 | ||
|             if (j < mapArr.length && i < mapArr[j].length)
 | ||
|                 map[j][i] = mapArr[j][i];
 | ||
|         }
 | ||
|     }
 | ||
|     return map;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getBlockOpacityFromFlag = function (floorId, x, y, flags) {
 | ||
|     if (flags == null) flags = (core.status.hero || {}).flags;
 | ||
|     if (flags == null) return null;
 | ||
|     var __opacity__ = flags.__opacity__ || {};
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     return (__opacity__[floorId] || {})[index];
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getBlockFilterFromFlag = function (floorId, x, y, flags) {
 | ||
|     if (flags == null) flags = (core.status.hero || {}).flags;
 | ||
|     if (flags == null) return null;
 | ||
|     var __filter__ = flags.__filter__ || {};
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     return core.clone((__filter__[floorId] || {})[index]);
 | ||
| };
 | ||
| 
 | ||
| ////// 设置某个点的不透明度 //////
 | ||
| maps.prototype.setBlockOpacity = function (opacity, x, y, floorId) {
 | ||
|     if (window.flags == null) return;
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     if (!window.flags.__opacity__) window.flags.__opacity__ = {};
 | ||
|     if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     var __opacity__ = window.flags.__opacity__;
 | ||
|     if (!__opacity__[floorId]) __opacity__[floorId] = {};
 | ||
|     if (opacity == null) delete __opacity__[floorId][index];
 | ||
|     else __opacity__[floorId][index] = opacity;
 | ||
| 
 | ||
|     ////// 重绘该点图块
 | ||
|     var block = core.getBlock(x, y, floorId, true);
 | ||
|     if (block != null) {
 | ||
|         block.opacity = opacity;
 | ||
|         if (floorId == core.status.floorId && !block.disable) {
 | ||
|             if (block.event.cls == 'autotile') {
 | ||
|                 core.redrawMap();
 | ||
|             } else {
 | ||
|                 core.drawBlock(block);
 | ||
|                 core.addGlobalAnimate(block);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.setBlockFilter = function (filter, x, y, floorId) {
 | ||
|     if (window.flags == null) return;
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     if (!window.flags.__filter__) window.flags.__filter__ = {};
 | ||
|     if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     var __filter__ = window.flags.__filter__;
 | ||
|     if (!__filter__[floorId]) __filter__[floorId] = {};
 | ||
|     if (filter == null) delete __filter__[floorId][index];
 | ||
|     else {
 | ||
|         if (
 | ||
|             !filter.blur &&
 | ||
|             !filter.hue &&
 | ||
|             !filter.shadow &&
 | ||
|             !filter.grayscale &&
 | ||
|             !filter.invert
 | ||
|         )
 | ||
|             delete __filter__[floorId][index];
 | ||
|         else __filter__[floorId][index] = core.clone(filter);
 | ||
|     }
 | ||
| 
 | ||
|     ////// 重绘该点图块
 | ||
|     var block = core.getBlock(x, y, floorId, true);
 | ||
|     if (block != null) {
 | ||
|         block.filter = core.clone(filter);
 | ||
|         if (floorId == core.status.floorId && !block.disable) {
 | ||
|             if (block.event.cls == 'autotile') {
 | ||
|                 core.redrawMap();
 | ||
|             } else {
 | ||
|                 core.drawBlock(block);
 | ||
|                 core.addGlobalAnimate(block);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 某个点图块是否被强制启用或禁用
 | ||
| maps.prototype.isMapBlockDisabled = function (floorId, x, y, flags) {
 | ||
|     if (flags == null) flags = (core.status.hero || {}).flags;
 | ||
|     if (flags == null) return null;
 | ||
|     var __disabled__ = flags.__disabled__ || {};
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     if ((flags.__removed__ || []).indexOf(floorId) >= 0) return null;
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     if (!__disabled__[floorId]) return null;
 | ||
|     if (__disabled__[floorId][0].indexOf(index) >= 0) return true;
 | ||
|     if (__disabled__[floorId][1].indexOf(index) >= 0) return false;
 | ||
| };
 | ||
| 
 | ||
| ////// 设置某个点的图块强制启用/禁用状态
 | ||
| maps.prototype.setMapBlockDisabled = function (floorId, x, y, disabled) {
 | ||
|     if (window.flags == null) return;
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     if (!window.flags.__disabled__) window.flags.__disabled__ = {};
 | ||
|     if ((window.flags.__removed__ || []).indexOf(floorId) >= 0) return;
 | ||
|     var __disabled__ = window.flags.__disabled__ || {};
 | ||
|     if (!__disabled__[floorId]) __disabled__[floorId] = [[], []];
 | ||
|     var index = x + y * core.floors[floorId].width;
 | ||
|     __disabled__[floorId][0] = __disabled__[floorId][0].filter(function (x) {
 | ||
|         return x != index;
 | ||
|     });
 | ||
|     __disabled__[floorId][1] = __disabled__[floorId][1].filter(function (x) {
 | ||
|         return x != index;
 | ||
|     });
 | ||
|     if (disabled == null) return;
 | ||
|     if (disabled) __disabled__[floorId][0].push(index);
 | ||
|     else __disabled__[floorId][1].push(index);
 | ||
| };
 | ||
| 
 | ||
| ////// 解压缩地图
 | ||
| maps.prototype.decompressMap = function (mapArr, floorId) {
 | ||
|     var mw = core.floors[floorId].width;
 | ||
|     var mh = core.floors[floorId].height;
 | ||
|     var floorMap = this._processInvalidMap(core.floors[floorId].map, mw, mh);
 | ||
| 
 | ||
|     if (!mapArr) return core.cloneArray(floorMap);
 | ||
| 
 | ||
|     for (var x = 0; x < mh; x++) {
 | ||
|         if (x >= mapArr.length) {
 | ||
|             mapArr.push(0);
 | ||
|         }
 | ||
|         if (mapArr[x] === 0) {
 | ||
|             mapArr[x] = core.cloneArray(floorMap[x]);
 | ||
|         } else {
 | ||
|             for (var y = 0; y < mw; y++) {
 | ||
|                 if (y >= mapArr[x].length) mapArr[x].push(-1);
 | ||
|                 if (mapArr[x][y] === -1) {
 | ||
|                     mapArr[x][y] = floorMap[x][y];
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     return mapArr;
 | ||
| };
 | ||
| 
 | ||
| ////// 将当前地图重新变成数字,以便于存档 //////
 | ||
| maps.prototype.saveMap = function (floorId) {
 | ||
|     var maps = core.status.maps;
 | ||
|     if (!floorId) {
 | ||
|         var map = {};
 | ||
|         for (var id in maps) {
 | ||
|             var obj = this.saveMap(id);
 | ||
|             if (Object.keys(obj).length > 0) map[id] = obj;
 | ||
|         }
 | ||
|         return map;
 | ||
|     }
 | ||
|     // 砍层状态:直接返回
 | ||
|     if ((flags.__removed__ || []).indexOf(floorId) >= 0) {
 | ||
|         return {};
 | ||
|     }
 | ||
| 
 | ||
|     var map = maps[floorId];
 | ||
|     var thisFloor = this._compressFloorData(map, core.floors[floorId]);
 | ||
|     var mapArr = this.compressMap(
 | ||
|         map.blocks
 | ||
|             ? this._getMapArrayFromBlocks(
 | ||
|                   map.blocks,
 | ||
|                   map.width,
 | ||
|                   map.height,
 | ||
|                   true
 | ||
|               )
 | ||
|             : map.map,
 | ||
|         floorId
 | ||
|     );
 | ||
|     if (mapArr != null) thisFloor.map = mapArr;
 | ||
|     return thisFloor;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._compressFloorData = function (map, floor) {
 | ||
|     var thisFloor = {};
 | ||
|     var notCopy = this._loadFloor_doNotCopy();
 | ||
|     for (var name in map) {
 | ||
|         if (notCopy.indexOf(name) == -1) {
 | ||
|             var floorData = floor[name];
 | ||
|             if (!core.utils.same(map[name], floorData)) {
 | ||
|                 thisFloor[name] = core.clone(map[name]);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     return thisFloor;
 | ||
| };
 | ||
| 
 | ||
| ////// 将存档中的地图信息重新读取出来 //////
 | ||
| maps.prototype.loadMap = function (data, floorId, flags) {
 | ||
|     if (!floorId) {
 | ||
|         var map = {};
 | ||
|         core.floorIds.forEach(function (id) {
 | ||
|             if (core.inArray((flags || {}).__removed__, id)) {
 | ||
|                 data[id] = {
 | ||
|                     deleted: true,
 | ||
|                     canFlyTo: false,
 | ||
|                     canFlyFrom: false,
 | ||
|                     cannotViewMap: true
 | ||
|                 };
 | ||
|             }
 | ||
|             map[id] = core.maps.loadFloor(id, data[id]);
 | ||
|         });
 | ||
|         return map;
 | ||
|     }
 | ||
|     return this.loadFloor(floorId, data[floorId]);
 | ||
| };
 | ||
| 
 | ||
| ////// 更改地图画布的尺寸
 | ||
| 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.v2 =
 | ||
|         core.bigmap.width * core.bigmap.height > core.bigmap.threshold;
 | ||
|     var width = core.bigmap.v2 ? core._PX_ + 64 : core.bigmap.width * 32;
 | ||
|     var height = core.bigmap.v2 ? core._PY_ + 64 : core.bigmap.height * 32;
 | ||
| 
 | ||
|     core.bigmap.canvas.forEach(function (cn) {
 | ||
|         if (core.domStyle.hdCanvas.includes(cn))
 | ||
|             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._PX_) * 96 + 'vw';
 | ||
|             core.canvas[cn].canvas.style.height =
 | ||
|                 (height / core._PY_) * 96 + 'vw';
 | ||
|         }
 | ||
|     });
 | ||
| };
 | ||
| 
 | ||
| ////// 将当前地图重新变成二维数组形式 //////
 | ||
| maps.prototype.getMapArray = function (floorId, noCache) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     var map = core.status.maps[floorId];
 | ||
|     if (!map.blocks || !noCache) return map.map;
 | ||
|     return (map.map = this._getMapArrayFromBlocks(
 | ||
|         map.blocks,
 | ||
|         map.width,
 | ||
|         map.height
 | ||
|     ));
 | ||
| };
 | ||
| 
 | ||
| ////// 获得地图上某点的数字
 | ||
| maps.prototype.getMapNumber = function (x, y, floorId, noCache) {
 | ||
|     return this.getMapArray(floorId, noCache)[y][x];
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._updateMapArray = function (floorId, x, y) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     var map = core.status.maps[floorId];
 | ||
|     if (!map.blocks) return;
 | ||
|     if (x == null || y == null) return this.getMapArray(floorId, true);
 | ||
|     var block = this.getBlock(x, y, floorId, true);
 | ||
|     if (block == null || block.disable) map.map[y][x] = 0;
 | ||
|     else map.map[y][x] = block.id;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getMapArrayFromBlocks = function (
 | ||
|     blockArray,
 | ||
|     width,
 | ||
|     height,
 | ||
|     showDisable
 | ||
| ) {
 | ||
|     var blocks = [];
 | ||
|     for (var x = 0; x < height; x++) blocks.push(Array(width).fill(0));
 | ||
| 
 | ||
|     blockArray.forEach(function (block) {
 | ||
|         if (showDisable || !block.disable) blocks[block.y][block.x] = block.id;
 | ||
|     });
 | ||
|     return blocks;
 | ||
| };
 | ||
| 
 | ||
| ////// 以x,y的形式返回每个点的事件 //////
 | ||
| maps.prototype.getMapBlocksObj = function (floorId, noCache) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (core.status.mapBlockObjs[floorId] && !noCache)
 | ||
|         return core.status.mapBlockObjs[floorId];
 | ||
| 
 | ||
|     var obj = {};
 | ||
|     core.extractBlocks(floorId);
 | ||
|     core.status.maps[floorId].blocks.forEach(function (block) {
 | ||
|         obj[block.x + ',' + block.y] = block;
 | ||
|     });
 | ||
|     return (core.status.mapBlockObjs[floorId] = obj);
 | ||
| };
 | ||
| 
 | ||
| ////// 将背景前景层变成二维数组的形式 //////
 | ||
| 
 | ||
| maps.prototype._getBgFgMapArray = function (name, floorId, noCache) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return [];
 | ||
|     var width = core.floors[floorId].width;
 | ||
|     var height = core.floors[floorId].height;
 | ||
| 
 | ||
|     // @ts-ignore
 | ||
|     if (!noCache && core.status[name + 'maps'][floorId])
 | ||
|         // @ts-ignore
 | ||
|         return core.status[name + 'maps'][floorId];
 | ||
| 
 | ||
|     var arr =
 | ||
|         main.mode == 'editor' &&
 | ||
|         // @ts-ignore
 | ||
|         !(window.editor && editor.uievent && editor.uievent.isOpen)
 | ||
|             ? // @ts-ignore
 | ||
|               core.cloneArray(editor[name + 'map'])
 | ||
|             : null;
 | ||
|     if (arr == null)
 | ||
|         // @ts-ignore
 | ||
|         arr = core.cloneArray(core.floors[floorId][name + 'map'] || []);
 | ||
| 
 | ||
|     for (var y = 0; y < height; ++y) {
 | ||
|         if (arr[y] == null) arr[y] = Array(width).fill(0);
 | ||
|     }
 | ||
|     // @ts-ignore
 | ||
|     (core.getFlag('__' + name + 'v__', {})[floorId] || []).forEach(
 | ||
|         // @ts-ignore
 | ||
|         function (one) {
 | ||
|             arr[one[1]][one[0]] = one[2] || 0;
 | ||
|         }
 | ||
|     );
 | ||
|     // @ts-ignore
 | ||
|     (core.getFlag('__' + name + 'd__', {})[floorId] || []).forEach(
 | ||
|         // @ts-ignore
 | ||
|         function (one) {
 | ||
|             arr[one[1]][one[0]] = 0;
 | ||
|         }
 | ||
|     );
 | ||
|     if (main.mode == 'editor') {
 | ||
|         for (var x = 0; x < width; x++) {
 | ||
|             for (var y = 0; y < height; y++) {
 | ||
|                 // @ts-ignore
 | ||
|                 arr[y][x] = arr[y][x].idnum || arr[y][x] || 0;
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     // @ts-ignore
 | ||
|     if (core.status[name + 'maps'])
 | ||
|         // @ts-ignore
 | ||
|         core.status[name + 'maps'][floorId] = arr;
 | ||
|     return arr;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getBgMapArray = function (floorId) {
 | ||
|     return this._getBgFgMapArray('bg', floorId);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getFgMapArray = function (floorId) {
 | ||
|     return this._getBgFgMapArray('fg', floorId);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getBgFgNumber = function (name, x, y, floorId) {
 | ||
|     if (x == null) x = core.getHeroLoc('x');
 | ||
|     if (y == null) y = core.getHeroLoc('y');
 | ||
|     return this._getBgFgMapArray(name, floorId)[y][x];
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getBgNumber = function (x, y, floorId) {
 | ||
|     return this._getBgFgNumber('bg', x, y, floorId);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.getFgNumber = function (x, y, floorId) {
 | ||
|     return this._getBgFgNumber('fg', x, y, floorId);
 | ||
| };
 | ||
| 
 | ||
| // ------ 当前能否朝某方向移动,能否瞬间移动 ------ //
 | ||
| 
 | ||
| ////// 生成全图的当前可移动信息 //////
 | ||
| maps.prototype.generateMovableArray = function (floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     var arrays = this._generateMovableArray_arrays(floorId);
 | ||
| 
 | ||
|     var width = core.floors[floorId].width,
 | ||
|         height = core.floors[floorId].height;
 | ||
|     var array = [];
 | ||
|     for (var x = 0; x < width; ++x) {
 | ||
|         array[x] = Array(height).fill([]);
 | ||
|     }
 | ||
|     var v2 = floorId == core.status.floorId && core.bigmap.v2;
 | ||
|     const half = core._HALF_WIDTH_;
 | ||
|     var startX = v2
 | ||
|         ? Math.max(0, core.bigmap.posX - half - core.bigmap.extend)
 | ||
|         : 0;
 | ||
|     var endX = v2
 | ||
|         ? Math.min(
 | ||
|               width,
 | ||
|               core.bigmap.posX + core._WIDTH_ - half + core.bigmap.extend + 1
 | ||
|           )
 | ||
|         : width;
 | ||
|     var startY = v2
 | ||
|         ? Math.max(0, core.bigmap.posY - half - core.bigmap.extend)
 | ||
|         : 0;
 | ||
|     var endY = v2
 | ||
|         ? Math.min(
 | ||
|               height,
 | ||
|               core.bigmap.posY + core._HEIGHT_ - half + core.bigmap.extend + 1
 | ||
|           )
 | ||
|         : height;
 | ||
| 
 | ||
|     for (var x = startX; x < endX; x++) {
 | ||
|         for (var y = startY; y < endY; y++) {
 | ||
|             array[x][y] = ['left', 'down', 'up', 'right'].filter(
 | ||
|                 function (direction) {
 | ||
|                     return core.maps._canMoveHero_checkPoint(
 | ||
|                         x,
 | ||
|                         y,
 | ||
|                         direction,
 | ||
|                         floorId,
 | ||
|                         arrays
 | ||
|                     );
 | ||
|                 }
 | ||
|             );
 | ||
|         }
 | ||
|     }
 | ||
|     return array;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._generateMovableArray_arrays = function (floorId) {
 | ||
|     // see src/plugin/game/fiveLayer.js
 | ||
| };
 | ||
| 
 | ||
| ////// 勇士能否前往某方向 //////
 | ||
| maps.prototype.canMoveHero = function (x, y, direction, floorId) {
 | ||
|     if (x == null) x = core.getHeroLoc('x');
 | ||
|     if (y == null) y = core.getHeroLoc('y');
 | ||
|     direction = direction || core.getHeroLoc('direction');
 | ||
|     return this._canMoveHero_checkPoint(x, y, direction, floorId);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveHero_checkPoint = function (
 | ||
|     x,
 | ||
|     y,
 | ||
|     direction,
 | ||
|     floorId,
 | ||
|     arrays
 | ||
| ) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return false;
 | ||
|     arrays = arrays || this._generateMovableArray_arrays(floorId);
 | ||
|     const floor = core.status.maps[floorId];
 | ||
| 
 | ||
|     // 1. 检查该点 cannotMove
 | ||
|     if (
 | ||
|         core.inArray(
 | ||
|             (core.floors[floorId].cannotMove || {})[x + ',' + y],
 | ||
|             direction
 | ||
|         )
 | ||
|     )
 | ||
|         return false;
 | ||
| 
 | ||
|     var nx = x + core.utils.scan[direction].x,
 | ||
|         ny = y + core.utils.scan[direction].y;
 | ||
| 
 | ||
|     if (
 | ||
|         nx < 0 ||
 | ||
|         ny < 0 ||
 | ||
|         nx >= core.floors[floorId].width ||
 | ||
|         ny >= core.floors[floorId].height
 | ||
|     )
 | ||
|         return false;
 | ||
| 
 | ||
|     // 2. 检查下个点的 cannotMoveIn
 | ||
|     if (
 | ||
|         core.inArray(
 | ||
|             (core.floors[floorId].cannotMoveIn || {})[nx + ',' + ny],
 | ||
|             core.turnDirection(':back', direction)
 | ||
|         )
 | ||
|     )
 | ||
|         return false;
 | ||
| 
 | ||
|     // 3. 检查该点素材的 cannotOut 和下一个点的 cannotIn
 | ||
|     if (
 | ||
|         this._canMoveHero_checkCannotInOut(
 | ||
|             Object.keys(arrays).map(function (name) {
 | ||
|                 return arrays[name][y][x];
 | ||
|             }),
 | ||
|             'cannotOut',
 | ||
|             direction
 | ||
|         )
 | ||
|     )
 | ||
|         return false;
 | ||
|     if (
 | ||
|         this._canMoveHero_checkCannotInOut(
 | ||
|             Object.keys(arrays).map(function (name) {
 | ||
|                 return arrays[name][ny][nx];
 | ||
|             }),
 | ||
|             'cannotIn',
 | ||
|             direction
 | ||
|         )
 | ||
|     )
 | ||
|         return false;
 | ||
| 
 | ||
|     // 4. 检查是否能进将死的领域
 | ||
|     if (
 | ||
|         floorId == core.status.floorId &&
 | ||
|         !core.flags.canGoDeadZone &&
 | ||
|         !core.status.lockControl &&
 | ||
|         Math.max(core.status.hero.hp, 1) <=
 | ||
|             (floor.enemy.mapDamage[`${nx},${ny}`]?.damage ?? 0) &&
 | ||
|         arrays.eventArray[ny][nx] == 0
 | ||
|     )
 | ||
|         return false;
 | ||
| 
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveHero_checkCannotInOut = function (
 | ||
|     number,
 | ||
|     name,
 | ||
|     direction
 | ||
| ) {
 | ||
|     if (number instanceof Array) {
 | ||
|         for (var x in number) {
 | ||
|             if (this._canMoveHero_checkCannotInOut(number[x], name, direction))
 | ||
|                 return true;
 | ||
|         }
 | ||
|         return false;
 | ||
|     }
 | ||
|     if (name == 'cannotIn') direction = core.turnDirection(':back', direction);
 | ||
|     return core.inArray(
 | ||
|         (this.getBlockByNumber(number).event || {})[name],
 | ||
|         direction
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 能否瞬间移动 //////
 | ||
| maps.prototype.canMoveDirectly = function (destX, destY) {
 | ||
|     return this.canMoveDirectlyArray([[destX, destY]])[0];
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.canMoveDirectlyArray = function (locs, canMoveArray) {
 | ||
|     var ans = [],
 | ||
|         number = locs.length;
 | ||
| 
 | ||
|     var fromX = core.getHeroLoc('x'),
 | ||
|         fromY = core.getHeroLoc('y');
 | ||
|     if (!this._canMoveDirectly_checkGlobal()) {
 | ||
|         for (var i = 0; i < number; ++i) ans.push(-1);
 | ||
|         return ans;
 | ||
|     }
 | ||
|     for (var i = 0; i < number; ++i) {
 | ||
|         if (locs[i][0] == fromX && locs[i][1] == fromY) {
 | ||
|             ans.push(0);
 | ||
|             number--;
 | ||
|         } else if (
 | ||
|             locs[i][0] < 0 ||
 | ||
|             locs[i][0] >= core.bigmap.width ||
 | ||
|             locs[i][1] < 0 ||
 | ||
|             locs[i][1] >= core.bigmap.height
 | ||
|         ) {
 | ||
|             ans.push(-1);
 | ||
|             number--;
 | ||
|         } else ans.push(null);
 | ||
|     }
 | ||
|     if (number == 0) return ans;
 | ||
| 
 | ||
|     // 检查起点事件
 | ||
|     if (!this._canMoveDirectly_checkStartPoint(fromX, fromY)) {
 | ||
|         for (var i in ans) {
 | ||
|             if (ans[i] == null) ans[i] = -1;
 | ||
|         }
 | ||
|         return ans;
 | ||
|     }
 | ||
| 
 | ||
|     return this._canMoveDirectly_bfs(
 | ||
|         fromX,
 | ||
|         fromY,
 | ||
|         locs,
 | ||
|         number,
 | ||
|         ans,
 | ||
|         canMoveArray
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveDirectly_checkGlobal = function () {
 | ||
|     // 检查全塔是否禁止瞬间移动
 | ||
|     if (!core.flags.enableMoveDirectly) return false;
 | ||
|     // 检查该楼层是否不可瞬间移动
 | ||
|     if (core.status.thisMap.cannotMoveDirectly) return false;
 | ||
|     // flag:cannotMoveDirectly为true:不能
 | ||
|     if (core.hasFlag('cannotMoveDirectly')) return false;
 | ||
| 
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveDirectly_checkStartPoint = function (sx, sy) {
 | ||
|     if (core.status.thisMap.enemy.mapDamage[`${sx},${sy}`]) return false;
 | ||
|     var block = core.getBlock(sx, sy);
 | ||
|     if (block != null) {
 | ||
|         // 只有起点是传送点才是能无视
 | ||
|         return block.event.trigger == 'changeFloor';
 | ||
|     }
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveDirectly_bfs = function (
 | ||
|     sx,
 | ||
|     sy,
 | ||
|     locs,
 | ||
|     number,
 | ||
|     ans,
 | ||
|     canMoveArray
 | ||
| ) {
 | ||
|     canMoveArray = canMoveArray || this.generateMovableArray();
 | ||
|     var blocksObj = this.getMapBlocksObj();
 | ||
|     // 滑冰
 | ||
|     var bgMap = this.getBgMapArray();
 | ||
| 
 | ||
|     var visited = [],
 | ||
|         queue = [];
 | ||
|     visited[sx + ',' + sy] = 0;
 | ||
|     queue.push(sx + ',' + sy);
 | ||
| 
 | ||
|     while (queue.length > 0) {
 | ||
|         var now = queue.shift().split(','),
 | ||
|             x = parseInt(now[0]),
 | ||
|             y = parseInt(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 (!this._canMoveDirectly_checkNextPoint(blocksObj, nx, ny))
 | ||
|                 continue;
 | ||
|             visited[nindex] = visited[now] + 1;
 | ||
|             // if (nx == ex && ny == ey) return visited[nindex];
 | ||
|             for (var i in ans) {
 | ||
|                 if (locs[i][0] == nx && locs[i][1] == ny && ans[i] == null) {
 | ||
|                     // 不可以绿点为终点
 | ||
|                     var block = blocksObj[nx + ',' + ny];
 | ||
|                     if (block && !block.disable && block.event.trigger) {
 | ||
|                         ans[i] = -1;
 | ||
|                     } else {
 | ||
|                         ans[i] = visited[nindex];
 | ||
|                     }
 | ||
|                     number--;
 | ||
|                     if (number == 0) return ans;
 | ||
|                 }
 | ||
|             }
 | ||
|             queue.push(nindex);
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     for (var i in ans) {
 | ||
|         if (ans[i] == null) ans[i] = -1;
 | ||
|     }
 | ||
|     return ans;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._canMoveDirectly_checkNextPoint = function (blocksObj, x, y) {
 | ||
|     var index = x + ',' + y;
 | ||
|     var block = blocksObj[index];
 | ||
|     // 该点是否不可通行或有脚本
 | ||
|     if (
 | ||
|         block &&
 | ||
|         !block.disable &&
 | ||
|         (block.event.noPass || block.event.script || block.event.event)
 | ||
|     )
 | ||
|         return false;
 | ||
|     // 该点是否是绿点可触发
 | ||
|     if (block && !block.disable && block.event.trigger) {
 | ||
|         if (block.event.trigger != 'changeFloor') return false;
 | ||
|         var ignore = core.flags.ignoreChangeFloor;
 | ||
|         if (block.event.data && block.event.data.ignoreChangeFloor != null)
 | ||
|             ignore = block.event.data.ignoreChangeFloor;
 | ||
|         if (!ignore) return false;
 | ||
|     }
 | ||
|     // 是否存在阻激夹域伤害
 | ||
|     const damage = core.status.thisMap.enemy.mapDamage[index];
 | ||
|     if (damage) {
 | ||
|         if (damage.damage !== 0) return false;
 | ||
|         if (damage.ambush) return false;
 | ||
|         if (damage.repulse) return false;
 | ||
|     }
 | ||
| 
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| ////// 自动寻路找寻最优路径 //////
 | ||
| maps.prototype.automaticRoute = function (destX, destY) {
 | ||
|     var startX = core.getHeroLoc('x'),
 | ||
|         startY = core.getHeroLoc('y');
 | ||
|     if (destX == startX && destY == startY) return [];
 | ||
|     // BFS找寻最短路径
 | ||
|     var route = this._automaticRoute_bfs(startX, startY, destX, destY);
 | ||
|     if (route[destX + ',' + destY] == null) return [];
 | ||
|     // 路径数组转换
 | ||
|     var ans = [],
 | ||
|         nowX = destX,
 | ||
|         nowY = destY;
 | ||
|     while (nowX != startX || nowY != startY) {
 | ||
|         var dir = route[nowX + ',' + nowY];
 | ||
|         ans.push({ direction: dir, x: nowX, y: nowY });
 | ||
|         nowX -= core.utils.scan[dir].x;
 | ||
|         nowY -= core.utils.scan[dir].y;
 | ||
|     }
 | ||
|     ans.reverse();
 | ||
|     return ans;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._automaticRoute_bfs = function (startX, startY, destX, destY) {
 | ||
|     var route = {},
 | ||
|         canMoveArray = this.generateMovableArray();
 | ||
|     // 使用优先队列
 | ||
|     var queue = new PriorityQueue({
 | ||
|         comparator: function (a, b) {
 | ||
|             return a.depth - b.depth;
 | ||
|         }
 | ||
|     });
 | ||
|     route[startX + ',' + startY] = '';
 | ||
|     queue.queue({ depth: 0, x: startX, y: startY });
 | ||
|     var blocks = core.getMapBlocksObj();
 | ||
|     const floor = core.status.thisMap;
 | ||
| 
 | ||
|     while (queue.length != 0) {
 | ||
|         var curr = queue.dequeue(),
 | ||
|             deep = curr.depth,
 | ||
|             nowX = curr.x,
 | ||
|             nowY = curr.y;
 | ||
|         for (var direction in core.utils.scan) {
 | ||
|             if (!core.inArray(canMoveArray[nowX][nowY], direction)) continue;
 | ||
|             var nx = nowX + core.utils.scan[direction].x;
 | ||
|             var ny = nowY + core.utils.scan[direction].y;
 | ||
| 
 | ||
|             if (
 | ||
|                 nx < 0 ||
 | ||
|                 nx >= core.bigmap.width ||
 | ||
|                 ny < 0 ||
 | ||
|                 ny >= core.bigmap.height ||
 | ||
|                 route[nx + ',' + ny] != null
 | ||
|             )
 | ||
|                 continue;
 | ||
| 
 | ||
|             // 重点
 | ||
|             if (nx == destX && ny == destY) {
 | ||
|                 route[nx + ',' + ny] = direction;
 | ||
|                 break;
 | ||
|             }
 | ||
|             // 不可通行
 | ||
|             if (core.noPass(nx, ny)) continue;
 | ||
|             route[nx + ',' + ny] = direction;
 | ||
|             queue.queue({
 | ||
|                 depth: deep + this._automaticRoute_deepAdd(nx, ny, blocks),
 | ||
|                 x: nx,
 | ||
|                 y: ny
 | ||
|             });
 | ||
|         }
 | ||
|         if (route[destX + ',' + destY] != null) break;
 | ||
|     }
 | ||
|     return route;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._automaticRoute_deepAdd = function (x, y, blocks) {
 | ||
|     // 判定每个可通行点的损耗值,越高越应该绕路
 | ||
|     var deepAdd = 1;
 | ||
|     var block = blocks[x + ',' + y];
 | ||
|     if (block && !block.disable) {
 | ||
|         var id = block.event.id;
 | ||
| 
 | ||
|         // 绕过血瓶和绿宝石
 | ||
|         if (
 | ||
|             core.hasFlag('__potionNoRouting__') &&
 | ||
|             (id.endsWith('Potion') || id == 'greenGem')
 | ||
|         )
 | ||
|             deepAdd += 100;
 | ||
|     }
 | ||
|     // 绕过存在伤害的地方
 | ||
|     const damage = core.status.thisMap.enemy.mapDamage[`${x},${y}`];
 | ||
|     if (damage) {
 | ||
|         deepAdd += damage.damage * 100;
 | ||
|         deepAdd += !!damage.mockery ? 1e8 : 0;
 | ||
|         deepAdd += !!damage.hunt ? 1e8 : 0;
 | ||
|     }
 | ||
| 
 | ||
|     return deepAdd;
 | ||
| };
 | ||
| 
 | ||
| // -------- 绘制地图,各层图块,楼层贴图,Autotile -------- //
 | ||
| 
 | ||
| maps.prototype._getBigImageInfo = function (bigImage, face, animate) {
 | ||
|     face = face || 'down';
 | ||
|     if (['up', 'down', 'left', 'right'].indexOf(face) < 0) face = 'down';
 | ||
|     var per_width = bigImage.width / 4;
 | ||
|     var per_height = bigImage.height / 4;
 | ||
|     var sx = animate * per_width,
 | ||
|         sy;
 | ||
|     if (per_height <= per_width / 2) {
 | ||
|         // 强制视为 1*4 的怪物
 | ||
|         per_height = bigImage.height;
 | ||
|         sy = 0;
 | ||
|     } else {
 | ||
|         sy = core.material.icons.hero[face].loc * per_height;
 | ||
|     }
 | ||
|     var dx, dy;
 | ||
|     switch (face) {
 | ||
|         case 'down':
 | ||
|         case 'up':
 | ||
|         case 'left':
 | ||
|         case 'right':
 | ||
|             dx = 16 - per_width / 2;
 | ||
|             dy = 32 - per_height;
 | ||
|             break;
 | ||
|         // case "left": dx = 0; dy = 32 - per_height; break;
 | ||
|         // case "right": dx = 32 - per_width; dy = 32 - per_height; break;
 | ||
|     }
 | ||
| 
 | ||
|     return {
 | ||
|         sx: sx,
 | ||
|         sy: sy,
 | ||
|         per_width: per_width,
 | ||
|         per_height: per_height,
 | ||
|         face: face,
 | ||
|         dx: dx,
 | ||
|         dy: dy
 | ||
|     };
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制一个图块 //////
 | ||
| maps.prototype.drawBlock = function (block, animate, ctx) {
 | ||
|     if (block.event.id == 'none') return;
 | ||
|     var redraw = animate != null;
 | ||
|     if (!redraw) animate = 0;
 | ||
|     var x = block.x,
 | ||
|         y = block.y;
 | ||
|     // --- 在界面外的动画不绘制
 | ||
| 
 | ||
|     // 判定是否绘制
 | ||
|     if (core.bigmap.v2) {
 | ||
|         var posX = core.bigmap.posX,
 | ||
|             posY = core.bigmap.posY;
 | ||
|         if (
 | ||
|             x < posX - 1 ||
 | ||
|             y < posY - 1 ||
 | ||
|             x > posX + core._WIDTH_ ||
 | ||
|             y > posY + core._HEIGHT_ + 1
 | ||
|         ) {
 | ||
|             // +1 for 48 height
 | ||
|             return;
 | ||
|         }
 | ||
|     } else {
 | ||
|         if (
 | ||
|             redraw &&
 | ||
|             block.event.animate > 1 &&
 | ||
|             (32 * x < core.bigmap.offsetX - 64 ||
 | ||
|                 32 * x > core.bigmap.offsetX + core._PX_ + 32 ||
 | ||
|                 32 * y < core.bigmap.offsetY - 64 ||
 | ||
|                 32 * y > core.bigmap.offsetY + core._PY_ + 32 + 16)
 | ||
|         ) {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     var blockInfo = this.getBlockInfo(block);
 | ||
|     if (blockInfo == null) return;
 | ||
|     if (blockInfo.cls != 'tileset')
 | ||
|         blockInfo.posX = animate % blockInfo.animate;
 | ||
|     blockInfo.opacity = block.opacity;
 | ||
|     blockInfo.filter = block.filter;
 | ||
|     if (!block.name) this._drawBlockInfo(blockInfo, block.x, block.y, ctx);
 | ||
|     else this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y, ctx);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBlockInfo_bigImage = function (blockInfo, x, y, ctx) {
 | ||
|     var bigImageInfo = this._getBigImageInfo(
 | ||
|         blockInfo.bigImage,
 | ||
|         blockInfo.face,
 | ||
|         blockInfo.posX
 | ||
|     );
 | ||
|     var per_width = bigImageInfo.per_width,
 | ||
|         per_height = bigImageInfo.per_height,
 | ||
|         sx = bigImageInfo.sx,
 | ||
|         sy = bigImageInfo.sy;
 | ||
|     var bigImage = blockInfo.bigImage;
 | ||
| 
 | ||
|     if (main.mode == 'editor') {
 | ||
|         var px = 32 * x - 32 * core.bigmap.posX;
 | ||
|         var py = 32 * y - 32 * core.bigmap.posY;
 | ||
|         if (ctx == null) ctx = 'event';
 | ||
|         core.clearMap(ctx, px, py, 32, 32);
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             bigImage,
 | ||
|             sx,
 | ||
|             sy,
 | ||
|             per_width,
 | ||
|             per_height,
 | ||
|             px,
 | ||
|             py,
 | ||
|             32,
 | ||
|             32
 | ||
|         );
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     var px = 32 * x - core.bigmap.offsetX;
 | ||
|     var py = 32 * y - core.bigmap.offsetY;
 | ||
| 
 | ||
|     // 上半部分 - 会遮挡勇士;z值高于event2,为51
 | ||
|     var header = '_bigImage_header_' + x + '_' + y;
 | ||
|     // 下半部分 - 会被勇士遮挡;z值高于event,为31
 | ||
|     var body = '_bigImage_body_' + x + '_' + y;
 | ||
|     var dx = bigImageInfo.dx,
 | ||
|         dy = bigImageInfo.dy;
 | ||
| 
 | ||
|     switch (bigImageInfo.face) {
 | ||
|         case 'down':
 | ||
|         case 'up':
 | ||
|         case 'left':
 | ||
|         case 'right':
 | ||
|             core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
 | ||
|                 core.drawImage(
 | ||
|                     header,
 | ||
|                     bigImage,
 | ||
|                     sx,
 | ||
|                     sy,
 | ||
|                     per_width,
 | ||
|                     -dy,
 | ||
|                     0,
 | ||
|                     0,
 | ||
|                     per_width,
 | ||
|                     -dy
 | ||
|                 );
 | ||
|             });
 | ||
|             core.createCanvas(body, px + dx, py, per_width, 32, 31);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
 | ||
|                 core.drawImage(
 | ||
|                     body,
 | ||
|                     bigImage,
 | ||
|                     sx,
 | ||
|                     sy - dy,
 | ||
|                     per_width,
 | ||
|                     32,
 | ||
|                     0,
 | ||
|                     0,
 | ||
|                     per_width,
 | ||
|                     32
 | ||
|                 );
 | ||
|             });
 | ||
|             break;
 | ||
|         /*case "left":
 | ||
|             core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
 | ||
|                 core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
 | ||
|             });
 | ||
|             core.createCanvas(body, px + dx, py, per_width, 32, 31);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
 | ||
|                 core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
 | ||
|             });
 | ||
|             break;
 | ||
|         case "right":
 | ||
|             core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
 | ||
|                 core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
 | ||
|             });
 | ||
|             core.createCanvas(body, px + dx, py, per_width, per_height / 2 + 16, 31);
 | ||
|             this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
 | ||
|                 core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
 | ||
|             });
 | ||
|             break;*/
 | ||
|     }
 | ||
|     if (core.dymCanvas[header]) {
 | ||
|         core.dymCanvas[header].canvas.setAttribute('_ox', 32 * x + dx);
 | ||
|         core.dymCanvas[header].canvas.setAttribute('_oy', 32 * y + dy);
 | ||
|     }
 | ||
|     if (core.dymCanvas[body]) {
 | ||
|         core.dymCanvas[body].canvas.setAttribute('_ox', 32 * x + dx);
 | ||
|         core.dymCanvas[body].canvas.setAttribute('_oy', 32 * y);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBlockInfo_drawWithFilter = function (blockInfo, ctx, func) {
 | ||
|     var alpha = null;
 | ||
|     if (blockInfo.opacity != null)
 | ||
|         alpha = core.setAlpha(ctx, blockInfo.opacity);
 | ||
|     core.setFilter(ctx, blockInfo.filter);
 | ||
|     func();
 | ||
|     core.setFilter(ctx, null);
 | ||
|     if (alpha != null) core.setAlpha(ctx, alpha);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBlockInfo = function (blockInfo, x, y, ctx) {
 | ||
|     if (blockInfo.bigImage)
 | ||
|         return this._drawBlockInfo_bigImage(blockInfo, x, y, ctx);
 | ||
| 
 | ||
|     var image = blockInfo.image,
 | ||
|         posX = blockInfo.posX,
 | ||
|         posY = blockInfo.posY,
 | ||
|         height = blockInfo.height;
 | ||
|     var px = 32 * x - 32 * core.bigmap.posX;
 | ||
|     var py = 32 * y - 32 * core.bigmap.posY;
 | ||
|     if (ctx == null) ctx = 'event';
 | ||
| 
 | ||
|     this._drawBlockInfo_drawWithFilter(blockInfo, ctx, function () {
 | ||
|         core.clearMap(ctx, px, py, 32, 32);
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             image,
 | ||
|             posX * 32,
 | ||
|             posY * height + height - 32,
 | ||
|             32,
 | ||
|             32,
 | ||
|             px,
 | ||
|             py,
 | ||
|             32,
 | ||
|             32
 | ||
|         );
 | ||
|     });
 | ||
|     if (height > 32) {
 | ||
|         this._drawBlockInfo_drawWithFilter(blockInfo, 'event2', function () {
 | ||
|             core.clearMap('event2', px, py + 32 - height, 32, height - 32);
 | ||
|             core.drawImage(
 | ||
|                 'event2',
 | ||
|                 image,
 | ||
|                 posX * 32,
 | ||
|                 posY * height,
 | ||
|                 32,
 | ||
|                 height - 32,
 | ||
|                 px,
 | ||
|                 py + 32 - height,
 | ||
|                 32,
 | ||
|                 height - 32
 | ||
|             );
 | ||
|         });
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y, ctx) {
 | ||
|     var image = blockInfo.image,
 | ||
|         posX = blockInfo.posX,
 | ||
|         posY = blockInfo.posY,
 | ||
|         height = blockInfo.height;
 | ||
|     var px = 32 * x - 32 * core.bigmap.posX;
 | ||
|     var py = 32 * y - 32 * core.bigmap.posY;
 | ||
|     if (ctx == null) ctx = name;
 | ||
| 
 | ||
|     core.clearMap(ctx, px, py + 32 - height, 32, height);
 | ||
|     if (name == 'bg') {
 | ||
|         if (height > 32) {
 | ||
|             core.clearMap(ctx, px, py - 32, 32, 32);
 | ||
|             core.drawImage(ctx, core.material.groundCanvas.canvas, px, py - 32);
 | ||
|         }
 | ||
|         core.drawImage(ctx, core.material.groundCanvas.canvas, px, py);
 | ||
|     }
 | ||
|     var alpha = null;
 | ||
|     if (blockInfo.opacity != null)
 | ||
|         alpha = core.setAlpha(ctx, blockInfo.opacity);
 | ||
|     else if (name == 'fg' && this._drawBlockInfo_shouldBlurFg(x, y))
 | ||
|         alpha = core.setAlpha(ctx, 0.6);
 | ||
|     core.setFilter(ctx, blockInfo.filter);
 | ||
|     core.drawImage(
 | ||
|         ctx,
 | ||
|         image,
 | ||
|         posX * 32,
 | ||
|         posY * height,
 | ||
|         32,
 | ||
|         height,
 | ||
|         px,
 | ||
|         py + 32 - height,
 | ||
|         32,
 | ||
|         height
 | ||
|     );
 | ||
|     core.setFilter(ctx, null);
 | ||
|     if (alpha != null) core.setAlpha(ctx, alpha);
 | ||
| };
 | ||
| 
 | ||
| ////// 是否应当存在事件时虚化前景层 //////
 | ||
| maps.prototype._drawBlockInfo_shouldBlurFg = function (x, y) {
 | ||
|     if (main.mode == 'play' && !core.flags.blurFg) return false;
 | ||
|     var block = this.getBlock(x, y);
 | ||
|     if (block == null || block.id == 0) return false;
 | ||
|     if (block.event.cls == 'autotile' || block.event.cls == 'tileset')
 | ||
|         return block.event.script || block.event.event;
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| ////// 生成groundPattern //////
 | ||
| maps.prototype.generateGroundPattern = function (floorId) {
 | ||
|     // 生成floorId层的groundPattern(盒子内的怪物动画)
 | ||
|     var groundId =
 | ||
|         (
 | ||
|             (core.status.maps || core.floors)[floorId || core.status.floorId] ||
 | ||
|             {}
 | ||
|         ).defaultGround || 'ground';
 | ||
|     var groundInfo = core.getBlockInfo(groundId);
 | ||
|     if (groundInfo == null) return;
 | ||
|     core.material.groundCanvas.clearRect(0, 0, 32, 32);
 | ||
|     core.material.groundCanvas.drawImage(
 | ||
|         groundInfo.image,
 | ||
|         32 * groundInfo.posX,
 | ||
|         groundInfo.height * groundInfo.posY,
 | ||
|         32,
 | ||
|         32,
 | ||
|         0,
 | ||
|         0,
 | ||
|         32,
 | ||
|         32
 | ||
|     );
 | ||
|     core.material.groundPattern = core.material.groundCanvas.createPattern(
 | ||
|         core.material.groundCanvas.canvas,
 | ||
|         'repeat'
 | ||
|     );
 | ||
|     // 如果需要用纯色可以直接将下面代码改成改成
 | ||
|     // core.material.groundPattern = '#000000';
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制某张地图 //////
 | ||
| maps.prototype.drawMap = function (floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     // core.clearMap('all');
 | ||
|     // this.generateGroundPattern(floorId);
 | ||
|     core.status.floorId = floorId;
 | ||
|     core.extractBlocks(floorId);
 | ||
|     core.status.thisMap = core.status.maps[floorId];
 | ||
| 
 | ||
|     if (main.mode === 'editor') {
 | ||
|         this._drawMap_drawAll();
 | ||
|         if (core.status.curtainColor) {
 | ||
|             core.fillRect(
 | ||
|                 'curtain',
 | ||
|                 0,
 | ||
|                 0,
 | ||
|                 core._PX_,
 | ||
|                 core._PY_,
 | ||
|                 core.arrayToRGBA(core.status.curtainColor)
 | ||
|             );
 | ||
|         }
 | ||
|         core.drawHero();
 | ||
|     }
 | ||
|     core.updateStatusBar();
 | ||
| };
 | ||
| 
 | ||
| ////// 重绘某张地图 //////
 | ||
| maps.prototype.redrawMap = function () {
 | ||
|     if (main.mode === 'editor') {
 | ||
|         core.bigmap.canvas.forEach(function (one) {
 | ||
|             core.clearMap(one);
 | ||
|         });
 | ||
|         this._drawMap_drawAll(null, { redraw: true });
 | ||
|         core.drawDamage();
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawMap_drawAll = function (floorId, config) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     this.drawBg(floorId, config);
 | ||
|     this.drawEvents(floorId);
 | ||
|     this.drawFg(floorId, config);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawMap_drawBlockInfo = function (
 | ||
|     ctx,
 | ||
|     block,
 | ||
|     blockInfo,
 | ||
|     arr,
 | ||
|     config
 | ||
| ) {
 | ||
|     if (blockInfo == null) return;
 | ||
|     var onMap = config.onMap;
 | ||
|     if (onMap && core.bigmap.v2) {
 | ||
|         // 判定是否绘制
 | ||
|         var posX = core.bigmap.posX,
 | ||
|             posY = core.bigmap.posY;
 | ||
|         if (
 | ||
|             block.x < posX - 1 ||
 | ||
|             block.y < posY - 1 ||
 | ||
|             block.x > posX + core._WIDTH_ ||
 | ||
|             block.y > posY + core._HEIGHT_ + 1
 | ||
|         ) {
 | ||
|             // +1 for 48 height
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     if (blockInfo.cls == 'autotile') {
 | ||
|         // Autotile单独处理
 | ||
|         var alpha = null;
 | ||
|         if (block.opacity != null) alpha = core.setAlpha(ctx, block.opacity);
 | ||
|         core.setFilter(ctx, block.filter);
 | ||
|         this._drawAutotile(ctx, arr, block, 32, 0, 0, 0, onMap);
 | ||
|         core.setFilter(ctx, null);
 | ||
|         if (alpha != null) core.setAlpha(ctx, alpha);
 | ||
|         if (onMap) this.addGlobalAnimate(block);
 | ||
|         return;
 | ||
|     }
 | ||
|     if (!onMap) {
 | ||
|         var height = blockInfo.height;
 | ||
|         if (blockInfo.bigImage) {
 | ||
|             config.postDraw.push(function () {
 | ||
|                 var bigImageInfo = core.maps._getBigImageInfo(
 | ||
|                     blockInfo.bigImage,
 | ||
|                     blockInfo.face,
 | ||
|                     0
 | ||
|                 );
 | ||
|                 var per_width = bigImageInfo.per_width,
 | ||
|                     per_height = bigImageInfo.per_height;
 | ||
|                 core.maps._drawBlockInfo_drawWithFilter(
 | ||
|                     block,
 | ||
|                     ctx,
 | ||
|                     function () {
 | ||
|                         core.drawImage(
 | ||
|                             ctx,
 | ||
|                             blockInfo.bigImage,
 | ||
|                             bigImageInfo.sx,
 | ||
|                             bigImageInfo.sy,
 | ||
|                             per_width,
 | ||
|                             per_height,
 | ||
|                             32 * block.x + bigImageInfo.dx,
 | ||
|                             32 * block.y + bigImageInfo.dy,
 | ||
|                             per_width,
 | ||
|                             per_height
 | ||
|                         );
 | ||
|                     }
 | ||
|                 );
 | ||
|             });
 | ||
|             return;
 | ||
|         }
 | ||
|         this._drawBlockInfo_drawWithFilter(block, ctx, function () {
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 blockInfo.image,
 | ||
|                 32 * blockInfo.posX,
 | ||
|                 height * blockInfo.posY,
 | ||
|                 32,
 | ||
|                 height,
 | ||
|                 32 * block.x,
 | ||
|                 32 * block.y + 32 - height,
 | ||
|                 32,
 | ||
|                 height
 | ||
|             );
 | ||
|         });
 | ||
|         return;
 | ||
|     }
 | ||
|     this.drawBlock(block, null, ctx);
 | ||
|     this.addGlobalAnimate(block);
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制背景层 //////
 | ||
| // config:绘制的参数,可包含如下项:
 | ||
| // redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用);
 | ||
| maps.prototype.drawBg = function (floorId, config) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (config == null) config = {};
 | ||
|     if (typeof config == 'string' || config.canvas) config = { ctx: config };
 | ||
|     config = Object.assign({}, config);
 | ||
|     if (config.ctx == null) {
 | ||
|         config.onMap = true;
 | ||
|         config.ctx = 'bg';
 | ||
|         core.clearMap('bg');
 | ||
|         core.status.floorAnimateObjs = this._getFloorImages(floorId);
 | ||
|     }
 | ||
|     var toDrawCtx = core.getContextByName(config.ctx);
 | ||
|     if (!toDrawCtx) return;
 | ||
| 
 | ||
|     var cacheCtx = toDrawCtx;
 | ||
|     if (config.onMap) {
 | ||
|         cacheCtx = core.bigmap.cacheCanvas;
 | ||
|         cacheCtx.canvas.width = toDrawCtx.canvas.width;
 | ||
|         cacheCtx.canvas.height = toDrawCtx.canvas.height;
 | ||
|         if (core.bigmap.v2) cacheCtx.translate(32, 32);
 | ||
|     }
 | ||
|     this._drawBg_draw(floorId, toDrawCtx, cacheCtx, config);
 | ||
|     if (config.onMap) cacheCtx.translate(0, 0);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
 | ||
|     // see src/plugin/game/fiveLayer.js
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawBg_drawBackground = function (floorId, config) {
 | ||
|     var groundId =
 | ||
|         (core.status.maps || core.floors)[floorId].defaultGround || 'ground';
 | ||
|     var groundInfo = core.getBlockInfo(groundId);
 | ||
|     var onMap = config.onMap;
 | ||
|     if (groundInfo != null) {
 | ||
|         var start = onMap && core.bigmap.v2 ? -1 : 0;
 | ||
|         var endX =
 | ||
|             onMap && core.bigmap.v2
 | ||
|                 ? core._WIDTH_ + 1
 | ||
|                 : core.floors[floorId].width;
 | ||
|         var endY =
 | ||
|             onMap && core.bigmap.v2
 | ||
|                 ? core._HEIGHT_ + 1
 | ||
|                 : core.floors[floorId].height;
 | ||
| 
 | ||
|         var patternCanvas = document.createElement('canvas');
 | ||
|         patternCanvas.width = patternCanvas.height = 32;
 | ||
|         var patternCtx = patternCanvas.getContext('2d');
 | ||
|         core.drawImage(
 | ||
|             patternCtx,
 | ||
|             groundInfo.image,
 | ||
|             32 * groundInfo.posX,
 | ||
|             groundInfo.height * groundInfo.posY,
 | ||
|             32,
 | ||
|             32,
 | ||
|             0,
 | ||
|             0,
 | ||
|             32,
 | ||
|             32
 | ||
|         );
 | ||
| 
 | ||
|         core.fillRect(
 | ||
|             config.ctx,
 | ||
|             32 * start,
 | ||
|             32 * start,
 | ||
|             32 * (endX - start),
 | ||
|             32 * (endY - start),
 | ||
|             patternCtx.createPattern(patternCanvas, 'repeat')
 | ||
|         );
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制事件层 //////
 | ||
| maps.prototype.drawEvents = function (floorId, blocks, config) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (config == null) config = {};
 | ||
|     if (typeof config == 'string' || config.canvas) config = { ctx: config };
 | ||
|     config = Object.assign({}, config);
 | ||
|     if (config.ctx == null) {
 | ||
|         config.onMap = true;
 | ||
|         config.ctx = 'event';
 | ||
|         core.clearMap('event');
 | ||
|         core.clearMap('event2');
 | ||
|     }
 | ||
|     var toDrawCtx = core.getContextByName(config.ctx);
 | ||
|     if (!toDrawCtx) return;
 | ||
| 
 | ||
|     var cacheCtx = toDrawCtx;
 | ||
|     if (config.onMap) {
 | ||
|         cacheCtx = core.bigmap.cacheCanvas;
 | ||
|         cacheCtx.canvas.width = toDrawCtx.canvas.width;
 | ||
|         cacheCtx.canvas.height = toDrawCtx.canvas.height;
 | ||
|         if (core.bigmap.v2) cacheCtx.translate(32, 32);
 | ||
|     }
 | ||
| 
 | ||
|     var arr = null;
 | ||
|     if (!blocks) {
 | ||
|         core.extractBlocks(floorId);
 | ||
|         blocks = core.status.maps[floorId].blocks;
 | ||
|         arr = this.getMapArray(floorId, !config.redraw);
 | ||
|     } else {
 | ||
|         arr = this._getMapArrayFromBlocks(
 | ||
|             blocks,
 | ||
|             core.floors[floorId].width,
 | ||
|             core.floors[floorId].height
 | ||
|         );
 | ||
|     }
 | ||
|     config.postDraw = [];
 | ||
| 
 | ||
|     blocks
 | ||
|         .filter(function (block) {
 | ||
|             if (config.onMap && core.bigmap.v2) {
 | ||
|                 // 判定是否绘制
 | ||
|                 var posX = core.bigmap.posX,
 | ||
|                     posY = core.bigmap.posY;
 | ||
|                 if (
 | ||
|                     block.x < posX - 1 ||
 | ||
|                     block.y < posY - 1 ||
 | ||
|                     block.x > posX + core._WIDTH_ ||
 | ||
|                     block.y > posY + core._HEIGHT_ + 1
 | ||
|                 ) {
 | ||
|                     // +1 for 48 height
 | ||
|                     return false;
 | ||
|                 }
 | ||
|             }
 | ||
|             return block.event && !block.disable;
 | ||
|         })
 | ||
|         .forEach(function (block) {
 | ||
|             core.maps._drawMap_drawBlockInfo(
 | ||
|                 cacheCtx,
 | ||
|                 block,
 | ||
|                 core.maps.getBlockInfo(block),
 | ||
|                 arr,
 | ||
|                 config
 | ||
|             );
 | ||
|         });
 | ||
|     config.postDraw.forEach(function (v) {
 | ||
|         v();
 | ||
|     });
 | ||
|     delete config.postDraw;
 | ||
| 
 | ||
|     if (config.onMap) {
 | ||
|         core.drawImage(
 | ||
|             toDrawCtx,
 | ||
|             cacheCtx.canvas,
 | ||
|             core.bigmap.v2 ? -32 : 0,
 | ||
|             core.bigmap.v2 ? -32 : 0
 | ||
|         );
 | ||
|         cacheCtx.translate(0, 0);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制前景层 //////
 | ||
| // config:绘制的参数,可包含如下项:
 | ||
| // redraw - 是否是重绘;ctx - 要绘制到的画布(仅限缩略图使用);
 | ||
| maps.prototype.drawFg = function (floorId, config) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (config == null) config = {};
 | ||
|     if (typeof config == 'string' || config.canvas) config = { ctx: config };
 | ||
|     config = Object.assign({}, config);
 | ||
|     if (config.ctx == null) {
 | ||
|         config.onMap = true;
 | ||
|         config.ctx = 'fg';
 | ||
|         core.clearMap('fg');
 | ||
|     }
 | ||
|     var toDrawCtx = core.getContextByName(config.ctx);
 | ||
|     if (!toDrawCtx) return;
 | ||
| 
 | ||
|     var cacheCtx = toDrawCtx;
 | ||
|     if (config.onMap) {
 | ||
|         cacheCtx = core.bigmap.cacheCanvas;
 | ||
|         cacheCtx.canvas.width = toDrawCtx.canvas.width;
 | ||
|         cacheCtx.canvas.height = toDrawCtx.canvas.height;
 | ||
|         if (core.bigmap.v2) cacheCtx.translate(32, 32);
 | ||
|     }
 | ||
|     this._drawFg_draw(floorId, toDrawCtx, cacheCtx, config);
 | ||
|     if (config.onMap) cacheCtx.translate(0, 0);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawFg_draw = function (floorId, toDrawCtx, cacheCtx, config) {
 | ||
|     // see src/plugin/game/fiveLayer.js
 | ||
| };
 | ||
| 
 | ||
| ////// 实际的背景/前景图块的绘制 //////
 | ||
| maps.prototype._drawBgFgMap = function (floorId, name, config) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     var width = core.floors[floorId].width;
 | ||
|     var height = core.floors[floorId].height;
 | ||
| 
 | ||
|     if (!core.status[name + 'maps']) core.status[name + 'maps'] = {};
 | ||
| 
 | ||
|     var startX =
 | ||
|         config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posX - 1) : 0;
 | ||
|     var endX =
 | ||
|         config.onMap && core.bigmap.v2
 | ||
|             ? Math.min(width, core.bigmap.posX + core._WIDTH_ + 1)
 | ||
|             : width;
 | ||
|     var startY =
 | ||
|         config.onMap && core.bigmap.v2 ? Math.max(0, core.bigmap.posY - 1) : 0;
 | ||
|     var endY =
 | ||
|         config.onMap && core.bigmap.v2
 | ||
|             ? Math.min(height, core.bigmap.posY + core._HEIGHT_ + 2)
 | ||
|             : height;
 | ||
| 
 | ||
|     var arr = this._getBgFgMapArray(name, floorId, !config.redraw);
 | ||
|     config.postDraw = [];
 | ||
|     for (var x = startX; x < endX; x++) {
 | ||
|         for (var y = startY; y < endY; y++) {
 | ||
|             if (arr[y][x] == 0) continue;
 | ||
|             var block = this.initBlock(x, y, arr[y][x], true);
 | ||
|             block.name = name;
 | ||
|             var blockInfo = this.getBlockInfo(block);
 | ||
|             if (!blockInfo) continue;
 | ||
|             this._drawMap_drawBlockInfo(
 | ||
|                 config.ctx,
 | ||
|                 block,
 | ||
|                 blockInfo,
 | ||
|                 arr,
 | ||
|                 config
 | ||
|             );
 | ||
|         }
 | ||
|     }
 | ||
|     config.postDraw.forEach(function (v) {
 | ||
|         v();
 | ||
|     });
 | ||
|     delete config.postDraw;
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制楼层贴图 //////
 | ||
| maps.prototype._drawFloorImages = function (
 | ||
|     floorId,
 | ||
|     ctx,
 | ||
|     name,
 | ||
|     images,
 | ||
|     currStatus,
 | ||
|     onMap
 | ||
| ) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!images) images = this._getFloorImages(floorId);
 | ||
|     var redraw = currStatus != null;
 | ||
|     images.forEach(function (one) {
 | ||
|         var image = core.material.images.images[core.getMappedName(one.name)];
 | ||
|         var frame = one.frame || 1;
 | ||
|         if (!image) return;
 | ||
|         var flag = '__floorImg__' + floorId + '_' + one.x + '_' + one.y;
 | ||
|         if (core.hasFlag(flag)) return;
 | ||
|         if (redraw && frame == 1) return; // 不重绘
 | ||
| 
 | ||
|         if (/.*\.gif/i.test(one.name)) {
 | ||
|             if (redraw) return;
 | ||
|             this._drawFloorImages_gif(image, one.x, one.y);
 | ||
|             return;
 | ||
|         }
 | ||
|         this._drawFloorImage(ctx, name, one, image, currStatus, onMap);
 | ||
|     }, this);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getFloorImages = function (floorId) {
 | ||
|     return (
 | ||
|         (
 | ||
|             (core.status.maps || core.floors)[floorId || core.status.floorId] ||
 | ||
|             {}
 | ||
|         ).images || []
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawFloorImages_gif = function (image, dx, dy) {
 | ||
|     // Deprecated.
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawFloorImage = function (
 | ||
|     ctx,
 | ||
|     name,
 | ||
|     one,
 | ||
|     image,
 | ||
|     currStatus,
 | ||
|     onMap
 | ||
| ) {
 | ||
|     var height = image.height;
 | ||
|     var imageName = one.name + (one.reverse || '');
 | ||
|     var width = parseInt(
 | ||
|         (one.w == null ? image.width : one.w) / (one.frame || 1)
 | ||
|     );
 | ||
|     var height = one.h == null ? image.height : one.h;
 | ||
|     var sx = (one.sx || 0) + ((currStatus || 0) % (one.frame || 1)) * width;
 | ||
|     var sy = one.sy || 0;
 | ||
|     var x = one.x || 0,
 | ||
|         y = one.y || 0;
 | ||
|     if (onMap && core.bigmap.v2) {
 | ||
|         if (
 | ||
|             x > 32 * core.bigmap.posX + core._PX_ + 32 ||
 | ||
|             x + width < 32 * core.bigmap.posX - 32 ||
 | ||
|             y > 32 * core.bigmap.posX + core._PY_ + 32 ||
 | ||
|             y + height < 32 * core.bigmap.posY - 32
 | ||
|         ) {
 | ||
|             return;
 | ||
|         }
 | ||
|         x -= 32 * core.bigmap.posX;
 | ||
|         y -= 32 * core.bigmap.posY;
 | ||
|     }
 | ||
| 
 | ||
|     if (one.canvas != 'auto' && one.canvas != name) return;
 | ||
|     if (one.canvas != 'auto') {
 | ||
|         if (currStatus != null) core.clearMap(ctx, x, y, width, height);
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             imageName,
 | ||
|             sx,
 | ||
|             sy,
 | ||
|             width,
 | ||
|             height,
 | ||
|             x,
 | ||
|             y,
 | ||
|             width,
 | ||
|             height
 | ||
|         );
 | ||
|     } else {
 | ||
|         if (name == 'bg') {
 | ||
|             if (currStatus != null)
 | ||
|                 core.clearMap(ctx, x, y + height - 32, width, 32);
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 imageName,
 | ||
|                 sx,
 | ||
|                 sy + height - 32,
 | ||
|                 width,
 | ||
|                 32,
 | ||
|                 x,
 | ||
|                 y + height - 32,
 | ||
|                 width,
 | ||
|                 32
 | ||
|             );
 | ||
|         } else if (name == 'fg') {
 | ||
|             if (currStatus != null)
 | ||
|                 core.clearMap(ctx, x, y, width, height - 32);
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 imageName,
 | ||
|                 sx,
 | ||
|                 sy,
 | ||
|                 width,
 | ||
|                 height - 32,
 | ||
|                 x,
 | ||
|                 y,
 | ||
|                 width,
 | ||
|                 height - 32
 | ||
|             );
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制Autotile //////
 | ||
| 
 | ||
| maps.prototype._drawAutotile = function (
 | ||
|     ctx,
 | ||
|     mapArr,
 | ||
|     block,
 | ||
|     size,
 | ||
|     left,
 | ||
|     top,
 | ||
|     status,
 | ||
|     onMap
 | ||
| ) {
 | ||
|     var xx = block.x,
 | ||
|         yy = block.y;
 | ||
|     var autotile = core.material.images['autotile'][block.event.id];
 | ||
|     status = status || 0;
 | ||
|     status %= Math.floor(autotile.width / 96);
 | ||
|     var done = {};
 | ||
|     var isGrass = function (x, y) {
 | ||
|         if (
 | ||
|             core.maps._drawAutotile_getAutotileAroundId(
 | ||
|                 mapArr[yy][xx],
 | ||
|                 x,
 | ||
|                 y,
 | ||
|                 mapArr
 | ||
|             )
 | ||
|         ) {
 | ||
|             return 1;
 | ||
|         } else {
 | ||
|             return 0;
 | ||
|         }
 | ||
|     };
 | ||
|     var iG = [];
 | ||
|     [-1, 0, 1].forEach(function (_x) {
 | ||
|         iG[_x] = [];
 | ||
|         [-1, 0, 1].forEach(function (_y) {
 | ||
|             iG[_x][_y] = isGrass(xx + _x, yy + _y);
 | ||
|         });
 | ||
|     });
 | ||
|     if (iG[-1][-1] + iG[0][-1] + iG[0][0] + iG[-1][0] == 3 && !iG[-1][-1]) {
 | ||
|         this._drawAutotile_render(
 | ||
|             ctx,
 | ||
|             xx * size + left,
 | ||
|             yy * size + top,
 | ||
|             size,
 | ||
|             autotile,
 | ||
|             status,
 | ||
|             16,
 | ||
|             null,
 | ||
|             onMap
 | ||
|         );
 | ||
|         done[0] = true;
 | ||
|     }
 | ||
|     if (iG[0][-1] + iG[1][-1] + iG[1][0] + iG[0][0] == 3 && !iG[1][-1]) {
 | ||
|         this._drawAutotile_render(
 | ||
|             ctx,
 | ||
|             xx * size + left + size / 2,
 | ||
|             yy * size + top,
 | ||
|             size,
 | ||
|             autotile,
 | ||
|             status,
 | ||
|             17,
 | ||
|             null,
 | ||
|             onMap
 | ||
|         );
 | ||
|         done[1] = true;
 | ||
|     }
 | ||
|     if (iG[0][0] + iG[1][0] + iG[1][1] + iG[0][1] == 3 && !iG[1][1]) {
 | ||
|         this._drawAutotile_render(
 | ||
|             ctx,
 | ||
|             xx * size + left + size / 2,
 | ||
|             yy * size + top + size / 2,
 | ||
|             size,
 | ||
|             autotile,
 | ||
|             status,
 | ||
|             18,
 | ||
|             null,
 | ||
|             onMap
 | ||
|         );
 | ||
|         done[3] = true;
 | ||
|     }
 | ||
|     if (iG[0 - 1][0] + iG[0][0] + iG[0][1] + iG[-1][1] == 3 && !iG[-1][1]) {
 | ||
|         this._drawAutotile_render(
 | ||
|             ctx,
 | ||
|             xx * size + left,
 | ||
|             yy * size + top + size / 2,
 | ||
|             size,
 | ||
|             autotile,
 | ||
|             status,
 | ||
|             19,
 | ||
|             null,
 | ||
|             onMap
 | ||
|         );
 | ||
|         done[2] = true;
 | ||
|     }
 | ||
|     var _id = iG[0][-1] + 2 * iG[-1][0] + 4 * iG[0][1] + 8 * iG[1][0];
 | ||
| 
 | ||
|     this._drawAutotile_render(
 | ||
|         ctx,
 | ||
|         xx * size,
 | ||
|         yy * size,
 | ||
|         size,
 | ||
|         autotile,
 | ||
|         status,
 | ||
|         _id,
 | ||
|         done,
 | ||
|         onMap
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_render = function (
 | ||
|     canvas,
 | ||
|     x,
 | ||
|     y,
 | ||
|     size,
 | ||
|     autotile,
 | ||
|     status,
 | ||
|     index,
 | ||
|     done,
 | ||
|     onMap
 | ||
| ) {
 | ||
|     if (onMap) {
 | ||
|         x -= 32 * core.bigmap.posX;
 | ||
|         y -= 32 * core.bigmap.posY;
 | ||
|     }
 | ||
|     var indexData = [
 | ||
|         [[96 * status, 0, 32, 32, x, y, size, size]],
 | ||
|         [
 | ||
|             [96 * status, 3 * 32, 16, 32, x, y, size / 2, size],
 | ||
|             [
 | ||
|                 96 * status + 2 * 32 + 16,
 | ||
|                 3 * 32,
 | ||
|                 16,
 | ||
|                 32,
 | ||
|                 x + size / 2,
 | ||
|                 y,
 | ||
|                 size / 2,
 | ||
|                 size
 | ||
|             ]
 | ||
|         ],
 | ||
|         [
 | ||
|             [96 * status + 2 * 32, 32, 32, 16, x, y, size, size / 2],
 | ||
|             [
 | ||
|                 96 * status + 2 * 32,
 | ||
|                 3 * 32 + 16,
 | ||
|                 32,
 | ||
|                 16,
 | ||
|                 x,
 | ||
|                 y + size / 2,
 | ||
|                 size,
 | ||
|                 size / 2
 | ||
|             ]
 | ||
|         ],
 | ||
|         [[96 * status + 2 * 32, 3 * 32, 32, 32, x, y, size, size]],
 | ||
|         [
 | ||
|             [96 * status, 32, 16, 32, x, y, size / 2, size],
 | ||
|             [
 | ||
|                 96 * status + 2 * 32 + 16,
 | ||
|                 32,
 | ||
|                 16,
 | ||
|                 32,
 | ||
|                 x + size / 2,
 | ||
|                 y,
 | ||
|                 size / 2,
 | ||
|                 size
 | ||
|             ]
 | ||
|         ],
 | ||
|         [
 | ||
|             [96 * status, 2 * 32, 16, 32, x, y, size / 2, size],
 | ||
|             [
 | ||
|                 96 * status + 2 * 32 + 16,
 | ||
|                 2 * 32,
 | ||
|                 16,
 | ||
|                 32,
 | ||
|                 x + size / 2,
 | ||
|                 y,
 | ||
|                 size / 2,
 | ||
|                 size
 | ||
|             ]
 | ||
|         ],
 | ||
|         [[96 * status + 2 * 32, 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status + 2 * 32, 2 * 32, 32, 32, x, y, size, size]],
 | ||
|         [
 | ||
|             [96 * status, 32, 32, 16, x, y, size, size / 2],
 | ||
|             [96 * status, 3 * 32 + 16, 32, 16, x, y + size / 2, size, size / 2]
 | ||
|         ],
 | ||
|         [[96 * status, 3 * 32, 32, 32, x, y, size, size]],
 | ||
|         [
 | ||
|             [96 * status + 32, 32, 32, 16, x, y, size, size / 2],
 | ||
|             [
 | ||
|                 96 * status + 32,
 | ||
|                 3 * 32 + 16,
 | ||
|                 32,
 | ||
|                 16,
 | ||
|                 x,
 | ||
|                 y + size / 2,
 | ||
|                 size,
 | ||
|                 size / 2
 | ||
|             ]
 | ||
|         ],
 | ||
|         [[96 * status + 32, 3 * 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status, 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status, 2 * 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status + 32, 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status + 32, 2 * 32, 32, 32, x, y, size, size]],
 | ||
|         [[96 * status + 2 * 32, 0, 16, 16, x, y, size / 2, size / 2]],
 | ||
|         [[96 * status + 2 * 32 + 16, 0, 16, 16, x, y, size / 2, size / 2]],
 | ||
|         [[96 * status + 2 * 32 + 16, 16, 16, 16, x, y, size / 2, size / 2]],
 | ||
|         [[96 * status + 2 * 32, 16, 16, 16, x, y, size / 2, size / 2]]
 | ||
|     ];
 | ||
|     var data = indexData[index];
 | ||
|     if (index >= 16) {
 | ||
|         // 拐角直接绘制
 | ||
|         core.drawImage(
 | ||
|             canvas,
 | ||
|             autotile,
 | ||
|             data[0][0],
 | ||
|             data[0][1],
 | ||
|             data[0][2],
 | ||
|             data[0][3],
 | ||
|             data[0][4],
 | ||
|             data[0][5],
 | ||
|             size / 2,
 | ||
|             size / 2
 | ||
|         );
 | ||
|     } else {
 | ||
|         // 非拐角要根据是否已经绘制进行切分后绘制
 | ||
|         this._drawAutotile_renderCut(canvas, autotile, x, y, size, data, done);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_renderCut = function (
 | ||
|     canvas,
 | ||
|     autotile,
 | ||
|     x,
 | ||
|     y,
 | ||
|     size,
 | ||
|     data,
 | ||
|     done
 | ||
| ) {
 | ||
|     var drawData = [];
 | ||
|     done = done || {};
 | ||
|     if (data.length == 2) {
 | ||
|         var idx = 0;
 | ||
|         var cut = 0;
 | ||
|         for (var i in data) {
 | ||
|             if (data[i][2] % 32) {
 | ||
|                 // 是否纵切
 | ||
|                 cut = 0;
 | ||
|             } else if (data[i][3] % 32) {
 | ||
|                 // 是否横切
 | ||
|                 cut = 1;
 | ||
|             }
 | ||
|             if (data[i][0] % 32 || data[i][1] % 32) {
 | ||
|                 // right down
 | ||
|                 idx = 1;
 | ||
|             } else {
 | ||
|                 // left top
 | ||
|                 idx = 0;
 | ||
|             }
 | ||
|             if (cut) {
 | ||
|                 idx *= 2;
 | ||
|                 if (!done[idx]) drawData[idx] = [data[i][0], data[i][1]];
 | ||
|                 if (!done[idx + 1])
 | ||
|                     drawData[idx + 1] = [parseInt(data[i][0]) + 16, data[i][1]];
 | ||
|             } else {
 | ||
|                 if (!done[idx]) drawData[idx] = [data[i][0], data[i][1]];
 | ||
|                 if (!done[idx + 2])
 | ||
|                     drawData[idx + 2] = [data[i][0], parseInt(data[i][1]) + 16];
 | ||
|             }
 | ||
|         }
 | ||
|     } else {
 | ||
|         if (!done[0]) drawData[0] = [data[0][0], data[0][1]];
 | ||
|         if (!done[1]) drawData[1] = [data[0][0] + 16, data[0][1]];
 | ||
|         if (!done[2]) drawData[2] = [data[0][0], data[0][1] + 16];
 | ||
|         if (!done[3]) drawData[3] = [data[0][0] + 16, data[0][1] + 16];
 | ||
|     }
 | ||
|     for (var i = 0; i < 4; i++) {
 | ||
|         var dt = drawData[i];
 | ||
|         if (!dt) continue;
 | ||
|         core.drawImage(
 | ||
|             canvas,
 | ||
|             autotile,
 | ||
|             dt[0],
 | ||
|             dt[1],
 | ||
|             16,
 | ||
|             16,
 | ||
|             x + ((i % 2) * size) / 2,
 | ||
|             y + (Math.floor(i / 2) * size) / 2,
 | ||
|             size / 2,
 | ||
|             size / 2
 | ||
|         );
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_drawBlockByIndex = function (
 | ||
|     ctx,
 | ||
|     dx,
 | ||
|     dy,
 | ||
|     autotileImg,
 | ||
|     index,
 | ||
|     size,
 | ||
|     status
 | ||
| ) {
 | ||
|     //index为autotile的图块索引1-48
 | ||
|     var sx = 16 * ((index - 1) % 6),
 | ||
|         sy = 16 * ~~((index - 1) / 6);
 | ||
|     status = status || 0;
 | ||
|     status %= Math.floor(autotileImg.width / 96);
 | ||
|     core.drawImage(
 | ||
|         ctx,
 | ||
|         autotileImg,
 | ||
|         sx + 96 * status,
 | ||
|         sy,
 | ||
|         16,
 | ||
|         16,
 | ||
|         dx,
 | ||
|         dy,
 | ||
|         size / 2,
 | ||
|         size / 2
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_getAutotileAroundId = function (
 | ||
|     currId,
 | ||
|     x,
 | ||
|     y,
 | ||
|     mapArr
 | ||
| ) {
 | ||
|     if (x < 0 || y < 0 || x >= mapArr[0].length || y >= mapArr.length) return 1;
 | ||
|     else
 | ||
|         return (
 | ||
|             (core.material.autotileEdges[currId] || []).indexOf(mapArr[y][x]) >=
 | ||
|             0
 | ||
|         );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_checkAround = function (x, y, mapArr) {
 | ||
|     // 得到周围四个32*32块(周围每块都包含当前块的1/4,不清楚的话画下图你就明白)的数组索引
 | ||
|     var currId = mapArr[y][x];
 | ||
|     var pointBlock = [];
 | ||
|     for (var i = 0; i < 4; i++) {
 | ||
|         var bsum = 0;
 | ||
|         var offsetx = i % 2,
 | ||
|             offsety = ~~(i / 2);
 | ||
|         for (var j = 0; j < 4; j++) {
 | ||
|             var mx = j % 2,
 | ||
|                 my = ~~(j / 2);
 | ||
|             var b = this._drawAutotile_getAutotileAroundId(
 | ||
|                 currId,
 | ||
|                 x + offsetx + mx - 1,
 | ||
|                 y + offsety + my - 1,
 | ||
|                 mapArr
 | ||
|             );
 | ||
|             bsum += b * Math.pow(2, 3 - j);
 | ||
|         }
 | ||
|         pointBlock.push(bsum);
 | ||
|     }
 | ||
|     return pointBlock;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotile_getAutotileIndexs = function (
 | ||
|     x,
 | ||
|     y,
 | ||
|     mapArr,
 | ||
|     indexArrs
 | ||
| ) {
 | ||
|     var indexArr = [];
 | ||
|     var pointBlocks = this._drawAutotile_checkAround(x, y, mapArr);
 | ||
|     for (var i = 0; i < 4; i++) {
 | ||
|         var arr = indexArrs[pointBlocks[i]];
 | ||
|         indexArr.push(arr[3 - i]);
 | ||
|     }
 | ||
|     return indexArr;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawAutotileAnimate = function (block, animate) {
 | ||
|     var x = block.x,
 | ||
|         y = block.y;
 | ||
|     // ------ 界面外的动画不绘制
 | ||
|     if (core.bigmap.v2) {
 | ||
|         var posX = core.bigmap.posX,
 | ||
|             posY = core.bigmap.posY;
 | ||
|         if (
 | ||
|             x < posX - 1 ||
 | ||
|             y < posY - 1 ||
 | ||
|             x > posX + core._WIDTH_ ||
 | ||
|             y > posY + core._HEIGHT_
 | ||
|         ) {
 | ||
|             return;
 | ||
|         }
 | ||
|     } else {
 | ||
|         if (
 | ||
|             32 * x < core.bigmap.offsetX - 64 ||
 | ||
|             32 * x > core.bigmap.offsetX + core._PX_ + 32 ||
 | ||
|             32 * y < core.bigmap.offsetY - 64 ||
 | ||
|             32 * y > core.bigmap.offsetY + core._PY_ + 32 + 16
 | ||
|         ) {
 | ||
|             return;
 | ||
|         }
 | ||
|     }
 | ||
| 
 | ||
|     var cv = block.name ? core.canvas[block.name] : core.canvas.event;
 | ||
|     core.clearMap(
 | ||
|         cv,
 | ||
|         32 * x - 32 * core.bigmap.posX,
 | ||
|         32 * y - 32 * core.bigmap.posY,
 | ||
|         32,
 | ||
|         32
 | ||
|     );
 | ||
|     var alpha = null;
 | ||
|     if (block.opacity != null) alpha = core.setAlpha(cv, block.opacity);
 | ||
|     core.setFilter(cv, block.filter);
 | ||
|     if (block.name) {
 | ||
|         if (block.name == 'bg')
 | ||
|             core.drawImage(
 | ||
|                 'bg',
 | ||
|                 core.material.groundCanvas.canvas,
 | ||
|                 32 * x - 32 * core.bigmap.posX,
 | ||
|                 32 * y - 32 * core.bigmap.posY
 | ||
|             );
 | ||
|         this._drawAutotile(
 | ||
|             cv,
 | ||
|             this._getBgFgMapArray(block.name),
 | ||
|             block,
 | ||
|             32,
 | ||
|             0,
 | ||
|             0,
 | ||
|             animate,
 | ||
|             true
 | ||
|         );
 | ||
|     } else {
 | ||
|         this._drawAutotile(
 | ||
|             cv,
 | ||
|             this.getMapArray(),
 | ||
|             block,
 | ||
|             32,
 | ||
|             0,
 | ||
|             0,
 | ||
|             animate,
 | ||
|             true
 | ||
|         );
 | ||
|     }
 | ||
|     core.setFilter(cv, null);
 | ||
|     if (alpha != null) core.setAlpha(cv, alpha);
 | ||
| };
 | ||
| 
 | ||
| ////// 为autotile判定边界 //////
 | ||
| maps.prototype._makeAutotileEdges = function () {
 | ||
|     var autotileIds = Object.keys(core.material.images.autotile);
 | ||
|     core.material.autotileEdges = {};
 | ||
| 
 | ||
|     var canvas = document.createElement('canvas'),
 | ||
|         ctx = canvas.getContext('2d');
 | ||
|     canvas.width = canvas.height = 32;
 | ||
|     ctx.mozImageSmoothingEnabled = false;
 | ||
|     ctx.webkitImageSmoothingEnabled = false;
 | ||
|     ctx.msImageSmoothingEnabled = false;
 | ||
|     ctx.imageSmoothingEnabled = false;
 | ||
| 
 | ||
|     var first = {},
 | ||
|         second = {};
 | ||
|     autotileIds.forEach(function (t) {
 | ||
|         var n = core.maps.getNumberById(t);
 | ||
|         core.clearMap(ctx, 0, 0, 32, 32);
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             core.material.images.autotile[t],
 | ||
|             0,
 | ||
|             0,
 | ||
|             32,
 | ||
|             32,
 | ||
|             0,
 | ||
|             0,
 | ||
|             32,
 | ||
|             32
 | ||
|         );
 | ||
|         first[n] = canvas.toDataURL('image/png');
 | ||
|         core.clearMap(ctx, 0, 0, 32, 32);
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             core.material.images.autotile[t],
 | ||
|             32,
 | ||
|             0,
 | ||
|             32,
 | ||
|             32,
 | ||
|             0,
 | ||
|             0,
 | ||
|             32,
 | ||
|             32
 | ||
|         );
 | ||
|         second[n] = canvas.toDataURL('image/png');
 | ||
|     });
 | ||
| 
 | ||
|     for (var n in first) {
 | ||
|         n = parseInt(n);
 | ||
|         core.material.autotileEdges[n] = [n];
 | ||
|         for (var n2 in second) {
 | ||
|             n2 = parseInt(n2);
 | ||
|             if (n == n2) continue;
 | ||
|             if (first[n] == second[n2]) {
 | ||
|                 core.material.autotileEdges[n].push(n2);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制缩略图 //////
 | ||
| // 此函数将绘制一个缩略图,floorId为目标floorId,blocks为地图的图块(可为null使用floorId对应默认的)
 | ||
| // options为绘制选项(可为null),包括:
 | ||
| //    heroLoc: 勇士位置;heroIcon:勇士图标(默认当前勇士);damage:是否绘制显伤;flags:当前的flags(存读档时使用)
 | ||
| //    ctx:要绘制到的画布(名);x,y:起点横纵坐标(默认0);size:大小(默认416/480);
 | ||
| //    all:是否绘制全图(默认false);centerX,centerY:截取中心(默认为地图正中心)
 | ||
| //    noHD:不使用高清绘制,避免存读档界面出问题
 | ||
| maps.prototype.drawThumbnail = function (floorId, blocks, options) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     options = options || {};
 | ||
|     if (typeof options == 'string' || options.canvas)
 | ||
|         options = { ctx: options };
 | ||
|     var ctx = options.ctx;
 | ||
|     // Step1:绘制到tempCanvas上
 | ||
|     this._drawThumbnail_drawTempCanvas(floorId, blocks, options);
 | ||
|     options.ctx = ctx;
 | ||
|     // Step2:从tempCanvas绘制到对应的画布上
 | ||
|     this._drawThumbnail_drawToTarget(floorId, options);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawThumbnail_drawTempCanvas = function (
 | ||
|     floorId,
 | ||
|     blocks,
 | ||
|     options
 | ||
| ) {
 | ||
|     var width = core.floors[floorId].width;
 | ||
|     var height = core.floors[floorId].height;
 | ||
|     // 绘制到tempCanvas上面
 | ||
|     var tempCanvas = core.bigmap.tempCanvas;
 | ||
| 
 | ||
|     // 如果是大地图模式?
 | ||
|     if (options.all) {
 | ||
|         if (options.noHD) {
 | ||
|             tempCanvas.canvas.width = width * 32;
 | ||
|             tempCanvas.canvas.height = height * 32;
 | ||
|             tempCanvas.canvas.removeAttribute('isHD');
 | ||
|         } else {
 | ||
|             core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
 | ||
|         }
 | ||
|     } else if (width * height > core.bigmap.threshold) {
 | ||
|         options.v2 = true;
 | ||
|         if (options.noHD) {
 | ||
|             tempCanvas.canvas.width = core._PX_;
 | ||
|             tempCanvas.canvas.height = core._PY_;
 | ||
|             tempCanvas.canvas.removeAttribute('isHD');
 | ||
|         } else core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
 | ||
|         var centerX = options.centerX,
 | ||
|             centerY = options.centerY;
 | ||
|         if (centerX == null) centerX = Math.floor(width / 2);
 | ||
|         if (centerY == null) centerY = Math.floor(height / 2);
 | ||
|         var offsetX = core.clamp(
 | ||
|                 centerX - core._HALF_WIDTH_,
 | ||
|                 0,
 | ||
|                 width - core._WIDTH_
 | ||
|             ),
 | ||
|             offsetY = core.clamp(
 | ||
|                 centerY - core._HALF_HEIGHT_,
 | ||
|                 0,
 | ||
|                 height - core._HEIGHT_
 | ||
|             );
 | ||
|         tempCanvas.translate(-32 * offsetX, -32 * offsetY, false, true);
 | ||
|     } else {
 | ||
|         options.v2 = false;
 | ||
|         if (options.noHD) {
 | ||
|             tempCanvas.canvas.width = width * 32;
 | ||
|             tempCanvas.canvas.height = height * 32;
 | ||
|             tempCanvas.canvas.removeAttribute('isHD');
 | ||
|         } else core.maps._setHDCanvasSize(tempCanvas, width * 32, height * 32);
 | ||
|     }
 | ||
|     options.ctx = tempCanvas;
 | ||
| 
 | ||
|     // 地图过大的缩略图不绘制显伤
 | ||
|     if (width * height > core.bigmap.threshold) options.damage = false;
 | ||
| 
 | ||
|     // --- 暂存 flags
 | ||
|     var hasHero = core.status.hero != null,
 | ||
|         flags = null;
 | ||
|     if (options.flags) {
 | ||
|         if (!hasHero) core.status.hero = {};
 | ||
|         flags = core.status.hero.flags;
 | ||
|         core.status.hero.flags = options.flags;
 | ||
|     }
 | ||
| 
 | ||
|     this._drawThumbnail_realDrawTempCanvas(floorId, blocks, options);
 | ||
| 
 | ||
|     // --- 恢复 flags
 | ||
|     if (!hasHero) delete core.status.hero;
 | ||
|     else if (flags != null) core.status.hero.flags = flags;
 | ||
|     tempCanvas.setTransform(1, 0, 0, 1, 0, 0);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawThumbnail_realDrawTempCanvas = function (
 | ||
|     floorId,
 | ||
|     blocks,
 | ||
|     options
 | ||
| ) {
 | ||
|     Mota.r(() => {
 | ||
|         const setting = Mota.require('@motajs/legacy-ui').mainSetting;
 | ||
|         options.ctx.imageSmoothingEnabled = !setting.getValue(
 | ||
|             'screen.antiAliasing',
 | ||
|             true
 | ||
|         );
 | ||
|     });
 | ||
|     // 缩略图:背景
 | ||
|     this.drawBg(floorId, options);
 | ||
|     // 缩略图:事件
 | ||
|     this.drawEvents(floorId, blocks, options);
 | ||
|     // 缩略图:勇士
 | ||
|     if (options.heroLoc) {
 | ||
|         options.heroIcon =
 | ||
|             options.heroIcon || core.status.hero.image || 'hero.png';
 | ||
|         options.heroIcon = core.getMappedName(options.heroIcon);
 | ||
|         const image = core.material.images.images[options.heroIcon];
 | ||
|         if (image) {
 | ||
|             var icon = core.material.icons.hero[options.heroLoc.direction];
 | ||
|             var height =
 | ||
|                 core.material.images.images[options.heroIcon].height / 4;
 | ||
|             var width = (image.width || 128) / 4;
 | ||
|             core.drawImage(
 | ||
|                 options.ctx,
 | ||
|                 core.material.images.images[options.heroIcon],
 | ||
|                 icon.stop * width,
 | ||
|                 icon.loc * height,
 | ||
|                 width,
 | ||
|                 height,
 | ||
|                 32 * options.heroLoc.x + 32 - width,
 | ||
|                 32 * options.heroLoc.y + 32 - height,
 | ||
|                 width,
 | ||
|                 height
 | ||
|             );
 | ||
|         }
 | ||
|     }
 | ||
|     // 缩略图:前景
 | ||
|     this.drawFg(floorId, options);
 | ||
|     options.ctx.imageSmoothingEnabled = true;
 | ||
|     // 缩略图:显伤
 | ||
|     if (options.damage && core.hasItem('book')) {
 | ||
|         core.control.updateDamage(floorId, options.ctx, true);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._drawThumbnail_drawToTarget = function (floorId, options) {
 | ||
|     var ctx = core.getContextByName(options.ctx);
 | ||
|     if (ctx == null) return;
 | ||
|     var x = options.x || 0,
 | ||
|         y = options.y || 0,
 | ||
|         size = options.size || 1;
 | ||
|     // size的含义改为(0,1]范围的系数以适配长方形,默认为1,楼传为3/4,SL界面为0.3
 | ||
|     var w = size * core._PX_,
 | ||
|         h = size * core._PY_;
 | ||
|     // 特判是否为编辑器,编辑器中长宽均采用core.js的遗留正方形像素边长,以保证下面的绘制正常
 | ||
|     if (main.mode == 'editor') w = h = size * core.__PIXELS__;
 | ||
|     var width = core.floors[floorId].width,
 | ||
|         height = core.floors[floorId].height;
 | ||
|     var centerX = options.centerX,
 | ||
|         centerY = options.centerY;
 | ||
|     if (centerX == null) centerX = Math.floor(width / 2);
 | ||
|     if (centerY == null) centerY = Math.floor(height / 2);
 | ||
|     var tempCanvas = core.bigmap.tempCanvas;
 | ||
| 
 | ||
|     if (options.inFlyMap) {
 | ||
|         ctx.drawImage(
 | ||
|             tempCanvas.canvas,
 | ||
|             0,
 | ||
|             0,
 | ||
|             tempCanvas.canvas.width,
 | ||
|             tempCanvas.canvas.height,
 | ||
|             options.x,
 | ||
|             options.y,
 | ||
|             options.w,
 | ||
|             options.h
 | ||
|         );
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     const scale = core.domStyle.scale * devicePixelRatio;
 | ||
|     if (options.all) {
 | ||
|         var tempWidth = tempCanvas.canvas.width,
 | ||
|             tempHeight = tempCanvas.canvas.height;
 | ||
|         // 绘制全景图
 | ||
|         if (tempWidth <= tempHeight) {
 | ||
|             var realHeight = h,
 | ||
|                 realWidth = (realHeight * tempWidth) / tempHeight;
 | ||
|             var side = (w - realWidth) / 2;
 | ||
|             core.fillRect(ctx, x, y, side, realHeight, '#000000');
 | ||
|             core.fillRect(ctx, x + w - side, y, side, realHeight);
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 tempCanvas.canvas,
 | ||
|                 0,
 | ||
|                 0,
 | ||
|                 tempWidth,
 | ||
|                 tempHeight,
 | ||
|                 x + side,
 | ||
|                 y,
 | ||
|                 realWidth,
 | ||
|                 realHeight
 | ||
|             );
 | ||
|         } else {
 | ||
|             var realWidth = w,
 | ||
|                 realHeight = (realWidth * tempHeight) / tempWidth;
 | ||
|             var side = (h - realHeight) / 2;
 | ||
|             core.fillRect(ctx, x, y, realWidth, side, '#000000');
 | ||
|             core.fillRect(ctx, x, y + h - side, realWidth, side);
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 tempCanvas.canvas,
 | ||
|                 0,
 | ||
|                 0,
 | ||
|                 tempWidth,
 | ||
|                 tempHeight,
 | ||
|                 x,
 | ||
|                 y + side,
 | ||
|                 realWidth,
 | ||
|                 realHeight
 | ||
|             );
 | ||
|         }
 | ||
|         ctx.imageSmoothingEnabled = true;
 | ||
|     } else {
 | ||
|         // 只绘制可见窗口
 | ||
|         var pw = core._PX_,
 | ||
|             ph = core._PY_,
 | ||
|             hw = core._HALF_WIDTH_,
 | ||
|             hh = core._HALF_HEIGHT_,
 | ||
|             W = core._WIDTH_,
 | ||
|             H = core._HEIGHT_;
 | ||
|         if (main.mode == 'editor') {
 | ||
|             pw = ph = core.__PIXELS__;
 | ||
|             hw = hh = core.__HALF_SIZE__;
 | ||
|             W = H = core.__SIZE__;
 | ||
|         }
 | ||
|         if (options.v2) {
 | ||
|             if (options.noHD) {
 | ||
|                 core.drawImage(
 | ||
|                     ctx,
 | ||
|                     tempCanvas.canvas,
 | ||
|                     0,
 | ||
|                     0,
 | ||
|                     pw,
 | ||
|                     ph,
 | ||
|                     x,
 | ||
|                     y,
 | ||
|                     w,
 | ||
|                     h
 | ||
|                 );
 | ||
|             } else {
 | ||
|                 core.drawImage(
 | ||
|                     ctx,
 | ||
|                     tempCanvas.canvas,
 | ||
|                     0,
 | ||
|                     0,
 | ||
|                     pw * scale,
 | ||
|                     ph * scale,
 | ||
|                     x,
 | ||
|                     y,
 | ||
|                     w,
 | ||
|                     h
 | ||
|                 );
 | ||
|             }
 | ||
|             ctx.imageSmoothingEnabled = true;
 | ||
|         } else {
 | ||
|             var offsetX = core.clamp(centerX - hw, 0, width - W),
 | ||
|                 offsetY = core.clamp(centerY - hh, 0, height - H);
 | ||
|             if (options.noHD) {
 | ||
|                 core.drawImage(
 | ||
|                     ctx,
 | ||
|                     tempCanvas.canvas,
 | ||
|                     offsetX * 32,
 | ||
|                     offsetY * 32,
 | ||
|                     pw,
 | ||
|                     ph,
 | ||
|                     x,
 | ||
|                     y,
 | ||
|                     w,
 | ||
|                     h
 | ||
|                 );
 | ||
|                 ctx.imageSmoothingEnabled = true;
 | ||
|                 return;
 | ||
|             }
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 tempCanvas.canvas,
 | ||
|                 offsetX * 32,
 | ||
|                 offsetY * 32,
 | ||
|                 pw * scale,
 | ||
|                 ph * scale,
 | ||
|                 x,
 | ||
|                 y,
 | ||
|                 w,
 | ||
|                 h
 | ||
|             );
 | ||
|             ctx.imageSmoothingEnabled = true;
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| // -------- 获得某个点的图块信息 -------- //
 | ||
| 
 | ||
| ////// 某个点是否不可通行 //////
 | ||
| maps.prototype.noPass = function (x, y, floorId) {
 | ||
|     var block = core.getBlock(x, y, floorId);
 | ||
|     if (block == null) return false;
 | ||
|     return block.event.noPass;
 | ||
| };
 | ||
| 
 | ||
| ////// 某个点是否存在NPC //////
 | ||
| maps.prototype.npcExists = function (x, y, floorId) {
 | ||
|     var block = this.getBlock(x, y, floorId);
 | ||
|     if (block == null) return false;
 | ||
|     return block.event.cls.indexOf('npc') == 0;
 | ||
| };
 | ||
| 
 | ||
| ////// 某个点是否存在(指定的)地形 //////
 | ||
| maps.prototype.terrainExists = function (x, y, id, floorId) {
 | ||
|     var block = this.getBlock(x, y, floorId);
 | ||
|     if (block == null) return false;
 | ||
|     return block.event.cls == 'terrains' && (id ? block.event.id == id : true);
 | ||
| };
 | ||
| 
 | ||
| ////// 某个点是否存在楼梯 //////
 | ||
| maps.prototype.stairExists = function (x, y, floorId) {
 | ||
|     var blockId = this.getBlockId(x, y, floorId);
 | ||
|     if (blockId == null) return false;
 | ||
|     var ids = ['upFloor', 'downFloor'];
 | ||
|     ids = ids.concat([
 | ||
|         'leftPortal',
 | ||
|         'rightPortal',
 | ||
|         'upPortal',
 | ||
|         'downPortal',
 | ||
|         'portal',
 | ||
|         'starPortal'
 | ||
|     ]);
 | ||
|     return ids.indexOf(blockId) >= 0;
 | ||
| };
 | ||
| 
 | ||
| ////// 当前位置是否在楼梯边 //////
 | ||
| maps.prototype.nearStair = function () {
 | ||
|     var x = core.getHeroLoc('x'),
 | ||
|         y = core.getHeroLoc('y');
 | ||
|     return (
 | ||
|         this.stairExists(x, y) ||
 | ||
|         this.stairExists(x - 1, y) ||
 | ||
|         this.stairExists(x, y - 1) ||
 | ||
|         this.stairExists(x + 1, y) ||
 | ||
|         this.stairExists(x, y + 1)
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 某个点是否存在(指定的)怪物 //////
 | ||
| maps.prototype.enemyExists = function (x, y, id, floorId) {
 | ||
|     var block = this.getBlock(x, y, floorId);
 | ||
|     if (block == null) return false;
 | ||
|     return (
 | ||
|         block.event.cls.indexOf('enemy') == 0 &&
 | ||
|         (id ? block.event.id == id : true)
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的block //////
 | ||
| maps.prototype.getBlock = function (x, y, floorId, showDisable) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return null;
 | ||
|     core.extractBlocks(floorId);
 | ||
|     var blockObjs = this.getMapBlocksObj(floorId);
 | ||
|     var block = blockObjs[x + ',' + y];
 | ||
|     if (block && (showDisable || !block.disable)) return block;
 | ||
|     return null;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的blockId //////
 | ||
| maps.prototype.getBlockId = function (x, y, floorId, showDisable) {
 | ||
|     var block = core.getBlock(x, y, floorId, showDisable);
 | ||
|     return block == null ? null : block.event.id;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的数字 //////
 | ||
| maps.prototype.getBlockNumber = function (x, y, floorId, showDisable) {
 | ||
|     var block = core.getBlock(x, y, floorId, showDisable);
 | ||
|     return block == null ? null : block.id;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的blockCls //////
 | ||
| maps.prototype.getBlockCls = function (x, y, floorId, showDisable) {
 | ||
|     var block = core.getBlock(x, y, floorId, showDisable);
 | ||
|     return block == null ? null : block.event.cls;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的不透明度 //////
 | ||
| maps.prototype.getBlockOpacity = function (x, y, floorId, showDisable) {
 | ||
|     var block = core.getBlock(x, y, floorId, showDisable);
 | ||
|     if (block == null) return null;
 | ||
|     if (block.opacity == null) return 1.0;
 | ||
|     return block.opacity == null ? 1.0 : block.opacity;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个点的filter //////
 | ||
| maps.prototype.getBlockFilter = function (x, y, floorId, showDisable) {
 | ||
|     var block = core.getBlock(x, y, floorId, showDisable);
 | ||
|     if (block == null) return null;
 | ||
|     if (block.filter == null)
 | ||
|         return { blur: 0, hue: 0, grayscale: 0, invert: false, shadow: 0 };
 | ||
|     return core.clone(block.filter);
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个图块或素材的信息,包括 ID,cls,图片,坐标,faceIds 等等 //////
 | ||
| maps.prototype.getBlockInfo = function (block) {
 | ||
|     if (!block) return null;
 | ||
|     if (typeof block == 'string') {
 | ||
|         // 参数是ID
 | ||
|         block = this.getNumberById(block);
 | ||
|     }
 | ||
|     if (typeof block == 'number') {
 | ||
|         // 参数是数字
 | ||
|         if (block == 0) return null;
 | ||
|         block = this.getBlockByNumber(block);
 | ||
|     }
 | ||
|     var number = block.id,
 | ||
|         id = block.event.id,
 | ||
|         cls = block.event.cls,
 | ||
|         name = block.event.name,
 | ||
|         image = null,
 | ||
|         posX = 0,
 | ||
|         posY = 0,
 | ||
|         animate = block.event.animate,
 | ||
|         doorInfo = block.event.doorInfo,
 | ||
|         height = block.event.height || 32,
 | ||
|         faceIds = {},
 | ||
|         face = 'down',
 | ||
|         bigImage = null;
 | ||
| 
 | ||
|     if (id == 'none') return null;
 | ||
|     else if (id == 'airwall') {
 | ||
|         if (!core.material.images.airwall) return null;
 | ||
|         image = core.material.images.airwall;
 | ||
|         name = '空气墙';
 | ||
|     } else if (cls == 'tileset') {
 | ||
|         var offset = core.icons.getTilesetOffset(id);
 | ||
|         if (offset == null) return null;
 | ||
|         posX = offset.x;
 | ||
|         posY = offset.y;
 | ||
|         image = core.material.images.tilesets[offset.image];
 | ||
|     } else if (cls == 'autotile') {
 | ||
|         image = core.material.images.autotile[id];
 | ||
|     } else {
 | ||
|         image = core.material.images[cls];
 | ||
|         posY = core.material.icons[cls][id];
 | ||
|         faceIds = block.event.faceIds || {};
 | ||
|         for (var f in faceIds) {
 | ||
|             if (faceIds[f] == id) {
 | ||
|                 face = f;
 | ||
|                 break;
 | ||
|             }
 | ||
|         }
 | ||
|         if (block.event.bigImage)
 | ||
|             bigImage = core.material.images.images[block.event.bigImage];
 | ||
|         if (core.material.enemys[id]) {
 | ||
|             name = core.material.enemys[id].name;
 | ||
|             bigImage =
 | ||
|                 core.material.images.images[core.material.enemys[id].bigImage];
 | ||
|         } else if (core.material.items[id]) {
 | ||
|             name = core.material.items[id].name;
 | ||
|         }
 | ||
|         // 非门效果则强制变成四帧动画
 | ||
|         if (!doorInfo && bigImage != null) animate = 4;
 | ||
|     }
 | ||
| 
 | ||
|     return {
 | ||
|         number: number,
 | ||
|         id: id,
 | ||
|         cls: cls,
 | ||
|         name: name,
 | ||
|         image: image,
 | ||
|         posX: posX,
 | ||
|         doorInfo: doorInfo,
 | ||
|         posY: posY,
 | ||
|         height: height,
 | ||
|         faceIds: faceIds,
 | ||
|         animate: animate,
 | ||
|         face: face,
 | ||
|         bigImage: bigImage
 | ||
|     };
 | ||
| };
 | ||
| 
 | ||
| ////// 搜索某个图块出现的所有位置 //////
 | ||
| maps.prototype.searchBlock = function (id, floorId, showDisable) {
 | ||
|     if (typeof id == 'number') id = this.getBlockByNumber(id).event.id;
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     var result = [];
 | ||
|     if (floorId instanceof Array) {
 | ||
|         floorId.forEach(function (floorId) {
 | ||
|             result = result.concat(core.searchBlock(id, floorId, showDisable));
 | ||
|         });
 | ||
|         return result;
 | ||
|     }
 | ||
|     core.extractBlocks(floorId);
 | ||
|     for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) {
 | ||
|         var block = core.status.maps[floorId].blocks[i];
 | ||
|         if (
 | ||
|             (showDisable || !block.disable) &&
 | ||
|             (core.matchWildcard(id, block.event.id) ||
 | ||
|                 core.matchRegex(id, block.event.id))
 | ||
|         ) {
 | ||
|             result.push({
 | ||
|                 floorId: floorId,
 | ||
|                 x: block.x,
 | ||
|                 y: block.y,
 | ||
|                 block: block
 | ||
|             });
 | ||
|         }
 | ||
|     }
 | ||
|     return result;
 | ||
| };
 | ||
| 
 | ||
| ////// 给定筛选函数,搜索某个图块出现的所有位置 //////
 | ||
| maps.prototype.searchBlockWithFilter = function (
 | ||
|     blockFilter,
 | ||
|     floorId,
 | ||
|     showDisable
 | ||
| ) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     var result = [];
 | ||
|     if (floorId instanceof Array) {
 | ||
|         floorId.forEach(function (floorId) {
 | ||
|             result = result.concat(
 | ||
|                 core.searchBlockWithFilter(blockFilter, floorId, showDisable)
 | ||
|             );
 | ||
|         });
 | ||
|         return result;
 | ||
|     }
 | ||
|     core.extractBlocks(floorId);
 | ||
|     for (var i = 0; i < core.status.maps[floorId].blocks.length; ++i) {
 | ||
|         var block = core.status.maps[floorId].blocks[i];
 | ||
|         if ((showDisable || !block.disable) && blockFilter(block)) {
 | ||
|             result.push({
 | ||
|                 floorId: floorId,
 | ||
|                 x: block.x,
 | ||
|                 y: block.y,
 | ||
|                 block: block
 | ||
|             });
 | ||
|         }
 | ||
|     }
 | ||
|     return result;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得某个图块,其行走图朝向朝下的图块ID //////
 | ||
| maps.prototype.getFaceDownId = function (block) {
 | ||
|     if (block == null) return null;
 | ||
|     if (typeof block == 'string') {
 | ||
|         // 参数是ID
 | ||
|         block = this.getNumberById(block);
 | ||
|     }
 | ||
|     if (typeof block == 'number') {
 | ||
|         // 参数是数字
 | ||
|         if (block == 0) return null;
 | ||
|         block = this.getBlockByNumber(block);
 | ||
|     }
 | ||
|     if (!block.event) return null;
 | ||
|     return (block.event.faceIds || {}).down || block.event.id;
 | ||
| };
 | ||
| 
 | ||
| // -------- 启用/禁用图块,楼层贴图 -------- //
 | ||
| 
 | ||
| ////// 将某个块从禁用变成启用状态 //////
 | ||
| maps.prototype.showBlock = function (x, y, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     var block = core.getBlock(x, y, floorId, true);
 | ||
|     if (block == null) return; // 不存在
 | ||
|     // 本身是禁用事件,启用之
 | ||
|     if (block.disable) {
 | ||
|         block.disable = false;
 | ||
|         core.setMapBlockDisabled(floorId, x, y, false);
 | ||
|         this._updateMapArray(floorId, block.x, block.y);
 | ||
|         Mota.require('@user/data-base').hook.emit(
 | ||
|             'setBlock',
 | ||
|             x,
 | ||
|             y,
 | ||
|             floorId,
 | ||
|             block?.id ?? 0,
 | ||
|             0
 | ||
|         );
 | ||
|         // 在本层,添加动画
 | ||
|         if (floorId == core.status.floorId) {
 | ||
|             if (block.event.cls == 'autotile') {
 | ||
|                 core.redrawMap();
 | ||
|             } else {
 | ||
|                 core.drawBlock(block);
 | ||
|                 core.addGlobalAnimate(block);
 | ||
|                 core.updateStatusBar(false, true);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 只隐藏但不删除某块 //////
 | ||
| maps.prototype.hideBlock = function (x, y, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
| 
 | ||
|     var block = core.getBlock(x, y, floorId, true);
 | ||
|     if (block == null) return; // 不存在
 | ||
| 
 | ||
|     block.disable = true;
 | ||
|     core.setMapBlockDisabled(floorId, block.x, block.y, true);
 | ||
|     this._updateMapArray(floorId, block.x, block.y);
 | ||
|     Mota.require('@user/data-base').hook.emit(
 | ||
|         'setBlock',
 | ||
|         x,
 | ||
|         y,
 | ||
|         floorId,
 | ||
|         0,
 | ||
|         block?.id ?? 0
 | ||
|     );
 | ||
| 
 | ||
|     // 删除动画,清除地图
 | ||
|     this._removeBlockFromMap(floorId, block);
 | ||
| };
 | ||
| 
 | ||
| ////// 根据图块的索引来隐藏图块 //////
 | ||
| maps.prototype.hideBlockByIndex = function (index, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     core.extractBlocks(floorId);
 | ||
|     var blocks = core.status.maps[floorId].blocks,
 | ||
|         block = blocks[index];
 | ||
|     block.disable = true;
 | ||
|     core.setMapBlockDisabled(floorId, block.x, block.y, true);
 | ||
|     this._updateMapArray(floorId, block.x, block.y);
 | ||
|     Mota.require('@user/data-base').hook.emit(
 | ||
|         'setBlock',
 | ||
|         x,
 | ||
|         y,
 | ||
|         floorId,
 | ||
|         0,
 | ||
|         block?.id ?? 0
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 一次性隐藏多个block //////
 | ||
| maps.prototype.hideBlockByIndexes = function (indexes, floorId) {
 | ||
|     indexes
 | ||
|         .sort(function (a, b) {
 | ||
|             return b - a;
 | ||
|         })
 | ||
|         .forEach(function (index) {
 | ||
|             core.hideBlockByIndex(index, floorId);
 | ||
|         });
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._removeBlockFromMap = function (floorId, block) {
 | ||
|     if (floorId != core.status.floorId) return;
 | ||
|     var filter = block.filter || {};
 | ||
|     if (block.event.cls == 'autotile' || filter.blur > 0 || filter.shadow > 0) {
 | ||
|         core.redrawMap();
 | ||
|     } else {
 | ||
|         var x = block.x,
 | ||
|             y = block.y;
 | ||
|         var px = 32 * x - core.bigmap.posX * 32;
 | ||
|         var py = 32 * y - core.bigmap.posY * 32;
 | ||
|         core.removeGlobalAnimate(x, y);
 | ||
|         core.clearMap('event', px, py, 32, 32);
 | ||
|         var height = block.event.height || 32;
 | ||
|         if (height > 32)
 | ||
|             core.clearMap('event2', px, py + 32 - height, 32, height - 32);
 | ||
|         // 删除大怪物
 | ||
|         core.deleteCanvas('_bigImage_header_' + x + '_' + y);
 | ||
|         core.deleteCanvas('_bigImage_body_' + x + '_' + y);
 | ||
|         core.updateStatusBar();
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 删除某个图块 //////
 | ||
| maps.prototype.removeBlock = function (x, y, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return false;
 | ||
| 
 | ||
|     core.extractBlocks(floorId);
 | ||
|     const blocks = core.status.maps[floorId].blocks;
 | ||
|     const i = blocks.findIndex(v => v.x === x && v.y === y);
 | ||
|     if (i !== -1) {
 | ||
|         const block = blocks[i];
 | ||
|         this.removeBlockByIndex(i, floorId);
 | ||
|         this._removeBlockFromMap(floorId, block);
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| };
 | ||
| 
 | ||
| ////// 根据block的索引(尽可能)删除该块 //////
 | ||
| maps.prototype.removeBlockByIndex = function (index, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     core.extractBlocks(floorId);
 | ||
|     var blocks = core.status.maps[floorId].blocks,
 | ||
|         block = blocks[index];
 | ||
|     blocks.splice(index, 1);
 | ||
|     if (core.status.mapBlockObjs[floorId])
 | ||
|         delete core.status.mapBlockObjs[floorId][block.x + ',' + block.y];
 | ||
|     core.setMapBlockDisabled(floorId, block.x, block.y, true);
 | ||
|     this._updateMapArray(floorId, block.x, block.y);
 | ||
|     Mota.require('@user/data-base').hook.emit(
 | ||
|         'setBlock',
 | ||
|         block.x,
 | ||
|         block.y,
 | ||
|         floorId,
 | ||
|         0,
 | ||
|         block?.id ?? 0
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 一次性删除多个block //////
 | ||
| maps.prototype.removeBlockByIndexes = function (indexes, floorId) {
 | ||
|     indexes
 | ||
|         .sort(function (a, b) {
 | ||
|             return b - a;
 | ||
|         })
 | ||
|         .forEach(function (index) {
 | ||
|             core.removeBlockByIndex(index, floorId);
 | ||
|         });
 | ||
| };
 | ||
| 
 | ||
| ////// 显示前景/背景地图 //////
 | ||
| maps.prototype.showBgFgMap = function (name, loc, floorId, callback) {
 | ||
|     this._triggerBgFgMap('show', name, loc, floorId, callback);
 | ||
| };
 | ||
| 
 | ||
| ////// 隐藏前景/背景地图 //////
 | ||
| maps.prototype.hideBgFgMap = function (name, loc, floorId, callback) {
 | ||
|     this._triggerBgFgMap('hide', name, loc, floorId, callback);
 | ||
| };
 | ||
| 
 | ||
| ////// 设置前景/背景地图的显示状态 //////
 | ||
| maps.prototype._triggerBgFgMap = function (type, name, loc, floorId, callback) {
 | ||
|     if (type != 'show') type = 'hide';
 | ||
|     if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return;
 | ||
|     if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc];
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
| 
 | ||
|     if (loc.length == 0) return;
 | ||
|     var disabled = core.getFlag('__' + name + 'd__', {});
 | ||
|     disabled[floorId] = disabled[floorId] || [];
 | ||
|     loc.forEach(function (t) {
 | ||
|         if (type == 'hide') {
 | ||
|             disabled[floorId].push([t[0], t[1]]);
 | ||
|         } else {
 | ||
|             disabled[floorId] = disabled[floorId].filter(function (one) {
 | ||
|                 return one[0] != t[0] || one[1] != t[1];
 | ||
|             });
 | ||
|         }
 | ||
|     });
 | ||
|     core.setFlag('__' + name + 'd__', disabled);
 | ||
| 
 | ||
|     core.status[name + 'maps'][floorId] = null;
 | ||
| 
 | ||
|     if (floorId == core.status.floorId) {
 | ||
|         core.redrawMap();
 | ||
|     }
 | ||
|     if (callback) callback();
 | ||
| };
 | ||
| 
 | ||
| ////// 显示一个楼层贴图 //////
 | ||
| maps.prototype.showFloorImage = function (loc, floorId, callback) {
 | ||
|     this._triggerFloorImage('show', loc, floorId, callback);
 | ||
| };
 | ||
| 
 | ||
| ////// 隐藏一个楼层贴图 //////
 | ||
| maps.prototype.hideFloorImage = function (loc, floorId, callback) {
 | ||
|     this._triggerFloorImage('hide', loc, floorId, callback);
 | ||
| };
 | ||
| 
 | ||
| ///// 设置贴图显示状态 //////
 | ||
| maps.prototype._triggerFloorImage = function (type, loc, floorId, callback) {
 | ||
|     if (type != 'show') type = 'hide';
 | ||
|     if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc];
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
| 
 | ||
|     if (loc.length == 0) return;
 | ||
|     loc.forEach(function (t) {
 | ||
|         var x = t[0],
 | ||
|             y = t[1];
 | ||
|         var flag = '__floorImg__' + floorId + '_' + x + '_' + y;
 | ||
|         if (type == 'hide') core.setFlag(flag, true);
 | ||
|         else core.removeFlag(flag);
 | ||
|     });
 | ||
| 
 | ||
|     if (floorId == core.status.floorId) {
 | ||
|         core.redrawMap();
 | ||
|     }
 | ||
|     if (callback) callback();
 | ||
| };
 | ||
| 
 | ||
| ////// 改变图块 //////
 | ||
| maps.prototype.setBlock = function (number, x, y, floorId, noredraw) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId || number == null || x == null || y == null) return;
 | ||
|     if (
 | ||
|         x < 0 ||
 | ||
|         x >= core.floors[floorId].width ||
 | ||
|         y < 0 ||
 | ||
|         y >= core.floors[floorId].height
 | ||
|     )
 | ||
|         return;
 | ||
|     if (typeof number == 'string') {
 | ||
|         const num = Number(number);
 | ||
|         if (!isNaN(num)) number = num;
 | ||
|         else number = core.getNumberById(number);
 | ||
|     }
 | ||
| 
 | ||
|     var block = this.initBlock(x, y, number, true, core.floors[floorId]);
 | ||
|     if (block.id == 0 && !block.event.trigger) {
 | ||
|         // 转变图块为0且该点无事件,视为删除
 | ||
|         core.removeBlock(x, y, floorId);
 | ||
|         return;
 | ||
|     }
 | ||
|     var originBlock = core.getBlock(x, y, floorId, true);
 | ||
|     var originEvent = originBlock == null ? null : originBlock.event;
 | ||
|     if (originBlock == null) {
 | ||
|         core.status.maps[floorId].blocks.push(block);
 | ||
|         if (core.status.mapBlockObjs[floorId])
 | ||
|             core.status.mapBlockObjs[floorId][block.x + ',' + block.y] = block;
 | ||
|         core.setMapBlockDisabled(floorId, block.x, block.y, false);
 | ||
|         delete block.disable;
 | ||
|     } else {
 | ||
|         originBlock.id = number;
 | ||
|         originBlock.event = block.event;
 | ||
|         block = originBlock;
 | ||
|     }
 | ||
|     this._updateMapArray(floorId, x, y);
 | ||
|     if (floorId == core.status.floorId) {
 | ||
|         // 有任何一个是autotile直接重绘地图
 | ||
|         if (
 | ||
|             (originEvent != null && originEvent.cls == 'autotile') ||
 | ||
|             (block.event.cls == 'autotile' && !noredraw)
 | ||
|         ) {
 | ||
|             core.redrawMap();
 | ||
|         } else {
 | ||
|             if (originEvent != null) {
 | ||
|                 this._removeBlockFromMap(floorId, {
 | ||
|                     x: x,
 | ||
|                     y: y,
 | ||
|                     event: originEvent
 | ||
|                 });
 | ||
|             }
 | ||
|             if (!block.disable) {
 | ||
|                 if (!noredraw) {
 | ||
|                     core.drawBlock(block);
 | ||
|                     core.addGlobalAnimate(block);
 | ||
|                     core.updateStatusBar();
 | ||
|                 }
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     Mota.require('@user/data-base').hook.emit(
 | ||
|         'setBlock',
 | ||
|         x,
 | ||
|         y,
 | ||
|         floorId,
 | ||
|         number,
 | ||
|         originBlock?.id ?? 0
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.animateSetBlock = function (
 | ||
|     number,
 | ||
|     x,
 | ||
|     y,
 | ||
|     floorId,
 | ||
|     time,
 | ||
|     callback
 | ||
| ) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     time = time || 0;
 | ||
|     if (floorId != core.status.floorId || time == 0) {
 | ||
|         // 不在当前楼层,直接忽略
 | ||
|         this.setBlock(number, x, y, floorId);
 | ||
|         if (callback) callback();
 | ||
|         return;
 | ||
|     }
 | ||
|     if (typeof number == 'string') {
 | ||
|         const num = Number(number);
 | ||
|         if (!isNaN(num)) number = num;
 | ||
|         else number = core.getNumberById(number);
 | ||
|     }
 | ||
|     var originBlock = core.getBlock(x, y, floorId, true);
 | ||
|     var block = this.initBlock(x, y, number, true, core.floors[floorId]);
 | ||
| 
 | ||
|     // 如果原本是启用的
 | ||
|     if (originBlock != null && !originBlock.disable) {
 | ||
|         return this._animateSetBlock_originEnabled(
 | ||
|             block,
 | ||
|             number,
 | ||
|             x,
 | ||
|             y,
 | ||
|             floorId,
 | ||
|             time,
 | ||
|             callback
 | ||
|         );
 | ||
|     }
 | ||
| 
 | ||
|     // 如果原本不存在
 | ||
|     if (originBlock == null) {
 | ||
|         return this._animateSetBlock_originNotExists(
 | ||
|             block,
 | ||
|             number,
 | ||
|             x,
 | ||
|             y,
 | ||
|             floorId,
 | ||
|             time,
 | ||
|             callback
 | ||
|         );
 | ||
|     }
 | ||
| 
 | ||
|     // 如果原本存在且禁用;应当直接设置,没有动画
 | ||
|     if (originBlock != null && originBlock.disable) {
 | ||
|         return this._animateSetBlock_originDisabled(
 | ||
|             number,
 | ||
|             x,
 | ||
|             y,
 | ||
|             floorId,
 | ||
|             callback
 | ||
|         );
 | ||
|     }
 | ||
|     if (callback) callback();
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateSetBlock_originEnabled = function (
 | ||
|     block,
 | ||
|     number,
 | ||
|     x,
 | ||
|     y,
 | ||
|     floorId,
 | ||
|     time,
 | ||
|     callback
 | ||
| ) {
 | ||
|     // 情况1:设置到0
 | ||
|     if (block.id == 0) {
 | ||
|         // 如果该点红点没有事件 - 直接删除
 | ||
|         if (!block.event.trigger) {
 | ||
|             return this.animateBlock([x, y], 'remove', time, callback);
 | ||
|         } else {
 | ||
|             // 如果该点红点有事件;则设置到0,但是需启用
 | ||
|             return this.animateBlock([x, y], 'hide', time, function () {
 | ||
|                 core.setBlock(0, x, y, floorId);
 | ||
|                 core.showBlock(x, y, floorId);
 | ||
|                 if (callback) callback();
 | ||
|             });
 | ||
|         }
 | ||
|     }
 | ||
|     // 情况2:设置到非0
 | ||
|     else {
 | ||
|         return this.animateBlock([x, y], 'hide', time / 2, function () {
 | ||
|             core.setBlock(number, x, y, floorId);
 | ||
|             core.animateBlock([x, y], 'show', time / 2, callback);
 | ||
|         });
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateSetBlock_originNotExists = function (
 | ||
|     block,
 | ||
|     number,
 | ||
|     x,
 | ||
|     y,
 | ||
|     floorId,
 | ||
|     time,
 | ||
|     callback
 | ||
| ) {
 | ||
|     // 情况1:设置到0;没有动画效果
 | ||
|     if (block.id == 0) {
 | ||
|         core.setBlock(number, x, y, floorId);
 | ||
|         if (callback) callback();
 | ||
|     } else {
 | ||
|         // 情况2:设置到非0,有淡入动画
 | ||
|         core.setBlock(number, x, y, floorId);
 | ||
|         core.hideBlock(x, y, floorId);
 | ||
|         core.animateBlock([x, y], 'show', time, callback);
 | ||
|         return;
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateSetBlock_originDisabled = function (
 | ||
|     number,
 | ||
|     x,
 | ||
|     y,
 | ||
|     floorId,
 | ||
|     callback
 | ||
| ) {
 | ||
|     core.setBlock(number, x, y, floorId);
 | ||
|     if (callback) callback();
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.animateSetBlocks = function (
 | ||
|     number,
 | ||
|     locs,
 | ||
|     floorId,
 | ||
|     time,
 | ||
|     callback
 | ||
| ) {
 | ||
|     if (!(locs instanceof Array)) {
 | ||
|         if (callback) callback();
 | ||
|         return;
 | ||
|     }
 | ||
|     if (typeof locs[0] == 'number' && typeof locs[1] == 'number') locs = [locs];
 | ||
| 
 | ||
|     var count = locs.length;
 | ||
|     var _afterSet = function () {
 | ||
|         count--;
 | ||
|         if (count == 0) {
 | ||
|             if (callback) callback();
 | ||
|         }
 | ||
|     };
 | ||
|     locs.forEach(function (loc) {
 | ||
|         core.animateSetBlock(number, loc[0], loc[1], floorId, time, _afterSet);
 | ||
|     });
 | ||
| };
 | ||
| 
 | ||
| ////// 事件转向 //////
 | ||
| maps.prototype.turnBlock = function (direction, x, y, floorId) {
 | ||
|     var id = core.getBlockId(x, y, floorId, true);
 | ||
|     var blockInfo = core.getBlockInfo(id);
 | ||
|     if (blockInfo == null) return;
 | ||
|     var faceIds = blockInfo.faceIds || {};
 | ||
|     var currDirection = null;
 | ||
|     for (var dir in core.utils.scan) {
 | ||
|         if (faceIds[dir] == id) {
 | ||
|             currDirection = dir;
 | ||
|         }
 | ||
|     }
 | ||
|     if (currDirection == null) return;
 | ||
|     var nextDirection = core.turnDirection(direction, currDirection);
 | ||
|     var nextId = faceIds[nextDirection];
 | ||
|     if (nextId != null && nextId != id) {
 | ||
|         this.setBlock(nextId, x, y, floorId);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 将地图中所有某个图块替换成另一个图块 //////
 | ||
| maps.prototype.replaceBlock = function (fromNumber, toNumber, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (floorId instanceof Array) {
 | ||
|         floorId.forEach(function (floorId) {
 | ||
|             core.replaceBlock(fromNumber, toNumber, floorId);
 | ||
|         });
 | ||
|         return;
 | ||
|     }
 | ||
|     var toBlock = this.getBlockByNumber(toNumber, true);
 | ||
|     core.extractBlocks(floorId);
 | ||
|     core.status.maps[floorId].blocks.forEach(function (block) {
 | ||
|         if (block.id == fromNumber) {
 | ||
|             block.id = toNumber;
 | ||
|             for (var one in toBlock.event) {
 | ||
|                 block.event[one] = core.clone(toBlock.event[one]);
 | ||
|             }
 | ||
|             this._updateMapArray(floorId, block.x, block.y);
 | ||
|             Mota.require('@user/data-base').hook.emit(
 | ||
|                 'setBlock',
 | ||
|                 x,
 | ||
|                 y,
 | ||
|                 floorId,
 | ||
|                 fromNumber,
 | ||
|                 toNumber
 | ||
|             );
 | ||
|         }
 | ||
|     }, this);
 | ||
|     if (floorId == core.status.floorId) core.redrawMap();
 | ||
| };
 | ||
| 
 | ||
| ////// 改变前景背景的图块 //////
 | ||
| maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId || number == null || x == null || y == null) return;
 | ||
|     if (
 | ||
|         x < 0 ||
 | ||
|         x >= core.floors[floorId].width ||
 | ||
|         y < 0 ||
 | ||
|         y >= core.floors[floorId].height
 | ||
|     )
 | ||
|         return;
 | ||
|     if (!name || (!name.startsWith('bg') && !name.startsWith('fg'))) return;
 | ||
| 
 | ||
|     if (typeof number == 'string') {
 | ||
|         const num = Number(number);
 | ||
|         if (!isNaN(num)) number = num;
 | ||
|         else number = core.getNumberById(number);
 | ||
|     }
 | ||
| 
 | ||
|     var values = core.getFlag('__' + name + 'v__', {});
 | ||
|     values[floorId] = (values[floorId] || []).filter(function (one) {
 | ||
|         return one[0] != x || one[1] != y;
 | ||
|     });
 | ||
|     values[floorId].push([x, y, number]);
 | ||
|     core.setFlag('__' + name + 'v__', values);
 | ||
| 
 | ||
|     core.status[name + 'maps'][floorId] = null;
 | ||
| 
 | ||
|     this._getBgFgMapArray(name, floorId, true);
 | ||
| 
 | ||
|     if (floorId == core.status.floorId) {
 | ||
|         core.clearMap(name);
 | ||
|         if (name.startsWith('bg')) core.drawBg(floorId);
 | ||
|         else core.drawFg(floorId);
 | ||
|     }
 | ||
| 
 | ||
|     Mota.require('@user/data-base').hook.emit(
 | ||
|         'setBgFgBlock',
 | ||
|         name,
 | ||
|         number,
 | ||
|         x,
 | ||
|         y,
 | ||
|         floorId
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 重置地图 //////
 | ||
| maps.prototype.resetMap = function (floorId) {
 | ||
|     floorId = floorId || core.status.floorId;
 | ||
|     if (!floorId) return;
 | ||
|     if (typeof floorId == 'string') floorId = [floorId];
 | ||
|     var needRefresh = false;
 | ||
|     floorId.forEach(function (t) {
 | ||
|         core.status.maps[t] = core.maps.loadFloor(t);
 | ||
|         // 重置本层的全部独立事件
 | ||
|         Object.keys(core.status.hero.flags).forEach(function (one) {
 | ||
|             if (one.startsWith(floorId + '@'))
 | ||
|                 delete core.status.hero.flags[one];
 | ||
|         });
 | ||
|         // 重置本层的图块删除信息
 | ||
|         delete (flags.__disabled__ || {})[t];
 | ||
|         delete (core.status.mapBlockObjs || {})[t];
 | ||
|         if (t == core.status.floorId) needRefresh = true;
 | ||
|     });
 | ||
|     if (needRefresh) this.redrawMap();
 | ||
|     core.drawTip('地图重置成功');
 | ||
| };
 | ||
| 
 | ||
| // -------- 移动/跳跃图块,图块的淡入淡出 -------- //
 | ||
| 
 | ||
| ////// 初始化独立的block canvas //////
 | ||
| maps.prototype._initDetachedBlock = function (blockInfo, x, y, displayDamage) {
 | ||
|     // Deprecated. See src/plugin/game/fx/rewrite.ts
 | ||
| };
 | ||
| 
 | ||
| ////// 移动独立的block canvas //////
 | ||
| maps.prototype._moveDetachedBlock = function (
 | ||
|     blockInfo,
 | ||
|     nowX,
 | ||
|     nowY,
 | ||
|     opacity,
 | ||
|     canvases
 | ||
| ) {
 | ||
|     // Deprecated.
 | ||
| };
 | ||
| 
 | ||
| ////// 删除独立的block canvas //////
 | ||
| maps.prototype._deleteDetachedBlock = function (canvases) {
 | ||
|     // Deprecated.
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._getAndRemoveBlock = function (x, y) {
 | ||
|     var block = core.getBlock(x, y);
 | ||
|     if (block == null) return null;
 | ||
|     var blockInfo = this.getBlockInfo(block);
 | ||
|     if (blockInfo == null) return;
 | ||
|     core.removeBlock(x, y);
 | ||
|     return [block, blockInfo];
 | ||
| };
 | ||
| 
 | ||
| ////// 显示移动某块的动画,达到{“type”:”move”}的效果 //////
 | ||
| maps.prototype.moveBlock = function (x, y, steps, time, keep, callback) {
 | ||
|     if (core.status.replay.speed == 24) time = 1;
 | ||
|     time = time || 500;
 | ||
|     var blockArr = this._getAndRemoveBlock(x, y);
 | ||
|     if (blockArr == null) {
 | ||
|         if (callback) callback();
 | ||
|         return;
 | ||
|     }
 | ||
|     var block = blockArr[0],
 | ||
|         blockInfo = blockArr[1];
 | ||
|     var moveSteps = (steps || [])
 | ||
|         .map(function (t) {
 | ||
|             return [t.split(':')[0], parseInt(t.split(':')[1] || '1')];
 | ||
|         })
 | ||
|         .filter(function (t) {
 | ||
|             return (
 | ||
|                 [
 | ||
|                     'up',
 | ||
|                     'down',
 | ||
|                     'left',
 | ||
|                     'right',
 | ||
|                     'forward',
 | ||
|                     'backward',
 | ||
|                     'leftup',
 | ||
|                     'leftdown',
 | ||
|                     'rightup',
 | ||
|                     'rightdown',
 | ||
|                     'speed'
 | ||
|                 ].indexOf(t[0]) >= 0 && !(t[0] == 'speed' && t[1] < 16)
 | ||
|             );
 | ||
|         });
 | ||
|     var canvases = this._initDetachedBlock(
 | ||
|         blockInfo,
 | ||
|         x,
 | ||
|         y,
 | ||
|         block.event.animate !== false
 | ||
|     );
 | ||
|     this._moveDetachedBlock(blockInfo, 32 * x, 32 * y, 1, canvases);
 | ||
| 
 | ||
|     var moveInfo = {
 | ||
|         sx: x,
 | ||
|         sy: y,
 | ||
|         x: x,
 | ||
|         y: y,
 | ||
|         px: 32 * x,
 | ||
|         py: 32 * y,
 | ||
|         opacity: 1,
 | ||
|         keep: keep,
 | ||
|         lastDirection: null,
 | ||
|         offset: 1,
 | ||
|         moveSteps: moveSteps,
 | ||
|         step: 0,
 | ||
|         per_time: time / 16 / core.status.replay.speed
 | ||
|     };
 | ||
|     this._moveBlock_doMove(blockInfo, canvases, moveInfo, callback);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._moveBlock_doMove = function (
 | ||
|     blockInfo,
 | ||
|     canvases,
 | ||
|     moveInfo,
 | ||
|     callback
 | ||
| ) {
 | ||
|     var animateTotal = blockInfo.animate,
 | ||
|         animateTime = 0;
 | ||
|     // 强制npc48行走时使用四帧动画
 | ||
|     if (!blockInfo.doorInfo && !blockInfo.bigImage && blockInfo.cls == 'npc48')
 | ||
|         animateTotal = 4;
 | ||
|     var _run = function () {
 | ||
|         var cb = function () {
 | ||
|             core.maps._deleteDetachedBlock(canvases);
 | ||
|             // 不消失
 | ||
|             if (moveInfo.keep) {
 | ||
|                 core.setBlock(blockInfo.number, moveInfo.x, moveInfo.y);
 | ||
|                 core.showBlock(moveInfo.x, moveInfo.y);
 | ||
|                 core.moveEnemyOnPoint(
 | ||
|                     moveInfo.sx,
 | ||
|                     moveInfo.sy,
 | ||
|                     moveInfo.x,
 | ||
|                     moveInfo.y
 | ||
|                 );
 | ||
|             }
 | ||
|             if (callback) callback();
 | ||
|         };
 | ||
| 
 | ||
|         var animate = window.setInterval(function () {
 | ||
|             if (blockInfo.cls != 'tileset') {
 | ||
|                 animateTime += moveInfo.per_time;
 | ||
|                 if (animateTime > core.values.animateSpeed) {
 | ||
|                     animateTime = 0;
 | ||
|                     blockInfo.posX = (blockInfo.posX + 1) % animateTotal;
 | ||
|                 }
 | ||
|             }
 | ||
|             if (moveInfo.moveSteps.length != 0) {
 | ||
|                 if (core.maps._moveBlock_updateSpeed(moveInfo)) {
 | ||
|                     clearInterval(animate);
 | ||
|                     delete core.animateFrame.asyncId[animate];
 | ||
|                     _run();
 | ||
|                 } else
 | ||
|                     core.maps._moveBlock_moving(blockInfo, canvases, moveInfo);
 | ||
|             } else
 | ||
|                 core.maps._moveJumpBlock_finished(
 | ||
|                     blockInfo,
 | ||
|                     canvases,
 | ||
|                     moveInfo,
 | ||
|                     animate,
 | ||
|                     cb
 | ||
|                 );
 | ||
|         }, moveInfo.per_time);
 | ||
| 
 | ||
|         core.animateFrame.lastAsyncId = animate;
 | ||
|         core.animateFrame.asyncId[animate] = cb;
 | ||
|     };
 | ||
|     _run();
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._moveBlock_updateSpeed = function (moveInfo) {
 | ||
|     if (
 | ||
|         moveInfo.step == 0 &&
 | ||
|         moveInfo.moveSteps[0][0] == 'speed' &&
 | ||
|         moveInfo.moveSteps[0][1] >= 16
 | ||
|     ) {
 | ||
|         moveInfo.per_time =
 | ||
|             moveInfo.moveSteps[0][1] / 16 / core.status.replay.speed;
 | ||
|         moveInfo.moveSteps.shift();
 | ||
|         return true;
 | ||
|     }
 | ||
|     return false;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._moveBlock_updateDirection = function (blockInfo, moveInfo) {
 | ||
|     moveInfo.offset = 1;
 | ||
|     var curr = moveInfo.moveSteps[0];
 | ||
|     // 展开forward和backward
 | ||
|     if ((curr[0] == 'backward' || curr[0] == 'forward') && curr[1] > 1) {
 | ||
|         moveInfo.moveSteps.shift();
 | ||
|         for (var i = 0; i < curr[1]; ++i) {
 | ||
|             moveInfo.moveSteps.unshift([curr[0], 1]);
 | ||
|         }
 | ||
|         return this._moveBlock_updateDirection(blockInfo, moveInfo);
 | ||
|     }
 | ||
|     if (moveInfo.lastDirection == null) {
 | ||
|         for (var d in blockInfo.faceIds) {
 | ||
|             if (blockInfo.faceIds[d] == blockInfo.id) {
 | ||
|                 moveInfo.lastDirection = d;
 | ||
|                 break;
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     if (curr[0] == 'forward' || curr[0] == 'backward') {
 | ||
|         if (moveInfo.lastDirection == null) {
 | ||
|             moveInfo.moveSteps.shift();
 | ||
|             return false;
 | ||
|         }
 | ||
|         if (curr[0] == 'backward') moveInfo.offset = -1;
 | ||
|         curr[0] = moveInfo.lastDirection;
 | ||
|     }
 | ||
|     moveInfo.lastDirection = curr[0];
 | ||
| 
 | ||
|     // 根据faceIds修改朝向
 | ||
|     var faceDirection = curr[0];
 | ||
|     if (faceDirection == 'leftup' || faceDirection == 'leftdown')
 | ||
|         faceDirection = 'left';
 | ||
|     if (faceDirection == 'rightup' || faceDirection == 'rightdown')
 | ||
|         faceDirection = 'right';
 | ||
|     var currid = blockInfo.faceIds[faceDirection];
 | ||
|     blockInfo.face = faceDirection;
 | ||
|     if (currid) {
 | ||
|         var posY = core.material.icons[blockInfo.cls][currid];
 | ||
|         if (posY != null) {
 | ||
|             blockInfo.number = core.getNumberById(currid) || blockInfo.number;
 | ||
|             blockInfo.posY = posY;
 | ||
|         }
 | ||
|     }
 | ||
|     // 处理 left:0 的情况,仅转向
 | ||
|     if (curr[1] <= 0) {
 | ||
|         moveInfo.moveSteps.shift();
 | ||
|         return false;
 | ||
|     }
 | ||
|     moveInfo.x += core.utils.scan2[curr[0]].x * moveInfo.offset;
 | ||
|     moveInfo.y += core.utils.scan2[curr[0]].y * moveInfo.offset;
 | ||
|     return true;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._moveBlock_moving = function (blockInfo, canvases, moveInfo) {
 | ||
|     if (moveInfo.step == 0) {
 | ||
|         if (!this._moveBlock_updateDirection(blockInfo, moveInfo)) return;
 | ||
|     }
 | ||
|     var curr = moveInfo.moveSteps[0];
 | ||
|     moveInfo.step++;
 | ||
|     moveInfo.px += core.utils.scan2[curr[0]].x * 2 * moveInfo.offset;
 | ||
|     moveInfo.py += core.utils.scan2[curr[0]].y * 2 * moveInfo.offset;
 | ||
|     this._moveDetachedBlock(
 | ||
|         blockInfo,
 | ||
|         moveInfo.px,
 | ||
|         moveInfo.py,
 | ||
|         moveInfo.opacity,
 | ||
|         canvases
 | ||
|     );
 | ||
|     if (moveInfo.step == 16) {
 | ||
|         moveInfo.step = 0;
 | ||
|         moveInfo.moveSteps[0][1]--;
 | ||
|         if (moveInfo.moveSteps[0][1] <= 0) {
 | ||
|             moveInfo.moveSteps.shift();
 | ||
|         }
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 显示跳跃某块的动画,达到{"type":"jump"}的效果 //////
 | ||
| maps.prototype.jumpBlock = function (sx, sy, ex, ey, time, keep, callback) {
 | ||
|     time = time || 500;
 | ||
|     var blockArr = this._getAndRemoveBlock(sx, sy);
 | ||
|     if (blockArr == null) {
 | ||
|         if (callback) callback();
 | ||
|         return;
 | ||
|     }
 | ||
|     var block = blockArr[0],
 | ||
|         blockInfo = blockArr[1];
 | ||
|     var canvases = this._initDetachedBlock(
 | ||
|         blockInfo,
 | ||
|         sx,
 | ||
|         sy,
 | ||
|         block.event.animate !== false
 | ||
|     );
 | ||
|     this._moveDetachedBlock(blockInfo, 32 * sx, 32 * sy, 1, canvases);
 | ||
|     var jumpInfo = this.__generateJumpInfo(sx, sy, ex, ey, time);
 | ||
|     jumpInfo.keep = keep;
 | ||
| 
 | ||
|     this._jumpBlock_doJump(blockInfo, canvases, jumpInfo, callback);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.__generateJumpInfo = function (sx, sy, ex, ey, time) {
 | ||
|     var dx = ex - sx,
 | ||
|         dy = ey - sy,
 | ||
|         distance = Math.round(Math.sqrt(dx * dx + dy * dy));
 | ||
|     var jump_peak = 6 + distance,
 | ||
|         jump_count = jump_peak * 2;
 | ||
|     time /= Math.max(core.status.replay.speed, 1);
 | ||
|     return {
 | ||
|         sx: sx,
 | ||
|         sy: sy,
 | ||
|         x: sx,
 | ||
|         y: sy,
 | ||
|         ex: ex,
 | ||
|         ey: ey,
 | ||
|         px: 32 * sx,
 | ||
|         py: 32 * sy,
 | ||
|         opacity: 1,
 | ||
|         jump_peak: jump_peak,
 | ||
|         jump_count: jump_count,
 | ||
|         step: 0,
 | ||
|         per_time: time / jump_count
 | ||
|     };
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._jumpBlock_doJump = function (
 | ||
|     blockInfo,
 | ||
|     canvases,
 | ||
|     jumpInfo,
 | ||
|     callback
 | ||
| ) {
 | ||
|     var cb = function () {
 | ||
|         core.maps._deleteDetachedBlock(canvases);
 | ||
|         // 不消失
 | ||
|         if (jumpInfo.keep) {
 | ||
|             core.setBlock(blockInfo.number, jumpInfo.ex, jumpInfo.ey);
 | ||
|             core.showBlock(jumpInfo.ex, jumpInfo.ey);
 | ||
|             core.moveEnemyOnPoint(
 | ||
|                 jumpInfo.sx,
 | ||
|                 jumpInfo.sy,
 | ||
|                 jumpInfo.ex,
 | ||
|                 jumpInfo.ey
 | ||
|             );
 | ||
|         }
 | ||
|         if (callback) callback();
 | ||
|     };
 | ||
| 
 | ||
|     var animate = window.setInterval(function () {
 | ||
|         if (jumpInfo.jump_count > 0)
 | ||
|             core.maps._jumpBlock_jumping(blockInfo, canvases, jumpInfo);
 | ||
|         else
 | ||
|             core.maps._moveJumpBlock_finished(
 | ||
|                 blockInfo,
 | ||
|                 canvases,
 | ||
|                 jumpInfo,
 | ||
|                 animate,
 | ||
|                 cb
 | ||
|             );
 | ||
|     }, jumpInfo.per_time);
 | ||
| 
 | ||
|     core.animateFrame.lastAsyncId = animate;
 | ||
|     core.animateFrame.asyncId[animate] = cb;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype.__updateJumpInfo = function (jumpInfo) {
 | ||
|     jumpInfo.jump_count--;
 | ||
|     jumpInfo.x =
 | ||
|         (jumpInfo.x * jumpInfo.jump_count + jumpInfo.ex) /
 | ||
|         (jumpInfo.jump_count + 1.0);
 | ||
|     jumpInfo.y =
 | ||
|         (jumpInfo.y * jumpInfo.jump_count + jumpInfo.ey) /
 | ||
|         (jumpInfo.jump_count + 1.0);
 | ||
|     jumpInfo.px = 32 * jumpInfo.x;
 | ||
|     var delta = Math.abs(jumpInfo.jump_count - jumpInfo.jump_peak);
 | ||
|     jumpInfo.py =
 | ||
|         32 * jumpInfo.y -
 | ||
|         (jumpInfo.jump_peak * jumpInfo.jump_peak - delta * delta) / 2;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._jumpBlock_jumping = function (blockInfo, canvases, jumpInfo) {
 | ||
|     this.__updateJumpInfo(jumpInfo);
 | ||
|     core.maps._moveDetachedBlock(
 | ||
|         blockInfo,
 | ||
|         jumpInfo.px,
 | ||
|         jumpInfo.py,
 | ||
|         jumpInfo.opacity,
 | ||
|         canvases
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._moveJumpBlock_finished = function (
 | ||
|     blockInfo,
 | ||
|     canvases,
 | ||
|     info,
 | ||
|     animate,
 | ||
|     cb
 | ||
| ) {
 | ||
|     if (info.keep) info.opacity = 0;
 | ||
|     else info.opacity -= 0.06;
 | ||
|     if (info.opacity <= 0) {
 | ||
|         delete core.animateFrame.asyncId[animate];
 | ||
|         clearInterval(animate);
 | ||
|         cb();
 | ||
|     } else {
 | ||
|         this._moveDetachedBlock(
 | ||
|             blockInfo,
 | ||
|             info.px,
 | ||
|             info.py,
 | ||
|             info.opacity,
 | ||
|             canvases
 | ||
|         );
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 显示/隐藏某个块时的动画效果 //////
 | ||
| maps.prototype.animateBlock = function (loc, type, time, callback) {
 | ||
|     if (core.status.replay.speed == 24) time = 1;
 | ||
|     if (typeof loc[0] == 'number' && typeof loc[1] == 'number') loc = [loc];
 | ||
|     if (
 | ||
|         type != 'show' &&
 | ||
|         type != 'hide' &&
 | ||
|         type != 'remove' &&
 | ||
|         typeof type != 'number'
 | ||
|     ) {
 | ||
|         if (callback) callback();
 | ||
|         return;
 | ||
|     }
 | ||
|     loc.forEach(function (t) {
 | ||
|         if (type === 'show') core.showBlock(t[0], t[1]);
 | ||
|         else if (type === 'hide') core.hideBlock(t[0], t[1]);
 | ||
|         else if (type === 'remove') core.removeBlock(t[0], t[1]);
 | ||
|         else core.showBlock(t[0], t[1]);
 | ||
|     });
 | ||
|     callback?.();
 | ||
|     // --- 检测所有是0的点
 | ||
|     // var list = this._animateBlock_getList(loc, type);
 | ||
|     // if (list.length == 0) {
 | ||
|     //     if (callback) callback();
 | ||
|     //     return;
 | ||
|     // }
 | ||
|     // this._animateBlock_drawList(list, 0);
 | ||
|     // time /= Math.max(core.status.replay.speed, 1);
 | ||
|     // this._animateBlock_doAnimate(loc, list, type, time, callback);
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateBlock_doAnimate = function (
 | ||
|     loc,
 | ||
|     list,
 | ||
|     type,
 | ||
|     time,
 | ||
|     callback
 | ||
| ) {
 | ||
|     var step = 0,
 | ||
|         steps = Math.max(Math.floor(time / 10), 1);
 | ||
|     var cb = function () {
 | ||
|         list.forEach(function (t) {
 | ||
|             if (t.blockInfo) core.maps._deleteDetachedBlock(t.canvases);
 | ||
|         });
 | ||
|         loc.forEach(function (t) {
 | ||
|             if (type == 'show') core.showBlock(t[0], t[1]);
 | ||
|             else if (type == 'hide') core.hideBlock(t[0], t[1]);
 | ||
|             else if (type == 'remove') core.removeBlock(t[0], t[1]);
 | ||
|             else {
 | ||
|                 core.setBlockOpacity(type, t[0], t[1]);
 | ||
|                 core.showBlock(t[0], t[1]);
 | ||
|             }
 | ||
|         });
 | ||
|         if (callback) callback();
 | ||
|     };
 | ||
| 
 | ||
|     var animate = setInterval(function () {
 | ||
|         step++;
 | ||
|         core.maps._animateBlock_drawList(list, step / steps);
 | ||
|         if (step == steps) {
 | ||
|             delete core.animateFrame.asyncId[animate];
 | ||
|             clearInterval(animate);
 | ||
|             cb();
 | ||
|         }
 | ||
|     }, 10);
 | ||
| 
 | ||
|     core.animateFrame.lastAsyncId = animate;
 | ||
|     core.animateFrame.asyncId[animate] = cb;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateBlock_getList = function (loc, type) {
 | ||
|     var list = [];
 | ||
|     loc.forEach(function (t) {
 | ||
|         var block = core.getBlock(t[0], t[1], null, true);
 | ||
|         if (block == null) return;
 | ||
| 
 | ||
|         var fromOpacity = block.opacity;
 | ||
|         if (fromOpacity == null) fromOpacity = 1.0;
 | ||
| 
 | ||
|         var blockInfo = core.maps.getBlockInfo(block);
 | ||
|         if (blockInfo == null) {
 | ||
|             list.push({ x: t[0], y: t[1] });
 | ||
|             return;
 | ||
|         }
 | ||
|         if (typeof type == 'number' && block.disable) return;
 | ||
|         // 该点是否已经被启用/删除
 | ||
|         if (
 | ||
|             (type == 'show' && !block.disable) ||
 | ||
|             ((type == 'hide' || type == 'remove') && block.disable)
 | ||
|         ) {
 | ||
|             list.push({ x: t[0], y: t[1] });
 | ||
|             return;
 | ||
|         }
 | ||
| 
 | ||
|         var toOpacity = type;
 | ||
|         if (type == 'show') {
 | ||
|             toOpacity = fromOpacity;
 | ||
|             fromOpacity = 0.0;
 | ||
|         } else if (type == 'hide' || type == 'remove') {
 | ||
|             core.hideBlock(t[0], t[1]); // 暂时先隐藏
 | ||
|             toOpacity = 0.0;
 | ||
|         } else {
 | ||
|             core.hideBlock(t[0], t[1]); // 暂时先隐藏
 | ||
|         }
 | ||
| 
 | ||
|         var canvases = core.maps._initDetachedBlock(
 | ||
|             blockInfo,
 | ||
|             t[0],
 | ||
|             t[1],
 | ||
|             block.event.displayDamage !== false
 | ||
|         );
 | ||
| 
 | ||
|         list.push({
 | ||
|             x: t[0],
 | ||
|             y: t[1],
 | ||
|             blockInfo: blockInfo,
 | ||
|             canvases: canvases,
 | ||
|             fromOpacity: fromOpacity,
 | ||
|             toOpacity: toOpacity
 | ||
|         });
 | ||
|     });
 | ||
|     return list;
 | ||
| };
 | ||
| 
 | ||
| maps.prototype._animateBlock_drawList = function (list, progress) {
 | ||
|     list.forEach(function (t) {
 | ||
|         if (t.blockInfo)
 | ||
|             core.maps._moveDetachedBlock(
 | ||
|                 t.blockInfo,
 | ||
|                 t.x * 32,
 | ||
|                 t.y * 32,
 | ||
|                 t.fromOpacity + progress * (t.toOpacity - t.fromOpacity),
 | ||
|                 t.canvases
 | ||
|             );
 | ||
|     });
 | ||
| };
 | ||
| 
 | ||
| // ------ 全局动画控制,动画绘制 ------ //
 | ||
| 
 | ||
| ////// 添加一个全局动画 //////
 | ||
| maps.prototype.addGlobalAnimate = function (block) {
 | ||
|     if (!block || !block.event) return;
 | ||
|     this.removeGlobalAnimate(block.x, block.y, block.name);
 | ||
|     if (block.event.cls == 'autotile') {
 | ||
|         var id = block.event.id,
 | ||
|             img = core.material.images.autotile[id];
 | ||
|         if (!img || img.width == 96) return;
 | ||
|         core.status.autotileAnimateObjs.push(block);
 | ||
|     } else {
 | ||
|         if (
 | ||
|             !block.event.bigImage &&
 | ||
|             (!block.event.animate || block.event.animate == 1)
 | ||
|         )
 | ||
|             return;
 | ||
|         core.status.globalAnimateObjs.push(block);
 | ||
|     }
 | ||
| };
 | ||
| 
 | ||
| ////// 删除一个或所有全局动画 //////
 | ||
| maps.prototype.removeGlobalAnimate = function (x, y, name) {
 | ||
|     // 没有定义xy,则全部删除
 | ||
|     if (x == null || y == null) {
 | ||
|         core.status.globalAnimateStatus = 0;
 | ||
|         core.status.globalAnimateObjs = [];
 | ||
|         core.status.autotileAnimateObjs = [];
 | ||
|         core.status.floorAnimateObjs = [];
 | ||
|         return;
 | ||
|     }
 | ||
| 
 | ||
|     core.status.globalAnimateObjs = core.status.globalAnimateObjs.filter(
 | ||
|         function (block) {
 | ||
|             return block.x != x || block.y != y || block.name != name;
 | ||
|         }
 | ||
|     );
 | ||
| 
 | ||
|     // 检查Autotile
 | ||
|     core.status.autotileAnimateObjs = core.status.autotileAnimateObjs.filter(
 | ||
|         function (block) {
 | ||
|             return block.x != x || block.y != y || block.name != name;
 | ||
|         }
 | ||
|     );
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制UI层的box动画 //////
 | ||
| maps.prototype.drawBoxAnimate = function () {
 | ||
|     if (core.status.boxAnimateObjs.length == 0) return;
 | ||
|     // check ui2
 | ||
|     if (
 | ||
|         main.mode == 'play' &&
 | ||
|         core.status.boxAnimateObjs.filter(function (one) {
 | ||
|             return one.bigImage;
 | ||
|         }).length > 0 &&
 | ||
|         !core.dymCanvas.ui2
 | ||
|     ) {
 | ||
|         core.createCanvas('ui2', 0, 0, core._PX_, core._PY_, 142);
 | ||
|     }
 | ||
|     core.clearMap('ui2');
 | ||
| 
 | ||
|     core.status.boxAnimateObjs.forEach(function (obj) {
 | ||
|         if (obj.bigImage) {
 | ||
|             var ctx = obj.ctx || 'ui2';
 | ||
|             var bigImageInfo = core.maps._getBigImageInfo(
 | ||
|                 obj.bigImage,
 | ||
|                 obj.face,
 | ||
|                 core.status.globalAnimateStatus % 4
 | ||
|             );
 | ||
|             var sx = bigImageInfo.sx,
 | ||
|                 sy = bigImageInfo.sy,
 | ||
|                 per_width = bigImageInfo.per_width,
 | ||
|                 per_height = bigImageInfo.per_height;
 | ||
|             var actual_width = Math.min(per_width, obj.max_width || per_width),
 | ||
|                 actual_height = (per_height * actual_width) / per_width;
 | ||
|             var x = obj.centerX - actual_width / 2,
 | ||
|                 y = obj.centerY - actual_height / 2;
 | ||
|             core.clearMap(ctx, x, y, actual_width, actual_height);
 | ||
|             core.fillRect(
 | ||
|                 ctx,
 | ||
|                 x,
 | ||
|                 y,
 | ||
|                 actual_width,
 | ||
|                 actual_height,
 | ||
|                 core.material.groundPattern
 | ||
|             );
 | ||
|             core.strokeRect(ctx, x, y, actual_width, actual_height, 'gold', 2);
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 obj.bigImage,
 | ||
|                 sx,
 | ||
|                 sy,
 | ||
|                 per_width,
 | ||
|                 per_height,
 | ||
|                 obj.centerX - actual_width / 2,
 | ||
|                 obj.centerY - actual_height / 2,
 | ||
|                 actual_width,
 | ||
|                 actual_height
 | ||
|             );
 | ||
|         } else {
 | ||
|             var ctx = obj.ctx || 'ui';
 | ||
|             core.clearMap(ctx, obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight);
 | ||
|             core.fillRect(
 | ||
|                 ctx,
 | ||
|                 obj.bgx,
 | ||
|                 obj.bgy,
 | ||
|                 obj.bgWidth,
 | ||
|                 obj.bgHeight,
 | ||
|                 core.material.groundPattern
 | ||
|             );
 | ||
|             core.drawImage(
 | ||
|                 ctx,
 | ||
|                 obj.image,
 | ||
|                 (core.status.globalAnimateStatus % obj.animate) * 32,
 | ||
|                 obj.pos,
 | ||
|                 32,
 | ||
|                 obj.height,
 | ||
|                 obj.x,
 | ||
|                 obj.y,
 | ||
|                 obj.dw || 32,
 | ||
|                 obj.dh || obj.height
 | ||
|             );
 | ||
|         }
 | ||
|     });
 | ||
|     if (main.mode != 'play') core.status.boxAnimateObjs = [];
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制动画 //////
 | ||
| maps.prototype.drawAnimate = function (name, x, y, alignWindow, callback) {
 | ||
|     name = core.getMappedName(name);
 | ||
| 
 | ||
|     // 正在播放录像:不显示动画
 | ||
|     if (
 | ||
|         core.isReplaying() ||
 | ||
|         !core.material.animates[name] ||
 | ||
|         x == null ||
 | ||
|         y == null
 | ||
|     ) {
 | ||
|         if (callback) callback();
 | ||
|         return -1;
 | ||
|     }
 | ||
| 
 | ||
|     // 开始绘制
 | ||
|     var animate = core.material.animates[name],
 | ||
|         centerX = 32 * x + 16,
 | ||
|         centerY = 32 * y + 16;
 | ||
|     if (alignWindow) {
 | ||
|         centerX += core.bigmap.offsetX;
 | ||
|         centerY += core.bigmap.offsetY;
 | ||
|     }
 | ||
|     animate.se = animate.se || {};
 | ||
|     if (typeof animate.se == 'string') animate.se = { 1: animate.se };
 | ||
| 
 | ||
|     var id = setTimeout(null);
 | ||
|     core.status.animateObjs.push({
 | ||
|         name: name,
 | ||
|         id: id,
 | ||
|         animate: animate,
 | ||
|         centerX: centerX,
 | ||
|         centerY: centerY,
 | ||
|         index: 0,
 | ||
|         callback: callback
 | ||
|     });
 | ||
| 
 | ||
|     return id;
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制一个跟随勇士的动画 //////
 | ||
| maps.prototype.drawHeroAnimate = function (name, callback) {
 | ||
|     name = core.getMappedName(name);
 | ||
| 
 | ||
|     // 正在播放录像或动画不存在:不显示动画
 | ||
|     if (core.isReplaying() || !core.material.animates[name]) {
 | ||
|         if (callback) callback();
 | ||
|         return -1;
 | ||
|     }
 | ||
| 
 | ||
|     // 开始绘制
 | ||
|     var animate = core.material.animates[name];
 | ||
|     animate.se = animate.se || {};
 | ||
|     if (typeof animate.se == 'string') animate.se = { 1: animate.se };
 | ||
| 
 | ||
|     var id = setTimeout(null);
 | ||
|     core.status.animateObjs.push({
 | ||
|         name: name,
 | ||
|         id: id,
 | ||
|         animate: animate,
 | ||
|         hero: true,
 | ||
|         index: 0,
 | ||
|         callback: callback
 | ||
|     });
 | ||
| 
 | ||
|     return id;
 | ||
| };
 | ||
| 
 | ||
| ////// 获得当前正在播放的所有(指定)动画的id列表 //////
 | ||
| maps.prototype.getPlayingAnimates = function (name) {
 | ||
|     return (core.status.animateObjs || [])
 | ||
|         .filter(function (one) {
 | ||
|             return name == null || one.name == name;
 | ||
|         })
 | ||
|         .map(function (one) {
 | ||
|             return one.id;
 | ||
|         });
 | ||
| };
 | ||
| 
 | ||
| ////// 绘制动画的某一帧 //////
 | ||
| maps.prototype._drawAnimateFrame = function (
 | ||
|     name,
 | ||
|     animate,
 | ||
|     centerX,
 | ||
|     centerY,
 | ||
|     index
 | ||
| ) {
 | ||
|     var ctx = core.getContextByName(name);
 | ||
|     if (!ctx) return;
 | ||
|     var frame = animate.frames[index % animate.frame];
 | ||
|     core.playSound(
 | ||
|         (animate.se || {})[(index % animate.frame) + 1],
 | ||
|         (animate.pitch || {})[(index % animate.frame) + 1]
 | ||
|     );
 | ||
|     var ratio = animate.ratio;
 | ||
|     frame.forEach(function (t) {
 | ||
|         var image = animate.images[t.index];
 | ||
|         if (!image) return;
 | ||
| 
 | ||
|         var realWidth = (image.width * ratio * t.zoom) / 100;
 | ||
|         var realHeight = (image.height * ratio * t.zoom) / 100;
 | ||
|         core.setAlpha(ctx, t.opacity / 255);
 | ||
| 
 | ||
|         var cx = centerX + t.x,
 | ||
|             cy = centerY + t.y;
 | ||
| 
 | ||
|         var ix = cx - realWidth / 2 - core.bigmap.offsetX,
 | ||
|             iy = cy - realHeight / 2 - core.bigmap.offsetY;
 | ||
| 
 | ||
|         var mirror = t.mirror ? 'x' : null;
 | ||
|         var angle = t.angle ? (-t.angle * Math.PI) / 180 : null;
 | ||
|         core.drawImage(
 | ||
|             ctx,
 | ||
|             image,
 | ||
|             ix,
 | ||
|             iy,
 | ||
|             realWidth,
 | ||
|             realHeight,
 | ||
|             null,
 | ||
|             null,
 | ||
|             null,
 | ||
|             null,
 | ||
|             angle,
 | ||
|             mirror
 | ||
|         );
 | ||
| 
 | ||
|         core.setAlpha(ctx, 1);
 | ||
|     });
 | ||
| };
 | ||
| 
 | ||
| ////// 停止动画 //////
 | ||
| maps.prototype.stopAnimate = function (id, doCallback) {
 | ||
|     for (var i = 0; i < core.status.animateObjs.length; i++) {
 | ||
|         var obj = core.status.animateObjs[i];
 | ||
|         if (id == null || obj.id == id) {
 | ||
|             if (doCallback) {
 | ||
|                 (function (callback) {
 | ||
|                     setTimeout(function () {
 | ||
|                         if (callback) callback();
 | ||
|                     });
 | ||
|                 })(obj.callback);
 | ||
|             }
 | ||
|         }
 | ||
|     }
 | ||
|     core.status.animateObjs = core.status.animateObjs.filter(function (x) {
 | ||
|         return id != null && x.id != id;
 | ||
|     });
 | ||
|     if (core.status.animateObjs.length == 0) core.clearMap('animate');
 | ||
| };
 |