tianta/libs/maps.js

3113 lines
121 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"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 () {
return [
"firstArrive", "eachArrive", "blocks", "parallelDo", "map", "bgmap", "fgmap",
"events", "changeFloor", "beforeBattle", "afterBattle", "afterGetItem", "afterOpenDoor",
"cannotMove", "cannotMoveIn"
];
}
/// 根据需求解析出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 = 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 parseInt(number) || 0;
}
// tilesets
if (/^X\d+$/.test(id)) {
if (core.icons.getTilesetOffset(id)) return parseInt(id.substring(1));
}
// 特殊ID
if (id == 'none') return 0;
if (id == 'airwall') return 17;
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.indexOf(cn) >= 0)
core.maps._setHDCanvasSize(core.canvas[cn], width, height);
else {
core.canvas[cn].canvas.width = width;
core.canvas[cn].canvas.height = height;
}
core.canvas[cn].canvas.style.width = width * core.domStyle.scale + "px";
core.canvas[cn].canvas.style.height = height * core.domStyle.scale + "px";
core.canvas[cn].translate(core.bigmap.v2 ? 32 : 0, core.bigmap.v2 ? 32 : 0);
if (main.mode === 'editor' && editor.isMobile) {
core.canvas[cn].canvas.style.width = width / core._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;
if (!noCache && core.status[name + "maps"][floorId])
return core.status[name + "maps"][floorId];
var arr = (main.mode == 'editor' && !(window.editor && editor.uievent && editor.uievent.isOpen))
? core.cloneArray(editor[name + 'map']) : null;
if (arr == null)
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);
}
(core.getFlag('__' + name + 'v__', {})[floorId] || []).forEach(function (one) {
arr[one[1]][one[0]] = one[2] || 0;
});
(core.getFlag('__' + name + 'd__', {})[floorId] || []).forEach(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++) {
arr[y][x] = arr[y][x].idnum || arr[y][x] || 0;
}
}
}
if (core.status[name + "maps"])
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;
var startX = v2 ? Math.max(0, core.bigmap.posX - core.bigmap.extend) : 0;
var endX = v2 ? Math.min(width, core.bigmap.posX + core._WIDTH_ + core.bigmap.extend + 1) : width;
var startY = v2 ? Math.max(0, core.bigmap.posY - core.bigmap.extend) : 0;
var endY = v2 ? Math.min(height, core.bigmap.posY + core._HEIGHT_ + 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) {
return {
bgArray: this.getBgMapArray(floorId),
fgArray: this.getFgMapArray(floorId),
eventArray: this.getMapArray(floorId)
};
}
////// 勇士能否前往某方向 //////
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);
// 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) <= ((core.status.checkBlock.damage || {})[nx + "," + ny] || 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.checkBlock.damage[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;
}
// 是否存在阻激夹域伤害
if (core.status.checkBlock.damage[index]) return false;
if (core.status.checkBlock.repulse[index]) return false;
// 是否存在捕捉
if (core.status.checkBlock.ambush[index]) 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();
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 (id == "light") deepAdd += 100;
// 绕过路障
if (id.endsWith("Net") && !core.hasFlag(id.substring(0, id.length - 3))) deepAdd += 100;
// 绕过血瓶和绿宝石
if (core.hasFlag('__potionNoRouting__') && (id.endsWith("Potion") || id == 'greenGem')) deepAdd += 100;
// 绕过传送点
// if (block.event.trigger == 'changeFloor') deepAdd+=10;
}
// 绕过存在伤害的地方
deepAdd += (core.status.checkBlock.damage[x + "," + y] || 0) * 100;
// 绕过捕捉
if (core.status.checkBlock.ambush[x + "," + y]) deepAdd += 1000;
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];
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 () {
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) {
config.ctx = cacheCtx;
core.maps._drawBg_drawBackground(floorId, config);
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制背景图块;后绘制的覆盖先绘制的。
core.maps._drawFloorImages(floorId, config.ctx, 'bg', null, null, config.onMap);
core.maps._drawBgFgMap(floorId, 'bg', config);
if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
config.ctx = toDrawCtx;
}
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) {
config.ctx = cacheCtx;
// ------ 调整这两行的顺序来控制是先绘制贴图还是先绘制前景图块;后绘制的覆盖先绘制的。
core.maps._drawFloorImages(floorId, config.ctx, 'fg', null, null, config.onMap);
core.maps._drawBgFgMap(floorId, 'fg', config);
if (config.onMap) core.drawImage(toDrawCtx, cacheCtx.canvas, core.bigmap.v2 ? -32 : 0, core.bigmap.v2 ? -32 : 0);
config.ctx = toDrawCtx;
}
////// 实际的背景/前景图块的绘制 //////
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) {
core.dom.gif.innerHTML = "";
var gif = new Image();
gif.src = image.src;
gif.style.position = 'absolute';
gif.style.left = (dx * core.domStyle.scale) + "px";
gif.style.top = (dy * core.domStyle.scale) + "px";
gif.style.width = image.width * core.domStyle.scale + "px";
gif.style.height = image.height * core.domStyle.scale + "px";
core.dom.gif.appendChild(gif);
return;
}
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 %= parseInt(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 + parseInt(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 %= parseInt(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;
cv.clearRect(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为目标floorIdblocks为地图的图块可为null使用floorId对应默认的
// options为绘制选项可为null包括
// heroLoc: 勇士位置heroIcon勇士图标默认当前勇士damage是否绘制显伤flags当前的flags存读档时使用
// ctx要绘制到的画布x,y起点横纵坐标默认0size大小默认416/480
// all是否绘制全图默认falsecenterX,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) {
// 缩略图:背景
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);
var icon = core.material.icons.hero[options.heroLoc.direction];
var height = core.material.images.images[options.heroIcon].height / 4;
var width = (core.material.images.images[options.heroIcon].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);
// 缩略图:显伤
if (options.damage && core.hasItem('book')) {
core.updateCheckBlock(floorId);
core.control.updateDamage(floorId, options.ctx);
}
}
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/4SL界面为0.3
var w = Math.ceil(size * core._PX_), h = Math.ceil(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;
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);
}
}
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);
} 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);
} else {
core.drawImage(ctx, tempCanvas.canvas, offsetX * 32 * scale, offsetY * 32 * scale, pw * scale, ph * scale, x, y, w, h);
}
}
}
}
// -------- 获得某个点的图块信息 -------- //
////// 某个点是否不可通行 //////
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);
}
////// 获得某个图块或素材的信息,包括 IDcls图片坐标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);
// 在本层,添加动画
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);
// 删除动画,清除地图
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);
}
////// 一次性隐藏多个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);
for (var i in core.status.maps[floorId].blocks) {
var block = core.status.maps[floorId].blocks[i];
if (block.x == x && block.y == y) {
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);
}
////// 一次性删除多个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) {
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') {
if (/^\d+$/.test(number)) number = parseInt(number);
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') {
core.redrawMap();
} else {
if (originEvent != null) {
this._removeBlockFromMap(floorId, { x: x, y: y, event: originEvent });
}
if (!block.disable) {
core.drawBlock(block);
core.addGlobalAnimate(block);
core.updateStatusBar();
}
}
}
}
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') {
if (/^\d+$/.test(number)) number = parseInt(number);
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);
}
}, 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') {
if (/^\d+$/.test(number)) number = parseInt(number);
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);
}
}
////// 重置地图 //////
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) {
var headCanvas = null, bodyCanvas = '__body_' + x + "_" + y, damageCanvas = null;
// head
if (!blockInfo.bigImage && blockInfo.height > 32) {
headCanvas = "__head_" + x + "_" + y;
core.createCanvas(headCanvas, 0, 0, 32, blockInfo.height - 32, 55);
}
// body
if (blockInfo.bigImage) {
var bigImageInfo = this._getBigImageInfo(blockInfo.bigImage, blockInfo.face, blockInfo.posX);
core.createCanvas(bodyCanvas, 0, 0, bigImageInfo.per_width, bigImageInfo.per_height, 35);
} else {
core.createCanvas(bodyCanvas, 0, 0, 32, 32, 35);
}
// damage
var damage = null, damageColor = null;
if (blockInfo.cls.indexOf('enemy') == 0 && core.hasItem('book') && displayDamage) {
var damageString = core.enemys.getDamageString(blockInfo.id, x, y);
damage = damageString.damage;
damageColor = damageString.color;
}
if (damage != null) {
damageCanvas = "__damage_" + x + "_" + y;
var ctx = core.createCanvas(damageCanvas, 0, 0, 32, 32, 65);
ctx.textAlign = 'left';
ctx.font = "bold 11px Arial";
core.fillBoldText(ctx, damage, 1, 31, damageColor);
if (core.flags.displayCritical) {
var critical = core.enemys.nextCriticals(blockInfo.id);
if (critical.length > 0) critical = critical[0];
critical = core.formatBigNumber(critical[0], true);
if (critical == '???') critical = '?';
core.fillBoldText(ctx, critical, 1, 21, '#FFFFFF');
}
}
return {
"headCanvas": headCanvas,
"bodyCanvas": bodyCanvas,
"damageCanvas": damageCanvas
}
}
////// 移动独立的block canvas //////
maps.prototype._moveDetachedBlock = function (blockInfo, nowX, nowY, opacity, canvases) {
var height = blockInfo.height, posX = blockInfo.posX, posY = blockInfo.posY, image = blockInfo.image;
var headCanvas = canvases.headCanvas, bodyCanvas = canvases.bodyCanvas, damageCanvas = canvases.damageCanvas;
if (headCanvas) {
core.dymCanvas[headCanvas].clearRect(0, 0, 32, height);
core.dymCanvas[headCanvas].drawImage(image, posX * 32, posY * height, 32, height - 32, 0, 0, 32, height - 32);
core.relocateCanvas(headCanvas, nowX - core.bigmap.offsetX, nowY + 32 - height - core.bigmap.offsetY);
core.setOpacity(headCanvas, opacity);
}
if (bodyCanvas) {
if (blockInfo.bigImage) {
var face = blockInfo.face;
if (!blockInfo.faceIds) face = 'down';
else if (!blockInfo.faceIds[face]) {
// 维持此时朝向
face = 'down';
for (var f in blockInfo.faceIds) {
if (blockInfo.faceIds[f] == blockInfo.id) {
face = f;
}
}
}
var bigImageInfo = this._getBigImageInfo(blockInfo.bigImage, face, blockInfo.posX);
var per_width = bigImageInfo.per_width, per_height = bigImageInfo.per_height;
core.dymCanvas[bodyCanvas].clearRect(0, 0, bigImageInfo.per_width, bigImageInfo.per_height);
core.dymCanvas[bodyCanvas].drawImage(blockInfo.bigImage, bigImageInfo.sx, bigImageInfo.sy, per_width, per_height, 0, 0, per_width, per_height);
core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX + bigImageInfo.dx, nowY - core.bigmap.offsetY + bigImageInfo.dy);
core.setOpacity(bodyCanvas, opacity);
} else {
core.dymCanvas[bodyCanvas].clearRect(0, 0, 32, 32);
core.dymCanvas[bodyCanvas].drawImage(image, posX * 32, posY * height + height - 32, 32, 32, 0, 0, 32, 32);
core.relocateCanvas(bodyCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY);
core.setOpacity(bodyCanvas, opacity);
}
}
if (damageCanvas) {
core.relocateCanvas(damageCanvas, nowX - core.bigmap.offsetX, nowY - core.bigmap.offsetY);
core.setOpacity(damageCanvas, opacity);
}
}
////// 删除独立的block canvas //////
maps.prototype._deleteDetachedBlock = function (canvases) {
core.deleteCanvas(canvases.headCanvas);
core.deleteCanvas(canvases.bodyCanvas);
core.deleteCanvas(canvases.damageCanvas);
}
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();
}
// --- 检测所有是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(parseInt(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');
}