You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

436 line
11 KiB

  1. let objects = require('../objects/objects');
  2. let physics = require('./physics');
  3. let spawners = require('./spawners');
  4. let resourceSpawner = require('./resourceSpawner');
  5. let globalZone = require('../config/zoneBase');
  6. let randomMap = require('./randomMap');
  7. let events = require('../misc/events');
  8. const mapObjects = require('./map/mapObjects');
  9. let mapFile = null;
  10. let mapScale = null;
  11. let padding = null;
  12. const objectifyProperties = oldProperties => {
  13. if (!oldProperties || !oldProperties.push)
  14. return oldProperties || {};
  15. let newProperties = {};
  16. oldProperties.forEach(p => {
  17. newProperties[p.name] = p.value;
  18. });
  19. return newProperties;
  20. };
  21. module.exports = {
  22. name: null,
  23. path: null,
  24. layers: [],
  25. mapFile: null,
  26. size: {
  27. w: 0,
  28. h: 0
  29. },
  30. custom: null,
  31. collisionMap: null,
  32. clientMap: null,
  33. oldLayers: {
  34. tiles: null,
  35. walls: null,
  36. doodads: null
  37. },
  38. objBlueprints: [],
  39. spawn: {
  40. x: 0,
  41. y: 0
  42. },
  43. rooms: [],
  44. hiddenRooms: [],
  45. hiddenWalls: null,
  46. hiddenTiles: null,
  47. zone: null,
  48. init: function (args) {
  49. this.name = args.name;
  50. this.path = args.path;
  51. try {
  52. this.zone = require('../' + this.path + '/' + this.name + '/zone');
  53. } catch (e) {
  54. this.zone = globalZone;
  55. }
  56. events.emit('onAfterGetZone', this.name, this.zone);
  57. let chats = null;
  58. try {
  59. chats = require('../' + this.path + '/' + this.name + '/chats');
  60. } catch (e) {}
  61. if (chats)
  62. this.zone.chats = chats;
  63. let dialogues = null;
  64. try {
  65. dialogues = require('../' + this.path + '/' + this.name + '/dialogues');
  66. } catch (e) {}
  67. events.emit('onBeforeGetDialogue', this.name, dialogues);
  68. if (dialogues)
  69. this.zone.dialogues = dialogues;
  70. this.zone = extend({}, globalZone, this.zone);
  71. let resources = this.zone.resources || {};
  72. for (let r in resources)
  73. resourceSpawner.register(r, resources[r]);
  74. mapFile = require('../' + this.path + '/' + this.name + '/map');
  75. this.mapFile = mapFile;
  76. //Fix for newer versions of Tiled
  77. this.mapFile.properties = objectifyProperties(this.mapFile.properties);
  78. mapScale = mapFile.tilesets[0].tileheight;
  79. this.custom = mapFile.properties.custom;
  80. if (mapFile.properties.spawn) {
  81. this.spawn = JSON.parse(mapFile.properties.spawn);
  82. if (!this.spawn.push)
  83. this.spawn = [this.spawn];
  84. }
  85. },
  86. create: function () {
  87. this.getMapFile();
  88. this.clientMap = {
  89. zoneId: -1,
  90. map: this.layers,
  91. hiddenWalls: this.hiddenWalls,
  92. hiddenTiles: this.hiddenTiles,
  93. collisionMap: this.collisionMap,
  94. clientObjects: this.objBlueprints,
  95. padding: padding,
  96. hiddenRooms: this.hiddenRooms
  97. };
  98. },
  99. getMapFile: function () {
  100. this.build();
  101. randomMap = extend({}, randomMap);
  102. this.oldMap = this.layers;
  103. randomMap.templates = extend([], this.rooms);
  104. randomMap.generateMappings(this);
  105. for (let i = 0; i < this.size.w; i++) {
  106. let row = this.layers[i];
  107. for (let j = 0; j < this.size.h; j++) {
  108. let cell = row[j];
  109. if (!cell)
  110. continue;
  111. cell = cell.split(',');
  112. let cLen = cell.length;
  113. let newCell = '';
  114. for (let k = 0; k < cLen; k++) {
  115. let c = cell[k];
  116. let newC = randomMap.randomizeTile(c);
  117. newCell += newC;
  118. //Wall?
  119. if ((c >= 160) && (c <= 352) && (newC === 0))
  120. this.collisionMap[i][j] = 0;
  121. if (k < cLen - 1)
  122. newCell += ',';
  123. }
  124. if (this.hiddenWalls[i][j])
  125. this.hiddenWalls[i][j] = randomMap.randomizeTile(this.hiddenWalls[i][j]);
  126. if (this.hiddenTiles[i][j])
  127. this.hiddenTiles[i][j] = randomMap.randomizeTile(this.hiddenTiles[i][j]);
  128. row[j] = newCell;
  129. }
  130. }
  131. //Fix for newer versions of Tiled
  132. randomMap.templates
  133. .forEach(r => {
  134. r.properties = objectifyProperties(r.properties);
  135. });
  136. randomMap.templates
  137. .filter(r => r.properties.mapping)
  138. .forEach(function (m) {
  139. let x = m.x;
  140. let y = m.y;
  141. let w = m.width;
  142. let h = m.height;
  143. for (let i = x; i < x + w; i++) {
  144. let row = this.layers[i];
  145. for (let j = y; j < y + h; j++)
  146. row[j] = '';
  147. }
  148. }, this);
  149. physics.init(this.collisionMap);
  150. padding = mapFile.properties.padding;
  151. mapFile = null;
  152. _.log('(M ' + this.name + '): Ready');
  153. },
  154. build: function () {
  155. this.size.w = mapFile.width;
  156. this.size.h = mapFile.height;
  157. this.layers = _.get2dArray(this.size.w, this.size.h, null);
  158. this.hiddenWalls = _.get2dArray(this.size.w, this.size.h, null);
  159. this.hiddenTiles = _.get2dArray(this.size.w, this.size.h, null);
  160. this.oldLayers.tiles = _.get2dArray(this.size.w, this.size.h, 0);
  161. this.oldLayers.walls = _.get2dArray(this.size.w, this.size.h, 0);
  162. this.oldLayers.objects = _.get2dArray(this.size.w, this.size.h, 0);
  163. let builders = {
  164. tile: this.builders.tile.bind(this),
  165. object: this.builders.object.bind(this)
  166. };
  167. this.collisionMap = _.get2dArray(this.size.w, this.size.h);
  168. //Rooms need to be ahead of exits
  169. mapFile.layers.rooms = (mapFile.layers.rooms || [])
  170. .sort(function (a, b) {
  171. if ((a.exit) && (!b.exit))
  172. return 1;
  173. return 0;
  174. });
  175. for (let i = 0; i < mapFile.layers.length; i++) {
  176. let layer = mapFile.layers[i];
  177. let layerName = layer.name;
  178. if (!layer.visible)
  179. continue;
  180. let data = layer.data || layer.objects;
  181. let firstItem = data[0];
  182. if (firstItem && firstItem.has('width')) {
  183. let info = {
  184. map: this.name,
  185. layer: layerName,
  186. objects: data
  187. };
  188. events.emit('onAfterGetLayerObjects', info);
  189. }
  190. let len = data.length;
  191. for (let j = 0; j < len; j++) {
  192. let cell = data[j];
  193. if ((cell.gid) || (cell.id))
  194. builders.object(layerName, cell, j);
  195. else {
  196. let y = ~~(j / this.size.w);
  197. let x = j - (y * this.size.w);
  198. let info = {
  199. map: this.name,
  200. layer: layerName,
  201. cell: cell,
  202. x: x,
  203. y: y
  204. };
  205. events.emit('onBeforeBuildLayerTile', info);
  206. builders.tile(layerName, info.cell, j);
  207. }
  208. }
  209. }
  210. },
  211. builders: {
  212. getCellInfo: function (cell) {
  213. let flipX = null;
  214. if ((cell ^ 0x80000000) > 0) {
  215. flipX = true;
  216. cell = cell ^ 0x80000000;
  217. }
  218. let firstGid = 0;
  219. let sheetName = null;
  220. for (let s = 0; s < mapFile.tilesets.length; s++) {
  221. let tileset = mapFile.tilesets[s];
  222. if (tileset.firstgid <= cell) {
  223. sheetName = tileset.name;
  224. firstGid = tileset.firstgid;
  225. }
  226. }
  227. cell = cell - firstGid + 1;
  228. return {
  229. sheetName: sheetName,
  230. cell: cell,
  231. flipX: flipX
  232. };
  233. },
  234. tile: function (layerName, cell, i) {
  235. let y = ~~(i / this.size.w);
  236. let x = i - (y * this.size.w);
  237. if (cell === 0) {
  238. if (layerName === 'tiles')
  239. this.collisionMap[x][y] = 1;
  240. return;
  241. }
  242. let cellInfo = this.builders.getCellInfo(cell);
  243. let sheetName = cellInfo.sheetName;
  244. cell = cellInfo.cell;
  245. if (sheetName === 'walls')
  246. cell += 192;
  247. else if (sheetName === 'objects')
  248. cell += 448;
  249. if ((layerName !== 'hiddenWalls') && (layerName !== 'hiddenTiles')) {
  250. let layer = this.layers;
  251. if (this.oldLayers[layerName])
  252. this.oldLayers[layerName][x][y] = cell;
  253. layer[x][y] = (layer[x][y] === null) ? cell : layer[x][y] + ',' + cell;
  254. } else if (layerName === 'hiddenWalls')
  255. this.hiddenWalls[x][y] = cell;
  256. else if (layerName === 'hiddenTiles')
  257. this.hiddenTiles[x][y] = cell;
  258. if (layerName.indexOf('walls') > -1)
  259. this.collisionMap[x][y] = 1;
  260. else if (sheetName.toLowerCase().indexOf('tiles') > -1) {
  261. //Check for water and water-like tiles
  262. if ([6, 7, 54, 55, 62, 63, 154, 189, 190].indexOf(cell) > -1)
  263. this.collisionMap[x][y] = 1;
  264. }
  265. },
  266. object: function (layerName, cell) {
  267. //Fixes for newer versions of tiled
  268. cell.properties = objectifyProperties(cell.properties);
  269. cell.polyline = cell.polyline || cell.polygon;
  270. let clientObj = (layerName === 'clientObjects');
  271. let cellInfo = this.builders.getCellInfo(cell.gid);
  272. let name = (cell.name || '');
  273. let objZoneName = name;
  274. if (name.indexOf('|') > -1) {
  275. let split = name.split('|');
  276. name = split[0];
  277. objZoneName = split[1];
  278. }
  279. let blueprint = {
  280. clientObj: clientObj,
  281. sheetName: cellInfo.sheetName,
  282. cell: cellInfo.cell - 1,
  283. x: cell.x / mapScale,
  284. y: (cell.y / mapScale) - 1,
  285. name: name,
  286. properties: cell.properties || {},
  287. layerName: layerName
  288. };
  289. if (objZoneName !== name)
  290. blueprint.objZoneName = objZoneName;
  291. if (this.zone) {
  292. if ((this.zone.objects) && (this.zone.objects[objZoneName.toLowerCase()]))
  293. extend(blueprint, this.zone.objects[objZoneName.toLowerCase()]);
  294. else if ((this.zone.objects) && (this.zone.mobs[objZoneName.toLowerCase()]))
  295. extend(blueprint, this.zone.mobs[objZoneName.toLowerCase()]);
  296. }
  297. if (blueprint.blocking)
  298. this.collisionMap[blueprint.x][blueprint.y] = 1;
  299. if ((blueprint.properties.cpnNotice) || (blueprint.properties.cpnLightPatch) || (layerName === 'rooms') || (layerName === 'hiddenRooms')) {
  300. blueprint.y++;
  301. blueprint.width = cell.width / mapScale;
  302. blueprint.height = cell.height / mapScale;
  303. } else if (cell.width === 24)
  304. blueprint.x++;
  305. if (cell.polyline)
  306. mapObjects.polyline(this.size, blueprint, cell, mapScale);
  307. if (layerName === 'rooms') {
  308. if (blueprint.properties.exit) {
  309. let room = this.rooms.find(function (r) {
  310. return (!(
  311. (blueprint.x + blueprint.width < r.x) ||
  312. (blueprint.y + blueprint.height < r.y) ||
  313. (blueprint.x >= r.x + r.width) ||
  314. (blueprint.y >= r.y + r.height)
  315. ));
  316. });
  317. room.exits.push(blueprint);
  318. } else if (blueprint.properties.resource)
  319. resourceSpawner.register(blueprint.properties.resource, blueprint);
  320. else {
  321. blueprint.exits = [];
  322. blueprint.objects = [];
  323. this.rooms.push(blueprint);
  324. }
  325. } else if (layerName === 'hiddenRooms') {
  326. blueprint.fog = (cell.properties || {}).fog;
  327. blueprint.discoverable = (cell.properties || {}).discoverable;
  328. this.hiddenRooms.push(blueprint);
  329. } else if (!clientObj) {
  330. if (!mapFile.properties.isRandom)
  331. spawners.register(blueprint, blueprint.spawnCd || mapFile.properties.spawnCd);
  332. else {
  333. let room = this.rooms.find(function (r) {
  334. return (!(
  335. (blueprint.x < r.x) ||
  336. (blueprint.y < r.y) ||
  337. (blueprint.x >= r.x + r.width) ||
  338. (blueprint.y >= r.y + r.height)
  339. ));
  340. });
  341. room.objects.push(blueprint);
  342. }
  343. } else {
  344. if ((cell.width) && (!cell.polyline)) {
  345. blueprint.width = cell.width / mapScale;
  346. blueprint.height = cell.height / mapScale;
  347. }
  348. let obj = objects.buildObjects([blueprint], true).getSimple(true);
  349. this.objBlueprints.push(obj);
  350. }
  351. }
  352. },
  353. getSpawnPos: function (obj) {
  354. let stats = obj.components.find(c => (c.type === 'stats'));
  355. let level = stats.values.level;
  356. let spawns = this.spawn.filter(s => (((s.maxLevel) && (s.maxLevel >= level)) || (!s.maxLevel)));
  357. return spawns[0];
  358. }
  359. };