diff --git a/bin/the-field-0.1.2.js b/bin/the-field-0.1.2.js deleted file mode 100644 index 0bdb275..0000000 --- a/bin/the-field-0.1.2.js +++ /dev/null @@ -1,687 +0,0 @@ -var TheField = -/******/ (function(modules) { // webpackBootstrap -/******/ // The module cache -/******/ var installedModules = {}; -/******/ -/******/ // The require function -/******/ function __webpack_require__(moduleId) { -/******/ -/******/ // Check if module is in cache -/******/ if(installedModules[moduleId]) { -/******/ return installedModules[moduleId].exports; -/******/ } -/******/ // Create a new module (and put it into the cache) -/******/ var module = installedModules[moduleId] = { -/******/ i: moduleId, -/******/ l: false, -/******/ exports: {} -/******/ }; -/******/ -/******/ // Execute the module function -/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); -/******/ -/******/ // Flag the module as loaded -/******/ module.l = true; -/******/ -/******/ // Return the exports of the module -/******/ return module.exports; -/******/ } -/******/ -/******/ -/******/ // expose the modules object (__webpack_modules__) -/******/ __webpack_require__.m = modules; -/******/ -/******/ // expose the module cache -/******/ __webpack_require__.c = installedModules; -/******/ -/******/ // identity function for calling harmony imports with the correct context -/******/ __webpack_require__.i = function(value) { return value; }; -/******/ -/******/ // define getter function for harmony exports -/******/ __webpack_require__.d = function(exports, name, getter) { -/******/ if(!__webpack_require__.o(exports, name)) { -/******/ Object.defineProperty(exports, name, { -/******/ configurable: false, -/******/ enumerable: true, -/******/ get: getter -/******/ }); -/******/ } -/******/ }; -/******/ -/******/ // getDefaultExport function for compatibility with non-harmony modules -/******/ __webpack_require__.n = function(module) { -/******/ var getter = module && module.__esModule ? -/******/ function getDefault() { return module['default']; } : -/******/ function getModuleExports() { return module; }; -/******/ __webpack_require__.d(getter, 'a', getter); -/******/ return getter; -/******/ }; -/******/ -/******/ // Object.prototype.hasOwnProperty.call -/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; -/******/ -/******/ // __webpack_public_path__ -/******/ __webpack_require__.p = "/bin/"; -/******/ -/******/ // Load entry module and return exports -/******/ return __webpack_require__(__webpack_require__.s = 7); -/******/ }) -/************************************************************************/ -/******/ ([ -/* 0 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -function __export(m) { - for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; -} -Object.defineProperty(exports, "__esModule", { value: true }); -__export(__webpack_require__(4)); -__export(__webpack_require__(6)); -__export(__webpack_require__(5)); -__export(__webpack_require__(3)); -__export(__webpack_require__(2)); - - -/***/ }), -/* 1 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var geom = __webpack_require__(0); -// tslint:disable:no-bitwise -/** - * In the shadowcasting algorithm, each shadow is represented by a "wedge", - * running from a "low" angle to a "high" angle. The wedges are all stored in - * a simple number array, with two numbers for each wedge. These constants - * (WEDGE_LOW and WEDGE_HIGH) help to identify which number is which. - * WEDGE_COUNT is just how many numbers per wedge. - */ -var WEDGE_LOW = 0; -var WEDGE_HIGH = 1; -var WEDGE_COUNT = 2; -/** - * Bodies in this algorithm do not entirely fill their tiles. This is - * implemented by adjusting the angles of the shadows the bodies cast, - * making the wedge very slightly narrower. BODY_EPSILON represents the - * amount of reduction on either side of the wedge. - */ -var BODY_EPSILON = 0.00001; -/** - * We avoid heap allocations during the core part of the algorithm by using this - * preallocated offset object. - */ -var LOCAL_OFF = new geom.Offset(); -/** - * For each number in the _tileFlags array, we store (1 << FLAGS_POW2) cells, - * as bits where a true indicates the presence of a body. - */ -var FLAGS_POW2 = 5; -/** - * The FieldOFViewMap represents the map over which the field of view will be - * computed. It starts out empty. You can add walls and bodies to it, and then - * use getFieldOfView() to compute the field of view from a given point. - */ -var FieldOfViewMap = /** @class */ (function () { - function FieldOfViewMap(width, height) { - this._size = new geom.Size(); - this._size.set(width, height); - this._tileFlags = new Array((this._size.area >> FLAGS_POW2) + 1).fill(0); - } - // setup and maintenance - FieldOfViewMap.prototype.addBody = function (x, y) { - LOCAL_OFF.set(x, y); - var index = this._size.index(LOCAL_OFF); - this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1)); - }; - FieldOfViewMap.prototype.removeBody = function (x, y) { - LOCAL_OFF.set(x, y); - var index = this._size.index(LOCAL_OFF); - this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1))); - }; - FieldOfViewMap.prototype.getBody = function (x, y) { - LOCAL_OFF.set(x, y); - var index = this._size.index(LOCAL_OFF); - return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0; - }; - // execution - /** - * Compute the field of view for a camera at the given tile. - * chebyshevRadius is the vision radius. It uses chebyshev distance - * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means - * that the limit of vision in a large empty field will be square. - * - * This returns a MaskRect, which indicates which tiles are visible. - * maskRect.get(x, y) will return true for visible tiles. - */ - FieldOfViewMap.prototype.getFieldOfView = function (x, y, chebyshevRadius) { - var origin = new geom.Offset(x, y); - var boundRect = new geom.Rectangle(origin.x - chebyshevRadius, origin.y - chebyshevRadius, chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1); - var mask = new geom.MaskRect(boundRect); - // the player can always see itself - mask.set(origin, true); - // the field is divided into quadrants - this._quadrant(mask, origin, chebyshevRadius, -1, -1); - this._quadrant(mask, origin, chebyshevRadius, 1, -1); - this._quadrant(mask, origin, chebyshevRadius, -1, 1); - this._quadrant(mask, origin, chebyshevRadius, 1, 1); - return mask; - }; - FieldOfViewMap.prototype._quadrant = function (mask, origin, chebyshevRadius, xDir, yDir) { - var startX = origin.x, startY = origin.y; - var endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1), -1), this._size.width) - startX) * xDir; - var endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1), -1), this._size.height) - startY) * yDir; - if (endDX < 0 || endDY < 0) { - // the origin is outside of the map - return; - } - var startMapIndex = this._size.index(origin); - var startMaskIndex = mask.index(origin); - // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant) - var wedges = [0, Number.POSITIVE_INFINITY]; - // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to - // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean - for (var dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex; dy !== endDY && wedges.length > 0; dy++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width) { - var divYpos = 1 / (dy + 0.5); - var divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5); - var wedgeIndex = 0; - // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to - // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean - for (var dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex, slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg; dx !== endDX && wedgeIndex !== wedges.length; dx++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir, - slopeY = slopeY + divYpos, slopeX = slopeX + divYneg) { - // the slopes of the four corners of this tile - // these are named as follows: - // slopeY is the slope closest to the Y axis - // slopeX is the slope closest to the X axis - // this is always true: - // slopeY < slopeX - // - // O = origin, C = current - // +---+---+---+ - // | O | | | - // +---+---+---X - // | | | C | - // +---+---Y---+ - // advance the wedge index until this tile is not after the current wedge - while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) { - // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to - // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean - wedgeIndex = wedgeIndex + WEDGE_COUNT; - if (wedgeIndex >= wedges.length) { - break; - } - } - if (wedgeIndex >= wedges.length) { - break; - } - // if the current wedge is after this tile, move on - if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) { - continue; - } - // we can see this tile - mask.setAt(maskIndex, true); - // const/let must be at the top of a block, in order not to trigger deoptimization due to - // https://github.com/nodejs/node/issues/9729 - { - var body = (dx !== 0 || dy !== 0) - && (this._tileFlags[mapIndex >> FLAGS_POW2] - & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0; - if (body) { - wedgeIndex = cutWedge(wedges, wedgeIndex, slopeY + BODY_EPSILON, slopeX - BODY_EPSILON); - } - } - } - } - }; - return FieldOfViewMap; -}()); -exports.FieldOfViewMap = FieldOfViewMap; -/** - * This function cuts a range of angles out of the wedge array. - */ -function cutWedge(wedges, wedgeIndex, low, high) { - for (;;) { - if (wedgeIndex === wedges.length) { - return wedgeIndex; - } - if (low <= wedges[wedgeIndex + WEDGE_HIGH]) { - break; - } - wedgeIndex += WEDGE_COUNT; - } - if (low <= wedges[wedgeIndex + WEDGE_LOW]) { - if (high >= wedges[wedgeIndex + WEDGE_HIGH]) { - // wedge is entirely occluded, remove it - wedges.splice(wedgeIndex, WEDGE_COUNT); - // now looking at the next wedge (or past the end) - return cutWedge(wedges, wedgeIndex, low, high); - } - else if (high >= wedges[wedgeIndex + WEDGE_LOW]) { - // low part of wedge is occluded, trim it - wedges[wedgeIndex + WEDGE_LOW] = high; - // still looking at the same wedge - } - else { - // this cut doesn't reach the current wedge - } - } - else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) { - // high part of wedge is occluded, trim it - wedges[wedgeIndex + WEDGE_HIGH] = low; - // move on to the next wedge - wedgeIndex += WEDGE_COUNT; - return cutWedge(wedges, wedgeIndex, low, high); - } - else { - // middle part of wedge is occluded, split it - wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low); - wedgeIndex += WEDGE_COUNT; - wedges[wedgeIndex + WEDGE_LOW] = high; - // now looking at the second wedge of the split - } - return wedgeIndex; -} - - -/***/ }), -/* 2 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var geom = __webpack_require__(0); -var LOCAL_OFF = new geom.Offset(); -var MaskRect = /** @class */ (function () { - function MaskRect(rect, initialValue, outsideValue) { - if (initialValue === void 0) { initialValue = false; } - if (outsideValue === void 0) { outsideValue = false; } - this._rectangle = new geom.Rectangle(); - this._rectangle.copyFrom(rect); - this._mask = new geom.Mask(rect, initialValue); - this._outsideValue = outsideValue; - } - // accessors - MaskRect.prototype.toString = function () { - return this._rectangle.northWest + "/" + this._outsideValue + "\n" + this._mask; - }; - Object.defineProperty(MaskRect.prototype, "westX", { - get: function () { - return this._rectangle.westX; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(MaskRect.prototype, "northY", { - get: function () { - return this._rectangle.northY; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(MaskRect.prototype, "width", { - get: function () { - return this._rectangle.width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(MaskRect.prototype, "height", { - get: function () { - return this._rectangle.height; - }, - enumerable: true, - configurable: true - }); - MaskRect.prototype.index = function (off) { - return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest)); - }; - MaskRect.prototype.getAt = function (index) { - return this._mask.getAt(index); - }; - MaskRect.prototype.get = function (x, y) { - LOCAL_OFF.set(x, y); - if (!this._rectangle.containsOffset(LOCAL_OFF)) { - return this._outsideValue; - } - return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest)); - }; - // mutators - MaskRect.prototype.setAt = function (index, value) { - this._mask.setAt(index, value); - return this; - }; - MaskRect.prototype.set = function (off, value) { - this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value); - return this; - }; - // utilities - MaskRect.prototype.forEach = function (cursor, callback) { - var _this = this; - this._mask.forEach(cursor, function (off, value) { - callback(off.addOffset(_this._rectangle.northWest), value); - }); - }; - return MaskRect; -}()); -exports.MaskRect = MaskRect; - - -/***/ }), -/* 3 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var geom = __webpack_require__(0); -var Mask = /** @class */ (function () { - // TODO consider Uint8Array for bits - function Mask(size, initialValue) { - if (initialValue === void 0) { initialValue = false; } - this._size = new geom.Size(); - this._size.copyFrom(size); - this._bits = new Array(this._size.area).fill(initialValue); - } - // accessors - Mask.prototype.toString = function () { - var ret = ''; - var off = new geom.Offset(); - for (var y = 0; y < this._size.height; y++) { - for (var x = 0; x < this._size.width; x++) { - off.set(x, y); - ret += this.get(off.set(x, y)) ? '☑' : '☐'; - } - ret += '\n'; - } - return ret; - }; - Object.defineProperty(Mask.prototype, "width", { - get: function () { - return this._size.width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Mask.prototype, "height", { - get: function () { - return this._size.height; - }, - enumerable: true, - configurable: true - }); - Mask.prototype.index = function (off) { - return this._size.index(off); - }; - Mask.prototype.getAt = function (index) { - return this._bits[index]; - }; - Mask.prototype.get = function (off) { - return this.getAt(this.index(off)); - }; - // mutators - Mask.prototype.setAt = function (index, value) { - this._bits[index] = value; - return this; - }; - Mask.prototype.set = function (off, value) { - return this.setAt(this.index(off), value); - }; - // utilities - Mask.prototype.forEach = function (cursor, callback) { - var _this = this; - var index = 0; - this._size.forEach(cursor, function (off) { - callback(off, _this._bits[index]); - index++; - }); - }; - return Mask; -}()); -exports.Mask = Mask; - - -/***/ }), -/* 4 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var Offset = /** @class */ (function () { - function Offset(x, y) { - if (typeof x === 'undefined') { - x = 0; - } - if (typeof y === 'undefined') { - y = 0; - } - this.x = x; - this.y = y; - } - Offset.prototype.toString = function () { - return "(" + this.x + "," + this.y + ")"; - }; - // mutators - Offset.prototype.set = function (x, y) { - this.x = x; - this.y = y; - return this; - }; - Offset.prototype.copyFrom = function (other) { - this.x = other.x; - this.y = other.y; - return this; - }; - Offset.prototype.addOffset = function (off) { - this.x += off.x; - this.y += off.y; - return this; - }; - Offset.prototype.subtractOffset = function (off) { - this.x -= off.x; - this.y -= off.y; - return this; - }; - return Offset; -}()); -exports.Offset = Offset; - - -/***/ }), -/* 5 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var geom = __webpack_require__(0); -var LOCAL_OFF = new geom.Offset(); -var Rectangle = /** @class */ (function () { - function Rectangle(westX, northY, width, height) { - if (typeof westX === 'undefined') { - westX = 0; - } - if (typeof northY === 'undefined') { - northY = 0; - } - if (typeof width === 'undefined') { - width = 0; - } - if (typeof height === 'undefined') { - height = 0; - } - this.northWest = new geom.Offset(westX, northY); - this.size = new geom.Size(width, height); - } - // accessors - Rectangle.prototype.toString = function () { - return "(" + this.westX + "," + this.northY + " " + this.width + "x" + this.height + ")"; - }; - Object.defineProperty(Rectangle.prototype, "northY", { - get: function () { - return this.northWest.y; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "southY", { - get: function () { - return this.northWest.y + this.size.height - 1; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "westX", { - get: function () { - return this.northWest.x; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "eastX", { - get: function () { - return this.northWest.x + this.size.width - 1; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "width", { - get: function () { - return this.size.width; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "height", { - get: function () { - return this.size.height; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "empty", { - get: function () { - return this.size.empty; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Rectangle.prototype, "area", { - get: function () { - return this.size.area; - }, - enumerable: true, - configurable: true - }); - // mutators - Rectangle.prototype.copyFrom = function (other) { - this.northWest.set(other.westX, other.northY); - this.size.set(other.width, other.height); - return this; - }; - // utilities - Rectangle.prototype.containsOffset = function (off) { - return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest)); - }; - Rectangle.prototype.index = function (off) { - return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest)); - }; - return Rectangle; -}()); -exports.Rectangle = Rectangle; - - -/***/ }), -/* 6 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -Object.defineProperty(exports, "__esModule", { value: true }); -var Size = /** @class */ (function () { - function Size(width, height) { - if (typeof width === 'undefined') { - width = 0; - } - if (typeof height === 'undefined') { - height = 0; - } - this.width = width; - this.height = height; - } - // accessors - Size.prototype.toString = function () { - return "(" + this.width + "x" + this.height + ")"; - }; - Object.defineProperty(Size.prototype, "empty", { - get: function () { - return this.width === 0 || this.height === 0; - }, - enumerable: true, - configurable: true - }); - Object.defineProperty(Size.prototype, "area", { - get: function () { - return this.width * this.height; - }, - enumerable: true, - configurable: true - }); - // mutators - Size.prototype.set = function (width, height) { - this.width = width; - this.height = height; - return this; - }; - Size.prototype.copyFrom = function (other) { - this.width = other.width; - this.height = other.height; - return this; - }; - // utilities - Size.prototype.containsOffset = function (off) { - return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height; - }; - Size.prototype.index = function (off) { - return off.y * this.width + off.x; - }; - Size.prototype.forEach = function (cursor, callback) { - for (var dy = 0; dy < this.height; dy++) { - for (var dx = 0; dx < this.width; dx++) { - cursor.x = dx; - cursor.y = dy; - callback(cursor); - } - } - }; - return Size; -}()); -exports.Size = Size; - - -/***/ }), -/* 7 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - -/* - * TheField - * github.com/sbj42/the-field - * James Clark - * Licensed under the MIT license. - */ -Object.defineProperty(exports, "__esModule", { value: true }); -var field_of_view_1 = __webpack_require__(1); -exports.FieldOfViewMap = field_of_view_1.FieldOfViewMap; -var geom_1 = __webpack_require__(0); -exports.MaskRect = geom_1.MaskRect; - - -/***/ }) -/******/ ]); -//# sourceMappingURL=the-field-0.1.2.js.map \ No newline at end of file diff --git a/bin/the-field-0.1.2.js.map b/bin/the-field-0.1.2.js.map deleted file mode 100644 index ac70e79..0000000 --- a/bin/the-field-0.1.2.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["webpack:///webpack/bootstrap f63b8aa5d7334f20d162","webpack:///./src/geom/index.ts","webpack:///./src/field-of-view.ts","webpack:///./src/geom/mask-rect.ts","webpack:///./src/geom/mask.ts","webpack:///./src/geom/offset.ts","webpack:///./src/geom/rectangle.ts","webpack:///./src/geom/size.ts","webpack:///./src/index.ts"],"names":[],"mappings":"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","file":"the-field-0.1.2.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/bin/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 7);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap f63b8aa5d7334f20d162","export * from './offset';\r\nexport * from './size';\r\nexport * from './rectangle';\r\nexport * from './mask';\r\nexport * from './mask-rect';\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/index.ts","import * as geom from './geom';\r\n\r\n// tslint:disable:no-bitwise\r\n\r\n/**\r\n * In the shadowcasting algorithm, each shadow is represented by a \"wedge\",\r\n * running from a \"low\" angle to a \"high\" angle. The wedges are all stored in\r\n * a simple number array, with two numbers for each wedge. These constants\r\n * (WEDGE_LOW and WEDGE_HIGH) help to identify which number is which.\r\n * WEDGE_COUNT is just how many numbers per wedge.\r\n */\r\nconst WEDGE_LOW = 0;\r\nconst WEDGE_HIGH = 1;\r\nconst WEDGE_COUNT = 2;\r\n\r\n/**\r\n * Bodies in this algorithm do not entirely fill their tiles. This is\r\n * implemented by adjusting the angles of the shadows the bodies cast,\r\n * making the wedge very slightly narrower. BODY_EPSILON represents the\r\n * amount of reduction on either side of the wedge.\r\n */\r\nconst BODY_EPSILON = 0.00001;\r\n\r\n/**\r\n * We avoid heap allocations during the core part of the algorithm by using this\r\n * preallocated offset object.\r\n */\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\n/**\r\n * For each number in the _tileFlags array, we store (1 << FLAGS_POW2) cells,\r\n * as bits where a true indicates the presence of a body.\r\n */\r\nconst FLAGS_POW2 = 5;\r\n\r\n/**\r\n * The FieldOFViewMap represents the map over which the field of view will be\r\n * computed. It starts out empty. You can add walls and bodies to it, and then\r\n * use getFieldOfView() to compute the field of view from a given point.\r\n */\r\nexport class FieldOfViewMap {\r\n private readonly _size = new geom.Size();\r\n private readonly _tileFlags: number[];\r\n\r\n constructor(width: number, height: number) {\r\n this._size.set(width, height);\r\n this._tileFlags = new Array((this._size.area >> FLAGS_POW2) + 1).fill(0);\r\n }\r\n\r\n // setup and maintenance\r\n\r\n addBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1));\r\n }\r\n\r\n removeBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1)));\r\n }\r\n\r\n getBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n }\r\n\r\n // execution\r\n\r\n /**\r\n * Compute the field of view for a camera at the given tile.\r\n * chebyshevRadius is the vision radius. It uses chebyshev distance\r\n * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means\r\n * that the limit of vision in a large empty field will be square.\r\n *\r\n * This returns a MaskRect, which indicates which tiles are visible.\r\n * maskRect.get(x, y) will return true for visible tiles.\r\n */\r\n getFieldOfView(x: number, y: number, chebyshevRadius: number): geom.MaskRect {\r\n const origin = new geom.Offset(x, y);\r\n const boundRect = new geom.Rectangle(\r\n origin.x - chebyshevRadius, origin.y - chebyshevRadius,\r\n chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1,\r\n );\r\n const mask = new geom.MaskRect(boundRect);\r\n // the player can always see itself\r\n mask.set(origin, true);\r\n // the field is divided into quadrants\r\n this._quadrant(mask, origin, chebyshevRadius, -1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, -1, 1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, 1);\r\n return mask;\r\n }\r\n\r\n private _quadrant(mask: geom.MaskRect, origin: geom.OffsetLike, chebyshevRadius: number,\r\n xDir: number, yDir: number) {\r\n const {x: startX, y: startY} = origin;\r\n const endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1),\r\n -1), this._size.width) - startX) * xDir;\r\n const endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1),\r\n -1), this._size.height) - startY) * yDir;\r\n if (endDX < 0 || endDY < 0) {\r\n // the origin is outside of the map\r\n return;\r\n }\r\n const startMapIndex = this._size.index(origin);\r\n const startMaskIndex = mask.index(origin);\r\n // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant)\r\n const wedges = [0, Number.POSITIVE_INFINITY];\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex;\r\n dy !== endDY && wedges.length > 0;\r\n dy ++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width\r\n ) {\r\n const divYpos = 1 / (dy + 0.5);\r\n const divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5);\r\n let wedgeIndex = 0;\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex,\r\n slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg;\r\n dx !== endDX && wedgeIndex !== wedges.length;\r\n dx ++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir,\r\n slopeY = slopeY + divYpos, slopeX = slopeX + divYneg\r\n ) {\r\n // the slopes of the four corners of this tile\r\n // these are named as follows:\r\n // slopeY is the slope closest to the Y axis\r\n // slopeX is the slope closest to the X axis\r\n // this is always true:\r\n // slopeY < slopeX\r\n //\r\n // O = origin, C = current\r\n // +---+---+---+\r\n // | O | | |\r\n // +---+---+---X\r\n // | | | C |\r\n // +---+---Y---+\r\n\r\n // advance the wedge index until this tile is not after the current wedge\r\n while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n wedgeIndex = wedgeIndex + WEDGE_COUNT;\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n }\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n\r\n // if the current wedge is after this tile, move on\r\n if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n continue;\r\n }\r\n\r\n // we can see this tile\r\n mask.setAt(maskIndex, true);\r\n\r\n // const/let must be at the top of a block, in order not to trigger deoptimization due to\r\n // https://github.com/nodejs/node/issues/9729\r\n {\r\n const body = (dx !== 0 || dy !== 0)\r\n && (this._tileFlags[mapIndex >> FLAGS_POW2]\r\n & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n if (body) {\r\n wedgeIndex = cutWedge(wedges, wedgeIndex,\r\n slopeY + BODY_EPSILON, slopeX - BODY_EPSILON);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * This function cuts a range of angles out of the wedge array.\r\n */\r\nfunction cutWedge(wedges: number[], wedgeIndex: number, low: number, high: number): number {\r\n for (; ; ) {\r\n if (wedgeIndex === wedges.length) {\r\n return wedgeIndex;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n break;\r\n }\r\n wedgeIndex += WEDGE_COUNT;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // wedge is entirely occluded, remove it\r\n wedges.splice(wedgeIndex, WEDGE_COUNT);\r\n // now looking at the next wedge (or past the end)\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else if (high >= wedges[wedgeIndex + WEDGE_LOW]) {\r\n // low part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // still looking at the same wedge\r\n } else {\r\n // this cut doesn't reach the current wedge\r\n }\r\n } else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // high part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_HIGH] = low;\r\n // move on to the next wedge\r\n wedgeIndex += WEDGE_COUNT;\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else {\r\n // middle part of wedge is occluded, split it\r\n wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low);\r\n wedgeIndex += WEDGE_COUNT;\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // now looking at the second wedge of the split\r\n }\r\n return wedgeIndex;\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/field-of-view.ts","import * as geom from '.';\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class MaskRect implements geom.RectangleLike {\r\n private readonly _rectangle = new geom.Rectangle();\r\n private readonly _mask: geom.Mask;\r\n private readonly _outsideValue: boolean;\r\n\r\n constructor(rect: geom.RectangleLike, initialValue = false, outsideValue = false) {\r\n this._rectangle.copyFrom(rect);\r\n this._mask = new geom.Mask(rect, initialValue);\r\n this._outsideValue = outsideValue;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `${this._rectangle.northWest}/${this._outsideValue}\\n${this._mask}`;\r\n }\r\n\r\n get westX() {\r\n return this._rectangle.westX;\r\n }\r\n\r\n get northY() {\r\n return this._rectangle.northY;\r\n }\r\n\r\n get width() {\r\n return this._rectangle.width;\r\n }\r\n\r\n get height() {\r\n return this._rectangle.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest));\r\n }\r\n\r\n getAt(index: number) {\r\n return this._mask.getAt(index);\r\n }\r\n\r\n get(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n if (!this._rectangle.containsOffset(LOCAL_OFF)) {\r\n return this._outsideValue;\r\n }\r\n return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest));\r\n }\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._mask.setAt(index, value);\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n this._mask.forEach(cursor, (off, value) => {\r\n callback(off.addOffset(this._rectangle.northWest), value);\r\n });\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/mask-rect.ts","import * as geom from '.';\r\n\r\nexport class Mask implements geom.SizeLike {\r\n private readonly _size = new geom.Size();\r\n private readonly _bits: boolean[];\r\n // TODO consider Uint8Array for bits\r\n\r\n constructor(size: geom.SizeLike, initialValue = false) {\r\n this._size.copyFrom(size);\r\n this._bits = new Array(this._size.area).fill(initialValue);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n let ret = '';\r\n const off = new geom.Offset();\r\n for (let y = 0; y < this._size.height; y ++) {\r\n for (let x = 0; x < this._size.width; x ++) {\r\n off.set(x, y);\r\n ret += this.get(off.set(x, y)) ? '☑' : '☐';\r\n }\r\n ret += '\\n';\r\n }\r\n return ret;\r\n }\r\n\r\n get width() {\r\n return this._size.width;\r\n }\r\n\r\n get height() {\r\n return this._size.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._size.index(off);\r\n }\r\n\r\n getAt(index: number) {\r\n return this._bits[index];\r\n }\r\n\r\n get(off: geom.OffsetLike) {\r\n return this.getAt(this.index(off));\r\n }\r\n\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._bits[index] = value;\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n return this.setAt(this.index(off), value);\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n let index = 0;\r\n this._size.forEach(cursor, (off) => {\r\n callback(off, this._bits[index]);\r\n index ++;\r\n });\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/mask.ts","export interface OffsetLike {\r\n readonly x: number;\r\n readonly y: number;\r\n}\r\n\r\nexport class Offset implements OffsetLike {\r\n x: number;\r\n y: number;\r\n\r\n constructor();\r\n constructor(x: number, y: number);\r\n constructor(x?: number, y?: number) {\r\n if (typeof x === 'undefined') {\r\n x = 0;\r\n }\r\n if (typeof y === 'undefined') {\r\n y = 0;\r\n }\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n toString() {\r\n return `(${this.x},${this.y})`;\r\n }\r\n\r\n // mutators\r\n\r\n set(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n return this;\r\n }\r\n\r\n copyFrom(other: OffsetLike) {\r\n this.x = other.x;\r\n this.y = other.y;\r\n return this;\r\n }\r\n\r\n addOffset(off: OffsetLike) {\r\n this.x += off.x;\r\n this.y += off.y;\r\n return this;\r\n }\r\n\r\n subtractOffset(off: OffsetLike) {\r\n this.x -= off.x;\r\n this.y -= off.y;\r\n return this;\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/offset.ts","import * as geom from '.';\r\n\r\nexport interface RectangleLike extends geom.SizeLike {\r\n readonly westX: number;\r\n readonly northY: number;\r\n}\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class Rectangle implements RectangleLike, geom.SizeLike {\r\n northWest: geom.Offset;\r\n size: geom.Size;\r\n\r\n constructor();\r\n constructor(westX: number, northY: number, width: number, height: number);\r\n constructor(westX?: number, northY?: number, width?: number, height?: number) {\r\n if (typeof westX === 'undefined') {\r\n westX = 0;\r\n }\r\n if (typeof northY === 'undefined') {\r\n northY = 0;\r\n }\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.northWest = new geom.Offset(westX, northY);\r\n this.size = new geom.Size(width, height);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.westX},${this.northY} ${this.width}x${this.height})`;\r\n }\r\n\r\n get northY() {\r\n return this.northWest.y;\r\n }\r\n\r\n get southY() {\r\n return this.northWest.y + this.size.height - 1;\r\n }\r\n\r\n get westX() {\r\n return this.northWest.x;\r\n }\r\n\r\n get eastX() {\r\n return this.northWest.x + this.size.width - 1;\r\n }\r\n\r\n get width() {\r\n return this.size.width;\r\n }\r\n\r\n get height() {\r\n return this.size.height;\r\n }\r\n\r\n get empty() {\r\n return this.size.empty;\r\n }\r\n\r\n get area() {\r\n return this.size.area;\r\n }\r\n\r\n // mutators\r\n\r\n copyFrom(other: RectangleLike) {\r\n this.northWest.set(other.westX, other.northY);\r\n this.size.set(other.width, other.height);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/rectangle.ts","import * as geom from '.';\r\n\r\nexport interface SizeLike {\r\n readonly width: number;\r\n readonly height: number;\r\n}\r\n\r\nexport class Size implements SizeLike {\r\n width: number;\r\n height: number;\r\n\r\n constructor();\r\n constructor(width: number, height: number);\r\n constructor(width?: number, height?: number) {\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.width = width;\r\n this.height = height;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.width}x${this.height})`;\r\n }\r\n\r\n get empty() {\r\n return this.width === 0 || this.height === 0;\r\n }\r\n\r\n get area() {\r\n return this.width * this.height;\r\n }\r\n\r\n // mutators\r\n\r\n set(width: number, height: number) {\r\n this.width = width;\r\n this.height = height;\r\n return this;\r\n }\r\n\r\n copyFrom(other: SizeLike) {\r\n this.width = other.width;\r\n this.height = other.height;\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return off.y * this.width + off.x;\r\n }\r\n\r\n forEach(cursor: geom.Offset, callback: (offset: geom.Offset) => void) {\r\n for (let dy = 0; dy < this.height; dy ++) {\r\n for (let dx = 0; dx < this.width; dx ++) {\r\n cursor.x = dx;\r\n cursor.y = dy;\r\n callback(cursor);\r\n }\r\n }\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/size.ts","/*\r\n * TheField\r\n * github.com/sbj42/the-field\r\n * James Clark\r\n * Licensed under the MIT license.\r\n */\r\n\r\nexport {FieldOfViewMap} from './field-of-view';\r\nexport {MaskRect} from './geom';\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.ts"],"sourceRoot":""} \ No newline at end of file diff --git a/bin/the-field-0.1.2.min.js b/bin/the-field-0.1.2.min.js deleted file mode 100644 index f8a9f93..0000000 --- a/bin/the-field-0.1.2.min.js +++ /dev/null @@ -1,2 +0,0 @@ -var TheField=function(t){function e(r){if(i[r])return i[r].exports;var n=i[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,e),n.l=!0,n.exports}var i={};return e.m=t,e.c=i,e.i=function(t){return t},e.d=function(t,i,r){e.o(t,i)||Object.defineProperty(t,i,{configurable:!1,enumerable:!0,get:r})},e.n=function(t){var i=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(i,"a",i),i},e.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},e.p="/bin/",e(e.s=7)}([function(t,e,i){"use strict";function r(t){for(var i in t)e.hasOwnProperty(i)||(e[i]=t[i])}Object.defineProperty(e,"__esModule",{value:!0}),r(i(4)),r(i(6)),r(i(5)),r(i(3)),r(i(2))},function(t,e,i){"use strict";function r(t,e,i,n){for(;;){if(e===t.length)return e;if(i<=t[e+s])break;e+=u}if(i<=t[e+o]){if(n>=t[e+s])return t.splice(e,u),r(t,e,i,n);n>=t[e+o]&&(t[e+o]=n)}else{if(n>=t[e+s])return t[e+s]=i,e+=u,r(t,e,i,n);t.splice(e,0,t[e+o],i),e+=u,t[e+o]=n}return e}Object.defineProperty(e,"__esModule",{value:!0});var n=i(0),o=0,s=1,u=2,h=new n.Offset,f=5,c=function(){function t(t,e){this._size=new n.Size,this._size.set(t,e),this._tileFlags=new Array(1+(this._size.area>>f)).fill(0)}return t.prototype.addBody=function(t,e){h.set(t,e);var i=this._size.index(h);this._tileFlags[i>>f]|=1<<(i&(1<>f]&=~(1<<(i&(1<>f]&1<<(i&(1<0;_++,b+=h*this._size.width,O+=h*t.width)for(var w=1/(_+.5),v=0===_?Number.POSITIVE_INFINITY:1/(_-.5),m=0,x=0,z=b,P=O,j=-.5*w,M=.5*v;x!==p&&m!==g.length;x++,z+=n,P+=n,j+=w,M+=v){for(;j>=g[m+s]&&!((m+=u)>=g.length););if(m>=g.length)break;if(!(M<=g[m+o])){t.setAt(P,!0);var F=(0!==x||0!==_)&&0!=(this._tileFlags[z>>f]&1<<(z&(1<=0&&t.y>=0&&t.x> FLAGS_POW2) + 1).fill(0);\r\n }\r\n // setup and maintenance\r\n FieldOfViewMap.prototype.addBody = function (x, y) {\r\n LOCAL_OFF.set(x, y);\r\n var index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1));\r\n };\r\n FieldOfViewMap.prototype.removeBody = function (x, y) {\r\n LOCAL_OFF.set(x, y);\r\n var index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1)));\r\n };\r\n FieldOfViewMap.prototype.getBody = function (x, y) {\r\n LOCAL_OFF.set(x, y);\r\n var index = this._size.index(LOCAL_OFF);\r\n return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n };\r\n // execution\r\n /**\r\n * Compute the field of view for a camera at the given tile.\r\n * chebyshevRadius is the vision radius. It uses chebyshev distance\r\n * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means\r\n * that the limit of vision in a large empty field will be square.\r\n *\r\n * This returns a MaskRect, which indicates which tiles are visible.\r\n * maskRect.get(x, y) will return true for visible tiles.\r\n */\r\n FieldOfViewMap.prototype.getFieldOfView = function (x, y, chebyshevRadius) {\r\n var origin = new geom.Offset(x, y);\r\n var boundRect = new geom.Rectangle(origin.x - chebyshevRadius, origin.y - chebyshevRadius, chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1);\r\n var mask = new geom.MaskRect(boundRect);\r\n // the player can always see itself\r\n mask.set(origin, true);\r\n // the field is divided into quadrants\r\n this._quadrant(mask, origin, chebyshevRadius, -1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, -1, 1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, 1);\r\n return mask;\r\n };\r\n FieldOfViewMap.prototype._quadrant = function (mask, origin, chebyshevRadius, xDir, yDir) {\r\n var startX = origin.x, startY = origin.y;\r\n var endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1), -1), this._size.width) - startX) * xDir;\r\n var endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1), -1), this._size.height) - startY) * yDir;\r\n if (endDX < 0 || endDY < 0) {\r\n // the origin is outside of the map\r\n return;\r\n }\r\n var startMapIndex = this._size.index(origin);\r\n var startMaskIndex = mask.index(origin);\r\n // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant)\r\n var wedges = [0, Number.POSITIVE_INFINITY];\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (var dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex; dy !== endDY && wedges.length > 0; dy++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width) {\r\n var divYpos = 1 / (dy + 0.5);\r\n var divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5);\r\n var wedgeIndex = 0;\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (var dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex, slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg; dx !== endDX && wedgeIndex !== wedges.length; dx++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir,\r\n slopeY = slopeY + divYpos, slopeX = slopeX + divYneg) {\r\n // the slopes of the four corners of this tile\r\n // these are named as follows:\r\n // slopeY is the slope closest to the Y axis\r\n // slopeX is the slope closest to the X axis\r\n // this is always true:\r\n // slopeY < slopeX\r\n //\r\n // O = origin, C = current\r\n // +---+---+---+\r\n // | O | | |\r\n // +---+---+---X\r\n // | | | C |\r\n // +---+---Y---+\r\n // advance the wedge index until this tile is not after the current wedge\r\n while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n wedgeIndex = wedgeIndex + WEDGE_COUNT;\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n }\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n // if the current wedge is after this tile, move on\r\n if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n continue;\r\n }\r\n // we can see this tile\r\n mask.setAt(maskIndex, true);\r\n // const/let must be at the top of a block, in order not to trigger deoptimization due to\r\n // https://github.com/nodejs/node/issues/9729\r\n {\r\n var body = (dx !== 0 || dy !== 0)\r\n && (this._tileFlags[mapIndex >> FLAGS_POW2]\r\n & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n if (body) {\r\n wedgeIndex = cutWedge(wedges, wedgeIndex, slopeY + BODY_EPSILON, slopeX - BODY_EPSILON);\r\n }\r\n }\r\n }\r\n }\r\n };\r\n return FieldOfViewMap;\r\n}());\r\nexports.FieldOfViewMap = FieldOfViewMap;\r\n/**\r\n * This function cuts a range of angles out of the wedge array.\r\n */\r\nfunction cutWedge(wedges, wedgeIndex, low, high) {\r\n for (;;) {\r\n if (wedgeIndex === wedges.length) {\r\n return wedgeIndex;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n break;\r\n }\r\n wedgeIndex += WEDGE_COUNT;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // wedge is entirely occluded, remove it\r\n wedges.splice(wedgeIndex, WEDGE_COUNT);\r\n // now looking at the next wedge (or past the end)\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n }\r\n else if (high >= wedges[wedgeIndex + WEDGE_LOW]) {\r\n // low part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // still looking at the same wedge\r\n }\r\n else {\r\n // this cut doesn't reach the current wedge\r\n }\r\n }\r\n else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // high part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_HIGH] = low;\r\n // move on to the next wedge\r\n wedgeIndex += WEDGE_COUNT;\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n }\r\n else {\r\n // middle part of wedge is occluded, split it\r\n wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low);\r\n wedgeIndex += WEDGE_COUNT;\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // now looking at the second wedge of the split\r\n }\r\n return wedgeIndex;\r\n}\r\n\n\n/***/ }),\n/* 2 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar geom = __webpack_require__(0);\r\nvar LOCAL_OFF = new geom.Offset();\r\nvar MaskRect = /** @class */ (function () {\r\n function MaskRect(rect, initialValue, outsideValue) {\r\n if (initialValue === void 0) { initialValue = false; }\r\n if (outsideValue === void 0) { outsideValue = false; }\r\n this._rectangle = new geom.Rectangle();\r\n this._rectangle.copyFrom(rect);\r\n this._mask = new geom.Mask(rect, initialValue);\r\n this._outsideValue = outsideValue;\r\n }\r\n // accessors\r\n MaskRect.prototype.toString = function () {\r\n return this._rectangle.northWest + \"/\" + this._outsideValue + \"\\n\" + this._mask;\r\n };\r\n Object.defineProperty(MaskRect.prototype, \"westX\", {\r\n get: function () {\r\n return this._rectangle.westX;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(MaskRect.prototype, \"northY\", {\r\n get: function () {\r\n return this._rectangle.northY;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(MaskRect.prototype, \"width\", {\r\n get: function () {\r\n return this._rectangle.width;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(MaskRect.prototype, \"height\", {\r\n get: function () {\r\n return this._rectangle.height;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n MaskRect.prototype.index = function (off) {\r\n return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest));\r\n };\r\n MaskRect.prototype.getAt = function (index) {\r\n return this._mask.getAt(index);\r\n };\r\n MaskRect.prototype.get = function (x, y) {\r\n LOCAL_OFF.set(x, y);\r\n if (!this._rectangle.containsOffset(LOCAL_OFF)) {\r\n return this._outsideValue;\r\n }\r\n return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest));\r\n };\r\n // mutators\r\n MaskRect.prototype.setAt = function (index, value) {\r\n this._mask.setAt(index, value);\r\n return this;\r\n };\r\n MaskRect.prototype.set = function (off, value) {\r\n this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value);\r\n return this;\r\n };\r\n // utilities\r\n MaskRect.prototype.forEach = function (cursor, callback) {\r\n var _this = this;\r\n this._mask.forEach(cursor, function (off, value) {\r\n callback(off.addOffset(_this._rectangle.northWest), value);\r\n });\r\n };\r\n return MaskRect;\r\n}());\r\nexports.MaskRect = MaskRect;\r\n\n\n/***/ }),\n/* 3 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar geom = __webpack_require__(0);\r\nvar Mask = /** @class */ (function () {\r\n // TODO consider Uint8Array for bits\r\n function Mask(size, initialValue) {\r\n if (initialValue === void 0) { initialValue = false; }\r\n this._size = new geom.Size();\r\n this._size.copyFrom(size);\r\n this._bits = new Array(this._size.area).fill(initialValue);\r\n }\r\n // accessors\r\n Mask.prototype.toString = function () {\r\n var ret = '';\r\n var off = new geom.Offset();\r\n for (var y = 0; y < this._size.height; y++) {\r\n for (var x = 0; x < this._size.width; x++) {\r\n off.set(x, y);\r\n ret += this.get(off.set(x, y)) ? '☑' : '☐';\r\n }\r\n ret += '\\n';\r\n }\r\n return ret;\r\n };\r\n Object.defineProperty(Mask.prototype, \"width\", {\r\n get: function () {\r\n return this._size.width;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Mask.prototype, \"height\", {\r\n get: function () {\r\n return this._size.height;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Mask.prototype.index = function (off) {\r\n return this._size.index(off);\r\n };\r\n Mask.prototype.getAt = function (index) {\r\n return this._bits[index];\r\n };\r\n Mask.prototype.get = function (off) {\r\n return this.getAt(this.index(off));\r\n };\r\n // mutators\r\n Mask.prototype.setAt = function (index, value) {\r\n this._bits[index] = value;\r\n return this;\r\n };\r\n Mask.prototype.set = function (off, value) {\r\n return this.setAt(this.index(off), value);\r\n };\r\n // utilities\r\n Mask.prototype.forEach = function (cursor, callback) {\r\n var _this = this;\r\n var index = 0;\r\n this._size.forEach(cursor, function (off) {\r\n callback(off, _this._bits[index]);\r\n index++;\r\n });\r\n };\r\n return Mask;\r\n}());\r\nexports.Mask = Mask;\r\n\n\n/***/ }),\n/* 4 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar Offset = /** @class */ (function () {\r\n function Offset(x, y) {\r\n if (typeof x === 'undefined') {\r\n x = 0;\r\n }\r\n if (typeof y === 'undefined') {\r\n y = 0;\r\n }\r\n this.x = x;\r\n this.y = y;\r\n }\r\n Offset.prototype.toString = function () {\r\n return \"(\" + this.x + \",\" + this.y + \")\";\r\n };\r\n // mutators\r\n Offset.prototype.set = function (x, y) {\r\n this.x = x;\r\n this.y = y;\r\n return this;\r\n };\r\n Offset.prototype.copyFrom = function (other) {\r\n this.x = other.x;\r\n this.y = other.y;\r\n return this;\r\n };\r\n Offset.prototype.addOffset = function (off) {\r\n this.x += off.x;\r\n this.y += off.y;\r\n return this;\r\n };\r\n Offset.prototype.subtractOffset = function (off) {\r\n this.x -= off.x;\r\n this.y -= off.y;\r\n return this;\r\n };\r\n return Offset;\r\n}());\r\nexports.Offset = Offset;\r\n\n\n/***/ }),\n/* 5 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar geom = __webpack_require__(0);\r\nvar LOCAL_OFF = new geom.Offset();\r\nvar Rectangle = /** @class */ (function () {\r\n function Rectangle(westX, northY, width, height) {\r\n if (typeof westX === 'undefined') {\r\n westX = 0;\r\n }\r\n if (typeof northY === 'undefined') {\r\n northY = 0;\r\n }\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.northWest = new geom.Offset(westX, northY);\r\n this.size = new geom.Size(width, height);\r\n }\r\n // accessors\r\n Rectangle.prototype.toString = function () {\r\n return \"(\" + this.westX + \",\" + this.northY + \" \" + this.width + \"x\" + this.height + \")\";\r\n };\r\n Object.defineProperty(Rectangle.prototype, \"northY\", {\r\n get: function () {\r\n return this.northWest.y;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"southY\", {\r\n get: function () {\r\n return this.northWest.y + this.size.height - 1;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"westX\", {\r\n get: function () {\r\n return this.northWest.x;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"eastX\", {\r\n get: function () {\r\n return this.northWest.x + this.size.width - 1;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"width\", {\r\n get: function () {\r\n return this.size.width;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"height\", {\r\n get: function () {\r\n return this.size.height;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"empty\", {\r\n get: function () {\r\n return this.size.empty;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Rectangle.prototype, \"area\", {\r\n get: function () {\r\n return this.size.area;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n // mutators\r\n Rectangle.prototype.copyFrom = function (other) {\r\n this.northWest.set(other.westX, other.northY);\r\n this.size.set(other.width, other.height);\r\n return this;\r\n };\r\n // utilities\r\n Rectangle.prototype.containsOffset = function (off) {\r\n return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n };\r\n Rectangle.prototype.index = function (off) {\r\n return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n };\r\n return Rectangle;\r\n}());\r\nexports.Rectangle = Rectangle;\r\n\n\n/***/ }),\n/* 6 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar Size = /** @class */ (function () {\r\n function Size(width, height) {\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.width = width;\r\n this.height = height;\r\n }\r\n // accessors\r\n Size.prototype.toString = function () {\r\n return \"(\" + this.width + \"x\" + this.height + \")\";\r\n };\r\n Object.defineProperty(Size.prototype, \"empty\", {\r\n get: function () {\r\n return this.width === 0 || this.height === 0;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n Object.defineProperty(Size.prototype, \"area\", {\r\n get: function () {\r\n return this.width * this.height;\r\n },\r\n enumerable: true,\r\n configurable: true\r\n });\r\n // mutators\r\n Size.prototype.set = function (width, height) {\r\n this.width = width;\r\n this.height = height;\r\n return this;\r\n };\r\n Size.prototype.copyFrom = function (other) {\r\n this.width = other.width;\r\n this.height = other.height;\r\n return this;\r\n };\r\n // utilities\r\n Size.prototype.containsOffset = function (off) {\r\n return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height;\r\n };\r\n Size.prototype.index = function (off) {\r\n return off.y * this.width + off.x;\r\n };\r\n Size.prototype.forEach = function (cursor, callback) {\r\n for (var dy = 0; dy < this.height; dy++) {\r\n for (var dx = 0; dx < this.width; dx++) {\r\n cursor.x = dx;\r\n cursor.y = dy;\r\n callback(cursor);\r\n }\r\n }\r\n };\r\n return Size;\r\n}());\r\nexports.Size = Size;\r\n\n\n/***/ }),\n/* 7 */\n/***/ (function(module, exports, __webpack_require__) {\n\n\"use strict\";\n\r\n/*\r\n * TheField\r\n * github.com/sbj42/the-field\r\n * James Clark\r\n * Licensed under the MIT license.\r\n */\r\nObject.defineProperty(exports, \"__esModule\", { value: true });\r\nvar field_of_view_1 = __webpack_require__(1);\r\nexports.FieldOfViewMap = field_of_view_1.FieldOfViewMap;\r\nvar geom_1 = __webpack_require__(0);\r\nexports.MaskRect = geom_1.MaskRect;\r\n\n\n/***/ })\n/******/ ]);\n\n\n// WEBPACK FOOTER //\n// the-field-0.1.2.min.js"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// identity function for calling harmony imports with the correct context\n \t__webpack_require__.i = function(value) { return value; };\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/bin/\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 7);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 9de17af506680bb139ee","export * from './offset';\r\nexport * from './size';\r\nexport * from './rectangle';\r\nexport * from './mask';\r\nexport * from './mask-rect';\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/index.ts","import * as geom from './geom';\r\n\r\n// tslint:disable:no-bitwise\r\n\r\n/**\r\n * In the shadowcasting algorithm, each shadow is represented by a \"wedge\",\r\n * running from a \"low\" angle to a \"high\" angle. The wedges are all stored in\r\n * a simple number array, with two numbers for each wedge. These constants\r\n * (WEDGE_LOW and WEDGE_HIGH) help to identify which number is which.\r\n * WEDGE_COUNT is just how many numbers per wedge.\r\n */\r\nconst WEDGE_LOW = 0;\r\nconst WEDGE_HIGH = 1;\r\nconst WEDGE_COUNT = 2;\r\n\r\n/**\r\n * Bodies in this algorithm do not entirely fill their tiles. This is\r\n * implemented by adjusting the angles of the shadows the bodies cast,\r\n * making the wedge very slightly narrower. BODY_EPSILON represents the\r\n * amount of reduction on either side of the wedge.\r\n */\r\nconst BODY_EPSILON = 0.00001;\r\n\r\n/**\r\n * We avoid heap allocations during the core part of the algorithm by using this\r\n * preallocated offset object.\r\n */\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\n/**\r\n * For each number in the _tileFlags array, we store (1 << FLAGS_POW2) cells,\r\n * as bits where a true indicates the presence of a body.\r\n */\r\nconst FLAGS_POW2 = 5;\r\n\r\n/**\r\n * The FieldOFViewMap represents the map over which the field of view will be\r\n * computed. It starts out empty. You can add walls and bodies to it, and then\r\n * use getFieldOfView() to compute the field of view from a given point.\r\n */\r\nexport class FieldOfViewMap {\r\n private readonly _size = new geom.Size();\r\n private readonly _tileFlags: number[];\r\n\r\n constructor(width: number, height: number) {\r\n this._size.set(width, height);\r\n this._tileFlags = new Array((this._size.area >> FLAGS_POW2) + 1).fill(0);\r\n }\r\n\r\n // setup and maintenance\r\n\r\n addBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1));\r\n }\r\n\r\n removeBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1)));\r\n }\r\n\r\n getBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n }\r\n\r\n // execution\r\n\r\n /**\r\n * Compute the field of view for a camera at the given tile.\r\n * chebyshevRadius is the vision radius. It uses chebyshev distance\r\n * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means\r\n * that the limit of vision in a large empty field will be square.\r\n *\r\n * This returns a MaskRect, which indicates which tiles are visible.\r\n * maskRect.get(x, y) will return true for visible tiles.\r\n */\r\n getFieldOfView(x: number, y: number, chebyshevRadius: number): geom.MaskRect {\r\n const origin = new geom.Offset(x, y);\r\n const boundRect = new geom.Rectangle(\r\n origin.x - chebyshevRadius, origin.y - chebyshevRadius,\r\n chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1,\r\n );\r\n const mask = new geom.MaskRect(boundRect);\r\n // the player can always see itself\r\n mask.set(origin, true);\r\n // the field is divided into quadrants\r\n this._quadrant(mask, origin, chebyshevRadius, -1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, -1, 1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, 1);\r\n return mask;\r\n }\r\n\r\n private _quadrant(mask: geom.MaskRect, origin: geom.OffsetLike, chebyshevRadius: number,\r\n xDir: number, yDir: number) {\r\n const {x: startX, y: startY} = origin;\r\n const endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1),\r\n -1), this._size.width) - startX) * xDir;\r\n const endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1),\r\n -1), this._size.height) - startY) * yDir;\r\n if (endDX < 0 || endDY < 0) {\r\n // the origin is outside of the map\r\n return;\r\n }\r\n const startMapIndex = this._size.index(origin);\r\n const startMaskIndex = mask.index(origin);\r\n // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant)\r\n const wedges = [0, Number.POSITIVE_INFINITY];\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex;\r\n dy !== endDY && wedges.length > 0;\r\n dy ++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width\r\n ) {\r\n const divYpos = 1 / (dy + 0.5);\r\n const divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5);\r\n let wedgeIndex = 0;\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex,\r\n slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg;\r\n dx !== endDX && wedgeIndex !== wedges.length;\r\n dx ++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir,\r\n slopeY = slopeY + divYpos, slopeX = slopeX + divYneg\r\n ) {\r\n // the slopes of the four corners of this tile\r\n // these are named as follows:\r\n // slopeY is the slope closest to the Y axis\r\n // slopeX is the slope closest to the X axis\r\n // this is always true:\r\n // slopeY < slopeX\r\n //\r\n // O = origin, C = current\r\n // +---+---+---+\r\n // | O | | |\r\n // +---+---+---X\r\n // | | | C |\r\n // +---+---Y---+\r\n\r\n // advance the wedge index until this tile is not after the current wedge\r\n while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n wedgeIndex = wedgeIndex + WEDGE_COUNT;\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n }\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n\r\n // if the current wedge is after this tile, move on\r\n if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n continue;\r\n }\r\n\r\n // we can see this tile\r\n mask.setAt(maskIndex, true);\r\n\r\n // const/let must be at the top of a block, in order not to trigger deoptimization due to\r\n // https://github.com/nodejs/node/issues/9729\r\n {\r\n const body = (dx !== 0 || dy !== 0)\r\n && (this._tileFlags[mapIndex >> FLAGS_POW2]\r\n & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n if (body) {\r\n wedgeIndex = cutWedge(wedges, wedgeIndex,\r\n slopeY + BODY_EPSILON, slopeX - BODY_EPSILON);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * This function cuts a range of angles out of the wedge array.\r\n */\r\nfunction cutWedge(wedges: number[], wedgeIndex: number, low: number, high: number): number {\r\n for (; ; ) {\r\n if (wedgeIndex === wedges.length) {\r\n return wedgeIndex;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n break;\r\n }\r\n wedgeIndex += WEDGE_COUNT;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // wedge is entirely occluded, remove it\r\n wedges.splice(wedgeIndex, WEDGE_COUNT);\r\n // now looking at the next wedge (or past the end)\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else if (high >= wedges[wedgeIndex + WEDGE_LOW]) {\r\n // low part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // still looking at the same wedge\r\n } else {\r\n // this cut doesn't reach the current wedge\r\n }\r\n } else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // high part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_HIGH] = low;\r\n // move on to the next wedge\r\n wedgeIndex += WEDGE_COUNT;\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else {\r\n // middle part of wedge is occluded, split it\r\n wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low);\r\n wedgeIndex += WEDGE_COUNT;\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // now looking at the second wedge of the split\r\n }\r\n return wedgeIndex;\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/field-of-view.ts","import * as geom from '.';\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class MaskRect implements geom.RectangleLike {\r\n private readonly _rectangle = new geom.Rectangle();\r\n private readonly _mask: geom.Mask;\r\n private readonly _outsideValue: boolean;\r\n\r\n constructor(rect: geom.RectangleLike, initialValue = false, outsideValue = false) {\r\n this._rectangle.copyFrom(rect);\r\n this._mask = new geom.Mask(rect, initialValue);\r\n this._outsideValue = outsideValue;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `${this._rectangle.northWest}/${this._outsideValue}\\n${this._mask}`;\r\n }\r\n\r\n get westX() {\r\n return this._rectangle.westX;\r\n }\r\n\r\n get northY() {\r\n return this._rectangle.northY;\r\n }\r\n\r\n get width() {\r\n return this._rectangle.width;\r\n }\r\n\r\n get height() {\r\n return this._rectangle.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest));\r\n }\r\n\r\n getAt(index: number) {\r\n return this._mask.getAt(index);\r\n }\r\n\r\n get(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n if (!this._rectangle.containsOffset(LOCAL_OFF)) {\r\n return this._outsideValue;\r\n }\r\n return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest));\r\n }\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._mask.setAt(index, value);\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n this._mask.forEach(cursor, (off, value) => {\r\n callback(off.addOffset(this._rectangle.northWest), value);\r\n });\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/mask-rect.ts","import * as geom from '.';\r\n\r\nexport class Mask implements geom.SizeLike {\r\n private readonly _size = new geom.Size();\r\n private readonly _bits: boolean[];\r\n // TODO consider Uint8Array for bits\r\n\r\n constructor(size: geom.SizeLike, initialValue = false) {\r\n this._size.copyFrom(size);\r\n this._bits = new Array(this._size.area).fill(initialValue);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n let ret = '';\r\n const off = new geom.Offset();\r\n for (let y = 0; y < this._size.height; y ++) {\r\n for (let x = 0; x < this._size.width; x ++) {\r\n off.set(x, y);\r\n ret += this.get(off.set(x, y)) ? '☑' : '☐';\r\n }\r\n ret += '\\n';\r\n }\r\n return ret;\r\n }\r\n\r\n get width() {\r\n return this._size.width;\r\n }\r\n\r\n get height() {\r\n return this._size.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._size.index(off);\r\n }\r\n\r\n getAt(index: number) {\r\n return this._bits[index];\r\n }\r\n\r\n get(off: geom.OffsetLike) {\r\n return this.getAt(this.index(off));\r\n }\r\n\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._bits[index] = value;\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n return this.setAt(this.index(off), value);\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n let index = 0;\r\n this._size.forEach(cursor, (off) => {\r\n callback(off, this._bits[index]);\r\n index ++;\r\n });\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/mask.ts","export interface OffsetLike {\r\n readonly x: number;\r\n readonly y: number;\r\n}\r\n\r\nexport class Offset implements OffsetLike {\r\n x: number;\r\n y: number;\r\n\r\n constructor();\r\n constructor(x: number, y: number);\r\n constructor(x?: number, y?: number) {\r\n if (typeof x === 'undefined') {\r\n x = 0;\r\n }\r\n if (typeof y === 'undefined') {\r\n y = 0;\r\n }\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n toString() {\r\n return `(${this.x},${this.y})`;\r\n }\r\n\r\n // mutators\r\n\r\n set(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n return this;\r\n }\r\n\r\n copyFrom(other: OffsetLike) {\r\n this.x = other.x;\r\n this.y = other.y;\r\n return this;\r\n }\r\n\r\n addOffset(off: OffsetLike) {\r\n this.x += off.x;\r\n this.y += off.y;\r\n return this;\r\n }\r\n\r\n subtractOffset(off: OffsetLike) {\r\n this.x -= off.x;\r\n this.y -= off.y;\r\n return this;\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/offset.ts","import * as geom from '.';\r\n\r\nexport interface RectangleLike extends geom.SizeLike {\r\n readonly westX: number;\r\n readonly northY: number;\r\n}\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class Rectangle implements RectangleLike, geom.SizeLike {\r\n northWest: geom.Offset;\r\n size: geom.Size;\r\n\r\n constructor();\r\n constructor(westX: number, northY: number, width: number, height: number);\r\n constructor(westX?: number, northY?: number, width?: number, height?: number) {\r\n if (typeof westX === 'undefined') {\r\n westX = 0;\r\n }\r\n if (typeof northY === 'undefined') {\r\n northY = 0;\r\n }\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.northWest = new geom.Offset(westX, northY);\r\n this.size = new geom.Size(width, height);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.westX},${this.northY} ${this.width}x${this.height})`;\r\n }\r\n\r\n get northY() {\r\n return this.northWest.y;\r\n }\r\n\r\n get southY() {\r\n return this.northWest.y + this.size.height - 1;\r\n }\r\n\r\n get westX() {\r\n return this.northWest.x;\r\n }\r\n\r\n get eastX() {\r\n return this.northWest.x + this.size.width - 1;\r\n }\r\n\r\n get width() {\r\n return this.size.width;\r\n }\r\n\r\n get height() {\r\n return this.size.height;\r\n }\r\n\r\n get empty() {\r\n return this.size.empty;\r\n }\r\n\r\n get area() {\r\n return this.size.area;\r\n }\r\n\r\n // mutators\r\n\r\n copyFrom(other: RectangleLike) {\r\n this.northWest.set(other.westX, other.northY);\r\n this.size.set(other.width, other.height);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/rectangle.ts","import * as geom from '.';\r\n\r\nexport interface SizeLike {\r\n readonly width: number;\r\n readonly height: number;\r\n}\r\n\r\nexport class Size implements SizeLike {\r\n width: number;\r\n height: number;\r\n\r\n constructor();\r\n constructor(width: number, height: number);\r\n constructor(width?: number, height?: number) {\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.width = width;\r\n this.height = height;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.width}x${this.height})`;\r\n }\r\n\r\n get empty() {\r\n return this.width === 0 || this.height === 0;\r\n }\r\n\r\n get area() {\r\n return this.width * this.height;\r\n }\r\n\r\n // mutators\r\n\r\n set(width: number, height: number) {\r\n this.width = width;\r\n this.height = height;\r\n return this;\r\n }\r\n\r\n copyFrom(other: SizeLike) {\r\n this.width = other.width;\r\n this.height = other.height;\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return off.y * this.width + off.x;\r\n }\r\n\r\n forEach(cursor: geom.Offset, callback: (offset: geom.Offset) => void) {\r\n for (let dy = 0; dy < this.height; dy ++) {\r\n for (let dx = 0; dx < this.width; dx ++) {\r\n cursor.x = dx;\r\n cursor.y = dy;\r\n callback(cursor);\r\n }\r\n }\r\n }\r\n}\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/geom/size.ts","/*\r\n * TheField\r\n * github.com/sbj42/the-field\r\n * James Clark\r\n * Licensed under the MIT license.\r\n */\r\n\r\nexport {FieldOfViewMap} from './field-of-view';\r\nexport {MaskRect} from './geom';\r\n\n\n\n// WEBPACK FOOTER //\n// ./src/index.ts"],"sourceRoot":""} \ No newline at end of file diff --git a/bin/the-field-1.0.0.js b/bin/the-field-1.0.0.js new file mode 100644 index 0000000..dbbe6a4 --- /dev/null +++ b/bin/the-field-1.0.0.js @@ -0,0 +1,2 @@ +var TheField=function(t){var e={};function i(r){if(e[r])return e[r].exports;var n=e[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=t,i.c=e,i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)i.d(r,n,function(e){return t[e]}.bind(null,n));return r},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="/bin/",i(i.s=7)}([function(t,e,i){"use strict";function r(t){for(var i in t)e.hasOwnProperty(i)||(e[i]=t[i])}Object.defineProperty(e,"__esModule",{value:!0}),r(i(5)),r(i(4)),r(i(3)),r(i(2)),r(i(1))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(0),n=new r.Offset,o=function(){function t(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1),this._rectangle=new r.Rectangle,this._rectangle.copyFrom(t),this._mask=new r.Mask(t,e),this._outsideValue=i}return t.prototype.toString=function(){return this._rectangle.northWest+"/"+this._outsideValue+"\n"+this._mask},Object.defineProperty(t.prototype,"westX",{get:function(){return this._rectangle.westX},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"northY",{get:function(){return this._rectangle.northY},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"width",{get:function(){return this._rectangle.width},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"height",{get:function(){return this._rectangle.height},enumerable:!0,configurable:!0}),t.prototype.index=function(t){return this._mask.index(n.copyFrom(t).subtractOffset(this._rectangle.northWest))},t.prototype.getAt=function(t){return this._mask.getAt(t)},t.prototype.get=function(t,e){return n.set(t,e),this._rectangle.containsOffset(n)?this._mask.get(n.subtractOffset(this._rectangle.northWest)):this._outsideValue},t.prototype.setAt=function(t,e){return this._mask.setAt(t,e),this},t.prototype.set=function(t,e){return this._mask.set(n.copyFrom(t).subtractOffset(this._rectangle.northWest),e),this},t.prototype.forEach=function(t,e){var i=this;this._mask.forEach(t,function(t,r){e(t.addOffset(i._rectangle.northWest),r)})},t}();e.MaskRect=o},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(0),n=function(){function t(t,e){void 0===e&&(e=!1),this._size=new r.Size,this._size.copyFrom(t),this._bits=new Array(this._size.area).fill(e)}return t.prototype.toString=function(){for(var t="",e=new r.Offset,i=0;i=0&&t.y>=0&&t.x>h)).fill(0)}return t.prototype.addBody=function(t,e){u.set(t,e);var i=this._size.index(u);this._tileFlags[i>>h]|=1<<(i&(1<>h]&=~(1<<(i&(1<>h]&1<<(i&(1<0;b++,_+=u*this._size.width,O+=u*t.width)for(var v=1/(b+.5),m=0===b?Number.POSITIVE_INFINITY:1/(b-.5),w=0,x=0,z=_,P=O,j=-.5*v,M=.5*m;x!==p&&w!==g.length;x++,z+=r,P+=r,j+=v,M+=m){for(;j>=g[w+o]&&!((w+=s)>=g.length););if(w>=g.length)break;if(!(M<=g[w+n]))t.setAt(P,!0),(0!==x||0!==b)&&0!=(this._tileFlags[z>>h]&1<<(z&(1<=t[e+o])return t.splice(e,s),c(t,e,i,r);r>=t[e+n]&&(t[e+n]=r)}else{if(r>=t[e+o])return t[e+o]=i,c(t,e+=s,i,r);t.splice(e,0,t[e+n],i),t[(e+=s)+n]=r}return e}e.FieldOfViewMap=f},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(6);e.FieldOfViewMap=r.FieldOfViewMap;var n=i(0);e.MaskRect=n.MaskRect}]); +//# sourceMappingURL=the-field-1.0.0.js.map \ No newline at end of file diff --git a/bin/the-field-1.0.0.js.map b/bin/the-field-1.0.0.js.map new file mode 100644 index 0000000..2c9aa0b --- /dev/null +++ b/bin/the-field-1.0.0.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://TheField/webpack/bootstrap","webpack://TheField/./src/geom/index.ts","webpack://TheField/./src/geom/mask-rect.ts","webpack://TheField/./src/geom/mask.ts","webpack://TheField/./src/geom/rectangle.ts","webpack://TheField/./src/geom/size.ts","webpack://TheField/./src/geom/offset.ts","webpack://TheField/./src/field-of-view.ts","webpack://TheField/./src/index.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","__export","geom","LOCAL_OFF","Offset","MaskRect","rect","initialValue","outsideValue","this","_rectangle","Rectangle","copyFrom","_mask","Mask","_outsideValue","toString","northWest","westX","northY","width","height","index","off","subtractOffset","getAt","x","y","set","containsOffset","setAt","forEach","cursor","callback","_this","addOffset","size","_size","Size","_bits","Array","area","fill","ret","empty","other","dy","dx","WEDGE_LOW","WEDGE_HIGH","WEDGE_COUNT","FLAGS_POW2","FieldOfViewMap","_tileFlags","addBody","removeBody","getBody","getFieldOfView","chebyshevRadius","origin","boundRect","mask","_quadrant","xDir","yDir","startX","startY","endDX","Math","min","max","endDY","startMapIndex","startMaskIndex","wedges","Number","POSITIVE_INFINITY","yMapIndex","yMaskIndex","length","divYpos","divYneg","wedgeIndex","mapIndex","maskIndex","slopeY","slopeX","cutWedge","low","high","splice","field_of_view_1","geom_1"],"mappings":"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","file":"the-field-1.0.0.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/bin/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 7);\n","export * from './offset';\r\nexport * from './size';\r\nexport * from './rectangle';\r\nexport * from './mask';\r\nexport * from './mask-rect';\r\n","import * as geom from '.';\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class MaskRect implements geom.RectangleLike {\r\n private readonly _rectangle = new geom.Rectangle();\r\n private readonly _mask: geom.Mask;\r\n private readonly _outsideValue: boolean;\r\n\r\n constructor(rect: geom.RectangleLike, initialValue = false, outsideValue = false) {\r\n this._rectangle.copyFrom(rect);\r\n this._mask = new geom.Mask(rect, initialValue);\r\n this._outsideValue = outsideValue;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `${this._rectangle.northWest}/${this._outsideValue}\\n${this._mask}`;\r\n }\r\n\r\n get westX() {\r\n return this._rectangle.westX;\r\n }\r\n\r\n get northY() {\r\n return this._rectangle.northY;\r\n }\r\n\r\n get width() {\r\n return this._rectangle.width;\r\n }\r\n\r\n get height() {\r\n return this._rectangle.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest));\r\n }\r\n\r\n getAt(index: number) {\r\n return this._mask.getAt(index);\r\n }\r\n\r\n get(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n if (!this._rectangle.containsOffset(LOCAL_OFF)) {\r\n return this._outsideValue;\r\n }\r\n return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest));\r\n }\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._mask.setAt(index, value);\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n this._mask.forEach(cursor, (off, value) => {\r\n callback(off.addOffset(this._rectangle.northWest), value);\r\n });\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport class Mask implements geom.SizeLike {\r\n private readonly _size = new geom.Size();\r\n private readonly _bits: boolean[];\r\n // TODO consider Uint8Array for bits\r\n\r\n constructor(size: geom.SizeLike, initialValue = false) {\r\n this._size.copyFrom(size);\r\n this._bits = new Array(this._size.area).fill(initialValue);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n let ret = '';\r\n const off = new geom.Offset();\r\n for (let y = 0; y < this._size.height; y ++) {\r\n for (let x = 0; x < this._size.width; x ++) {\r\n off.set(x, y);\r\n ret += this.get(off.set(x, y)) ? '☑' : '☐';\r\n }\r\n ret += '\\n';\r\n }\r\n return ret;\r\n }\r\n\r\n get width() {\r\n return this._size.width;\r\n }\r\n\r\n get height() {\r\n return this._size.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._size.index(off);\r\n }\r\n\r\n getAt(index: number) {\r\n return this._bits[index];\r\n }\r\n\r\n get(off: geom.OffsetLike) {\r\n return this.getAt(this.index(off));\r\n }\r\n\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._bits[index] = value;\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n return this.setAt(this.index(off), value);\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n let index = 0;\r\n this._size.forEach(cursor, (off) => {\r\n callback(off, this._bits[index]);\r\n index ++;\r\n });\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport interface RectangleLike extends geom.SizeLike {\r\n readonly westX: number;\r\n readonly northY: number;\r\n}\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class Rectangle implements RectangleLike, geom.SizeLike {\r\n northWest: geom.Offset;\r\n size: geom.Size;\r\n\r\n constructor();\r\n constructor(westX: number, northY: number, width: number, height: number);\r\n constructor(westX?: number, northY?: number, width?: number, height?: number) {\r\n if (typeof westX === 'undefined') {\r\n westX = 0;\r\n }\r\n if (typeof northY === 'undefined') {\r\n northY = 0;\r\n }\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.northWest = new geom.Offset(westX, northY);\r\n this.size = new geom.Size(width, height);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.westX},${this.northY} ${this.width}x${this.height})`;\r\n }\r\n\r\n get northY() {\r\n return this.northWest.y;\r\n }\r\n\r\n get southY() {\r\n return this.northWest.y + this.size.height - 1;\r\n }\r\n\r\n get westX() {\r\n return this.northWest.x;\r\n }\r\n\r\n get eastX() {\r\n return this.northWest.x + this.size.width - 1;\r\n }\r\n\r\n get width() {\r\n return this.size.width;\r\n }\r\n\r\n get height() {\r\n return this.size.height;\r\n }\r\n\r\n get empty() {\r\n return this.size.empty;\r\n }\r\n\r\n get area() {\r\n return this.size.area;\r\n }\r\n\r\n // mutators\r\n\r\n copyFrom(other: RectangleLike) {\r\n this.northWest.set(other.westX, other.northY);\r\n this.size.set(other.width, other.height);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport interface SizeLike {\r\n readonly width: number;\r\n readonly height: number;\r\n}\r\n\r\nexport class Size implements SizeLike {\r\n width: number;\r\n height: number;\r\n\r\n constructor();\r\n constructor(width: number, height: number);\r\n constructor(width?: number, height?: number) {\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.width = width;\r\n this.height = height;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.width}x${this.height})`;\r\n }\r\n\r\n get empty() {\r\n return this.width === 0 || this.height === 0;\r\n }\r\n\r\n get area() {\r\n return this.width * this.height;\r\n }\r\n\r\n // mutators\r\n\r\n set(width: number, height: number) {\r\n this.width = width;\r\n this.height = height;\r\n return this;\r\n }\r\n\r\n copyFrom(other: SizeLike) {\r\n this.width = other.width;\r\n this.height = other.height;\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return off.y * this.width + off.x;\r\n }\r\n\r\n forEach(cursor: geom.Offset, callback: (offset: geom.Offset) => void) {\r\n for (let dy = 0; dy < this.height; dy ++) {\r\n for (let dx = 0; dx < this.width; dx ++) {\r\n cursor.x = dx;\r\n cursor.y = dy;\r\n callback(cursor);\r\n }\r\n }\r\n }\r\n}\r\n","export interface OffsetLike {\r\n readonly x: number;\r\n readonly y: number;\r\n}\r\n\r\nexport class Offset implements OffsetLike {\r\n x: number;\r\n y: number;\r\n\r\n constructor();\r\n constructor(x: number, y: number);\r\n constructor(x?: number, y?: number) {\r\n if (typeof x === 'undefined') {\r\n x = 0;\r\n }\r\n if (typeof y === 'undefined') {\r\n y = 0;\r\n }\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n toString() {\r\n return `(${this.x},${this.y})`;\r\n }\r\n\r\n // mutators\r\n\r\n set(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n return this;\r\n }\r\n\r\n copyFrom(other: OffsetLike) {\r\n this.x = other.x;\r\n this.y = other.y;\r\n return this;\r\n }\r\n\r\n addOffset(off: OffsetLike) {\r\n this.x += off.x;\r\n this.y += off.y;\r\n return this;\r\n }\r\n\r\n subtractOffset(off: OffsetLike) {\r\n this.x -= off.x;\r\n this.y -= off.y;\r\n return this;\r\n }\r\n}\r\n","import * as geom from './geom';\r\n\r\n// tslint:disable:no-bitwise\r\n\r\n/**\r\n * In the shadowcasting algorithm, each shadow is represented by a \"wedge\",\r\n * running from a \"low\" angle to a \"high\" angle. The wedges are all stored in\r\n * a simple number array, with two numbers for each wedge. These constants\r\n * (WEDGE_LOW and WEDGE_HIGH) help to identify which number is which.\r\n * WEDGE_COUNT is just how many numbers per wedge.\r\n */\r\nconst WEDGE_LOW = 0;\r\nconst WEDGE_HIGH = 1;\r\nconst WEDGE_COUNT = 2;\r\n\r\n/**\r\n * Bodies in this algorithm do not entirely fill their tiles. This is\r\n * implemented by adjusting the angles of the shadows the bodies cast,\r\n * making the wedge very slightly narrower. BODY_EPSILON represents the\r\n * amount of reduction on either side of the wedge.\r\n */\r\nconst BODY_EPSILON = 0.00001;\r\n\r\n/**\r\n * We avoid heap allocations during the core part of the algorithm by using this\r\n * preallocated offset object.\r\n */\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\n/**\r\n * For each number in the _tileFlags array, we store (1 << FLAGS_POW2) cells,\r\n * as bits where a true indicates the presence of a body.\r\n */\r\nconst FLAGS_POW2 = 5;\r\n\r\n/**\r\n * The FieldOFViewMap represents the map over which the field of view will be\r\n * computed. It starts out empty. You can add walls and bodies to it, and then\r\n * use getFieldOfView() to compute the field of view from a given point.\r\n */\r\nexport class FieldOfViewMap {\r\n private readonly _size = new geom.Size();\r\n private readonly _tileFlags: number[];\r\n\r\n constructor(width: number, height: number) {\r\n this._size.set(width, height);\r\n this._tileFlags = new Array((this._size.area >> FLAGS_POW2) + 1).fill(0);\r\n }\r\n\r\n // setup and maintenance\r\n\r\n addBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1));\r\n }\r\n\r\n removeBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1)));\r\n }\r\n\r\n getBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n }\r\n\r\n // execution\r\n\r\n /**\r\n * Compute the field of view for a camera at the given tile.\r\n * chebyshevRadius is the vision radius. It uses chebyshev distance\r\n * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means\r\n * that the limit of vision in a large empty field will be square.\r\n *\r\n * This returns a MaskRect, which indicates which tiles are visible.\r\n * maskRect.get(x, y) will return true for visible tiles.\r\n */\r\n getFieldOfView(x: number, y: number, chebyshevRadius: number): geom.MaskRect {\r\n const origin = new geom.Offset(x, y);\r\n const boundRect = new geom.Rectangle(\r\n origin.x - chebyshevRadius, origin.y - chebyshevRadius,\r\n chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1,\r\n );\r\n const mask = new geom.MaskRect(boundRect);\r\n // the player can always see itself\r\n mask.set(origin, true);\r\n // the field is divided into quadrants\r\n this._quadrant(mask, origin, chebyshevRadius, -1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, -1, 1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, 1);\r\n return mask;\r\n }\r\n\r\n private _quadrant(mask: geom.MaskRect, origin: geom.OffsetLike, chebyshevRadius: number,\r\n xDir: number, yDir: number) {\r\n const {x: startX, y: startY} = origin;\r\n const endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1),\r\n -1), this._size.width) - startX) * xDir;\r\n const endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1),\r\n -1), this._size.height) - startY) * yDir;\r\n if (endDX < 0 || endDY < 0) {\r\n // the origin is outside of the map\r\n return;\r\n }\r\n const startMapIndex = this._size.index(origin);\r\n const startMaskIndex = mask.index(origin);\r\n // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant)\r\n const wedges = [0, Number.POSITIVE_INFINITY];\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex;\r\n dy !== endDY && wedges.length > 0;\r\n dy ++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width\r\n ) {\r\n const divYpos = 1 / (dy + 0.5);\r\n const divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5);\r\n let wedgeIndex = 0;\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex,\r\n slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg;\r\n dx !== endDX && wedgeIndex !== wedges.length;\r\n dx ++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir,\r\n slopeY = slopeY + divYpos, slopeX = slopeX + divYneg\r\n ) {\r\n // the slopes of the four corners of this tile\r\n // these are named as follows:\r\n // slopeY is the slope closest to the Y axis\r\n // slopeX is the slope closest to the X axis\r\n // this is always true:\r\n // slopeY < slopeX\r\n //\r\n // O = origin, C = current\r\n // +---+---+---+\r\n // | O | | |\r\n // +---+---+---X\r\n // | | | C |\r\n // +---+---Y---+\r\n\r\n // advance the wedge index until this tile is not after the current wedge\r\n while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n wedgeIndex = wedgeIndex + WEDGE_COUNT;\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n }\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n\r\n // if the current wedge is after this tile, move on\r\n if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n continue;\r\n }\r\n\r\n // we can see this tile\r\n mask.setAt(maskIndex, true);\r\n\r\n // const/let must be at the top of a block, in order not to trigger deoptimization due to\r\n // https://github.com/nodejs/node/issues/9729\r\n {\r\n const body = (dx !== 0 || dy !== 0)\r\n && (this._tileFlags[mapIndex >> FLAGS_POW2]\r\n & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n if (body) {\r\n wedgeIndex = cutWedge(wedges, wedgeIndex,\r\n slopeY + BODY_EPSILON, slopeX - BODY_EPSILON);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * This function cuts a range of angles out of the wedge array.\r\n */\r\nfunction cutWedge(wedges: number[], wedgeIndex: number, low: number, high: number): number {\r\n for (; ; ) {\r\n if (wedgeIndex === wedges.length) {\r\n return wedgeIndex;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n break;\r\n }\r\n wedgeIndex += WEDGE_COUNT;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // wedge is entirely occluded, remove it\r\n wedges.splice(wedgeIndex, WEDGE_COUNT);\r\n // now looking at the next wedge (or past the end)\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else if (high >= wedges[wedgeIndex + WEDGE_LOW]) {\r\n // low part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // still looking at the same wedge\r\n } else {\r\n // this cut doesn't reach the current wedge\r\n }\r\n } else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // high part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_HIGH] = low;\r\n // move on to the next wedge\r\n wedgeIndex += WEDGE_COUNT;\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else {\r\n // middle part of wedge is occluded, split it\r\n wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low);\r\n wedgeIndex += WEDGE_COUNT;\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // now looking at the second wedge of the split\r\n }\r\n return wedgeIndex;\r\n}\r\n","/*\r\n * TheField\r\n * github.com/sbj42/the-field\r\n * James Clark\r\n * Licensed under the MIT license.\r\n */\r\n\r\nexport {FieldOfViewMap} from './field-of-view';\r\nexport {MaskRect} from './geom';\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/bin/the-field-1.0.0.min.js b/bin/the-field-1.0.0.min.js new file mode 100644 index 0000000..b4a6f1c --- /dev/null +++ b/bin/the-field-1.0.0.min.js @@ -0,0 +1,2 @@ +var TheField=function(t){var e={};function i(r){if(e[r])return e[r].exports;var n=e[r]={i:r,l:!1,exports:{}};return t[r].call(n.exports,n,n.exports,i),n.l=!0,n.exports}return i.m=t,i.c=e,i.d=function(t,e,r){i.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:r})},i.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},i.t=function(t,e){if(1&e&&(t=i(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var n in t)i.d(r,n,function(e){return t[e]}.bind(null,n));return r},i.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return i.d(e,"a",e),e},i.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},i.p="/bin/",i(i.s=7)}([function(t,e,i){"use strict";function r(t){for(var i in t)e.hasOwnProperty(i)||(e[i]=t[i])}Object.defineProperty(e,"__esModule",{value:!0}),r(i(5)),r(i(4)),r(i(3)),r(i(2)),r(i(1))},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(0),n=new r.Offset,o=function(){function t(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1),this._rectangle=new r.Rectangle,this._rectangle.copyFrom(t),this._mask=new r.Mask(t,e),this._outsideValue=i}return t.prototype.toString=function(){return this._rectangle.northWest+"/"+this._outsideValue+"\n"+this._mask},Object.defineProperty(t.prototype,"westX",{get:function(){return this._rectangle.westX},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"northY",{get:function(){return this._rectangle.northY},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"width",{get:function(){return this._rectangle.width},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"height",{get:function(){return this._rectangle.height},enumerable:!0,configurable:!0}),t.prototype.index=function(t){return this._mask.index(n.copyFrom(t).subtractOffset(this._rectangle.northWest))},t.prototype.getAt=function(t){return this._mask.getAt(t)},t.prototype.get=function(t,e){return n.set(t,e),this._rectangle.containsOffset(n)?this._mask.get(n.subtractOffset(this._rectangle.northWest)):this._outsideValue},t.prototype.setAt=function(t,e){return this._mask.setAt(t,e),this},t.prototype.set=function(t,e){return this._mask.set(n.copyFrom(t).subtractOffset(this._rectangle.northWest),e),this},t.prototype.forEach=function(t,e){var i=this;this._mask.forEach(t,function(t,r){e(t.addOffset(i._rectangle.northWest),r)})},t}();e.MaskRect=o},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(0),n=function(){function t(t,e){void 0===e&&(e=!1),this._size=new r.Size,this._size.copyFrom(t),this._bits=new Array(this._size.area).fill(e)}return t.prototype.toString=function(){for(var t="",e=new r.Offset,i=0;i=0&&t.y>=0&&t.x>h)).fill(0)}return t.prototype.addBody=function(t,e){u.set(t,e);var i=this._size.index(u);this._tileFlags[i>>h]|=1<<(i&(1<>h]&=~(1<<(i&(1<>h]&1<<(i&(1<0;b++,_+=u*this._size.width,O+=u*t.width)for(var v=1/(b+.5),m=0===b?Number.POSITIVE_INFINITY:1/(b-.5),w=0,x=0,z=_,P=O,j=-.5*v,M=.5*m;x!==p&&w!==g.length;x++,z+=r,P+=r,j+=v,M+=m){for(;j>=g[w+o]&&!((w+=s)>=g.length););if(w>=g.length)break;if(!(M<=g[w+n]))t.setAt(P,!0),(0!==x||0!==b)&&0!=(this._tileFlags[z>>h]&1<<(z&(1<=t[e+o])return t.splice(e,s),c(t,e,i,r);r>=t[e+n]&&(t[e+n]=r)}else{if(r>=t[e+o])return t[e+o]=i,c(t,e+=s,i,r);t.splice(e,0,t[e+n],i),t[(e+=s)+n]=r}return e}e.FieldOfViewMap=f},function(t,e,i){"use strict";Object.defineProperty(e,"__esModule",{value:!0});var r=i(6);e.FieldOfViewMap=r.FieldOfViewMap;var n=i(0);e.MaskRect=n.MaskRect}]); +//# sourceMappingURL=the-field-1.0.0.min.js.map \ No newline at end of file diff --git a/bin/the-field-1.0.0.min.js.map b/bin/the-field-1.0.0.min.js.map new file mode 100644 index 0000000..d63da58 --- /dev/null +++ b/bin/the-field-1.0.0.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack://TheField/webpack/bootstrap","webpack://TheField/./src/geom/index.ts","webpack://TheField/./src/geom/mask-rect.ts","webpack://TheField/./src/geom/mask.ts","webpack://TheField/./src/geom/rectangle.ts","webpack://TheField/./src/geom/size.ts","webpack://TheField/./src/geom/offset.ts","webpack://TheField/./src/field-of-view.ts","webpack://TheField/./src/index.ts"],"names":["installedModules","__webpack_require__","moduleId","exports","module","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","__export","geom","LOCAL_OFF","Offset","MaskRect","rect","initialValue","outsideValue","this","_rectangle","Rectangle","copyFrom","_mask","Mask","_outsideValue","toString","northWest","westX","northY","width","height","index","off","subtractOffset","getAt","x","y","set","containsOffset","setAt","forEach","cursor","callback","_this","addOffset","size","_size","Size","_bits","Array","area","fill","ret","empty","other","dy","dx","WEDGE_LOW","WEDGE_HIGH","WEDGE_COUNT","FLAGS_POW2","FieldOfViewMap","_tileFlags","addBody","removeBody","getBody","getFieldOfView","chebyshevRadius","origin","boundRect","mask","_quadrant","xDir","yDir","startX","startY","endDX","Math","min","max","endDY","startMapIndex","startMaskIndex","wedges","Number","POSITIVE_INFINITY","yMapIndex","yMaskIndex","length","divYpos","divYneg","wedgeIndex","mapIndex","maskIndex","slopeY","slopeX","cutWedge","low","high","splice","field_of_view_1","geom_1"],"mappings":"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","file":"the-field-1.0.0.min.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"/bin/\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 7);\n","export * from './offset';\r\nexport * from './size';\r\nexport * from './rectangle';\r\nexport * from './mask';\r\nexport * from './mask-rect';\r\n","import * as geom from '.';\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class MaskRect implements geom.RectangleLike {\r\n private readonly _rectangle = new geom.Rectangle();\r\n private readonly _mask: geom.Mask;\r\n private readonly _outsideValue: boolean;\r\n\r\n constructor(rect: geom.RectangleLike, initialValue = false, outsideValue = false) {\r\n this._rectangle.copyFrom(rect);\r\n this._mask = new geom.Mask(rect, initialValue);\r\n this._outsideValue = outsideValue;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `${this._rectangle.northWest}/${this._outsideValue}\\n${this._mask}`;\r\n }\r\n\r\n get westX() {\r\n return this._rectangle.westX;\r\n }\r\n\r\n get northY() {\r\n return this._rectangle.northY;\r\n }\r\n\r\n get width() {\r\n return this._rectangle.width;\r\n }\r\n\r\n get height() {\r\n return this._rectangle.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._mask.index(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest));\r\n }\r\n\r\n getAt(index: number) {\r\n return this._mask.getAt(index);\r\n }\r\n\r\n get(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n if (!this._rectangle.containsOffset(LOCAL_OFF)) {\r\n return this._outsideValue;\r\n }\r\n return this._mask.get(LOCAL_OFF.subtractOffset(this._rectangle.northWest));\r\n }\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._mask.setAt(index, value);\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n this._mask.set(LOCAL_OFF.copyFrom(off).subtractOffset(this._rectangle.northWest), value);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n this._mask.forEach(cursor, (off, value) => {\r\n callback(off.addOffset(this._rectangle.northWest), value);\r\n });\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport class Mask implements geom.SizeLike {\r\n private readonly _size = new geom.Size();\r\n private readonly _bits: boolean[];\r\n // TODO consider Uint8Array for bits\r\n\r\n constructor(size: geom.SizeLike, initialValue = false) {\r\n this._size.copyFrom(size);\r\n this._bits = new Array(this._size.area).fill(initialValue);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n let ret = '';\r\n const off = new geom.Offset();\r\n for (let y = 0; y < this._size.height; y ++) {\r\n for (let x = 0; x < this._size.width; x ++) {\r\n off.set(x, y);\r\n ret += this.get(off.set(x, y)) ? '☑' : '☐';\r\n }\r\n ret += '\\n';\r\n }\r\n return ret;\r\n }\r\n\r\n get width() {\r\n return this._size.width;\r\n }\r\n\r\n get height() {\r\n return this._size.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this._size.index(off);\r\n }\r\n\r\n getAt(index: number) {\r\n return this._bits[index];\r\n }\r\n\r\n get(off: geom.OffsetLike) {\r\n return this.getAt(this.index(off));\r\n }\r\n\r\n // mutators\r\n\r\n setAt(index: number, value: boolean) {\r\n this._bits[index] = value;\r\n return this;\r\n }\r\n\r\n set(off: geom.OffsetLike, value: boolean) {\r\n return this.setAt(this.index(off), value);\r\n }\r\n\r\n // utilities\r\n\r\n forEach(cursor: geom.Offset, callback: (cursor: geom.Offset, value: boolean) => void) {\r\n let index = 0;\r\n this._size.forEach(cursor, (off) => {\r\n callback(off, this._bits[index]);\r\n index ++;\r\n });\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport interface RectangleLike extends geom.SizeLike {\r\n readonly westX: number;\r\n readonly northY: number;\r\n}\r\n\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\nexport class Rectangle implements RectangleLike, geom.SizeLike {\r\n northWest: geom.Offset;\r\n size: geom.Size;\r\n\r\n constructor();\r\n constructor(westX: number, northY: number, width: number, height: number);\r\n constructor(westX?: number, northY?: number, width?: number, height?: number) {\r\n if (typeof westX === 'undefined') {\r\n westX = 0;\r\n }\r\n if (typeof northY === 'undefined') {\r\n northY = 0;\r\n }\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.northWest = new geom.Offset(westX, northY);\r\n this.size = new geom.Size(width, height);\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.westX},${this.northY} ${this.width}x${this.height})`;\r\n }\r\n\r\n get northY() {\r\n return this.northWest.y;\r\n }\r\n\r\n get southY() {\r\n return this.northWest.y + this.size.height - 1;\r\n }\r\n\r\n get westX() {\r\n return this.northWest.x;\r\n }\r\n\r\n get eastX() {\r\n return this.northWest.x + this.size.width - 1;\r\n }\r\n\r\n get width() {\r\n return this.size.width;\r\n }\r\n\r\n get height() {\r\n return this.size.height;\r\n }\r\n\r\n get empty() {\r\n return this.size.empty;\r\n }\r\n\r\n get area() {\r\n return this.size.area;\r\n }\r\n\r\n // mutators\r\n\r\n copyFrom(other: RectangleLike) {\r\n this.northWest.set(other.westX, other.northY);\r\n this.size.set(other.width, other.height);\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return this.size.containsOffset(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return this.size.index(LOCAL_OFF.copyFrom(off).subtractOffset(this.northWest));\r\n }\r\n}\r\n","import * as geom from '.';\r\n\r\nexport interface SizeLike {\r\n readonly width: number;\r\n readonly height: number;\r\n}\r\n\r\nexport class Size implements SizeLike {\r\n width: number;\r\n height: number;\r\n\r\n constructor();\r\n constructor(width: number, height: number);\r\n constructor(width?: number, height?: number) {\r\n if (typeof width === 'undefined') {\r\n width = 0;\r\n }\r\n if (typeof height === 'undefined') {\r\n height = 0;\r\n }\r\n this.width = width;\r\n this.height = height;\r\n }\r\n\r\n // accessors\r\n\r\n toString() {\r\n return `(${this.width}x${this.height})`;\r\n }\r\n\r\n get empty() {\r\n return this.width === 0 || this.height === 0;\r\n }\r\n\r\n get area() {\r\n return this.width * this.height;\r\n }\r\n\r\n // mutators\r\n\r\n set(width: number, height: number) {\r\n this.width = width;\r\n this.height = height;\r\n return this;\r\n }\r\n\r\n copyFrom(other: SizeLike) {\r\n this.width = other.width;\r\n this.height = other.height;\r\n return this;\r\n }\r\n\r\n // utilities\r\n\r\n containsOffset(off: geom.OffsetLike) {\r\n return off.x >= 0 && off.y >= 0 && off.x < this.width && off.y < this.height;\r\n }\r\n\r\n index(off: geom.OffsetLike) {\r\n return off.y * this.width + off.x;\r\n }\r\n\r\n forEach(cursor: geom.Offset, callback: (offset: geom.Offset) => void) {\r\n for (let dy = 0; dy < this.height; dy ++) {\r\n for (let dx = 0; dx < this.width; dx ++) {\r\n cursor.x = dx;\r\n cursor.y = dy;\r\n callback(cursor);\r\n }\r\n }\r\n }\r\n}\r\n","export interface OffsetLike {\r\n readonly x: number;\r\n readonly y: number;\r\n}\r\n\r\nexport class Offset implements OffsetLike {\r\n x: number;\r\n y: number;\r\n\r\n constructor();\r\n constructor(x: number, y: number);\r\n constructor(x?: number, y?: number) {\r\n if (typeof x === 'undefined') {\r\n x = 0;\r\n }\r\n if (typeof y === 'undefined') {\r\n y = 0;\r\n }\r\n this.x = x;\r\n this.y = y;\r\n }\r\n\r\n toString() {\r\n return `(${this.x},${this.y})`;\r\n }\r\n\r\n // mutators\r\n\r\n set(x: number, y: number) {\r\n this.x = x;\r\n this.y = y;\r\n return this;\r\n }\r\n\r\n copyFrom(other: OffsetLike) {\r\n this.x = other.x;\r\n this.y = other.y;\r\n return this;\r\n }\r\n\r\n addOffset(off: OffsetLike) {\r\n this.x += off.x;\r\n this.y += off.y;\r\n return this;\r\n }\r\n\r\n subtractOffset(off: OffsetLike) {\r\n this.x -= off.x;\r\n this.y -= off.y;\r\n return this;\r\n }\r\n}\r\n","import * as geom from './geom';\r\n\r\n// tslint:disable:no-bitwise\r\n\r\n/**\r\n * In the shadowcasting algorithm, each shadow is represented by a \"wedge\",\r\n * running from a \"low\" angle to a \"high\" angle. The wedges are all stored in\r\n * a simple number array, with two numbers for each wedge. These constants\r\n * (WEDGE_LOW and WEDGE_HIGH) help to identify which number is which.\r\n * WEDGE_COUNT is just how many numbers per wedge.\r\n */\r\nconst WEDGE_LOW = 0;\r\nconst WEDGE_HIGH = 1;\r\nconst WEDGE_COUNT = 2;\r\n\r\n/**\r\n * Bodies in this algorithm do not entirely fill their tiles. This is\r\n * implemented by adjusting the angles of the shadows the bodies cast,\r\n * making the wedge very slightly narrower. BODY_EPSILON represents the\r\n * amount of reduction on either side of the wedge.\r\n */\r\nconst BODY_EPSILON = 0.00001;\r\n\r\n/**\r\n * We avoid heap allocations during the core part of the algorithm by using this\r\n * preallocated offset object.\r\n */\r\nconst LOCAL_OFF = new geom.Offset();\r\n\r\n/**\r\n * For each number in the _tileFlags array, we store (1 << FLAGS_POW2) cells,\r\n * as bits where a true indicates the presence of a body.\r\n */\r\nconst FLAGS_POW2 = 5;\r\n\r\n/**\r\n * The FieldOFViewMap represents the map over which the field of view will be\r\n * computed. It starts out empty. You can add walls and bodies to it, and then\r\n * use getFieldOfView() to compute the field of view from a given point.\r\n */\r\nexport class FieldOfViewMap {\r\n private readonly _size = new geom.Size();\r\n private readonly _tileFlags: number[];\r\n\r\n constructor(width: number, height: number) {\r\n this._size.set(width, height);\r\n this._tileFlags = new Array((this._size.area >> FLAGS_POW2) + 1).fill(0);\r\n }\r\n\r\n // setup and maintenance\r\n\r\n addBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] |= 1 << (index & ((1 << FLAGS_POW2) - 1));\r\n }\r\n\r\n removeBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n this._tileFlags[index >> FLAGS_POW2] &= ~(1 << (index & ((1 << FLAGS_POW2) - 1)));\r\n }\r\n\r\n getBody(x: number, y: number) {\r\n LOCAL_OFF.set(x, y);\r\n const index = this._size.index(LOCAL_OFF);\r\n return (this._tileFlags[index >> FLAGS_POW2] & (1 << (index & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n }\r\n\r\n // execution\r\n\r\n /**\r\n * Compute the field of view for a camera at the given tile.\r\n * chebyshevRadius is the vision radius. It uses chebyshev distance\r\n * (https://en.wikipedia.org/wiki/Chebyshev_distance), which just means\r\n * that the limit of vision in a large empty field will be square.\r\n *\r\n * This returns a MaskRect, which indicates which tiles are visible.\r\n * maskRect.get(x, y) will return true for visible tiles.\r\n */\r\n getFieldOfView(x: number, y: number, chebyshevRadius: number): geom.MaskRect {\r\n const origin = new geom.Offset(x, y);\r\n const boundRect = new geom.Rectangle(\r\n origin.x - chebyshevRadius, origin.y - chebyshevRadius,\r\n chebyshevRadius * 2 + 1, chebyshevRadius * 2 + 1,\r\n );\r\n const mask = new geom.MaskRect(boundRect);\r\n // the player can always see itself\r\n mask.set(origin, true);\r\n // the field is divided into quadrants\r\n this._quadrant(mask, origin, chebyshevRadius, -1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, -1);\r\n this._quadrant(mask, origin, chebyshevRadius, -1, 1);\r\n this._quadrant(mask, origin, chebyshevRadius, 1, 1);\r\n return mask;\r\n }\r\n\r\n private _quadrant(mask: geom.MaskRect, origin: geom.OffsetLike, chebyshevRadius: number,\r\n xDir: number, yDir: number) {\r\n const {x: startX, y: startY} = origin;\r\n const endDX = (Math.min(Math.max(startX + xDir * (chebyshevRadius + 1),\r\n -1), this._size.width) - startX) * xDir;\r\n const endDY = (Math.min(Math.max(startY + yDir * (chebyshevRadius + 1),\r\n -1), this._size.height) - startY) * yDir;\r\n if (endDX < 0 || endDY < 0) {\r\n // the origin is outside of the map\r\n return;\r\n }\r\n const startMapIndex = this._size.index(origin);\r\n const startMaskIndex = mask.index(origin);\r\n // Initial wedge is from slope zero to slope infinity (i.e. the whole quadrant)\r\n const wedges = [0, Number.POSITIVE_INFINITY];\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dy = 0, yMapIndex = startMapIndex, yMaskIndex = startMaskIndex;\r\n dy !== endDY && wedges.length > 0;\r\n dy ++, yMapIndex = yMapIndex + yDir * this._size.width, yMaskIndex = yMaskIndex + yDir * mask.width\r\n ) {\r\n const divYpos = 1 / (dy + 0.5);\r\n const divYneg = dy === 0 ? Number.POSITIVE_INFINITY : 1 / (dy - 0.5);\r\n let wedgeIndex = 0;\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n for (let dx = 0, mapIndex = yMapIndex, maskIndex = yMaskIndex,\r\n slopeY = -0.5 * divYpos, slopeX = 0.5 * divYneg;\r\n dx !== endDX && wedgeIndex !== wedges.length;\r\n dx ++, mapIndex = mapIndex + xDir, maskIndex = maskIndex + xDir,\r\n slopeY = slopeY + divYpos, slopeX = slopeX + divYneg\r\n ) {\r\n // the slopes of the four corners of this tile\r\n // these are named as follows:\r\n // slopeY is the slope closest to the Y axis\r\n // slopeX is the slope closest to the X axis\r\n // this is always true:\r\n // slopeY < slopeX\r\n //\r\n // O = origin, C = current\r\n // +---+---+---+\r\n // | O | | |\r\n // +---+---+---X\r\n // | | | C |\r\n // +---+---Y---+\r\n\r\n // advance the wedge index until this tile is not after the current wedge\r\n while (slopeY >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // X += Y must be written as X = X + Y, in order not to trigger deoptimization due to\r\n // http://stackoverflow.com/questions/34595356/what-does-compound-let-const-assignment-mean\r\n wedgeIndex = wedgeIndex + WEDGE_COUNT;\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n }\r\n if (wedgeIndex >= wedges.length) {\r\n break;\r\n }\r\n\r\n // if the current wedge is after this tile, move on\r\n if (slopeX <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n continue;\r\n }\r\n\r\n // we can see this tile\r\n mask.setAt(maskIndex, true);\r\n\r\n // const/let must be at the top of a block, in order not to trigger deoptimization due to\r\n // https://github.com/nodejs/node/issues/9729\r\n {\r\n const body = (dx !== 0 || dy !== 0)\r\n && (this._tileFlags[mapIndex >> FLAGS_POW2]\r\n & (1 << (mapIndex & ((1 << FLAGS_POW2) - 1)))) !== 0;\r\n if (body) {\r\n wedgeIndex = cutWedge(wedges, wedgeIndex,\r\n slopeY + BODY_EPSILON, slopeX - BODY_EPSILON);\r\n }\r\n }\r\n }\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * This function cuts a range of angles out of the wedge array.\r\n */\r\nfunction cutWedge(wedges: number[], wedgeIndex: number, low: number, high: number): number {\r\n for (; ; ) {\r\n if (wedgeIndex === wedges.length) {\r\n return wedgeIndex;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n break;\r\n }\r\n wedgeIndex += WEDGE_COUNT;\r\n }\r\n if (low <= wedges[wedgeIndex + WEDGE_LOW]) {\r\n if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // wedge is entirely occluded, remove it\r\n wedges.splice(wedgeIndex, WEDGE_COUNT);\r\n // now looking at the next wedge (or past the end)\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else if (high >= wedges[wedgeIndex + WEDGE_LOW]) {\r\n // low part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // still looking at the same wedge\r\n } else {\r\n // this cut doesn't reach the current wedge\r\n }\r\n } else if (high >= wedges[wedgeIndex + WEDGE_HIGH]) {\r\n // high part of wedge is occluded, trim it\r\n wedges[wedgeIndex + WEDGE_HIGH] = low;\r\n // move on to the next wedge\r\n wedgeIndex += WEDGE_COUNT;\r\n return cutWedge(wedges, wedgeIndex, low, high);\r\n } else {\r\n // middle part of wedge is occluded, split it\r\n wedges.splice(wedgeIndex, 0, wedges[wedgeIndex + WEDGE_LOW], low);\r\n wedgeIndex += WEDGE_COUNT;\r\n wedges[wedgeIndex + WEDGE_LOW] = high;\r\n // now looking at the second wedge of the split\r\n }\r\n return wedgeIndex;\r\n}\r\n","/*\r\n * TheField\r\n * github.com/sbj42/the-field\r\n * James Clark\r\n * Licensed under the MIT license.\r\n */\r\n\r\nexport {FieldOfViewMap} from './field-of-view';\r\nexport {MaskRect} from './geom';\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/package.json b/package.json index 6e54569..cf61362 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "the-field", - "version": "0.1.2", + "version": "1.0.0", "description": "Basic shadow-casting field-of-view algorithm", "keywords": [ "fov",