roguelike-pumpkin-patch
Version:
A roguelike development library in JavaScript.
1,096 lines (1,082 loc) • 47.1 kB
JavaScript
(function webpackUniversalModuleDefinition(root, factory) {
if(typeof exports === 'object' && typeof module === 'object')
module.exports = factory();
else if(typeof define === 'function' && define.amd)
define([], factory);
else if(typeof exports === 'object')
exports["RPP"] = factory();
else
root["RPP"] = factory();
})(self, function() {
return /******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ 865:
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
// ESM COMPAT FLAG
__webpack_require__.r(__webpack_exports__);
// EXPORTS
__webpack_require__.d(__webpack_exports__, {
"Display": () => (/* reexport */ display_Display),
"EventManager": () => (/* reexport */ event_EventManager),
"FOV": () => (/* reexport */ fov_FOV),
"PathFinder": () => (/* reexport */ pathfinder_PathFinder),
"Random": () => (/* reexport */ random_Random)
});
;// CONCATENATED MODULE: ./lib/display/Tile.js
var __assign = (undefined && undefined.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __rest = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var __spreadArrays = (undefined && undefined.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
var baseClassName = "pumpkin-tile";
/** Class to keep track of each individual tile in the display */
var Tile = /** @class */ (function () {
function Tile(tileOptions, position, tileSize) {
// Create necessary elements and apply classes
this.element = document.createElement('div');
this.element.classList.add(baseClassName);
// Set tile content and colour scheme
var _a = tileOptions.content, content = _a === void 0 ? '' : _a, _b = tileOptions.color, color = _b === void 0 ? '' : _b, _c = tileOptions.background, background = _c === void 0 ? '' : _c, _d = tileOptions.className, className = _d === void 0 ? '' : _d, _e = tileOptions.classList, classList = _e === void 0 ? [] : _e, rest = __rest(tileOptions, ["content", "color", "background", "className", "classList"]);
this.content = content;
this.color = color;
this.background = background;
if (classList.length > 0) {
this.classList = classList;
}
else {
this.className = className;
}
// Set the tile size
this.tileWidth = (tileSize === null || tileSize === void 0 ? void 0 : tileSize.tileWidth) ? tileSize.tileWidth : 16;
this.tileHeight = (tileSize === null || tileSize === void 0 ? void 0 : tileSize.tileHeight) ? tileSize.tileHeight : this.tileWidth;
// Set the tile position
this.position = position;
}
;
Object.defineProperty(Tile.prototype, "content", {
/** Get or set the tile contents */
get: function () {
return this._content;
},
set: function (newContent) {
// Create contentElement if it doesn't already exist
this.confirmContentElement();
// Only update if the new and old content don't match
if (this._content !== newContent) {
// If content is a string, just add it
if (typeof newContent === 'string') {
this.contentElement.innerHTML = newContent;
}
// If it is an element, empty the tile and append the new content
else {
while (this.contentElement.lastElementChild) {
this.contentElement.removeChild(this.contentElement.lastElementChild);
}
this.contentElement.appendChild(newContent);
}
this._content = newContent;
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "background", {
/** Get or set the background colour */
get: function () {
return this._background;
},
set: function (newBackground) {
if (newBackground !== this._background) {
this._background = newBackground;
this.element.style.backgroundColor = newBackground;
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "color", {
/** Get or set the color colour */
get: function () {
return this._color;
},
set: function (newcolor) {
if (newcolor !== this._color) {
this._color = newcolor;
this.element.style.color = newcolor;
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "position", {
/** Get or set position */
get: function () {
return this._position;
},
set: function (position) {
this._position = __assign({}, position);
this.element.style.left = position.x * this.tileWidth + "px";
this.element.style.top = position.y * this.tileHeight + "px";
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "tileWidth", {
/** Get or set tile width */
get: function () {
return this._tileWidth;
},
set: function (newWidth) {
this._tileWidth = newWidth;
this.element.style.width = newWidth + "px";
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "tileHeight", {
/** Get or set the tile height */
get: function () {
return this._tileHeight;
},
set: function (newHeight) {
this._tileHeight = newHeight;
this.element.style.height = newHeight + "px";
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "className", {
/** Get or set the classname */
get: function () {
return this.classList.join(" ");
},
set: function (newClass) {
if (newClass) {
this.classList = newClass.split(" ");
}
else {
this.classList = [];
}
},
enumerable: false,
configurable: true
});
Object.defineProperty(Tile.prototype, "classList", {
/** Get or set the list of classes */
get: function () {
return __spreadArrays([baseClassName], this._classList);
},
set: function (newClassList) {
var _this = this;
if (!this._classList) {
this._classList = [];
}
// Only add/remove classes if the two lists are actually different
if (newClassList.length !== this._classList.length ||
!newClassList.every(function (className, i) { return className === _this._classList[i]; })) {
this._classList = newClassList;
// Set using the getter, to ensure baseClassName is still on the list.
this.element.className = this.classList.join(' ');
}
},
enumerable: false,
configurable: true
});
/** Set options for the tile */
Tile.prototype.setOptions = function (newOptions) {
var _a = newOptions.content, content = _a === void 0 ? "" : _a, _b = newOptions.background, background = _b === void 0 ? "" : _b, _c = newOptions.color, color = _c === void 0 ? "" : _c, _d = newOptions.className, className = _d === void 0 ? "" : _d, classList = newOptions.classList;
this.content = content;
this.background = background;
this.color = color;
if (classList) {
this.classList = classList;
}
else {
this.className = className;
}
};
/**
* Update options for the tile
*/
Tile.prototype.updateOptions = function (newOptions) {
var content = newOptions.content, background = newOptions.background, color = newOptions.color, className = newOptions.className, classList = newOptions.classList;
if (typeof content !== "undefined") {
this.content = content;
}
if (typeof background !== "undefined") {
this.background = background;
}
if (typeof color !== "undefined") {
this.color = color;
}
if (classList && classList.length > 0) {
this.classList = classList;
}
else if (typeof className !== "undefined") {
this.className = className;
}
};
/** Check if a contentElement exists, and if it doesn't, add it */
Tile.prototype.confirmContentElement = function () {
if (!this.contentElement) {
this.contentElement = document.createElement('div');
this.element.appendChild(this.contentElement);
}
};
return Tile;
}());
/* harmony default export */ const display_Tile = (Tile);
//# sourceMappingURL=Tile.js.map
;// CONCATENATED MODULE: ./lib/display/DisplayStyle.js
// Default styling for the display. This gets inserted into the document head, before other stylesheets (so that you can override them if desired!)
var css = "\n.pumpkin-container {\n position: relative;\n overflow: hidden;\n background-color: #000000;\n color: #ffffff;\n}\n\n.pumpkin-display {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n}\n\n.pumpkin-tile {\n position: absolute;\n}\n\n.pumpkin-tile > * {\n position: absolute;\n left: 50%;\n top: 50%;\n transform: translate(-50%, -50%);\n z-index: 10;\n}\n";
/* harmony default export */ const DisplayStyle = (css);
//# sourceMappingURL=DisplayStyle.js.map
;// CONCATENATED MODULE: ./lib/display/Display.js
var Display_rest = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
/** Display class, to create and control a display */
var Display = /** @class */ (function () {
/** Create a new Display
* @param {DisplayParams} parameters - Object of parameters to initialize the display.
*/
function Display(parameters) {
var target = parameters.target, _a = parameters.width, width = _a === void 0 ? 1 : _a, _b = parameters.height, height = _b === void 0 ? 1 : _b, tileWidth = parameters.tileWidth, tileHeight = parameters.tileHeight, rest = Display_rest(parameters, ["target", "width", "height", "tileWidth", "tileHeight"]);
// Set the target
this.target = target;
if (this.target.className) {
this.target.classList.add("pumpkin-container");
}
else {
this.target.className = "pumpkin-container";
}
// Create the element for the display
this.element = document.createElement('div');
this.element.className = "pumpkin-display";
this.element.setAttribute("aria-hidden", "true");
// Set the display dimensions
this.dimensions = { width: width, height: height };
this.tileSize = {
tileWidth: (tileWidth) ? tileWidth : 16,
tileHeight: (tileHeight) ? tileHeight : (tileWidth) ? tileWidth : 16
};
// Add style to the page for the display
this.applyDefaultStyles();
// Append to the container element
this.target.appendChild(this.element);
}
;
Object.defineProperty(Display.prototype, "tileSize", {
/** Tile size */
get: function () {
return this._tileSize;
},
set: function (newTileSize) {
var _a;
this._tileSize = newTileSize;
this.element.style.fontSize = newTileSize.tileHeight + "px";
(_a = this.tiles) === null || _a === void 0 ? void 0 : _a.forEach(function (tile) {
tile.tileWidth = newTileSize.tileWidth;
tile.tileHeight = newTileSize.tileHeight;
tile.position = tile.position;
});
this.resetSize();
},
enumerable: false,
configurable: true
});
;
;
Object.defineProperty(Display.prototype, "dimensions", {
/** Get or set the display dimensions */
get: function () {
return { width: this._width, height: this._height };
},
set: function (newDimensions) {
if (newDimensions.width !== this._width && newDimensions.height !== this._height) {
this._width = newDimensions.width;
this._height = newDimensions.height;
// Reset the display to accomodate the new size
this.allocateDisplay();
this.resetSize();
this.moveToCenter();
}
},
enumerable: false,
configurable: true
});
;
;
/** Reset display element size */
Display.prototype.resetSize = function () {
if (this._width && this._height && this.tileSize) {
this.element.style.width = this._width * this.tileSize.tileWidth + "px";
this.element.style.height = this._height * this.tileSize.tileHeight + "px";
}
};
/** Position to center the display view on */
Display.prototype.centerDisplay = function (x, y) {
if (typeof x === "undefined" || typeof y === "undefined") {
this.centerPosition = undefined;
}
else {
this.centerPosition = {
x: x,
y: y
};
}
this.moveToCenter();
};
Display.prototype.moveToCenter = function () {
if (this.centerPosition) {
var xPercent = (this.centerPosition.x + 0.5) / this.dimensions.width;
var yPercent = (this.centerPosition.y + 0.5) / this.dimensions.height;
this.element.style.transform = "translate(" + -xPercent * 100 + "%," + -yPercent * 100 + "%)";
}
else {
this.element.style.transform = "";
}
};
/** Build the array of tiles and attach them to the display */
Display.prototype.allocateDisplay = function () {
var _this = this;
// Start a fresh tiles array
if (this.tiles) {
// Empty display if it has contents already
this.tiles.forEach(function (tile) {
_this.element.removeChild(tile.element);
});
}
this.tiles = [];
// Generate tiles
for (var y = 0; y < this._height; y++) {
for (var x = 0; x < this._width; x++) {
// Make a new tile
var newTile = new display_Tile({
content: '',
}, { x: x, y: y }, this.tileSize);
// Add it to the list of tiles
this.tiles.push(newTile);
// Append to the actual display
this.element.appendChild(newTile.element);
}
}
};
;
/** Get the display tile at the specified position
* @param {number} x - Position from the left side of the display
* @param {number} y - Position from the top of the display
*/
Display.prototype.getTile = function (x, y) {
if (x >= 0 && x < this._width && y >= 0 && y < this._height) {
var index = x + y * this._width;
return this.tiles[index];
}
else {
return undefined;
}
};
;
/** Take input and format into TileOptions */
Display.prototype.formatTileOptions = function (input) {
if (typeof input === "string") {
return { content: input };
}
else if (input instanceof HTMLElement) {
return { content: input };
}
else {
return input;
}
};
/** Set details for the specified tile */
Display.prototype.setTile = function (x, y, newOptions) {
var tile = this.getTile(x, y);
if (tile) {
tile.setOptions(this.formatTileOptions(newOptions));
}
};
;
/** Update details for the specified tile, preserving every unset property. */
Display.prototype.updateTile = function (x, y, newOptions) {
var tile = this.getTile(x, y);
if (tile) {
tile.updateOptions(this.formatTileOptions(newOptions));
}
};
;
/** Given the size of the target container, and the tile size, determine the number of tiles needed. */
Display.prototype.calculateDimensions = function (clientRect) {
if (clientRect === void 0) { clientRect = this.target.getBoundingClientRect(); }
var clientWidth = Math.abs(clientRect.right - clientRect.left);
var clientHeight = Math.abs(clientRect.bottom - clientRect.top);
// Round down; we do not want partial tiles
return {
width: Math.floor(clientWidth / this.tileSize.tileWidth),
height: Math.floor(clientHeight / this.tileSize.tileHeight)
};
};
;
/** Given the size of the target container, and the number of tiles, determine the tile size needed
* This assumes square tiles are desired.
*/
Display.prototype.calculateTileSize = function (clientRect) {
if (clientRect === void 0) { clientRect = this.target.getBoundingClientRect(); }
var clientWidth = Math.abs(clientRect.right - clientRect.left);
var clientHeight = Math.abs(clientRect.bottom - clientRect.top);
// This could potentially give absurd results, so get the "naive first-guess" here
var size = {
tileWidth: clientWidth / this.dimensions.width,
tileHeight: clientHeight / this.dimensions.height
};
// Choose the lowest of the two. This is the maximum square tile size that will fit the given dimensions
var maxTileSize = Math.min(size.tileWidth, size.tileHeight);
// Don't bother rounding; fonts can be precise numbers
return {
tileWidth: maxTileSize,
tileHeight: maxTileSize
};
};
;
/** Add the default styles to the head of the page. */
Display.prototype.applyDefaultStyles = function () {
var stylesId = "pumpkin-default-styles";
// Check to make sure the styles aren't already present
if (!document.getElementById(stylesId)) {
// Create the style element
var styles = document.createElement("style");
styles.id = stylesId;
styles.type = "text/css";
styles.appendChild(document.createTextNode(DisplayStyle));
// Get the head of the page
var head = document.head;
// Find the first style or link element, and insert in front of it
var firstStyle = document.querySelector("style, link");
head.insertBefore(styles, firstStyle);
}
};
return Display;
}());
/* harmony default export */ const display_Display = (Display);
;
//# sourceMappingURL=Display.js.map
;// CONCATENATED MODULE: ./lib/event/EventManager.js
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __generator = (undefined && undefined.__generator) || function (thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (_) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
};
/** Event manager, to keep track of turns */
var EventManager = /** @class */ (function () {
function EventManager(parameters) {
if (!parameters) {
parameters = {};
}
;
var _a = parameters.type, type = _a === void 0 ? "simple" : _a;
this.type = type;
this.queue = [];
this.time = 0;
}
;
/** Add an event to the queue */
EventManager.prototype.add = function (addedEvent) {
var event = {};
// Determine type of the input, and handle accordingly
if (addedEvent instanceof Function) {
event.callback = addedEvent;
}
else if ("act" in addedEvent) {
event.actor = addedEvent;
}
else {
Object.assign(event, addedEvent);
}
// Assume repeating if an actor was provided
if (typeof event.repeats === "undefined" && event.actor) {
event.repeats = true;
}
// Complex event queue uses delay time a bit better
if (this.type === "complex") {
if (!event.delay) {
event.delay = 1;
}
var scheduleFor = event.delay + this.time;
// Insert the event at the appropriate time
if (this.queue.length === 0 || this.queue[this.queue.length - 1].time <= scheduleFor) {
this.queue.push({
event: event,
time: scheduleFor
});
}
else {
for (var i = 0; i < this.queue.length; i++) {
if (scheduleFor < this.queue[i].time) {
this.queue.splice(i, 0, {
event: event,
time: scheduleFor
});
break;
}
}
}
}
else {
// Simple, no weird time shit
this.queue.push({
event: event,
time: 0
});
}
};
/** Run the next event */
EventManager.prototype.advance = function () {
return __awaiter(this, void 0, void 0, function () {
var thisEvent;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
// Confirm if there is anything in the queue
if (this.queue.length === 0) {
throw new Error("Event queue is empty.");
}
thisEvent = this.queue.shift();
// Update the time
this.time = thisEvent.time;
// If repeats is a number, reduce it.
if (typeof thisEvent.event.repeats === "number") {
thisEvent.event.repeats--;
}
// Check if it needs to repeat
if (thisEvent.event.repeats) {
// re-add to the queue
this.add(thisEvent.event);
}
if (!thisEvent.event.callback) return [3 /*break*/, 2];
return [4 /*yield*/, thisEvent.event.callback()];
case 1:
_a.sent();
_a.label = 2;
case 2:
if (!thisEvent.event.actor) return [3 /*break*/, 4];
return [4 /*yield*/, thisEvent.event.actor.act()];
case 3:
_a.sent();
_a.label = 4;
case 4: return [2 /*return*/];
}
});
});
};
/** Remove actor from the event queue */
EventManager.prototype.remove = function (actor) {
var _this = this;
var matches = [];
this.queue.forEach(function (event, index) {
if (event.event.actor === actor) {
matches.push(index);
}
});
// Reverse matches (work from the end first)
matches.reverse();
// Remove each match
matches.forEach(function (match) {
_this.queue.splice(match, 1);
});
};
Object.defineProperty(EventManager.prototype, "length", {
/** Determine the number of queued events in the queue. */
get: function () {
return this.queue.length;
},
enumerable: false,
configurable: true
});
return EventManager;
}());
/* harmony default export */ const event_EventManager = (EventManager);
//# sourceMappingURL=EventManager.js.map
;// CONCATENATED MODULE: ./lib/random/Random.js
/** Random generator */
var Random = /** @class */ (function () {
function Random(seed, base) {
if (!seed) {
// Get seed from milliseconds since Jan 1st, 1970
seed = Date.now();
}
this.seed = Math.floor(seed);
this.weyl = 0;
this.x = 0;
this.base = (base) ? base : 100000;
// Run it a couple of times, in case the seed isn't that good.
for (var i = 0; i < 10; i++) {
this.getRandom();
}
}
;
/** Generate a random number from 0 <= number < 1 */
// An attempt to reproduce something resembling the Middle Square Weyl Sequence PRNG
// See Widynski (2017) https://arxiv.org/abs/1704.00358v5
// The above algorithm uses unsigned ints. JS uses signed floats. Further testing required to see whether or not this is actually a problem.
Random.prototype.getRandom = function () {
this.x *= this.x;
this.x += (this.weyl += this.seed);
// Note, >>> makes the shift be unsigned. The >>> 0 at the end flips the "sign" bit to be positive, ensuring a non-negative result.
this.x = ((this.x >>> 32) | (this.x << 32)) >>> 0;
return (this.x % this.base) / this.base;
};
/** Get a random number in a range */
Random.prototype.getNumber = function (min, max, integer) {
if (typeof integer === "undefined") {
if (Number.isInteger(min) && Number.isInteger(max)) {
integer = true;
}
}
if (integer) {
return Math.floor(this.getRandom() * (max + 1 - min)) + Math.ceil(min);
}
else {
return (this.getRandom() * (max - min)) + min;
}
};
/** Get a random element from an array */
Random.prototype.getRandomElement = function (array) {
var randomIndex = this.getNumber(0, array.length - 1, true);
return array[randomIndex];
};
/** Get a random element, with weights */
Random.prototype.getWeightedElement = function (array) {
var totalWeight = 0;
var integer = true;
array.forEach(function (element) {
totalWeight += element.weight;
integer = integer && Number.isInteger(element.weight);
});
var randomNumber = this.getNumber((integer) ? 1 : 0, totalWeight, integer);
// Go through the array until we have a winner
for (var i = 0; i < array.length; i++) {
randomNumber -= array[i].weight;
if (randomNumber <= 0) {
// Found it!
return array[i].option;
}
}
// Not found; seems like a problem
throw new Error("No match found.");
};
return Random;
}());
/* harmony default export */ const random_Random = (Random);
//# sourceMappingURL=Random.js.map
;// CONCATENATED MODULE: ./lib/pathfinder/PathFinder.js
var PathFinder_rest = (undefined && undefined.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
var PathFinder_spreadArrays = (undefined && undefined.__spreadArrays) || function () {
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
for (var r = Array(s), k = 0, i = 0; i < il; i++)
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
r[k] = a[j];
return r;
};
/** Pathfinder to determine how to travel from one point to another */
var PathFinder = /** @class */ (function () {
function PathFinder(parameters) {
var canPass = parameters.canPass, metric = parameters.metric, maxIterations = parameters.maxIterations, weight = parameters.weight, rest = PathFinder_rest(parameters, ["canPass", "metric", "maxIterations", "weight"]);
this.canPass = canPass;
if (!metric) {
// Default metric is Manhattan metric, if none provided
metric = function (position1, position2) {
return Math.abs(position2[1] - position1[1]) + Math.abs(position2[0] - position1[0]);
};
}
if (!weight) {
// Default to everything being length of 1
weight = function (position) { return 1; };
}
this.maxIterations = maxIterations;
this.metric = metric;
this.weight = weight;
}
/** Find route from startPosition to endPosition, via A* */
PathFinder.prototype.findPath = function (startPosition, endPosition, orthogonalOnly) {
var _this = this;
if (orthogonalOnly === void 0) { orthogonalOnly = false; }
var route = [];
// Limit the loop so it doesn't break things
var maxIterations = (this.maxIterations) ? this.maxIterations : 40 * this.metric(startPosition, endPosition);
var iterations = 0;
// Initialize the list, and add the start to it
var closedList = [
{
position: PathFinder_spreadArrays(startPosition),
steps: 0,
distanceFromGoal: this.metric(startPosition, endPosition),
previousLocation: null
}
];
var openList = [];
// Handle diagonals
var stepSizeArr = [0, 1, 1.2];
// Find a path
while (iterations < maxIterations &&
!this.contains(closedList, endPosition)) {
iterations++;
// Expand the open list
closedList.forEach(function (location) {
for (var i = -1; i < 2; i++) {
for (var j = -1; j < 2; j++) {
if (orthogonalOnly && i !== 0 && j !== 0) {
continue;
}
var newPosition = [location.position[0] + i, location.position[1] + j];
// Determine the cost / size of step into the square
var stepSize = stepSizeArr[Math.abs(i) + Math.abs(j)] * _this.weight(newPosition);
if (!_this.canPass(newPosition)) {
continue;
}
var inClosedListAlready = _this.getLocation(closedList, newPosition);
var inOpenListAlready = _this.getLocation(openList, newPosition);
// New position is in neither list
if (!inClosedListAlready && !inOpenListAlready) {
openList.push({
position: newPosition,
steps: location.steps + stepSize,
distanceFromGoal: _this.metric(newPosition, endPosition),
previousLocation: location
});
}
else {
// if the position is already in the list, adjust to be whichever version is shorter
if (inClosedListAlready && inClosedListAlready.steps > location.steps + stepSize) {
inClosedListAlready.steps = location.steps + stepSize;
inClosedListAlready.previousLocation = location;
}
if (inOpenListAlready && inOpenListAlready.steps > location.steps + stepSize) {
inOpenListAlready.steps = location.steps + stepSize;
inOpenListAlready.previousLocation = location;
}
}
}
}
});
// Sort the open list (highest --> lowest)
openList.sort(function (a, b) { return (b.steps + b.distanceFromGoal) - (a.steps + a.distanceFromGoal); });
// Pop off the lowest openList item and add it to the closed list
closedList.push(openList.pop());
}
// Found a route! Put the pieces together by working backwards
var location = this.getLocation(closedList, endPosition);
if (this.contains(closedList, endPosition)) {
iterations = 0;
while ((location.position[0] !== startPosition[0] || location.position[1] !== startPosition[1]) && iterations < maxIterations) {
iterations++;
route.push(location.position);
location = location.previousLocation;
}
}
return route.reverse();
};
PathFinder.prototype.isEqual = function (position1, position2) {
return (position1.position[0] === position2.position[0] && position1.position[1] === position2.position[1]);
};
PathFinder.prototype.contains = function (locationList, testLocation) {
var _this = this;
if (Array.isArray(testLocation)) {
return locationList.some(function (location) {
return (location.position[0] === testLocation[0] && location.position[1] === testLocation[1]);
});
}
else {
return locationList.some(function (location) {
return _this.isEqual(location, testLocation);
});
}
};
PathFinder.prototype.getLocation = function (locationList, testPosition) {
for (var _i = 0, locationList_1 = locationList; _i < locationList_1.length; _i++) {
var location_1 = locationList_1[_i];
if (location_1.position[0] === testPosition[0] && location_1.position[1] === testPosition[1]) {
return location_1;
}
}
return undefined;
};
return PathFinder;
}());
/* harmony default export */ const pathfinder_PathFinder = (PathFinder);
//# sourceMappingURL=PathFinder.js.map
;// CONCATENATED MODULE: ./lib/fov/FOV.js
/** Field of view */
var FOV = /** @class */ (function () {
/** Accepts a callback function to determine if a location is seethrough */
function FOV(canSee, range) {
this.canSee = canSee;
this.range = range ? range : 8;
}
;
/** Do the FOV calculation */
FOV.prototype.look = function (position, lookRangeOverride) {
var range = (lookRangeOverride) ? lookRangeOverride : this.range;
// See the starting location (hooray! Great start)
this.canSee(position);
// const lookTiles:Array<Tile> = [];
var shadows = [];
var newShadows = [];
// From nearby to far away
var i = 0;
var j = 0;
for (var distance = 1; distance <= range; distance++) {
// Get square shell around position
for (var side = 0; side < 4; side++) {
for (var edge = -distance; edge <= distance; edge++) {
if (side === 0) {
i = edge;
j = distance;
}
else if (side === 1) {
j = edge;
i = distance;
}
else if (side === 2) {
i = edge;
j = -distance;
}
else {
j = edge;
i = -distance;
}
var lookPos = [position[0] + i, position[1] + j];
var dist = this.distance(position, lookPos);
// Out of range? Skip.
if (dist > range) {
continue;
}
// In shadows? Skip.
var angleTo = this.angleTo(position, lookPos);
var angularSize = this.angularSize(position, lookPos) / 2;
var inShadows = false;
if (this.isInShadows(angleTo, shadows) &&
this.isInShadows(angleTo + angularSize, shadows) &&
this.isInShadows(angleTo - angularSize, shadows)) {
inShadows = true;
}
// Now, test if we can see through the tile
if (inShadows || !this.canSee(lookPos)) {
// Square is opaque! Add its shadow
newShadows.push({
startAngle: angleTo - angularSize,
endAngle: angleTo + angularSize
});
}
}
}
// Add newShadows to shadows
while (newShadows.length > 0) {
// shadows.push(newShadows.pop());
this.combineShadow(shadows, newShadows.pop());
}
// Check if we should call it quits
if (shadows.length === 1 && shadows[0].endAngle - shadows[0].startAngle >= 360) {
return;
}
}
};
;
/** Get angle a tile resides in
* This ranges from -180 to 180, so be careful
*/
FOV.prototype.angleTo = function (startPosition, endPosition) {
var y = endPosition[1] - startPosition[1];
var x = endPosition[0] - startPosition[0];
var angle = 180 * Math.atan2(y, x) / Math.PI;
return (angle >= 0) ? angle : angle + 360;
};
;
/** Get angular size of a square */
FOV.prototype.angularSize = function (startPosition, endPosition) {
var distance = this.distance(startPosition, endPosition);
return 360 * Math.atan(1 / (2 * distance)) / Math.PI;
};
;
/** Get distance */
FOV.prototype.distance = function (startPosition, endPosition) {
return Math.sqrt(Math.pow((endPosition[1] - startPosition[1]), 2) + Math.pow((endPosition[0] - startPosition[0]), 2));
};
/** Check if in shadows */
FOV.prototype.isInShadows = function (angle, shadows) {
var negAngle = angle - 360;
for (var _i = 0, shadows_1 = shadows; _i < shadows_1.length; _i++) {
var shadow = shadows_1[_i];
if ((angle <= shadow.endAngle && angle >= shadow.startAngle) || (negAngle <= shadow.endAngle && negAngle >= shadow.startAngle)) {
return true;
}
}
return false;
};
/** Add a shadow to the shadow array */
FOV.prototype.combineShadow = function (shadows, newShadow) {
var overLapArr = [];
for (var i = 0; i < shadows.length; i++) {
var shadow = shadows[i];
// Check if they overlap
if (newShadow.startAngle < shadow.endAngle && newShadow.endAngle > shadow.startAngle) {
newShadow.startAngle = Math.min(shadow.startAngle, newShadow.startAngle);
newShadow.endAngle = Math.max(shadow.endAngle, newShadow.endAngle);
overLapArr.push(i);
}
}
if (overLapArr.length > 0) {
var mainShadow = shadows[overLapArr.shift()];
mainShadow.startAngle = newShadow.startAngle;
mainShadow.endAngle = newShadow.endAngle;
for (var i = overLapArr.length - 1; i >= 0; i--) {
shadows.splice(overLapArr[i], 1);
}
}
else {
shadows.push(newShadow);
}
};
return FOV;
}());
/* harmony default export */ const fov_FOV = (FOV);
//# sourceMappingURL=FOV.js.map
;// CONCATENATED MODULE: ./lib/index.js
//# sourceMappingURL=index.js.map
/***/ })
/******/ });
/************************************************************************/
/******/ // The module cache
/******/ var __webpack_module_cache__ = {};
/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ if(__webpack_module_cache__[moduleId]) {
/******/ return __webpack_module_cache__[moduleId].exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
/******/
/************************************************************************/
/******/ /* webpack/runtime/define property getters */
/******/ (() => {
/******/ // define getter functions for harmony exports
/******/ __webpack_require__.d = (exports, definition) => {
/******/ for(var key in definition) {
/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {
/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] });
/******/ }
/******/ }
/******/ };
/******/ })();
/******/
/******/ /* webpack/runtime/hasOwnProperty shorthand */
/******/ (() => {
/******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop))
/******/ })();
/******/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
/******/ // module exports must be returned from runtime so entry inlining is disabled
/******/ // startup
/******/ // Load entry module and return exports
/******/ return __webpack_require__(865);
/******/ })()
;
});