RoomRandomMap.ts 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. /// <reference path="../Room.ts" />
  2. /// <reference path="RoomRandom.ts" />
  3. interface MapCoordinates {
  4. x : number;
  5. y : number;
  6. z : number;
  7. }
  8. class RoomRandomMap {
  9. private positionTable : {[x : number] : {[y : number] : RoomRandom}} = {};
  10. private roomMap = new Map<Room, Array<number>>();
  11. public lowestX = 0;
  12. public lowestY = 0;
  13. public highestX = 0;
  14. public highestY = 0;
  15. public limitsInvalid = false;
  16. /**
  17. * This is a count of how many connections are actually available, assuming rooms that can connect through some direction.
  18. * @type {number}
  19. */
  20. public availableConnections : Array<Array<MapCoordinates>>;
  21. /**
  22. * This is a count of rooms since the last cache clear. Used to mean more, but now is just a count of how many rooms were placed from the current region.
  23. * @type {number}
  24. */
  25. public rooms;
  26. /**
  27. * Clears the current room cache and creates a new one that is empty
  28. */
  29. public emptyCache () {
  30. this.availableConnections = [];
  31. Room.DIRECTIONS.forEach(() => {
  32. this.availableConnections.push([]);
  33. });
  34. this.rooms = 0;
  35. }
  36. public getAvailableConnections () {
  37. return this.availableConnections.reduce((previousValue, currentValue, currentIndex, array) => {
  38. return previousValue + (currentValue.length);
  39. }, 0);
  40. }
  41. public removeFromCache (coordinatesToRemove : MapCoordinates, direction : number) {
  42. let directionArray = this.availableConnections[direction];
  43. for (let k = 0, coordinates = directionArray[k]; coordinates != undefined; coordinates = directionArray[++k]) {
  44. if (coordinates.x == coordinatesToRemove.x && coordinates.y == coordinatesToRemove.y) {
  45. directionArray.splice(k, 1);
  46. return;
  47. }
  48. }
  49. }
  50. public addToCache (coordinatesToAdd : MapCoordinates, direction : number) {
  51. let directionArray = this.availableConnections[direction];
  52. for (let k = 0, coordinates = directionArray[k]; coordinates != undefined; coordinates = directionArray[++k]) {
  53. if (coordinates.x == coordinatesToAdd.x && coordinates.y == coordinatesToAdd.y) {
  54. return;
  55. }
  56. }
  57. directionArray.push(coordinatesToAdd);
  58. }
  59. public getAnyFromCache (direction : number) : RoomRandom {
  60. let array = this.availableConnections[direction];
  61. if (array.length > 0) {
  62. let randomIndex = Math.floor(Math.random() * (array.length));
  63. let randomCoordinates = array[randomIndex];
  64. if (randomCoordinates != undefined) {
  65. return this.getRoom(randomCoordinates.x, randomCoordinates.y);
  66. }
  67. }
  68. }
  69. public isFree (x : number, y : number) {
  70. return (this.positionTable[x] == undefined || this.positionTable[x][y] === undefined);
  71. }
  72. public isFreeSquare (centerX : number, centerY : number, distanceFromCenter : number) {
  73. for (let x = centerX - distanceFromCenter; x <= centerX + distanceFromCenter; x++) {
  74. for (let y = centerY - distanceFromCenter; y <= centerY + distanceFromCenter; y++) {
  75. if (!this.isFree(x,y)) {
  76. return false;
  77. }
  78. }
  79. }
  80. return true;
  81. }
  82. public block (x : number, y : number) {
  83. if (this.isFree(x, y)) {
  84. if (this.positionTable[x] == undefined) {
  85. this.positionTable[x] = {};
  86. }
  87. this.positionTable[x][y] = null;
  88. this.updateCacheOnPosition(x, y);
  89. this.updateLimits(x, y);
  90. }
  91. }
  92. public updateAllLimits () {
  93. this.highestX = 0;
  94. this.highestY = 0;
  95. this.lowestX = 0;
  96. this.lowestY = 0;
  97. for (let x in this.positionTable) {
  98. for (let y in this.positionTable[x]) {
  99. if (this.positionTable[x][y] != undefined && this.positionTable[x][y] != null) {
  100. this.updateLimits(parseInt(x), parseInt(y));
  101. }
  102. }
  103. }
  104. this.limitsInvalid = false;
  105. }
  106. public updateLimits (x, y) {
  107. if (x > this.highestX) this.highestX = x;
  108. if (y > this.highestY) this.highestY = y;
  109. if (y < this.lowestY) this.lowestY = y;
  110. if (x < this.lowestX) this.lowestX = x;
  111. }
  112. public map (room : RoomRandom, x : number, y : number) {
  113. if (this.positionTable[x] == undefined) {
  114. this.positionTable[x] = {};
  115. }
  116. this.positionTable[x][y] = room;
  117. this.roomMap.set(room, [x, y]);
  118. this.updateCacheOnPosition(x, y);
  119. // If we ever want to draw maps, this will be useful
  120. this.updateLimits(x, y);
  121. room.placed = true;
  122. room.lastMap = this;
  123. this.rooms++;
  124. }
  125. public unmap (x : number, y : number) {
  126. if (this.positionTable[x] != undefined && this.positionTable[x][y] != undefined) {
  127. let room = this.positionTable[x][y];
  128. room.placed = false;
  129. this.roomMap.delete(this.positionTable[x][y]);
  130. delete (this.positionTable[x][y]);
  131. this.rooms--;
  132. this.updateCacheOnPosition(x, y);
  133. this.limitsInvalid = true;
  134. }
  135. }
  136. private updateCacheOnPosition (x : number, y : number) {
  137. let coordinates = [x, y, 0];
  138. let coordinatesMap = <MapCoordinates> {x : x, y : y};
  139. let coordinatesBlocked = !this.isFree(x, y);
  140. let coordinatesRoom = this.getRoom(x, y);
  141. Room.DIRECTIONS.forEach(direction => {
  142. let oppositeDirection = OppositeDirection[Direction[direction]];
  143. let shifted = Room.shift(coordinates, direction);
  144. let shiftedMap = <MapCoordinates> {x : shifted[0], y : shifted[1]};
  145. let shiftedBlocked = !this.isFree(shifted[0], shifted[1]);
  146. let shiftedRoom = this.getRoom(shifted[0], shifted[1]);
  147. if (coordinatesRoom != undefined) {
  148. if (shiftedBlocked) {
  149. this.removeFromCache(coordinatesMap, direction);
  150. } else if (coordinatesRoom.isConnectableOn(direction)) {
  151. this.addToCache(coordinatesMap, direction);
  152. }
  153. } else {
  154. this.removeFromCache(coordinatesMap, direction);
  155. }
  156. if (shiftedRoom != undefined) {
  157. if (coordinatesBlocked) {
  158. this.removeFromCache(shiftedMap, oppositeDirection);
  159. } else if (shiftedRoom.isConnectableOn(oppositeDirection)) {
  160. this.addToCache(shiftedMap, oppositeDirection);
  161. }
  162. } else {
  163. this.removeFromCache(shiftedMap, oppositeDirection);
  164. }
  165. });
  166. }
  167. public getRoom (x : number, y : number) {
  168. if (this.positionTable[x] != undefined) {
  169. if (this.positionTable[x][y] != null) {
  170. return this.positionTable[x][y];
  171. }
  172. }
  173. return undefined;
  174. }
  175. public getCoordinates (room : Room) : Array<number> {
  176. return this.roomMap.get(room);
  177. }
  178. public getRoomCount () {
  179. return this.roomMap.size;
  180. }
  181. public getWidth () {
  182. return this.highestX - this.lowestX;
  183. }
  184. public getHeight () {
  185. return this.highestY - this.lowestY;
  186. }
  187. public static PREFERRED_GROWTH_HORIZONTAL = 0;
  188. public static PREFERRED_GROWTH_VERTICAL = 1;
  189. public static PREFERRED_GROWTH_ANY = 2;
  190. public getPreferredGrowth () {
  191. let ratio = this.getHeight() / this.getWidth();
  192. let idealRatio = 2.5; // This means we'd prefer a tall map that'd look good on our screen
  193. let difference = Math.abs(ratio - idealRatio);
  194. if (difference < 0.5) {
  195. return RoomRandomMap.PREFERRED_GROWTH_ANY;
  196. } else {
  197. if (ratio < idealRatio) {
  198. return RoomRandomMap.PREFERRED_GROWTH_VERTICAL;
  199. } else {
  200. return RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL;
  201. }
  202. }
  203. }
  204. public static isDirectionPreferred (direction : number, growth : number) {
  205. if (growth == RoomRandomMap.PREFERRED_GROWTH_ANY) {
  206. return true;
  207. } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
  208. return growth == RoomRandomMap.PREFERRED_GROWTH_VERTICAL;
  209. } else {
  210. return growth == RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL;
  211. }
  212. }
  213. }