malwoden
Version:
   
233 lines • 9.32 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BSPDungeonBuilder = exports.BSPDungeonNode = void 0;
var rand_1 = require("../rand");
var rect_1 = require("../struct/rect");
var builder_1 = require("./builder");
var util_1 = require("./util");
var BSPDungeonNode = /** @class */ (function (_super) {
__extends(BSPDungeonNode, _super);
function BSPDungeonNode(_a) {
var v1 = _a.v1, v2 = _a.v2, rng = _a.rng;
var _this = _super.call(this, v1, v2) || this;
_this.leafMinWidth = 5;
_this.leafMinHeight = 5;
_this.rng = rng;
return _this;
}
BSPDungeonNode.prototype.connectChildren = function () { };
BSPDungeonNode.prototype.getRandomSplitDir = function () {
var splitDir = this.rng.nextBoolean()
? "vertical"
: "horizontal";
if (this.width() > this.height() && this.width() / this.height() > 1.25) {
splitDir = "horizontal";
}
else if (this.height() > this.width() &&
this.height() / this.width() > 1.25) {
splitDir = "vertical";
}
return splitDir;
};
BSPDungeonNode.prototype.split = function () {
if (this.getRandomSplitDir() === "horizontal") {
this.splitHorizontal();
}
else {
this.splitVertical();
}
};
BSPDungeonNode.prototype.getChildren = function () {
if (this.childA === undefined || this.childB === undefined)
return [];
else
return [this.childA, this.childB];
};
BSPDungeonNode.prototype.isLeafNode = function () {
return this.childA === undefined && this.childB === undefined;
};
BSPDungeonNode.prototype.splitVertical = function () {
if (this.isLeafNode() === false) {
throw new Error("BSPDungeonNode already split!");
}
var minH = this.leafMinHeight;
var maxH = this.height() - this.leafMinHeight;
if (maxH < minH) {
return;
}
var h = this.rng.nextInt(minH, maxH);
this.childA = new BSPDungeonNode({
v1: { x: this.v1.x, y: this.v1.y },
v2: { x: this.v2.x, y: this.v1.y + h - 1 },
rng: this.rng,
});
this.childB = new BSPDungeonNode({
v1: { x: this.v1.x, y: this.v1.y + h },
v2: { x: this.v2.x, y: this.v2.y },
rng: this.rng,
});
};
BSPDungeonNode.prototype.splitHorizontal = function () {
if (this.isLeafNode() === false) {
throw new Error("BSPDungeonNode already split!");
}
var minW = this.leafMinWidth;
var maxW = this.width() - this.leafMinWidth;
if (maxW < minW) {
return;
}
var w = this.rng.nextInt(minW, maxW);
this.childA = new BSPDungeonNode({
v1: { x: this.v1.x, y: this.v1.y },
v2: { x: this.v1.x + w - 1, y: this.v2.y },
rng: this.rng,
});
this.childB = new BSPDungeonNode({
v1: { x: this.v1.x + w, y: this.v1.y },
v2: { x: this.v2.x, y: this.v2.y },
rng: this.rng,
});
};
return BSPDungeonNode;
}(rect_1.Rect));
exports.BSPDungeonNode = BSPDungeonNode;
/**
* DungeonGenerator creates a number of rooms, and then works to connect
* them.
*/
var BSPDungeonBuilder = /** @class */ (function (_super) {
__extends(BSPDungeonBuilder, _super);
function BSPDungeonBuilder(config) {
var _a;
var _this = _super.call(this, config) || this;
_this.hallways = [];
_this.rooms = [];
_this.wallTile = config.wallTile;
_this.floorTile = config.floorTile;
_this.rng = (_a = config.rng) !== null && _a !== void 0 ? _a : new rand_1.AleaRNG();
_this.map.fill(_this.wallTile);
_this.root = new BSPDungeonNode({
v1: { x: 0, y: 0 },
v2: { x: config.width - 1, y: config.height - 1 },
rng: _this.rng,
});
return _this;
}
BSPDungeonBuilder.prototype.getLeafNodes = function () {
var leafs = [];
var horizon = [this.root];
while (horizon.length) {
var node = horizon.pop();
if (node.isLeafNode()) {
leafs.push(node);
}
horizon.push.apply(horizon, node.getChildren());
}
return leafs;
};
/**
* Splits the dungeon n times. A count of 1 would divide the dungeon in two,
* count of 2 divides it in 4, etc.
* @param count - number
*/
BSPDungeonBuilder.prototype.splitByCount = function (count) {
for (var i = 0; i < count; i++) {
var leafs = this.getLeafNodes();
for (var _i = 0, leafs_1 = leafs; _i < leafs_1.length; _i++) {
var l = leafs_1[_i];
l.split();
}
}
};
/**
* Creates rooms given the current BSP Tree. Use the 'split' method first to generate areas, then
* call createRooms to generate rooms within those areas
*
* @param options - Options to create the rooms
* @param options.minWidth - The minimum width of a generated room.
* @param options.minHeight - The minimum height of a generated room.
* @param options.maxWidth - The maximum width of a generated room. Will never be wider than the BSP area.
* @param options.maxHeight - The maximum height of a generated room. Will never be taller than the BSP area.
* @param options.padding - Can pad the area to ensure rooms aren't against the boundaries. Default 0.
*/
BSPDungeonBuilder.prototype.createRooms = function (options) {
var _a, _b, _c;
var minWidth = options.minWidth, minHeight = options.minHeight;
var padding = (_a = options.padding) !== null && _a !== void 0 ? _a : 0;
var leafs = this.getLeafNodes();
for (var _i = 0, leafs_2 = leafs; _i < leafs_2.length; _i++) {
var area = leafs_2[_i];
var areaWidth = area.width() - padding * 2;
var areaHeight = area.height() - padding * 2;
var maxWidth = Math.min((_b = options.maxWidth) !== null && _b !== void 0 ? _b : areaWidth, areaWidth);
var maxHeight = Math.min((_c = options.maxHeight) !== null && _c !== void 0 ? _c : areaHeight, areaHeight);
if (maxWidth < minWidth || maxHeight < minHeight)
continue;
var w = this.rng.nextInt(minWidth, maxWidth);
var h = this.rng.nextInt(minHeight, maxHeight);
var pv1 = { x: area.v1.x + padding, y: area.v1.y + padding };
var pv2 = { x: area.v2.x - padding, y: area.v2.y - padding };
var randX = this.rng.nextInt(pv1.x, pv2.x - w + 1);
var randY = this.rng.nextInt(pv1.y, pv2.y - h + 1);
var room = rect_1.Rect.FromWidthHeight({ x: randX, y: randY }, w, h);
this.carveRoom(room);
this.rooms.push(room);
}
};
BSPDungeonBuilder.prototype.carveRoom = function (room) {
for (var x = room.v1.x; x <= room.v2.x; x++) {
for (var y = room.v1.y; y <= room.v2.y; y++) {
this.map.set({ x: x, y: y }, this.floorTile);
}
}
};
/**
* Gets all rooms created. These will each belong to a leaf node of the BSP Tree.
* @returns Rect[] - A list of all rooms
*/
BSPDungeonBuilder.prototype.getRooms = function () {
return this.rooms;
};
/**
* Creates simple right angle hallways between existing rooms.
* @returns BSPDungeon - Can be used for method chaining.
*/
BSPDungeonBuilder.prototype.createSimpleHallways = function () {
this.hallways = [];
var shuffledRooms = this.rng.shuffle(this.rooms);
var connectedRooms = [];
while (shuffledRooms.length) {
var nextRoom = shuffledRooms.pop();
// if not the first room, connect it in
if (connectedRooms.length) {
var roomToConnect = connectedRooms[connectedRooms.length - 1];
var hallway = util_1.getSimpleHallwayFromRooms(nextRoom, roomToConnect);
this.hallways.push(hallway);
}
connectedRooms.push(nextRoom);
}
};
/**
* Returns a list of all hallways
* @returns Vector2[][] - The hallways
*/
BSPDungeonBuilder.prototype.getHallways = function () {
return this.hallways;
};
return BSPDungeonBuilder;
}(builder_1.Builder));
exports.BSPDungeonBuilder = BSPDungeonBuilder;
//# sourceMappingURL=bsp-dungeon-builder.js.map