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.loadFloor = function (floorId, map) {
    var floor = core.floors[floorId];
    var content = {};
    content['floorId'] = floor.floorId;
    content['name'] = floor.name;
    content['title'] = floor.title;
    content['canFlyTo'] = floor.canFlyTo;
    if (!core.isset(map)) map=floor.map;
    var mapIntoBlocks = function(map,maps,floor,floorId){
        var blocks = [];
        var mw = core.floors[floorId].width || 13;
        var mh = core.floors[floorId].height || 13;
        for (var i = 0; i < mh; i++) {
            for (var j = 0; j < mw; j++) {
                var block = maps.initBlock(j, i, (map[i]||[])[j]||0);
                maps.addInfo(block);
                maps.addEvent(block,j,i,floor.events[j+","+i])
                maps.addChangeFloor(block,j,i,floor.changeFloor[j+","+i]);
                if (core.isset(block.event)) blocks.push(block);
            }
        }
        return blocks;
    }
    if (main.mode=='editor'){
        main.editor.mapIntoBlocks = function(map,floor,floorId){
            return mapIntoBlocks(map,core.maps,floor,floorId);
        }
    }
    // 事件处理
    content['blocks'] = mapIntoBlocks(map,this,floor,floorId);
    return content;
}

////// 数字和ID的对应关系 //////
maps.prototype.initBlock = function (x, y, id) {
    var disable=null;
    id = ""+id;
    if (id.length>2) {
        if (id.indexOf(":f")==id.length-2) {
            id = id.substring(0, id.length - 2);
            disable = true;
        }
        else if (id.indexOf(":t")==id.length-2) {
            id = id.substring(0, id.length - 2);
            disable = false;
        }
    }
    id=parseInt(id);
    var tmp = {'x': x, 'y': y, 'id': id};
    if (disable!=null) tmp.disable = disable;

    if (id==17) {
        tmp.event = {"cls": "terrains", "id": "airwall", "noPass": true};
    }
    else if (id in this.blocksInfo) tmp.event = JSON.parse(JSON.stringify(this.blocksInfo[id]));
    else {
        var tilesetOffset = core.icons.getTilesetOffset(id);
        if (tilesetOffset != null) {
            tmp.event = {"cls": "tileset", "id": "X"+id, "noPass": true};
        }
    }

    return tmp;
}

