RoomRandomMap.ts 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 block (x : number, y : number) {
  73. if (this.isFree(x, y)) {
  74. if (this.positionTable[x] == undefined) {
  75. this.positionTable[x] = {};
  76. }
  77. this.positionTable[x][y] = null;
  78. this.updateCacheOnPosition(x, y);
  79. this.updateLimits(x, y);
  80. }
  81. }
  82. public updateAllLimits () {
  83. this.highestX = 0;
  84. this.highestY = 0;
  85. this.lowestX = 0;
  86. this.lowestY = 0;
  87. for (let x in this.positionTable) {
  88. for (let y in this.positionTable[x]) {
  89. if (this.positionTable[x][y] != undefined && this.positionTable[x][y] != null) {
  90. this.updateLimits(parseInt(x), parseInt(y));
  91. }
  92. }
  93. }
  94. this.limitsInvalid = false;
  95. }
  96. public updateLimits (x, y) {
  97. if (x > this.highestX) this.highestX = x;
  98. if (y > this.highestY) this.highestY = y;
  99. if (y < this.lowestY) this.lowestY = y;
  100. if (x < this.lowestX) this.lowestX = x;
  101. }
  102. public map (room : RoomRandom, x : number, y : number) {
  103. if (this.positionTable[x] == undefined) {
  104. this.positionTable[x] = {};
  105. }
  106. this.positionTable[x][y] = room;
  107. this.roomMap.set(room, [x, y]);
  108. this.updateCacheOnPosition(x, y);
  109. // If we ever want to draw maps, this will be useful
  110. this.updateLimits(x, y);
  111. room.placed = true;
  112. room.lastMap = this;
  113. this.rooms++;
  114. }
  115. public unmap (x : number, y : number) {
  116. if (this.positionTable[x] != undefined && this.positionTable[x][y] != undefined) {
  117. let room = this.positionTable[x][y];
  118. room.placed = false;
  119. this.roomMap.delete(this.positionTable[x][y]);
  120. delete (this.positionTable[x][y]);
  121. this.rooms--;
  122. this.updateCacheOnPosition(x, y);
  123. this.limitsInvalid = true;
  124. }
  125. }
  126. private updateCacheOnPosition (x : number, y : number) {
  127. let coordinates = [x, y, 0];
  128. let coordinatesMap = <MapCoordinates> {x : x, y : y};
  129. let coordinatesBlocked = !this.isFree(x, y);
  130. let coordinatesRoom = this.getRoom(x, y);
  131. Room.DIRECTIONS.forEach(direction => {
  132. let oppositeDirection = OppositeDirection[Direction[direction]];
  133. let shifted = Room.shift(coordinates, direction);
  134. let shiftedMap = <MapCoordinates> {x : shifted[0], y : shifted[1]};
  135. let shiftedBlocked = !this.isFree(shifted[0], shifted[1]);
  136. let shiftedRoom = this.getRoom(shifted[0], shifted[1]);
  137. if (coordinatesRoom != undefined) {
  138. if (shiftedBlocked) {
  139. this.removeFromCache(coordinatesMap, direction);
  140. } else if (coordinatesRoom.isConnectableOn(direction)) {
  141. this.addToCache(coordinatesMap, direction);
  142. }
  143. } else {
  144. this.removeFromCache(coordinatesMap, direction);
  145. }
  146. if (shiftedRoom != undefined) {
  147. if (coordinatesBlocked) {
  148. this.removeFromCache(shiftedMap, oppositeDirection);
  149. } else if (shiftedRoom.isConnectableOn(oppositeDirection)) {
  150. this.addToCache(shiftedMap, oppositeDirection);
  151. }
  152. } else {
  153. this.removeFromCache(shiftedMap, oppositeDirection);
  154. }
  155. });
  156. }
  157. public getRoom (x : number, y : number) {
  158. if (this.positionTable[x] != undefined) {
  159. if (this.positionTable[x][y] != null) {
  160. return this.positionTable[x][y];
  161. }
  162. }
  163. return undefined;
  164. }
  165. public getCoordinates (room : Room) : Array<number> {
  166. return this.roomMap.get(room);
  167. }
  168. public getRoomCount () {
  169. return this.roomMap.size;
  170. }
  171. public getWidth () {
  172. return this.highestX - this.lowestX;
  173. }
  174. public getHeight () {
  175. return this.highestY - this.lowestY;
  176. }
  177. public static PREFERRED_GROWTH_HORIZONTAL = 0;
  178. public static PREFERRED_GROWTH_VERTICAL = 1;
  179. public static PREFERRED_GROWTH_ANY = 2;
  180. public getPreferredGrowth () {
  181. let ratio = this.getHeight() / this.getWidth();
  182. let idealRatio = 2.5; // This means we'd prefer a tall map that'd look good on our screen
  183. let difference = Math.abs(ratio - idealRatio);
  184. if (difference < 0.5) {
  185. return RoomRandomMap.PREFERRED_GROWTH_ANY;
  186. } else {
  187. if (ratio < idealRatio) {
  188. return RoomRandomMap.PREFERRED_GROWTH_VERTICAL;
  189. } else {
  190. return RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL;
  191. }
  192. }
  193. }
  194. public static isDirectionPreferred (direction : number, growth : number) {
  195. if (growth == RoomRandomMap.PREFERRED_GROWTH_ANY) {
  196. return true;
  197. } else if (direction == Direction.NORTH || direction == Direction.SOUTH) {
  198. return growth == RoomRandomMap.PREFERRED_GROWTH_VERTICAL;
  199. } else {
  200. return growth == RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL;
  201. }
  202. }
  203. }