/// enum Direction { NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST, NORTHWEST, UP, DOWN } var DirectionNames : {[id: string] : string} = (() => { enum names { NORTH = "North", SOUTH = "South", EAST = "East", WEST = "West", SOUTHEAST = "Southeast", NORTHWEST = "Northwest", SOUTHWEST = "Southwest", NORTHEAST = "Northeast", UP = "Down", DOWN = "Up" }; let obj : {[id: string] : string} = {}; for (let name in names) { obj[name] = names[name]; obj[Direction[name]] = names[name]; } return obj; })(); var OppositeDirection : {[id : number] : Direction} = (() => { let obj = {}; obj[Direction.NORTH] = Direction.SOUTH; obj[Direction.SOUTH] = Direction.NORTH; obj[Direction.EAST] = Direction.WEST; obj[Direction.WEST] = Direction.EAST; obj[Direction.SOUTHEAST] = Direction.NORTHWEST; obj[Direction.NORTHWEST] = Direction.SOUTHEAST; obj[Direction.SOUTHWEST] = Direction.NORTHEAST; obj[Direction.NORTHEAST] = Direction.SOUTHWEST; obj[Direction.UP] = Direction.DOWN; obj[Direction.DOWN] = Direction.UP; // Make it work with the name too for (let i = 0; i < Object.keys(Direction).length / 2; i++) { obj[Direction[i]] = obj[i]; } return obj; })(); class Room implements Printable { protected name : string; public connections : Array; public description : Say = new Say(); public fodder : boolean; public visited : boolean = false; public constructor (id? : string, fodder? : boolean) { this.name = id == undefined ? "Room" : id; this.connections = new Array(Room.DIRECTIONS.length); // Array the same size as directions, but filled with undefined this.fodder = fodder; if (fodder != true) { Room.addRoom(this); } } public getName () { return this.name; } public place (thing : Thing) { Thing.InsideRoomRelation.setRelation(this, thing); } public remove (thing : Thing) { // Don't remove stuff from other rooms if (Thing.InsideRoomRelation.getLeft(thing) == this) { Thing.InsideRoomRelation.unsetRight(thing); } } public getContained () : Array { return > Thing.InsideRoomRelation.getRight(this); } public getContainedAndVisibleTo (observer : Thing) : Array { let contained = this.getContained(); let result = []; contained.forEach((value) => { if (value.visible && value !== observer) { result.push(value); } }); return result; } public static DIRECTIONS : Array = (() => { let directions : Array = []; for (let i = 0; i < Object.keys(Direction).length / 2; i++) { directions.push(i); } return directions; })(); public getContainedAndVisible () : Array { return this.getContainedAndVisibleTo(WorldState.player); } public mapRoom (r : Room, direction : Direction) { let oppositeDirection = OppositeDirection[direction]; if (this.connections[direction] != undefined) { console.warn("Replacing a connected room.", this, " connected through ", direction, " to ", this.connections[direction]); this.connections[direction].unmapRoom(oppositeDirection); } this.connections[direction] = r; if (r.connections[oppositeDirection] != undefined) { console.warn("Replacing a connected room.", r, " connected through ", oppositeDirection, " to ", r.connections[oppositeDirection]); r.unmapRoom(oppositeDirection); } r.connections[oppositeDirection] = this; } public unmapRoom (direction : Direction) { if (this.connections[direction] != undefined) { let r = this.connections[direction]; this.connections[direction] = undefined; r.unmapRoom(OppositeDirection[direction]); } } public getPrintedName () { return this.name; } public getConnectedRooms () : Array { let rooms = []; this.connections.forEach(room => { if (room != undefined) { rooms.push(room); } }); return rooms; } /** * This returns the best direction to follow if going from the current room to another room. * THIS CODE IS REALLY EXPENSIVE AND SHOULD ONLY BE USED AS A LAST RESORT * WARNING: THIS CODE WILL FAIL IF THE TARGET ROOM IS TOO FAR FROM THE CURRENT ROOM (FOR SECURITY REASONS). * This code runs through every. single. room. to find the best route to take. * If you need an NPC to stick to a region, don't let it go out of it in the first place! * @param room * @param validityCode * @returns {any} */ // TODO: Make this shit fast public bestDirectionTo (room : Room, validityCode? : (room : Room) => boolean) { if (validityCode == undefined) validityCode = () => {return true}; /** * Maximum amount of steps that will be considered for a route. * 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. * * @type {number} */ let maxSteps = 10; maxSteps = maxSteps > WorldState.getMaximumRememberedRooms() ? maxSteps : WorldState.getMaximumRememberedRooms(); let recursiveBestPath = (cPath : Array, cRoom : Room, destination : Room) => { // Ignore "bad" rooms if (!validityCode(cRoom)) { return; } // Prevent the code from straying too far if (cRoom == destination) { maxSteps = maxSteps > cPath.length ? cPath.length : maxSteps; // Stop considering worse routes return cPath; } else if (cPath.length > maxSteps) { return undefined; } else { let paths = []; for (let index in Room.DIRECTIONS) { let direction = Room.DIRECTIONS[index]; let nextRoom = cRoom.connections[direction]; if (nextRoom != undefined && cPath.indexOf(nextRoom) == -1 && validityCode(nextRoom)) { let path = recursiveBestPath(cPath.concat([nextRoom]), nextRoom, destination); if (path != undefined) { paths.push(path); } } } let shortestIndex = 0; paths.forEach((value, index, array) => { if (value.length < paths[shortestIndex].length) { shortestIndex = index; } }); return paths[shortestIndex]; } }; let paths = Array(Room.DIRECTIONS.length); let shortestIndex; for (let index in Room.DIRECTIONS) { let direction = Room.DIRECTIONS[index]; let nextRoom = this.connections[direction]; if (nextRoom != undefined) { paths[direction] = recursiveBestPath([this, nextRoom], nextRoom, room); if (paths[direction] != undefined && (shortestIndex == undefined || paths[shortestIndex].length > paths[direction].length)) { shortestIndex = direction; } } } return shortestIndex; } public static getDirectionXYZ (direction : Direction) { var y = 0; if ([Direction.NORTH, Direction.NORTHEAST, Direction.NORTHWEST].indexOf(direction) != -1) { y = 1; } else if ([Direction.SOUTH, Direction.SOUTHEAST, Direction.SOUTHWEST].indexOf(direction) != -1) { y = -1; } var x = 0; if ([Direction.EAST, Direction.SOUTHEAST, Direction.NORTHEAST].indexOf(direction) != -1) { x = 1; } else if ([Direction.WEST, Direction.SOUTHWEST, Direction.NORTHWEST].indexOf(direction) != -1) { x = -1; } var z = direction == Direction.UP ? 1 : direction == Direction.DOWN ? -1 : 0; return [x, y, z]; } public static shift (coordinates : Array, direction : number) { let coordinatesVector = Room.getDirectionXYZ(direction); coordinates.forEach((value, index, array) => { coordinatesVector[index] += coordinates[index]; }); return coordinatesVector; } protected static rooms : {[id : string] : Room} = {}; protected static addRoom (room : Room) { Room.rooms[room.name] = room; } public static getRooms () : Array { let rooms = []; for (let name in Room.rooms) { rooms.push(Room.rooms[name]); } return rooms; } public static getRoom (id : string) { return Room.rooms[id]; } }