////// 添加一些信息到block上 //////
maps.prototype.addInfo = function (block) {
    if (core.isset(block.event)) {
        if (block.event.cls.indexOf("enemy")==0 && !core.isset(block.event.trigger)) {
            block.event.trigger = 'battle';
        }
        if (block.event.cls == 'items' && !core.isset(block.event.trigger)) {
            block.event.trigger = 'getItem';
        }
        if (!core.isset(block.event.noPass)) {
            if (block.event.cls.indexOf("enemy")==0 || block.event.cls.indexOf("npc")==0 || block.event.cls=='terrains' || block.event.cls=='autotile') {
                block.event.noPass = true;
            }
        }
        if (!core.isset(block.event.animate)) {
            if (block.event.cls=='enemys' || block.event.cls=='npcs') {
                block.event.animate = 2;
            }
            if (block.event.cls == 'animates' || block.event.cls == 'enemy48' || block.event.cls == 'npc48') {
                block.event.animate = 4;
            }
        }
        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 (!core.isset(event)) return;
    if (!core.isset(block.event)) { // 本身是空地？
        block.event = {'cls': 'terrains', 'id': 'none', 'noPass': false};
    }
    // event是字符串或数组？
    if (typeof event == "string") {
        event = {"data": [event]};
    }
    else if (event instanceof Array) {
        event = {"data": event};
    }
    if (!core.isset(event.data))
        event.data = [];

    // 覆盖noPass
    if (core.isset(event.noPass))
        block.event.noPass = event.noPass;

    // 覆盖enable
    if (!core.isset(block.disable) && core.isset(event.enable)) {
        block.disable=!event.enable;
    }
    // 覆盖trigger
    if (!core.isset(block.event.trigger)) {
        if (core.isset(event.trigger)) block.event.trigger=event.trigger;
        else block.event.trigger='action';
    }
    else if (core.isset(event.trigger) && event.trigger!='checkBlock') {
        block.event.trigger=event.trigger;
    }
    // 覆盖其他属性
    for (var key in event) {
        if (key!="disable" && key!="trigger" && key!="noPass" && core.isset(event[key])) {
            block.event[key]=core.clone(event[key]);
        }
    }
}

////// 向该楼层添加剧本的楼层转换事件 //////
maps.prototype.addChangeFloor = function (block, x, y, event, ground) {
    if (!core.isset(event)) return;
    this.addEvent(block, x, y, {"trigger": "changeFloor", "data": event}, ground);
}

////// 初始化所有地图 //////
maps.prototype.initMaps = function (floorIds) {
    var maps = {};
    for (var i=0;i<floorIds.length;i++) {
        var floorId = floorIds[i];
        maps[floorId] = this.loadFloor(floorId);
    }
    return maps;
}

////// 将当前地图重新变成数字，以便于存档 //////
maps.prototype.save = function(maps, floorId) {
    if (!core.isset(floorId)) {
        var map = {};
        for (var id in maps) {
            map[id] = this.save(maps, id);
            // map.push(this.save(maps, id));
        }
        return map;
    }

    var thisFloor = maps[floorId];
    var mw = core.floors[floorId].width || 13;
    var mh = core.floors[floorId].height || 13;

    var blocks = [];
    for (var x=0;x<mh;x++) {
        blocks[x]=[];
        for (var y=0;y<mw;y++) {
            blocks[x].push(0);
        }
    }
    thisFloor.blocks.forEach(function (block) {
        if (core.isset(block.disable)) {
            if (!block.disable) blocks[block.y][block.x] = block.id+":t";
            else blocks[block.y][block.x] = block.id+":f";
        }
        else blocks[block.y][block.x] = block.id;
    });
    return blocks;
}

////// 更改地图画布的尺寸
maps.prototype.resizeMap = function(floorId) {
    floorId = floorId || core.status.floorId;
    core.bigmap.width = core.floors[floorId].width || 13;
    core.bigmap.height = core.floors[floorId].height || 13;
    var cwidth = core.bigmap.width * 32;
    var cheight = core.bigmap.height * 32;
    core.bigmap.canvas.forEach(function(cn){
        core.canvas[cn].canvas.setAttribute("width",cwidth);
        core.canvas[cn].canvas.setAttribute("height",cheight);
        core.canvas[cn].canvas.style.width = cwidth*core.domStyle.scale + "px";
        core.canvas[cn].canvas.style.height = cheight*core.domStyle.scale + "px";
        if(main.mode==='editor' && editor.isMobile){
            core.canvas[cn].canvas.style.width = core.bigmap.width*32/416*96 + "vw";
            core.canvas[cn].canvas.style.height = core.bigmap.height*32/416*96 + "vw";
        }
    });
}

////// 将存档中的地图信息重新读取出来 //////
maps.prototype.load = function (data, floorId) {
    if (floorId == undefined) {
        var map = {};
        core.floorIds.forEach(function (id) {
            map[id] = core.maps.loadFloor(id, data[id]);
        })
        return map;
    }
    return this.loadFloor(floorId, data[floorId]);
}

////// 将当前地图重新变成二维数组形式 //////
maps.prototype.getMapArray = function (blockArray,width,height){

    width=width||13;
    height=height||13;

    var blocks = [];
    for (var x=0;x<height;x++) {
        blocks[x]=[];
        for (var y=0;y<width;y++) {
            blocks[x].push(0);
        }
    }
    blockArray.forEach(function (block) {
        if (!block.disable && block.x<width && block.y<height)
            blocks[block.y][block.x] = block.id;
    });
    return blocks;
}



////// 勇士能否前往某方向 //////
maps.prototype.canMoveHero = function(x,y,direction,floorId) {
    if (!core.isset(x)) x=core.getHeroLoc('x');
    if (!core.isset(y)) y=core.getHeroLoc('y');
    if (!core.isset(direction)) direction=core.getHeroLoc('direction');
    if (!core.isset(floorId)) floorId=core.status.floorId;

    // 检查当前块的cannotMove
    if (core.isset(core.floors[floorId].cannotMove)) {
        var cannotMove = core.floors[floorId].cannotMove[x+","+y];
        if (core.isset(cannotMove) && cannotMove instanceof Array && cannotMove.indexOf(direction)>=0)
            return false;
    }

    var nowBlock = core.getBlock(x,y,floorId);
    if (nowBlock!=null){
        var nowId = nowBlock.block.event.id;
        var nowIsArrow = nowId.slice(0, 5).toLowerCase() == 'arrow';
        if(nowIsArrow){
            var nowArrow = nowId.slice(5).toLowerCase();
            if (direction != nowArrow) {
                return false;
            }
        }
    }
    var scan = {
        'up': {'x': 0, 'y': -1},
        'left': {'x': -1, 'y': 0},
        'down': {'x': 0, 'y': 1},
        'right': {'x': 1, 'y': 0}
    };
    var nx = x+scan[direction].x, ny = y+scan[direction].y;
    var nextBlock = core.getBlock(nx,ny);
    if (nextBlock!=null){
        var nextId = nextBlock.block.event.id;
        // 遇到单向箭头处理
        var isArrow = nextId.slice(0, 5).toLowerCase() == 'arrow';
        if(isArrow){
            var nextArrow = nextId.slice(5).toLowerCase();
            if ( (scan[direction].x + scan[nextArrow].x) == 0 && (scan[direction].y + scan[nextArrow].y) == 0 ) {
                return false;
            }
        }
    }

    // 检查将死的领域
    if (floorId==core.status.floorId && core.status.hero.hp <= core.status.checkBlock.damage[nx+core.bigmap.width*ny]
        && !core.flags.canGoDeadZone && core.getBlock(nx, ny)==null)
        return false;

    return true;
}

////// 能否瞬间移动 //////
maps.prototype.canMoveDirectly = function (destX,destY) {

    // 不可瞬间移动请返回0
    if (!core.flags.enableMoveDirectly) return -1;

    // 中毒状态：不能
    if (core.hasFlag('poison')) return -1;

    var fromX = core.getHeroLoc('x'), fromY = core.getHeroLoc('y');
    if (fromX==destX&&fromY==destY) return 0;

    // 可以无视起点事件
    var nowBlockId = core.getBlockId(fromX, fromY);
    if ((nowBlockId!=null&&nowBlockId!='upFloor'&&nowBlockId!='downFloor'&&nowBlockId!='portal'
        &&nowBlockId!='upPortal'&&nowBlockId!='leftPortal'&&nowBlockId!='downPortal'&&nowBlockId!='rightPortal')
        ||core.status.checkBlock.damage[fromX+core.bigmap.width*fromY]>0)
        return -1;

    // BFS
    var visited=[], queue=[];
    visited[fromX+core.bigmap.width*fromY]=0;
    queue.push(fromX+core.bigmap.width*fromY);

    var directions = {
        "left": [-1,0],
        "up": [0,-1],
        "right": [1,0],
        "down": [0,1]
    }
    while (queue.length>0) {
        var now=queue.shift(), nowX=parseInt(now%core.bigmap.width), nowY=parseInt(now/core.bigmap.width);

        for (var dir in directions) {
            if (!core.canMoveHero(nowX, nowY, dir)) continue;
            var nx=nowX+directions[dir][0], ny=nowY+directions[dir][1];
            if (nx<0||nx>=core.bigmap.width||ny<0||ny>=core.bigmap.height||visited[nx+core.bigmap.width*ny]||core.getBlock(nx,ny)!=null||core.status.checkBlock.damage[nx+core.bigmap.width*ny]>0) continue;
            visited[nx+core.bigmap.width*ny]=visited[nowX+core.bigmap.width*nowY]+1;
            if (nx==destX&&ny==destY) return visited[nx+core.bigmap.width*ny];
            queue.push(nx+core.bigmap.width*ny);
        }
    }
    return -1;
}

maps.prototype.drawBlock = function (block, animate, dx, dy) {
    // none：空地
    if (block.event.id=='none') return;

    var cls = block.event.cls, height = block.event.height || 32;

    var image, x, y;

    if (cls == 'tileset') {
        var offset = core.icons.getTilesetOffset(block.event.id);
        if (offset == null) return;
        image = core.material.images.tilesets[offset.image];
        x = offset.x;
        y = offset.y;
    }
    else if (cls == 'autotile') return;
    // 空气墙的单独处理
    else if (block.id==17) {
        if (!core.isset(core.material.images.airwall)) return;
        image = core.material.images.airwall;
        x = y = 0;
    }
    else {
        image = core.material.images[cls];
        x = (animate||0)%(block.event.animate||1);
        y = core.material.icons[cls][block.event.id];
    }
    dx = dx || 0;
    dy = dy || 0;

    core.canvas.event.clearRect(block.x * 32 + dx, block.y * 32 + dy, 32, 32);
    core.canvas.event.drawImage(image, x * 32, y * height + height-32, 32, 32, block.x * 32 + dx, block.y * 32 + dy, 32, 32);
    if (height>32) {
        core.canvas.event2.clearRect(block.x * 32 + dx, block.y * 32 + 32 - height + dy, 32, height-32)
        core.canvas.event2.drawImage(image, x * 32, y * height, 32, height-32, block.x * 32 + dx, block.y*32 + 32 - height + dy, 32, height-32);
    }
}

////// 背景/前景图块的绘制 //////
maps.prototype.drawBgFgMap = function (floorId, canvas, name) {
    var width = core.floors[floorId].width || 13;
    var height = core.floors[floorId].height || 13;

    var groundId = core.floors[floorId].defaultGround || "ground";
    var blockIcon = core.material.icons.terrains[groundId];
    var blockImage = core.material.images.terrains;

    var getMapArray = function (name) {
        var arr = core.clone(core.floors[floorId][name+"map"] || []);
        if(main.mode=='editor')arr = core.clone(editor[name+"map"])||arr;
        for (var x = 0; x < width; x++) {
            for (var y = 0; y < height; y++) {
                arr[y] = arr[y] || [];
                if (core.hasFlag(name + "_" + floorId + "_" + x + "_" + y)) arr[y][x] = 0;
                else arr[y][x] = core.getFlag(name + "v_" + floorId + "_" + x + "_" + y, arr[y][x] || 0);
                if(main.mode=='editor')arr[y][x]= arr[y][x].idnum || arr[y][x] || 0;
            }
        }
        return arr;
    }
    var arr = getMapArray(name);
    for (var x = 0; x < width; x++) {
        for (var y = 0; y < height; y++) {
            if (name=='bg')
                canvas.drawImage(blockImage, 0, blockIcon * 32, 32, 32, x * 32, y * 32, 32, 32);
            if (arr[y][x]>0) {
                var block = core.maps.initBlock(x, y, arr[y][x]);
                if (core.isset(block.event)) {
                    var id = block.event.id, cls = block.event.cls;
                    if (cls == 'autotile')
                        core.drawAutotile(canvas, arr, block, 32, 0, 0);
                    else if (cls == 'tileset') {
                        var offset = core.icons.getTilesetOffset(id);
                        if (offset!=null) {
                            canvas.drawImage(core.material.images.tilesets[offset.image], 32*offset.x, 32*offset.y, 32, 32, 32*x, 32*y, 32, 32);
                        }
                    }
                    else if (arr[y][x]==17) {
                        if (core.isset(core.material.images.airwall)) {
                            canvas.drawImage(core.material.images.airwall, 32*x, 32*y);
                        }
                    }
                    else
                        canvas.drawImage(core.material.images[cls], 0, core.material.icons[cls][id] * 32, 32, 32, x * 32, y * 32, 32, 32);
                }
            }
        }
    }

}

////// 绘制某张地图 //////
maps.prototype.drawMap = function (mapName, callback) {
    mapName = mapName || core.status.floorId;
    core.clearMap('all');
    core.removeGlobalAnimate(null, null, true);
    var drawBg = function(){

        core.maps.drawBgFgMap(mapName, core.canvas.bg, "bg");
        core.maps.drawBgFgMap(mapName, core.canvas.fg, "fg");

        var images = [];
        if (core.isset(core.floors[mapName].images)) {
            images = core.floors[mapName].images;
            if (typeof images == 'string') {
                images = [[0, 0, images]];
            }
        }
        images.forEach(function (t) {
            var dx=parseInt(t[0]), dy=parseInt(t[1]), p=t[2];
            if (core.isset(dx) && core.isset(dy) &&
                !core.hasFlag("floorimg_"+mapName+"_"+dx+"_"+dy) &&
                core.isset(core.material.images.images[p])) {
                var image = core.material.images.images[p];
                if (!t[3]) {
                    if (/.*\.gif/i.test(p) && main.mode=='play') {
                        core.dom.gif.innerHTML = "";
                        var gif = new Image();
                        gif.src = core.material.images.images[p].src;
                        gif.style.position = 'absolute';
                        gif.style.left = (32*dx*core.domStyle.scale)+"px";
                        gif.style.top = (32*dy*core.domStyle.scale)+"px";
                        gif.style.width = core.material.images.images[p].width*core.domStyle.scale+"px";
                        gif.style.height = core.material.images.images[p].height*core.domStyle.scale+"px";
                        core.dom.gif.appendChild(gif);
                    }
                    else {
                        core.canvas.bg.drawImage(image, 32*dx, 32*dy, image.width, image.height);
                    }
                }
                else if (t[3]==1)
                    core.canvas.fg.drawImage(image, 32*dx, 32*dy, image.width, image.height);
                else if (t[3]==2) {
                    core.canvas.fg.drawImage(image, 0, 0, image.width, image.height-32,
                        32*dx, 32*dy, image.width, image.height-32);
                    core.canvas.bg.drawImage(image, 0, image.height-32, image.width, 32,
                        32*dx, 32*dy + image.height - 32, image.width, 32);
                }
            }
        })

    }
    if (main.mode=='editor'){
        // just do not run drawBg

        // //---move to main.editor.updateMap
        // main.editor.drawMapBg = function(){
        //     core.clearMap('bg');
        //     core.clearMap('fg');
        //     drawBg();
        // }
    } else {
        drawBg();
    }

    core.status.floorId = mapName;
    core.status.thisMap = core.status.maps[mapName];
    var drawEvent = function(){
        var mapData = core.status.maps[core.status.floorId];
        var mapBlocks = mapData.blocks;

        var mapArray = core.maps.getMapArray(mapBlocks,core.bigmap.width,core.bigmap.height);
        for (var b = 0; b < mapBlocks.length; b++) {
            // 事件启用
            var block = mapBlocks[b];
            if (core.isset(block.event) && !block.disable) {
                if (block.event.cls == 'autotile') {
                    core.drawAutotile(core.canvas.event, mapArray, block, 32, 0, 0);
                }
                else {
                    core.drawBlock(block);
                    core.addGlobalAnimate(block);
                }
            }
        }
    }

    if (main.mode=='editor'){
        main.editor.updateMap = function(){
            core.removeGlobalAnimate(null, null, true);
            core.clearMap('bg');
            core.clearMap('event');
            core.clearMap('event2');
            core.clearMap('fg');
            drawBg();
            drawEvent();
            core.setGlobalAnimate(core.values.animateSpeed);
        }
    } else {
        drawEvent();
        core.setGlobalAnimate(core.values.animateSpeed);
        core.drawHero();
        core.updateStatusBar();
    }
    if (core.isset(callback))
        callback();
}

////// 绘制Autotile //////
maps.prototype.drawAutotile = function(ctx, mapArr, block, size, left, top){
    var indexArrs = [ //16种组合的图块索引数组; // 将autotile分割成48块16*16的小块; 数组索引即对应各个小块
        //                                     +----+----+----+----+----+----+
        [10,  9,  4, 3 ],  //0   bin:0000      | 1  | 2  | 3  | 4  | 5  | 6  |
        [10,  9,  4, 13],  //1   bin:0001      +----+----+----+----+----+----+
        [10,  9, 18, 3 ],  //2   bin:0010      | 7  | 8  | 9  | 10 | 11 | 12 |
        [10,  9, 16, 15],  //3   bin:0011      +----+----+----+----+----+----+
        [10, 43,  4, 3 ],  //4   bin:0100      | 13 | 14 | 15 | 16 | 17 | 18 |
        [10, 31,  4, 25],  //5   bin:0101      +----+----+----+----+----+----+
        [10,  7,  2, 3 ],  //6   bin:0110      | 19 | 20 | 21 | 22 | 23 | 24 |
        [10, 31, 16, 5 ],  //7   bin:0111      +----+----+----+----+----+----+
        [48,  9,  4, 3 ],  //8   bin:1000      | 25 | 26 | 27 | 28 | 29 | 30 |
        [ 8,  9,  4, 1 ],  //9   bin:1001      +----+----+----+----+----+----+
        [36,  9, 30, 3 ],  //10  bin:1010      | 31 | 32 | 33 | 34 | 35 | 36 |
        [36,  9,  6, 15],  //11  bin:1011      +----+----+----+----+----+----+
        [46, 45,  4, 3 ],  //12  bin:1100      | 37 | 38 | 39 | 40 | 41 | 42 |
        [46, 11,  4, 25],  //13  bin:1101      +----+----+----+----+----+----+
        [12, 45, 30, 3 ],  //14  bin:1110      | 43 | 44 | 45 | 46 | 47 | 48 |
        [34, 33, 28, 27]   //15  bin:1111      +----+----+----+----+----+----+
    ];

    var drawBlockByIndex = function(ctx, dx, dy, autotileImg, index, size){ //index为autotile的图块索引1-48
        var sx = 16*((index-1)%6), sy = 16*(~~((index-1)/6));
        ctx.drawImage(autotileImg, sx, sy, 16, 16, dx, dy, size/2, size/2);
    }
    var getAutotileAroundId = function(currId, x, y) {
        if(x<0 || y<0 || x>=mapArr[0].length || y>=mapArr.length) return 1;
        else return mapArr[y][x]==currId ? 1:0;
    }
    var checkAround = function(x, y){ // 得到周围四个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 = getAutotileAroundId(currId, x+offsetx+mx-1, y+offsety+my-1);
                bsum += b*(Math.pow(2, 3-j));
            }
            pointBlock.push(bsum);
        }
        return pointBlock;
    }
    var getAutotileIndexs = function(x, y){
        var indexArr = [];
        var pointBlocks = checkAround(x, y);
        for(var i=0; i<4; i++){
            var arr = indexArrs[pointBlocks[i]]
            indexArr.push(arr[3-i]);
        }
        return indexArr;
    }
    // 开始绘制autotile
    var x = block.x, y = block.y;
    var pieceIndexs = getAutotileIndexs(x, y);

    //修正四个边角的固定搭配
    if(pieceIndexs[0] == 13){
        if(pieceIndexs[1] == 16) pieceIndexs[1] = 14;
        if(pieceIndexs[2] == 31) pieceIndexs[2] = 19;
    }
    if(pieceIndexs[1] == 18){
        if(pieceIndexs[0] == 15) pieceIndexs[0] = 17;
        if(pieceIndexs[3] == 36) pieceIndexs[3] = 24;
    }
    if(pieceIndexs[2] == 43){
        if(pieceIndexs[0] == 25) pieceIndexs[0] = 37;
        if(pieceIndexs[3] == 46) pieceIndexs[3] = 44;
    }
    if(pieceIndexs[3] == 48){
        if(pieceIndexs[1] == 30) pieceIndexs[1] = 42;
        if(pieceIndexs[2] == 45) pieceIndexs[2] = 47;
    }
    for(var i=0; i<4; i++){
        var index = pieceIndexs[i];
        var dx = x*size + size/2*(i%2), dy = y*size + size/2*(~~(i/2));
        drawBlockByIndex(ctx, dx+left, dy+top, core.material.images['autotile'][block.event.id], index, size);
    }
}

