/// /// interface MapCoordinates { x : number; y : number; z : number; } class RoomRandomMap { private positionTable : {[x : number] : {[y : number] : RoomRandom}} = {}; private roomMap = new Map>(); public lowestX = 0; public lowestY = 0; public highestX = 0; public highestY = 0; public limitsInvalid = false; /** * This is a count of how many connections are actually available, assuming rooms that can connect through some direction. * @type {number} */ public availableConnections : Array>; /** * 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. * @type {number} */ public rooms; /** * Clears the current room cache and creates a new one that is empty */ public emptyCache () { this.availableConnections = []; Room.DIRECTIONS.forEach(() => { this.availableConnections.push([]); }); this.rooms = 0; } public getAvailableConnections () { return this.availableConnections.reduce((previousValue, currentValue, currentIndex, array) => { return previousValue + (currentValue.length); }, 0); } public removeFromCache (coordinatesToRemove : MapCoordinates, direction : number) { let directionArray = this.availableConnections[direction]; for (let k = 0, coordinates = directionArray[k]; coordinates != undefined; coordinates = directionArray[++k]) { if (coordinates.x == coordinatesToRemove.x && coordinates.y == coordinatesToRemove.y) { directionArray.splice(k, 1); return; } } } public addToCache (coordinatesToAdd : MapCoordinates, direction : number) { let directionArray = this.availableConnections[direction]; for (let k = 0, coordinates = directionArray[k]; coordinates != undefined; coordinates = directionArray[++k]) { if (coordinates.x == coordinatesToAdd.x && coordinates.y == coordinatesToAdd.y) { return; } } directionArray.push(coordinatesToAdd); } public getAnyFromCache (direction : number) : RoomRandom { let array = this.availableConnections[direction]; if (array.length > 0) { let randomIndex = Math.floor(Math.random() * (array.length)); let randomCoordinates = array[randomIndex]; if (randomCoordinates != undefined) { return this.getRoom(randomCoordinates.x, randomCoordinates.y); } } } public isFree (x : number, y : number) { return (this.positionTable[x] == undefined || this.positionTable[x][y] === undefined); } public isFreeSquare (centerX : number, centerY : number, distanceFromCenter : number) { for (let x = centerX - distanceFromCenter; x <= centerX + distanceFromCenter; x++) { for (let y = centerY - distanceFromCenter; y <= centerY + distanceFromCenter; y++) { if (!this.isFree(x,y)) { return false; } } } return true; } public block (x : number, y : number) { if (this.isFree(x, y)) { if (this.positionTable[x] == undefined) { this.positionTable[x] = {}; } this.positionTable[x][y] = null; this.updateCacheOnPosition(x, y); this.updateLimits(x, y); } } public updateAllLimits () { this.highestX = 0; this.highestY = 0; this.lowestX = 0; this.lowestY = 0; for (let x in this.positionTable) { for (let y in this.positionTable[x]) { if (this.positionTable[x][y] != undefined && this.positionTable[x][y] != null) { this.updateLimits(parseInt(x), parseInt(y)); } } } this.limitsInvalid = false; } public updateLimits (x, y) { if (x > this.highestX) this.highestX = x; if (y > this.highestY) this.highestY = y; if (y < this.lowestY) this.lowestY = y; if (x < this.lowestX) this.lowestX = x; } public map (room : RoomRandom, x : number, y : number) { if (this.positionTable[x] == undefined) { this.positionTable[x] = {}; } this.positionTable[x][y] = room; this.roomMap.set(room, [x, y]); this.updateCacheOnPosition(x, y); // If we ever want to draw maps, this will be useful this.updateLimits(x, y); room.placed = true; room.lastMap = this; this.rooms++; } public unmap (x : number, y : number) { if (this.positionTable[x] != undefined && this.positionTable[x][y] != undefined) { let room = this.positionTable[x][y]; room.placed = false; this.roomMap.delete(this.positionTable[x][y]); delete (this.positionTable[x][y]); this.rooms--; this.updateCacheOnPosition(x, y); this.limitsInvalid = true; } } private updateCacheOnPosition (x : number, y : number) { let coordinates = [x, y, 0]; let coordinatesMap = {x : x, y : y}; let coordinatesBlocked = !this.isFree(x, y); let coordinatesRoom = this.getRoom(x, y); Room.DIRECTIONS.forEach(direction => { let oppositeDirection = OppositeDirection[Direction[direction]]; let shifted = Room.shift(coordinates, direction); let shiftedMap = {x : shifted[0], y : shifted[1]}; let shiftedBlocked = !this.isFree(shifted[0], shifted[1]); let shiftedRoom = this.getRoom(shifted[0], shifted[1]); if (coordinatesRoom != undefined) { if (shiftedBlocked) { this.removeFromCache(coordinatesMap, direction); } else if (coordinatesRoom.isConnectableOn(direction)) { this.addToCache(coordinatesMap, direction); } } else { this.removeFromCache(coordinatesMap, direction); } if (shiftedRoom != undefined) { if (coordinatesBlocked) { this.removeFromCache(shiftedMap, oppositeDirection); } else if (shiftedRoom.isConnectableOn(oppositeDirection)) { this.addToCache(shiftedMap, oppositeDirection); } } else { this.removeFromCache(shiftedMap, oppositeDirection); } }); } public getRoom (x : number, y : number) { if (this.positionTable[x] != undefined) { if (this.positionTable[x][y] != null) { return this.positionTable[x][y]; } } return undefined; } public getCoordinates (room : Room) : Array { return this.roomMap.get(room); } public getRoomCount () { return this.roomMap.size; } public getWidth () { return this.highestX - this.lowestX; } public getHeight () { return this.highestY - this.lowestY; } public static PREFERRED_GROWTH_HORIZONTAL = 0; public static PREFERRED_GROWTH_VERTICAL = 1; public static PREFERRED_GROWTH_ANY = 2; public getPreferredGrowth () { let ratio = this.getHeight() / this.getWidth(); let idealRatio = 2.5; // This means we'd prefer a tall map that'd look good on our screen let difference = Math.abs(ratio - idealRatio); if (difference < 0.5) { return RoomRandomMap.PREFERRED_GROWTH_ANY; } else { if (ratio < idealRatio) { return RoomRandomMap.PREFERRED_GROWTH_VERTICAL; } else { return RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL; } } } public static isDirectionPreferred (direction : number, growth : number) { if (growth == RoomRandomMap.PREFERRED_GROWTH_ANY) { return true; } else if (direction == Direction.NORTH || direction == Direction.SOUTH) { return growth == RoomRandomMap.PREFERRED_GROWTH_VERTICAL; } else { return growth == RoomRandomMap.PREFERRED_GROWTH_HORIZONTAL; } } }