Room.ts 9.0 KB

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