////// 某个点是否不可通行 //////
maps.prototype.noPassExists = function (x, y, floorId) {
    var block = core.getBlock(x,y,floorId);
    if (block==null) return false;
    return core.isset(block.block.event.noPass) && block.block.event.noPass;
}

////// 某个点是否在区域内且不可通行 //////
maps.prototype.noPass = function (x, y) {
    return x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height || this.noPassExists(x,y);
}

////// 某个点是否存在NPC //////
maps.prototype.npcExists = function (x, y, floorId) {
    var block = this.getBlock(x,y,floorId);
    if (block==null) return false;
    return block.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.block.event.cls=='terrains' && (core.isset(id)?block.block.event.id==id:true);
}

////// 某个点是否存在楼梯 //////
maps.prototype.stairExists = function (x, y, floorId) {
    var block = this.getBlock(x,y,floorId);
    if (block==null) return false;
    return block.block.event.cls=='terrains' && (block.block.event.id=='upFloor' || block.block.event.id=='downFloor');
}

////// 当前位置是否在楼梯边 //////
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.block.event.cls.indexOf('enemy')==0 && (core.isset(id)?block.block.event.id==id:true);
}

////// 获得某个点的block //////
maps.prototype.getBlock = function (x, y, floorId, showDisable) {
    if (!core.isset(floorId)) floorId=core.status.floorId;
    var blocks = core.status.maps[floorId].blocks;
    for (var n=0;n<blocks.length;n++) {
        if (blocks[n].x==x && blocks[n].y==y && core.isset(blocks[n].event)) {
            if (!showDisable && blocks[n].disable) return null;
            return {"index": n, "block": blocks[n]};
        }
    }
    return null;
}

