您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

402 行
8.9 KiB

  1. const physics = require('./physics');
  2. const resourceSpawner = require('./resourceSpawner');
  3. const globalZone = require('../config/zoneBase');
  4. const randomMap = require('./randomMap/randomMap');
  5. const generateMappings = require('./randomMap/generateMappings');
  6. const events = require('../misc/events');
  7. const spriteBuilder = require('./spriteBuilder/index');
  8. //Builders
  9. const buildTile = require('./map/builders/tile');
  10. const buildObject = require('./map/builders/object');
  11. //Helpers
  12. const canPathFromPos = require('./map/canPathFromPos');
  13. const getObjectifiedProperties = require('./map/getObjectifiedProperties');
  14. let mapFile = null;
  15. let mapScale = null;
  16. let padding = null;
  17. module.exports = {
  18. name: null,
  19. path: null,
  20. layers: [],
  21. mapFile: null,
  22. //The size of the base map, before mods are applied
  23. originalSize: {
  24. w: 0,
  25. h: 0
  26. },
  27. //The size of the map after mods are applied
  28. size: {
  29. w: 0,
  30. h: 0
  31. },
  32. custom: null,
  33. collisionMap: null,
  34. clientMap: null,
  35. oldLayers: {
  36. tiles: null,
  37. walls: null,
  38. doodads: null
  39. },
  40. objBlueprints: [],
  41. spawn: {
  42. x: 0,
  43. y: 0
  44. },
  45. rooms: [],
  46. hiddenRooms: [],
  47. hiddenWalls: null,
  48. hiddenTiles: null,
  49. zone: null,
  50. init: function (args) {
  51. this.name = args.name;
  52. this.path = args.path;
  53. try {
  54. this.zone = require('../' + this.path + '/' + this.name + '/zone');
  55. } catch (e) {
  56. this.zone = globalZone;
  57. }
  58. events.emit('onAfterGetZone', this.name, this.zone);
  59. let chats = null;
  60. try {
  61. chats = require('../' + this.path + '/' + this.name + '/chats');
  62. } catch (e) {}
  63. if (chats)
  64. this.zone.chats = chats;
  65. let dialogues = null;
  66. try {
  67. dialogues = require('../' + this.path + '/' + this.name + '/dialogues');
  68. } catch (e) {}
  69. events.emit('onBeforeGetDialogue', this.name, dialogues);
  70. if (dialogues)
  71. this.zone.dialogues = dialogues;
  72. this.zone = extend({}, globalZone, this.zone);
  73. let resources = this.zone.resources || {};
  74. for (let r in resources)
  75. resourceSpawner.register(r, resources[r]);
  76. mapFile = require('../' + this.path + '/' + this.name + '/map');
  77. this.mapFile = mapFile;
  78. //Fix for newer versions of Tiled
  79. this.mapFile.properties = getObjectifiedProperties(this.mapFile.properties);
  80. mapScale = mapFile.tilesets[0].tileheight;
  81. this.mapScale = mapScale;
  82. this.custom = mapFile.properties.custom;
  83. if (mapFile.properties.spawn) {
  84. this.spawn = JSON.parse(mapFile.properties.spawn);
  85. if (!this.spawn.push)
  86. this.spawn = [this.spawn];
  87. }
  88. },
  89. create: function () {
  90. this.getMapFile();
  91. this.clientMap = {
  92. zoneId: -1,
  93. map: this.layers,
  94. collisionMap: this.collisionMap,
  95. clientObjects: this.objBlueprints,
  96. padding: padding,
  97. hiddenRooms: this.hiddenRooms,
  98. spriteAtlasPath: spriteBuilder.getPath(),
  99. noFlipTiles: spriteBuilder.getNoFlipTiles(),
  100. tileOpacities: spriteBuilder.getTileOpacities()
  101. };
  102. },
  103. getMapFile: function () {
  104. this.build();
  105. this.randomMap = extend({}, randomMap);
  106. this.oldMap = extend([], this.layers);
  107. this.randomMap.templates = extend([], this.rooms);
  108. generateMappings(this.randomMap, this);
  109. if (!mapFile.properties.isRandom) {
  110. for (let i = 0; i < this.size.w; i++) {
  111. let row = this.layers[i];
  112. for (let j = 0; j < this.size.h; j++) {
  113. let cell = row[j];
  114. if (!cell)
  115. continue;
  116. cell = cell.split(',');
  117. let cLen = cell.length;
  118. let newCell = '';
  119. for (let k = 0; k < cLen; k++) {
  120. let c = cell[k];
  121. let newC = c;
  122. //Randomize tile
  123. const msgBeforeRandomizePosition = {
  124. success: true,
  125. x: i,
  126. y: j,
  127. map: this.name
  128. };
  129. events.emit('onBeforeRandomizePosition', msgBeforeRandomizePosition);
  130. if (msgBeforeRandomizePosition.success)
  131. newC = this.randomMap.randomizeTile(c);
  132. newCell += newC;
  133. //Wall?
  134. if ((c >= 160) && (c <= 352) && (newC === 0))
  135. this.collisionMap[i][j] = 0;
  136. if (k < cLen - 1)
  137. newCell += ',';
  138. }
  139. let fakeContents = [];
  140. const hiddenWall = this.hiddenWalls[i][j];
  141. const hiddenTile = this.hiddenTiles[i][j];
  142. if (hiddenTile)
  143. fakeContents.push(-this.randomMap.randomizeTile(hiddenTile));
  144. if (hiddenWall)
  145. fakeContents.push(-this.randomMap.randomizeTile(hiddenWall));
  146. if (fakeContents.length)
  147. newCell += ',' + fakeContents.join(',');
  148. row[j] = newCell;
  149. }
  150. }
  151. }
  152. //Fix for newer versions of Tiled
  153. this.randomMap.templates
  154. .forEach(r => {
  155. r.properties = getObjectifiedProperties(r.properties);
  156. });
  157. this.randomMap.templates
  158. .filter(r => r.properties.mapping)
  159. .forEach(function (m) {
  160. let x = m.x;
  161. let y = m.y;
  162. let w = m.width;
  163. let h = m.height;
  164. for (let i = x; i < x + w; i++) {
  165. let row = this.layers[i];
  166. for (let j = y; j < y + h; j++)
  167. row[j] = '';
  168. }
  169. }, this);
  170. physics.init(this.collisionMap);
  171. padding = mapFile.properties.padding;
  172. mapFile = null;
  173. },
  174. build: function () {
  175. const mapSize = {
  176. w: mapFile.width,
  177. h: mapFile.height
  178. };
  179. this.originalSize = {
  180. w: mapFile.width,
  181. h: mapFile.height
  182. };
  183. events.emit('onBeforeGetMapSize', this.name, mapSize);
  184. this.size.w = mapSize.w;
  185. this.size.h = mapSize.h;
  186. const { w: oldW, h: oldH } = this.originalSize;
  187. const { w, h } = this.size;
  188. this.layers = _.get2dArray(w, h, null);
  189. this.hiddenWalls = _.get2dArray(w, h, null);
  190. this.hiddenTiles = _.get2dArray(w, h, null);
  191. this.oldLayers.tiles = _.get2dArray(w, h, 0);
  192. this.oldLayers.walls = _.get2dArray(w, h, 0);
  193. this.oldLayers.doodads = _.get2dArray(w, h, 0);
  194. let builders = {
  195. tile: this.builders.tile.bind(this),
  196. object: this.builders.object.bind(this)
  197. };
  198. this.collisionMap = _.get2dArray(w, h);
  199. const layers = [...mapFile.layers.filter(l => l.objects), ...mapFile.layers.filter(l => !l.objects)];
  200. //Rooms need to be ahead of exits
  201. const layerRooms = layers.find(l => l.name === 'rooms') || {};
  202. layerRooms.objects.sort((a, b) => {
  203. const isExitA = a?.properties?.some(p => p.name === 'exit');
  204. const isExitB = b?.properties?.some(p => p.name === 'exit');
  205. if (isExitA && !isExitB)
  206. return 1;
  207. else if (!isExitA && isExitB)
  208. return -1;
  209. return 0;
  210. });
  211. for (let i = 0; i < layers.length; i++) {
  212. let layer = layers[i];
  213. let layerName = layer.name;
  214. if (!layer.visible)
  215. continue;
  216. let data = layer.data || layer.objects;
  217. if (layer.objects) {
  218. let info = {
  219. map: this.name,
  220. layer: layerName,
  221. objects: data,
  222. mapScale,
  223. size: this.size
  224. };
  225. events.emit('onAfterGetLayerObjects', info);
  226. }
  227. if (layer.objects) {
  228. let len = data.length;
  229. for (let j = 0; j < len; j++) {
  230. let cell = data[j];
  231. builders.object(layerName, cell, j);
  232. }
  233. } else {
  234. for (let x = 0; x < w; x++) {
  235. for (let y = 0; y < h; y++) {
  236. let index = (y * oldW) + x;
  237. const msgBuild = {
  238. map: this.name,
  239. layer: layerName,
  240. sheetName: null,
  241. cell: 0,
  242. x,
  243. y
  244. };
  245. if (x < oldW && y < oldH)
  246. msgBuild.cell = data[index];
  247. events.emit('onBeforeBuildLayerTile', msgBuild);
  248. builders.tile(msgBuild);
  249. events.emit('onAfterBuildLayerTile', msgBuild);
  250. }
  251. }
  252. }
  253. }
  254. },
  255. getOffsetCellPos: function (sheetName, cell) {
  256. const { config: { atlasTextureDimensions, atlasTextures } } = clientConfig;
  257. const indexInAtlas = atlasTextures.indexOf(sheetName);
  258. let offset = 0;
  259. for (let i = 0; i < indexInAtlas; i++) {
  260. const dimensions = atlasTextureDimensions[atlasTextures[i]];
  261. offset += (dimensions.width / 8) * (dimensions.height / 8);
  262. }
  263. return cell + offset;
  264. },
  265. getCellInfo: function (gid, x, y, layerName) {
  266. const cellInfoMsg = {
  267. mapName: this.name,
  268. x,
  269. y,
  270. layerName,
  271. tilesets: mapFile.tilesets,
  272. sheetName: null
  273. };
  274. events.emit('onBeforeGetCellInfo', cellInfoMsg);
  275. const tilesets = cellInfoMsg.tilesets;
  276. let flipX = null;
  277. if ((gid ^ 0x80000000) > 0) {
  278. flipX = true;
  279. gid = gid ^ 0x80000000;
  280. }
  281. let firstGid = 0;
  282. let sheetName = cellInfoMsg.sheetName;
  283. if (!sheetName) {
  284. for (let s = 0; s < tilesets.length; s++) {
  285. let tileset = tilesets[s];
  286. if (tileset.firstgid <= gid) {
  287. sheetName = tileset.name;
  288. firstGid = tileset.firstgid;
  289. }
  290. }
  291. gid = gid - firstGid + 1;
  292. }
  293. return {
  294. cell: gid,
  295. sheetName,
  296. flipX
  297. };
  298. },
  299. builders: {
  300. tile: function (info) {
  301. buildTile(this, info);
  302. },
  303. object: function (layerName, cell) {
  304. buildObject(this, layerName, cell);
  305. }
  306. },
  307. getSpawnPos: function (obj) {
  308. let stats = obj.components.find(c => (c.type === 'stats'));
  309. let level = stats.values.level;
  310. let spawns = this.spawn.filter(s => (((s.maxLevel) && (s.maxLevel >= level)) || (!s.maxLevel)));
  311. return spawns[0];
  312. },
  313. //Find if any spawns can path to a position. This is important for when maps change and players
  314. // log in on tiles that aren't blocking but not able to reach anywhere useful
  315. canPathFromPos: function (pos) {
  316. return canPathFromPos(this, pos);
  317. }
  318. };