UNPKG

roguelike-pumpkin-patch

Version:
1,096 lines (1,082 loc) 47.1 kB
(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); /******/ })() ; });