////// 获得某个点的blockId //////
maps.prototype.getBlockId = function (x, y, floorId, showDisable) {
    var block = core.getBlock(x, y, floorId, showDisable);
    if (block == null) return null;
    if (core.isset(block.block.event)) return block.block.event.id;
    return null;
}

////// 获得某个点的blockCls //////
maps.prototype.getBlockCls = function (x, y, floorId, showDisable) {
    var block = core.getBlock(x, y, floorId, showDisable);
    if (block == null) return null;
    if (core.isset(block.block.event)) return block.block.event.cls;
    return null;
}

////// 显示移动某块的动画，达到{“type”:”move”}的效果 //////
maps.prototype.moveBlock = function(x,y,steps,time,keep,callback) {
    time = time || 500;

    core.clearMap('route');

    var block = core.getBlock(x,y);
    if (block==null) {// 不存在
        if (core.isset(callback)) callback();
        return;
    }
    var id = block.block.id;

    core.status.replay.animate=true;

    // 需要删除该块
    core.removeBlock(x,y);

    core.clearMap('ui');
    core.setAlpha('ui', 1.0);

    block=block.block;

    var image, bx, by, height = block.event.height || 32;
    if (block.event.cls == 'tileset') {
        var offset = core.icons.getTilesetOffset(block.event.id);
        if (offset==null) {
            if (core.isset(callback)) callback();
            return;
        }
        bx = offset.x;
        by = offset.y;
        image = core.material.images.tilesets[offset.image];
    }
    // 不支持autotile
    else if (block.event.cls == 'autotile') {
        if (core.isset(callback)) callback();
        return;
    }
    // 空气墙；忽略事件
    else if (block.id==17) {
        if (core.isset(callback)) callback();
        return;
    }
    else {
        image = core.material.images[block.event.cls];
        bx = 0;
        by = core.material.icons[block.event.cls][block.event.id];
    }

    var opacityVal = 1;
    core.setOpacity('route', opacityVal);
    core.canvas.route.drawImage(image, bx * 32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height);

    // 要运行的轨迹：将steps展开
    var moveSteps=[];
    steps.forEach(function (e) {
        if (typeof e=="string") {
            moveSteps.push(e);
        }
        else {
            if (!core.isset(e.value)) {
                moveSteps.push(e.direction)
            }
            else {
                for (var i=0;i<e.value;i++) {
                    moveSteps.push(e.direction);
                }
            }
        }
    });

    var nowX=32*x, nowY=32*y, step=0;
    var scan = {
        'up': {'x': 0, 'y': -1},
        'left': {'x': -1, 'y': 0},
        'down': {'x': 0, 'y': 1},
        'right': {'x': 1, 'y': 0}
    };

    var animateValue = block.event.animate || 1;
    var animateCurrent = 0;
    var animateTime = 0;

    var animate=window.setInterval(function() {

        animateTime += time / 16 / core.status.replay.speed;
        if (animateTime >= core.values.animateSpeed) {
            animateCurrent++;
            animateTime = 0;
            if (animateCurrent>=animateValue) animateCurrent=0;
        }
        if (block.event.cls=='tileset') {
            animateCurrent = bx;
        }

        // 已经移动完毕，消失
        if (moveSteps.length==0) {
            if (keep) opacityVal=0;
            else opacityVal -= 0.06;
            core.setOpacity('route', opacityVal);
            core.clearMap('route', nowX, nowY-height+32, 32, height);
            core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height);
            if (opacityVal<=0) {
                clearInterval(animate);
                core.clearMap('route');
                core.setOpacity('route', 1);
                // 不消失
                if (keep) {
                    core.setBlock(id, nowX/32, nowY/32);
                    core.showBlock(nowX/32, nowY/32);
                }
                core.status.replay.animate=false;
                if (core.isset(callback)) callback();
            }
        }
        else {
            // 移动中
            step++;
            nowX+=scan[moveSteps[0]].x*2;
            nowY+=scan[moveSteps[0]].y*2;
            core.clearMap('route', nowX-32, nowY-32, 96, 96);
            // 绘制
            core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, nowX, nowY-height+32, 32, height);
            if (step==16) {
                // 该移动完毕，继续
                step=0;
                moveSteps.shift();
            }
        }
    }, time / 16 / core.status.replay.speed);
}

