Room.ts 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /// <reference path="../../Elements/Classes/Say.ts" />
  2. enum Direction {
  3. NORTH, NORTHEAST, EAST,
  4. SOUTHEAST, SOUTH, SOUTHWEST,
  5. WEST, NORTHWEST, UP, DOWN
  6. }
  7. var DirectionNames : {[id: string] : string} = (() => {
  8. enum names {
  9. NORTH = "North",
  10. SOUTH = "South",
  11. EAST = "East",
  12. WEST = "West",
  13. SOUTHEAST = "Southeast",
  14. NORTHWEST = "Northwest",
  15. SOUTHWEST = "Southwest",
  16. NORTHEAST = "Northeast",
  17. UP = "Down",
  18. DOWN = "Up"
  19. };
  20. let obj : {[id: string] : string} = {};
  21. for (let name in names) {
  22. obj[name] = names[name];
  23. obj[Direction[name]] = names[name];
  24. }
  25. return obj;
  26. })();
  27. var OppositeDirection : {[id : number] : Direction} = (() => {
  28. let obj = {};
  29. obj[Direction.NORTH] = Direction.SOUTH;
  30. obj[Direction.SOUTH] = Direction.NORTH;
  31. obj[Direction.EAST] = Direction.WEST;
  32. obj[Direction.WEST] = Direction.EAST;
  33. obj[Direction.SOUTHEAST] = Direction.NORTHWEST;
  34. obj[Direction.NORTHWEST] = Direction.SOUTHEAST;
  35. obj[Direction.SOUTHWEST] = Direction.NORTHEAST;
  36. obj[Direction.NORTHEAST] = Direction.SOUTHWEST;
  37. obj[Direction.UP] = Direction.DOWN;
  38. obj[Direction.DOWN] = Direction.UP;
  39. // Make it work with the name too
  40. for (let i = 0; i < Object.keys(Direction).length / 2; i++) {
  41. obj[Direction[i]] = obj[i];
  42. }
  43. return obj;
  44. })();
  45. class Room implements Printable {
  46. protected name : string;
  47. public connections : Array<Room>;
  48. public description : Say = new Say();
  49. public fodder : boolean;
  50. public constructor (id? : string, fodder? : boolean) {
  51. this.name = id == undefined ? "Room" : id;
  52. this.connections = new Array(Room.DIRECTIONS.length); // Array the same size as directions, but filled with undefined
  53. this.fodder = fodder;
  54. if (fodder != true) {
  55. Room.addRoom(this);
  56. }
  57. }
  58. public getName () {
  59. return this.name;
  60. }
  61. public place (thing : Thing) {
  62. Thing.InsideRoomRelation.setRelation(this, thing);
  63. }
  64. public remove (thing : Thing) {
  65. // Don't remove stuff from other rooms
  66. if (Thing.InsideRoomRelation.getLeft(thing) == this) {
  67. Thing.InsideRoomRelation.unsetRight(thing);
  68. }
  69. }
  70. public getContained () : Array<Thing> {
  71. return <Array<Thing>> Thing.InsideRoomRelation.getRight(this);
  72. }
  73. public getContainedAndVisibleTo (observer : Thing) : Array<Thing> {
  74. let contained = this.getContained();
  75. let result = [];
  76. contained.forEach((value) => {
  77. if (value.visible && value !== observer) {
  78. result.push(value);
  79. }
  80. });
  81. return result;
  82. }
  83. public static DIRECTIONS : Array<Direction> = (() => {
  84. let directions : Array<Direction> = [];
  85. for (let i = 0; i < Object.keys(Direction).length / 2; i++) {
  86. directions.push(i);
  87. }
  88. return directions;
  89. })();
  90. public getContainedAndVisible () : Array<Thing> {
  91. return this.getContainedAndVisibleTo(WorldState.player);
  92. }
  93. public mapRoom (r : Room, direction : Direction) {
  94. let oppositeDirection = OppositeDirection[direction];
  95. if (this.connections[direction] != undefined) {
  96. console.warn("Replacing a connected room.", this, " connected through ", direction, " to ", this.connections[direction]);
  97. this.connections[direction].unmapRoom(oppositeDirection);
  98. }
  99. this.connections[direction] = r;
  100. if (r.connections[oppositeDirection] != undefined) {
  101. console.warn("Replacing a connected room.", r, " connected through ", oppositeDirection, " to ", r.connections[oppositeDirection]);
  102. r.unmapRoom(oppositeDirection);
  103. }
  104. r.connections[oppositeDirection] = this;
  105. }
  106. public unmapRoom (direction : Direction) {
  107. if (this.connections[direction] != undefined) {
  108. let r = this.connections[direction];
  109. this.connections[direction] = undefined;
  110. r.unmapRoom(OppositeDirection[direction]);
  111. }
  112. }
  113. public getPrintedName () {
  114. return this.name;
  115. }
  116. public getConnectedRooms () : Array<Room> {
  117. let rooms = [];
  118. this.connections.forEach(room => {
  119. if (room != undefined) {
  120. rooms.push(room);
  121. }
  122. });
  123. return rooms;
  124. }
  125. /**
  126. * This returns the best direction to follow if going from the current room to another room.
  127. * THIS CODE IS REALLY EXPENSIVE AND SHOULD ONLY BE USED AS A LAST RESORT
  128. * WARNING: THIS CODE WILL FAIL IF THE TARGET ROOM IS TOO FAR FROM THE CURRENT ROOM (FOR SECURITY REASONS).
  129. * This code runs through every. single. room. to find the best route to take.
  130. * If you need an NPC to stick to a region, don't let it go out of it in the first place!
  131. * @param room
  132. * @param validityCode
  133. * @returns {any}
  134. */
  135. // TODO: Make this shit fast
  136. public bestDirectionTo (room : Room, validityCode? : (room : Room) => boolean) {
  137. if (validityCode == undefined) validityCode = () => {return true};
  138. /**
  139. * Maximum amount of steps that will be considered for a route.
  140. * This is useful to prevent the code from spanning too many rooms, as each room can have Room.DIRECTIONS.length directions to make another call, etc.
  141. *
  142. * @type {number}
  143. */
  144. let maxSteps = 10;
  145. maxSteps = maxSteps > WorldState.getMaximumRememberedRooms() ? maxSteps : WorldState.getMaximumRememberedRooms();
  146. let recursiveBestPath = (cPath : Array<Room>, cRoom : Room, destination : Room) => {
  147. // Ignore "bad" rooms
  148. if (!validityCode(cRoom)) {
  149. return;
  150. }
  151. // Prevent the code from straying too far
  152. if (cRoom == destination) {
  153. maxSteps = maxSteps > cPath.length ? cPath.length : maxSteps; // Stop considering worse routes
  154. return cPath;
  155. } else if (cPath.length > maxSteps) {
  156. return undefined;
  157. } else {
  158. let paths = [];
  159. for (let index in Room.DIRECTIONS) {
  160. let direction = Room.DIRECTIONS[index];
  161. let nextRoom = cRoom.connections[direction];
  162. if (nextRoom != undefined && cPath.indexOf(nextRoom) == -1 && validityCode(nextRoom)) {
  163. let path = recursiveBestPath(cPath.concat([nextRoom]), nextRoom, destination);
  164. if (path != undefined) {
  165. paths.push(path);
  166. }
  167. }
  168. }
  169. let shortestIndex = 0;
  170. paths.forEach((value, index, array) => {
  171. if (value.length < paths[shortestIndex].length) {
  172. shortestIndex = index;
  173. }
  174. });
  175. return paths[shortestIndex];
  176. }
  177. };
  178. let paths = Array(Room.DIRECTIONS.length);
  179. let shortestIndex;
  180. for (let index in Room.DIRECTIONS) {
  181. let direction = Room.DIRECTIONS[index];
  182. let nextRoom = this.connections[direction];
  183. if (nextRoom != undefined) {
  184. paths[direction] = recursiveBestPath([this, nextRoom], nextRoom, room);
  185. if (paths[direction] != undefined && (shortestIndex == undefined || paths[shortestIndex].length > paths[direction].length)) {
  186. shortestIndex = direction;
  187. }
  188. }
  189. }
  190. return shortestIndex;
  191. }
  192. public static getDirectionXYZ (direction : Direction) {
  193. var y = 0;
  194. if ([Direction.NORTH, Direction.NORTHEAST, Direction.NORTHWEST].indexOf(direction) != -1) {
  195. y = 1;
  196. } else if ([Direction.SOUTH, Direction.SOUTHEAST, Direction.SOUTHWEST].indexOf(direction) != -1) {
  197. y = -1;
  198. }
  199. var x = 0;
  200. if ([Direction.EAST, Direction.SOUTHEAST, Direction.NORTHEAST].indexOf(direction) != -1) {
  201. x = 1;
  202. } else if ([Direction.WEST, Direction.SOUTHWEST, Direction.NORTHWEST].indexOf(direction) != -1) {
  203. x = -1;
  204. }
  205. var z = direction == Direction.UP ? 1 :
  206. direction == Direction.DOWN ? -1 :
  207. 0;
  208. return [x, y, z];
  209. }
  210. public static shift (coordinates : Array<number>, direction : number) {
  211. let coordinatesVector = Room.getDirectionXYZ(direction);
  212. coordinates.forEach((value, index, array) => {
  213. coordinatesVector[index] += coordinates[index];
  214. });
  215. return coordinatesVector;
  216. }
  217. protected static rooms : {[id : string] : Room} = {};
  218. protected static addRoom (room : Room) {
  219. Room.rooms[room.name] = room;
  220. }
  221. public static getRooms () : Array<Room> {
  222. let rooms = [];
  223. for (let name in Room.rooms) {
  224. rooms.push(Room.rooms[name]);
  225. }
  226. return rooms;
  227. }
  228. public static getRoom (id : string) {
  229. return Room.rooms[id];
  230. }
  231. }