HumanBreak/public/libs/maps.js
2023-04-25 20:50:23 +08:00

4555 lines
138 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.

///<reference path="../../src/types/core.d.ts" />
'use strict';
function maps() {
this._init();
}
maps.prototype._init = function () {
this.blocksInfo = maps_90f36752_8815_4be8_b32b_d7fad1d0542e;
//delete(maps_90f36752_8815_4be8_b32b_d7fad1d0542e);
};
maps.prototype._initFloors = function (floorId) {
if (!floorId) {
core.floorIds.forEach(function (floorId) {
core.maps._initFloors(floorId);
});
return;
}
// 战前事件兼容性
if (!core.floors[floorId].beforeBattle)
core.floors[floorId].beforeBattle = {};
// cannotMoveIn兼容性
if (!core.floors[floorId].cannotMoveIn)
core.floors[floorId].cannotMoveIn = {};
};
maps.prototype._resetFloorImages = function () {
for (var floorId in core.status.maps) {
(core.status.maps[floorId].images || []).forEach(function (one) {
var flag = '__floorImg__' + floorId + '_' + one.x + '_' + one.y;
if (core.getFlag(flag) == null) {
if (one.disabled) core.setFlag(flag, true);
}
});
}
};
maps.prototype._setHDCanvasSize = function (ctx, width, height) {
ctx.setTransform(1, 0, 0, 1, 0, 0);
var ratio = core.domStyle.scale;
ratio *= devicePixelRatio;
if (width != null) ctx.canvas.width = width * ratio;
if (height != null) ctx.canvas.height = height * ratio;
ctx.scale(ratio, ratio);
ctx.canvas.setAttribute('isHD', 1);
};
// ------ 加载地图与地图的存档读档(压缩与解压缩) ------ //
////// 加载某个楼层(从剧本或存档中) //////
maps.prototype.loadFloor = function (floorId, map) {
var floor = core.floors[floorId];
if (!map) map = core.cloneArray(floor.map);
if (map instanceof Array) {
map = { map: map };
}
if (!map.map) map.map = core.cloneArray(floor.map);
var content = {};
var notCopy = this._loadFloor_doNotCopy();
for (var name in floor) {
if (notCopy.indexOf(name) == -1 && floor[name] != null)
content[name] = core.clone(floor[name]);
}
for (var name in map) {
if (notCopy.indexOf(name) == -1 && map[name] != null)
content[name] = core.clone(map[name]);
}
content.map = map.map;
if (main.mode == 'editor') {
this.extractBlocks(content);
}
return content;
};
maps.prototype._loadFloor_doNotCopy = function () {
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.includes(cn))
core.maps._setHDCanvasSize(core.canvas[cn], width, height);
else {
core.canvas[cn].canvas.width = width;
core.canvas[cn].canvas.height = height;
}
core.canvas[cn].canvas.style.width = width * core.domStyle.scale + 'px';
core.canvas[cn].canvas.style.height =
height * core.domStyle.scale + 'px';
core.canvas[cn].translate(
core.bigmap.v2 ? 32 : 0,
core.bigmap.v2 ? 32 : 0
);
if (main.mode === 'editor' && editor.isMobile) {
core.canvas[cn].canvas.style.width =
(width / core._PX_) * 96 + 'vw';
core.canvas[cn].canvas.style.height =
(height / core._PY_) * 96 + 'vw';
}
});
};
////// 将当前地图重新变成二维数组形式 //////
maps.prototype.getMapArray = function (floorId, noCache) {
floorId = floorId || core.status.floorId;
var map = core.status.maps[floorId];
if (!map.blocks || !noCache) return map.map;
return (map.map = this._getMapArrayFromBlocks(
map.blocks,
map.width,
map.height
));
};
////// 获得地图上某点的数字
maps.prototype.getMapNumber = function (x, y, floorId, noCache) {
return this.getMapArray(floorId, noCache)[y][x];
};
maps.prototype._updateMapArray = function (floorId, x, y) {
floorId = floorId || core.status.floorId;
var map = core.status.maps[floorId];
if (!map.blocks) return;
if (x == null || y == null) return this.getMapArray(floorId, true);
var block = this.getBlock(x, y, floorId, true);
if (block == null || block.disable) map.map[y][x] = 0;
else map.map[y][x] = block.id;
};
maps.prototype._getMapArrayFromBlocks = function (
blockArray,
width,
height,
showDisable
) {
var blocks = [];
for (var x = 0; x < height; x++) blocks.push(Array(width).fill(0));
blockArray.forEach(function (block) {
if (showDisable || !block.disable) blocks[block.y][block.x] = block.id;
});
return blocks;
};
////// 以x,y的形式返回每个点的事件 //////
maps.prototype.getMapBlocksObj = function (floorId, noCache) {
floorId = floorId || core.status.floorId;
if (core.status.mapBlockObjs[floorId] && !noCache)
return core.status.mapBlockObjs[floorId];
var obj = {};
core.extractBlocks(floorId);
core.status.maps[floorId].blocks.forEach(function (block) {
obj[block.x + ',' + block.y] = block;
});
return (core.status.mapBlockObjs[floorId] = obj);
};
////// 将背景前景层变成二维数组的形式 //////
maps.prototype._getBgFgMapArray = function (name, floorId, noCache) {
floorId = floorId || core.status.floorId;
if (!floorId) return [];
var width = core.floors[floorId].width;
var height = core.floors[floorId].height;
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.mockery[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;
deepAdd += core.status.checkBlock.mockery[`${x},${y}`] ? 1000 : 0;
return deepAdd;
};
// -------- 绘制地图各层图块楼层贴图Autotile -------- //
maps.prototype._getBigImageInfo = function (bigImage, face, animate) {
face = face || 'down';
if (['up', 'down', 'left', 'right'].indexOf(face) < 0) face = 'down';
var per_width = bigImage.width / 4;
var per_height = bigImage.height / 4;
var sx = animate * per_width,
sy;
if (per_height <= per_width / 2) {
// 强制视为 1*4 的怪物
per_height = bigImage.height;
sy = 0;
} else {
sy = core.material.icons.hero[face].loc * per_height;
}
var dx, dy;
switch (face) {
case 'down':
case 'up':
case 'left':
case 'right':
dx = 16 - per_width / 2;
dy = 32 - per_height;
break;
// case "left": dx = 0; dy = 32 - per_height; break;
// case "right": dx = 32 - per_width; dy = 32 - per_height; break;
}
return {
sx: sx,
sy: sy,
per_width: per_width,
per_height: per_height,
face: face,
dx: dx,
dy: dy
};
};
////// 绘制一个图块 //////
maps.prototype.drawBlock = function (block, animate, ctx) {
if (block.event.id == 'none') return;
var redraw = animate != null;
if (!redraw) animate = 0;
var x = block.x,
y = block.y;
// --- 在界面外的动画不绘制
// 判定是否绘制
if (core.bigmap.v2) {
var posX = core.bigmap.posX,
posY = core.bigmap.posY;
if (
x < posX - 1 ||
y < posY - 1 ||
x > posX + core._WIDTH_ ||
y > posY + core._HEIGHT_ + 1
) {
// +1 for 48 height
return;
}
} else {
if (
redraw &&
block.event.animate > 1 &&
(32 * x < core.bigmap.offsetX - 64 ||
32 * x > core.bigmap.offsetX + core._PX_ + 32 ||
32 * y < core.bigmap.offsetY - 64 ||
32 * y > core.bigmap.offsetY + core._PY_ + 32 + 16)
) {
return;
}
}
var blockInfo = this.getBlockInfo(block);
if (blockInfo == null) return;
if (blockInfo.cls != 'tileset')
blockInfo.posX = animate % blockInfo.animate;
blockInfo.opacity = block.opacity;
blockInfo.filter = block.filter;
if (!block.name) this._drawBlockInfo(blockInfo, block.x, block.y, ctx);
else this._drawBlockInfo_bgfg(blockInfo, block.name, block.x, block.y, ctx);
};
maps.prototype._drawBlockInfo_bigImage = function (blockInfo, x, y, ctx) {
var bigImageInfo = this._getBigImageInfo(
blockInfo.bigImage,
blockInfo.face,
blockInfo.posX
);
var per_width = bigImageInfo.per_width,
per_height = bigImageInfo.per_height,
sx = bigImageInfo.sx,
sy = bigImageInfo.sy;
var bigImage = blockInfo.bigImage;
if (main.mode == 'editor') {
var px = 32 * x - 32 * core.bigmap.posX;
var py = 32 * y - 32 * core.bigmap.posY;
if (ctx == null) ctx = 'event';
core.clearMap(ctx, px, py, 32, 32);
core.drawImage(
ctx,
bigImage,
sx,
sy,
per_width,
per_height,
px,
py,
32,
32
);
return;
}
var px = 32 * x - core.bigmap.offsetX;
var py = 32 * y - core.bigmap.offsetY;
// 上半部分 - 会遮挡勇士z值高于event2为51
var header = '_bigImage_header_' + x + '_' + y;
// 下半部分 - 会被勇士遮挡z值高于event为31
var body = '_bigImage_body_' + x + '_' + y;
var dx = bigImageInfo.dx,
dy = bigImageInfo.dy;
switch (bigImageInfo.face) {
case 'down':
case 'up':
case 'left':
case 'right':
core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
core.drawImage(
header,
bigImage,
sx,
sy,
per_width,
-dy,
0,
0,
per_width,
-dy
);
});
core.createCanvas(body, px + dx, py, per_width, 32, 31);
this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
core.drawImage(
body,
bigImage,
sx,
sy - dy,
per_width,
32,
0,
0,
per_width,
32
);
});
break;
/*case "left":
core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
});
core.createCanvas(body, px + dx, py, per_width, 32, 31);
this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
});
break;
case "right":
core.createCanvas(header, px + dx, py + dy, per_width, -dy, 51);
this._drawBlockInfo_drawWithFilter(blockInfo, header, function () {
core.drawImage(header, bigImage, sx, sy, per_width, -dy, 0, 0, per_width, -dy);
});
core.createCanvas(body, px + dx, py, per_width, per_height / 2 + 16, 31);
this._drawBlockInfo_drawWithFilter(blockInfo, body, function () {
core.drawImage(body, bigImage, sx, sy - dy, per_width, 32, 0, 0, per_width, 32);
});
break;*/
}
if (core.dymCanvas[header]) {
core.dymCanvas[header].canvas.setAttribute('_ox', 32 * x + dx);
core.dymCanvas[header].canvas.setAttribute('_oy', 32 * y + dy);
}
if (core.dymCanvas[body]) {
core.dymCanvas[body].canvas.setAttribute('_ox', 32 * x + dx);
core.dymCanvas[body].canvas.setAttribute('_oy', 32 * y);
}
};
maps.prototype._drawBlockInfo_drawWithFilter = function (blockInfo, ctx, func) {
var alpha = null;
if (blockInfo.opacity != null)
alpha = core.setAlpha(ctx, blockInfo.opacity);
core.setFilter(ctx, blockInfo.filter);
func();
core.setFilter(ctx, null);
if (alpha != null) core.setAlpha(ctx, alpha);
};
maps.prototype._drawBlockInfo = function (blockInfo, x, y, ctx) {
if (blockInfo.bigImage)
return this._drawBlockInfo_bigImage(blockInfo, x, y, ctx);
var image = blockInfo.image,
posX = blockInfo.posX,
posY = blockInfo.posY,
height = blockInfo.height;
var px = 32 * x - 32 * core.bigmap.posX;
var py = 32 * y - 32 * core.bigmap.posY;
if (ctx == null) ctx = 'event';
this._drawBlockInfo_drawWithFilter(blockInfo, ctx, function () {
core.clearMap(ctx, px, py, 32, 32);
core.drawImage(
ctx,
image,
posX * 32,
posY * height + height - 32,
32,
32,
px,
py,
32,
32
);
});
if (height > 32) {
this._drawBlockInfo_drawWithFilter(blockInfo, 'event2', function () {
core.clearMap('event2', px, py + 32 - height, 32, height - 32);
core.drawImage(
'event2',
image,
posX * 32,
posY * height,
32,
height - 32,
px,
py + 32 - height,
32,
height - 32
);
});
}
};
maps.prototype._drawBlockInfo_bgfg = function (blockInfo, name, x, y, ctx) {
var image = blockInfo.image,
posX = blockInfo.posX,
posY = blockInfo.posY,
height = blockInfo.height;
var px = 32 * x - 32 * core.bigmap.posX;
var py = 32 * y - 32 * core.bigmap.posY;
if (ctx == null) ctx = name;
core.clearMap(ctx, px, py + 32 - height, 32, height);
if (name == 'bg') {
if (height > 32) {
core.clearMap(ctx, px, py - 32, 32, 32);
core.drawImage(ctx, core.material.groundCanvas.canvas, px, py - 32);
}
core.drawImage(ctx, core.material.groundCanvas.canvas, px, py);
}
var alpha = null;
if (blockInfo.opacity != null)
alpha = core.setAlpha(ctx, blockInfo.opacity);
else if (name == 'fg' && this._drawBlockInfo_shouldBlurFg(x, y))
alpha = core.setAlpha(ctx, 0.6);
core.setFilter(ctx, blockInfo.filter);
core.drawImage(
ctx,
image,
posX * 32,
posY * height,
32,
height,
px,
py + 32 - height,
32,
height
);
core.setFilter(ctx, null);
if (alpha != null) core.setAlpha(ctx, alpha);
};
////// 是否应当存在事件时虚化前景层 //////
maps.prototype._drawBlockInfo_shouldBlurFg = function (x, y) {
if (main.mode == 'play' && !core.flags.blurFg) return false;
var block = this.getBlock(x, y);
if (block == null || block.id == 0) return false;
if (block.event.cls == 'autotile' || block.event.cls == 'tileset')
return block.event.script || block.event.event;
return true;
};
////// 生成groundPattern //////
maps.prototype.generateGroundPattern = function (floorId) {
// 生成floorId层的groundPattern盒子内的怪物动画
var groundId =
(
(core.status.maps || core.floors)[floorId || core.status.floorId] ||
{}
).defaultGround || 'ground';
var groundInfo = core.getBlockInfo(groundId);
if (groundInfo == null) return;
core.material.groundCanvas.clearRect(0, 0, 32, 32);
core.material.groundCanvas.drawImage(
groundInfo.image,
32 * groundInfo.posX,
groundInfo.height * groundInfo.posY,
32,
32,
0,
0,
32,
32
);
core.material.groundPattern = core.material.groundCanvas.createPattern(
core.material.groundCanvas.canvas,
'repeat'
);
// 如果需要用纯色可以直接将下面代码改成改成
// core.material.groundPattern = '#000000';
};
////// 绘制某张地图 //////
maps.prototype.drawMap = function (floorId) {
floorId = floorId || core.status.floorId;
if (!floorId) return;
core.clearMap('all');
this.generateGroundPattern(floorId);
core.status.floorId = floorId;
core.extractBlocks(floorId);
core.status.thisMap = core.status.maps[floorId];
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;
core.clearMap(
cv,
32 * x - 32 * core.bigmap.posX,
32 * y - 32 * core.bigmap.posY,
32,
32
);
var alpha = null;
if (block.opacity != null) alpha = core.setAlpha(cv, block.opacity);
core.setFilter(cv, block.filter);
if (block.name) {
if (block.name == 'bg')
core.drawImage(
'bg',
core.material.groundCanvas.canvas,
32 * x - 32 * core.bigmap.posX,
32 * y - 32 * core.bigmap.posY
);
this._drawAutotile(
cv,
this._getBgFgMapArray(block.name),
block,
32,
0,
0,
animate,
true
);
} else {
this._drawAutotile(
cv,
this.getMapArray(),
block,
32,
0,
0,
animate,
true
);
}
core.setFilter(cv, null);
if (alpha != null) core.setAlpha(cv, alpha);
};
////// 为autotile判定边界 //////
maps.prototype._makeAutotileEdges = function () {
var autotileIds = Object.keys(core.material.images.autotile);
core.material.autotileEdges = {};
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
canvas.width = canvas.height = 32;
ctx.mozImageSmoothingEnabled = false;
ctx.webkitImageSmoothingEnabled = false;
ctx.msImageSmoothingEnabled = false;
ctx.imageSmoothingEnabled = false;
var first = {},
second = {};
autotileIds.forEach(function (t) {
var n = core.maps.getNumberById(t);
core.clearMap(ctx, 0, 0, 32, 32);
core.drawImage(
ctx,
core.material.images.autotile[t],
0,
0,
32,
32,
0,
0,
32,
32
);
first[n] = canvas.toDataURL('image/png');
core.clearMap(ctx, 0, 0, 32, 32);
core.drawImage(
ctx,
core.material.images.autotile[t],
32,
0,
32,
32,
0,
0,
32,
32
);
second[n] = canvas.toDataURL('image/png');
});
for (var n in first) {
n = parseInt(n);
core.material.autotileEdges[n] = [n];
for (var n2 in second) {
n2 = parseInt(n2);
if (n == n2) continue;
if (first[n] == second[n2]) {
core.material.autotileEdges[n].push(n2);
}
}
}
};
////// 绘制缩略图 //////
// 此函数将绘制一个缩略图floorId为目标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
) {
options.ctx.imageSmoothingEnabled = core.getLocalStorage(
'antiAliasing',
true
);
// 缩略图:背景
this.drawBg(floorId, options);
// 缩略图:事件
this.drawEvents(floorId, blocks, options);
// 缩略图:勇士
if (options.heroLoc) {
options.heroIcon =
options.heroIcon || core.status.hero.image || 'hero.png';
options.heroIcon = core.getMappedName(options.heroIcon);
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);
options.ctx.imageSmoothingEnabled = true;
// 缩略图:显伤
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 = size * core._PX_,
h = size * core._PY_;
// 特判是否为编辑器编辑器中长宽均采用core.js的遗留正方形像素边长以保证下面的绘制正常
if (main.mode == 'editor') w = h = size * core.__PIXELS__;
var width = core.floors[floorId].width,
height = core.floors[floorId].height;
var centerX = options.centerX,
centerY = options.centerY;
if (centerX == null) centerX = Math.floor(width / 2);
if (centerY == null) centerY = Math.floor(height / 2);
var tempCanvas = core.bigmap.tempCanvas;
if (options.inFlyMap) {
ctx.drawImage(
tempCanvas.canvas,
0,
0,
tempCanvas.canvas.width,
tempCanvas.canvas.height,
options.x,
options.y,
options.w,
options.h
);
return;
}
const scale = core.domStyle.scale * devicePixelRatio;
if (options.all) {
var tempWidth = tempCanvas.canvas.width,
tempHeight = tempCanvas.canvas.height;
// 绘制全景图
if (tempWidth <= tempHeight) {
var realHeight = h,
realWidth = (realHeight * tempWidth) / tempHeight;
var side = (w - realWidth) / 2;
core.fillRect(ctx, x, y, side, realHeight, '#000000');
core.fillRect(ctx, x + w - side, y, side, realHeight);
core.drawImage(
ctx,
tempCanvas.canvas,
0,
0,
tempWidth,
tempHeight,
x + side,
y,
realWidth,
realHeight
);
} else {
var realWidth = w,
realHeight = (realWidth * tempHeight) / tempWidth;
var side = (h - realHeight) / 2;
core.fillRect(ctx, x, y, realWidth, side, '#000000');
core.fillRect(ctx, x, y + h - side, realWidth, side);
core.drawImage(
ctx,
tempCanvas.canvas,
0,
0,
tempWidth,
tempHeight,
x,
y + side,
realWidth,
realHeight
);
}
ctx.imageSmoothingEnabled = true;
} else {
// 只绘制可见窗口
var pw = core._PX_,
ph = core._PY_,
hw = core._HALF_WIDTH_,
hh = core._HALF_HEIGHT_,
W = core._WIDTH_,
H = core._HEIGHT_;
if (main.mode == 'editor') {
pw = ph = core.__PIXELS__;
hw = hh = core.__HALF_SIZE__;
W = H = core.__SIZE__;
}
if (options.v2) {
if (options.noHD) {
core.drawImage(
ctx,
tempCanvas.canvas,
0,
0,
pw,
ph,
x,
y,
w,
h
);
} else {
core.drawImage(
ctx,
tempCanvas.canvas,
0,
0,
pw * scale,
ph * scale,
x,
y,
w,
h
);
}
ctx.imageSmoothingEnabled = true;
} else {
var offsetX = core.clamp(centerX - hw, 0, width - W),
offsetY = core.clamp(centerY - hh, 0, height - H);
if (options.noHD) {
core.drawImage(
ctx,
tempCanvas.canvas,
offsetX * 32,
offsetY * 32,
pw,
ph,
x,
y,
w,
h
);
ctx.imageSmoothingEnabled = true;
return;
}
core.drawImage(
ctx,
tempCanvas.canvas,
offsetX * 32,
offsetY * 32,
pw * scale,
ph * scale,
x,
y,
w,
h
);
ctx.imageSmoothingEnabled = true;
}
}
};
// -------- 获得某个点的图块信息 -------- //
////// 某个点是否不可通行 //////
maps.prototype.noPass = function (x, y, floorId) {
var block = core.getBlock(x, y, floorId);
if (block == null) return false;
return block.event.noPass;
};
////// 某个点是否存在NPC //////
maps.prototype.npcExists = function (x, y, floorId) {
var block = this.getBlock(x, y, floorId);
if (block == null) return false;
return block.event.cls.indexOf('npc') == 0;
};
////// 某个点是否存在(指定的)地形 //////
maps.prototype.terrainExists = function (x, y, id, floorId) {
var block = this.getBlock(x, y, floorId);
if (block == null) return false;
return block.event.cls == 'terrains' && (id ? block.event.id == id : true);
};
////// 某个点是否存在楼梯 //////
maps.prototype.stairExists = function (x, y, floorId) {
var blockId = this.getBlockId(x, y, floorId);
if (blockId == null) return false;
var ids = ['upFloor', 'downFloor'];
ids = ids.concat([
'leftPortal',
'rightPortal',
'upPortal',
'downPortal',
'portal',
'starPortal'
]);
return ids.indexOf(blockId) >= 0;
};
////// 当前位置是否在楼梯边 //////
maps.prototype.nearStair = function () {
var x = core.getHeroLoc('x'),
y = core.getHeroLoc('y');
return (
this.stairExists(x, y) ||
this.stairExists(x - 1, y) ||
this.stairExists(x, y - 1) ||
this.stairExists(x + 1, y) ||
this.stairExists(x, y + 1)
);
};
////// 某个点是否存在(指定的)怪物 //////
maps.prototype.enemyExists = function (x, y, id, floorId) {
var block = this.getBlock(x, y, floorId);
if (block == null) return false;
return (
block.event.cls.indexOf('enemy') == 0 &&
(id ? block.event.id == id : true)
);
};
////// 获得某个点的block //////
maps.prototype.getBlock = function (x, y, floorId, showDisable) {
floorId = floorId || core.status.floorId;
if (!floorId) return null;
core.extractBlocks(floorId);
var blockObjs = this.getMapBlocksObj(floorId);
var block = blockObjs[x + ',' + y];
if (block && (showDisable || !block.disable)) return block;
return null;
};
////// 获得某个点的blockId //////
maps.prototype.getBlockId = function (x, y, floorId, showDisable) {
var block = core.getBlock(x, y, floorId, showDisable);
return block == null ? null : block.event.id;
};
////// 获得某个点的数字 //////
maps.prototype.getBlockNumber = function (x, y, floorId, showDisable) {
var block = core.getBlock(x, y, floorId, showDisable);
return block == null ? null : block.id;
};
////// 获得某个点的blockCls //////
maps.prototype.getBlockCls = function (x, y, floorId, showDisable) {
var block = core.getBlock(x, y, floorId, showDisable);
return block == null ? null : block.event.cls;
};
////// 获得某个点的不透明度 //////
maps.prototype.getBlockOpacity = function (x, y, floorId, showDisable) {
var block = core.getBlock(x, y, floorId, showDisable);
if (block == null) return null;
if (block.opacity == null) return 1.0;
return block.opacity == null ? 1.0 : block.opacity;
};
////// 获得某个点的filter //////
maps.prototype.getBlockFilter = function (x, y, floorId, showDisable) {
var block = core.getBlock(x, y, floorId, showDisable);
if (block == null) return null;
if (block.filter == null)
return { blur: 0, hue: 0, grayscale: 0, invert: false, shadow: 0 };
return core.clone(block.filter);
};
////// 获得某个图块或素材的信息,包括 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);
const blocks = core.status.maps[floorId].blocks;
const i = blocks.findIndex(v => v.x === x && v.y === y);
if (i !== -1) {
const block = blocks[i];
this.removeBlockByIndex(i, floorId);
this._removeBlockFromMap(floorId, block);
if (!main.replayChecking) core.updateShadow(true);
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, noredraw) {
floorId = floorId || core.status.floorId;
if (!floorId || number == null || x == null || y == null) return;
if (
x < 0 ||
x >= core.floors[floorId].width ||
y < 0 ||
y >= core.floors[floorId].height
)
return;
if (typeof number == 'string') {
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' && !noredraw)
) {
core.redrawMap();
} else {
if (originEvent != null) {
this._removeBlockFromMap(floorId, {
x: x,
y: y,
event: originEvent
});
}
if (!block.disable) {
if (!noredraw) {
core.drawBlock(block);
core.addGlobalAnimate(block);
core.updateStatusBar();
}
}
}
}
if (!main.replayChecking) core.updateShadow(true);
};
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');
};