////// 显示跳跃某块的动画，达到{"type":"jump"}的效果 //////
maps.prototype.jumpBlock = function(sx,sy,ex,ey,time,keep,callback) {
    time = time || 500;
    core.clearMap('route');
    var block = core.getBlock(sx,sy);
    if (block==null) {
        if (core.isset(callback)) callback();
        return;
    }
    var id = block.block.id;

    core.status.replay.animate=true;

    // 需要删除该块
    core.removeBlock(sx,sy);
    core.clearMap('ui');
    core.setAlpha('ui', 1.0);

    block=block.block;
    var image, bx, by, height = block.event.height || 32;
    if (block.event.cls == 'tileset') {
        var offset = core.icons.getTilesetOffset(block.event.id);
        if (offset==null) {
            if (core.isset(callback)) callback();
            return;
        }
        bx = offset.x;
        by = offset.y;
        image = core.material.images.tilesets[offset.image];
    }
    // 不支持autotile
    else if (block.event.cls == 'autotile') {
        if (core.isset(callback)) callback();
        return;
    }
    // 空气墙；忽略事件
    else if (block.id==17) {
        if (core.isset(callback)) callback();
        return;
    }
    else {
        image = core.material.images[block.event.cls];
        bx = 0;
        by = core.material.icons[block.event.cls][block.event.id];
    }

    var opacityVal = 1;
    core.setOpacity('route', opacityVal);
    core.canvas.route.drawImage(image, bx*32, by * height, 32, height, block.x * 32, block.y * 32 +32 - height, 32, height);

    core.playSound('jump.mp3');

    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;
    var currx = sx, curry = sy;

    var drawX = function() {
        return currx * 32;
    }

    var drawY = function() {
        var ret = curry * 32;
        if(jump_count >= jump_peak){
            var n = jump_count - jump_peak;
        }else{
            var n = jump_peak - jump_count;
        }
        return ret - (jump_peak * jump_peak - n * n) / 2;
    }

    var updateJump = function() {
        jump_count--;
        currx = (currx * jump_count + ex) / (jump_count + 1.0);
        curry = (curry * jump_count + ey) / (jump_count + 1.0);
    }

    var animateValue = block.event.animate || 1;
    var animateCurrent = 0;
    var animateTime = 0;
    var animate=window.setInterval(function() {

        animateTime += time / 16 / core.status.replay.speed;
        if (animateTime >= core.values.animateSpeed) {
            animateCurrent++;
            animateTime = 0;
            if (animateCurrent >= animateValue) animateCurrent = 0;
        }
        if (block.event.cls=='tileset') {
            animateCurrent = bx;
        }

        if (jump_count>0) {
            core.clearMap('route', drawX(), drawY()-height+32, 32, height);
            updateJump();
            core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height);
        }
        else {
            if (keep) opacityVal=0;
            else opacityVal -= 0.06;
            core.setOpacity('route', opacityVal);
            core.clearMap('route', drawX(), drawY()-height+32, 32, height);
            core.canvas.route.drawImage(image, animateCurrent * 32, by * height, 32, height, drawX(), drawY()-height+32, 32, height);
            if (opacityVal<=0) {
                clearInterval(animate);
                core.clearMap('route');
                core.setOpacity('route', 1);
                if (keep) {
                    core.setBlock(id, ex, ey);
                    core.showBlock(ex, ey);
                }
                core.status.replay.animate=false;
                if (core.isset(callback)) callback();
            }
        }

    }, time / 16 / core.status.replay.speed);
}

