Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 

522 linhas
13 KiB

  1. define([
  2. ], function(
  3. ) {
  4. return {
  5. templates: null,
  6. tileMappings: {},
  7. gapMappings: {},
  8. rooms: [],
  9. exitAreas: [],
  10. maxDistance: 14,
  11. minDistance: 0,
  12. bounds: [0, 0, 0, 0],
  13. generate: function(instance) {
  14. this.rooms = [];
  15. this.exitAreas = [];
  16. this.tileMappings = {};
  17. this.bounds = [0, 0, 0, 0];
  18. this.templates = extend(true, [], instance.map.rooms);
  19. this.setupTemplates(instance.map);
  20. this.generateMappings(instance.map);
  21. var startTemplate = this.templates.filter(t => t.properties.start);
  22. startTemplate = startTemplate[this.randInt(0, startTemplate.length)];
  23. var startRoom = this.buildRoom(startTemplate);
  24. if (!this.isValidDungeon())
  25. this.generate(instance);
  26. else {
  27. this.offsetRooms(startRoom);
  28. this.buildMap(instance, startRoom);
  29. }
  30. },
  31. isValidDungeon: function() {
  32. var endRooms = this.rooms.filter(r => r.connections.length == 0);
  33. var endDistanceReached = endRooms.find(r => r.distance == this.maxDistance, this);
  34. if (!endDistanceReached)
  35. return false;
  36. var valid = true;
  37. endRooms
  38. .forEach(function(r) {
  39. if (r.distance < this.minDistance)
  40. valid = false;
  41. else if (r.distance > this.maxDistance)
  42. valid = false;
  43. }, this);
  44. return valid;
  45. },
  46. setupTemplates: function(map) {
  47. this.templates.forEach(function(r, typeId) {
  48. if (r.properties.mapping)
  49. return;
  50. r.typeId = typeId;
  51. for (var i = 0; i < 2; i++) {
  52. for (var j = 0; j < 2; j++) {
  53. for (var k = 0; k < 2; k++) {
  54. if (i + j + k == 0)
  55. continue;
  56. var flipped = extend(true, {
  57. flipX: !!i,
  58. flipY: !!j,
  59. rotate: !!k
  60. }, r);
  61. flipped.exits.forEach(function(e) {
  62. var direction = JSON.parse(e.properties.exit);
  63. if (flipped.flipX) {
  64. direction[0] *= -1;
  65. e.x = r.x + r.width - (e.x - r.x) - e.width;
  66. }
  67. if (flipped.flipY) {
  68. direction[1] *= -1;
  69. e.y = r.y + r.height - (e.y - r.y) - e.height;
  70. }
  71. if (flipped.rotate) {
  72. direction = [direction[1], direction[0]];
  73. var t = e.x;
  74. e.x = r.x + (e.y - r.y);
  75. e.y = r.y + (t - r.x);
  76. t = e.width;
  77. e.width = e.height;
  78. e.height = t;
  79. }
  80. e.properties.exit = JSON.stringify(direction);
  81. });
  82. flipped.objects.forEach(function(o) {
  83. if (flipped.flipX)
  84. o.x = r.x + r.width - (o.x - r.x) - 1;
  85. if (flipped.flipY)
  86. o.y = r.y + r.height - (o.y - r.y) - 1;
  87. if (flipped.rotate) {
  88. var t = o.x;
  89. o.x = r.x + (o.y - r.y);
  90. o.y = r.y + (t - r.x);
  91. }
  92. });
  93. if (flipped.rotate) {
  94. var t = flipped.width;
  95. flipped.width = flipped.height;
  96. flipped.height = t;
  97. }
  98. this.templates.push(flipped);
  99. }
  100. }
  101. }
  102. }, this);
  103. this.templates.forEach(function(r) {
  104. var rotate = r.rotate;
  105. var w = rotate ? r.height : r.width;
  106. var h = rotate ? r.width : r.height;
  107. r.map = _.get2dArray(r.width, r.height);
  108. r.tiles = _.get2dArray(r.width, r.height);
  109. r.collisionMap = _.get2dArray(r.width, r.height);
  110. r.oldExits = extend(true, [], r.exits);
  111. for (var i = 0; i < w; i++) {
  112. for (var j = 0; j < h; j++) {
  113. var ii = rotate ? j : i;
  114. var jj = rotate ? i : j;
  115. var x = r.flipX ? (r.x + w - i - 1) : (r.x + i);
  116. var y = r.flipY ? (r.y + h - j - 1) : (r.y + j);
  117. r.map[ii][jj] = map.oldMap[x][y];
  118. r.tiles[ii][jj] = map.oldLayers.tiles[x][y];
  119. r.collisionMap[ii][jj] = map.oldCollisionMap[x][y];
  120. }
  121. }
  122. });
  123. },
  124. generateMappings: function(map) {
  125. var oldMap = map.oldMap;
  126. this.templates
  127. .filter(r => r.properties.mapping)
  128. .forEach(function(m) {
  129. var x = m.x;
  130. var y = m.y;
  131. var w = m.width;
  132. var h = m.height;
  133. var baseTile = oldMap[x][y];
  134. baseTile = baseTile
  135. .replace('0,', '')
  136. .replace(',', '');
  137. var mapping = null;
  138. if ((!m.properties.wall) && (!m.properties.floor))
  139. mapping = this.tileMappings[baseTile] = [];
  140. else
  141. mapping = this.gapMappings[baseTile] = [];
  142. for (var i = x + 2; i < x + w; i++) {
  143. for (var j = y; j < y + h; j++) {
  144. var oM = oldMap[i][j];
  145. if (oM.replace) {
  146. oM = oM
  147. .replace('0,', '')
  148. .replace(',', '');
  149. }
  150. mapping.push(oM);
  151. }
  152. }
  153. }, this);
  154. },
  155. buildMap: function(instance, startRoom) {
  156. var w = this.bounds[2] - this.bounds[0];
  157. var h = this.bounds[3] - this.bounds[1];
  158. var map = instance.map;
  159. var clientMap = map.clientMap;
  160. clientMap.map = _.get2dArray(w, h);
  161. clientMap.collisionMap = _.get2dArray(w, h);
  162. var startTemplate = startRoom.template;
  163. map.spawn = [{
  164. x: startRoom.x + ~~(startTemplate.width / 2),
  165. y: startRoom.y + ~~(startTemplate.height / 2)
  166. }];
  167. this.drawRoom(instance, startRoom);
  168. this.fillGaps(instance);
  169. instance.physics.init(clientMap.collisionMap);
  170. this.spawnObjects(instance, startRoom);
  171. },
  172. fillGaps: function(instance) {
  173. var map = instance.map.clientMap.map;
  174. var oldMap = instance.map.oldMap;
  175. var w = map.length;
  176. var h = map[0].length;
  177. var len = w * h / 120;
  178. var floorTile = this.templates.find(t => t.properties.floor);
  179. floorTile = oldMap[floorTile.x][floorTile.y];
  180. var wallTile = this.templates.find(t => t.properties.wall);
  181. wallTile = oldMap[wallTile.x][wallTile.y];
  182. for (var i = 0; i < len; i++) {
  183. var xMin = this.randInt(0, w);
  184. var yMin = this.randInt(0, h);
  185. var xMax = Math.min(w, xMin + this.randInt(2, 7));
  186. var yMax = Math.min(h, yMin + this.randInt(2, 7));
  187. for (var x = xMin; x < xMax; x++) {
  188. for (var y = yMin; y < yMax; y++) {
  189. if (map[x][y])
  190. continue;
  191. if (this.randInt(0, 10) < 6) {
  192. if (this.randInt(0, 10) < 3)
  193. map[x][y] = this.randomizeTile(wallTile, null, true);
  194. else
  195. map[x][y] = this.randomizeTile(floorTile, null, true);
  196. }
  197. }
  198. }
  199. }
  200. },
  201. randomizeTile: function(tile, floorTile, gapMapping) {
  202. var mapping = gapMapping ? this.gapMappings[tile] : this.tileMappings[tile];
  203. if (!mapping)
  204. return tile;
  205. tile = mapping[this.randInt(0, mapping.length)];
  206. if (!tile) {
  207. if (floorTile)
  208. return this.randomizeTile(floorTile);
  209. else
  210. return 0;
  211. }
  212. return tile;
  213. },
  214. drawRoom: function(instance, room) {
  215. var map = instance.map.clientMap.map;
  216. var template = room.template;
  217. var collisionMap = instance.map.clientMap.collisionMap;
  218. for (var i = 0; i < template.width; i++) {
  219. var x = room.x + i;
  220. for (var j = 0; j < template.height; j++) {
  221. var y = room.y + j;
  222. var tile = template.map[i][j];
  223. if (!tile)
  224. continue;
  225. var currentTile = map[x][y];
  226. var collides = template.collisionMap[i][j];
  227. var floorTile = template.tiles[i][j];
  228. if (!currentTile) {
  229. map[x][y] = this.randomizeTile(tile, floorTile);
  230. collisionMap[x][y] = collides;
  231. continue;
  232. } else {
  233. //Remove objects from this position since it falls in another room
  234. template.objects.spliceWhere(function(o) {
  235. var ox = o.x - template.x + room.x;
  236. var oy = o.y - template.y + room.y;
  237. return ((ox == x) && (oy == y));
  238. });
  239. }
  240. var didCollide = collisionMap[x][y];
  241. if (collides) {
  242. if (didCollide) {
  243. var isExitTile = this.exitAreas.find(function(e) {
  244. return (!((x < e.x) || (y < e.y) || (x >= e.x + e.width) || (y >= e.y + e.height)));
  245. });
  246. if (isExitTile) {
  247. var isThisExit = template.oldExits.find(function(e) {
  248. var ex = room.x + (e.x - template.x);
  249. var ey = room.y + (e.y - template.y);
  250. return (!((x < ex) || (y < ey) || (x >= ex + e.width) || (y >= ey + e.height)));
  251. });
  252. if (isThisExit) {
  253. map[x][y] = this.randomizeTile(floorTile);
  254. collisionMap[x][y] = false;
  255. } else
  256. collisionMap[x][y] = true;
  257. }
  258. }
  259. } else if (didCollide) {
  260. collisionMap[x][y] = false;
  261. map[x][y] = this.randomizeTile(floorTile);
  262. }
  263. }
  264. }
  265. template.oldExits.forEach(function(e) {
  266. this.exitAreas.push({
  267. x: room.x + (e.x - template.x),
  268. y: room.y + (e.y - template.y),
  269. width: e.width,
  270. height: e.height
  271. });
  272. }, this);
  273. room.connections.forEach(c => this.drawRoom(instance, c), this);
  274. },
  275. spawnObjects: function(instance, room) {
  276. var template = room.template;
  277. var spawners = instance.spawners;
  278. var spawnCd = instance.map.mapFile.properties.spawnCd;
  279. var collisionMap = instance.map.clientMap.collisionMap;
  280. template.objects.forEach(function(o) {
  281. o.x = o.x - template.x + room.x;
  282. o.y = o.y - template.y + room.y;
  283. o.amount = 1;
  284. o.scaleDrops = true;
  285. spawners.register(o, spawnCd);
  286. });
  287. room.connections.forEach(c => this.spawnObjects(instance, c), this);
  288. },
  289. buildRoom: function(template, connectTo, templateExit, connectToExit, isHallway) {
  290. var room = {
  291. x: 0,
  292. y: 0,
  293. distance: 0,
  294. isHallway: isHallway,
  295. template: extend(true, {}, template),
  296. connections: []
  297. };
  298. if (connectTo) {
  299. room.x = connectTo.x + connectToExit.x - connectTo.template.x + (template.x - templateExit.x);
  300. room.y = connectTo.y + connectToExit.y - connectTo.template.y + (template.y - templateExit.y);
  301. room.distance = connectTo.distance + 1;
  302. room.parent = connectTo;
  303. }
  304. if (this.doesCollide(room, connectTo))
  305. return false;
  306. if (connectTo)
  307. connectTo.connections.push(room);
  308. this.rooms.push(room);
  309. this.updateBounds(room);
  310. if (room.distance < this.maxDistance) {
  311. var count = this.randInt(1, room.template.exits.length);
  312. for (var i = 0; i < count; i++) {
  313. this.setupConnection(room, !isHallway);
  314. }
  315. }
  316. if ((isHallway) && (room.connections.length == 0)) {
  317. this.rooms.spliceWhere(r => r == room);
  318. room.parent.connections.spliceWhere(c => c == room);
  319. return false;
  320. }
  321. return room;
  322. },
  323. setupConnection: function(fromRoom, isHallway) {
  324. if (fromRoom.template.exits.length == 0)
  325. return true;
  326. var fromExit = fromRoom.template.exits.splice(this.randInt(0, fromRoom.template.exits.length), 1)[0];
  327. var exitDirection = JSON.parse(fromExit.properties.exit);
  328. var templates = this.templates.filter(function(t) {
  329. if (
  330. (t.properties.mapping) ||
  331. (!!t.properties.hallway != isHallway) ||
  332. (t.properties.start) ||
  333. (
  334. (t.properties.end) &&
  335. (fromRoom.distance + 1 != this.maxDistance)
  336. )
  337. )
  338. return false;
  339. else {
  340. var isValid = t.exits.some(function(e) {
  341. var direction = JSON.parse(e.properties.exit);
  342. return ((direction[0] == -exitDirection[0]) && (direction[1] == -exitDirection[1]));
  343. });
  344. if ((isValid) && (t.properties.maxOccur)) {
  345. var occurs = this.rooms.filter(r => (r.template.typeId == t.typeId)).length;
  346. if (occurs >= ~~t.properties.maxOccur)
  347. isValid = false;
  348. }
  349. if ((isValid) && (fromRoom.distance + 1 == this.maxDistance)) {
  350. //If there is an exit available, rather use that
  351. if (!t.properties.end) {
  352. var endsAvailable = this.templates.filter(function(tt) {
  353. if (!tt.properties.end)
  354. return false;
  355. else if (!~~tt.properties.maxOccur)
  356. return true;
  357. else if (this.rooms.filter(r => r.template.typeId == tt.typeId).length < ~~tt.properties.maxOccur)
  358. return true;
  359. }, this);
  360. if (endsAvailable.length > 0)
  361. isValid = false;
  362. }
  363. }
  364. return isValid;
  365. }
  366. }, this);
  367. if (templates.length == 0) {
  368. fromRoom.template.exits.push(fromExit);
  369. return false;
  370. }
  371. var template = extend(true, {}, templates[this.randInt(0, templates.length)]);
  372. var templateExit = template.exits.filter(function(e) {
  373. var direction = JSON.parse(e.properties.exit);
  374. return ((direction[0] == -exitDirection[0]) && (direction[1] == -exitDirection[1]));
  375. });
  376. templateExit = templateExit[this.randInt(0, templateExit.length)];
  377. var exitIndex = template.exits.firstIndex(e => e == templateExit);
  378. template.exits.splice(exitIndex, 1);
  379. var success = this.buildRoom(template, fromRoom, templateExit, fromExit, isHallway);
  380. if (!success) {
  381. fromRoom.template.exits.push(fromExit);
  382. return false;
  383. }
  384. return true;
  385. },
  386. offsetRooms: function(room) {
  387. var bounds = this.bounds;
  388. var dx = (this.bounds[0] < 0) ? -bounds[0] : 0;
  389. var dy = (this.bounds[1] < 0) ? -bounds[1] : 0;
  390. this.performOffset(room, dx, dy);
  391. this.bounds = [bounds[0] + dx, bounds[1] + dy, bounds[2] + dx, bounds[3] + dy];
  392. },
  393. performOffset: function(room, dx, dy) {
  394. room.x += dx;
  395. room.y += dy;
  396. room.connections.forEach(c => this.performOffset(c, dx, dy), this);
  397. },
  398. updateBounds: function(room) {
  399. this.bounds[0] = Math.min(this.bounds[0], room.x);
  400. this.bounds[1] = Math.min(this.bounds[1], room.y);
  401. this.bounds[2] = Math.max(this.bounds[2], room.x + room.template.width);
  402. this.bounds[3] = Math.max(this.bounds[3], room.y + room.template.height);
  403. },
  404. doesCollide: function(room, ignore) {
  405. for (var i = 0; i < this.rooms.length; i++) {
  406. var r = this.rooms[i];
  407. if (r == ignore)
  408. continue;
  409. var collides = (!(
  410. (room.x + room.template.width < r.x) ||
  411. (room.y + room.template.height < r.y) ||
  412. (room.x >= r.x + r.template.width) ||
  413. (room.y >= r.y + r.template.height)
  414. ));
  415. if (collides)
  416. return true;
  417. }
  418. return false;
  419. },
  420. randInt: function(min, max) {
  421. return ~~(Math.random() * (max - min)) + min;
  422. }
  423. };
  424. });