rot-js
Version:
A roguelike toolkit in JavaScript
1,451 lines (1,436 loc) • 184 kB
JavaScript
function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
function _createForOfIteratorHelperLoose(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (it) return (it = it.call(o)).next.bind(it); if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; return function () { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; _setPrototypeOf(subClass, superClass); }
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf ? Object.setPrototypeOf.bind() : function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ROT = {}));
})(this, function (exports) {
'use strict';
/**
* This code is an implementation of Alea algorithm; (C) 2010 Johannes Baagøe.
* Alea is licensed according to the http://en.wikipedia.org/wiki/MIT_License.
*/
var FRAC = 2.3283064365386963e-10; /* 2^-32 */
var RNG = /*#__PURE__*/function () {
function RNG() {
this._seed = 0;
this._s0 = 0;
this._s1 = 0;
this._s2 = 0;
this._c = 0;
}
var _proto = RNG.prototype;
_proto.getSeed = function getSeed() {
return this._seed;
}
/**
* Seed the number generator
*/;
_proto.setSeed = function setSeed(seed) {
seed = seed < 1 ? 1 / seed : seed;
this._seed = seed;
this._s0 = (seed >>> 0) * FRAC;
seed = seed * 69069 + 1 >>> 0;
this._s1 = seed * FRAC;
seed = seed * 69069 + 1 >>> 0;
this._s2 = seed * FRAC;
this._c = 1;
return this;
}
/**
* @returns Pseudorandom value [0,1), uniformly distributed
*/;
_proto.getUniform = function getUniform() {
var t = 2091639 * this._s0 + this._c * FRAC;
this._s0 = this._s1;
this._s1 = this._s2;
this._c = t | 0;
this._s2 = t - this._c;
return this._s2;
}
/**
* @param lowerBound The lower end of the range to return a value from, inclusive
* @param upperBound The upper end of the range to return a value from, inclusive
* @returns Pseudorandom value [lowerBound, upperBound], using ROT.RNG.getUniform() to distribute the value
*/;
_proto.getUniformInt = function getUniformInt(lowerBound, upperBound) {
var max = Math.max(lowerBound, upperBound);
var min = Math.min(lowerBound, upperBound);
return Math.floor(this.getUniform() * (max - min + 1)) + min;
}
/**
* @param mean Mean value
* @param stddev Standard deviation. ~95% of the absolute values will be lower than 2*stddev.
* @returns A normally distributed pseudorandom value
*/;
_proto.getNormal = function getNormal(mean, stddev) {
if (mean === void 0) {
mean = 0;
}
if (stddev === void 0) {
stddev = 1;
}
var u, v, r;
do {
u = 2 * this.getUniform() - 1;
v = 2 * this.getUniform() - 1;
r = u * u + v * v;
} while (r > 1 || r == 0);
var gauss = u * Math.sqrt(-2 * Math.log(r) / r);
return mean + gauss * stddev;
}
/**
* @returns Pseudorandom value [1,100] inclusive, uniformly distributed
*/;
_proto.getPercentage = function getPercentage() {
return 1 + Math.floor(this.getUniform() * 100);
}
/**
* @returns Randomly picked item, null when length=0
*/;
_proto.getItem = function getItem(array) {
if (!array.length) {
return null;
}
return array[Math.floor(this.getUniform() * array.length)];
}
/**
* @returns New array with randomized items
*/;
_proto.shuffle = function shuffle(array) {
var result = [];
var clone = array.slice();
while (clone.length) {
var _index = clone.indexOf(this.getItem(clone));
result.push(clone.splice(_index, 1)[0]);
}
return result;
}
/**
* @param data key=whatever, value=weight (relative probability)
* @returns whatever
*/;
_proto.getWeightedValue = function getWeightedValue(data) {
var total = 0;
for (var _id in data) {
total += data[_id];
}
var random = this.getUniform() * total;
var id,
part = 0;
for (id in data) {
part += data[id];
if (random < part) {
return id;
}
}
// If by some floating-point annoyance we have
// random >= total, just return the last id.
return id;
}
/**
* Get RNG state. Useful for storing the state and re-setting it via setState.
* @returns Internal state
*/;
_proto.getState = function getState() {
return [this._s0, this._s1, this._s2, this._c];
}
/**
* Set a previously retrieved state.
*/;
_proto.setState = function setState(state) {
this._s0 = state[0];
this._s1 = state[1];
this._s2 = state[2];
this._c = state[3];
return this;
}
/**
* Returns a cloned RNG
*/;
_proto.clone = function clone() {
var clone = new RNG();
return clone.setState(this.getState());
};
return RNG;
}();
var RNG$1 = new RNG().setSeed(Date.now());
/**
* @class Abstract display backend module
* @private
*/
var Backend = /*#__PURE__*/function () {
function Backend() {}
var _proto2 = Backend.prototype;
_proto2.getContainer = function getContainer() {
return null;
};
_proto2.setOptions = function setOptions(options) {
this._options = options;
};
return Backend;
}();
var Canvas = /*#__PURE__*/function (_Backend) {
_inheritsLoose(Canvas, _Backend);
function Canvas() {
var _this;
_this = _Backend.call(this) || this;
_this._ctx = document.createElement("canvas").getContext("2d");
return _this;
}
var _proto3 = Canvas.prototype;
_proto3.schedule = function schedule(cb) {
requestAnimationFrame(cb);
};
_proto3.getContainer = function getContainer() {
return this._ctx.canvas;
};
_proto3.setOptions = function setOptions(opts) {
_Backend.prototype.setOptions.call(this, opts);
var style = opts.fontStyle ? opts.fontStyle + " " : "";
var font = style + " " + opts.fontSize + "px " + opts.fontFamily;
this._ctx.font = font;
this._updateSize();
this._ctx.font = font;
this._ctx.textAlign = "center";
this._ctx.textBaseline = "middle";
};
_proto3.clear = function clear() {
var oldComposite = this._ctx.globalCompositeOperation;
this._ctx.globalCompositeOperation = "copy";
this._ctx.fillStyle = this._options.bg;
this._ctx.fillRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height);
this._ctx.globalCompositeOperation = oldComposite;
};
_proto3.eventToPosition = function eventToPosition(x, y) {
var canvas = this._ctx.canvas;
var rect = canvas.getBoundingClientRect();
x -= rect.left;
y -= rect.top;
x *= canvas.width / rect.width;
y *= canvas.height / rect.height;
if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) {
return [-1, -1];
}
return this._normalizedEventToPosition(x, y);
};
return Canvas;
}(Backend);
/**
* Always positive modulus
* @param x Operand
* @param n Modulus
* @returns x modulo n
*/
function mod(x, n) {
return (x % n + n) % n;
}
function clamp(val, min, max) {
if (min === void 0) {
min = 0;
}
if (max === void 0) {
max = 1;
}
if (val < min) return min;
if (val > max) return max;
return val;
}
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.substring(1);
}
/**
* Format a string in a flexible way. Scans for %s strings and replaces them with arguments. List of patterns is modifiable via String.format.map.
* @param {string} template
* @param {any} [argv]
*/
function format(template) {
for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
var map = format.map;
var replacer = function replacer(match, group1, group2, index) {
if (template.charAt(index - 1) == "%") {
return match.substring(1);
}
if (!args.length) {
return match;
}
var obj = args[0];
var group = group1 || group2;
var parts = group.split(",");
var name = parts.shift() || "";
var method = map[name.toLowerCase()];
if (!method) {
return match;
}
obj = args.shift();
var replaced = obj[method].apply(obj, parts);
var first = name.charAt(0);
if (first != first.toLowerCase()) {
replaced = capitalize(replaced);
}
return replaced;
};
return template.replace(/%(?:([a-z]+)|(?:{([^}]+)}))/gi, replacer);
}
format.map = {
"s": "toString"
};
var util = /*#__PURE__*/Object.freeze({
__proto__: null,
mod: mod,
clamp: clamp,
capitalize: capitalize,
format: format
});
/**
* @class Hexagonal backend
* @private
*/
var Hex = /*#__PURE__*/function (_Canvas) {
_inheritsLoose(Hex, _Canvas);
function Hex() {
var _this2;
_this2 = _Canvas.call(this) || this;
_this2._spacingX = 0;
_this2._spacingY = 0;
_this2._hexSize = 0;
return _this2;
}
var _proto4 = Hex.prototype;
_proto4.draw = function draw(data, clearBefore) {
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
var px = [(x + 1) * this._spacingX, y * this._spacingY + this._hexSize];
if (this._options.transpose) {
px.reverse();
}
if (clearBefore) {
this._ctx.fillStyle = bg;
this._fill(px[0], px[1]);
}
if (!ch) {
return;
}
this._ctx.fillStyle = fg;
var chars = [].concat(ch);
for (var i = 0; i < chars.length; i++) {
this._ctx.fillText(chars[i], px[0], Math.ceil(px[1]));
}
};
_proto4.computeSize = function computeSize(availWidth, availHeight) {
if (this._options.transpose) {
availWidth += availHeight;
availHeight = availWidth - availHeight;
availWidth -= availHeight;
}
var width = Math.floor(availWidth / this._spacingX) - 1;
var height = Math.floor((availHeight - 2 * this._hexSize) / this._spacingY + 1);
return [width, height];
};
_proto4.computeFontSize = function computeFontSize(availWidth, availHeight) {
if (this._options.transpose) {
availWidth += availHeight;
availHeight = availWidth - availHeight;
availWidth -= availHeight;
}
var hexSizeWidth = 2 * availWidth / ((this._options.width + 1) * Math.sqrt(3)) - 1;
var hexSizeHeight = availHeight / (2 + 1.5 * (this._options.height - 1));
var hexSize = Math.min(hexSizeWidth, hexSizeHeight);
// compute char ratio
var oldFont = this._ctx.font;
this._ctx.font = "100px " + this._options.fontFamily;
var width = Math.ceil(this._ctx.measureText("W").width);
this._ctx.font = oldFont;
var ratio = width / 100;
hexSize = Math.floor(hexSize) + 1; // closest larger hexSize
// FIXME char size computation does not respect transposed hexes
var fontSize = 2 * hexSize / (this._options.spacing * (1 + ratio / Math.sqrt(3)));
// closest smaller fontSize
return Math.ceil(fontSize) - 1;
};
_proto4._normalizedEventToPosition = function _normalizedEventToPosition(x, y) {
var nodeSize;
if (this._options.transpose) {
x += y;
y = x - y;
x -= y;
nodeSize = this._ctx.canvas.width;
} else {
nodeSize = this._ctx.canvas.height;
}
var size = nodeSize / this._options.height;
y = Math.floor(y / size);
if (mod(y, 2)) {
/* odd row */
x -= this._spacingX;
x = 1 + 2 * Math.floor(x / (2 * this._spacingX));
} else {
x = 2 * Math.floor(x / (2 * this._spacingX));
}
return [x, y];
}
/**
* Arguments are pixel values. If "transposed" mode is enabled, then these two are already swapped.
*/;
_proto4._fill = function _fill(cx, cy) {
var a = this._hexSize;
var b = this._options.border;
var ctx = this._ctx;
ctx.beginPath();
if (this._options.transpose) {
ctx.moveTo(cx - a + b, cy);
ctx.lineTo(cx - a / 2 + b, cy + this._spacingX - b);
ctx.lineTo(cx + a / 2 - b, cy + this._spacingX - b);
ctx.lineTo(cx + a - b, cy);
ctx.lineTo(cx + a / 2 - b, cy - this._spacingX + b);
ctx.lineTo(cx - a / 2 + b, cy - this._spacingX + b);
ctx.lineTo(cx - a + b, cy);
} else {
ctx.moveTo(cx, cy - a + b);
ctx.lineTo(cx + this._spacingX - b, cy - a / 2 + b);
ctx.lineTo(cx + this._spacingX - b, cy + a / 2 - b);
ctx.lineTo(cx, cy + a - b);
ctx.lineTo(cx - this._spacingX + b, cy + a / 2 - b);
ctx.lineTo(cx - this._spacingX + b, cy - a / 2 + b);
ctx.lineTo(cx, cy - a + b);
}
ctx.fill();
};
_proto4._updateSize = function _updateSize() {
var opts = this._options;
var charWidth = Math.ceil(this._ctx.measureText("W").width);
this._hexSize = Math.floor(opts.spacing * (opts.fontSize + charWidth / Math.sqrt(3)) / 2);
this._spacingX = this._hexSize * Math.sqrt(3) / 2;
this._spacingY = this._hexSize * 1.5;
var xprop;
var yprop;
if (opts.transpose) {
xprop = "height";
yprop = "width";
} else {
xprop = "width";
yprop = "height";
}
this._ctx.canvas[xprop] = Math.ceil((opts.width + 1) * this._spacingX);
this._ctx.canvas[yprop] = Math.ceil((opts.height - 1) * this._spacingY + 2 * this._hexSize);
};
return Hex;
}(Canvas);
/**
* @class Rectangular backend
* @private
*/
var Rect = /*#__PURE__*/function (_Canvas2) {
_inheritsLoose(Rect, _Canvas2);
function Rect() {
var _this3;
_this3 = _Canvas2.call(this) || this;
_this3._spacingX = 0;
_this3._spacingY = 0;
_this3._canvasCache = {};
return _this3;
}
var _proto5 = Rect.prototype;
_proto5.setOptions = function setOptions(options) {
_Canvas2.prototype.setOptions.call(this, options);
this._canvasCache = {};
};
_proto5.draw = function draw(data, clearBefore) {
if (Rect.cache) {
this._drawWithCache(data);
} else {
this._drawNoCache(data, clearBefore);
}
};
_proto5._drawWithCache = function _drawWithCache(data) {
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
var hash = "" + ch + fg + bg;
var canvas;
if (hash in this._canvasCache) {
canvas = this._canvasCache[hash];
} else {
var b = this._options.border;
canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = this._spacingX;
canvas.height = this._spacingY;
ctx.fillStyle = bg;
ctx.fillRect(b, b, canvas.width - b, canvas.height - b);
if (ch) {
ctx.fillStyle = fg;
ctx.font = this._ctx.font;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
var chars = [].concat(ch);
for (var i = 0; i < chars.length; i++) {
ctx.fillText(chars[i], this._spacingX / 2, Math.ceil(this._spacingY / 2));
}
}
this._canvasCache[hash] = canvas;
}
this._ctx.drawImage(canvas, x * this._spacingX, y * this._spacingY);
};
_proto5._drawNoCache = function _drawNoCache(data, clearBefore) {
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
if (clearBefore) {
var b = this._options.border;
this._ctx.fillStyle = bg;
this._ctx.fillRect(x * this._spacingX + b, y * this._spacingY + b, this._spacingX - b, this._spacingY - b);
}
if (!ch) {
return;
}
this._ctx.fillStyle = fg;
var chars = [].concat(ch);
for (var i = 0; i < chars.length; i++) {
this._ctx.fillText(chars[i], (x + 0.5) * this._spacingX, Math.ceil((y + 0.5) * this._spacingY));
}
};
_proto5.computeSize = function computeSize(availWidth, availHeight) {
var width = Math.floor(availWidth / this._spacingX);
var height = Math.floor(availHeight / this._spacingY);
return [width, height];
};
_proto5.computeFontSize = function computeFontSize(availWidth, availHeight) {
var boxWidth = Math.floor(availWidth / this._options.width);
var boxHeight = Math.floor(availHeight / this._options.height);
/* compute char ratio */
var oldFont = this._ctx.font;
this._ctx.font = "100px " + this._options.fontFamily;
var width = Math.ceil(this._ctx.measureText("W").width);
this._ctx.font = oldFont;
var ratio = width / 100;
var widthFraction = ratio * boxHeight / boxWidth;
if (widthFraction > 1) {
/* too wide with current aspect ratio */
boxHeight = Math.floor(boxHeight / widthFraction);
}
return Math.floor(boxHeight / this._options.spacing);
};
_proto5._normalizedEventToPosition = function _normalizedEventToPosition(x, y) {
return [Math.floor(x / this._spacingX), Math.floor(y / this._spacingY)];
};
_proto5._updateSize = function _updateSize() {
var opts = this._options;
var charWidth = Math.ceil(this._ctx.measureText("W").width);
this._spacingX = Math.ceil(opts.spacing * charWidth);
this._spacingY = Math.ceil(opts.spacing * opts.fontSize);
if (opts.forceSquareRatio) {
this._spacingX = this._spacingY = Math.max(this._spacingX, this._spacingY);
}
this._ctx.canvas.width = opts.width * this._spacingX;
this._ctx.canvas.height = opts.height * this._spacingY;
};
return Rect;
}(Canvas);
Rect.cache = false;
/**
* @class Tile backend
* @private
*/
var Tile = /*#__PURE__*/function (_Canvas3) {
_inheritsLoose(Tile, _Canvas3);
function Tile() {
var _this4;
_this4 = _Canvas3.call(this) || this;
_this4._colorCanvas = document.createElement("canvas");
return _this4;
}
var _proto6 = Tile.prototype;
_proto6.draw = function draw(data, clearBefore) {
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
var tileWidth = this._options.tileWidth;
var tileHeight = this._options.tileHeight;
if (clearBefore) {
if (this._options.tileColorize) {
this._ctx.clearRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
} else {
this._ctx.fillStyle = bg;
this._ctx.fillRect(x * tileWidth, y * tileHeight, tileWidth, tileHeight);
}
}
if (!ch) {
return;
}
var chars = [].concat(ch);
var fgs = [].concat(fg);
var bgs = [].concat(bg);
for (var i = 0; i < chars.length; i++) {
var tile = this._options.tileMap[chars[i]];
if (!tile) {
throw new Error("Char \"" + chars[i] + "\" not found in tileMap");
}
if (this._options.tileColorize) {
// apply colorization
var canvas = this._colorCanvas;
var context = canvas.getContext("2d");
context.globalCompositeOperation = "source-over";
context.clearRect(0, 0, tileWidth, tileHeight);
var _fg = fgs[i];
var _bg = bgs[i];
context.drawImage(this._options.tileSet, tile[0], tile[1], tileWidth, tileHeight, 0, 0, tileWidth, tileHeight);
if (_fg != "transparent") {
context.fillStyle = _fg;
context.globalCompositeOperation = "source-atop";
context.fillRect(0, 0, tileWidth, tileHeight);
}
if (_bg != "transparent") {
context.fillStyle = _bg;
context.globalCompositeOperation = "destination-over";
context.fillRect(0, 0, tileWidth, tileHeight);
}
this._ctx.drawImage(canvas, x * tileWidth, y * tileHeight, tileWidth, tileHeight);
} else {
// no colorizing, easy
this._ctx.drawImage(this._options.tileSet, tile[0], tile[1], tileWidth, tileHeight, x * tileWidth, y * tileHeight, tileWidth, tileHeight);
}
}
};
_proto6.computeSize = function computeSize(availWidth, availHeight) {
var width = Math.floor(availWidth / this._options.tileWidth);
var height = Math.floor(availHeight / this._options.tileHeight);
return [width, height];
};
_proto6.computeFontSize = function computeFontSize() {
throw new Error("Tile backend does not understand font size");
};
_proto6._normalizedEventToPosition = function _normalizedEventToPosition(x, y) {
return [Math.floor(x / this._options.tileWidth), Math.floor(y / this._options.tileHeight)];
};
_proto6._updateSize = function _updateSize() {
var opts = this._options;
this._ctx.canvas.width = opts.width * opts.tileWidth;
this._ctx.canvas.height = opts.height * opts.tileHeight;
this._colorCanvas.width = opts.tileWidth;
this._colorCanvas.height = opts.tileHeight;
};
return Tile;
}(Canvas);
function fromString(str) {
var cached, r;
if (str in CACHE) {
cached = CACHE[str];
} else {
if (str.charAt(0) == "#") {
// hex rgb
var matched = str.match(/[0-9a-f]/gi) || [];
var values = matched.map(function (x) {
return parseInt(x, 16);
});
if (values.length == 3) {
cached = values.map(function (x) {
return x * 17;
});
} else {
for (var i = 0; i < 3; i++) {
values[i + 1] += 16 * values[i];
values.splice(i, 1);
}
cached = values;
}
} else if (r = str.match(/rgb\(([0-9, ]+)\)/i)) {
// decimal rgb
cached = r[1].split(/\s*,\s*/).map(function (x) {
return parseInt(x);
});
} else {
// html name
cached = [0, 0, 0];
}
CACHE[str] = cached;
}
return cached.slice();
}
/**
* Add two or more colors
*/
function add(color1) {
var result = color1.slice();
for (var _len2 = arguments.length, colors = new Array(_len2 > 1 ? _len2 - 1 : 0), _key2 = 1; _key2 < _len2; _key2++) {
colors[_key2 - 1] = arguments[_key2];
}
for (var i = 0; i < 3; i++) {
for (var j = 0; j < colors.length; j++) {
result[i] += colors[j][i];
}
}
return result;
}
/**
* Add two or more colors, MODIFIES FIRST ARGUMENT
*/
function add_(color1) {
for (var _len3 = arguments.length, colors = new Array(_len3 > 1 ? _len3 - 1 : 0), _key3 = 1; _key3 < _len3; _key3++) {
colors[_key3 - 1] = arguments[_key3];
}
for (var i = 0; i < 3; i++) {
for (var j = 0; j < colors.length; j++) {
color1[i] += colors[j][i];
}
}
return color1;
}
/**
* Multiply (mix) two or more colors
*/
function multiply(color1) {
var result = color1.slice();
for (var _len4 = arguments.length, colors = new Array(_len4 > 1 ? _len4 - 1 : 0), _key4 = 1; _key4 < _len4; _key4++) {
colors[_key4 - 1] = arguments[_key4];
}
for (var i = 0; i < 3; i++) {
for (var j = 0; j < colors.length; j++) {
result[i] *= colors[j][i] / 255;
}
result[i] = Math.round(result[i]);
}
return result;
}
/**
* Multiply (mix) two or more colors, MODIFIES FIRST ARGUMENT
*/
function multiply_(color1) {
for (var _len5 = arguments.length, colors = new Array(_len5 > 1 ? _len5 - 1 : 0), _key5 = 1; _key5 < _len5; _key5++) {
colors[_key5 - 1] = arguments[_key5];
}
for (var i = 0; i < 3; i++) {
for (var j = 0; j < colors.length; j++) {
color1[i] *= colors[j][i] / 255;
}
color1[i] = Math.round(color1[i]);
}
return color1;
}
/**
* Interpolate (blend) two colors with a given factor
*/
function interpolate(color1, color2, factor) {
if (factor === void 0) {
factor = 0.5;
}
var result = color1.slice();
for (var i = 0; i < 3; i++) {
result[i] = Math.round(result[i] + factor * (color2[i] - color1[i]));
}
return result;
}
var lerp = interpolate;
/**
* Interpolate (blend) two colors with a given factor in HSL mode
*/
function interpolateHSL(color1, color2, factor) {
if (factor === void 0) {
factor = 0.5;
}
var hsl1 = rgb2hsl(color1);
var hsl2 = rgb2hsl(color2);
for (var i = 0; i < 3; i++) {
hsl1[i] += factor * (hsl2[i] - hsl1[i]);
}
return hsl2rgb(hsl1);
}
var lerpHSL = interpolateHSL;
/**
* Create a new random color based on this one
* @param color
* @param diff Set of standard deviations
*/
function randomize(color, diff) {
if (!(diff instanceof Array)) {
diff = Math.round(RNG$1.getNormal(0, diff));
}
var result = color.slice();
for (var i = 0; i < 3; i++) {
result[i] += diff instanceof Array ? Math.round(RNG$1.getNormal(0, diff[i])) : diff;
}
return result;
}
/**
* Converts an RGB color value to HSL. Expects 0..255 inputs, produces 0..1 outputs.
*/
function rgb2hsl(color) {
var r = color[0] / 255;
var g = color[1] / 255;
var b = color[2] / 255;
var max = Math.max(r, g, b),
min = Math.min(r, g, b);
var h = 0,
s,
l = (max + min) / 2;
if (max == min) {
s = 0; // achromatic
} else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r:
h = (g - b) / d + (g < b ? 6 : 0);
break;
case g:
h = (b - r) / d + 2;
break;
case b:
h = (r - g) / d + 4;
break;
}
h /= 6;
}
return [h, s, l];
}
function hue2rgb(p, q, t) {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1 / 6) return p + (q - p) * 6 * t;
if (t < 1 / 2) return q;
if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6;
return p;
}
/**
* Converts an HSL color value to RGB. Expects 0..1 inputs, produces 0..255 outputs.
*/
function hsl2rgb(color) {
var l = color[2];
if (color[1] == 0) {
l = Math.round(l * 255);
return [l, l, l];
} else {
var s = color[1];
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
var r = hue2rgb(p, q, color[0] + 1 / 3);
var g = hue2rgb(p, q, color[0]);
var b = hue2rgb(p, q, color[0] - 1 / 3);
return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)];
}
}
function toRGB(color) {
var clamped = color.map(function (x) {
return clamp(x, 0, 255);
});
return "rgb(" + clamped.join(",") + ")";
}
function toHex(color) {
var clamped = color.map(function (x) {
return clamp(x, 0, 255).toString(16).padStart(2, "0");
});
return "#" + clamped.join("");
}
var CACHE = {
"black": [0, 0, 0],
"navy": [0, 0, 128],
"darkblue": [0, 0, 139],
"mediumblue": [0, 0, 205],
"blue": [0, 0, 255],
"darkgreen": [0, 100, 0],
"green": [0, 128, 0],
"teal": [0, 128, 128],
"darkcyan": [0, 139, 139],
"deepskyblue": [0, 191, 255],
"darkturquoise": [0, 206, 209],
"mediumspringgreen": [0, 250, 154],
"lime": [0, 255, 0],
"springgreen": [0, 255, 127],
"aqua": [0, 255, 255],
"cyan": [0, 255, 255],
"midnightblue": [25, 25, 112],
"dodgerblue": [30, 144, 255],
"forestgreen": [34, 139, 34],
"seagreen": [46, 139, 87],
"darkslategray": [47, 79, 79],
"darkslategrey": [47, 79, 79],
"limegreen": [50, 205, 50],
"mediumseagreen": [60, 179, 113],
"turquoise": [64, 224, 208],
"royalblue": [65, 105, 225],
"steelblue": [70, 130, 180],
"darkslateblue": [72, 61, 139],
"mediumturquoise": [72, 209, 204],
"indigo": [75, 0, 130],
"darkolivegreen": [85, 107, 47],
"cadetblue": [95, 158, 160],
"cornflowerblue": [100, 149, 237],
"mediumaquamarine": [102, 205, 170],
"dimgray": [105, 105, 105],
"dimgrey": [105, 105, 105],
"slateblue": [106, 90, 205],
"olivedrab": [107, 142, 35],
"slategray": [112, 128, 144],
"slategrey": [112, 128, 144],
"lightslategray": [119, 136, 153],
"lightslategrey": [119, 136, 153],
"mediumslateblue": [123, 104, 238],
"lawngreen": [124, 252, 0],
"chartreuse": [127, 255, 0],
"aquamarine": [127, 255, 212],
"maroon": [128, 0, 0],
"purple": [128, 0, 128],
"olive": [128, 128, 0],
"gray": [128, 128, 128],
"grey": [128, 128, 128],
"skyblue": [135, 206, 235],
"lightskyblue": [135, 206, 250],
"blueviolet": [138, 43, 226],
"darkred": [139, 0, 0],
"darkmagenta": [139, 0, 139],
"saddlebrown": [139, 69, 19],
"darkseagreen": [143, 188, 143],
"lightgreen": [144, 238, 144],
"mediumpurple": [147, 112, 216],
"darkviolet": [148, 0, 211],
"palegreen": [152, 251, 152],
"darkorchid": [153, 50, 204],
"yellowgreen": [154, 205, 50],
"sienna": [160, 82, 45],
"brown": [165, 42, 42],
"darkgray": [169, 169, 169],
"darkgrey": [169, 169, 169],
"lightblue": [173, 216, 230],
"greenyellow": [173, 255, 47],
"paleturquoise": [175, 238, 238],
"lightsteelblue": [176, 196, 222],
"powderblue": [176, 224, 230],
"firebrick": [178, 34, 34],
"darkgoldenrod": [184, 134, 11],
"mediumorchid": [186, 85, 211],
"rosybrown": [188, 143, 143],
"darkkhaki": [189, 183, 107],
"silver": [192, 192, 192],
"mediumvioletred": [199, 21, 133],
"indianred": [205, 92, 92],
"peru": [205, 133, 63],
"chocolate": [210, 105, 30],
"tan": [210, 180, 140],
"lightgray": [211, 211, 211],
"lightgrey": [211, 211, 211],
"palevioletred": [216, 112, 147],
"thistle": [216, 191, 216],
"orchid": [218, 112, 214],
"goldenrod": [218, 165, 32],
"crimson": [220, 20, 60],
"gainsboro": [220, 220, 220],
"plum": [221, 160, 221],
"burlywood": [222, 184, 135],
"lightcyan": [224, 255, 255],
"lavender": [230, 230, 250],
"darksalmon": [233, 150, 122],
"violet": [238, 130, 238],
"palegoldenrod": [238, 232, 170],
"lightcoral": [240, 128, 128],
"khaki": [240, 230, 140],
"aliceblue": [240, 248, 255],
"honeydew": [240, 255, 240],
"azure": [240, 255, 255],
"sandybrown": [244, 164, 96],
"wheat": [245, 222, 179],
"beige": [245, 245, 220],
"whitesmoke": [245, 245, 245],
"mintcream": [245, 255, 250],
"ghostwhite": [248, 248, 255],
"salmon": [250, 128, 114],
"antiquewhite": [250, 235, 215],
"linen": [250, 240, 230],
"lightgoldenrodyellow": [250, 250, 210],
"oldlace": [253, 245, 230],
"red": [255, 0, 0],
"fuchsia": [255, 0, 255],
"magenta": [255, 0, 255],
"deeppink": [255, 20, 147],
"orangered": [255, 69, 0],
"tomato": [255, 99, 71],
"hotpink": [255, 105, 180],
"coral": [255, 127, 80],
"darkorange": [255, 140, 0],
"lightsalmon": [255, 160, 122],
"orange": [255, 165, 0],
"lightpink": [255, 182, 193],
"pink": [255, 192, 203],
"gold": [255, 215, 0],
"peachpuff": [255, 218, 185],
"navajowhite": [255, 222, 173],
"moccasin": [255, 228, 181],
"bisque": [255, 228, 196],
"mistyrose": [255, 228, 225],
"blanchedalmond": [255, 235, 205],
"papayawhip": [255, 239, 213],
"lavenderblush": [255, 240, 245],
"seashell": [255, 245, 238],
"cornsilk": [255, 248, 220],
"lemonchiffon": [255, 250, 205],
"floralwhite": [255, 250, 240],
"snow": [255, 250, 250],
"yellow": [255, 255, 0],
"lightyellow": [255, 255, 224],
"ivory": [255, 255, 240],
"white": [255, 255, 255]
};
var color = /*#__PURE__*/Object.freeze({
__proto__: null,
fromString: fromString,
add: add,
add_: add_,
multiply: multiply,
multiply_: multiply_,
interpolate: interpolate,
lerp: lerp,
interpolateHSL: interpolateHSL,
lerpHSL: lerpHSL,
randomize: randomize,
rgb2hsl: rgb2hsl,
hsl2rgb: hsl2rgb,
toRGB: toRGB,
toHex: toHex
});
/**
* @class Tile backend
* @private
*/
var TileGL = /*#__PURE__*/function (_Backend2) {
_inheritsLoose(TileGL, _Backend2);
function TileGL() {
var _this5;
_this5 = _Backend2.call(this) || this;
_this5._uniforms = {};
try {
_this5._gl = _this5._initWebGL();
} catch (e) {
if (typeof e === "string") {
alert(e);
} else if (e instanceof Error) {
alert(e.message);
}
}
return _this5;
}
TileGL.isSupported = function isSupported() {
return !!document.createElement("canvas").getContext("webgl2", {
preserveDrawingBuffer: true
});
};
var _proto7 = TileGL.prototype;
_proto7.schedule = function schedule(cb) {
requestAnimationFrame(cb);
};
_proto7.getContainer = function getContainer() {
return this._gl.canvas;
};
_proto7.setOptions = function setOptions(opts) {
var _this6 = this;
_Backend2.prototype.setOptions.call(this, opts);
this._updateSize();
var tileSet = this._options.tileSet;
if (tileSet && "complete" in tileSet && !tileSet.complete) {
tileSet.addEventListener("load", function () {
return _this6._updateTexture(tileSet);
});
} else {
this._updateTexture(tileSet);
}
};
_proto7.draw = function draw(data, clearBefore) {
var gl = this._gl;
var opts = this._options;
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
var scissorY = gl.canvas.height - (y + 1) * opts.tileHeight;
gl.scissor(x * opts.tileWidth, scissorY, opts.tileWidth, opts.tileHeight);
if (clearBefore) {
if (opts.tileColorize) {
gl.clearColor(0, 0, 0, 0);
} else {
gl.clearColor.apply(gl, parseColor(bg));
}
gl.clear(gl.COLOR_BUFFER_BIT);
}
if (!ch) {
return;
}
var chars = [].concat(ch);
var bgs = [].concat(bg);
var fgs = [].concat(fg);
gl.uniform2fv(this._uniforms["targetPosRel"], [x, y]);
for (var i = 0; i < chars.length; i++) {
var tile = this._options.tileMap[chars[i]];
if (!tile) {
throw new Error("Char \"" + chars[i] + "\" not found in tileMap");
}
gl.uniform1f(this._uniforms["colorize"], opts.tileColorize ? 1 : 0);
gl.uniform2fv(this._uniforms["tilesetPosAbs"], tile);
if (opts.tileColorize) {
gl.uniform4fv(this._uniforms["tint"], parseColor(fgs[i]));
gl.uniform4fv(this._uniforms["bg"], parseColor(bgs[i]));
}
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
}
/*
for (let i=0;i<chars.length;i++) {
if (this._options.tileColorize) { // apply colorization
let canvas = this._colorCanvas;
let context = canvas.getContext("2d") as CanvasRenderingContext2D;
context.globalCompositeOperation = "source-over";
context.clearRect(0, 0, tileWidth, tileHeight);
let fg = fgs[i];
let bg = bgs[i];
context.drawImage(
this._options.tileSet!,
tile[0], tile[1], tileWidth, tileHeight,
0, 0, tileWidth, tileHeight
);
if (fg != "transparent") {
context.fillStyle = fg;
context.globalCompositeOperation = "source-atop";
context.fillRect(0, 0, tileWidth, tileHeight);
}
if (bg != "transparent") {
context.fillStyle = bg;
context.globalCompositeOperation = "destination-over";
context.fillRect(0, 0, tileWidth, tileHeight);
}
this._ctx.drawImage(canvas, x*tileWidth, y*tileHeight, tileWidth, tileHeight);
} else { // no colorizing, easy
this._ctx.drawImage(
this._options.tileSet!,
tile[0], tile[1], tileWidth, tileHeight,
x*tileWidth, y*tileHeight, tileWidth, tileHeight
);
}
}
*/
};
_proto7.clear = function clear() {
var gl = this._gl;
gl.clearColor.apply(gl, parseColor(this._options.bg));
gl.scissor(0, 0, gl.canvas.width, gl.canvas.height);
gl.clear(gl.COLOR_BUFFER_BIT);
};
_proto7.computeSize = function computeSize(availWidth, availHeight) {
var width = Math.floor(availWidth / this._options.tileWidth);
var height = Math.floor(availHeight / this._options.tileHeight);
return [width, height];
};
_proto7.computeFontSize = function computeFontSize() {
throw new Error("Tile backend does not understand font size");
};
_proto7.eventToPosition = function eventToPosition(x, y) {
var canvas = this._gl.canvas;
var rect = canvas.getBoundingClientRect();
x -= rect.left;
y -= rect.top;
x *= canvas.width / rect.width;
y *= canvas.height / rect.height;
if (x < 0 || y < 0 || x >= canvas.width || y >= canvas.height) {
return [-1, -1];
}
return this._normalizedEventToPosition(x, y);
};
_proto7._initWebGL = function _initWebGL() {
var _this7 = this;
var gl = document.createElement("canvas").getContext("webgl2", {
preserveDrawingBuffer: true
});
window.gl = gl;
var program = createProgram(gl, VS, FS);
gl.useProgram(program);
createQuad(gl);
UNIFORMS.forEach(function (name) {
return _this7._uniforms[name] = gl.getUniformLocation(program, name);
});
this._program = program;
gl.enable(gl.BLEND);
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.SCISSOR_TEST);
return gl;
};
_proto7._normalizedEventToPosition = function _normalizedEventToPosition(x, y) {
return [Math.floor(x / this._options.tileWidth), Math.floor(y / this._options.tileHeight)];
};
_proto7._updateSize = function _updateSize() {
var gl = this._gl;
var opts = this._options;
var canvasSize = [opts.width * opts.tileWidth, opts.height * opts.tileHeight];
gl.canvas.width = canvasSize[0];
gl.canvas.height = canvasSize[1];
gl.viewport(0, 0, canvasSize[0], canvasSize[1]);
gl.uniform2fv(this._uniforms["tileSize"], [opts.tileWidth, opts.tileHeight]);
gl.uniform2fv(this._uniforms["targetSize"], canvasSize);
};
_proto7._updateTexture = function _updateTexture(tileSet) {
createTexture(this._gl, tileSet);
};
return TileGL;
}(Backend);
var UNIFORMS = ["targetPosRel", "tilesetPosAbs", "tileSize", "targetSize", "colorize", "bg", "tint"];
var VS = "\n#version 300 es\n\nin vec2 tilePosRel;\nout vec2 tilesetPosPx;\n\nuniform vec2 tilesetPosAbs;\nuniform vec2 tileSize;\nuniform vec2 targetSize;\nuniform vec2 targetPosRel;\n\nvoid main() {\n\tvec2 targetPosPx = (targetPosRel + tilePosRel) * tileSize;\n\tvec2 targetPosNdc = ((targetPosPx / targetSize)-0.5)*2.0;\n\ttargetPosNdc.y *= -1.0;\n\n\tgl_Position = vec4(targetPosNdc, 0.0, 1.0);\n\ttilesetPosPx = tilesetPosAbs + tilePosRel * tileSize;\n}".trim();
var FS = "\n#version 300 es\nprecision highp float;\n\nin vec2 tilesetPosPx;\nout vec4 fragColor;\nuniform sampler2D image;\nuniform bool colorize;\nuniform vec4 bg;\nuniform vec4 tint;\n\nvoid main() {\n\tfragColor = vec4(0, 0, 0, 1);\n\n\tvec4 texel = texelFetch(image, ivec2(tilesetPosPx), 0);\n\n\tif (colorize) {\n\t\ttexel.rgb = tint.a * tint.rgb + (1.0-tint.a) * texel.rgb;\n\t\tfragColor.rgb = texel.a*texel.rgb + (1.0-texel.a)*bg.rgb;\n\t\tfragColor.a = texel.a + (1.0-texel.a)*bg.a;\n\t} else {\n\t\tfragColor = texel;\n\t}\n}".trim();
function createProgram(gl, vss, fss) {
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vss);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(vs) || "");
}
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fss);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
throw new Error(gl.getShaderInfoLog(fs) || "");
}
var p = gl.createProgram();
gl.attachShader(p, vs);
gl.attachShader(p, fs);
gl.linkProgram(p);
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) {
throw new Error(gl.getProgramInfoLog(p) || "");
}
return p;
}
function createQuad(gl) {
var pos = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
var buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, pos, gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
}
function createTexture(gl, data) {
var t = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, t);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.REPEAT);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.REPEAT);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 0);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
return t;
}
var colorCache = {};
function parseColor(color$1) {
if (!(color$1 in colorCache)) {
var parsed;
if (color$1 == "transparent") {
parsed = [0, 0, 0, 0];
} else if (color$1.indexOf("rgba") > -1) {
parsed = (color$1.match(/[\d.]+/g) || []).map(Number);
for (var i = 0; i < 3; i++) {
parsed[i] = parsed[i] / 255;
}
} else {
parsed = fromString(color$1).map(function ($) {
return $ / 255;
});
parsed.push(1);
}
colorCache[color$1] = parsed;
}
return colorCache[color$1];
}
function clearToAnsi(bg) {
return "\x1B[0;48;5;" + termcolor(bg) + "m\x1B[2J";
}
function colorToAnsi(fg, bg) {
return "\x1B[0;38;5;" + termcolor(fg) + ";48;5;" + termcolor(bg) + "m";
}
function positionToAnsi(x, y) {
return "\x1B[" + (y + 1) + ";" + (x + 1) + "H";
}
function termcolor(color$1) {
var SRC_COLORS = 256.0;
var DST_COLORS = 6.0;
var COLOR_RATIO = DST_COLORS / SRC_COLORS;
var rgb = fromString(color$1);
var r = Math.floor(rgb[0] * COLOR_RATIO);
var g = Math.floor(rgb[1] * COLOR_RATIO);
var b = Math.floor(rgb[2] * COLOR_RATIO);
return r * 36 + g * 6 + b * 1 + 16;
}
var Term = /*#__PURE__*/function (_Backend3) {
_inheritsLoose(Term, _Backend3);
function Term() {
var _this8;
_this8 = _Backend3.call(this) || this;
_this8._offset = [0, 0];
_this8._cursor = [-1, -1];
_this8._lastColor = "";
return _this8;
}
var _proto8 = Term.prototype;
_proto8.schedule = function schedule(cb) {
setTimeout(cb, 1000 / 60);
};
_proto8.setOptions = function setOptions(options) {
_Backend3.prototype.setOptions.call(this, options);
var size = [options.width, options.height];
var avail = this.computeSize();
this._offset = avail.map(function (val, index) {
return Math.floor((val - size[index]) / 2);
});
};
_proto8.clear = function clear() {
process.stdout.write(clearToAnsi(this._options.bg));
};
_proto8.draw = function draw(data, clearBefore) {
// determine where to draw what with what colors
var x = data[0],
y = data[1],
ch = data[2],
fg = data[3],
bg = data[4];
// determine if we need to move the terminal cursor
var dx = this._offset[0] + x;
var dy = this._offset[1] + y;
var size = this.computeSize();
if (dx < 0 || dx >= size[0]) {
return;
}
if (dy < 0 || dy >= size[1]) {
return;
}
if (dx !== this._cursor[0] || dy !== this._cursor[1]) {
process.stdout.write(positionToAnsi(dx, dy));
this._cursor[0] = dx;
this._cursor[1] = dy;
}
// terminals automatically clear, but if we're clearing when we're
// not otherwise provided with a character, just use a space instead
if (clearBefore) {
if (!ch) {
ch = " ";
}
}
// if we're not clearing and not provided with a character, do nothing
if (!ch) {
return;
}
// determine if we need to change colors
var newColor = colorToAnsi(fg, bg);
if (newColor !== this._lastColor) {
process.stdout.write(newColor);
this._lastColor = newColor;
}
if (ch != '\t') {
// write the provided symbol to the display
var chars = [].concat(ch);
process.stdout.write(chars[0]);
}
// update our position, given that we wrote a character
this._cursor[0]++;
if (this._cursor[0] >= size[0]) {
this._cursor[0] = 0;
this._cursor[1]++;
}
};
_proto8.computeFontSize = function computeFontSize() {
throw new Error("Terminal backend has no notion of font size");
};
_proto8.eventToPosition = function eventToPosition(x, y) {
return [x, y];
};
_proto8.computeSize = function computeSize() {
return [process.stdout.columns, process.stdout.rows];
};
return Term;
}(Backend);
/**
* @namespace
* Contains text tokenization and breaking routines
*/
var RE_COLORS = /%([bc]){([^}]*)}/g;
// token types
var TYPE_TEXT = 0;
var TYPE_NEWLINE = 1;
var TYPE_FG = 2;
var TYPE_BG = 3;
/**
* Measure size of a resulting text block
*/
function measure(str, maxWidth) {
var result = {
width: 0,
height: 1
};
var tokens = tokenize(str, maxWidth);
var lineWidth = 0;
for (var i = 0; i < tokens.length; i++) {
var token = tokens[i];
switch (token.type) {
case TYPE_TEXT:
lineWidth += token.value.length;
break;
case TYPE_NEWLINE:
result.height++;
result.width = Math.max(result.width, lineWidth);
lineWidth = 0;
break;
}
}
result.width = Math.max(result.width, lineWidth);
return result;
}
/**
* Convert string to a series of a formatting commands
*/
function tokenize(str, maxWidth) {
var result = [];
/* first tokenization pass - split texts and color formatting commands */
var offset = 0;
str.replace(RE_COLORS, function (match, type, name, index) {
/* string before */
var part = str.substring(offset, index);
if (part.length) {
result.push({
type: TYPE_TEXT,
value: part
});
}
/* color command */
result.push({
type: type == "c" ? TYPE_FG : TYPE_BG,
value: name.trim()
});
offset = index + match.length;
return "";
});
/* last remaining part */
var part = str.substring(offset);
if (part.length) {
result.push({
type: TYPE_TEXT,
value: part
});
}
return breakLines(result, maxWidth);
}
/* insert line breaks into first-pass tokenized data */
function breakLines(tokens, maxWidth) {
if (!maxWidth) {
maxWidth = Infinity;
}
var i = 0;
var lineLength = 0;
var lastTokenWithSpace = -1;
while (i < tokens.length) {
/* take all text tokens, remove space, apply linebreaks */
var token = tokens[i];
if (token.type == TYPE_NEWLINE) {
/* reset */