////// 显示/隐藏某个块时的动画效果 //////
maps.prototype.animateBlock = function (loc,type,time,callback) {
    if (type!='hide') type='show';

    core.clearMap('route');

    if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
        loc = [loc];

    var list = [];
    loc.forEach(function (t) {
        var block = core.getBlock(t[0],t[1],null,true);
        if (block==null) return;
        block=block.block;
        var image, bx, by, height = block.event.height || 32;
        if (block.event.cls == 'tileset') {
            var offset = core.icons.getTilesetOffset(block.event.id);
            if (offset==null) {
                if (core.isset(callback)) callback();
                return;
            }
            bx = offset.x;
            by = offset.y;
            image = core.material.images.tilesets[offset.image];
        }
        // 不支持autotile
        else if (block.event.cls == 'autotile') {
            return;
        }
        // 空气墙，忽略事件
        else if (block.id==17) return;
        else {
            image = core.material.images[block.event.cls];
            bx = 0;
            by = core.material.icons[block.event.cls][block.event.id];
        }
        list.push({
            'x': t[0], 'y': t[1], 'height': height,
            'bx': bx, 'by': by, 'image': image
        })
    })

    if (list.length==0) {
        if (core.isset(callback)) callback();
        return;
    }

    core.status.replay.animate=true;
    var draw = function () {
        list.forEach(function (t) {
            core.canvas.route.drawImage(t.image, t.bx*32, t.by*t.height, 32, t.height, t.x*32, t.y*32+32-t.height, 32, t.height);
        })
    }

    var opacityVal = 0;
    if (type=='hide') opacityVal=1;

    core.setOpacity('route', opacityVal);
    draw();

    var animate = window.setInterval(function () {
        if (type=='show') opacityVal += 0.1;
        else opacityVal -= 0.1;
        core.setOpacity('route', opacityVal);
        if (opacityVal >=1 || opacityVal<=0) {
            clearInterval(animate);
            core.clearMap('route');
            core.setOpacity('route', 1);
            core.status.replay.animate=false;
            if (core.isset(callback)) callback();
        }
    }, time / 10 / core.status.replay.speed);
}

