/// /// /// /// /// /// interface RandomizingRoomOptions { region : RegionRandom; room : RoomRandom; map : RoomRandomMap; } class RegionRandom extends Region { private randomized = false; public map : RoomRandomMap; public fodderRoomClass : typeof RoomRandom = RoomRandomFodder; public placedRooms : Array = []; public constructor (name : string, map? : RoomRandomMap) { super(name); this.map = map == undefined ? new RoomRandomMap() : map; } public async randomize () { if (!this.randomized) { await RegionRandom.rulebookRandomizeRegion.execute({ noun : this }); } } public placeAt (room : RoomRandom, x : number, y : number) { this.map.map(room, x, y); this.place(room); } public static rng : () => number = () => { return Math.random(); }; public static rulebookRandomizeRegion = new Rulebook("Randomizing Random Region something"); public static rulebookPlaceRoom = new Rulebook("Placing Random Room something"); public static rulebookBeforePlaceRoom = new Rulebook("Before placing Random Room something"); public static rulebookAfterPlaceRoom = new Rulebook("After placing Random Room something"); public static ruleFirstRandomizeRegion = RegionRandom.rulebookRandomizeRegion.createAndAddRule({ name : "Empty map cache to start randomizing region", firstPriority : Rule.PRIORITY_HIGHEST, code : runner => { let region = runner.noun; // We don't want to connect a region to another region unintentionally region.map.emptyCache(); } }); public static ruleBasicRandomizeRegion = RegionRandom.rulebookRandomizeRegion.createAndAddRule({ name : "Randomize all unplaced, randomizable rooms in region something", code : async runner => { let region = runner.noun; let roomShuffler = new Shuffler( Region.InRelation.getAllRightTypes(region, RoomRandom).filter((room : RoomRandom) => { return room.randomizable && !room.placed && (room == WorldState.player.getRoom() || (RegionRandom.rng() * 100) <= room.appearChance); }), RegionRandom.rng ); for (let room = roomShuffler.getOne(); room != undefined; room = roomShuffler.getOne()) { // Prevent available connections from getting too low // If we're placing rooms with too few availableConnections, we might end up reaching 0 availableConnections // Which would mean no more rooms can be placed. while (region.map.rooms > 0 && region.map.getAvailableConnections() < 4) { let fodder = new region.fodderRoomClass(); let options = { map : region.map, room : fodder, region : region }; region.place(fodder); await RegionRandom.rulebookBeforePlaceRoom.execute({noun : options}); await RegionRandom.rulebookPlaceRoom.execute({noun : options}); await RegionRandom.rulebookAfterPlaceRoom.execute({noun : options}); } let options = { map : region.map, room : room, region : region }; await RegionRandom.rulebookBeforePlaceRoom.execute({noun : options}); await RegionRandom.rulebookPlaceRoom.execute({noun : options}); await RegionRandom.rulebookAfterPlaceRoom.execute({noun : options}); if (!room.placed) { Elements.CurrentTurnHandler.printAsError(new Say("Was unable to place room ", room, ". Game might be unplayable.")); } } } }); public static ruleAddExtraConnections = RegionRandom.rulebookRandomizeRegion.createAndAddRule({ firstPriority : Rule.PRIORITY_LOWEST, name : "Add extra connections to rooms in region", code : runner => { let region = runner.noun; let placedRooms = Region.InRelation.getAllRightTypes(region, RoomRandom).filter((room : RoomRandom) => { return room.randomizable && room.placed; }); placedRooms.forEach((room : RoomRandom) => { let myCoordinates = region.map.getCoordinates(room); let directionShuffler = new Shuffler(room.connectableOn.slice(0), RegionRandom.rng); for (let direction = directionShuffler.getOne(); direction != undefined && (RegionRandom.rng() * 100) <= room.extraConnectionChance; direction = directionShuffler.getOne()) { if (room.connections[direction] == undefined) { let otherCoordinates = Room.shift(myCoordinates, direction); let otherRoom = region.map.getRoom(otherCoordinates[0], otherCoordinates[1]); if (otherRoom != undefined && otherRoom.randomizable && otherRoom.isConnectableOn(OppositeDirection[Direction[direction]]) && (RegionRandom.rng() * 100) <= otherRoom.extraConnectionChance) { room.mapRoom(otherRoom, direction); } } } }); } }); public static rulePlaceFirstRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({ name : "Placing First room something", firstPriority : Rule.PRIORITY_HIGHEST, code : runner => { let placingOptions = runner.noun; if (placingOptions.map.isFree(0, 0)) { placingOptions.map.map(placingOptions.room, 0, 0); return true; } }, conditions : runner => { return runner.noun.map.rooms == 0; } }); public static rulePlaceNonTrickyRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({ name : "Placing non-tricky room something", firstPriority : Rule.PRIORITY_HIGH, code : runner => { let placingOptions = runner.noun; //let directionShuffler = new Shuffler(placingOptions.room.connectableOn); let preferredGrowthDirection = placingOptions.map.getPreferredGrowth(); let directionShuffler = new ShufflerDirection(placingOptions.room.connectableOn, preferredGrowthDirection); //for (let direction = directionShuffler.getOne(); direction != undefined; direction = directionShuffler.getOne()) { for (let direction = directionShuffler.getDirection(); direction != undefined; direction = directionShuffler.getDirection()) { let oppositeDirection = OppositeDirection[Direction[direction]]; let connectableRoom = placingOptions.map.getAnyFromCache(oppositeDirection); if (connectableRoom != undefined) { let otherCoordinates = placingOptions.map.getCoordinates(connectableRoom); let myCoordinates = Room.shift(otherCoordinates, oppositeDirection); placingOptions.room.mapRoom(connectableRoom, direction); placingOptions.map.map(placingOptions.room, myCoordinates[0], myCoordinates[1]); return true; } } }, conditions : runner => { return runner.noun.room.trickyCode == undefined; } }); public static rulePlaceTrickyRoom = RegionRandom.rulebookPlaceRoom.createAndAddRule({ name : "Placing tricky room something", code : runner => { let placingOptions = runner.noun; let placedRooms = > placingOptions.region.getRooms().filter((room) => { return room instanceof RoomRandom && room.placed; }); if (placedRooms.length == 0) { Elements.CurrentTurnHandler.printAsError("Unable to place room " + placingOptions.room.getPrintedName() + ": There are no rooms to connect to!"); return false; } let roomShuffler = new Shuffler(placedRooms, RegionRandom.rng); for (let connectableRoom = roomShuffler.getOne(); connectableRoom != undefined; connectableRoom = roomShuffler.getOne()) { let trickier = { region : placingOptions.region, map : placingOptions.map, otherRoom : connectableRoom }; let tricky = placingOptions.room.getAnyDirection(trickier); if (tricky != undefined) { placingOptions.room.mapRoom(connectableRoom, tricky.trickyRoomDirection); placingOptions.map.map(placingOptions.room, tricky.x, tricky.y); return true; } } // THIS WORKS // I DON'T KNOW WHY // I DON'T CARE WHY // LEAVE let connectableThroughFodder = (fodderStep : number, connectingRoom : RoomRandom) => { let trickier = { region : placingOptions.region, map : placingOptions.map, otherRoom : connectingRoom }; if (fodderStep == 0) { return placingOptions.room.getAnyDirection(trickier); } else { let newFodder = new (placingOptions.region.fodderRoomClass)(); //let directionShuffler = new Shuffler(newFodder.connectableOn, RegionRandom.rng); let preferredGrowthDirection = placingOptions.map.getPreferredGrowth(); let directionShuffler = new ShufflerDirection(placingOptions.room.connectableOn, preferredGrowthDirection); for (let direction = directionShuffler.getDirection(); direction != undefined; direction = directionShuffler.getDirection()) { let oppositeDirection = OppositeDirection[Direction[direction]]; let otherCoordinates = placingOptions.map.getCoordinates(connectingRoom); let wouldbeCoordinates = Room.shift(otherCoordinates, oppositeDirection); let fodderTricky = { otherRoom : connectingRoom, otherRoomDirection : oppositeDirection, trickyRoomDirection : direction, map : placingOptions.map, region : placingOptions.region, x : wouldbeCoordinates[0], y : wouldbeCoordinates[1] }; if (newFodder.isPlaceable(fodderTricky)) { newFodder.mapRoom(connectingRoom, fodderTricky.trickyRoomDirection); placingOptions.map.map(newFodder, fodderTricky.x, fodderTricky.y); let nextTricky = connectableThroughFodder(fodderStep - 1, newFodder); if (nextTricky != undefined) { placingOptions.region.place(newFodder); return nextTricky; } else { newFodder.unmapRoom(fodderTricky.trickyRoomDirection); placingOptions.map.unmap(fodderTricky.x, fodderTricky.y); } } } } }; for (let fodderLevel = 1; fodderLevel < 40; fodderLevel++) { roomShuffler.restart(); for (let connectableRoom = roomShuffler.getOne(); connectableRoom != undefined; connectableRoom = roomShuffler.getOne()) { let tricky = connectableThroughFodder(fodderLevel, connectableRoom); if (tricky != undefined) { placingOptions.room.mapRoom(tricky.otherRoom, tricky.trickyRoomDirection); placingOptions.map.map(placingOptions.room, tricky.x, tricky.y); return true; } } } Elements.CurrentTurnHandler.printAsError("Unable to place room " + placingOptions.room.getPrintedName() + ": All attempts failed"); return false; } }); }