///
///
///
///
///
///
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;
}
});
}