////// 将某个块从禁用变成启用状态 //////
maps.prototype.showBlock = function(x, y, floodId) {
    floodId = floodId || core.status.floorId;
    var block = core.getBlock(x,y,floodId,true);
    if (block==null) return; // 不存在
    block=block.block;
    // 本身是禁用事件，启用之
    if (block.disable) {
        block.disable = false;
        // 在本层，添加动画
        if (floodId == core.status.floorId && core.isset(block.event)) {
            core.drawBlock(block);
            core.addGlobalAnimate(block);
            core.syncGlobalAnimate();
        }
        core.updateStatusBar();
    }
}

////// 只隐藏但不删除某块 //////
maps.prototype.hideBlock = function (x, y, floorId) {
    floorId = floorId || core.status.floorId;

    var block = core.getBlock(x,y,floorId,true);
    if (block==null) return; // 不存在

    // 删除动画，清除地图
    if (floorId==core.status.floorId) {
        core.removeGlobalAnimate(x, y);
        core.canvas.event.clearRect(x * 32, y * 32, 32, 32);
        var height = 32;
        if (core.isset(block.block.event)) height=block.block.event.height||32;
        if (height>32)
            core.canvas.event2.clearRect(x * 32, y * 32 +32-height, 32, height-32);
    }

    block.disable = true;
    core.updateStatusBar();
}

////// 将某个块从启用变成禁用状态 //////
maps.prototype.removeBlock = function (x, y, floorId) {
    floorId = floorId || core.status.floorId;

    var block = core.getBlock(x,y,floorId,true);
    if (block==null) return; // 不存在

    var index=block.index;

    // 删除动画，清除地图
    if (floorId==core.status.floorId) {
        core.removeGlobalAnimate(x, y);
        core.canvas.event.clearRect(x * 32, y * 32, 32, 32);
        var height = 32;
        if (core.isset(block.block.event)) height=block.block.event.height||32;
        if (height>32)
            core.canvas.event2.clearRect(x * 32, y * 32 +32-height, 32, height-32);
    }

    // 删除Index
    core.removeBlockById(index, floorId);
    core.updateStatusBar();
}

////// 根据block的索引删除该块 //////
maps.prototype.removeBlockById = function (index, floorId) {

    var blocks = core.status.maps[floorId].blocks, block = blocks[index];
    var x=block.x, y=block.y;

    // 检查该点是否存在事件
    var event = core.floors[floorId].events[x+","+y];
    if (!core.isset(event))
        event = core.floors[floorId].changeFloor[x+","+y];

    // 检查是否存在重生
    var isReborn = false;
    if (core.isset(block.event) && block.event.cls.indexOf('enemy')==0
        && core.enemys.hasSpecial(core.material.enemys[block.event.id].special, 23))
        isReborn = true;

    // 不存在事件，直接删除
    if (!isReborn && !core.isset(event)) {
        blocks.splice(index,1);
        return;
    }
    block.disable = true;
}

////// 一次性删除多个block //////
maps.prototype.removeBlockByIds = function (floorId, ids) {
    ids.sort(function (a,b) {return b-a}).forEach(function (id) {
        core.removeBlockById(id, floorId);
    });
}

////// 改变图块 //////
maps.prototype.setBlock = function (number, x, y, floorId) {
    floorId = floorId || core.status.floorId;
    if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return;
    if (x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height) return;

    var originBlock=core.getBlock(x,y,floorId,true);
    var block = core.maps.initBlock(x,y,number);
    core.maps.addInfo(block);
    core.maps.addEvent(block,x,y,core.floors[floorId].events[x+","+y]);
    core.maps.addChangeFloor(block,x,y,core.floors[floorId].changeFloor[x+","+y]);
    if (core.isset(block.event)) {
        if (originBlock==null) {
            core.status.maps[floorId].blocks.push(block);
        }
        else {
            originBlock.block.id = number;
            originBlock.block.event = block.event;
        }
        if (floorId==core.status.floorId) {
            core.drawMap(floorId);
        }
    }
}

////// 改变图层块 //////
maps.prototype.setBgFgBlock = function (name, number, x, y, floorId) {
    floorId = floorId || core.status.floorId;
    if (!core.isset(number) || !core.isset(x) || !core.isset(y)) return;
    if (x<0 || x>=core.bigmap.width || y<0 || y>=core.bigmap.height) return;
    if (name!='bg' && name!='fg') return;

    core.setFlag(name+"v_"+floorId+"_"+x+"_"+y, number);
    if (floorId == core.status.floorId)
        core.drawMap(floorId);
}

////// 添加一个全局动画 //////
maps.prototype.addGlobalAnimate = function (b) {
    if (main.mode=='editor' && main.editor.disableGlobalAnimate) return;
    if (!core.isset(b.event) || !core.isset(b.event.animate) || b.event.animate==1) return;

    var block = core.clone(b);
    block.status = 0;

    core.status.globalAnimateObjs.push(block);

}

////// 删除一个或所有全局动画 //////
maps.prototype.removeGlobalAnimate = function (x, y, all) {
    if (main.mode=='editor' && main.editor.disableGlobalAnimate) return;

    if (all) {
        core.status.globalAnimateObjs = [];
        return;
    }

    for (var t = 0; t < core.status.globalAnimateObjs.length; t++) {
        if (core.status.globalAnimateObjs[t].x == x && core.status.globalAnimateObjs[t].y == y) {
            core.status.globalAnimateObjs.splice(t, 1);
            return;
        }
    }
}

////// 设置全局动画的显示效果 //////
maps.prototype.setGlobalAnimate = function (speed) {
    if (main.mode=='editor' && main.editor.disableGlobalAnimate) return;
    core.syncGlobalAnimate();
    core.animateFrame.speed = speed;
    core.animateFrame.globalAnimate = true;
}

////// 同步所有的全局动画效果 //////
maps.prototype.syncGlobalAnimate = function () {
    core.status.globalAnimateObjs.forEach(function (t) {
        t.status=0;
    })
}

////// 绘制UI层的box动画 //////
maps.prototype.drawBoxAnimate = function () {
    for (var a = 0; a < core.status.boxAnimateObjs.length; a++) {
        var obj = core.status.boxAnimateObjs[a];
        obj.status = ((obj.status||0)+1)%obj.animate;
        core.clearMap('ui', obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight);
        core.fillRect('ui', obj.bgx, obj.bgy, obj.bgWidth, obj.bgHeight, core.animateFrame.background);
        core.canvas.ui.drawImage(obj.image, obj.status * 32, obj.pos,
            32, obj.height, obj.x, obj.y, 32, obj.height);
    }
}

////// 绘制动画的某一帧 //////
maps.prototype.drawAnimateFrame = function (animate, centerX, centerY, index) {
    var frame = animate.frames[index];
    var ratio = animate.ratio;
    frame.forEach(function (t) {
        var image = animate.images[t.index];
        if (!core.isset(image)) return;
        var realWidth = image.width * ratio * t.zoom / 100;
        var realHeight = image.height * ratio * t.zoom / 100;
        core.setAlpha('animate', t.opacity / 255);

        var cx = centerX+t.x, cy=centerY+t.y;

        if (!t.mirror && !t.angle) {
            core.canvas.animate.drawImage(image, cx-realWidth/2 - core.bigmap.offsetX, cy-realHeight/2 - core.bigmap.offsetY, realWidth, realHeight);
        }
        else {
            core.saveCanvas('animate');
            core.canvas.animate.translate(cx,cy);
            if (t.angle)
                core.canvas.animate.rotate(-t.angle*Math.PI/180);
            if (t.mirror)
                core.canvas.animate.scale(-1,1);
            core.canvas.animate.drawImage(image, -realWidth/2 - core.bigmap.offsetX, -realHeight/2 - core.bigmap.offsetY, realWidth, realHeight);
            core.loadCanvas('animate');
        }
    })
}

////// 绘制动画 //////
maps.prototype.drawAnimate = function (name, x, y, callback) {

    // 正在播放录像：不显示动画
    if (core.isset(core.status.replay) && core.status.replay.replaying) {
        if (core.isset(callback)) callback();
        return;
    }

    // 检测动画是否存在
    if (!core.isset(core.material.animates[name]) || !core.isset(x) || !core.isset(y)) {
        if (core.isset(callback)) callback();
        return;
    }

    clearInterval(core.interval.animateInterval);

    // 开始绘制
    var animate = core.material.animates[name], centerX = 32*x+16, centerY = 32*y+16;
    // 播放音效
    core.playSound(animate.se);

    // 异步绘制：使用requestAnimationFrame进行绘制
    if (!core.isset(callback)) {
        core.status.animateObjs.push({"animate": animate, "centerX": centerX, "centerY": centerY, "index": 0});
        return;
    }

    var index=0;
    core.clearMap('animate');
    core.maps.drawAnimateFrame(animate, centerX, centerY, index++);

    core.interval.animateInterval = setInterval(function (t) {
        if (index == animate.frames.length) {
            clearInterval(core.interval.animateInterval);
            core.clearMap('animate');
            core.setAlpha('animate', 1);
            if (core.isset(callback)) callback();
            return;
        }
        core.clearMap('animate');
        core.maps.drawAnimateFrame(animate, centerX, centerY, index++);
    }, 50);
}

maps.prototype.setFloorImage = 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 (loc.length==0) return;
    loc.forEach(function (t) {
        var x=t[0], y=t[1];
        var flag = "floorimg_"+floorId+"_"+x+"_"+y;
        core.setFlag(flag, type=='show'?false:true);
    })

    if (floorId==core.status.floorId) {
        core.drawMap(floorId, callback);
    }
    else {
        if (core.isset(callback)) callback();
    }
}

maps.prototype.setBgFgMap = function (type, name, loc, floorId, callback) {
    if (type!='show') type='hide';
    if (name!='fg') name='bg';
    if (typeof loc[0] == 'number' && typeof loc[1] == 'number')
        loc = [loc];
    floorId = floorId||core.status.floorId;

    if (loc.length==0) return;
    loc.forEach(function (t) {
        var x=t[0], y=t[1];
        var flag = name+"_"+floorId+"_"+x+"_"+y;
        core.setFlag(flag, type=='show'?false:true);
    })

    if (floorId==core.status.floorId) {
        core.drawMap(floorId, callback);
    }
    else {
        if (core.isset(callback)) callback();
    }
}

maps.prototype.resetMap = function(floorId) {
    var floorId = floorId||core.status.floorId;
    core.status.maps[floorId] = this.loadFloor(floorId);
    if (floorId==core.status.floorId) {
        this.drawMap(floorId, function () {
            core.drawTip("地图重置成功");
        })
    }
    else {
        core.drawTip(floorId+"地图重置成功");
    }
}