From 823b09e9444a4e79163d92128b8f597de7f84b19 Mon Sep 17 00:00:00 2001 From: jwinterm Date: Sun, 27 Apr 2025 09:03:16 -0400 Subject: [PATCH] Initial AI commit --- .gitignore | 35 + dbcalls.js | 67 + game.js | 186 + html/favicon.ico | Bin 0 -> 5687 bytes html/index.html | 207 + html/js/game.js | 227 + html/js/jquery-3.4.1.min.js | 2 + html/js/options.js | 119 + html/js/rot.js | 7228 +++++++++++++++++ html/js/rot.min.js | 138 + html/js/teletype.js | 81 + html/styles/fonts/pixel-operator/.uuid | 1 + html/styles/fonts/pixel-operator/LICENSE.txt | 121 + .../pixel-operator/PixelOperator-Bold.ttf | Bin 0 -> 16984 bytes .../fonts/pixel-operator/PixelOperator.ttf | Bin 0 -> 17272 bytes .../pixel-operator/PixelOperator8-Bold.ttf | Bin 0 -> 18624 bytes .../fonts/pixel-operator/PixelOperator8.ttf | Bin 0 -> 19944 bytes .../fonts/pixel-operator/PixelOperatorHB.ttf | Bin 0 -> 17204 bytes .../fonts/pixel-operator/PixelOperatorHB8.ttf | Bin 0 -> 19076 bytes .../pixel-operator/PixelOperatorHBSC.ttf | Bin 0 -> 17112 bytes .../pixel-operator/PixelOperatorMono-Bold.ttf | Bin 0 -> 16744 bytes .../pixel-operator/PixelOperatorMono.ttf | Bin 0 -> 16972 bytes .../PixelOperatorMono8-Bold.ttf | Bin 0 -> 18624 bytes .../pixel-operator/PixelOperatorMono8.ttf | Bin 0 -> 19872 bytes .../pixel-operator/PixelOperatorMonoHB.ttf | Bin 0 -> 17120 bytes .../pixel-operator/PixelOperatorMonoHB8.ttf | Bin 0 -> 19020 bytes .../pixel-operator/PixelOperatorSC-Bold.ttf | Bin 0 -> 16716 bytes .../fonts/pixel-operator/PixelOperatorSC.ttf | Bin 0 -> 16968 bytes html/styles/fonts/stylesheet.css | 67 + .../pixeloperatormono-bold-webfont.woff | Bin 0 -> 13952 bytes .../pixeloperatormono-bold-webfont.woff2 | Bin 0 -> 10148 bytes html/styles/pixeloperatormono-webfont.woff | Bin 0 -> 12892 bytes html/styles/pixeloperatormono-webfont.woff2 | Bin 0 -> 9352 bytes html/styles/stylesheet.css | 199 + html/styles/test.css | 3 + html/test.html | 24 + html/tiles.png | Bin 0 -> 26448 bytes html/tiles.xcf | Bin 0 -> 162113 bytes index.js | 285 + package-lock.json | 1597 ++++ package.json | 19 + rot.js | 7228 +++++++++++++++++ rot.min.js | 138 + rpccalls.js | 57 + user.js | 45 + 45 files changed, 18074 insertions(+) create mode 100644 .gitignore create mode 100644 dbcalls.js create mode 100644 game.js create mode 100644 html/favicon.ico create mode 100644 html/index.html create mode 100644 html/js/game.js create mode 100644 html/js/jquery-3.4.1.min.js create mode 100644 html/js/options.js create mode 100644 html/js/rot.js create mode 100644 html/js/rot.min.js create mode 100644 html/js/teletype.js create mode 100644 html/styles/fonts/pixel-operator/.uuid create mode 100644 html/styles/fonts/pixel-operator/LICENSE.txt create mode 100644 html/styles/fonts/pixel-operator/PixelOperator-Bold.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperator.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperator8-Bold.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperator8.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorHB.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorHB8.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorHBSC.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMono-Bold.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMono.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMono8-Bold.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMono8.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMonoHB.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorMonoHB8.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorSC-Bold.ttf create mode 100644 html/styles/fonts/pixel-operator/PixelOperatorSC.ttf create mode 100644 html/styles/fonts/stylesheet.css create mode 100644 html/styles/pixeloperatormono-bold-webfont.woff create mode 100644 html/styles/pixeloperatormono-bold-webfont.woff2 create mode 100644 html/styles/pixeloperatormono-webfont.woff create mode 100644 html/styles/pixeloperatormono-webfont.woff2 create mode 100644 html/styles/stylesheet.css create mode 100644 html/styles/test.css create mode 100644 html/test.html create mode 100644 html/tiles.png create mode 100644 html/tiles.xcf create mode 100644 index.js create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 rot.js create mode 100644 rot.min.js create mode 100644 rpccalls.js create mode 100644 user.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..81bbc2b --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +# Node.js dependencies +node_modules/ +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Logs +logs/ +*.log +*.tlog +*.out +*.pid +*.gz + +# Environment variables +.env + +# Build files +dist/ +build/ + +# Temporary files +tmp/ +temp/ +*.tmp + +# IDE files +.vscode/ +.idea/ +*.swp +*.swo + +# OS generated files +.DS_Store +Thumbs.db diff --git a/dbcalls.js b/dbcalls.js new file mode 100644 index 0000000..07f4fe5 --- /dev/null +++ b/dbcalls.js @@ -0,0 +1,67 @@ +const { Client } = require('pg'); + +const client = new Client({ + user: 'postgres', + host: 'localhost', + database: 'bitdungeon', + password: 'postgres', + port: 5432, +}); +client.connect(); + +// Add this function to create the necessary table if it doesn't exist +function initializeDatabase() { + const createTableQuery = ` + CREATE TABLE IF NOT EXISTS visitors ( + id SERIAL PRIMARY KEY, + socketid VARCHAR(255) NOT NULL, + ip VARCHAR(100) NOT NULL, + time BIGINT NOT NULL + ) + `; + + client.query(createTableQuery) + .then(() => console.log("Database initialized")) + .catch(err => console.error("Database initialization error:", err)); +} + +// Call this function when starting up +initializeDatabase(); + +// String for inserting new visitor +const insertVisitorText = 'INSERT INTO visitors(socketid, ip, time) VALUES($1, $2, $3)'; +// Function for inserting new visitor and returning ID# +function insertVisitor(socketid, ip, cookie) { + values = [socketid, ip, Math.floor(new Date() / 1000)]; + + // First check if table exists to prevent errors + client.query("SELECT to_regclass('visitors')", (err, res) => { + if (err) { + console.error("Database check error:", err); + return; + } + + // If table doesn't exist yet, try to initialize again + if (res.rows[0].to_regclass === null) { + console.log("Table 'visitors' doesn't exist yet, creating it now..."); + initializeDatabase(); + return; + } + + // Insert the visitor + client.query(insertVisitorText, values, (err, res) => { + if (err) { + console.log(err.stack); + } else if (res.rows && res.rows[0]) { + console.log("Visitor inserted:", res.rows[0]); + } else { + console.log("Visitor inserted"); + } + }); + }); +} + + +module.exports = { + insertVisitor: insertVisitor +} diff --git a/game.js b/game.js new file mode 100644 index 0000000..c4c8432 --- /dev/null +++ b/game.js @@ -0,0 +1,186 @@ +const ROT = require('./rot.js'); + +// Define the missing generateDungeon function +function generateDungeon(width, height) { + // Create dungeon using ROT.js Map.Digger + const digger = new ROT.Map.Digger(width, height, { + roomWidth: [3, 9], + roomHeight: [3, 7], + corridorLength: [2, 6], + dugPercentage: 0.2 + }); + + // Initialize the empty map with walls (1) + const map = Array(height).fill().map(() => Array(width).fill(1)); + + // Fill in floors (0) using digger's callback + digger.create((x, y, value) => { + // value: 0 = floor, 1 = wall + map[y][x] = value; + }); + + // Get rooms that were created + const rooms = digger.getRooms(); + + // Place entrance in the first room + const entranceRoom = rooms[0]; + const entranceCenter = entranceRoom.getCenter(); + const entrance = [entranceCenter[0], entranceCenter[1]]; + + // Place exit in the last room + const exitRoom = rooms[rooms.length - 1]; + const exitCenter = exitRoom.getCenter(); + const exit = [exitCenter[0], exitCenter[1]]; + + // Place treasure in a middle room (not first or last) + let treasureRoom; + if (rooms.length > 2) { + treasureRoom = rooms[Math.floor(rooms.length / 2)]; + } else { + // Fallback if we have fewer than 3 rooms + treasureRoom = rooms[0]; + } + const treasureCenter = treasureRoom.getCenter(); + // Place treasure slightly off center to make it more interesting + const treasure = [ + treasureCenter[0] + Math.floor(Math.random() * 3) - 1, + treasureCenter[1] + Math.floor(Math.random() * 3) - 1 + ]; + + // Ensure the treasure is on a floor tile + if (map[treasure[1]][treasure[0]] !== 0) { + treasure[0] = treasureCenter[0]; + treasure[1] = treasureCenter[1]; + } + + return { + map: map, + rooms: rooms, + entrance: entrance, + exit: exit, + treasure: treasure + }; +} + +class Game { + constructor(socketId, mapWidth, mapHeight) { + this.socketId = socketId; + this.width = mapWidth || 50; + this.height = mapHeight || 30; + this.gameState = 'waiting'; // waiting, active, won, lost + this.startBlock = null; + this.dungeon = null; + this.player = { x: 0, y: 0, hasKey: false, hasTreasure: false }; + this.monster = { x: 0, y: 0 }; + this.fee = 0; // Amount player paid + this.generateDungeon(); + } + + generateDungeon() { + const dungeon = generateDungeon(this.width, this.height); + this.dungeon = dungeon; + + if (dungeon.entrance) { + this.player.x = dungeon.entrance[0]; + this.player.y = dungeon.entrance[1]; + } + + // Place monster far from entrance + if (dungeon.rooms && dungeon.rooms.length > 2) { + const monsterRoom = dungeon.rooms[Math.floor(dungeon.rooms.length * 0.7)]; + const center = monsterRoom.getCenter(); + this.monster.x = center[0]; + this.monster.y = center[1]; + } + } + + movePlayer(dx, dy) { + const newX = this.player.x + dx; + const newY = this.player.y + dy; + + // Check if the move is valid (not into a wall) + if (this.dungeon.map[newY][newX] === 0) { + this.player.x = newX; + this.player.y = newY; + + // Check if player found treasure + if (this.dungeon.treasure && + newX === this.dungeon.treasure[0] && + newY === this.dungeon.treasure[1]) { + this.player.hasTreasure = true; + } + + // Check if player reached exit + if (this.dungeon.exit && + newX === this.dungeon.exit[0] && + newY === this.dungeon.exit[1]) { + this.gameState = 'won'; + return { status: 'won', hasTreasure: this.player.hasTreasure }; + } + + // Move monster after player moves + this.moveMonster(); + + // Check if monster caught player + if (this.monster.x === this.player.x && this.monster.y === this.player.y) { + this.gameState = 'lost'; + return { status: 'lost', reason: 'caught' }; + } + + return { status: 'moved' }; + } + + return { status: 'invalid' }; + } + + moveMonster() { + // Simple monster AI to move toward player + const dx = Math.sign(this.player.x - this.monster.x); + const dy = Math.sign(this.player.y - this.monster.y); + + // Try horizontal move + if (dx !== 0) { + if (this.dungeon.map[this.monster.y][this.monster.x + dx] === 0) { + this.monster.x += dx; + return; + } + } + + // Try vertical move + if (dy !== 0) { + if (this.dungeon.map[this.monster.y + dy][this.monster.x] === 0) { + this.monster.y += dy; + return; + } + } + + // Try random direction if direct path is blocked + const dirs = [[0,1],[1,0],[0,-1],[-1,0]]; + const shuffledDirs = ROT.RNG.shuffle(dirs.slice()); + + for (const [dx, dy] of shuffledDirs) { + const nx = this.monster.x + dx; + const ny = this.monster.y + dy; + if (this.dungeon.map[ny] && this.dungeon.map[ny][nx] === 0) { + this.monster.x = nx; + this.monster.y = ny; + break; + } + } + } + + getState() { + return { + gameState: this.gameState, + player: this.player, + monster: this.monster, + map: this.dungeon.map, + entrance: this.dungeon.entrance, + exit: this.dungeon.exit, + treasure: this.dungeon.treasure, + hasTreasure: this.player.hasTreasure + }; + } +} + +module.exports = Game; \ No newline at end of file diff --git a/html/favicon.ico b/html/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..8585e957e9efe34d31da7307c03a3ae9458156b8 GIT binary patch literal 5687 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 + + + Wowgue + + + + +
+
+

+
+ +
+ Block height: 0 +
+ +
+
+
    +
  • Welcome to Wowgue!
  • +
  • Type 'hello' to begin
  • +
+
+
+ +
+ +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + diff --git a/html/js/game.js b/html/js/game.js new file mode 100644 index 0000000..6e19788 --- /dev/null +++ b/html/js/game.js @@ -0,0 +1,227 @@ +var Game = { + // Change dimensions to match the display options (25 × 19 tiles) + _screenWidth: 25, // Used for drawing coordinates (columns) + _screenHeight: 19, // Used for drawing coordinates (rows) + _mapWidth: 25, // Logical map width (should match display) + _mapHeight: 19, // Logical map height (should match display) + _display: null, + _map: null, + _player: null, + _monster: null, + _exit: null, + _entrance: null, + _treasure: null, + _gameActive: false, + _message: "", // To display messages like 'waiting' + + init: function() { + // Assuming 'options' is defined globally or passed correctly + console.log("Creating ROT.Display with options:", options); + try { + this._display = new ROT.Display(options); + console.log("ROT.Display created."); + // Do not append here; we use external logic to append container + } catch (e) { + console.error("Error creating ROT.Display:", e); + alert("Failed to initialize display. Check console for errors."); + return; + } + + // Initialize empty map representation based on _mapWidth and _mapHeight + this._map = []; + for (var i = 0; i < this._mapWidth; i++) { + this._map[i] = []; + for (var j = 0; j < this._mapHeight; j++) { + // Default to wall visually; adjust as needed + this._map[i][j] = 1; + } + } + + var game = this; + // Set up keyboard input + window.addEventListener("keydown", function(e) { + var code = e.keyCode; + + // If game isn't active, ignore all keys except Enter + if (!game._gameActive && code !== 13) { + return; + } + + // Enter key to start game + if (code === 13 && !game._gameActive) { + console.log("Enter pressed, sending 'enter' message to server."); + socket.emit('chat message', 'enter'); + game._message = "Connecting..."; + game._drawWelcomeScreen(); + e.preventDefault(); + return; + } + + // Movement controls + var direction = ""; + switch (code) { + case 38: case 75: case 87: // up, k, w + direction = "up"; + break; + case 40: case 74: case 83: // down, j, s + direction = "down"; + break; + case 37: case 72: case 65: // left, h, a + direction = "left"; + break; + case 39: case 76: case 68: // right, l, d + direction = "right"; + break; + default: + return; + } + + if (direction && game._gameActive) { + socket.emit('move', direction); + e.preventDefault(); + } + }); + + // Draw welcome screen + this._message = "Press Enter or type 'enter' to Play!"; + this._drawWelcomeScreen(); + }, + + // Initialize game with data from server + startGame: function(data) { + console.log("Starting game with data:", data); + + this._map = data.map; + this._player = data.player; + this._monster = data.monster; + this._entrance = data.entrance; + this._exit = data.exit; + this._treasure = data.treasure; + this._gameActive = true; + + this._drawGameScreen(); + }, + + clearDisplay: function() { + // Clear the entire display area + this._display.clear(); + }, + + _drawGameScreen: function() { + this.clearDisplay(); + + // Draw map + for (var x = 0; x < this._mapWidth; x++) { + for (var y = 0; y < this._mapHeight; y++) { + var tile = this._map[y] && this._map[y][x] ? this._map[y][x] : 1; + + if (tile === 0) { + this._display.draw(x, y, "'", "#fff"); // Floor + } else { + this._display.draw(x, y, "#", "#777"); // Wall + } + } + } + + // Draw special features + if (this._entrance) { + this._display.draw(this._entrance[0], this._entrance[1], "<", "#0f0"); + } + + if (this._exit) { + this._display.draw(this._exit[0], this._exit[1], ">", "#0f0"); + } + + if (this._treasure && (!this._player || !this._player.hasTreasure)) { + this._display.draw(this._treasure[0], this._treasure[1], "$", "#ff0"); + } + + // Draw player + if (this._player) { + this._display.draw(this._player.x, this._player.y, "@", "#fff"); + } + + // Draw monster + if (this._monster) { + this._display.draw(this._monster.x, this._monster.y, "~", "#f00"); + } + + // Draw status line + var statusY = this._mapHeight; // Position below map + this._display.drawText(0, statusY, "--------------------------------------------------------------------------------"); // Separator + statusY++; + + var statusLine = `Use Arrows/WASD/HJKL. Find ($) and reach exit (>). Avoid (~).`; + if (this._player && this._player.hasTreasure) { + statusLine = "You have the treasure ($)! Reach the exit (>)!"; + } + this._display.drawText(1, statusY, statusLine); + }, + + _drawWelcomeScreen: function() { + this.clearDisplay(); + var y = 5; + this._display.drawText(this._screenWidth / 2 - 5, y++, "%c{yellow}WOWGUE"); + y++; + y+=2; + this._display.drawText(this._screenWidth / 2 - 10, y++, "@ - This is you"); + this._display.drawText(this._screenWidth / 2 - 10, y++, "> - Escape the dungeon"); + this._display.drawText(this._screenWidth / 2 - 10, y++, "~ - Avoid the monster"); + this._display.drawText(this._screenWidth / 2 - 10, y++, "$ - Find the treasure"); + y+=2; + // Display dynamic message (like waiting or error) + if (this._message) { + this._display.drawText(this._screenWidth / 2 - this._message.length / 2, y++, `%c{yellow}${this._message}`); + } + }, + + _drawWinScreen: function(hasTreasure) { + this.clearDisplay(); + var y = 5; + this._display.drawText(this._screenWidth / 2 - 5, y++, "%c{green}YOU WIN!"); + y++; + + if (hasTreasure) { + this._display.drawText(this._screenWidth / 2 - 15, y++, "You found the treasure and escaped!"); + } else { + this._display.drawText(this._screenWidth / 2 - 10, y++, "You escaped the dungeon!"); + } + + y++; + this._gameActive = false; + this._message = "Press Enter to Play Again!"; + this._display.drawText(this._screenWidth / 2 - (this._message.length / 2), y++, `%c{yellow}${this._message}`); + }, + + _drawLoseScreen: function(reason) { + this.clearDisplay(); + var y = 5; + this._display.drawText(this._screenWidth / 2 - 5, y++, "%c{red}GAME OVER!"); + y++; + + if (reason === 'timeout') { + this._display.drawText(this._screenWidth / 2 - 20, y++, "You didn't escape before the next block!"); + } else if (reason === 'caught') { + this._display.drawText(this._screenWidth / 2 - 15, y++, "The monster caught you!"); + } else { + this._display.drawText(this._screenWidth / 2 - 10, y++, `Reason: ${reason}`); + } + + y++; + this._gameActive = false; + this._message = "Press Enter to Play Again!"; + this._display.drawText(this._screenWidth / 2 - (this._message.length / 2), y++, `%c{yellow}${this._message}`); + }, + + getDisplay: function() { + return this._display; + }, + + getScreenWidth: function() { + return this._screenWidth; + }, + + getScreenHeight: function() { + return this._screenHeight; + } +}; \ No newline at end of file diff --git a/html/js/jquery-3.4.1.min.js b/html/js/jquery-3.4.1.min.js new file mode 100644 index 0000000..a1c07fd --- /dev/null +++ b/html/js/jquery-3.4.1.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0": [32, 0], // Exit + "@": [64, 0], // Player + "~": [96, 0], // Monster + "<": [0, 32], // Entrance + "=": [32, 32], // Monster Entrance + "#": [64, 32], // Wall + "$": [96, 32], // Treasure + // ... include all other necessary character mappings ... + "a": [128, 0], + "b": [160, 0], + "c": [192, 0], + "d": [224, 0], + "e": [256, 0], + "f": [288, 0], + "g": [320, 0], + "h": [352, 0], + "i": [384, 0], + "j": [416, 0], + "k": [448, 0], + "l": [480, 0], + "m": [512, 0], // Duplicate M? Ensure one is correct + "n": [544, 0], + "o": [576, 0], + "p": [608, 0], + "q": [640, 0], + "r": [672, 0], + "s": [704, 0], + "t": [736, 0], + "u": [768, 0], + "v": [800, 0], + "w": [832, 0], + "x": [864, 0], + "y": [896, 0], + "z": [928, 0], + "A": [128, 32], + "B": [160, 32], + "C": [192, 32], + "D": [224, 32], + "E": [256, 32], + "F": [288, 32], + "G": [320, 32], + "H": [352, 32], + "I": [384, 32], + "J": [416, 32], + "K": [448, 32], + "L": [480, 32], + "M": [512, 32], // Already mapped M + "N": [544, 32], + "O": [576, 32], + "P": [608, 32], + "Q": [640, 32], + "R": [672, 32], + "S": [704, 32], + "T": [736, 32], + "U": [768, 32], + "V": [800, 32], + "W": [832, 32], + "X": [864, 32], + "Y": [896, 32], + "Z": [928, 32], + "&": [0, 64], + "-": [32, 64], + "+": [64, 64], + "`": [96, 64], + "0": [128, 64], + "1": [160, 64], + "2": [192, 64], + "3": [224, 64], + "4": [256, 64], + "5": [288, 64], + "6": [320, 64], + "7": [352, 64], + "8": [384, 64], + "9": [416, 64], + ".": [448, 64], + ":": [480, 64], + ",": [512, 64], + ";": [544, 64], + "(": [576, 64], + "*": [608, 64], + "!": [640, 64], + "?": [672, 64], + "}": [704, 64], + "^": [736, 64], + ")": [768, 64], + "[": [800, 64], + "]": [832, 64], + "{": [864, 64], + "%": [896, 64], + "^": [928, 64], // Duplicate ^ + " ": [992, 64] + } +}; diff --git a/html/js/rot.js b/html/js/rot.js new file mode 100644 index 0000000..03f3919 --- /dev/null +++ b/html/js/rot.js @@ -0,0 +1,7228 @@ +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : 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() { + this._ctx.fillStyle = this._options.bg; + + this._ctx.fillRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height); + }; + + _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({ + 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({ + 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); + + TileGL.isSupported = function isSupported() { + return !!document.createElement("canvas").getContext("webgl2", { + preserveDrawingBuffer: true + }); + }; + + function TileGL() { + var _this5; + + _this5 = _Backend2.call(this) || this; + _this5._uniforms = {}; + + try { + _this5._gl = _this5._initWebGL(); + } catch (e) { + alert(e.message); + } + + return _this5; + } + + 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= 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) { + if (!(color in colorCache)) { + var parsed; + + if (color == "transparent") { + parsed = [0, 0, 0, 0]; + } else if (color.indexOf("rgba") > -1) { + parsed = (color.match(/[\d.]+/g) || []).map(Number); + + for (var i = 0; i < 3; i++) { + parsed[i] = parsed[i] / 255; + } + } else { + parsed = fromString(color).map(function ($) { + return $ / 255; + }); + parsed.push(1); + } + + colorCache[color] = parsed; + } + + return colorCache[color]; + } + + 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) { + var SRC_COLORS = 256.0; + var DST_COLORS = 6.0; + var COLOR_RATIO = DST_COLORS / SRC_COLORS; + var rgb = fromString(color); + 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; + } // 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 */ + lineLength = 0; + lastTokenWithSpace = -1; + } + + if (token.type != TYPE_TEXT) { + /* skip non-text tokens */ + i++; + continue; + } + /* remove spaces at the beginning of line */ + + + while (lineLength == 0 && token.value.charAt(0) == " ") { + token.value = token.value.substring(1); + } + /* forced newline? insert two new tokens after this one */ + + + var _index2 = token.value.indexOf("\n"); + + if (_index2 != -1) { + token.value = breakInsideToken(tokens, i, _index2, true); + /* if there are spaces at the end, we must remove them (we do not want the line too long) */ + + var arr = token.value.split(""); + + while (arr.length && arr[arr.length - 1] == " ") { + arr.pop(); + } + + token.value = arr.join(""); + } + /* token degenerated? */ + + + if (!token.value.length) { + tokens.splice(i, 1); + continue; + } + + if (lineLength + token.value.length > maxWidth) { + /* line too long, find a suitable breaking spot */ + + /* is it possible to break within this token? */ + var _index3 = -1; + + while (1) { + var nextIndex = token.value.indexOf(" ", _index3 + 1); + + if (nextIndex == -1) { + break; + } + + if (lineLength + nextIndex > maxWidth) { + break; + } + + _index3 = nextIndex; + } + + if (_index3 != -1) { + /* break at space within this one */ + token.value = breakInsideToken(tokens, i, _index3, true); + } else if (lastTokenWithSpace != -1) { + /* is there a previous token where a break can occur? */ + var _token = tokens[lastTokenWithSpace]; + + var breakIndex = _token.value.lastIndexOf(" "); + + _token.value = breakInsideToken(tokens, lastTokenWithSpace, breakIndex, true); + i = lastTokenWithSpace; + } else { + /* force break in this token */ + token.value = breakInsideToken(tokens, i, maxWidth - lineLength, false); + } + } else { + /* line not long, continue */ + lineLength += token.value.length; + + if (token.value.indexOf(" ") != -1) { + lastTokenWithSpace = i; + } + } + + i++; + /* advance to next token */ + } + + tokens.push({ + type: TYPE_NEWLINE + }); + /* insert fake newline to fix the last text line */ + + /* remove trailing space from text tokens before newlines */ + + var lastTextToken = null; + + for (var _i = 0; _i < tokens.length; _i++) { + var _token2 = tokens[_i]; + + switch (_token2.type) { + case TYPE_TEXT: + lastTextToken = _token2; + break; + + case TYPE_NEWLINE: + if (lastTextToken) { + /* remove trailing space */ + var _arr = lastTextToken.value.split(""); + + while (_arr.length && _arr[_arr.length - 1] == " ") { + _arr.pop(); + } + + lastTextToken.value = _arr.join(""); + } + + lastTextToken = null; + break; + } + } + + tokens.pop(); + /* remove fake token */ + + return tokens; + } + /** + * Create new tokens and insert them into the stream + * @param {object[]} tokens + * @param {int} tokenIndex Token being processed + * @param {int} breakIndex Index within current token's value + * @param {bool} removeBreakChar Do we want to remove the breaking character? + * @returns {string} remaining unbroken token value + */ + + + function breakInsideToken(tokens, tokenIndex, breakIndex, removeBreakChar) { + var newBreakToken = { + type: TYPE_NEWLINE + }; + var newTextToken = { + type: TYPE_TEXT, + value: tokens[tokenIndex].value.substring(breakIndex + (removeBreakChar ? 1 : 0)) + }; + tokens.splice(tokenIndex + 1, 0, newBreakToken, newTextToken); + return tokens[tokenIndex].value.substring(0, breakIndex); + } + + var text = + /*#__PURE__*/ + Object.freeze({ + TYPE_TEXT: TYPE_TEXT, + TYPE_NEWLINE: TYPE_NEWLINE, + TYPE_FG: TYPE_FG, + TYPE_BG: TYPE_BG, + measure: measure, + tokenize: tokenize + }); + /** Default with for display and map generators */ + + var DEFAULT_WIDTH = 80; + /** Default height for display and map generators */ + + var DEFAULT_HEIGHT = 25; + var DIRS = { + 4: [[0, -1], [1, 0], [0, 1], [-1, 0]], + 8: [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]], + 6: [[-1, -1], [1, -1], [2, 0], [1, 1], [-1, 1], [-2, 0]] + }; + var KEYS = { + /** Cancel key. */ + VK_CANCEL: 3, + + /** Help key. */ + VK_HELP: 6, + + /** Backspace key. */ + VK_BACK_SPACE: 8, + + /** Tab key. */ + VK_TAB: 9, + + /** 5 key on Numpad when NumLock is unlocked. Or on Mac, clear key which is positioned at NumLock key. */ + VK_CLEAR: 12, + + /** Return/enter key on the main keyboard. */ + VK_RETURN: 13, + + /** Reserved, but not used. */ + VK_ENTER: 14, + + /** Shift key. */ + VK_SHIFT: 16, + + /** Control key. */ + VK_CONTROL: 17, + + /** Alt (Option on Mac) key. */ + VK_ALT: 18, + + /** Pause key. */ + VK_PAUSE: 19, + + /** Caps lock. */ + VK_CAPS_LOCK: 20, + + /** Escape key. */ + VK_ESCAPE: 27, + + /** Space bar. */ + VK_SPACE: 32, + + /** Page Up key. */ + VK_PAGE_UP: 33, + + /** Page Down key. */ + VK_PAGE_DOWN: 34, + + /** End key. */ + VK_END: 35, + + /** Home key. */ + VK_HOME: 36, + + /** Left arrow. */ + VK_LEFT: 37, + + /** Up arrow. */ + VK_UP: 38, + + /** Right arrow. */ + VK_RIGHT: 39, + + /** Down arrow. */ + VK_DOWN: 40, + + /** Print Screen key. */ + VK_PRINTSCREEN: 44, + + /** Ins(ert) key. */ + VK_INSERT: 45, + + /** Del(ete) key. */ + VK_DELETE: 46, + + /***/ + VK_0: 48, + + /***/ + VK_1: 49, + + /***/ + VK_2: 50, + + /***/ + VK_3: 51, + + /***/ + VK_4: 52, + + /***/ + VK_5: 53, + + /***/ + VK_6: 54, + + /***/ + VK_7: 55, + + /***/ + VK_8: 56, + + /***/ + VK_9: 57, + + /** Colon (:) key. Requires Gecko 15.0 */ + VK_COLON: 58, + + /** Semicolon (;) key. */ + VK_SEMICOLON: 59, + + /** Less-than (<) key. Requires Gecko 15.0 */ + VK_LESS_THAN: 60, + + /** Equals (=) key. */ + VK_EQUALS: 61, + + /** Greater-than (>) key. Requires Gecko 15.0 */ + VK_GREATER_THAN: 62, + + /** Question mark (?) key. Requires Gecko 15.0 */ + VK_QUESTION_MARK: 63, + + /** Atmark (@) key. Requires Gecko 15.0 */ + VK_AT: 64, + + /***/ + VK_A: 65, + + /***/ + VK_B: 66, + + /***/ + VK_C: 67, + + /***/ + VK_D: 68, + + /***/ + VK_E: 69, + + /***/ + VK_F: 70, + + /***/ + VK_G: 71, + + /***/ + VK_H: 72, + + /***/ + VK_I: 73, + + /***/ + VK_J: 74, + + /***/ + VK_K: 75, + + /***/ + VK_L: 76, + + /***/ + VK_M: 77, + + /***/ + VK_N: 78, + + /***/ + VK_O: 79, + + /***/ + VK_P: 80, + + /***/ + VK_Q: 81, + + /***/ + VK_R: 82, + + /***/ + VK_S: 83, + + /***/ + VK_T: 84, + + /***/ + VK_U: 85, + + /***/ + VK_V: 86, + + /***/ + VK_W: 87, + + /***/ + VK_X: 88, + + /***/ + VK_Y: 89, + + /***/ + VK_Z: 90, + + /***/ + VK_CONTEXT_MENU: 93, + + /** 0 on the numeric keypad. */ + VK_NUMPAD0: 96, + + /** 1 on the numeric keypad. */ + VK_NUMPAD1: 97, + + /** 2 on the numeric keypad. */ + VK_NUMPAD2: 98, + + /** 3 on the numeric keypad. */ + VK_NUMPAD3: 99, + + /** 4 on the numeric keypad. */ + VK_NUMPAD4: 100, + + /** 5 on the numeric keypad. */ + VK_NUMPAD5: 101, + + /** 6 on the numeric keypad. */ + VK_NUMPAD6: 102, + + /** 7 on the numeric keypad. */ + VK_NUMPAD7: 103, + + /** 8 on the numeric keypad. */ + VK_NUMPAD8: 104, + + /** 9 on the numeric keypad. */ + VK_NUMPAD9: 105, + + /** * on the numeric keypad. */ + VK_MULTIPLY: 106, + + /** + on the numeric keypad. */ + VK_ADD: 107, + + /***/ + VK_SEPARATOR: 108, + + /** - on the numeric keypad. */ + VK_SUBTRACT: 109, + + /** Decimal point on the numeric keypad. */ + VK_DECIMAL: 110, + + /** / on the numeric keypad. */ + VK_DIVIDE: 111, + + /** F1 key. */ + VK_F1: 112, + + /** F2 key. */ + VK_F2: 113, + + /** F3 key. */ + VK_F3: 114, + + /** F4 key. */ + VK_F4: 115, + + /** F5 key. */ + VK_F5: 116, + + /** F6 key. */ + VK_F6: 117, + + /** F7 key. */ + VK_F7: 118, + + /** F8 key. */ + VK_F8: 119, + + /** F9 key. */ + VK_F9: 120, + + /** F10 key. */ + VK_F10: 121, + + /** F11 key. */ + VK_F11: 122, + + /** F12 key. */ + VK_F12: 123, + + /** F13 key. */ + VK_F13: 124, + + /** F14 key. */ + VK_F14: 125, + + /** F15 key. */ + VK_F15: 126, + + /** F16 key. */ + VK_F16: 127, + + /** F17 key. */ + VK_F17: 128, + + /** F18 key. */ + VK_F18: 129, + + /** F19 key. */ + VK_F19: 130, + + /** F20 key. */ + VK_F20: 131, + + /** F21 key. */ + VK_F21: 132, + + /** F22 key. */ + VK_F22: 133, + + /** F23 key. */ + VK_F23: 134, + + /** F24 key. */ + VK_F24: 135, + + /** Num Lock key. */ + VK_NUM_LOCK: 144, + + /** Scroll Lock key. */ + VK_SCROLL_LOCK: 145, + + /** Circumflex (^) key. Requires Gecko 15.0 */ + VK_CIRCUMFLEX: 160, + + /** Exclamation (!) key. Requires Gecko 15.0 */ + VK_EXCLAMATION: 161, + + /** Double quote () key. Requires Gecko 15.0 */ + VK_DOUBLE_QUOTE: 162, + + /** Hash (#) key. Requires Gecko 15.0 */ + VK_HASH: 163, + + /** Dollar sign ($) key. Requires Gecko 15.0 */ + VK_DOLLAR: 164, + + /** Percent (%) key. Requires Gecko 15.0 */ + VK_PERCENT: 165, + + /** Ampersand (&) key. Requires Gecko 15.0 */ + VK_AMPERSAND: 166, + + /** Underscore (_) key. Requires Gecko 15.0 */ + VK_UNDERSCORE: 167, + + /** Open parenthesis (() key. Requires Gecko 15.0 */ + VK_OPEN_PAREN: 168, + + /** Close parenthesis ()) key. Requires Gecko 15.0 */ + VK_CLOSE_PAREN: 169, + + /* Asterisk (*) key. Requires Gecko 15.0 */ + VK_ASTERISK: 170, + + /** Plus (+) key. Requires Gecko 15.0 */ + VK_PLUS: 171, + + /** Pipe (|) key. Requires Gecko 15.0 */ + VK_PIPE: 172, + + /** Hyphen-US/docs/Minus (-) key. Requires Gecko 15.0 */ + VK_HYPHEN_MINUS: 173, + + /** Open curly bracket ({) key. Requires Gecko 15.0 */ + VK_OPEN_CURLY_BRACKET: 174, + + /** Close curly bracket (}) key. Requires Gecko 15.0 */ + VK_CLOSE_CURLY_BRACKET: 175, + + /** Tilde (~) key. Requires Gecko 15.0 */ + VK_TILDE: 176, + + /** Comma (,) key. */ + VK_COMMA: 188, + + /** Period (.) key. */ + VK_PERIOD: 190, + + /** Slash (/) key. */ + VK_SLASH: 191, + + /** Back tick (`) key. */ + VK_BACK_QUOTE: 192, + + /** Open square bracket ([) key. */ + VK_OPEN_BRACKET: 219, + + /** Back slash (\) key. */ + VK_BACK_SLASH: 220, + + /** Close square bracket (]) key. */ + VK_CLOSE_BRACKET: 221, + + /** Quote (''') key. */ + VK_QUOTE: 222, + + /** Meta key on Linux, Command key on Mac. */ + VK_META: 224, + + /** AltGr key on Linux. Requires Gecko 15.0 */ + VK_ALTGR: 225, + + /** Windows logo key on Windows. Or Super or Hyper key on Linux. Requires Gecko 15.0 */ + VK_WIN: 91, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANA: 21, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANGUL: 21, + + /** 英数 key on Japanese Mac keyboard. Requires Gecko 15.0 */ + VK_EISU: 22, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_JUNJA: 23, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_FINAL: 24, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANJA: 25, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANJI: 25, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_CONVERT: 28, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_NONCONVERT: 29, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_ACCEPT: 30, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_MODECHANGE: 31, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SELECT: 41, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_PRINT: 42, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_EXECUTE: 43, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SLEEP: 95 + }; + var BACKENDS = { + "hex": Hex, + "rect": Rect, + "tile": Tile, + "tile-gl": TileGL, + "term": Term + }; + var DEFAULT_OPTIONS = { + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT, + transpose: false, + layout: "rect", + fontSize: 15, + spacing: 1, + border: 0, + forceSquareRatio: false, + fontFamily: "monospace", + fontStyle: "", + fg: "#ccc", + bg: "#000", + tileWidth: 32, + tileHeight: 32, + tileMap: {}, + tileSet: null, + tileColorize: false + }; + /** + * @class Visual map display + */ + + var Display = + /*#__PURE__*/ + function () { + function Display(options) { + if (options === void 0) { + options = {}; + } + + this._data = {}; + this._dirty = false; // false = nothing, true = all, object = dirty cells + + this._options = {}; + options = Object.assign({}, DEFAULT_OPTIONS, options); + this.setOptions(options); + this.DEBUG = this.DEBUG.bind(this); + this._tick = this._tick.bind(this); + + this._backend.schedule(this._tick); + } + /** + * Debug helper, ideal as a map generator callback. Always bound to this. + * @param {int} x + * @param {int} y + * @param {int} what + */ + + + var _proto9 = Display.prototype; + + _proto9.DEBUG = function DEBUG(x, y, what) { + var colors = [this._options.bg, this._options.fg]; + this.draw(x, y, null, null, colors[what % colors.length]); + }; + /** + * Clear the whole display (cover it with background color) + */ + + + _proto9.clear = function clear() { + this._data = {}; + this._dirty = true; + }; + /** + * @see ROT.Display + */ + + + _proto9.setOptions = function setOptions(options) { + Object.assign(this._options, options); + + if (options.width || options.height || options.fontSize || options.fontFamily || options.spacing || options.layout) { + if (options.layout) { + var ctor = BACKENDS[options.layout]; + this._backend = new ctor(); + } + + this._backend.setOptions(this._options); + + this._dirty = true; + } + + return this; + }; + /** + * Returns currently set options + */ + + + _proto9.getOptions = function getOptions() { + return this._options; + }; + /** + * Returns the DOM node of this display + */ + + + _proto9.getContainer = function getContainer() { + return this._backend.getContainer(); + }; + /** + * Compute the maximum width/height to fit into a set of given constraints + * @param {int} availWidth Maximum allowed pixel width + * @param {int} availHeight Maximum allowed pixel height + * @returns {int[2]} cellWidth,cellHeight + */ + + + _proto9.computeSize = function computeSize(availWidth, availHeight) { + return this._backend.computeSize(availWidth, availHeight); + }; + /** + * Compute the maximum font size to fit into a set of given constraints + * @param {int} availWidth Maximum allowed pixel width + * @param {int} availHeight Maximum allowed pixel height + * @returns {int} fontSize + */ + + + _proto9.computeFontSize = function computeFontSize(availWidth, availHeight) { + return this._backend.computeFontSize(availWidth, availHeight); + }; + + _proto9.computeTileSize = function computeTileSize(availWidth, availHeight) { + var width = Math.floor(availWidth / this._options.width); + var height = Math.floor(availHeight / this._options.height); + return [width, height]; + }; + /** + * Convert a DOM event (mouse or touch) to map coordinates. Uses first touch for multi-touch. + * @param {Event} e event + * @returns {int[2]} -1 for values outside of the canvas + */ + + + _proto9.eventToPosition = function eventToPosition(e) { + var x, y; + + if ("touches" in e) { + x = e.touches[0].clientX; + y = e.touches[0].clientY; + } else { + x = e.clientX; + y = e.clientY; + } + + return this._backend.eventToPosition(x, y); + }; + /** + * @param {int} x + * @param {int} y + * @param {string || string[]} ch One or more chars (will be overlapping themselves) + * @param {string} [fg] foreground color + * @param {string} [bg] background color + */ + + + _proto9.draw = function draw(x, y, ch, fg, bg) { + if (!fg) { + fg = this._options.fg; + } + + if (!bg) { + bg = this._options.bg; + } + + var key = x + "," + y; + this._data[key] = [x, y, ch, fg, bg]; + + if (this._dirty === true) { + return; + } // will already redraw everything + + + if (!this._dirty) { + this._dirty = {}; + } // first! + + + this._dirty[key] = true; + }; + /** + * Draws a text at given position. Optionally wraps at a maximum length. Currently does not work with hex layout. + * @param {int} x + * @param {int} y + * @param {string} text May contain color/background format specifiers, %c{name}/%b{name}, both optional. %c{}/%b{} resets to default. + * @param {int} [maxWidth] wrap at what width? + * @returns {int} lines drawn + */ + + + _proto9.drawText = function drawText(x, y, text, maxWidth) { + var fg = null; + var bg = null; + var cx = x; + var cy = y; + var lines = 1; + + if (!maxWidth) { + maxWidth = this._options.width - x; + } + + var tokens = tokenize(text, maxWidth); + + while (tokens.length) { + // interpret tokenized opcode stream + var token = tokens.shift(); + + switch (token.type) { + case TYPE_TEXT: + var isSpace = false, + isPrevSpace = false, + isFullWidth = false, + isPrevFullWidth = false; + + for (var i = 0; i < token.value.length; i++) { + var cc = token.value.charCodeAt(i); + var c = token.value.charAt(i); // Assign to `true` when the current char is full-width. + + isFullWidth = cc > 0xff00 && cc < 0xff61 || cc > 0xffdc && cc < 0xffe8 || cc > 0xffee; // Current char is space, whatever full-width or half-width both are OK. + + isSpace = c.charCodeAt(0) == 0x20 || c.charCodeAt(0) == 0x3000; // The previous char is full-width and + // current char is nether half-width nor a space. + + if (isPrevFullWidth && !isFullWidth && !isSpace) { + cx++; + } // add an extra position + // The current char is full-width and + // the previous char is not a space. + + + if (isFullWidth && !isPrevSpace) { + cx++; + } // add an extra position + + + this.draw(cx++, cy, c, fg, bg); + isPrevSpace = isSpace; + isPrevFullWidth = isFullWidth; + } + + break; + + case TYPE_FG: + fg = token.value || null; + break; + + case TYPE_BG: + bg = token.value || null; + break; + + case TYPE_NEWLINE: + cx = x; + cy++; + lines++; + break; + } + } + + return lines; + }; + /** + * Timer tick: update dirty parts + */ + + + _proto9._tick = function _tick() { + this._backend.schedule(this._tick); + + if (!this._dirty) { + return; + } + + if (this._dirty === true) { + // draw all + this._backend.clear(); + + for (var id in this._data) { + this._draw(id, false); + } // redraw cached data + + } else { + // draw only dirty + for (var key in this._dirty) { + this._draw(key, true); + } + } + + this._dirty = false; + }; + /** + * @param {string} key What to draw + * @param {bool} clearBefore Is it necessary to clean before? + */ + + + _proto9._draw = function _draw(key, clearBefore) { + var data = this._data[key]; + + if (data[4] != this._options.bg) { + clearBefore = true; + } + + this._backend.draw(data, clearBefore); + }; + + return Display; + }(); + + Display.Rect = Rect; + Display.Hex = Hex; + Display.Tile = Tile; + Display.TileGL = TileGL; + Display.Term = Term; + /** + * @class (Markov process)-based string generator. + * Copied from a RogueBasin article. + * Offers configurable order and prior. + */ + + var StringGenerator = + /*#__PURE__*/ + function () { + function StringGenerator(options) { + this._options = { + words: false, + order: 3, + prior: 0.001 + }; + Object.assign(this._options, options); + this._boundary = String.fromCharCode(0); + this._suffix = this._boundary; + this._prefix = []; + + for (var i = 0; i < this._options.order; i++) { + this._prefix.push(this._boundary); + } + + this._priorValues = {}; + this._priorValues[this._boundary] = this._options.prior; + this._data = {}; + } + /** + * Remove all learning data + */ + + + var _proto10 = StringGenerator.prototype; + + _proto10.clear = function clear() { + this._data = {}; + this._priorValues = {}; + }; + /** + * @returns {string} Generated string + */ + + + _proto10.generate = function generate() { + var result = [this._sample(this._prefix)]; + + while (result[result.length - 1] != this._boundary) { + result.push(this._sample(result)); + } + + return this._join(result.slice(0, -1)); + }; + /** + * Observe (learn) a string from a training set + */ + + + _proto10.observe = function observe(string) { + var tokens = this._split(string); + + for (var i = 0; i < tokens.length; i++) { + this._priorValues[tokens[i]] = this._options.prior; + } + + tokens = this._prefix.concat(tokens).concat(this._suffix); + /* add boundary symbols */ + + for (var _i2 = this._options.order; _i2 < tokens.length; _i2++) { + var context = tokens.slice(_i2 - this._options.order, _i2); + var event = tokens[_i2]; + + for (var j = 0; j < context.length; j++) { + var subcontext = context.slice(j); + + this._observeEvent(subcontext, event); + } + } + }; + + _proto10.getStats = function getStats() { + var parts = []; + var priorCount = Object.keys(this._priorValues).length; + priorCount--; // boundary + + parts.push("distinct samples: " + priorCount); + var dataCount = Object.keys(this._data).length; + var eventCount = 0; + + for (var p in this._data) { + eventCount += Object.keys(this._data[p]).length; + } + + parts.push("dictionary size (contexts): " + dataCount); + parts.push("dictionary size (events): " + eventCount); + return parts.join(", "); + }; + /** + * @param {string} + * @returns {string[]} + */ + + + _proto10._split = function _split(str) { + return str.split(this._options.words ? /\s+/ : ""); + }; + /** + * @param {string[]} + * @returns {string} + */ + + + _proto10._join = function _join(arr) { + return arr.join(this._options.words ? " " : ""); + }; + /** + * @param {string[]} context + * @param {string} event + */ + + + _proto10._observeEvent = function _observeEvent(context, event) { + var key = this._join(context); + + if (!(key in this._data)) { + this._data[key] = {}; + } + + var data = this._data[key]; + + if (!(event in data)) { + data[event] = 0; + } + + data[event]++; + }; + /** + * @param {string[]} + * @returns {string} + */ + + + _proto10._sample = function _sample(context) { + context = this._backoff(context); + + var key = this._join(context); + + var data = this._data[key]; + var available = {}; + + if (this._options.prior) { + for (var event in this._priorValues) { + available[event] = this._priorValues[event]; + } + + for (var _event in data) { + available[_event] += data[_event]; + } + } else { + available = data; + } + + return RNG$1.getWeightedValue(available); + }; + /** + * @param {string[]} + * @returns {string[]} + */ + + + _proto10._backoff = function _backoff(context) { + if (context.length > this._options.order) { + context = context.slice(-this._options.order); + } else if (context.length < this._options.order) { + context = this._prefix.slice(0, this._options.order - context.length).concat(context); + } + + while (!(this._join(context) in this._data) && context.length > 0) { + context = context.slice(1); + } + + return context; + }; + + return StringGenerator; + }(); + + var EventQueue = + /*#__PURE__*/ + function () { + /** + * @class Generic event queue: stores events and retrieves them based on their time + */ + function EventQueue() { + this._time = 0; + this._events = []; + this._eventTimes = []; + } + /** + * @returns {number} Elapsed time + */ + + + var _proto11 = EventQueue.prototype; + + _proto11.getTime = function getTime() { + return this._time; + }; + /** + * Clear all scheduled events + */ + + + _proto11.clear = function clear() { + this._events = []; + this._eventTimes = []; + return this; + }; + /** + * @param {?} event + * @param {number} time + */ + + + _proto11.add = function add(event, time) { + var index = this._events.length; + + for (var i = 0; i < this._eventTimes.length; i++) { + if (this._eventTimes[i] > time) { + index = i; + break; + } + } + + this._events.splice(index, 0, event); + + this._eventTimes.splice(index, 0, time); + }; + /** + * Locates the nearest event, advances time if necessary. Returns that event and removes it from the queue. + * @returns {? || null} The event previously added by addEvent, null if no event available + */ + + + _proto11.get = function get() { + if (!this._events.length) { + return null; + } + + var time = this._eventTimes.splice(0, 1)[0]; + + if (time > 0) { + /* advance */ + this._time += time; + + for (var i = 0; i < this._eventTimes.length; i++) { + this._eventTimes[i] -= time; + } + } + + return this._events.splice(0, 1)[0]; + }; + /** + * Get the time associated with the given event + * @param {?} event + * @returns {number} time + */ + + + _proto11.getEventTime = function getEventTime(event) { + var index = this._events.indexOf(event); + + if (index == -1) { + return undefined; + } + + return this._eventTimes[index]; + }; + /** + * Remove an event from the queue + * @param {?} event + * @returns {bool} success? + */ + + + _proto11.remove = function remove(event) { + var index = this._events.indexOf(event); + + if (index == -1) { + return false; + } + + this._remove(index); + + return true; + }; + + /** + * Remove an event from the queue + * @param {int} index + */ + _proto11._remove = function _remove(index) { + this._events.splice(index, 1); + + this._eventTimes.splice(index, 1); + }; + + return EventQueue; + }(); + + var Scheduler = + /*#__PURE__*/ + function () { + /** + * @class Abstract scheduler + */ + function Scheduler() { + this._queue = new EventQueue(); + this._repeat = []; + this._current = null; + } + /** + * @see ROT.EventQueue#getTime + */ + + + var _proto12 = Scheduler.prototype; + + _proto12.getTime = function getTime() { + return this._queue.getTime(); + }; + /** + * @param {?} item + * @param {bool} repeat + */ + + + _proto12.add = function add(item, repeat) { + if (repeat) { + this._repeat.push(item); + } + + return this; + }; + /** + * Get the time the given item is scheduled for + * @param {?} item + * @returns {number} time + */ + + + _proto12.getTimeOf = function getTimeOf(item) { + return this._queue.getEventTime(item); + }; + /** + * Clear all items + */ + + + _proto12.clear = function clear() { + this._queue.clear(); + + this._repeat = []; + this._current = null; + return this; + }; + /** + * Remove a previously added item + * @param {?} item + * @returns {bool} successful? + */ + + + _proto12.remove = function remove(item) { + var result = this._queue.remove(item); + + var index = this._repeat.indexOf(item); + + if (index != -1) { + this._repeat.splice(index, 1); + } + + if (this._current == item) { + this._current = null; + } + + return result; + }; + /** + * Schedule next item + * @returns {?} + */ + + + _proto12.next = function next() { + this._current = this._queue.get(); + return this._current; + }; + + return Scheduler; + }(); + /** + * @class Simple fair scheduler (round-robin style) + */ + + + var Simple = + /*#__PURE__*/ + function (_Scheduler) { + _inheritsLoose(Simple, _Scheduler); + + function Simple() { + return _Scheduler.apply(this, arguments) || this; + } + + var _proto13 = Simple.prototype; + + _proto13.add = function add(item, repeat) { + this._queue.add(item, 0); + + return _Scheduler.prototype.add.call(this, item, repeat); + }; + + _proto13.next = function next() { + if (this._current !== null && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, 0); + } + + return _Scheduler.prototype.next.call(this); + }; + + return Simple; + }(Scheduler); + /** + * @class Speed-based scheduler + */ + + + var Speed = + /*#__PURE__*/ + function (_Scheduler2) { + _inheritsLoose(Speed, _Scheduler2); + + function Speed() { + return _Scheduler2.apply(this, arguments) || this; + } + + var _proto14 = Speed.prototype; + + /** + * @param {object} item anything with "getSpeed" method + * @param {bool} repeat + * @param {number} [time=1/item.getSpeed()] + * @see ROT.Scheduler#add + */ + _proto14.add = function add(item, repeat, time) { + this._queue.add(item, time !== undefined ? time : 1 / item.getSpeed()); + + return _Scheduler2.prototype.add.call(this, item, repeat); + }; + /** + * @see ROT.Scheduler#next + */ + + + _proto14.next = function next() { + if (this._current && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, 1 / this._current.getSpeed()); + } + + return _Scheduler2.prototype.next.call(this); + }; + + return Speed; + }(Scheduler); + /** + * @class Action-based scheduler + * @augments ROT.Scheduler + */ + + + var Action = + /*#__PURE__*/ + function (_Scheduler3) { + _inheritsLoose(Action, _Scheduler3); + + function Action() { + var _this9; + + _this9 = _Scheduler3.call(this) || this; + _this9._defaultDuration = 1; + /* for newly added */ + + _this9._duration = _this9._defaultDuration; + /* for this._current */ + + return _this9; + } + /** + * @param {object} item + * @param {bool} repeat + * @param {number} [time=1] + * @see ROT.Scheduler#add + */ + + + var _proto15 = Action.prototype; + + _proto15.add = function add(item, repeat, time) { + this._queue.add(item, time || this._defaultDuration); + + return _Scheduler3.prototype.add.call(this, item, repeat); + }; + + _proto15.clear = function clear() { + this._duration = this._defaultDuration; + return _Scheduler3.prototype.clear.call(this); + }; + + _proto15.remove = function remove(item) { + if (item == this._current) { + this._duration = this._defaultDuration; + } + + return _Scheduler3.prototype.remove.call(this, item); + }; + /** + * @see ROT.Scheduler#next + */ + + + _proto15.next = function next() { + if (this._current !== null && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, this._duration || this._defaultDuration); + + this._duration = this._defaultDuration; + } + + return _Scheduler3.prototype.next.call(this); + }; + /** + * Set duration for the active item + */ + + + _proto15.setDuration = function setDuration(time) { + if (this._current) { + this._duration = time; + } + + return this; + }; + + return Action; + }(Scheduler); + + var index = { + Simple: Simple, + Speed: Speed, + Action: Action + }; + + var FOV = + /*#__PURE__*/ + function () { + /** + * @class Abstract FOV algorithm + * @param {function} lightPassesCallback Does the light pass through x,y? + * @param {object} [options] + * @param {int} [options.topology=8] 4/6/8 + */ + function FOV(lightPassesCallback, options) { + if (options === void 0) { + options = {}; + } + + this._lightPasses = lightPassesCallback; + this._options = Object.assign({ + topology: 8 + }, options); + } + /** + * Return all neighbors in a concentric ring + * @param {int} cx center-x + * @param {int} cy center-y + * @param {int} r range + */ + + + var _proto16 = FOV.prototype; + + _proto16._getCircle = function _getCircle(cx, cy, r) { + var result = []; + var dirs, countFactor, startOffset; + + switch (this._options.topology) { + case 4: + countFactor = 1; + startOffset = [0, 1]; + dirs = [DIRS[8][7], DIRS[8][1], DIRS[8][3], DIRS[8][5]]; + break; + + case 6: + dirs = DIRS[6]; + countFactor = 1; + startOffset = [-1, 1]; + break; + + case 8: + dirs = DIRS[4]; + countFactor = 2; + startOffset = [-1, 1]; + break; + + default: + throw new Error("Incorrect topology for FOV computation"); + break; + } + /* starting neighbor */ + + + var x = cx + startOffset[0] * r; + var y = cy + startOffset[1] * r; + /* circle */ + + for (var i = 0; i < dirs.length; i++) { + for (var j = 0; j < r * countFactor; j++) { + result.push([x, y]); + x += dirs[i][0]; + y += dirs[i][1]; + } + } + + return result; + }; + + return FOV; + }(); + /** + * @class Discrete shadowcasting algorithm. Obsoleted by Precise shadowcasting. + * @augments ROT.FOV + */ + + + var DiscreteShadowcasting = + /*#__PURE__*/ + function (_FOV) { + _inheritsLoose(DiscreteShadowcasting, _FOV); + + function DiscreteShadowcasting() { + return _FOV.apply(this, arguments) || this; + } + + var _proto17 = DiscreteShadowcasting.prototype; + + _proto17.compute = function compute(x, y, R, callback) { + /* this place is always visible */ + callback(x, y, 0, 1); + /* standing in a dark place. FIXME is this a good idea? */ + + if (!this._lightPasses(x, y)) { + return; + } + /* start and end angles */ + + + var DATA = []; + var A, B, cx, cy, blocks; + /* analyze surrounding cells in concentric rings, starting from the center */ + + for (var r = 1; r <= R; r++) { + var neighbors = this._getCircle(x, y, r); + + var angle = 360 / neighbors.length; + + for (var i = 0; i < neighbors.length; i++) { + cx = neighbors[i][0]; + cy = neighbors[i][1]; + A = angle * (i - 0.5); + B = A + angle; + blocks = !this._lightPasses(cx, cy); + + if (this._visibleCoords(Math.floor(A), Math.ceil(B), blocks, DATA)) { + callback(cx, cy, r, 1); + } + + if (DATA.length == 2 && DATA[0] == 0 && DATA[1] == 360) { + return; + } + /* cutoff? */ + + } + /* for all cells in this ring */ + + } + /* for all rings */ + + }; + /** + * @param {int} A start angle + * @param {int} B end angle + * @param {bool} blocks Does current cell block visibility? + * @param {int[][]} DATA shadowed angle pairs + */ + + + _proto17._visibleCoords = function _visibleCoords(A, B, blocks, DATA) { + if (A < 0) { + var v1 = this._visibleCoords(0, B, blocks, DATA); + + var v2 = this._visibleCoords(360 + A, 360, blocks, DATA); + + return v1 || v2; + } + + var index = 0; + + while (index < DATA.length && DATA[index] < A) { + index++; + } + + if (index == DATA.length) { + /* completely new shadow */ + if (blocks) { + DATA.push(A, B); + } + + return true; + } + + var count = 0; + + if (index % 2) { + /* this shadow starts in an existing shadow, or within its ending boundary */ + while (index < DATA.length && DATA[index] < B) { + index++; + count++; + } + + if (count == 0) { + return false; + } + + if (blocks) { + if (count % 2) { + DATA.splice(index - count, count, B); + } else { + DATA.splice(index - count, count); + } + } + + return true; + } else { + /* this shadow starts outside an existing shadow, or within a starting boundary */ + while (index < DATA.length && DATA[index] < B) { + index++; + count++; + } + /* visible when outside an existing shadow, or when overlapping */ + + + if (A == DATA[index - count] && count == 1) { + return false; + } + + if (blocks) { + if (count % 2) { + DATA.splice(index - count, count, A); + } else { + DATA.splice(index - count, count, A, B); + } + } + + return true; + } + }; + + return DiscreteShadowcasting; + }(FOV); + /** + * @class Precise shadowcasting algorithm + * @augments ROT.FOV + */ + + + var PreciseShadowcasting = + /*#__PURE__*/ + function (_FOV2) { + _inheritsLoose(PreciseShadowcasting, _FOV2); + + function PreciseShadowcasting() { + return _FOV2.apply(this, arguments) || this; + } + + var _proto18 = PreciseShadowcasting.prototype; + + _proto18.compute = function compute(x, y, R, callback) { + /* this place is always visible */ + callback(x, y, 0, 1); + /* standing in a dark place. FIXME is this a good idea? */ + + if (!this._lightPasses(x, y)) { + return; + } + /* list of all shadows */ + + + var SHADOWS = []; + var cx, cy, blocks, A1, A2, visibility; + /* analyze surrounding cells in concentric rings, starting from the center */ + + for (var r = 1; r <= R; r++) { + var neighbors = this._getCircle(x, y, r); + + var neighborCount = neighbors.length; + + for (var i = 0; i < neighborCount; i++) { + cx = neighbors[i][0]; + cy = neighbors[i][1]; + /* shift half-an-angle backwards to maintain consistency of 0-th cells */ + + A1 = [i ? 2 * i - 1 : 2 * neighborCount - 1, 2 * neighborCount]; + A2 = [2 * i + 1, 2 * neighborCount]; + blocks = !this._lightPasses(cx, cy); + visibility = this._checkVisibility(A1, A2, blocks, SHADOWS); + + if (visibility) { + callback(cx, cy, r, visibility); + } + + if (SHADOWS.length == 2 && SHADOWS[0][0] == 0 && SHADOWS[1][0] == SHADOWS[1][1]) { + return; + } + /* cutoff? */ + + } + /* for all cells in this ring */ + + } + /* for all rings */ + + }; + /** + * @param {int[2]} A1 arc start + * @param {int[2]} A2 arc end + * @param {bool} blocks Does current arc block visibility? + * @param {int[][]} SHADOWS list of active shadows + */ + + + _proto18._checkVisibility = function _checkVisibility(A1, A2, blocks, SHADOWS) { + if (A1[0] > A2[0]) { + /* split into two sub-arcs */ + var v1 = this._checkVisibility(A1, [A1[1], A1[1]], blocks, SHADOWS); + + var v2 = this._checkVisibility([0, 1], A2, blocks, SHADOWS); + + return (v1 + v2) / 2; + } + /* index1: first shadow >= A1 */ + + + var index1 = 0, + edge1 = false; + + while (index1 < SHADOWS.length) { + var old = SHADOWS[index1]; + var diff = old[0] * A1[1] - A1[0] * old[1]; + + if (diff >= 0) { + /* old >= A1 */ + if (diff == 0 && !(index1 % 2)) { + edge1 = true; + } + + break; + } + + index1++; + } + /* index2: last shadow <= A2 */ + + + var index2 = SHADOWS.length, + edge2 = false; + + while (index2--) { + var _old = SHADOWS[index2]; + + var _diff = A2[0] * _old[1] - _old[0] * A2[1]; + + if (_diff >= 0) { + /* old <= A2 */ + if (_diff == 0 && index2 % 2) { + edge2 = true; + } + + break; + } + } + + var visible = true; + + if (index1 == index2 && (edge1 || edge2)) { + /* subset of existing shadow, one of the edges match */ + visible = false; + } else if (edge1 && edge2 && index1 + 1 == index2 && index2 % 2) { + /* completely equivalent with existing shadow */ + visible = false; + } else if (index1 > index2 && index1 % 2) { + /* subset of existing shadow, not touching */ + visible = false; + } + + if (!visible) { + return 0; + } + /* fast case: not visible */ + + + var visibleLength; + /* compute the length of visible arc, adjust list of shadows (if blocking) */ + + var remove = index2 - index1 + 1; + + if (remove % 2) { + if (index1 % 2) { + /* first edge within existing shadow, second outside */ + var P = SHADOWS[index1]; + visibleLength = (A2[0] * P[1] - P[0] * A2[1]) / (P[1] * A2[1]); + + if (blocks) { + SHADOWS.splice(index1, remove, A2); + } + } else { + /* second edge within existing shadow, first outside */ + var _P = SHADOWS[index2]; + visibleLength = (_P[0] * A1[1] - A1[0] * _P[1]) / (A1[1] * _P[1]); + + if (blocks) { + SHADOWS.splice(index1, remove, A1); + } + } + } else { + if (index1 % 2) { + /* both edges within existing shadows */ + var P1 = SHADOWS[index1]; + var P2 = SHADOWS[index2]; + visibleLength = (P2[0] * P1[1] - P1[0] * P2[1]) / (P1[1] * P2[1]); + + if (blocks) { + SHADOWS.splice(index1, remove); + } + } else { + /* both edges outside existing shadows */ + if (blocks) { + SHADOWS.splice(index1, remove, A1, A2); + } + + return 1; + /* whole arc visible! */ + } + } + + var arcLength = (A2[0] * A1[1] - A1[0] * A2[1]) / (A1[1] * A2[1]); + return visibleLength / arcLength; + }; + + return PreciseShadowcasting; + }(FOV); + /** Octants used for translating recursive shadowcasting offsets */ + + + var OCTANTS = [[-1, 0, 0, 1], [0, -1, 1, 0], [0, -1, -1, 0], [-1, 0, 0, -1], [1, 0, 0, -1], [0, 1, -1, 0], [0, 1, 1, 0], [1, 0, 0, 1]]; + /** + * @class Recursive shadowcasting algorithm + * Currently only supports 4/8 topologies, not hexagonal. + * Based on Peter Harkins' implementation of Björn Bergström's algorithm described here: http://www.roguebasin.com/index.php?title=FOV_using_recursive_shadowcasting + * @augments ROT.FOV + */ + + var RecursiveShadowcasting = + /*#__PURE__*/ + function (_FOV3) { + _inheritsLoose(RecursiveShadowcasting, _FOV3); + + function RecursiveShadowcasting() { + return _FOV3.apply(this, arguments) || this; + } + + var _proto19 = RecursiveShadowcasting.prototype; + + /** + * Compute visibility for a 360-degree circle + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {function} callback + */ + _proto19.compute = function compute(x, y, R, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + + for (var i = 0; i < OCTANTS.length; i++) { + this._renderOctant(x, y, OCTANTS[i], R, callback); + } + }; + /** + * Compute visibility for a 180-degree arc + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {int} dir Direction to look in (expressed in a ROT.DIRS value); + * @param {function} callback + */ + + + _proto19.compute180 = function compute180(x, y, R, dir, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + var previousOctant = (dir - 1 + 8) % 8; //Need to retrieve the previous octant to render a full 180 degrees + + var nextPreviousOctant = (dir - 2 + 8) % 8; //Need to retrieve the previous two octants to render a full 180 degrees + + var nextOctant = (dir + 1 + 8) % 8; //Need to grab to next octant to render a full 180 degrees + + this._renderOctant(x, y, OCTANTS[nextPreviousOctant], R, callback); + + this._renderOctant(x, y, OCTANTS[previousOctant], R, callback); + + this._renderOctant(x, y, OCTANTS[dir], R, callback); + + this._renderOctant(x, y, OCTANTS[nextOctant], R, callback); + }; + + /** + * Compute visibility for a 90-degree arc + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {int} dir Direction to look in (expressed in a ROT.DIRS value); + * @param {function} callback + */ + _proto19.compute90 = function compute90(x, y, R, dir, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + var previousOctant = (dir - 1 + 8) % 8; //Need to retrieve the previous octant to render a full 90 degrees + + this._renderOctant(x, y, OCTANTS[dir], R, callback); + + this._renderOctant(x, y, OCTANTS[previousOctant], R, callback); + }; + /** + * Render one octant (45-degree arc) of the viewshed + * @param {int} x + * @param {int} y + * @param {int} octant Octant to be rendered + * @param {int} R Maximum visibility radius + * @param {function} callback + */ + + + _proto19._renderOctant = function _renderOctant(x, y, octant, R, callback) { + //Radius incremented by 1 to provide same coverage area as other shadowcasting radiuses + this._castVisibility(x, y, 1, 1.0, 0.0, R + 1, octant[0], octant[1], octant[2], octant[3], callback); + }; + /** + * Actually calculates the visibility + * @param {int} startX The starting X coordinate + * @param {int} startY The starting Y coordinate + * @param {int} row The row to render + * @param {float} visSlopeStart The slope to start at + * @param {float} visSlopeEnd The slope to end at + * @param {int} radius The radius to reach out to + * @param {int} xx + * @param {int} xy + * @param {int} yx + * @param {int} yy + * @param {function} callback The callback to use when we hit a block that is visible + */ + + + _proto19._castVisibility = function _castVisibility(startX, startY, row, visSlopeStart, visSlopeEnd, radius, xx, xy, yx, yy, callback) { + if (visSlopeStart < visSlopeEnd) { + return; + } + + for (var i = row; i <= radius; i++) { + var dx = -i - 1; + var dy = -i; + var blocked = false; + var newStart = 0; //'Row' could be column, names here assume octant 0 and would be flipped for half the octants + + while (dx <= 0) { + dx += 1; //Translate from relative coordinates to map coordinates + + var mapX = startX + dx * xx + dy * xy; + var mapY = startY + dx * yx + dy * yy; //Range of the row + + var slopeStart = (dx - 0.5) / (dy + 0.5); + var slopeEnd = (dx + 0.5) / (dy - 0.5); //Ignore if not yet at left edge of Octant + + if (slopeEnd > visSlopeStart) { + continue; + } //Done if past right edge + + + if (slopeStart < visSlopeEnd) { + break; + } //If it's in range, it's visible + + + if (dx * dx + dy * dy < radius * radius) { + callback(mapX, mapY, i, 1); + } + + if (!blocked) { + //If tile is a blocking tile, cast around it + if (!this._lightPasses(mapX, mapY) && i < radius) { + blocked = true; + + this._castVisibility(startX, startY, i + 1, visSlopeStart, slopeStart, radius, xx, xy, yx, yy, callback); + + newStart = slopeEnd; + } + } else { + //Keep narrowing if scanning across a block + if (!this._lightPasses(mapX, mapY)) { + newStart = slopeEnd; + continue; + } //Block has ended + + + blocked = false; + visSlopeStart = newStart; + } + } + + if (blocked) { + break; + } + } + }; + + return RecursiveShadowcasting; + }(FOV); + + var index$1 = { + DiscreteShadowcasting: DiscreteShadowcasting, + PreciseShadowcasting: PreciseShadowcasting, + RecursiveShadowcasting: RecursiveShadowcasting + }; + + var Map = + /*#__PURE__*/ + function () { + /** + * @class Base map generator + * @param {int} [width=ROT.DEFAULT_WIDTH] + * @param {int} [height=ROT.DEFAULT_HEIGHT] + */ + function Map(width, height) { + if (width === void 0) { + width = DEFAULT_WIDTH; + } + + if (height === void 0) { + height = DEFAULT_HEIGHT; + } + + this._width = width; + this._height = height; + } + + var _proto20 = Map.prototype; + + _proto20._fillMap = function _fillMap(value) { + var map = []; + + for (var i = 0; i < this._width; i++) { + map.push([]); + + for (var j = 0; j < this._height; j++) { + map[i].push(value); + } + } + + return map; + }; + + return Map; + }(); + /** + * @class Simple empty rectangular room + * @augments ROT.Map + */ + + + var Arena = + /*#__PURE__*/ + function (_Map) { + _inheritsLoose(Arena, _Map); + + function Arena() { + return _Map.apply(this, arguments) || this; + } + + var _proto21 = Arena.prototype; + + _proto21.create = function create(callback) { + var w = this._width - 1; + var h = this._height - 1; + + for (var i = 0; i <= w; i++) { + for (var j = 0; j <= h; j++) { + var empty = i && j && i < w && j < h; + callback(i, j, empty ? 0 : 1); + } + } + + return this; + }; + + return Arena; + }(Map); + /** + * @class Dungeon map: has rooms and corridors + * @augments ROT.Map + */ + + + var Dungeon = + /*#__PURE__*/ + function (_Map2) { + _inheritsLoose(Dungeon, _Map2); + + function Dungeon(width, height) { + var _this10; + + _this10 = _Map2.call(this, width, height) || this; + _this10._rooms = []; + _this10._corridors = []; + return _this10; + } + /** + * Get all generated rooms + * @returns {ROT.Map.Feature.Room[]} + */ + + + var _proto22 = Dungeon.prototype; + + _proto22.getRooms = function getRooms() { + return this._rooms; + }; + /** + * Get all generated corridors + * @returns {ROT.Map.Feature.Corridor[]} + */ + + + _proto22.getCorridors = function getCorridors() { + return this._corridors; + }; + + return Dungeon; + }(Map); + /** + * @class Dungeon feature; has own .create() method + */ + + + var Feature = function Feature() {}; + /** + * @class Room + * @augments ROT.Map.Feature + * @param {int} x1 + * @param {int} y1 + * @param {int} x2 + * @param {int} y2 + * @param {int} [doorX] + * @param {int} [doorY] + */ + + + var Room = + /*#__PURE__*/ + function (_Feature) { + _inheritsLoose(Room, _Feature); + + function Room(x1, y1, x2, y2, doorX, doorY) { + var _this11; + + _this11 = _Feature.call(this) || this; + _this11._x1 = x1; + _this11._y1 = y1; + _this11._x2 = x2; + _this11._y2 = y2; + _this11._doors = {}; + + if (doorX !== undefined && doorY !== undefined) { + _this11.addDoor(doorX, doorY); + } + + return _this11; + } + + /** + * Room of random size, with a given doors and direction + */ + Room.createRandomAt = function createRandomAt(x, y, dx, dy, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + + if (dx == 1) { + /* to the right */ + var y2 = y - Math.floor(RNG$1.getUniform() * height); + return new this(x + 1, y2, x + width, y2 + height - 1, x, y); + } + + if (dx == -1) { + /* to the left */ + var _y = y - Math.floor(RNG$1.getUniform() * height); + + return new this(x - width, _y, x - 1, _y + height - 1, x, y); + } + + if (dy == 1) { + /* to the bottom */ + var x2 = x - Math.floor(RNG$1.getUniform() * width); + return new this(x2, y + 1, x2 + width - 1, y + height, x, y); + } + + if (dy == -1) { + /* to the top */ + var _x = x - Math.floor(RNG$1.getUniform() * width); + + return new this(_x, y - height, _x + width - 1, y - 1, x, y); + } + + throw new Error("dx or dy must be 1 or -1"); + }; + /** + * Room of random size, positioned around center coords + */ + + + Room.createRandomCenter = function createRandomCenter(cx, cy, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + var x1 = cx - Math.floor(RNG$1.getUniform() * width); + var y1 = cy - Math.floor(RNG$1.getUniform() * height); + var x2 = x1 + width - 1; + var y2 = y1 + height - 1; + return new this(x1, y1, x2, y2); + }; + /** + * Room of random size within a given dimensions + */ + + + Room.createRandom = function createRandom(availWidth, availHeight, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + var left = availWidth - width - 1; + var top = availHeight - height - 1; + var x1 = 1 + Math.floor(RNG$1.getUniform() * left); + var y1 = 1 + Math.floor(RNG$1.getUniform() * top); + var x2 = x1 + width - 1; + var y2 = y1 + height - 1; + return new this(x1, y1, x2, y2); + }; + + var _proto23 = Room.prototype; + + _proto23.addDoor = function addDoor(x, y) { + this._doors[x + "," + y] = 1; + return this; + }; + /** + * @param {function} + */ + + + _proto23.getDoors = function getDoors(cb) { + for (var key in this._doors) { + var parts = key.split(","); + cb(parseInt(parts[0]), parseInt(parts[1])); + } + + return this; + }; + + _proto23.clearDoors = function clearDoors() { + this._doors = {}; + return this; + }; + + _proto23.addDoors = function addDoors(isWallCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x != left && x != right && y != top && y != bottom) { + continue; + } + + if (isWallCallback(x, y)) { + continue; + } + + this.addDoor(x, y); + } + } + + return this; + }; + + _proto23.debug = function debug() { + console.log("room", this._x1, this._y1, this._x2, this._y2); + }; + + _proto23.isValid = function isValid(isWallCallback, canBeDugCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x == left || x == right || y == top || y == bottom) { + if (!isWallCallback(x, y)) { + return false; + } + } else { + if (!canBeDugCallback(x, y)) { + return false; + } + } + } + } + + return true; + }; + /** + * @param {function} digCallback Dig callback with a signature (x, y, value). Values: 0 = empty, 1 = wall, 2 = door. Multiple doors are allowed. + */ + + + _proto23.create = function create(digCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + var value = 0; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x + "," + y in this._doors) { + value = 2; + } else if (x == left || x == right || y == top || y == bottom) { + value = 1; + } else { + value = 0; + } + + digCallback(x, y, value); + } + } + }; + + _proto23.getCenter = function getCenter() { + return [Math.round((this._x1 + this._x2) / 2), Math.round((this._y1 + this._y2) / 2)]; + }; + + _proto23.getLeft = function getLeft() { + return this._x1; + }; + + _proto23.getRight = function getRight() { + return this._x2; + }; + + _proto23.getTop = function getTop() { + return this._y1; + }; + + _proto23.getBottom = function getBottom() { + return this._y2; + }; + + return Room; + }(Feature); + /** + * @class Corridor + * @augments ROT.Map.Feature + * @param {int} startX + * @param {int} startY + * @param {int} endX + * @param {int} endY + */ + + + var Corridor = + /*#__PURE__*/ + function (_Feature2) { + _inheritsLoose(Corridor, _Feature2); + + function Corridor(startX, startY, endX, endY) { + var _this12; + + _this12 = _Feature2.call(this) || this; + _this12._startX = startX; + _this12._startY = startY; + _this12._endX = endX; + _this12._endY = endY; + _this12._endsWithAWall = true; + return _this12; + } + + Corridor.createRandomAt = function createRandomAt(x, y, dx, dy, options) { + var min = options.corridorLength[0]; + var max = options.corridorLength[1]; + var length = RNG$1.getUniformInt(min, max); + return new this(x, y, x + dx * length, y + dy * length); + }; + + var _proto24 = Corridor.prototype; + + _proto24.debug = function debug() { + console.log("corridor", this._startX, this._startY, this._endX, this._endY); + }; + + _proto24.isValid = function isValid(isWallCallback, canBeDugCallback) { + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + var length = 1 + Math.max(Math.abs(dx), Math.abs(dy)); + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + var nx = dy; + var ny = -dx; + var ok = true; + + for (var i = 0; i < length; i++) { + var x = sx + i * dx; + var y = sy + i * dy; + + if (!canBeDugCallback(x, y)) { + ok = false; + } + + if (!isWallCallback(x + nx, y + ny)) { + ok = false; + } + + if (!isWallCallback(x - nx, y - ny)) { + ok = false; + } + + if (!ok) { + length = i; + this._endX = x - dx; + this._endY = y - dy; + break; + } + } + /** + * If the length degenerated, this corridor might be invalid + */ + + /* not supported */ + + + if (length == 0) { + return false; + } + /* length 1 allowed only if the next space is empty */ + + + if (length == 1 && isWallCallback(this._endX + dx, this._endY + dy)) { + return false; + } + /** + * We do not want the corridor to crash into a corner of a room; + * if any of the ending corners is empty, the N+1th cell of this corridor must be empty too. + * + * Situation: + * #######1 + * .......? + * #######2 + * + * The corridor was dug from left to right. + * 1, 2 - problematic corners, ? = N+1th cell (not dug) + */ + + + var firstCornerBad = !isWallCallback(this._endX + dx + nx, this._endY + dy + ny); + var secondCornerBad = !isWallCallback(this._endX + dx - nx, this._endY + dy - ny); + this._endsWithAWall = isWallCallback(this._endX + dx, this._endY + dy); + + if ((firstCornerBad || secondCornerBad) && this._endsWithAWall) { + return false; + } + + return true; + }; + /** + * @param {function} digCallback Dig callback with a signature (x, y, value). Values: 0 = empty. + */ + + + _proto24.create = function create(digCallback) { + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + var length = 1 + Math.max(Math.abs(dx), Math.abs(dy)); + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + for (var i = 0; i < length; i++) { + var x = sx + i * dx; + var y = sy + i * dy; + digCallback(x, y, 0); + } + + return true; + }; + + _proto24.createPriorityWalls = function createPriorityWalls(priorityWallCallback) { + if (!this._endsWithAWall) { + return; + } + + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + var nx = dy; + var ny = -dx; + priorityWallCallback(this._endX + dx, this._endY + dy); + priorityWallCallback(this._endX + nx, this._endY + ny); + priorityWallCallback(this._endX - nx, this._endY - ny); + }; + + return Corridor; + }(Feature); + /** + * @class Dungeon generator which tries to fill the space evenly. Generates independent rooms and tries to connect them. + * @augments ROT.Map.Dungeon + */ + + + var Uniform = + /*#__PURE__*/ + function (_Dungeon) { + _inheritsLoose(Uniform, _Dungeon); + + function Uniform(width, height, options) { + var _this13; + + _this13 = _Dungeon.call(this, width, height) || this; + _this13._options = { + roomWidth: [3, 9], + roomHeight: [3, 5], + roomDugPercentage: 0.1, + timeLimit: 1000 + /* we stop after this much time has passed (msec) */ + + }; + Object.assign(_this13._options, options); + _this13._map = []; + _this13._dug = 0; + _this13._roomAttempts = 20; + /* new room is created N-times until is considered as impossible to generate */ + + _this13._corridorAttempts = 20; + /* corridors are tried N-times until the level is considered as impossible to connect */ + + _this13._connected = []; + /* list of already connected rooms */ + + _this13._unconnected = []; + /* list of remaining unconnected rooms */ + + _this13._digCallback = _this13._digCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + _this13._canBeDugCallback = _this13._canBeDugCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + _this13._isWallCallback = _this13._isWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + return _this13; + } + /** + * Create a map. If the time limit has been hit, returns null. + * @see ROT.Map#create + */ + + + var _proto25 = Uniform.prototype; + + _proto25.create = function create(callback) { + var t1 = Date.now(); + + while (1) { + var t2 = Date.now(); + + if (t2 - t1 > this._options.timeLimit) { + return null; + } + /* time limit! */ + + + this._map = this._fillMap(1); + this._dug = 0; + this._rooms = []; + this._unconnected = []; + + this._generateRooms(); + + if (this._rooms.length < 2) { + continue; + } + + if (this._generateCorridors()) { + break; + } + } + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this._map[i][j]); + } + } + } + + return this; + }; + /** + * Generates a suitable amount of rooms + */ + + + _proto25._generateRooms = function _generateRooms() { + var w = this._width - 2; + var h = this._height - 2; + var room; + + do { + room = this._generateRoom(); + + if (this._dug / (w * h) > this._options.roomDugPercentage) { + break; + } + /* achieved requested amount of free space */ + + } while (room); + /* either enough rooms, or not able to generate more of them :) */ + + }; + /** + * Try to generate one room + */ + + + _proto25._generateRoom = function _generateRoom() { + var count = 0; + + while (count < this._roomAttempts) { + count++; + var room = Room.createRandom(this._width, this._height, this._options); + + if (!room.isValid(this._isWallCallback, this._canBeDugCallback)) { + continue; + } + + room.create(this._digCallback); + + this._rooms.push(room); + + return room; + } + /* no room was generated in a given number of attempts */ + + + return null; + }; + /** + * Generates connectors beween rooms + * @returns {bool} success Was this attempt successfull? + */ + + + _proto25._generateCorridors = function _generateCorridors() { + var cnt = 0; + + while (cnt < this._corridorAttempts) { + cnt++; + this._corridors = []; + /* dig rooms into a clear map */ + + this._map = this._fillMap(1); + + for (var i = 0; i < this._rooms.length; i++) { + var room = this._rooms[i]; + room.clearDoors(); + room.create(this._digCallback); + } + + this._unconnected = RNG$1.shuffle(this._rooms.slice()); + this._connected = []; + + if (this._unconnected.length) { + this._connected.push(this._unconnected.pop()); + } + /* first one is always connected */ + + + while (1) { + /* 1. pick random connected room */ + var connected = RNG$1.getItem(this._connected); + + if (!connected) { + break; + } + /* 2. find closest unconnected */ + + + var room1 = this._closestRoom(this._unconnected, connected); + + if (!room1) { + break; + } + /* 3. connect it to closest connected */ + + + var room2 = this._closestRoom(this._connected, room1); + + if (!room2) { + break; + } + + var ok = this._connectRooms(room1, room2); + + if (!ok) { + break; + } + /* stop connecting, re-shuffle */ + + + if (!this._unconnected.length) { + return true; + } + /* done; no rooms remain */ + + } + } + + return false; + }; + + /** + * For a given room, find the closest one from the list + */ + _proto25._closestRoom = function _closestRoom(rooms, room) { + var dist = Infinity; + var center = room.getCenter(); + var result = null; + + for (var i = 0; i < rooms.length; i++) { + var r = rooms[i]; + var c = r.getCenter(); + var dx = c[0] - center[0]; + var dy = c[1] - center[1]; + var d = dx * dx + dy * dy; + + if (d < dist) { + dist = d; + result = r; + } + } + + return result; + }; + + _proto25._connectRooms = function _connectRooms(room1, room2) { + /* + room1.debug(); + room2.debug(); + */ + var center1 = room1.getCenter(); + var center2 = room2.getCenter(); + var diffX = center2[0] - center1[0]; + var diffY = center2[1] - center1[1]; + var start; + var end; + var dirIndex1, dirIndex2, min, max, index; + + if (Math.abs(diffX) < Math.abs(diffY)) { + /* first try connecting north-south walls */ + dirIndex1 = diffY > 0 ? 2 : 0; + dirIndex2 = (dirIndex1 + 2) % 4; + min = room2.getLeft(); + max = room2.getRight(); + index = 0; + } else { + /* first try connecting east-west walls */ + dirIndex1 = diffX > 0 ? 1 : 3; + dirIndex2 = (dirIndex1 + 2) % 4; + min = room2.getTop(); + max = room2.getBottom(); + index = 1; + } + + start = this._placeInWall(room1, dirIndex1); + /* corridor will start here */ + + if (!start) { + return false; + } + + if (start[index] >= min && start[index] <= max) { + /* possible to connect with straight line (I-like) */ + end = start.slice(); + var value = 0; + + switch (dirIndex2) { + case 0: + value = room2.getTop() - 1; + break; + + case 1: + value = room2.getRight() + 1; + break; + + case 2: + value = room2.getBottom() + 1; + break; + + case 3: + value = room2.getLeft() - 1; + break; + } + + end[(index + 1) % 2] = value; + + this._digLine([start, end]); + } else if (start[index] < min - 1 || start[index] > max + 1) { + /* need to switch target wall (L-like) */ + var diff = start[index] - center2[index]; + var rotation = 0; + + switch (dirIndex2) { + case 0: + case 1: + rotation = diff < 0 ? 3 : 1; + break; + + case 2: + case 3: + rotation = diff < 0 ? 1 : 3; + break; + } + + dirIndex2 = (dirIndex2 + rotation) % 4; + end = this._placeInWall(room2, dirIndex2); + + if (!end) { + return false; + } + + var mid = [0, 0]; + mid[index] = start[index]; + var index2 = (index + 1) % 2; + mid[index2] = end[index2]; + + this._digLine([start, mid, end]); + } else { + /* use current wall pair, but adjust the line in the middle (S-like) */ + var _index4 = (index + 1) % 2; + + end = this._placeInWall(room2, dirIndex2); + + if (!end) { + return false; + } + + var _mid = Math.round((end[_index4] + start[_index4]) / 2); + + var mid1 = [0, 0]; + var mid2 = [0, 0]; + mid1[index] = start[index]; + mid1[_index4] = _mid; + mid2[index] = end[index]; + mid2[_index4] = _mid; + + this._digLine([start, mid1, mid2, end]); + } + + room1.addDoor(start[0], start[1]); + room2.addDoor(end[0], end[1]); + index = this._unconnected.indexOf(room1); + + if (index != -1) { + this._unconnected.splice(index, 1); + + this._connected.push(room1); + } + + index = this._unconnected.indexOf(room2); + + if (index != -1) { + this._unconnected.splice(index, 1); + + this._connected.push(room2); + } + + return true; + }; + + _proto25._placeInWall = function _placeInWall(room, dirIndex) { + var start = [0, 0]; + var dir = [0, 0]; + var length = 0; + + switch (dirIndex) { + case 0: + dir = [1, 0]; + start = [room.getLeft(), room.getTop() - 1]; + length = room.getRight() - room.getLeft() + 1; + break; + + case 1: + dir = [0, 1]; + start = [room.getRight() + 1, room.getTop()]; + length = room.getBottom() - room.getTop() + 1; + break; + + case 2: + dir = [1, 0]; + start = [room.getLeft(), room.getBottom() + 1]; + length = room.getRight() - room.getLeft() + 1; + break; + + case 3: + dir = [0, 1]; + start = [room.getLeft() - 1, room.getTop()]; + length = room.getBottom() - room.getTop() + 1; + break; + } + + var avail = []; + var lastBadIndex = -2; + + for (var i = 0; i < length; i++) { + var x = start[0] + i * dir[0]; + var y = start[1] + i * dir[1]; + avail.push(null); + var isWall = this._map[x][y] == 1; + + if (isWall) { + if (lastBadIndex != i - 1) { + avail[i] = [x, y]; + } + } else { + lastBadIndex = i; + + if (i) { + avail[i - 1] = null; + } + } + } + + for (var _i3 = avail.length - 1; _i3 >= 0; _i3--) { + if (!avail[_i3]) { + avail.splice(_i3, 1); + } + } + + return avail.length ? RNG$1.getItem(avail) : null; + }; + /** + * Dig a polyline. + */ + + + _proto25._digLine = function _digLine(points) { + for (var i = 1; i < points.length; i++) { + var start = points[i - 1]; + var end = points[i]; + var corridor = new Corridor(start[0], start[1], end[0], end[1]); + corridor.create(this._digCallback); + + this._corridors.push(corridor); + } + }; + + _proto25._digCallback = function _digCallback(x, y, value) { + this._map[x][y] = value; + + if (value == 0) { + this._dug++; + } + }; + + _proto25._isWallCallback = function _isWallCallback(x, y) { + if (x < 0 || y < 0 || x >= this._width || y >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto25._canBeDugCallback = function _canBeDugCallback(x, y) { + if (x < 1 || y < 1 || x + 1 >= this._width || y + 1 >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + return Uniform; + }(Dungeon); + /** + * @class Cellular automaton map generator + * @augments ROT.Map + * @param {int} [width=ROT.DEFAULT_WIDTH] + * @param {int} [height=ROT.DEFAULT_HEIGHT] + * @param {object} [options] Options + * @param {int[]} [options.born] List of neighbor counts for a new cell to be born in empty space + * @param {int[]} [options.survive] List of neighbor counts for an existing cell to survive + * @param {int} [options.topology] Topology 4 or 6 or 8 + */ + + + var Cellular = + /*#__PURE__*/ + function (_Map3) { + _inheritsLoose(Cellular, _Map3); + + function Cellular(width, height, options) { + var _this14; + + if (options === void 0) { + options = {}; + } + + _this14 = _Map3.call(this, width, height) || this; + _this14._options = { + born: [5, 6, 7, 8], + survive: [4, 5, 6, 7, 8], + topology: 8 + }; + + _this14.setOptions(options); + + _this14._dirs = DIRS[_this14._options.topology]; + _this14._map = _this14._fillMap(0); + return _this14; + } + /** + * Fill the map with random values + * @param {float} probability Probability for a cell to become alive; 0 = all empty, 1 = all full + */ + + + var _proto26 = Cellular.prototype; + + _proto26.randomize = function randomize(probability) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + this._map[i][j] = RNG$1.getUniform() < probability ? 1 : 0; + } + } + + return this; + }; + /** + * Change options. + * @see ROT.Map.Cellular + */ + + + _proto26.setOptions = function setOptions(options) { + Object.assign(this._options, options); + }; + + _proto26.set = function set(x, y, value) { + this._map[x][y] = value; + }; + + _proto26.create = function create(callback) { + var newMap = this._fillMap(0); + + var born = this._options.born; + var survive = this._options.survive; + + for (var j = 0; j < this._height; j++) { + var widthStep = 1; + var widthStart = 0; + + if (this._options.topology == 6) { + widthStep = 2; + widthStart = j % 2; + } + + for (var i = widthStart; i < this._width; i += widthStep) { + var cur = this._map[i][j]; + + var ncount = this._getNeighbors(i, j); + + if (cur && survive.indexOf(ncount) != -1) { + /* survive */ + newMap[i][j] = 1; + } else if (!cur && born.indexOf(ncount) != -1) { + /* born */ + newMap[i][j] = 1; + } + } + } + + this._map = newMap; + callback && this._serviceCallback(callback); + }; + + _proto26._serviceCallback = function _serviceCallback(callback) { + for (var j = 0; j < this._height; j++) { + var widthStep = 1; + var widthStart = 0; + + if (this._options.topology == 6) { + widthStep = 2; + widthStart = j % 2; + } + + for (var i = widthStart; i < this._width; i += widthStep) { + callback(i, j, this._map[i][j]); + } + } + }; + /** + * Get neighbor count at [i,j] in this._map + */ + + + _proto26._getNeighbors = function _getNeighbors(cx, cy) { + var result = 0; + + for (var i = 0; i < this._dirs.length; i++) { + var dir = this._dirs[i]; + var x = cx + dir[0]; + var y = cy + dir[1]; + + if (x < 0 || x >= this._width || y < 0 || y >= this._height) { + continue; + } + + result += this._map[x][y] == 1 ? 1 : 0; + } + + return result; + }; + /** + * Make sure every non-wall space is accessible. + * @param {function} callback to call to display map when do + * @param {int} value to consider empty space - defaults to 0 + * @param {function} callback to call when a new connection is made + */ + + + _proto26.connect = function connect(callback, value, connectionCallback) { + if (!value) value = 0; + var allFreeSpace = []; + var notConnected = {}; // find all free space + + var widthStep = 1; + var widthStarts = [0, 0]; + + if (this._options.topology == 6) { + widthStep = 2; + widthStarts = [0, 1]; + } + + for (var y = 0; y < this._height; y++) { + for (var x = widthStarts[y % 2]; x < this._width; x += widthStep) { + if (this._freeSpace(x, y, value)) { + var p = [x, y]; + notConnected[this._pointKey(p)] = p; + allFreeSpace.push([x, y]); + } + } + } + + var start = allFreeSpace[RNG$1.getUniformInt(0, allFreeSpace.length - 1)]; + + var key = this._pointKey(start); + + var connected = {}; + connected[key] = start; + delete notConnected[key]; // find what's connected to the starting point + + this._findConnected(connected, notConnected, [start], false, value); + + while (Object.keys(notConnected).length > 0) { + // find two points from notConnected to connected + var _p = this._getFromTo(connected, notConnected); + + var from = _p[0]; // notConnected + + var to = _p[1]; // connected + // find everything connected to the starting point + + var local = {}; + local[this._pointKey(from)] = from; + + this._findConnected(local, notConnected, [from], true, value); // connect to a connected cell + + + var tunnelFn = this._options.topology == 6 ? this._tunnelToConnected6 : this._tunnelToConnected; + tunnelFn.call(this, to, from, connected, notConnected, value, connectionCallback); // now all of local is connected + + for (var k in local) { + var pp = local[k]; + this._map[pp[0]][pp[1]] = value; + connected[k] = pp; + delete notConnected[k]; + } + } + + callback && this._serviceCallback(callback); + }; + /** + * Find random points to connect. Search for the closest point in the larger space. + * This is to minimize the length of the passage while maintaining good performance. + */ + + + _proto26._getFromTo = function _getFromTo(connected, notConnected) { + var from = [0, 0], + to = [0, 0], + d; + var connectedKeys = Object.keys(connected); + var notConnectedKeys = Object.keys(notConnected); + + for (var i = 0; i < 5; i++) { + if (connectedKeys.length < notConnectedKeys.length) { + var keys = connectedKeys; + to = connected[keys[RNG$1.getUniformInt(0, keys.length - 1)]]; + from = this._getClosest(to, notConnected); + } else { + var _keys = notConnectedKeys; + from = notConnected[_keys[RNG$1.getUniformInt(0, _keys.length - 1)]]; + to = this._getClosest(from, connected); + } + + d = (from[0] - to[0]) * (from[0] - to[0]) + (from[1] - to[1]) * (from[1] - to[1]); + + if (d < 64) { + break; + } + } // console.log(">>> connected=" + to + " notConnected=" + from + " dist=" + d); + + + return [from, to]; + }; + + _proto26._getClosest = function _getClosest(point, space) { + var minPoint = null; + var minDist = null; + + for (var k in space) { + var p = space[k]; + var d = (p[0] - point[0]) * (p[0] - point[0]) + (p[1] - point[1]) * (p[1] - point[1]); + + if (minDist == null || d < minDist) { + minDist = d; + minPoint = p; + } + } + + return minPoint; + }; + + _proto26._findConnected = function _findConnected(connected, notConnected, stack, keepNotConnected, value) { + while (stack.length > 0) { + var p = stack.splice(0, 1)[0]; + var tests = void 0; + + if (this._options.topology == 6) { + tests = [[p[0] + 2, p[1]], [p[0] + 1, p[1] - 1], [p[0] - 1, p[1] - 1], [p[0] - 2, p[1]], [p[0] - 1, p[1] + 1], [p[0] + 1, p[1] + 1]]; + } else { + tests = [[p[0] + 1, p[1]], [p[0] - 1, p[1]], [p[0], p[1] + 1], [p[0], p[1] - 1]]; + } + + for (var i = 0; i < tests.length; i++) { + var key = this._pointKey(tests[i]); + + if (connected[key] == null && this._freeSpace(tests[i][0], tests[i][1], value)) { + connected[key] = tests[i]; + + if (!keepNotConnected) { + delete notConnected[key]; + } + + stack.push(tests[i]); + } + } + } + }; + + _proto26._tunnelToConnected = function _tunnelToConnected(to, from, connected, notConnected, value, connectionCallback) { + var a, b; + + if (from[0] < to[0]) { + a = from; + b = to; + } else { + a = to; + b = from; + } + + for (var xx = a[0]; xx <= b[0]; xx++) { + this._map[xx][a[1]] = value; + var p = [xx, a[1]]; + + var pkey = this._pointKey(p); + + connected[pkey] = p; + delete notConnected[pkey]; + } + + if (connectionCallback && a[0] < b[0]) { + connectionCallback(a, [b[0], a[1]]); + } // x is now fixed + + + var x = b[0]; + + if (from[1] < to[1]) { + a = from; + b = to; + } else { + a = to; + b = from; + } + + for (var yy = a[1]; yy < b[1]; yy++) { + this._map[x][yy] = value; + var _p2 = [x, yy]; + + var _pkey = this._pointKey(_p2); + + connected[_pkey] = _p2; + delete notConnected[_pkey]; + } + + if (connectionCallback && a[1] < b[1]) { + connectionCallback([b[0], a[1]], [b[0], b[1]]); + } + }; + + _proto26._tunnelToConnected6 = function _tunnelToConnected6(to, from, connected, notConnected, value, connectionCallback) { + var a, b; + + if (from[0] < to[0]) { + a = from; + b = to; + } else { + a = to; + b = from; + } // tunnel diagonally until horizontally level + + + var xx = a[0]; + var yy = a[1]; + + while (!(xx == b[0] && yy == b[1])) { + var stepWidth = 2; + + if (yy < b[1]) { + yy++; + stepWidth = 1; + } else if (yy > b[1]) { + yy--; + stepWidth = 1; + } + + if (xx < b[0]) { + xx += stepWidth; + } else if (xx > b[0]) { + xx -= stepWidth; + } else if (b[1] % 2) { + // Won't step outside map if destination on is map's right edge + xx -= stepWidth; + } else { + // ditto for left edge + xx += stepWidth; + } + + this._map[xx][yy] = value; + var p = [xx, yy]; + + var pkey = this._pointKey(p); + + connected[pkey] = p; + delete notConnected[pkey]; + } + + if (connectionCallback) { + connectionCallback(from, to); + } + }; + + _proto26._freeSpace = function _freeSpace(x, y, value) { + return x >= 0 && x < this._width && y >= 0 && y < this._height && this._map[x][y] == value; + }; + + _proto26._pointKey = function _pointKey(p) { + return p[0] + "." + p[1]; + }; + + return Cellular; + }(Map); + + var FEATURES = { + "room": Room, + "corridor": Corridor + }; + /** + * Random dungeon generator using human-like digging patterns. + * Heavily based on Mike Anderson's ideas from the "Tyrant" algo, mentioned at + * http://www.roguebasin.roguelikedevelopment.org/index.php?title=Dungeon-Building_Algorithm. + */ + + var Digger = + /*#__PURE__*/ + function (_Dungeon2) { + _inheritsLoose(Digger, _Dungeon2); + + function Digger(width, height, options) { + var _this15; + + if (options === void 0) { + options = {}; + } + + _this15 = _Dungeon2.call(this, width, height) || this; + _this15._options = Object.assign({ + roomWidth: [3, 9], + roomHeight: [3, 5], + corridorLength: [3, 10], + dugPercentage: 0.2, + timeLimit: 1000 + /* we stop after this much time has passed (msec) */ + + }, options); + _this15._features = { + "room": 4, + "corridor": 4 + }; + _this15._map = []; + _this15._featureAttempts = 20; + /* how many times do we try to create a feature on a suitable wall */ + + _this15._walls = {}; + /* these are available for digging */ + + _this15._dug = 0; + _this15._digCallback = _this15._digCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._canBeDugCallback = _this15._canBeDugCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._isWallCallback = _this15._isWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._priorityWallCallback = _this15._priorityWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + return _this15; + } + + var _proto27 = Digger.prototype; + + _proto27.create = function create(callback) { + this._rooms = []; + this._corridors = []; + this._map = this._fillMap(1); + this._walls = {}; + this._dug = 0; + var area = (this._width - 2) * (this._height - 2); + + this._firstRoom(); + + var t1 = Date.now(); + var priorityWalls; + + do { + priorityWalls = 0; + var t2 = Date.now(); + + if (t2 - t1 > this._options.timeLimit) { + break; + } + /* find a good wall */ + + + var wall = this._findWall(); + + if (!wall) { + break; + } + /* no more walls */ + + + var parts = wall.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + + var dir = this._getDiggingDirection(x, y); + + if (!dir) { + continue; + } + /* this wall is not suitable */ + // console.log("wall", x, y); + + /* try adding a feature */ + + + var featureAttempts = 0; + + do { + featureAttempts++; + + if (this._tryFeature(x, y, dir[0], dir[1])) { + /* feature added */ + //if (this._rooms.length + this._corridors.length == 2) { this._rooms[0].addDoor(x, y); } /* first room oficially has doors */ + this._removeSurroundingWalls(x, y); + + this._removeSurroundingWalls(x - dir[0], y - dir[1]); + + break; + } + } while (featureAttempts < this._featureAttempts); + + for (var id in this._walls) { + if (this._walls[id] > 1) { + priorityWalls++; + } + } + } while (this._dug / area < this._options.dugPercentage || priorityWalls); + /* fixme number of priority walls */ + + + this._addDoors(); + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this._map[i][j]); + } + } + } + + this._walls = {}; + this._map = []; + return this; + }; + + _proto27._digCallback = function _digCallback(x, y, value) { + if (value == 0 || value == 2) { + /* empty */ + this._map[x][y] = 0; + this._dug++; + } else { + /* wall */ + this._walls[x + "," + y] = 1; + } + }; + + _proto27._isWallCallback = function _isWallCallback(x, y) { + if (x < 0 || y < 0 || x >= this._width || y >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto27._canBeDugCallback = function _canBeDugCallback(x, y) { + if (x < 1 || y < 1 || x + 1 >= this._width || y + 1 >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto27._priorityWallCallback = function _priorityWallCallback(x, y) { + this._walls[x + "," + y] = 2; + }; + + _proto27._firstRoom = function _firstRoom() { + var cx = Math.floor(this._width / 2); + var cy = Math.floor(this._height / 2); + var room = Room.createRandomCenter(cx, cy, this._options); + + this._rooms.push(room); + + room.create(this._digCallback); + }; + /** + * Get a suitable wall + */ + + + _proto27._findWall = function _findWall() { + var prio1 = []; + var prio2 = []; + + for (var _id2 in this._walls) { + var prio = this._walls[_id2]; + + if (prio == 2) { + prio2.push(_id2); + } else { + prio1.push(_id2); + } + } + + var arr = prio2.length ? prio2 : prio1; + + if (!arr.length) { + return null; + } + /* no walls :/ */ + + + var id = RNG$1.getItem(arr.sort()); // sort to make the order deterministic + + delete this._walls[id]; + return id; + }; + /** + * Tries adding a feature + * @returns {bool} was this a successful try? + */ + + + _proto27._tryFeature = function _tryFeature(x, y, dx, dy) { + var featureName = RNG$1.getWeightedValue(this._features); + var ctor = FEATURES[featureName]; + var feature = ctor.createRandomAt(x, y, dx, dy, this._options); + + if (!feature.isValid(this._isWallCallback, this._canBeDugCallback)) { + // console.log("not valid"); + // feature.debug(); + return false; + } + + feature.create(this._digCallback); // feature.debug(); + + if (feature instanceof Room) { + this._rooms.push(feature); + } + + if (feature instanceof Corridor) { + feature.createPriorityWalls(this._priorityWallCallback); + + this._corridors.push(feature); + } + + return true; + }; + + _proto27._removeSurroundingWalls = function _removeSurroundingWalls(cx, cy) { + var deltas = DIRS[4]; + + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + var x = cx + delta[0]; + var y = cy + delta[1]; + delete this._walls[x + "," + y]; + x = cx + 2 * delta[0]; + y = cy + 2 * delta[1]; + delete this._walls[x + "," + y]; + } + }; + /** + * Returns vector in "digging" direction, or false, if this does not exist (or is not unique) + */ + + + _proto27._getDiggingDirection = function _getDiggingDirection(cx, cy) { + if (cx <= 0 || cy <= 0 || cx >= this._width - 1 || cy >= this._height - 1) { + return null; + } + + var result = null; + var deltas = DIRS[4]; + + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + var x = cx + delta[0]; + var y = cy + delta[1]; + + if (!this._map[x][y]) { + /* there already is another empty neighbor! */ + if (result) { + return null; + } + + result = delta; + } + } + /* no empty neighbor */ + + + if (!result) { + return null; + } + + return [-result[0], -result[1]]; + }; + /** + * Find empty spaces surrounding rooms, and apply doors. + */ + + + _proto27._addDoors = function _addDoors() { + var data = this._map; + + function isWallCallback(x, y) { + return data[x][y] == 1; + } + + for (var i = 0; i < this._rooms.length; i++) { + var room = this._rooms[i]; + room.clearDoors(); + room.addDoors(isWallCallback); + } + }; + + return Digger; + }(Dungeon); + /** + * Join lists with "i" and "i+1" + */ + + + function addToList(i, L, R) { + R[L[i + 1]] = R[i]; + L[R[i]] = L[i + 1]; + R[i] = i + 1; + L[i + 1] = i; + } + /** + * Remove "i" from its list + */ + + + function removeFromList(i, L, R) { + R[L[i]] = R[i]; + L[R[i]] = L[i]; + R[i] = i; + L[i] = i; + } + /** + * Maze generator - Eller's algorithm + * See http://homepages.cwi.nl/~tromp/maze.html for explanation + */ + + + var EllerMaze = + /*#__PURE__*/ + function (_Map4) { + _inheritsLoose(EllerMaze, _Map4); + + function EllerMaze() { + return _Map4.apply(this, arguments) || this; + } + + var _proto28 = EllerMaze.prototype; + + _proto28.create = function create(callback) { + var map = this._fillMap(1); + + var w = Math.ceil((this._width - 2) / 2); + var rand = 9 / 24; + var L = []; + var R = []; + + for (var i = 0; i < w; i++) { + L.push(i); + R.push(i); + } + + L.push(w - 1); + /* fake stop-block at the right side */ + + var j; + + for (j = 1; j + 3 < this._height; j += 2) { + /* one row */ + for (var _i4 = 0; _i4 < w; _i4++) { + /* cell coords (will be always empty) */ + var x = 2 * _i4 + 1; + var y = j; + map[x][y] = 0; + /* right connection */ + + if (_i4 != L[_i4 + 1] && RNG$1.getUniform() > rand) { + addToList(_i4, L, R); + map[x + 1][y] = 0; + } + /* bottom connection */ + + + if (_i4 != L[_i4] && RNG$1.getUniform() > rand) { + /* remove connection */ + removeFromList(_i4, L, R); + } else { + /* create connection */ + map[x][y + 1] = 0; + } + } + } + /* last row */ + + + for (var _i5 = 0; _i5 < w; _i5++) { + /* cell coords (will be always empty) */ + var _x2 = 2 * _i5 + 1; + + var _y2 = j; + map[_x2][_y2] = 0; + /* right connection */ + + if (_i5 != L[_i5 + 1] && (_i5 == L[_i5] || RNG$1.getUniform() > rand)) { + /* dig right also if the cell is separated, so it gets connected to the rest of maze */ + addToList(_i5, L, R); + map[_x2 + 1][_y2] = 0; + } + + removeFromList(_i5, L, R); + } + + for (var _i6 = 0; _i6 < this._width; _i6++) { + for (var _j = 0; _j < this._height; _j++) { + callback(_i6, _j, map[_i6][_j]); + } + } + + return this; + }; + + return EllerMaze; + }(Map); + /** + * @class Recursively divided maze, http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method + * @augments ROT.Map + */ + + + var DividedMaze = + /*#__PURE__*/ + function (_Map5) { + _inheritsLoose(DividedMaze, _Map5); + + function DividedMaze() { + var _this16; + + _this16 = _Map5.apply(this, arguments) || this; + _this16._stack = []; + _this16._map = []; + return _this16; + } + + var _proto29 = DividedMaze.prototype; + + _proto29.create = function create(callback) { + var w = this._width; + var h = this._height; + this._map = []; + + for (var i = 0; i < w; i++) { + this._map.push([]); + + for (var j = 0; j < h; j++) { + var border = i == 0 || j == 0 || i + 1 == w || j + 1 == h; + + this._map[i].push(border ? 1 : 0); + } + } + + this._stack = [[1, 1, w - 2, h - 2]]; + + this._process(); + + for (var _i7 = 0; _i7 < w; _i7++) { + for (var _j2 = 0; _j2 < h; _j2++) { + callback(_i7, _j2, this._map[_i7][_j2]); + } + } + + this._map = []; + return this; + }; + + _proto29._process = function _process() { + while (this._stack.length) { + var room = this._stack.shift(); + /* [left, top, right, bottom] */ + + + this._partitionRoom(room); + } + }; + + _proto29._partitionRoom = function _partitionRoom(room) { + var availX = []; + var availY = []; + + for (var i = room[0] + 1; i < room[2]; i++) { + var top = this._map[i][room[1] - 1]; + var bottom = this._map[i][room[3] + 1]; + + if (top && bottom && !(i % 2)) { + availX.push(i); + } + } + + for (var j = room[1] + 1; j < room[3]; j++) { + var left = this._map[room[0] - 1][j]; + var right = this._map[room[2] + 1][j]; + + if (left && right && !(j % 2)) { + availY.push(j); + } + } + + if (!availX.length || !availY.length) { + return; + } + + var x = RNG$1.getItem(availX); + var y = RNG$1.getItem(availY); + this._map[x][y] = 1; + var walls = []; + var w = []; + walls.push(w); + /* left part */ + + for (var _i8 = room[0]; _i8 < x; _i8++) { + this._map[_i8][y] = 1; + w.push([_i8, y]); + } + + w = []; + walls.push(w); + /* right part */ + + for (var _i9 = x + 1; _i9 <= room[2]; _i9++) { + this._map[_i9][y] = 1; + w.push([_i9, y]); + } + + w = []; + walls.push(w); + /* top part */ + + for (var _j3 = room[1]; _j3 < y; _j3++) { + this._map[x][_j3] = 1; + w.push([x, _j3]); + } + + w = []; + walls.push(w); + /* bottom part */ + + for (var _j4 = y + 1; _j4 <= room[3]; _j4++) { + this._map[x][_j4] = 1; + w.push([x, _j4]); + } + + var solid = RNG$1.getItem(walls); + + for (var _i10 = 0; _i10 < walls.length; _i10++) { + var _w = walls[_i10]; + + if (_w == solid) { + continue; + } + + var hole = RNG$1.getItem(_w); + this._map[hole[0]][hole[1]] = 0; + } + + this._stack.push([room[0], room[1], x - 1, y - 1]); + /* left top */ + + + this._stack.push([x + 1, room[1], room[2], y - 1]); + /* right top */ + + + this._stack.push([room[0], y + 1, x - 1, room[3]]); + /* left bottom */ + + + this._stack.push([x + 1, y + 1, room[2], room[3]]); + /* right bottom */ + + }; + + return DividedMaze; + }(Map); + /** + * Icey's Maze generator + * See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation + */ + + + var IceyMaze = + /*#__PURE__*/ + function (_Map6) { + _inheritsLoose(IceyMaze, _Map6); + + function IceyMaze(width, height, regularity) { + var _this17; + + if (regularity === void 0) { + regularity = 0; + } + + _this17 = _Map6.call(this, width, height) || this; + _this17._regularity = regularity; + _this17._map = []; + return _this17; + } + + var _proto30 = IceyMaze.prototype; + + _proto30.create = function create(callback) { + var width = this._width; + var height = this._height; + + var map = this._fillMap(1); + + width -= width % 2 ? 1 : 2; + height -= height % 2 ? 1 : 2; + var cx = 0; + var cy = 0; + var nx = 0; + var ny = 0; + var done = 0; + var blocked = false; + var dirs = [[0, 0], [0, 0], [0, 0], [0, 0]]; + + do { + cx = 1 + 2 * Math.floor(RNG$1.getUniform() * (width - 1) / 2); + cy = 1 + 2 * Math.floor(RNG$1.getUniform() * (height - 1) / 2); + + if (!done) { + map[cx][cy] = 0; + } + + if (!map[cx][cy]) { + this._randomize(dirs); + + do { + if (Math.floor(RNG$1.getUniform() * (this._regularity + 1)) == 0) { + this._randomize(dirs); + } + + blocked = true; + + for (var i = 0; i < 4; i++) { + nx = cx + dirs[i][0] * 2; + ny = cy + dirs[i][1] * 2; + + if (this._isFree(map, nx, ny, width, height)) { + map[nx][ny] = 0; + map[cx + dirs[i][0]][cy + dirs[i][1]] = 0; + cx = nx; + cy = ny; + blocked = false; + done++; + break; + } + } + } while (!blocked); + } + } while (done + 1 < width * height / 4); + + for (var _i11 = 0; _i11 < this._width; _i11++) { + for (var j = 0; j < this._height; j++) { + callback(_i11, j, map[_i11][j]); + } + } + + this._map = []; + return this; + }; + + _proto30._randomize = function _randomize(dirs) { + for (var i = 0; i < 4; i++) { + dirs[i][0] = 0; + dirs[i][1] = 0; + } + + switch (Math.floor(RNG$1.getUniform() * 4)) { + case 0: + dirs[0][0] = -1; + dirs[1][0] = 1; + dirs[2][1] = -1; + dirs[3][1] = 1; + break; + + case 1: + dirs[3][0] = -1; + dirs[2][0] = 1; + dirs[1][1] = -1; + dirs[0][1] = 1; + break; + + case 2: + dirs[2][0] = -1; + dirs[3][0] = 1; + dirs[0][1] = -1; + dirs[1][1] = 1; + break; + + case 3: + dirs[1][0] = -1; + dirs[0][0] = 1; + dirs[3][1] = -1; + dirs[2][1] = 1; + break; + } + }; + + _proto30._isFree = function _isFree(map, x, y, width, height) { + if (x < 1 || y < 1 || x >= width || y >= height) { + return false; + } + + return map[x][y]; + }; + + return IceyMaze; + }(Map); + /** + * Dungeon generator which uses the "orginal" Rogue dungeon generation algorithm. See http://kuoi.com/~kamikaze/GameDesign/art07_rogue_dungeon.php + * @author hyakugei + */ + + + var Rogue = + /*#__PURE__*/ + function (_Map7) { + _inheritsLoose(Rogue, _Map7); + + function Rogue(width, height, options) { + var _this18; + + _this18 = _Map7.call(this, width, height) || this; + _this18.map = []; + _this18.rooms = []; + _this18.connectedCells = []; + options = Object.assign({ + cellWidth: 3, + cellHeight: 3 // ie. as an array with min-max values for each direction.... + + }, options); + /* + Set the room sizes according to the over-all width of the map, + and the cell sizes. + */ + + if (!options.hasOwnProperty("roomWidth")) { + options["roomWidth"] = _this18._calculateRoomSize(_this18._width, options["cellWidth"]); + } + + if (!options.hasOwnProperty("roomHeight")) { + options["roomHeight"] = _this18._calculateRoomSize(_this18._height, options["cellHeight"]); + } + + _this18._options = options; + return _this18; + } + + var _proto31 = Rogue.prototype; + + _proto31.create = function create(callback) { + this.map = this._fillMap(1); + this.rooms = []; + this.connectedCells = []; + + this._initRooms(); + + this._connectRooms(); + + this._connectUnconnectedRooms(); + + this._createRandomRoomConnections(); + + this._createRooms(); + + this._createCorridors(); + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this.map[i][j]); + } + } + } + + return this; + }; + + _proto31._calculateRoomSize = function _calculateRoomSize(size, cell) { + var max = Math.floor(size / cell * 0.8); + var min = Math.floor(size / cell * 0.25); + + if (min < 2) { + min = 2; + } + + if (max < 2) { + max = 2; + } + + return [min, max]; + }; + + _proto31._initRooms = function _initRooms() { + // create rooms array. This is the "grid" list from the algo. + for (var i = 0; i < this._options.cellWidth; i++) { + this.rooms.push([]); + + for (var j = 0; j < this._options.cellHeight; j++) { + this.rooms[i].push({ + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "connections": [], + "cellx": i, + "celly": j + }); + } + } + }; + + _proto31._connectRooms = function _connectRooms() { + //pick random starting grid + var cgx = RNG$1.getUniformInt(0, this._options.cellWidth - 1); + var cgy = RNG$1.getUniformInt(0, this._options.cellHeight - 1); + var idx; + var ncgx; + var ncgy; + var found = false; + var room; + var otherRoom; + var dirToCheck; // find unconnected neighbour cells + + do { + //dirToCheck = [0, 1, 2, 3, 4, 5, 6, 7]; + dirToCheck = [0, 2, 4, 6]; + dirToCheck = RNG$1.shuffle(dirToCheck); + + do { + found = false; + idx = dirToCheck.pop(); + ncgx = cgx + DIRS[8][idx][0]; + ncgy = cgy + DIRS[8][idx][1]; + + if (ncgx < 0 || ncgx >= this._options.cellWidth) { + continue; + } + + if (ncgy < 0 || ncgy >= this._options.cellHeight) { + continue; + } + + room = this.rooms[cgx][cgy]; + + if (room["connections"].length > 0) { + // as long as this room doesn't already coonect to me, we are ok with it. + if (room["connections"][0][0] == ncgx && room["connections"][0][1] == ncgy) { + break; + } + } + + otherRoom = this.rooms[ncgx][ncgy]; + + if (otherRoom["connections"].length == 0) { + otherRoom["connections"].push([cgx, cgy]); + this.connectedCells.push([ncgx, ncgy]); + cgx = ncgx; + cgy = ncgy; + found = true; + } + } while (dirToCheck.length > 0 && found == false); + } while (dirToCheck.length > 0); + }; + + _proto31._connectUnconnectedRooms = function _connectUnconnectedRooms() { + //While there are unconnected rooms, try to connect them to a random connected neighbor + //(if a room has no connected neighbors yet, just keep cycling, you'll fill out to it eventually). + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + this.connectedCells = RNG$1.shuffle(this.connectedCells); + var room; + var otherRoom; + var validRoom; + + for (var i = 0; i < this._options.cellWidth; i++) { + for (var j = 0; j < this._options.cellHeight; j++) { + room = this.rooms[i][j]; + + if (room["connections"].length == 0) { + var directions = [0, 2, 4, 6]; + directions = RNG$1.shuffle(directions); + validRoom = false; + + do { + var dirIdx = directions.pop(); + var newI = i + DIRS[8][dirIdx][0]; + var newJ = j + DIRS[8][dirIdx][1]; + + if (newI < 0 || newI >= cw || newJ < 0 || newJ >= ch) { + continue; + } + + otherRoom = this.rooms[newI][newJ]; + validRoom = true; + + if (otherRoom["connections"].length == 0) { + break; + } + + for (var k = 0; k < otherRoom["connections"].length; k++) { + if (otherRoom["connections"][k][0] == i && otherRoom["connections"][k][1] == j) { + validRoom = false; + break; + } + } + + if (validRoom) { + break; + } + } while (directions.length); + + if (validRoom) { + room["connections"].push([otherRoom["cellx"], otherRoom["celly"]]); + } else { + console.log("-- Unable to connect room."); + } + } + } + } + }; + + _proto31._createRandomRoomConnections = function _createRandomRoomConnections() {// Empty for now. + }; + + _proto31._createRooms = function _createRooms() { + var w = this._width; + var h = this._height; + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + var cwp = Math.floor(this._width / cw); + var chp = Math.floor(this._height / ch); + var roomw; + var roomh; + var roomWidth = this._options["roomWidth"]; + var roomHeight = this._options["roomHeight"]; + var sx; + var sy; + var otherRoom; + + for (var i = 0; i < cw; i++) { + for (var j = 0; j < ch; j++) { + sx = cwp * i; + sy = chp * j; + + if (sx == 0) { + sx = 1; + } + + if (sy == 0) { + sy = 1; + } + + roomw = RNG$1.getUniformInt(roomWidth[0], roomWidth[1]); + roomh = RNG$1.getUniformInt(roomHeight[0], roomHeight[1]); + + if (j > 0) { + otherRoom = this.rooms[i][j - 1]; + + while (sy - (otherRoom["y"] + otherRoom["height"]) < 3) { + sy++; + } + } + + if (i > 0) { + otherRoom = this.rooms[i - 1][j]; + + while (sx - (otherRoom["x"] + otherRoom["width"]) < 3) { + sx++; + } + } + + var sxOffset = Math.round(RNG$1.getUniformInt(0, cwp - roomw) / 2); + var syOffset = Math.round(RNG$1.getUniformInt(0, chp - roomh) / 2); + + while (sx + sxOffset + roomw >= w) { + if (sxOffset) { + sxOffset--; + } else { + roomw--; + } + } + + while (sy + syOffset + roomh >= h) { + if (syOffset) { + syOffset--; + } else { + roomh--; + } + } + + sx = sx + sxOffset; + sy = sy + syOffset; + this.rooms[i][j]["x"] = sx; + this.rooms[i][j]["y"] = sy; + this.rooms[i][j]["width"] = roomw; + this.rooms[i][j]["height"] = roomh; + + for (var ii = sx; ii < sx + roomw; ii++) { + for (var jj = sy; jj < sy + roomh; jj++) { + this.map[ii][jj] = 0; + } + } + } + } + }; + + _proto31._getWallPosition = function _getWallPosition(aRoom, aDirection) { + var rx; + var ry; + var door; + + if (aDirection == 1 || aDirection == 3) { + rx = RNG$1.getUniformInt(aRoom["x"] + 1, aRoom["x"] + aRoom["width"] - 2); + + if (aDirection == 1) { + ry = aRoom["y"] - 2; + door = ry + 1; + } else { + ry = aRoom["y"] + aRoom["height"] + 1; + door = ry - 1; + } + + this.map[rx][door] = 0; // i'm not setting a specific 'door' tile value right now, just empty space. + } else { + ry = RNG$1.getUniformInt(aRoom["y"] + 1, aRoom["y"] + aRoom["height"] - 2); + + if (aDirection == 2) { + rx = aRoom["x"] + aRoom["width"] + 1; + door = rx - 1; + } else { + rx = aRoom["x"] - 2; + door = rx + 1; + } + + this.map[door][ry] = 0; // i'm not setting a specific 'door' tile value right now, just empty space. + } + + return [rx, ry]; + }; + + _proto31._drawCorridor = function _drawCorridor(startPosition, endPosition) { + var xOffset = endPosition[0] - startPosition[0]; + var yOffset = endPosition[1] - startPosition[1]; + var xpos = startPosition[0]; + var ypos = startPosition[1]; + var tempDist; + var xDir; + var yDir; + var move; // 2 element array, element 0 is the direction, element 1 is the total value to move. + + var moves = []; // a list of 2 element arrays + + var xAbs = Math.abs(xOffset); + var yAbs = Math.abs(yOffset); + var percent = RNG$1.getUniform(); // used to split the move at different places along the long axis + + var firstHalf = percent; + var secondHalf = 1 - percent; + xDir = xOffset > 0 ? 2 : 6; + yDir = yOffset > 0 ? 4 : 0; + + if (xAbs < yAbs) { + // move firstHalf of the y offset + tempDist = Math.ceil(yAbs * firstHalf); + moves.push([yDir, tempDist]); // move all the x offset + + moves.push([xDir, xAbs]); // move sendHalf of the y offset + + tempDist = Math.floor(yAbs * secondHalf); + moves.push([yDir, tempDist]); + } else { + // move firstHalf of the x offset + tempDist = Math.ceil(xAbs * firstHalf); + moves.push([xDir, tempDist]); // move all the y offset + + moves.push([yDir, yAbs]); // move secondHalf of the x offset. + + tempDist = Math.floor(xAbs * secondHalf); + moves.push([xDir, tempDist]); + } + + this.map[xpos][ypos] = 0; + + while (moves.length > 0) { + move = moves.pop(); + + while (move[1] > 0) { + xpos += DIRS[8][move[0]][0]; + ypos += DIRS[8][move[0]][1]; + this.map[xpos][ypos] = 0; + move[1] = move[1] - 1; + } + } + }; + + _proto31._createCorridors = function _createCorridors() { + // Draw Corridors between connected rooms + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + var room; + var connection; + var otherRoom; + var wall; + var otherWall; + + for (var i = 0; i < cw; i++) { + for (var j = 0; j < ch; j++) { + room = this.rooms[i][j]; + + for (var k = 0; k < room["connections"].length; k++) { + connection = room["connections"][k]; + otherRoom = this.rooms[connection[0]][connection[1]]; // figure out what wall our corridor will start one. + // figure out what wall our corridor will end on. + + if (otherRoom["cellx"] > room["cellx"]) { + wall = 2; + otherWall = 4; + } else if (otherRoom["cellx"] < room["cellx"]) { + wall = 4; + otherWall = 2; + } else if (otherRoom["celly"] > room["celly"]) { + wall = 3; + otherWall = 1; + } else { + wall = 1; + otherWall = 3; + } + + this._drawCorridor(this._getWallPosition(room, wall), this._getWallPosition(otherRoom, otherWall)); + } + } + } + }; + + return Rogue; + }(Map); + + var index$2 = { + Arena: Arena, + Uniform: Uniform, + Cellular: Cellular, + Digger: Digger, + EllerMaze: EllerMaze, + DividedMaze: DividedMaze, + IceyMaze: IceyMaze, + Rogue: Rogue + }; + /** + * Base noise generator + */ + + var Noise = function Noise() {}; + + var F2 = 0.5 * (Math.sqrt(3) - 1); + var G2 = (3 - Math.sqrt(3)) / 6; + /** + * A simple 2d implementation of simplex noise by Ondrej Zara + * + * Based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java. + * Which is based on example code by Stefan Gustavson (stegu@itn.liu.se). + * With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). + * Better rank ordering method by Stefan Gustavson in 2012. + */ + + var Simplex = + /*#__PURE__*/ + function (_Noise) { + _inheritsLoose(Simplex, _Noise); + + /** + * @param gradients Random gradients + */ + function Simplex(gradients) { + var _this19; + + if (gradients === void 0) { + gradients = 256; + } + + _this19 = _Noise.call(this) || this; + _this19._gradients = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]]; + var permutations = []; + + for (var i = 0; i < gradients; i++) { + permutations.push(i); + } + + permutations = RNG$1.shuffle(permutations); + _this19._perms = []; + _this19._indexes = []; + + for (var _i12 = 0; _i12 < 2 * gradients; _i12++) { + _this19._perms.push(permutations[_i12 % gradients]); + + _this19._indexes.push(_this19._perms[_i12] % _this19._gradients.length); + } + + return _this19; + } + + var _proto32 = Simplex.prototype; + + _proto32.get = function get(xin, yin) { + var perms = this._perms; + var indexes = this._indexes; + var count = perms.length / 2; + var n0 = 0, + n1 = 0, + n2 = 0, + gi; // Noise contributions from the three corners + // Skew the input space to determine which simplex cell we're in + + var s = (xin + yin) * F2; // Hairy factor for 2D + + var i = Math.floor(xin + s); + var j = Math.floor(yin + s); + var t = (i + j) * G2; + var X0 = i - t; // Unskew the cell origin back to (x,y) space + + var Y0 = j - t; + var x0 = xin - X0; // The x,y distances from the cell origin + + var y0 = yin - Y0; // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + + var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + + if (x0 > y0) { + i1 = 1; + j1 = 0; + } else { + // lower triangle, XY order: (0,0)->(1,0)->(1,1) + i1 = 0; + j1 = 1; + } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + + + var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + + var y1 = y0 - j1 + G2; + var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords + + var y2 = y0 - 1 + 2 * G2; // Work out the hashed gradient indices of the three simplex corners + + var ii = mod(i, count); + var jj = mod(j, count); // Calculate the contribution from the three corners + + var t0 = 0.5 - x0 * x0 - y0 * y0; + + if (t0 >= 0) { + t0 *= t0; + gi = indexes[ii + perms[jj]]; + var grad = this._gradients[gi]; + n0 = t0 * t0 * (grad[0] * x0 + grad[1] * y0); + } + + var t1 = 0.5 - x1 * x1 - y1 * y1; + + if (t1 >= 0) { + t1 *= t1; + gi = indexes[ii + i1 + perms[jj + j1]]; + var _grad = this._gradients[gi]; + n1 = t1 * t1 * (_grad[0] * x1 + _grad[1] * y1); + } + + var t2 = 0.5 - x2 * x2 - y2 * y2; + + if (t2 >= 0) { + t2 *= t2; + gi = indexes[ii + 1 + perms[jj + 1]]; + var _grad2 = this._gradients[gi]; + n2 = t2 * t2 * (_grad2[0] * x2 + _grad2[1] * y2); + } // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + + + return 70 * (n0 + n1 + n2); + }; + + return Simplex; + }(Noise); + + var index$3 = { + Simplex: Simplex + }; + /** + * @class Abstract pathfinder + * @param {int} toX Target X coord + * @param {int} toY Target Y coord + * @param {function} passableCallback Callback to determine map passability + * @param {object} [options] + * @param {int} [options.topology=8] + */ + + var Path = + /*#__PURE__*/ + function () { + function Path(toX, toY, passableCallback, options) { + if (options === void 0) { + options = {}; + } + + this._toX = toX; + this._toY = toY; + this._passableCallback = passableCallback; + this._options = Object.assign({ + topology: 8 + }, options); + this._dirs = DIRS[this._options.topology]; + + if (this._options.topology == 8) { + /* reorder dirs for more aesthetic result (vertical/horizontal first) */ + this._dirs = [this._dirs[0], this._dirs[2], this._dirs[4], this._dirs[6], this._dirs[1], this._dirs[3], this._dirs[5], this._dirs[7]]; + } + } + + var _proto33 = Path.prototype; + + _proto33._getNeighbors = function _getNeighbors(cx, cy) { + var result = []; + + for (var i = 0; i < this._dirs.length; i++) { + var dir = this._dirs[i]; + var x = cx + dir[0]; + var y = cy + dir[1]; + + if (!this._passableCallback(x, y)) { + continue; + } + + result.push([x, y]); + } + + return result; + }; + + return Path; + }(); + /** + * @class Simplified Dijkstra's algorithm: all edges have a value of 1 + * @augments ROT.Path + * @see ROT.Path + */ + + + var Dijkstra = + /*#__PURE__*/ + function (_Path) { + _inheritsLoose(Dijkstra, _Path); + + function Dijkstra(toX, toY, passableCallback, options) { + var _this20; + + _this20 = _Path.call(this, toX, toY, passableCallback, options) || this; + _this20._computed = {}; + _this20._todo = []; + + _this20._add(toX, toY, null); + + return _this20; + } + /** + * Compute a path from a given point + * @see ROT.Path#compute + */ + + + var _proto34 = Dijkstra.prototype; + + _proto34.compute = function compute(fromX, fromY, callback) { + var key = fromX + "," + fromY; + + if (!(key in this._computed)) { + this._compute(fromX, fromY); + } + + if (!(key in this._computed)) { + return; + } + + var item = this._computed[key]; + + while (item) { + callback(item.x, item.y); + item = item.prev; + } + }; + /** + * Compute a non-cached value + */ + + + _proto34._compute = function _compute(fromX, fromY) { + while (this._todo.length) { + var item = this._todo.shift(); + + if (item.x == fromX && item.y == fromY) { + return; + } + + var neighbors = this._getNeighbors(item.x, item.y); + + for (var i = 0; i < neighbors.length; i++) { + var neighbor = neighbors[i]; + var x = neighbor[0]; + var y = neighbor[1]; + var id = x + "," + y; + + if (id in this._computed) { + continue; + } + /* already done */ + + + this._add(x, y, item); + } + } + }; + + _proto34._add = function _add(x, y, prev) { + var obj = { + x: x, + y: y, + prev: prev + }; + this._computed[x + "," + y] = obj; + + this._todo.push(obj); + }; + + return Dijkstra; + }(Path); + /** + * @class Simplified A* algorithm: all edges have a value of 1 + * @augments ROT.Path + * @see ROT.Path + */ + + + var AStar = + /*#__PURE__*/ + function (_Path2) { + _inheritsLoose(AStar, _Path2); + + function AStar(toX, toY, passableCallback, options) { + var _this21; + + if (options === void 0) { + options = {}; + } + + _this21 = _Path2.call(this, toX, toY, passableCallback, options) || this; + _this21._todo = []; + _this21._done = {}; + return _this21; + } + /** + * Compute a path from a given point + * @see ROT.Path#compute + */ + + + var _proto35 = AStar.prototype; + + _proto35.compute = function compute(fromX, fromY, callback) { + this._todo = []; + this._done = {}; + this._fromX = fromX; + this._fromY = fromY; + + this._add(this._toX, this._toY, null); + + while (this._todo.length) { + var _item = this._todo.shift(); + + var id = _item.x + "," + _item.y; + + if (id in this._done) { + continue; + } + + this._done[id] = _item; + + if (_item.x == fromX && _item.y == fromY) { + break; + } + + var neighbors = this._getNeighbors(_item.x, _item.y); + + for (var i = 0; i < neighbors.length; i++) { + var neighbor = neighbors[i]; + var x = neighbor[0]; + var y = neighbor[1]; + + var _id3 = x + "," + y; + + if (_id3 in this._done) { + continue; + } + + this._add(x, y, _item); + } + } + + var item = this._done[fromX + "," + fromY]; + + if (!item) { + return; + } + + while (item) { + callback(item.x, item.y); + item = item.prev; + } + }; + + _proto35._add = function _add(x, y, prev) { + var h = this._distance(x, y); + + var obj = { + x: x, + y: y, + prev: prev, + g: prev ? prev.g + 1 : 0, + h: h + }; + /* insert into priority queue */ + + var f = obj.g + obj.h; + + for (var i = 0; i < this._todo.length; i++) { + var item = this._todo[i]; + var itemF = item.g + item.h; + + if (f < itemF || f == itemF && h < item.h) { + this._todo.splice(i, 0, obj); + + return; + } + } + + this._todo.push(obj); + }; + + _proto35._distance = function _distance(x, y) { + switch (this._options.topology) { + case 4: + return Math.abs(x - this._fromX) + Math.abs(y - this._fromY); + break; + + case 6: + var dx = Math.abs(x - this._fromX); + var dy = Math.abs(y - this._fromY); + return dy + Math.max(0, (dx - dy) / 2); + break; + + case 8: + return Math.max(Math.abs(x - this._fromX), Math.abs(y - this._fromY)); + break; + } + }; + + return AStar; + }(Path); + + var index$4 = { + Dijkstra: Dijkstra, + AStar: AStar + }; + /** + * @class Asynchronous main loop + * @param {ROT.Scheduler} scheduler + */ + + var Engine = + /*#__PURE__*/ + function () { + function Engine(scheduler) { + this._scheduler = scheduler; + this._lock = 1; + } + /** + * Start the main loop. When this call returns, the loop is locked. + */ + + + var _proto36 = Engine.prototype; + + _proto36.start = function start() { + return this.unlock(); + }; + /** + * Interrupt the engine by an asynchronous action + */ + + + _proto36.lock = function lock() { + this._lock++; + return this; + }; + /** + * Resume execution (paused by a previous lock) + */ + + + _proto36.unlock = function unlock() { + if (!this._lock) { + throw new Error("Cannot unlock unlocked engine"); + } + + this._lock--; + + while (!this._lock) { + var actor = this._scheduler.next(); + + if (!actor) { + return this.lock(); + } + /* no actors */ + + + var result = actor.act(); + + if (result && result.then) { + /* actor returned a "thenable", looks like a Promise */ + this.lock(); + result.then(this.unlock.bind(this)); + } + } + + return this; + }; + + return Engine; + }(); + /** + * Lighting computation, based on a traditional FOV for multiple light sources and multiple passes. + */ + + + var Lighting = + /*#__PURE__*/ + function () { + function Lighting(reflectivityCallback, options) { + if (options === void 0) { + options = {}; + } + + this._reflectivityCallback = reflectivityCallback; + this._options = {}; + options = Object.assign({ + passes: 1, + emissionThreshold: 100, + range: 10 + }, options); + this._lights = {}; + this._reflectivityCache = {}; + this._fovCache = {}; + this.setOptions(options); + } + /** + * Adjust options at runtime + */ + + + var _proto37 = Lighting.prototype; + + _proto37.setOptions = function setOptions(options) { + Object.assign(this._options, options); + + if (options && options.range) { + this.reset(); + } + + return this; + }; + /** + * Set the used Field-Of-View algo + */ + + + _proto37.setFOV = function setFOV(fov) { + this._fov = fov; + this._fovCache = {}; + return this; + }; + /** + * Set (or remove) a light source + */ + + + _proto37.setLight = function setLight(x, y, color) { + var key = x + "," + y; + + if (color) { + this._lights[key] = typeof color == "string" ? fromString(color) : color; + } else { + delete this._lights[key]; + } + + return this; + }; + /** + * Remove all light sources + */ + + + _proto37.clearLights = function clearLights() { + this._lights = {}; + }; + /** + * Reset the pre-computed topology values. Call whenever the underlying map changes its light-passability. + */ + + + _proto37.reset = function reset() { + this._reflectivityCache = {}; + this._fovCache = {}; + return this; + }; + /** + * Compute the lighting + */ + + + _proto37.compute = function compute(lightingCallback) { + var doneCells = {}; + var emittingCells = {}; + var litCells = {}; + + for (var key in this._lights) { + /* prepare emitters for first pass */ + var light = this._lights[key]; + emittingCells[key] = [0, 0, 0]; + add_(emittingCells[key], light); + } + + for (var i = 0; i < this._options.passes; i++) { + /* main loop */ + this._emitLight(emittingCells, litCells, doneCells); + + if (i + 1 == this._options.passes) { + continue; + } + /* not for the last pass */ + + + emittingCells = this._computeEmitters(litCells, doneCells); + } + + for (var litKey in litCells) { + /* let the user know what and how is lit */ + var parts = litKey.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + lightingCallback(x, y, litCells[litKey]); + } + + return this; + }; + /** + * Compute one iteration from all emitting cells + * @param emittingCells These emit light + * @param litCells Add projected light to these + * @param doneCells These already emitted, forbid them from further calculations + */ + + + _proto37._emitLight = function _emitLight(emittingCells, litCells, doneCells) { + for (var key in emittingCells) { + var parts = key.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + + this._emitLightFromCell(x, y, emittingCells[key], litCells); + + doneCells[key] = 1; + } + + return this; + }; + /** + * Prepare a list of emitters for next pass + */ + + + _proto37._computeEmitters = function _computeEmitters(litCells, doneCells) { + var result = {}; + + for (var key in litCells) { + if (key in doneCells) { + continue; + } + /* already emitted */ + + + var _color = litCells[key]; + var reflectivity = void 0; + + if (key in this._reflectivityCache) { + reflectivity = this._reflectivityCache[key]; + } else { + var parts = key.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + reflectivity = this._reflectivityCallback(x, y); + this._reflectivityCache[key] = reflectivity; + } + + if (reflectivity == 0) { + continue; + } + /* will not reflect at all */ + + /* compute emission color */ + + + var emission = [0, 0, 0]; + var intensity = 0; + + for (var i = 0; i < 3; i++) { + var part = Math.round(_color[i] * reflectivity); + emission[i] = part; + intensity += part; + } + + if (intensity > this._options.emissionThreshold) { + result[key] = emission; + } + } + + return result; + }; + /** + * Compute one iteration from one cell + */ + + + _proto37._emitLightFromCell = function _emitLightFromCell(x, y, color, litCells) { + var key = x + "," + y; + var fov; + + if (key in this._fovCache) { + fov = this._fovCache[key]; + } else { + fov = this._updateFOV(x, y); + } + + for (var fovKey in fov) { + var formFactor = fov[fovKey]; + var result = void 0; + + if (fovKey in litCells) { + /* already lit */ + result = litCells[fovKey]; + } else { + /* newly lit */ + result = [0, 0, 0]; + litCells[fovKey] = result; + } + + for (var i = 0; i < 3; i++) { + result[i] += Math.round(color[i] * formFactor); + } + /* add light color */ + + } + + return this; + }; + /** + * Compute FOV ("form factor") for a potential light source at [x,y] + */ + + + _proto37._updateFOV = function _updateFOV(x, y) { + var key1 = x + "," + y; + var cache = {}; + this._fovCache[key1] = cache; + var range = this._options.range; + + function cb(x, y, r, vis) { + var key2 = x + "," + y; + var formFactor = vis * (1 - r / range); + + if (formFactor == 0) { + return; + } + + cache[key2] = formFactor; + } + + this._fov.compute(x, y, range, cb.bind(this)); + + return cache; + }; + + return Lighting; + }(); + + var Util = util; + var Color = color; + var Text = text; + exports.Util = Util; + exports.Color = Color; + exports.Text = Text; + exports.RNG = RNG$1; + exports.Display = Display; + exports.StringGenerator = StringGenerator; + exports.EventQueue = EventQueue; + exports.Scheduler = index; + exports.FOV = index$1; + exports.Map = index$2; + exports.Noise = index$3; + exports.Path = index$4; + exports.Engine = Engine; + exports.Lighting = Lighting; + exports.DEFAULT_WIDTH = DEFAULT_WIDTH; + exports.DEFAULT_HEIGHT = DEFAULT_HEIGHT; + exports.DIRS = DIRS; + exports.KEYS = KEYS; + Object.defineProperty(exports, '__esModule', { + value: true + }); +}); + diff --git a/html/js/rot.min.js b/html/js/rot.min.js new file mode 100644 index 0000000..c8d1f38 --- /dev/null +++ b/html/js/rot.min.js @@ -0,0 +1,138 @@ +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(g,p,r){g!=Array.prototype&&g!=Object.prototype&&(g[p]=r.value)};$jscomp.getGlobal=function(g){return"undefined"!=typeof window&&window===g?g:"undefined"!=typeof global&&null!=global?global:g};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(g,p,r,t){if(p){r=$jscomp.global;g=g.split(".");for(t=0;tr&&(r=Math.max(0,p+r));if(null==t||t>p)t=p;t=Number(t);0>t&&(t=Math.max(0,p+t));for(r=Number(r||0);rg||1342177279>>=1)p+=p;return t}},"es6","es3");$jscomp.stringPadding=function(g,p){g=void 0!==g?String(g):" ";return 0a?a:d}function t(d){return d.charAt(0).toUpperCase()+d.substring(1)}function w(d){for(var c=arguments.length,a=Array(1c;c++)a[c+1]+=16*a[c],a.splice(c,1);else a=(c=d.match(/rgb\(([0-9, ]+)\)/i))? +c[1].split(/\s*,\s*/).map(function(b){return parseInt(b)}):[0,0,0];Q[d]=a}return a.slice()}function Y(d){for(var c=arguments.length,a=Array(1c;c++)for(b=0;be;e++)b[e]=Math.round(b[e]+a*(c[e]-d[e]));return b}function aa(d,c,a){void 0===a&&(a=.5);d=R(d);c=R(c);for(var b=0;3>b;b++)d[b]+=a*(c[b]-d[b]);return ba(d)}function R(d){var c=d[0]/255,a=d[1]/255; +d=d[2]/255;var b=Math.max(c,a,d),e=Math.min(c,a,d),f=0,m=(b+e)/2;if(b==e)e=0;else{var k=b-e;e=.5a&&(a+=1);1a?c:a<2/3?d+(c-d)*(2/3-a)*6:d}function ba(d){var c=d[2];if(0==d[1])return c=Math.round(255*c),[c,c,c];var a=d[1];a=.5>c?c*(1+a):c+a-c*a;var b=2*c-a;c=S(b,a,d[0]+1/3);var e=S(b,a,d[0]);d=S(b,a,d[0]-1/3);return[Math.round(255* +c),Math.round(255*e),Math.round(255*d)]}function fa(d,c,a){var b=d.createShader(d.VERTEX_SHADER);d.shaderSource(b,c);d.compileShader(b);if(!d.getShaderParameter(b,d.COMPILE_STATUS))throw Error(d.getShaderInfoLog(b)||"");c=d.createShader(d.FRAGMENT_SHADER);d.shaderSource(c,a);d.compileShader(c);if(!d.getShaderParameter(c,d.COMPILE_STATUS))throw Error(d.getShaderInfoLog(c)||"");a=d.createProgram();d.attachShader(a,b);d.attachShader(a,c);d.linkProgram(a);if(!d.getProgramParameter(a,d.LINK_STATUS))throw Error(d.getProgramInfoLog(a)|| +"");return a}function ha(d){var c=new Float32Array([0,0,1,0,0,1,1,1]),a=d.createBuffer();d.bindBuffer(d.ARRAY_BUFFER,a);d.bufferData(d.ARRAY_BUFFER,c,d.STATIC_DRAW);d.enableVertexAttribArray(0);d.vertexAttribPointer(0,2,d.FLOAT,!1,0,0)}function M(d){if(!(d in T)){if("transparent"==d)var c=[0,0,0,0];else if(-1a;a++)c[a]/=255}else c=L(d).map(function(b){return b/255}),c.push(1);T[d]=c}return T[d]}function U(d){d=L(d);return 36* +Math.floor(.0234375*d[0])+6*Math.floor(.0234375*d[1])+1*Math.floor(.0234375*d[2])+16}function V(d,c){var a=[],b=0;d.replace(ia,function(e,m,k,h){var f=d.substring(b,h);f.length&&a.push({type:0,value:f});a.push({type:"c"==m?2:3,value:k.trim()});b=h+e.length;return""});var e=d.substring(b);e.length&&a.push({type:0,value:e});return ja(a,c)}function ja(d,c){c||(c=Infinity);for(var a=0,b=0,e=-1;ac){for(m=-1;;){var k=f.value.indexOf(" ",m+1);if(-1==k)break;if(b+k>c)break;m=k}-1!=m?f.value=N(d,a,m,!0):-1!=e?(a=d[e],f=a.value.lastIndexOf(" "),a.value=N(d,e,f,!0),a=e):f.value=N(d,a,c-b,!1)}else b+=f.value.length,-1!=f.value.indexOf(" ")&&(e=a);a++}else d.splice(a,1)}}d.push({type:1});c=null;for(b= +0;ba?1/a:a;this._s0=2.3283064365386963E-10*(a>>>0);a=69069*a+1>>>0;this._s1=2.3283064365386963E-10*a;this._s2=2.3283064365386963E-10*(69069*a+1>>>0);this._c=1;return this};c.getUniform=function(){var a=2091639*this._s0+2.3283064365386963E-10*this._c;this._s0=this._s1;this._s1=this._s2;this._c=a|0;return this._s2=a-this._c};c.getUniformInt=function(a,b){var e=Math.max(a,b);a=Math.min(a,b);return Math.floor(this.getUniform()* +(e-a+1))+a};c.getNormal=function(a,b){void 0===a&&(a=0);void 0===b&&(b=1);do{var e=2*this.getUniform()-1;var f=2*this.getUniform()-1;f=e*e+f*f}while(1b||0>e||b>=f.width||e>=f.height?[-1,-1]:this._normalizedEventToPosition(b,e)};return c}(I);w.map={s:"toString"};var ka=Object.freeze({mod:p,clamp:r,capitalize:t,format:w}),O=function(d){function c(){var b=d.call(this)||this; +b._spacingX=0;b._spacingY=0;b._hexSize=0;return b}_inheritsLoose(c,d);var a=c.prototype;a.draw=function(b,e){var f=b[2],a=b[3],k=b[4];b=[(b[0]+1)*this._spacingX,b[1]*this._spacingY+this._hexSize];this._options.transpose&&b.reverse();e&&(this._ctx.fillStyle=k,this._fill(b[0],b[1]));if(f)for(this._ctx.fillStyle=a,e=[].concat(f),f=0;fa;a++)for(e=0;ea;a++){for(e=0;e< +b.length;e++)c[a]*=b[e][a]/255;c[a]=Math.round(c[a])}return c},multiply_:function(d){for(var c=arguments.length,a=Array(1c;c++){for(b=0;ba;a++)d[a]+=c instanceof Array?Math.round(q.getNormal(0,c[a])):c;return d},rgb2hsl:R,hsl2rgb:ba, +toRGB:function(d){return"rgb("+d.map(function(c){return r(c,0,255)}).join(",")+")"},toHex:function(d){return"#"+d.map(function(c){return r(c,0,255).toString(16).padStart(2,"0")}).join("")}});var x=function(d){function c(){var b=d.call(this)||this;b._uniforms={};try{b._gl=b._initWebGL()}catch(e){alert(e.message)}return b}_inheritsLoose(c,d);c.isSupported=function(){return!!document.createElement("canvas").getContext("webgl2",{preserveDrawingBuffer:!0})};var a=c.prototype;a.schedule=function(b){requestAnimationFrame(b)}; +a.getContainer=function(){return this._gl.canvas};a.setOptions=function(b){var e=this;d.prototype.setOptions.call(this,b);this._updateSize();var f=this._options.tileSet;f&&"complete"in f&&!f.complete?f.addEventListener("load",function(){return e._updateTexture(f)}):this._updateTexture(f)};a.draw=function(b,e){var f=this._gl,a=this._options,k=b[0],h=b[1],c=b[2],d=b[3];b=b[4];f.scissor(k*a.tileWidth,f.canvas.height-(h+1)*a.tileHeight,a.tileWidth,a.tileHeight);e&&(a.tileColorize?f.clearColor(0,0,0,0): +f.clearColor.apply(f,M(b)),f.clear(f.COLOR_BUFFER_BIT));if(c)for(e=[].concat(c),c=[].concat(b),d=[].concat(d),f.uniform2fv(this._uniforms.targetPosRel,[k,h]),k=0;k +b||0>e||b>=f.width||e>=f.height?[-1,-1]:this._normalizedEventToPosition(b,e)};a._initWebGL=function(){var b=this,e=document.createElement("canvas").getContext("webgl2",{preserveDrawingBuffer:!0});window.gl=e;var f=fa(e,la,ma);e.useProgram(f);ha(e);na.forEach(function(a){return b._uniforms[a]=e.getUniformLocation(f,a)});this._program=f;e.enable(e.BLEND);e.blendFuncSeparate(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA);e.enable(e.SCISSOR_TEST);return e};a._normalizedEventToPosition= +function(b,e){return[Math.floor(b/this._options.tileWidth),Math.floor(e/this._options.tileHeight)]};a._updateSize=function(){var b=this._gl,e=this._options,a=[e.width*e.tileWidth,e.height*e.tileHeight];b.canvas.width=a[0];b.canvas.height=a[1];b.viewport(0,0,a[0],a[1]);b.uniform2fv(this._uniforms.tileSize,[e.tileWidth,e.tileHeight]);b.uniform2fv(this._uniforms.targetSize,a)};a._updateTexture=function(b){var e=this._gl,a=e.createTexture();e.bindTexture(e.TEXTURE_2D,a);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER, +e.NEAREST);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT);e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,0);e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,b)};return c}(I),na="targetPosRel tilesetPosAbs tileSize targetSize colorize bg tint".split(" "),la="#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}", +ma="#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}", +T={},u=function(d){function c(){var b=d.call(this)||this;b._offset=[0,0];b._cursor=[-1,-1];b._lastColor="";return b}_inheritsLoose(c,d);var a=c.prototype;a.schedule=function(b){setTimeout(b,1E3/60)};a.setOptions=function(b){d.prototype.setOptions.call(this,b);var e=[b.width,b.height];this._offset=this.computeSize().map(function(b,a){return Math.floor((b-e[a])/2)})};a.clear=function(){process.stdout.write("\u001b[0;48;5;"+U(this._options.bg)+"m\u001b[2J")};a.draw=function(b,e){var a=b[2],m=b[3],k= +b[4],c=this._offset[0]+b[0],d=this._offset[1]+b[1];b=this.computeSize();if(!(0>c||c>=b[0]||0>d||d>=b[1])){if(c!==this._cursor[0]||d!==this._cursor[1])process.stdout.write("\u001b["+(d+1)+";"+(c+1)+"H"),this._cursor[0]=c,this._cursor[1]=d;e&&(a||(a=" "));a&&(e="\u001b[0;38;5;"+U(m)+";48;5;"+U(k)+"m",e!==this._lastColor&&(process.stdout.write(e),this._lastColor=e),a=[].concat(a),process.stdout.write(a[0]),this._cursor[0]++,this._cursor[0]>=b[0]&&(this._cursor[0]=0,this._cursor[1]++))}};a.computeFontSize= +function(){throw Error("Terminal backend has no notion of font size");};a.eventToPosition=function(b,e){return[b,e]};a.computeSize=function(){return[process.stdout.columns,process.stdout.rows]};return c}(I),ia=/%([bc]){([^}]*)}/g;I=Object.freeze({TYPE_TEXT:0,TYPE_NEWLINE:1,TYPE_FG:2,TYPE_BG:3,measure:function(d,c){var a={width:0,height:1};d=V(d,c);for(var b=c=0;bl||65500l||65518this._options.order?a=a.slice(-this._options.order):a.lengthb){e=f;break}this._events.splice(e,0,a);this._eventTimes.splice(e,0,b)};c.get=function(){if(!this._events.length)return null;var a=this._eventTimes.splice(0,1)[0];if(0b)return e=this._visibleCoords(0,e,a,m),b=this._visibleCoords(360+b,360,a,m),e||b;for(var f=0;fe[0])return b=this._checkVisibility(b,[b[1],b[1]],a,c),e=this._checkVisibility([0,1],e,a,c),(b+e)/2;for(var f=0,m=!1;fd&&f%2&&(g=!1);if(!g)return 0;m=d-f+1;if(m%2)f%2?(d=c[f],d=(e[0]*d[1]-d[0]*e[1])/(d[1]*e[1]),a&&c.splice(f,m,e)):(d=c[d],d=(d[0]*b[1]-b[0]*d[1])/(b[1]*d[1]),a&&c.splice(f,m,b));else if(f%2)l=c[f],d=c[d],d=(d[0]*l[1]-l[0]*d[1])/(l[1]*d[1]),a&&c.splice(f,m);else return a&&c.splice(f,m,b,e),1;return d/((e[0]*b[1]-b[0]*e[1])/(b[1]*e[1]))};return c}(u);var C=[[-1,0,0,1],[0,-1,1,0],[0,-1,-1,0],[-1,0,0,-1],[1, +0,0,-1],[0,1,-1,0],[0,1,1,0],[1,0,0,1]];u=function(d){function c(){return d.apply(this,arguments)||this}_inheritsLoose(c,d);var a=c.prototype;a.compute=function(b,e,a,c){c(b,e,0,1);for(var f=0;f=f;){f+=1;var z=b+f*n+m*l,y=e+f*g+m*q,r=(f-.5)/(m+.5),t=(f+.5)/(m-.5);if(!(t>c)){if(rthis._options.timeLimit)return null;this._map=this._fillMap(1);this._dug=0;this._rooms=[];this._unconnected=[];this._generateRooms();if(!(2>this._rooms.length)&&this._generateCorridors())break}if(b)for(a=0;athis._options.roomDugPercentage)break}while(f)};a._generateRoom=function(){for(var b=0;b=n&&d[e]<=l){c=d.slice();n=0;switch(h){case 0:n=a.getTop()- +1;break;case 1:n=a.getRight()+1;break;case 2:n=a.getBottom()+1;break;case 3:n=a.getLeft()-1}c[(e+1)%2]=n;this._digLine([d,c])}else if(d[e]l+1){c=d[e]-c[e];n=0;switch(h){case 0:case 1:n=0>c?3:1;break;case 2:case 3:n=0>c?1:3}c=this._placeInWall(a,(h+n)%4);if(!c)return!1;h=[0,0];h[e]=d[e];e=(e+1)%2;h[e]=c[e];this._digLine([d,h,c])}else{n=(e+1)%2;c=this._placeInWall(a,h);if(!c)return!1;h=Math.round((c[n]+d[n])/2);l=[0,0];var g=[0,0];l[e]=d[e];l[n]=h;g[e]=c[e];g[n]=h;this._digLine([d,l,g,c])}b.addDoor(d[0], +d[1]);a.addDoor(c[0],c[1]);e=this._unconnected.indexOf(b);-1!=e&&(this._unconnected.splice(e,1),this._connected.push(b));e=this._unconnected.indexOf(a);-1!=e&&(this._unconnected.splice(e,1),this._connected.push(a));return!0};a._placeInWall=function(b,a){var e=[0,0],c=[0,0],d=0;switch(a){case 0:c=[1,0];e=[b.getLeft(),b.getTop()-1];d=b.getRight()-b.getLeft()+1;break;case 1:c=[0,1];e=[b.getRight()+1,b.getTop()];d=b.getBottom()-b.getTop()+1;break;case 2:c=[1,0];e=[b.getLeft(),b.getBottom()+1];d=b.getRight()- +b.getLeft()+1;break;case 3:c=[0,1],e=[b.getLeft()-1,b.getTop()],d=b.getBottom()-b.getTop()+1}b=[];a=-2;for(var h=0;hb||0>a||b>=this._width||a>=this._height?!1:1==this._map[b][a]};a._canBeDugCallback=function(b,a){return 1>b||1>a||b+1>=this._width||a+1>=this._height?!1:1==this._map[b][a]};return c}(H);var E=function(d){function c(b,a,f){void 0===f&&(f={});b=d.call(this,b,a)||this;b._options={born:[5,6,7,8],survive:[4,5,6,7,8],topology:8};b.setOptions(f);b._dirs=v[b._options.topology];b._map=b._fillMap(0);return b}_inheritsLoose(c,d);var a=c.prototype; +a.randomize=function(b){for(var a=0;ah||h>=this._width||0>d||d>=this._height||(e+=1==this._map[h][d]?1:0)}return e};a.connect=function(b,a,f){a||(a=0);var e=[],c={},d=1,n=[0,0];6==this._options.topology&& +(d=2,n=[0,1]);for(var l=0;ll&&!(h.lengthd);l++);return[e,c]};a._getClosest=function(b,a){var e=null,c=null,d;for(d in a){var h=a[d],n=(h[0]-b[0])*(h[0]-b[0])+(h[1]- +b[1])*(h[1]-b[1]);if(null==c||nf[1]&&(e--, +g=1);m=mf[0]?m-g:f[1]%2?m-g:m+g;this._map[m][e]=k;g=[m,e];var q=this._pointKey(g);c[q]=g;delete d[q]}h&&h(a,b)};a._freeSpace=function(b,a,f){return 0<=b&&bthis._options.timeLimit)break;var d=this._findWall();if(!d)break;var h=d.split(",");d=parseInt(h[0]);h=parseInt(h[1]);var g=this._getDiggingDirection(d,h);if(g){var l=0;do if(l++,this._tryFeature(d,h,g[0],g[1])){this._removeSurroundingWalls(d,h);this._removeSurroundingWalls(d-g[0],h-g[1]);break}while(l< +this._featureAttempts);for(var q in this._walls)1b||0>a||b>=this._width||a>=this._height?!1:1==this._map[b][a]};a._canBeDugCallback=function(b,a){return 1> +b||1>a||b+1>=this._width||a+1>=this._height?!1:1==this._map[b][a]};a._priorityWallCallback=function(b,a){this._walls[b+","+a]=2};a._firstRoom=function(){var b=P.createRandomCenter(Math.floor(this._width/2),Math.floor(this._height/2),this._options);this._rooms.push(b);b.create(this._digCallback)};a._findWall=function(){var b=[],a=[],f;for(f in this._walls)2==this._walls[f]?a.push(f):b.push(f);b=a.length?a:b;if(!b.length)return null;b=q.getItem(b.sort());delete this._walls[b];return b};a._tryFeature= +function(b,a,f,c){var e=q.getWeightedValue(this._features);b=qa[e].createRandomAt(b,a,f,c,this._options);if(!b.isValid(this._isWallCallback,this._canBeDugCallback))return!1;b.create(this._digCallback);b instanceof P&&this._rooms.push(b);b instanceof X&&(b.createPriorityWalls(this._priorityWallCallback),this._corridors.push(b));return!0};a._removeSurroundingWalls=function(b,a){for(var e=v[4],c=0;c=b||0>=a||b>=this._width-1||a>=this._height-1)return null;for(var e=null,c=v[4],d=0;dr;r++){var t=g+2*h[r][0];var A=l+2*h[r][1];if(this._isFree(d,t,A,a,c)){d[t][A]=0;d[g+h[r][0]][l+h[r][1]]=0;g=t;l= +A;p=!1;k++;break}}}while(!p)}}while(k+1a;a++)b[a][0]=0,b[a][1]=0;switch(Math.floor(4*q.getUniform())){case 0:b[0][0]=-1;b[1][0]=1;b[2][1]=-1;b[3][1]=1;break;case 1:b[3][0]=-1;b[2][0]=1;b[1][1]=-1;b[0][1]=1;break;case 2:b[2][0]=-1;b[3][0]=1;b[0][1]=-1;b[1][1]=1;break;case 3:b[1][0]=-1,b[0][0]=1,b[3][1]=-1,b[2][1]=1}};a._isFree=function(b,a,c,d,k){return 1>a|| +1>c||a>=d||c>=k?!1:b[a][c]};return c}(u);u=function(d){function c(b,a,c){b=d.call(this,b,a)||this;b.map=[];b.rooms=[];b.connectedCells=[];c=Object.assign({cellWidth:3,cellHeight:3},c);c.hasOwnProperty("roomWidth")||(c.roomWidth=b._calculateRoomSize(b._width,c.cellWidth));c.hasOwnProperty("roomHeight")||(c.roomHeight=b._calculateRoomSize(b._height,c.cellHeight));b._options=c;return b}_inheritsLoose(c,d);var a=c.prototype;a.create=function(b){this.map=this._fillMap(1);this.rooms=[];this.connectedCells= +[];this._initRooms();this._connectRooms();this._connectUnconnectedRooms();this._createRandomRoomConnections();this._createRooms();this._createCorridors();if(b)for(var a=0;ab&&(b=2);2>c&&(c=2);return[b,c]};a._initRooms=function(){for(var b=0;bh||h>=this._options.cellWidth||0>k||k>=this._options.cellHeight)){var g=this.rooms[b][a];if(0r||r>=b||0>p||p>=a)){d=this.rooms[r][p]; +k=!0;if(0==d.connections.length)break;for(r=0;rA-(u.y+u.height);)A++;if(0t-(u.x+u.width);)t++;u=Math.round(q.getUniformInt(0,k-g)/2);for(var x=Math.round(q.getUniformInt(0,h-l)/2);t+u+g>=b;)u?u--:g--;for(;A+x+l>=a;)x?x--:l--;t+=u;A+=x;this.rooms[v][w].x=t;this.rooms[v][w].y=A;this.rooms[v][w].width=g;this.rooms[v][w].height=l;for(u=t;ud.cellx? +(k=2,h=4):g.cellxd.celly?(k=3,h=1):(k=1,h=3),this._drawCorridor(this._getWallPosition(d,k),this._getWallPosition(g,h))}};return c}(u);x={Arena:x,Uniform:D,Cellular:E,Digger:H,EllerMaze:ra,DividedMaze:sa,IceyMaze:ta,Rogue:u};var ua=.5*(Math.sqrt(3)-1),K=(3-Math.sqrt(3))/6;u={Simplex:function(d){function c(a){void 0===a&&(a=256);var b=d.call(this)||this;b._gradients=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]];for(var c=[],f=0;fu){var v=1;var w=0}else v=0,w=1;t=l-v+K;var x=u-w+K;b=l-1+2*K;a=u-1+2*K;q=p(q,g);g=p(r,g);var B=.5-l*l-u*u;0<=B&&(B*=B,r=d[q+c[g]],k=this._gradients[r],k=B*B*(k[0]*l+k[1]*u));l=.5-t*t- +x*x;0<=l&&(l*=l,r=d[q+v+c[g+w]],h=this._gradients[r],h=l*l*(h[0]*t+h[1]*x));l=.5-b*b-a*a;0<=l&&(l*=l,r=d[q+1+c[g+1]],c=this._gradients[r],n=l*l*(c[0]*b+c[1]*a));return 70*(k+h+n)};return c}(function(){})};E=function(){function d(c,a,b,d){void 0===d&&(d={});this._toX=c;this._toY=a;this._passableCallback=b;this._options=Object.assign({topology:8},d);this._dirs=v[this._options.topology];8==this._options.topology&&(this._dirs=[this._dirs[0],this._dirs[2],this._dirs[4],this._dirs[6],this._dirs[1],this._dirs[3], +this._dirs[5],this._dirs[7]])}d.prototype._getNeighbors=function(c,a){for(var b=[],d=0;dl;l++){var p=Math.round(g[l]*k);h[l]=p;n+=p}n>this._options.emissionThreshold&&(c[d]=h)}}return c};c._emitLightFromCell=function(a,b,c,d){var e=a+","+b;a=e in this._fovCache?this._fovCache[e]:this._updateFOV(a,b);for(var f in a){b=a[f];f in +d?e=d[f]:(e=[0,0,0],d[f]=e);for(var g=0;3>g;g++)e[g]+=Math.round(c[g]*b)}return this};c._updateFOV=function(a,b){var c={};this._fovCache[a+","+b]=c;var d=this._options.range;this._fov.compute(a,b,d,function(a,b,e,f){e=f*(1-e/d);0!=e&&(c[a+","+b]=e)}.bind(this));return c};return d}();g.Util=ka;g.Color=J;g.Text=I;g.RNG=q;g.Display=G;g.StringGenerator=O;g.EventQueue=ea;g.Scheduler=F;g.FOV=B;g.Map=x;g.Noise=u;g.Path=D;g.Engine=E;g.Lighting=H;g.DEFAULT_WIDTH=80;g.DEFAULT_HEIGHT=25;g.DIRS=v;g.KEYS={VK_CANCEL:3, +VK_HELP:6,VK_BACK_SPACE:8,VK_TAB:9,VK_CLEAR:12,VK_RETURN:13,VK_ENTER:14,VK_SHIFT:16,VK_CONTROL:17,VK_ALT:18,VK_PAUSE:19,VK_CAPS_LOCK:20,VK_ESCAPE:27,VK_SPACE:32,VK_PAGE_UP:33,VK_PAGE_DOWN:34,VK_END:35,VK_HOME:36,VK_LEFT:37,VK_UP:38,VK_RIGHT:39,VK_DOWN:40,VK_PRINTSCREEN:44,VK_INSERT:45,VK_DELETE:46,VK_0:48,VK_1:49,VK_2:50,VK_3:51,VK_4:52,VK_5:53,VK_6:54,VK_7:55,VK_8:56,VK_9:57,VK_COLON:58,VK_SEMICOLON:59,VK_LESS_THAN:60,VK_EQUALS:61,VK_GREATER_THAN:62,VK_QUESTION_MARK:63,VK_AT:64,VK_A:65,VK_B:66,VK_C:67, +VK_D:68,VK_E:69,VK_F:70,VK_G:71,VK_H:72,VK_I:73,VK_J:74,VK_K:75,VK_L:76,VK_M:77,VK_N:78,VK_O:79,VK_P:80,VK_Q:81,VK_R:82,VK_S:83,VK_T:84,VK_U:85,VK_V:86,VK_W:87,VK_X:88,VK_Y:89,VK_Z:90,VK_CONTEXT_MENU:93,VK_NUMPAD0:96,VK_NUMPAD1:97,VK_NUMPAD2:98,VK_NUMPAD3:99,VK_NUMPAD4:100,VK_NUMPAD5:101,VK_NUMPAD6:102,VK_NUMPAD7:103,VK_NUMPAD8:104,VK_NUMPAD9:105,VK_MULTIPLY:106,VK_ADD:107,VK_SEPARATOR:108,VK_SUBTRACT:109,VK_DECIMAL:110,VK_DIVIDE:111,VK_F1:112,VK_F2:113,VK_F3:114,VK_F4:115,VK_F5:116,VK_F6:117,VK_F7:118, +VK_F8:119,VK_F9:120,VK_F10:121,VK_F11:122,VK_F12:123,VK_F13:124,VK_F14:125,VK_F15:126,VK_F16:127,VK_F17:128,VK_F18:129,VK_F19:130,VK_F20:131,VK_F21:132,VK_F22:133,VK_F23:134,VK_F24:135,VK_NUM_LOCK:144,VK_SCROLL_LOCK:145,VK_CIRCUMFLEX:160,VK_EXCLAMATION:161,VK_DOUBLE_QUOTE:162,VK_HASH:163,VK_DOLLAR:164,VK_PERCENT:165,VK_AMPERSAND:166,VK_UNDERSCORE:167,VK_OPEN_PAREN:168,VK_CLOSE_PAREN:169,VK_ASTERISK:170,VK_PLUS:171,VK_PIPE:172,VK_HYPHEN_MINUS:173,VK_OPEN_CURLY_BRACKET:174,VK_CLOSE_CURLY_BRACKET:175, +VK_TILDE:176,VK_COMMA:188,VK_PERIOD:190,VK_SLASH:191,VK_BACK_QUOTE:192,VK_OPEN_BRACKET:219,VK_BACK_SLASH:220,VK_CLOSE_BRACKET:221,VK_QUOTE:222,VK_META:224,VK_ALTGR:225,VK_WIN:91,VK_KANA:21,VK_HANGUL:21,VK_EISU:22,VK_JUNJA:23,VK_FINAL:24,VK_HANJA:25,VK_KANJI:25,VK_CONVERT:28,VK_NONCONVERT:29,VK_ACCEPT:30,VK_MODECHANGE:31,VK_SELECT:41,VK_PRINT:42,VK_EXECUTE:43,VK_SLEEP:95};Object.defineProperty(g,"__esModule",{value:!0})}); diff --git a/html/js/teletype.js b/html/js/teletype.js new file mode 100644 index 0000000..48476b5 --- /dev/null +++ b/html/js/teletype.js @@ -0,0 +1,81 @@ +(function ($) { + // writes the string + // + // @param jQuery $target + // @param String str + // @param Numeric cursor + // @param Numeric delay + // @param Function cb + // @return void + function typeString($target, str, cursor, delay, cb) { + $target.html(function (_, html) { + return html + str[cursor]; + }); + + if (cursor < str.length - 1) { + setTimeout(function () { + typeString($target, str, cursor + 1, delay, cb); + }, delay); + } + else { + cb(); + } + } + + // clears the string + // + // @param jQuery $target + // @param Numeric delay + // @param Function cb + // @return void + function deleteString($target, delay, cb) { + var length; + + $target.html(function (_, html) { + length = html.length; + return html.substr(0, length - 1); + }); + + if (length > 1) { + setTimeout(function () { + deleteString($target, delay, cb); + }, delay); + } + else { + cb(); + } + } + + // jQuery hook + $.fn.extend({ + teletype: function (opts) { + var settings = $.extend({}, $.teletype.defaults, opts); + + return $(this).each(function () { + (function loop($tar, idx) { + // type + typeString($tar, settings.text[idx], 0, settings.delay, function () { + // delete + setTimeout(function () { + deleteString($tar, settings.delay, function () { + loop($tar, (idx + 1) % settings.text.length); + }); + }, settings.pause); + }); + + }($(this), 0)); + }); + } + }); + + // plugin defaults + $.extend({ + teletype: { + defaults: { + delay: 100, + pause: 2500, + text: [] + } + } + }); + }(jQuery)); \ No newline at end of file diff --git a/html/styles/fonts/pixel-operator/.uuid b/html/styles/fonts/pixel-operator/.uuid new file mode 100644 index 0000000..a337373 --- /dev/null +++ b/html/styles/fonts/pixel-operator/.uuid @@ -0,0 +1 @@ +90232dfa-09e6-43b8-baa1-f3fc548757e8 \ No newline at end of file diff --git a/html/styles/fonts/pixel-operator/LICENSE.txt b/html/styles/fonts/pixel-operator/LICENSE.txt new file mode 100644 index 0000000..0e259d4 --- /dev/null +++ b/html/styles/fonts/pixel-operator/LICENSE.txt @@ -0,0 +1,121 @@ +Creative Commons Legal Code + +CC0 1.0 Universal + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS + PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM + THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED + HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer +exclusive Copyright and Related Rights (defined below) upon the creator +and subsequent owner(s) (each and all, an "owner") of an original work of +authorship and/or a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for +the purpose of contributing to a commons of creative, cultural and +scientific works ("Commons") that the public can reliably and without fear +of later claims of infringement build upon, modify, incorporate in other +works, reuse and redistribute as freely as possible in any form whatsoever +and for any purposes, including without limitation commercial purposes. +These owners may contribute to the Commons to promote the ideal of a free +culture and the further production of creative, cultural and scientific +works, or to gain reputation or greater distribution for their Work in +part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any +expectation of additional consideration or compensation, the person +associating CC0 with a Work (the "Affirmer"), to the extent that he or she +is an owner of Copyright and Related Rights in the Work, voluntarily +elects to apply CC0 to the Work and publicly distribute the Work under its +terms, with knowledge of his or her Copyright and Related Rights in the +Work and the meaning and intended legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be +protected by copyright and related or neighboring rights ("Copyright and +Related Rights"). Copyright and Related Rights include, but are not +limited to, the following: + + i. the right to reproduce, adapt, distribute, perform, display, + communicate, and translate a Work; + ii. moral rights retained by the original author(s) and/or performer(s); +iii. publicity and privacy rights pertaining to a person's image or + likeness depicted in a Work; + iv. rights protecting against unfair competition in regards to a Work, + subject to the limitations in paragraph 4(a), below; + v. rights protecting the extraction, dissemination, use and reuse of data + in a Work; + vi. database rights (such as those arising under Directive 96/9/EC of the + European Parliament and of the Council of 11 March 1996 on the legal + protection of databases, and under any national implementation + thereof, including any amended or successor version of such + directive); and +vii. other similar, equivalent or corresponding rights throughout the + world based on applicable law or treaty, and any national + implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention +of, applicable law, Affirmer hereby overtly, fully, permanently, +irrevocably and unconditionally waives, abandons, and surrenders all of +Affirmer's Copyright and Related Rights and associated claims and causes +of action, whether now known or unknown (including existing as well as +future claims and causes of action), in the Work (i) in all territories +worldwide, (ii) for the maximum duration provided by applicable law or +treaty (including future time extensions), (iii) in any current or future +medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional +purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each +member of the public at large and to the detriment of Affirmer's heirs and +successors, fully intending that such Waiver shall not be subject to +revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason +be judged legally invalid or ineffective under applicable law, then the +Waiver shall be preserved to the maximum extent permitted taking into +account Affirmer's express Statement of Purpose. In addition, to the +extent the Waiver is so judged Affirmer hereby grants to each affected +person a royalty-free, non transferable, non sublicensable, non exclusive, +irrevocable and unconditional license to exercise Affirmer's Copyright and +Related Rights in the Work (i) in all territories worldwide, (ii) for the +maximum duration provided by applicable law or treaty (including future +time extensions), (iii) in any current or future medium and for any number +of copies, and (iv) for any purpose whatsoever, including without +limitation commercial, advertising or promotional purposes (the +"License"). The License shall be deemed effective as of the date CC0 was +applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder +of the License, and in such case Affirmer hereby affirms that he or she +will not (i) exercise any of his or her remaining Copyright and Related +Rights in the Work or (ii) assert any associated claims and causes of +action with respect to the Work, in either case contrary to Affirmer's +express Statement of Purpose. + +4. Limitations and Disclaimers. + + a. No trademark or patent rights held by Affirmer are waived, abandoned, + surrendered, licensed or otherwise affected by this document. + b. Affirmer offers the Work as-is and makes no representations or + warranties of any kind concerning the Work, express, implied, + statutory or otherwise, including without limitation warranties of + title, merchantability, fitness for a particular purpose, non + infringement, or the absence of latent or other defects, accuracy, or + the present or absence of errors, whether or not discoverable, all to + the greatest extent permissible under applicable law. + c. Affirmer disclaims responsibility for clearing rights of other persons + that may apply to the Work or any use thereof, including without + limitation any person's Copyright and Related Rights in the Work. + Further, Affirmer disclaims responsibility for obtaining any necessary + consents, permissions or other rights required for any use of the + Work. + d. Affirmer understands and acknowledges that Creative Commons is not a + party to this document and has no duty or obligation with respect to + this CC0 or use of the Work. diff --git a/html/styles/fonts/pixel-operator/PixelOperator-Bold.ttf b/html/styles/fonts/pixel-operator/PixelOperator-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..745734f6c92d6c2855e477a32a00f98d2936db1d GIT binary patch literal 16984 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 literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperator.ttf b/html/styles/fonts/pixel-operator/PixelOperator.ttf new file mode 100644 index 0000000000000000000000000000000000000000..34fe947b8d4e7efa8e57798512ff15b232a763de GIT binary patch literal 17272 zcmcIs3z%F*l|Hv`_q^XTok>D~o=iw4Fid9h&JbcCAw&$X5O9E?nM`*cI4>rX7}$u2 zqav~zUEdpBMBI&t7HrcBC9r{cE;sb&6|Jq9VLGf@z&yc zQ%_&_;CtRY?Pns1UXj@CTf27*=5pvMt2W?%$=2SRw|wSfUwcHP^pHsV)NPsWbXCiW z4DS69$Kq|MD65Je0lhe`XKm{n-u;0Gw~XR?zli^6??6xYqTvgUi4?z#x?_Fay9d21 za;OA~{M;ro2d6TY`B}SW*?%0X<@A3-@K9?n^|jwNwxFOCzEjg3myPe~f*H16x!)O)S0a|i0uu`WsT zo|er$_7B=jR(9UsvYY@fWR|tUR%u*BarObKu-3=Nof$G^69QJdtkL zma=jECTT~R>0Bu5i0so&_V&Jx;p&u*r5p5zj#$PK^mXGFp5yC6o}%~I*U?}Z_au6M zlJcwF59S{2`#Q#-w10%w>mDEecS@R^dxW;OBd@38*R_4M`)EhHN}F<3Jwkt~bE`8e z?+N3>epL5B5Ab7rkNs!^ID}`85BDVo@R(uz+uMUHdio5Bdz*0HAS;0(4RWh|Uj9+O zDEG?)@}N8{-;tbG>Q#HEduMqa-Xd?Uca?XocZ1jMWxN4zw|8so@z~+mk=W5xLuz{J zjMU83>{NTIGj)IJ!PGaK8k=SUr->tX%NJz7d6rIhNjDAn9^xkqyUk~^6DUhccOf6jd;_pRJRxd(Fh z=kCev%Y8Waq1>&xow=KG1G&E3+j5!Q4Y_N_>&9c_-nfkYVC?a+$Hu-t_Q=?`#vUA7 zIktRk$+L%_eZoiv-2Rn6UJ;PP()3~|@Q8kJ(~l>Lic3n%$}1|Xs%vWN>Kl?%8mCU1 ze%g%F&o~nZ-8}28*>hUvo_$X1xoz{>JLWG~xM=Z`rOP_cTYmnEH>|wi!d0s;T66K* zH(v6lb(dat`4v~LziPwP*Sxvw+Uu_0c*9%Xx~W@k`I~pV^L=-H#co%Qm@B{se^W^xop#?mgf=>OJKh^IndX#X4i_VFJDoYZqx*}U~va+UfX5}@Nn=6MZ@2kvK9;^IgRZZ2|RST=uRdrQuuIjJ4rRu#^AF29m z)qPb@Ru@&*Ri9CPcJ<=w3#%`yzOH&p^_|rpufC`Hf$DEpKUV$Ynu?mWH5+O+)%4cv zt{JJhr{+k_^EJP(8Lus?ol-lq_Qu+~Ywxdpxc1T7Cu@(^9Yfr$?+)-Q|3=uG3Bx;4^25TcuJJ=&>-eB|V!Xmny|UU*o!n#Edab}HZCk&fwmG>V*_=(|1=Da={`T$>v%d$>v3REJDvk3lgZyvO7QK zES$fiszme!xWdfq=kFmQtbU^q;GdB9(m?_)ADB zxUH3>Oe06NO^cdTK26CcpK@wS&Q-acz-TlF48W;#9G*$u+ly+w*vs-E$_+B`)DDcT zK)Y%IKGcs}l3>;vWT^&*&S^Bf#Hu9X9Ik^jjeI~}ixbzw%TYYenEpN^9u$E0jY zGoJ>o^2pF;yuEq+oTmC|CQq~w%Nt6x%+N-Rl~@Y_Q|E!^2Tm{n6!lSh-qx(0XaRvIOJNHs~Y8pbtIa8(g9uc4mx$lI0&h#!iSGv6zVr3H5G##ezM!3bua>SjbCK#-X?g0%SP;z8%+=B7M1ha^8b1WmY5G-!E-eWwQe%4|)*;$7 zFH$~LN%(>cE#44JR7s!=`w#7)Ku4sRz+w4So1|;B!^>a*3 zO%X;ld}M)6qfxA+l{=iH7djrC1gTyX9CQH<$AE8G8Ds51xhZm}Z9rjzJQTTJ%UB#| z;#eTAgQ;nTu_dY_MfX~0#Q1vXqcn2&2~|Yvr0$(_f;XjWW2%c-Kmd(aL?U=mEpQrk z0G-&_)uhxlLX$@XZl*IFj%Q7A7`!;lctsY$ATyBIx*k;BvN zwDRWVn}`&0WH86_0zOm{$mleN8SEuelXutv=b#9Zg=r!|9Kp!^1HX)UrhRFoeY0(i z3{aa6M)1pIX+}!OKfn_tg^|px_GTd>I1h6UikPBTEyAMrDwl;kMzj@Z${$fB?V+`k zNA*F?8`P&MB|t3LH}Nu(3#jfWYudd^$ss&?jM2L$;*!hu)aqRhV&bLo0Q#;*svy4s z2QF~3z{E{+ltEaCW;?Lah-|TUNUJ2e83lk9Yb)v_PNtg2n8;deb4ktvJW-3y2(Nj= z@`{2`KmY^Y-fa4n{SldvuC-@IEJI5zLS++%e-p7lj-Cw1i|E_oLLk||TOo}Q1B`FM z1OvB>_@$4mRr?1XWpopG6M89vaBy7|pE7p1ypwZ*j7)kL-pw_Qu4~A<>u-c$ zzRhCNATs<*F|c4gMeWduC*`V{(X7wlaNf%d{ zQxNs(zvhVK%MoVPE{tJ>$;$X4wLXZQn#L4fO%`q(Bg+VRaIOvnmsC<=JaD;iBY9^$ zXC8b$M9afvRYV6;1N@!fmo5t(c@hK?iWjWMbO%7!JcylWoJD*aLHfc~2@R!S9dVvV zzIAN}nveuzD!Z6DYb?+{YFEs3X;(mTuHH}X;f^fkgB4Q2S}>a5G(!Hg6UVgr9Yz{O zfwG4IV>b@D(}~7Y?y)M)lLJsu?^9C#NE$P8erxk9u7tH6@evk=c*K7; zk0jWt5DiLkBE)8F(!;`ZNfFH*LX1-F5Utfu>}na|9@4_*3i6YRAXm=M^N3BaInI+B zfqMcEv}7|E&Igl^%)+n$Re-h0WD#e2EBpNsjdtWa%n#IVhy->;4K!H|)1j=$qqQxa9}$>YUNl>X05J{D zWDJF|$e~cM2V!v%^um0BxJ3IgA0s$-Wx^3Qq$(%}llrUtIS=Qv%ox=EwXY%~gstmH zKNZ*=RwJ+#A|B8cb_0!@Ji#C;#mvOymHlu)1r_86R>n#LS)c94OpbPq4Ki zvMX47yb4z|K&$IOzHTp2Q6_<&&RSka4Ck&R|1rEUPb7cN z*HXIYN$SegWWENSU?GIWjveh6i8l4;)=A2Du+L8)#yG?%HxBax z%9taNV}7(~$FV1l0}P6d2G1Y@EG4xj9EyDKE|7r>lZwxcEBqnuV?V|2n^a32dmN(& zm0p0&#tz&{4AiK5vx`gLC#hRQAl7LsJG}Icikp&?4$oSM<_s(8ObMNeh+)}ku-Dk(XIM>CB z=u{Vd1U`Ez{+blS)gEZGQQjIUVIDT(s^vu)G`6B_B4&ghk!1v z%jn3YKk#0Vvp8;ZA4D1Mx}&}FLT#&fG;w0*yypjyOf=RTzcDtg{-U&ln5j=BOkN1A zv5{IWQ!$kh9?_B*0H##8Hd=CR2wU(f~RJ7OP^2=z5O4NUGQmeNk!K_+3*iGieJ4IiC7V{6NhdS;f6h zw4G(z(wDS;;1ug0%(%ZUv;_NkssdsDCUvFf8fP>&plUzC+bqddvOcNmuy{}hQK4vN4ZA^ze|jrWz+p&at< zprb$zPCoMs>YaQF>z#bU`h5CfeZHNcUh^CC9C6Zpi||Hh{(&Up^_du2=#+hBeMiYxPT5=rNGbL)GsNy_o&H9iL5BQO0#IyE>;oOLB zPXWSD6+RuD)R%$rdG$`lh4oIx(fX(jM(c?cj?QvU)nJJFnP&Hz7pTt`;3Mb63>IE# zgoa;-!X5)3HMx+@J18w`ga}S);W|V;O3*kX0w9wB*rSQulo}4M6!nLtu>GjEKRTfvegyj46nXRL0|#fz(;RL0&X!&rkCoS5nUcLa$@R;-4wIR1d|4MsUd~8G$FH?h7B0q zbx`vKlv&J-o72L)E`0Kut z#k|0dncHjrtrm>_e+lMspbAKeYhU$xW8knOhiyj3>Q`N-kkQ0?BcuHK(1wC~T@TTQ zjI1}3K6M|glU^IUdYc0}`YmC-%G}V8_?vC-_&?jU4`gWgzhnacuKhV7{X99m z2|etZT5SxgDP3_f2g9vNWp^%a;Muns8&>U}?3rDEjV)XmHiDAdNiuO3riPCRBq;bJ z8cWOuWWiWYE|DB3A{X^zgArwa>#5-+>ZvFk(5iV)n!GV#PE$ zU9c8o{>mAcC}ERsRJL&v$I8^93u0*8eC4Ui^XBR zwl{Wg&4l(&o`vm=ot?V<5=Y-3v33mqg&n`y)myvdTQT&jrD47Db42|FeZu;@wMnFX zB!=g;&s*ax59#E|?fkGlBDWhjF06y=&~WV=>=@8W1IvU_pgd`NV6A3I%wKhlLbIaz zqKDFl9Yu02#dT--x<{j_Q?!fOUt&xQ{D-}QQJ9}8BBPUj{1FbO!_gVjIHBx#tIdo;CcL-`^4kZM|s^4B=Y|pz)lcVb-ZCORUEs5sYi{ zc`%0U1wN$X6A?I&&eP_&y4S01(cbJsaSfn-w3q1zkH;0KNX+A}HLQ#%0VWVSFYYaX zC;a9KcZFxmbL~Ds8J*(?6mvq{Gkaq0ceG37Jb43F{eecAVN!xkR>P5NMN79v;u)Bu zR^Zyi*BQC%Hz6zdXr>ulnRGq4WO9y!60m1AA6-_t8kmay?lqc|=qeR*5BPHHHc*Ow zbRA$9Xi5ii!PY^LrnQ33HSRAL`CHMfqY>T`YZEbbe$)0#Hc-LTq>Q4Eu>!|*ZI%b`bt?5-)75IvN4{O^^%cZ9Nn@5-)Tw7X1N*Pm!Rfm*@e0c zt}enmINh>Uc51s6-u_&R(vaRCmSI_g9f#erOcrBhoYFUHqIb6hcT;jb`VGqsXf=rb z11JxGb{}fDgAd+MYb{&!pwuTTumhIDz3sTppsnL`C(3Em4B>7!j#Vge9>Zu!zFEWm zeLBJpTwkZH2T*Fky;ah#+;&JCN``CBWe_8D;!TEm7%!iq;m6Ty1KlCWWL^PpJ5Y0r z9ci8z>hmy*HXXM|$DEH5+aa%Wg{2PUJ8dHCGrgJa9hr1$^UbMCx^Lc<$)qmo@7}tz zdq=8eZTHZw%<%AfPRx=_k#d{prk5synr6DAPT>eOD&6YM`%gpnpf|y3Ei(s%6!x_PME!wsw#n9v(SrI^MQkpFJXpW3_} z(xir{6-rC4*uFc{o4R~3Gt@mifNPo`&8inoc$wL{v$vb=0wRSZI@Q?vL6AmA1!SPE zP>dZAC>6R8!bRGz1G@1#*9`PShC^F3oyu%Sdt3X$bJ;2w?ltgy%CSyGvv3OeOvzv1 zYw~C9L;}B}^gFTR_1E)Cp{WfIbiOuA#LMwe)&Jc)`(8@=oOJEgTjGe|(ybWItw62sY?DE$jN325z(|{)}Q?Oez74I=k$J;71 zu%MZO=&c?e}Ex?tt@dj2a%)Si>L{yoNx3Lz=BB1gTAj~pYzKQF(Q!}1F}3Hv$T9{s9(O&*eO%AIKR`+xd4fGeK&FLa@%IK;5;;>!$)<}76 zq`WOsz9dqS6W_2!|>u1wKRJteLl+TOo4 tv6J8Ni*^nTaFX-eFYK`AC3^1YK*Gw8hqW9%!Q;iDKP*3w=ji`K@xP$By(|C# literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperator8-Bold.ttf b/html/styles/fonts/pixel-operator/PixelOperator8-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..10225eb8e3fc16375d26763fd3bf303ae7fefeaf GIT binary patch literal 18624 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 s$lqsU?X1oH_%;G? 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
n_A29){oBjp$#DJAx-N)jONtb?cSb9 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 literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorSC.ttf b/html/styles/fonts/pixel-operator/PixelOperatorSC.ttf new file mode 100644 index 0000000000000000000000000000000000000000..06783f817298fec9424a151f161574def024da33 GIT binary patch literal 16968 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 Sg2$61f0%zUkKzAU;eP;KEKPy{ literal 0 HcmV?d00001 diff --git a/html/styles/fonts/stylesheet.css b/html/styles/fonts/stylesheet.css new file mode 100644 index 0000000..687be9e --- /dev/null +++ b/html/styles/fonts/stylesheet.css @@ -0,0 +1,67 @@ +/* +@font-face { + font-family: 'pixel_operator_monoregular'; + src: url('pixeloperatormono-webfont.woff2') format('woff2'), + url('pixeloperatormono-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'pixel_operator_mono_8regular'; + src: url('pixeloperatormono8-webfont.woff2') format('woff2'), + url('pixeloperatormono8-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'pixel_operator_mono_8bold'; + src: url('pixeloperatormono8-bold-webfont.woff2') format('woff2'), + url('pixeloperatormono8-bold-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} + +@font-face { + font-family: 'pixel_operator_monobold'; + src: url('pixeloperatormono-bold-webfont.woff2') format('woff2'), + url('pixeloperatormono-bold-webfont.woff') format('woff'); + font-weight: normal; + font-style: normal; +} +*/ +body { + font-family: pixel_operator_monoregular; + background-color: lightgray; + color: blue; +} + +.header { + background-color: lightslategrey; +} + +h1 { + font-family: pixel_operator_monobold; + +} + +.wrapper { + display: grid; + grid-template-columns: auto auto auto; + grid-gap: 10px; + background-color: #2196F3; + padding: 10px; +} + +.wrapper > div { + background-color: rgba(255, 255, 255, 0.8); + text-align: center; + padding: 20px 0; + font-size: 30px; +} + +#item1 { + grid-column-start: 2; + grid-column-end: 3; +} \ No newline at end of file diff --git a/html/styles/pixeloperatormono-bold-webfont.woff b/html/styles/pixeloperatormono-bold-webfont.woff new file mode 100644 index 0000000000000000000000000000000000000000..40f690d0cdf2f245e4c580548bfe5d888de10654 GIT binary patch literal 13952 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 Lz#%~N4*>W-23w9* literal 0 HcmV?d00001 diff --git a/html/styles/pixeloperatormono-bold-webfont.woff2 b/html/styles/pixeloperatormono-bold-webfont.woff2 new file mode 100644 index 0000000000000000000000000000000000000000..76a19b05306f4b729c18b85e6f1846ee4bb2cf3d GIT binary patch literal 10148 zcmV;VCtKKePew8T0RR9104JmX5C8xG0GL<+04GEM0RR9100000000000000000000 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 ChVO#_ literal 0 HcmV?d00001 diff --git a/html/styles/stylesheet.css b/html/styles/stylesheet.css new file mode 100644 index 0000000..e15c511 --- /dev/null +++ b/html/styles/stylesheet.css @@ -0,0 +1,199 @@ +/* Basic body styling */ +body { + background-color: #222; + color: #eee; + font-family: sans-serif; + margin: 0; + padding: 0; + display: flex; /* Use flexbox to center wrapper */ + justify-content: center; + align-items: flex-start; /* Align wrapper to top */ + min-height: 100vh; +} + +/* Wrapper grid container */ +.wrapper { + display: grid; + /* Define grid areas */ + grid-template-areas: + "header header header" + "status game game" + "chat game game" + "chat game game" + "chat input input" + "footer footer footer"; + /* Define column sizes: status/chat column, game columns */ + grid-template-columns: 250px 1fr 1fr; /* Left sidebar fixed width, game takes remaining space */ + /* Define row sizes */ + grid-template-rows: auto auto 1fr 1fr auto auto; /* Header, status, chat rows, input, footer */ + gap: 10px; /* Spacing between grid items */ + padding: 10px; + max-width: 1400px; + width: 95%; + border: 1px solid #444; + background-color: #333; + height: 95vh; /* Set height to fill most of viewport */ +} + +/* Assign elements to grid areas */ +.header { + grid-area: header; + background-color: #444; + padding: 5px; +} + +.status { + grid-area: status; + background-color: #444; + padding: 10px; + font-weight: bold; +} + +.chat { + grid-area: chat; + background-color: #444; + padding: 10px; + display: flex; + flex-direction: column; + overflow: hidden; /* Prevent overflow */ +} + +.rotdis { + grid-area: game; + background-color: #111; + display: flex; + justify-content: center; + align-items: center; + overflow: hidden; +} + +/* Make ROT.js canvas display properly */ +.rotdis canvas { + display: block; + max-width: 100%; + max-height: 100%; + object-fit: contain; /* Preserve aspect ratio */ +} + +#messageInput { + grid-area: input; + background-color: #444; + padding: 10px; +} + +.footer { + grid-area: footer; + background-color: #444; + padding: 5px; + text-align: center; +} + +/* Header styling */ +.header h1 { + margin: 0; + padding: 5px; + text-align: center; +} + +/* Status styling */ +#blockheight { + color: lightblue; +} + +/* Chat box styling */ +#messageBox { + flex-grow: 1; /* Allow message box to fill chat area */ + border: 1px solid #555; + background-color: #2a2a2a; + overflow-y: auto; /* Enable vertical scrolling */ + height: 100%; /* Fill available height */ + margin-bottom: 5px; +} + +#messages { + list-style-type: none; + margin: 0; + padding: 5px; +} + +#messages li { + padding: 2px 0; + border-bottom: 1px dashed #444; + font-size: 0.9em; +} + +/* Chat input styling */ +#chatForm { + display: flex; +} + +#chatInput { + flex-grow: 1; + padding: 5px; + border: 1px solid #555; + background-color: #eee; + color: #111; +} + +#chatForm button { + padding: 5px 10px; + border: 1px solid #555; + background-color: #666; + color: #eee; + cursor: pointer; +} + +#chatForm button:hover { + background-color: #777; +} + +/* Teletype styling */ +#staticbanner { + margin: 0; + padding: 5px; + text-align: left; + font-size: 24px; + color: #fff; +} + +#banner { + display: inline-block; + min-height: 1em; +} + +#bannercursor { + display: inline-block; + color: #fff; +} + +/* Add these styles for chat messages */ + +#messages li.self-command { + color: #aaf; + font-style: italic; +} + +#messages li.payment { + color: #ff0; + font-weight: bold; + border-left: 3px solid #ff0; + padding-left: 5px; + margin: 5px 0; +} + +#messages li.win { + color: #0f0; + font-weight: bold; +} + +#messages li.lose { + color: #f00; + font-weight: bold; +} + +#messages li.game-start { + color: #0ff; + font-weight: bold; + margin: 5px 0; +} + diff --git a/html/styles/test.css b/html/styles/test.css new file mode 100644 index 0000000..8d7d127 --- /dev/null +++ b/html/styles/test.css @@ -0,0 +1,3 @@ +body { + color: green; +} \ No newline at end of file diff --git a/html/test.html b/html/test.html new file mode 100644 index 0000000..ad1f55a --- /dev/null +++ b/html/test.html @@ -0,0 +1,24 @@ + + + + Wowgue + + + + + + +
+

Welcome traveler...

+
+
+
1
+
2
+
3
+
4
+
5
+
6sssssssssssssssssssssssss
+
+ + + \ No newline at end of file diff --git a/html/tiles.png b/html/tiles.png new file mode 100644 index 0000000000000000000000000000000000000000..3e8101c75dc2c8925b05ba98e4fd9131e4663633 GIT binary patch literal 26448 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 literal 0 HcmV?d00001 diff --git a/html/tiles.xcf b/html/tiles.xcf new file mode 100644 index 0000000000000000000000000000000000000000..2fbed9da02d6b40fa873176856490e6210837586 GIT binary patch literal 162113 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 Sfi& user.socketid === socketId); +} + +// Modified block check function +setInterval(function() { + rpc.daemonCall("get_block_count", "", function(result) { + const currentHeight = result.result.count; + rpc.lastBlock.setHeight(currentHeight); + + // If new block found + if (currentHeight > lastBlockHeight) { + console.log(`New block found: ${currentHeight}`); + io.emit('blockheight', currentHeight); + + // Start games for waiting players + startGamesForWaiting(currentHeight); + + // Check active games for timeout + checkGamesTimeout(currentHeight); + + lastBlockHeight = currentHeight; + } else { + io.emit('blockheight', currentHeight); + } + }); +}, 10000); + +// Start games for waiting players +function startGamesForWaiting(blockHeight) { + while (WAITING_PLAYERS.length > 0) { + const userId = WAITING_PLAYERS.shift(); + const user = getUserBySocket(userId); + + if (user) { + user.blockRec = blockHeight; + const game = user.startGame(80, 40); // Create a new game + activeGames.set(userId, game); + + io.to(userId).emit('game_start', { + map: game.dungeon.map, + player: game.player, + monster: game.monster, + entrance: game.dungeon.entrance, + exit: game.dungeon.exit, + treasure: game.dungeon.treasure, + blockHeight: blockHeight + }); + } + } +} + +// Check if any active games have timed out +function checkGamesTimeout(currentHeight) { + activeGames.forEach((game, socketId) => { + const user = getUserBySocket(socketId); + + if (user && user.blockRec && currentHeight > user.blockRec + 1) { + // Game has timed out - player didn't escape in time + game.gameState = 'lost'; + io.to(socketId).emit('game_over', { + status: 'lost', + reason: 'timeout', + message: 'You didn\'t escape before the next block was found!' + }); + + activeGames.delete(socketId); + } + }); +} + +// Socket.io handlers +io.on('connection', function(socket) { + console.log('A user connected'); + console.log(socket.client.id); + console.log(socket.handshake.address); + + db.insertVisitor(socket.client.id, socket.handshake.address, 0); + users.push(new user.User(socket.client.id, socket.handshake.address)); + + io.to(`${socket.client.id}`).emit('welcome', socket.client.id); + + socket.on('chat message', function(msg) { + console.log(msg); + + if (msg.toLowerCase() == 'hello') { + io.to(`${socket.client.id}`).emit('message', + 'Welcome, to enter the dungeon type Enter, and you will be given a Wownero address, ' + + 'which you must send between 10-100 WOW to enter. The more you send, the more you can win.'); + } + else if (msg.toLowerCase() == 'enter') { + const currentUser = getUserBySocket(socket.client.id); + + if (currentUser) { + // FOR TESTING: Skip payment and directly queue the player + currentUser.verifyPayment(10); // Minimal test fee + WAITING_PLAYERS.push(socket.client.id); + + io.to(`${socket.client.id}`).emit('message', + 'For testing: You will enter the dungeon when the next block is found.'); + + // To test without waiting for a block, immediately start a game + startGameForPlayer(socket.client.id, lastBlockHeight || 1); + } + } + else { + io.emit('message', msg); + } + }); + + // Handle player movement + socket.on('move', function(direction) { + const game = activeGames.get(socket.client.id); + + if (game) { + let dx = 0, dy = 0; + + // Convert direction to dx,dy + switch(direction) { + case 'up': dy = -1; break; + case 'down': dy = 1; break; + case 'left': dx = -1; break; + case 'right': dx = 1; break; + } + + const result = game.movePlayer(dx, dy); + + // Send updated game state + socket.emit('game_update', { + player: game.player, + monster: game.monster, + status: result.status + }); + + // Handle win/lose conditions + if (result.status === 'won') { + const user = getUserBySocket(socket.client.id); + const reward = user.calculateReward(); + + socket.emit('game_over', { + status: 'won', + hasTreasure: game.player.hasTreasure, + reward: reward + }); + + // TODO: Process payout + + activeGames.delete(socket.client.id); + } + else if (result.status === 'lost') { + socket.emit('game_over', { + status: 'lost', + reason: result.reason + }); + + activeGames.delete(socket.client.id); + } + } + }); + + // Handle disconnection + socket.on('disconnect', function () { + console.log('A user disconnected'); + + // Clean up any active games + if (activeGames.has(socket.client.id)) { + activeGames.delete(socket.client.id); + } + + users = spliceOut(socket.client.id, "socketid", users); + }); +}); + +http.listen(3000, function() { + console.log('listening on *:3000'); +}); + + +// Remove objects from an array if one attribute matches +function spliceOut(target, field, array) { + for (var i = array.length - 1; i >= 0; --i) { + if (array[i][field] == target) { + array.splice(i,1); + } + } + return array; +} +// Check if objects are in an array if one attribute matches +function checkArray(target, field, array) { + for (var i = array.length - 1; i >= 0; --i) { + if (array[i][field] == target) { + return true; + } + } + return false; +} + +// Add this function to generate a dungeon +function generateDungeon(width, height) { + // Create a new instance of ROT.Map.Digger + const digger = new ROT.Map.Digger(width, height, { + roomWidth: [3, 9], + roomHeight: [3, 5], + corridorLength: [2, 5], + dugPercentage: 0.2 + }); + + // Create a map representation + const map = Array(height).fill().map(() => Array(width).fill(1)); // 1 = wall + + // Callback to dig out rooms and corridors + digger.create((x, y, value) => { + map[y][x] = value; // 0 = floor, 1 = wall + }); + + // Get rooms and place special features + const rooms = digger.getRooms(); + let entrance = null; + let exit = null; + let treasure = null; + + if (rooms.length > 0) { + // Place entrance in the first room + entrance = rooms[0].getCenter(); + + // Place exit in the last room + exit = rooms[rooms.length-1].getCenter(); + + // Place treasure in a middle room + const treasureRoom = rooms[Math.floor(rooms.length/2)]; + treasure = treasureRoom.getCenter(); + } + + return { + map: map, + entrance: entrance, + exit: exit, + treasure: treasure, + rooms: rooms + }; +} + +// Add this helper function to start a game for a specific player immediately: +function startGameForPlayer(socketId, blockHeight) { + const user = getUserBySocket(socketId); + + if (user) { + user.blockRec = blockHeight; + const game = user.startGame(25, 19); // Create a new game with dimensions matching our display + activeGames.set(socketId, game); + + io.to(socketId).emit('game_start', { + map: game.dungeon.map, + player: game.player, + monster: game.monster, + entrance: game.dungeon.entrance, + exit: game.dungeon.exit, + treasure: game.dungeon.treasure, + blockHeight: blockHeight + }); + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..30547ec --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1597 @@ +{ + "name": "bitrogue", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "bitrogue", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "axios": "^1.9.0", + "express": "^4.17.1", + "pg": "^8.15.5", + "request": "^2.88.0", + "socket.io": "^4.8.1" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==" + }, + "node_modules/@types/cors": { + "version": "2.8.17", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", + "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/node": { + "version": "22.15.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.0.tgz", + "integrity": "sha512-99S8dWD2DkeE6PBaEDw+In3aar7hdoBvjyJMR6vaKBTzpvR0P00ClzJMOoVrj9D2+Sy/YCwACYHnBTpMhg1UCA==", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==" + }, + "node_modules/axios": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.9.0.tgz", + "integrity": "sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/engine.io": { + "version": "6.6.4", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.4.tgz", + "integrity": "sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.17.1" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/engine.io/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==" + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" + }, + "node_modules/pg": { + "version": "8.15.5", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.15.5.tgz", + "integrity": "sha512-EpAhHFQc+aH9VfeffWIVC+XXk6lmAhS9W1FxtxcPXs94yxhrI1I6w/zkWfIOII/OkBv3Be04X3xMOj0kQ78l6w==", + "dependencies": { + "pg-connection-string": "^2.8.5", + "pg-pool": "^3.9.5", + "pg-protocol": "^1.9.5", + "pg-types": "^2.1.0", + "pgpass": "1.x" + }, + "engines": { + "node": ">= 8.0.0" + }, + "optionalDependencies": { + "pg-cloudflare": "^1.2.5" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } + } + }, + "node_modules/pg-cloudflare": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.2.5.tgz", + "integrity": "sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg==", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.8.5.tgz", + "integrity": "sha512-Ni8FuZ8yAF+sWZzojvtLE2b03cqjO5jNULcHFfM9ZZ0/JXrgom5pBREbtnAw7oxsxJqHw9Nz/XWORUEL3/IFow==" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pg-pool": { + "version": "3.9.5", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.9.5.tgz", + "integrity": "sha512-DxyAlOgvUzRFpFAZjbCc8fUfG7BcETDHgepFPf724B0i08k9PAiZV1tkGGgQIL0jbMEuR9jW1YN7eX+WgXxCsQ==", + "peerDependencies": { + "pg": ">=8.0" + } + }, + "node_modules/pg-protocol": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.9.5.tgz", + "integrity": "sha512-DYTWtWpfd5FOro3UnAfwvhD8jh59r2ig8bPtc9H8Ds7MscE/9NYruUQWFAOuraRl29jwcT2kyMFQ3MxeaVjUhg==" + }, + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "dependencies": { + "split2": "^4.1.0" + } + }, + "node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", + "dependencies": { + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/psl": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "dependencies": { + "punycode": "^2.3.1" + }, + "funding": { + "url": "https://github.com/sponsors/lupomontero" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/request/node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.5", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.5.tgz", + "integrity": "sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==", + "dependencies": { + "debug": "~4.3.4", + "ws": "~8.17.1" + } + }, + "node_modules/socket.io-adapter/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-adapter/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io-parser/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socket.io/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/sshpk": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==" + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==" + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/ws": { + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..3a569eb --- /dev/null +++ b/package.json @@ -0,0 +1,19 @@ +{ + "name": "bitrogue", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "node index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "jw", + "license": "ISC", + "dependencies": { + "axios": "^1.9.0", + "express": "^4.17.1", + "pg": "^8.15.5", + "request": "^2.88.0", + "socket.io": "^4.8.1" + } +} diff --git a/rot.js b/rot.js new file mode 100644 index 0000000..03f3919 --- /dev/null +++ b/rot.js @@ -0,0 +1,7228 @@ +function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } + +function _inheritsLoose(subClass, superClass) { subClass.prototype = Object.create(superClass.prototype); subClass.prototype.constructor = subClass; subClass.__proto__ = superClass; } + +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : 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() { + this._ctx.fillStyle = this._options.bg; + + this._ctx.fillRect(0, 0, this._ctx.canvas.width, this._ctx.canvas.height); + }; + + _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({ + 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({ + 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); + + TileGL.isSupported = function isSupported() { + return !!document.createElement("canvas").getContext("webgl2", { + preserveDrawingBuffer: true + }); + }; + + function TileGL() { + var _this5; + + _this5 = _Backend2.call(this) || this; + _this5._uniforms = {}; + + try { + _this5._gl = _this5._initWebGL(); + } catch (e) { + alert(e.message); + } + + return _this5; + } + + 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= 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) { + if (!(color in colorCache)) { + var parsed; + + if (color == "transparent") { + parsed = [0, 0, 0, 0]; + } else if (color.indexOf("rgba") > -1) { + parsed = (color.match(/[\d.]+/g) || []).map(Number); + + for (var i = 0; i < 3; i++) { + parsed[i] = parsed[i] / 255; + } + } else { + parsed = fromString(color).map(function ($) { + return $ / 255; + }); + parsed.push(1); + } + + colorCache[color] = parsed; + } + + return colorCache[color]; + } + + 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) { + var SRC_COLORS = 256.0; + var DST_COLORS = 6.0; + var COLOR_RATIO = DST_COLORS / SRC_COLORS; + var rgb = fromString(color); + 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; + } // 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 */ + lineLength = 0; + lastTokenWithSpace = -1; + } + + if (token.type != TYPE_TEXT) { + /* skip non-text tokens */ + i++; + continue; + } + /* remove spaces at the beginning of line */ + + + while (lineLength == 0 && token.value.charAt(0) == " ") { + token.value = token.value.substring(1); + } + /* forced newline? insert two new tokens after this one */ + + + var _index2 = token.value.indexOf("\n"); + + if (_index2 != -1) { + token.value = breakInsideToken(tokens, i, _index2, true); + /* if there are spaces at the end, we must remove them (we do not want the line too long) */ + + var arr = token.value.split(""); + + while (arr.length && arr[arr.length - 1] == " ") { + arr.pop(); + } + + token.value = arr.join(""); + } + /* token degenerated? */ + + + if (!token.value.length) { + tokens.splice(i, 1); + continue; + } + + if (lineLength + token.value.length > maxWidth) { + /* line too long, find a suitable breaking spot */ + + /* is it possible to break within this token? */ + var _index3 = -1; + + while (1) { + var nextIndex = token.value.indexOf(" ", _index3 + 1); + + if (nextIndex == -1) { + break; + } + + if (lineLength + nextIndex > maxWidth) { + break; + } + + _index3 = nextIndex; + } + + if (_index3 != -1) { + /* break at space within this one */ + token.value = breakInsideToken(tokens, i, _index3, true); + } else if (lastTokenWithSpace != -1) { + /* is there a previous token where a break can occur? */ + var _token = tokens[lastTokenWithSpace]; + + var breakIndex = _token.value.lastIndexOf(" "); + + _token.value = breakInsideToken(tokens, lastTokenWithSpace, breakIndex, true); + i = lastTokenWithSpace; + } else { + /* force break in this token */ + token.value = breakInsideToken(tokens, i, maxWidth - lineLength, false); + } + } else { + /* line not long, continue */ + lineLength += token.value.length; + + if (token.value.indexOf(" ") != -1) { + lastTokenWithSpace = i; + } + } + + i++; + /* advance to next token */ + } + + tokens.push({ + type: TYPE_NEWLINE + }); + /* insert fake newline to fix the last text line */ + + /* remove trailing space from text tokens before newlines */ + + var lastTextToken = null; + + for (var _i = 0; _i < tokens.length; _i++) { + var _token2 = tokens[_i]; + + switch (_token2.type) { + case TYPE_TEXT: + lastTextToken = _token2; + break; + + case TYPE_NEWLINE: + if (lastTextToken) { + /* remove trailing space */ + var _arr = lastTextToken.value.split(""); + + while (_arr.length && _arr[_arr.length - 1] == " ") { + _arr.pop(); + } + + lastTextToken.value = _arr.join(""); + } + + lastTextToken = null; + break; + } + } + + tokens.pop(); + /* remove fake token */ + + return tokens; + } + /** + * Create new tokens and insert them into the stream + * @param {object[]} tokens + * @param {int} tokenIndex Token being processed + * @param {int} breakIndex Index within current token's value + * @param {bool} removeBreakChar Do we want to remove the breaking character? + * @returns {string} remaining unbroken token value + */ + + + function breakInsideToken(tokens, tokenIndex, breakIndex, removeBreakChar) { + var newBreakToken = { + type: TYPE_NEWLINE + }; + var newTextToken = { + type: TYPE_TEXT, + value: tokens[tokenIndex].value.substring(breakIndex + (removeBreakChar ? 1 : 0)) + }; + tokens.splice(tokenIndex + 1, 0, newBreakToken, newTextToken); + return tokens[tokenIndex].value.substring(0, breakIndex); + } + + var text = + /*#__PURE__*/ + Object.freeze({ + TYPE_TEXT: TYPE_TEXT, + TYPE_NEWLINE: TYPE_NEWLINE, + TYPE_FG: TYPE_FG, + TYPE_BG: TYPE_BG, + measure: measure, + tokenize: tokenize + }); + /** Default with for display and map generators */ + + var DEFAULT_WIDTH = 80; + /** Default height for display and map generators */ + + var DEFAULT_HEIGHT = 25; + var DIRS = { + 4: [[0, -1], [1, 0], [0, 1], [-1, 0]], + 8: [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]], + 6: [[-1, -1], [1, -1], [2, 0], [1, 1], [-1, 1], [-2, 0]] + }; + var KEYS = { + /** Cancel key. */ + VK_CANCEL: 3, + + /** Help key. */ + VK_HELP: 6, + + /** Backspace key. */ + VK_BACK_SPACE: 8, + + /** Tab key. */ + VK_TAB: 9, + + /** 5 key on Numpad when NumLock is unlocked. Or on Mac, clear key which is positioned at NumLock key. */ + VK_CLEAR: 12, + + /** Return/enter key on the main keyboard. */ + VK_RETURN: 13, + + /** Reserved, but not used. */ + VK_ENTER: 14, + + /** Shift key. */ + VK_SHIFT: 16, + + /** Control key. */ + VK_CONTROL: 17, + + /** Alt (Option on Mac) key. */ + VK_ALT: 18, + + /** Pause key. */ + VK_PAUSE: 19, + + /** Caps lock. */ + VK_CAPS_LOCK: 20, + + /** Escape key. */ + VK_ESCAPE: 27, + + /** Space bar. */ + VK_SPACE: 32, + + /** Page Up key. */ + VK_PAGE_UP: 33, + + /** Page Down key. */ + VK_PAGE_DOWN: 34, + + /** End key. */ + VK_END: 35, + + /** Home key. */ + VK_HOME: 36, + + /** Left arrow. */ + VK_LEFT: 37, + + /** Up arrow. */ + VK_UP: 38, + + /** Right arrow. */ + VK_RIGHT: 39, + + /** Down arrow. */ + VK_DOWN: 40, + + /** Print Screen key. */ + VK_PRINTSCREEN: 44, + + /** Ins(ert) key. */ + VK_INSERT: 45, + + /** Del(ete) key. */ + VK_DELETE: 46, + + /***/ + VK_0: 48, + + /***/ + VK_1: 49, + + /***/ + VK_2: 50, + + /***/ + VK_3: 51, + + /***/ + VK_4: 52, + + /***/ + VK_5: 53, + + /***/ + VK_6: 54, + + /***/ + VK_7: 55, + + /***/ + VK_8: 56, + + /***/ + VK_9: 57, + + /** Colon (:) key. Requires Gecko 15.0 */ + VK_COLON: 58, + + /** Semicolon (;) key. */ + VK_SEMICOLON: 59, + + /** Less-than (<) key. Requires Gecko 15.0 */ + VK_LESS_THAN: 60, + + /** Equals (=) key. */ + VK_EQUALS: 61, + + /** Greater-than (>) key. Requires Gecko 15.0 */ + VK_GREATER_THAN: 62, + + /** Question mark (?) key. Requires Gecko 15.0 */ + VK_QUESTION_MARK: 63, + + /** Atmark (@) key. Requires Gecko 15.0 */ + VK_AT: 64, + + /***/ + VK_A: 65, + + /***/ + VK_B: 66, + + /***/ + VK_C: 67, + + /***/ + VK_D: 68, + + /***/ + VK_E: 69, + + /***/ + VK_F: 70, + + /***/ + VK_G: 71, + + /***/ + VK_H: 72, + + /***/ + VK_I: 73, + + /***/ + VK_J: 74, + + /***/ + VK_K: 75, + + /***/ + VK_L: 76, + + /***/ + VK_M: 77, + + /***/ + VK_N: 78, + + /***/ + VK_O: 79, + + /***/ + VK_P: 80, + + /***/ + VK_Q: 81, + + /***/ + VK_R: 82, + + /***/ + VK_S: 83, + + /***/ + VK_T: 84, + + /***/ + VK_U: 85, + + /***/ + VK_V: 86, + + /***/ + VK_W: 87, + + /***/ + VK_X: 88, + + /***/ + VK_Y: 89, + + /***/ + VK_Z: 90, + + /***/ + VK_CONTEXT_MENU: 93, + + /** 0 on the numeric keypad. */ + VK_NUMPAD0: 96, + + /** 1 on the numeric keypad. */ + VK_NUMPAD1: 97, + + /** 2 on the numeric keypad. */ + VK_NUMPAD2: 98, + + /** 3 on the numeric keypad. */ + VK_NUMPAD3: 99, + + /** 4 on the numeric keypad. */ + VK_NUMPAD4: 100, + + /** 5 on the numeric keypad. */ + VK_NUMPAD5: 101, + + /** 6 on the numeric keypad. */ + VK_NUMPAD6: 102, + + /** 7 on the numeric keypad. */ + VK_NUMPAD7: 103, + + /** 8 on the numeric keypad. */ + VK_NUMPAD8: 104, + + /** 9 on the numeric keypad. */ + VK_NUMPAD9: 105, + + /** * on the numeric keypad. */ + VK_MULTIPLY: 106, + + /** + on the numeric keypad. */ + VK_ADD: 107, + + /***/ + VK_SEPARATOR: 108, + + /** - on the numeric keypad. */ + VK_SUBTRACT: 109, + + /** Decimal point on the numeric keypad. */ + VK_DECIMAL: 110, + + /** / on the numeric keypad. */ + VK_DIVIDE: 111, + + /** F1 key. */ + VK_F1: 112, + + /** F2 key. */ + VK_F2: 113, + + /** F3 key. */ + VK_F3: 114, + + /** F4 key. */ + VK_F4: 115, + + /** F5 key. */ + VK_F5: 116, + + /** F6 key. */ + VK_F6: 117, + + /** F7 key. */ + VK_F7: 118, + + /** F8 key. */ + VK_F8: 119, + + /** F9 key. */ + VK_F9: 120, + + /** F10 key. */ + VK_F10: 121, + + /** F11 key. */ + VK_F11: 122, + + /** F12 key. */ + VK_F12: 123, + + /** F13 key. */ + VK_F13: 124, + + /** F14 key. */ + VK_F14: 125, + + /** F15 key. */ + VK_F15: 126, + + /** F16 key. */ + VK_F16: 127, + + /** F17 key. */ + VK_F17: 128, + + /** F18 key. */ + VK_F18: 129, + + /** F19 key. */ + VK_F19: 130, + + /** F20 key. */ + VK_F20: 131, + + /** F21 key. */ + VK_F21: 132, + + /** F22 key. */ + VK_F22: 133, + + /** F23 key. */ + VK_F23: 134, + + /** F24 key. */ + VK_F24: 135, + + /** Num Lock key. */ + VK_NUM_LOCK: 144, + + /** Scroll Lock key. */ + VK_SCROLL_LOCK: 145, + + /** Circumflex (^) key. Requires Gecko 15.0 */ + VK_CIRCUMFLEX: 160, + + /** Exclamation (!) key. Requires Gecko 15.0 */ + VK_EXCLAMATION: 161, + + /** Double quote () key. Requires Gecko 15.0 */ + VK_DOUBLE_QUOTE: 162, + + /** Hash (#) key. Requires Gecko 15.0 */ + VK_HASH: 163, + + /** Dollar sign ($) key. Requires Gecko 15.0 */ + VK_DOLLAR: 164, + + /** Percent (%) key. Requires Gecko 15.0 */ + VK_PERCENT: 165, + + /** Ampersand (&) key. Requires Gecko 15.0 */ + VK_AMPERSAND: 166, + + /** Underscore (_) key. Requires Gecko 15.0 */ + VK_UNDERSCORE: 167, + + /** Open parenthesis (() key. Requires Gecko 15.0 */ + VK_OPEN_PAREN: 168, + + /** Close parenthesis ()) key. Requires Gecko 15.0 */ + VK_CLOSE_PAREN: 169, + + /* Asterisk (*) key. Requires Gecko 15.0 */ + VK_ASTERISK: 170, + + /** Plus (+) key. Requires Gecko 15.0 */ + VK_PLUS: 171, + + /** Pipe (|) key. Requires Gecko 15.0 */ + VK_PIPE: 172, + + /** Hyphen-US/docs/Minus (-) key. Requires Gecko 15.0 */ + VK_HYPHEN_MINUS: 173, + + /** Open curly bracket ({) key. Requires Gecko 15.0 */ + VK_OPEN_CURLY_BRACKET: 174, + + /** Close curly bracket (}) key. Requires Gecko 15.0 */ + VK_CLOSE_CURLY_BRACKET: 175, + + /** Tilde (~) key. Requires Gecko 15.0 */ + VK_TILDE: 176, + + /** Comma (,) key. */ + VK_COMMA: 188, + + /** Period (.) key. */ + VK_PERIOD: 190, + + /** Slash (/) key. */ + VK_SLASH: 191, + + /** Back tick (`) key. */ + VK_BACK_QUOTE: 192, + + /** Open square bracket ([) key. */ + VK_OPEN_BRACKET: 219, + + /** Back slash (\) key. */ + VK_BACK_SLASH: 220, + + /** Close square bracket (]) key. */ + VK_CLOSE_BRACKET: 221, + + /** Quote (''') key. */ + VK_QUOTE: 222, + + /** Meta key on Linux, Command key on Mac. */ + VK_META: 224, + + /** AltGr key on Linux. Requires Gecko 15.0 */ + VK_ALTGR: 225, + + /** Windows logo key on Windows. Or Super or Hyper key on Linux. Requires Gecko 15.0 */ + VK_WIN: 91, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANA: 21, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANGUL: 21, + + /** 英数 key on Japanese Mac keyboard. Requires Gecko 15.0 */ + VK_EISU: 22, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_JUNJA: 23, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_FINAL: 24, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_HANJA: 25, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_KANJI: 25, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_CONVERT: 28, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_NONCONVERT: 29, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_ACCEPT: 30, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_MODECHANGE: 31, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SELECT: 41, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_PRINT: 42, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_EXECUTE: 43, + + /** Linux support for this keycode was added in Gecko 4.0. */ + VK_SLEEP: 95 + }; + var BACKENDS = { + "hex": Hex, + "rect": Rect, + "tile": Tile, + "tile-gl": TileGL, + "term": Term + }; + var DEFAULT_OPTIONS = { + width: DEFAULT_WIDTH, + height: DEFAULT_HEIGHT, + transpose: false, + layout: "rect", + fontSize: 15, + spacing: 1, + border: 0, + forceSquareRatio: false, + fontFamily: "monospace", + fontStyle: "", + fg: "#ccc", + bg: "#000", + tileWidth: 32, + tileHeight: 32, + tileMap: {}, + tileSet: null, + tileColorize: false + }; + /** + * @class Visual map display + */ + + var Display = + /*#__PURE__*/ + function () { + function Display(options) { + if (options === void 0) { + options = {}; + } + + this._data = {}; + this._dirty = false; // false = nothing, true = all, object = dirty cells + + this._options = {}; + options = Object.assign({}, DEFAULT_OPTIONS, options); + this.setOptions(options); + this.DEBUG = this.DEBUG.bind(this); + this._tick = this._tick.bind(this); + + this._backend.schedule(this._tick); + } + /** + * Debug helper, ideal as a map generator callback. Always bound to this. + * @param {int} x + * @param {int} y + * @param {int} what + */ + + + var _proto9 = Display.prototype; + + _proto9.DEBUG = function DEBUG(x, y, what) { + var colors = [this._options.bg, this._options.fg]; + this.draw(x, y, null, null, colors[what % colors.length]); + }; + /** + * Clear the whole display (cover it with background color) + */ + + + _proto9.clear = function clear() { + this._data = {}; + this._dirty = true; + }; + /** + * @see ROT.Display + */ + + + _proto9.setOptions = function setOptions(options) { + Object.assign(this._options, options); + + if (options.width || options.height || options.fontSize || options.fontFamily || options.spacing || options.layout) { + if (options.layout) { + var ctor = BACKENDS[options.layout]; + this._backend = new ctor(); + } + + this._backend.setOptions(this._options); + + this._dirty = true; + } + + return this; + }; + /** + * Returns currently set options + */ + + + _proto9.getOptions = function getOptions() { + return this._options; + }; + /** + * Returns the DOM node of this display + */ + + + _proto9.getContainer = function getContainer() { + return this._backend.getContainer(); + }; + /** + * Compute the maximum width/height to fit into a set of given constraints + * @param {int} availWidth Maximum allowed pixel width + * @param {int} availHeight Maximum allowed pixel height + * @returns {int[2]} cellWidth,cellHeight + */ + + + _proto9.computeSize = function computeSize(availWidth, availHeight) { + return this._backend.computeSize(availWidth, availHeight); + }; + /** + * Compute the maximum font size to fit into a set of given constraints + * @param {int} availWidth Maximum allowed pixel width + * @param {int} availHeight Maximum allowed pixel height + * @returns {int} fontSize + */ + + + _proto9.computeFontSize = function computeFontSize(availWidth, availHeight) { + return this._backend.computeFontSize(availWidth, availHeight); + }; + + _proto9.computeTileSize = function computeTileSize(availWidth, availHeight) { + var width = Math.floor(availWidth / this._options.width); + var height = Math.floor(availHeight / this._options.height); + return [width, height]; + }; + /** + * Convert a DOM event (mouse or touch) to map coordinates. Uses first touch for multi-touch. + * @param {Event} e event + * @returns {int[2]} -1 for values outside of the canvas + */ + + + _proto9.eventToPosition = function eventToPosition(e) { + var x, y; + + if ("touches" in e) { + x = e.touches[0].clientX; + y = e.touches[0].clientY; + } else { + x = e.clientX; + y = e.clientY; + } + + return this._backend.eventToPosition(x, y); + }; + /** + * @param {int} x + * @param {int} y + * @param {string || string[]} ch One or more chars (will be overlapping themselves) + * @param {string} [fg] foreground color + * @param {string} [bg] background color + */ + + + _proto9.draw = function draw(x, y, ch, fg, bg) { + if (!fg) { + fg = this._options.fg; + } + + if (!bg) { + bg = this._options.bg; + } + + var key = x + "," + y; + this._data[key] = [x, y, ch, fg, bg]; + + if (this._dirty === true) { + return; + } // will already redraw everything + + + if (!this._dirty) { + this._dirty = {}; + } // first! + + + this._dirty[key] = true; + }; + /** + * Draws a text at given position. Optionally wraps at a maximum length. Currently does not work with hex layout. + * @param {int} x + * @param {int} y + * @param {string} text May contain color/background format specifiers, %c{name}/%b{name}, both optional. %c{}/%b{} resets to default. + * @param {int} [maxWidth] wrap at what width? + * @returns {int} lines drawn + */ + + + _proto9.drawText = function drawText(x, y, text, maxWidth) { + var fg = null; + var bg = null; + var cx = x; + var cy = y; + var lines = 1; + + if (!maxWidth) { + maxWidth = this._options.width - x; + } + + var tokens = tokenize(text, maxWidth); + + while (tokens.length) { + // interpret tokenized opcode stream + var token = tokens.shift(); + + switch (token.type) { + case TYPE_TEXT: + var isSpace = false, + isPrevSpace = false, + isFullWidth = false, + isPrevFullWidth = false; + + for (var i = 0; i < token.value.length; i++) { + var cc = token.value.charCodeAt(i); + var c = token.value.charAt(i); // Assign to `true` when the current char is full-width. + + isFullWidth = cc > 0xff00 && cc < 0xff61 || cc > 0xffdc && cc < 0xffe8 || cc > 0xffee; // Current char is space, whatever full-width or half-width both are OK. + + isSpace = c.charCodeAt(0) == 0x20 || c.charCodeAt(0) == 0x3000; // The previous char is full-width and + // current char is nether half-width nor a space. + + if (isPrevFullWidth && !isFullWidth && !isSpace) { + cx++; + } // add an extra position + // The current char is full-width and + // the previous char is not a space. + + + if (isFullWidth && !isPrevSpace) { + cx++; + } // add an extra position + + + this.draw(cx++, cy, c, fg, bg); + isPrevSpace = isSpace; + isPrevFullWidth = isFullWidth; + } + + break; + + case TYPE_FG: + fg = token.value || null; + break; + + case TYPE_BG: + bg = token.value || null; + break; + + case TYPE_NEWLINE: + cx = x; + cy++; + lines++; + break; + } + } + + return lines; + }; + /** + * Timer tick: update dirty parts + */ + + + _proto9._tick = function _tick() { + this._backend.schedule(this._tick); + + if (!this._dirty) { + return; + } + + if (this._dirty === true) { + // draw all + this._backend.clear(); + + for (var id in this._data) { + this._draw(id, false); + } // redraw cached data + + } else { + // draw only dirty + for (var key in this._dirty) { + this._draw(key, true); + } + } + + this._dirty = false; + }; + /** + * @param {string} key What to draw + * @param {bool} clearBefore Is it necessary to clean before? + */ + + + _proto9._draw = function _draw(key, clearBefore) { + var data = this._data[key]; + + if (data[4] != this._options.bg) { + clearBefore = true; + } + + this._backend.draw(data, clearBefore); + }; + + return Display; + }(); + + Display.Rect = Rect; + Display.Hex = Hex; + Display.Tile = Tile; + Display.TileGL = TileGL; + Display.Term = Term; + /** + * @class (Markov process)-based string generator. + * Copied from a RogueBasin article. + * Offers configurable order and prior. + */ + + var StringGenerator = + /*#__PURE__*/ + function () { + function StringGenerator(options) { + this._options = { + words: false, + order: 3, + prior: 0.001 + }; + Object.assign(this._options, options); + this._boundary = String.fromCharCode(0); + this._suffix = this._boundary; + this._prefix = []; + + for (var i = 0; i < this._options.order; i++) { + this._prefix.push(this._boundary); + } + + this._priorValues = {}; + this._priorValues[this._boundary] = this._options.prior; + this._data = {}; + } + /** + * Remove all learning data + */ + + + var _proto10 = StringGenerator.prototype; + + _proto10.clear = function clear() { + this._data = {}; + this._priorValues = {}; + }; + /** + * @returns {string} Generated string + */ + + + _proto10.generate = function generate() { + var result = [this._sample(this._prefix)]; + + while (result[result.length - 1] != this._boundary) { + result.push(this._sample(result)); + } + + return this._join(result.slice(0, -1)); + }; + /** + * Observe (learn) a string from a training set + */ + + + _proto10.observe = function observe(string) { + var tokens = this._split(string); + + for (var i = 0; i < tokens.length; i++) { + this._priorValues[tokens[i]] = this._options.prior; + } + + tokens = this._prefix.concat(tokens).concat(this._suffix); + /* add boundary symbols */ + + for (var _i2 = this._options.order; _i2 < tokens.length; _i2++) { + var context = tokens.slice(_i2 - this._options.order, _i2); + var event = tokens[_i2]; + + for (var j = 0; j < context.length; j++) { + var subcontext = context.slice(j); + + this._observeEvent(subcontext, event); + } + } + }; + + _proto10.getStats = function getStats() { + var parts = []; + var priorCount = Object.keys(this._priorValues).length; + priorCount--; // boundary + + parts.push("distinct samples: " + priorCount); + var dataCount = Object.keys(this._data).length; + var eventCount = 0; + + for (var p in this._data) { + eventCount += Object.keys(this._data[p]).length; + } + + parts.push("dictionary size (contexts): " + dataCount); + parts.push("dictionary size (events): " + eventCount); + return parts.join(", "); + }; + /** + * @param {string} + * @returns {string[]} + */ + + + _proto10._split = function _split(str) { + return str.split(this._options.words ? /\s+/ : ""); + }; + /** + * @param {string[]} + * @returns {string} + */ + + + _proto10._join = function _join(arr) { + return arr.join(this._options.words ? " " : ""); + }; + /** + * @param {string[]} context + * @param {string} event + */ + + + _proto10._observeEvent = function _observeEvent(context, event) { + var key = this._join(context); + + if (!(key in this._data)) { + this._data[key] = {}; + } + + var data = this._data[key]; + + if (!(event in data)) { + data[event] = 0; + } + + data[event]++; + }; + /** + * @param {string[]} + * @returns {string} + */ + + + _proto10._sample = function _sample(context) { + context = this._backoff(context); + + var key = this._join(context); + + var data = this._data[key]; + var available = {}; + + if (this._options.prior) { + for (var event in this._priorValues) { + available[event] = this._priorValues[event]; + } + + for (var _event in data) { + available[_event] += data[_event]; + } + } else { + available = data; + } + + return RNG$1.getWeightedValue(available); + }; + /** + * @param {string[]} + * @returns {string[]} + */ + + + _proto10._backoff = function _backoff(context) { + if (context.length > this._options.order) { + context = context.slice(-this._options.order); + } else if (context.length < this._options.order) { + context = this._prefix.slice(0, this._options.order - context.length).concat(context); + } + + while (!(this._join(context) in this._data) && context.length > 0) { + context = context.slice(1); + } + + return context; + }; + + return StringGenerator; + }(); + + var EventQueue = + /*#__PURE__*/ + function () { + /** + * @class Generic event queue: stores events and retrieves them based on their time + */ + function EventQueue() { + this._time = 0; + this._events = []; + this._eventTimes = []; + } + /** + * @returns {number} Elapsed time + */ + + + var _proto11 = EventQueue.prototype; + + _proto11.getTime = function getTime() { + return this._time; + }; + /** + * Clear all scheduled events + */ + + + _proto11.clear = function clear() { + this._events = []; + this._eventTimes = []; + return this; + }; + /** + * @param {?} event + * @param {number} time + */ + + + _proto11.add = function add(event, time) { + var index = this._events.length; + + for (var i = 0; i < this._eventTimes.length; i++) { + if (this._eventTimes[i] > time) { + index = i; + break; + } + } + + this._events.splice(index, 0, event); + + this._eventTimes.splice(index, 0, time); + }; + /** + * Locates the nearest event, advances time if necessary. Returns that event and removes it from the queue. + * @returns {? || null} The event previously added by addEvent, null if no event available + */ + + + _proto11.get = function get() { + if (!this._events.length) { + return null; + } + + var time = this._eventTimes.splice(0, 1)[0]; + + if (time > 0) { + /* advance */ + this._time += time; + + for (var i = 0; i < this._eventTimes.length; i++) { + this._eventTimes[i] -= time; + } + } + + return this._events.splice(0, 1)[0]; + }; + /** + * Get the time associated with the given event + * @param {?} event + * @returns {number} time + */ + + + _proto11.getEventTime = function getEventTime(event) { + var index = this._events.indexOf(event); + + if (index == -1) { + return undefined; + } + + return this._eventTimes[index]; + }; + /** + * Remove an event from the queue + * @param {?} event + * @returns {bool} success? + */ + + + _proto11.remove = function remove(event) { + var index = this._events.indexOf(event); + + if (index == -1) { + return false; + } + + this._remove(index); + + return true; + }; + + /** + * Remove an event from the queue + * @param {int} index + */ + _proto11._remove = function _remove(index) { + this._events.splice(index, 1); + + this._eventTimes.splice(index, 1); + }; + + return EventQueue; + }(); + + var Scheduler = + /*#__PURE__*/ + function () { + /** + * @class Abstract scheduler + */ + function Scheduler() { + this._queue = new EventQueue(); + this._repeat = []; + this._current = null; + } + /** + * @see ROT.EventQueue#getTime + */ + + + var _proto12 = Scheduler.prototype; + + _proto12.getTime = function getTime() { + return this._queue.getTime(); + }; + /** + * @param {?} item + * @param {bool} repeat + */ + + + _proto12.add = function add(item, repeat) { + if (repeat) { + this._repeat.push(item); + } + + return this; + }; + /** + * Get the time the given item is scheduled for + * @param {?} item + * @returns {number} time + */ + + + _proto12.getTimeOf = function getTimeOf(item) { + return this._queue.getEventTime(item); + }; + /** + * Clear all items + */ + + + _proto12.clear = function clear() { + this._queue.clear(); + + this._repeat = []; + this._current = null; + return this; + }; + /** + * Remove a previously added item + * @param {?} item + * @returns {bool} successful? + */ + + + _proto12.remove = function remove(item) { + var result = this._queue.remove(item); + + var index = this._repeat.indexOf(item); + + if (index != -1) { + this._repeat.splice(index, 1); + } + + if (this._current == item) { + this._current = null; + } + + return result; + }; + /** + * Schedule next item + * @returns {?} + */ + + + _proto12.next = function next() { + this._current = this._queue.get(); + return this._current; + }; + + return Scheduler; + }(); + /** + * @class Simple fair scheduler (round-robin style) + */ + + + var Simple = + /*#__PURE__*/ + function (_Scheduler) { + _inheritsLoose(Simple, _Scheduler); + + function Simple() { + return _Scheduler.apply(this, arguments) || this; + } + + var _proto13 = Simple.prototype; + + _proto13.add = function add(item, repeat) { + this._queue.add(item, 0); + + return _Scheduler.prototype.add.call(this, item, repeat); + }; + + _proto13.next = function next() { + if (this._current !== null && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, 0); + } + + return _Scheduler.prototype.next.call(this); + }; + + return Simple; + }(Scheduler); + /** + * @class Speed-based scheduler + */ + + + var Speed = + /*#__PURE__*/ + function (_Scheduler2) { + _inheritsLoose(Speed, _Scheduler2); + + function Speed() { + return _Scheduler2.apply(this, arguments) || this; + } + + var _proto14 = Speed.prototype; + + /** + * @param {object} item anything with "getSpeed" method + * @param {bool} repeat + * @param {number} [time=1/item.getSpeed()] + * @see ROT.Scheduler#add + */ + _proto14.add = function add(item, repeat, time) { + this._queue.add(item, time !== undefined ? time : 1 / item.getSpeed()); + + return _Scheduler2.prototype.add.call(this, item, repeat); + }; + /** + * @see ROT.Scheduler#next + */ + + + _proto14.next = function next() { + if (this._current && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, 1 / this._current.getSpeed()); + } + + return _Scheduler2.prototype.next.call(this); + }; + + return Speed; + }(Scheduler); + /** + * @class Action-based scheduler + * @augments ROT.Scheduler + */ + + + var Action = + /*#__PURE__*/ + function (_Scheduler3) { + _inheritsLoose(Action, _Scheduler3); + + function Action() { + var _this9; + + _this9 = _Scheduler3.call(this) || this; + _this9._defaultDuration = 1; + /* for newly added */ + + _this9._duration = _this9._defaultDuration; + /* for this._current */ + + return _this9; + } + /** + * @param {object} item + * @param {bool} repeat + * @param {number} [time=1] + * @see ROT.Scheduler#add + */ + + + var _proto15 = Action.prototype; + + _proto15.add = function add(item, repeat, time) { + this._queue.add(item, time || this._defaultDuration); + + return _Scheduler3.prototype.add.call(this, item, repeat); + }; + + _proto15.clear = function clear() { + this._duration = this._defaultDuration; + return _Scheduler3.prototype.clear.call(this); + }; + + _proto15.remove = function remove(item) { + if (item == this._current) { + this._duration = this._defaultDuration; + } + + return _Scheduler3.prototype.remove.call(this, item); + }; + /** + * @see ROT.Scheduler#next + */ + + + _proto15.next = function next() { + if (this._current !== null && this._repeat.indexOf(this._current) != -1) { + this._queue.add(this._current, this._duration || this._defaultDuration); + + this._duration = this._defaultDuration; + } + + return _Scheduler3.prototype.next.call(this); + }; + /** + * Set duration for the active item + */ + + + _proto15.setDuration = function setDuration(time) { + if (this._current) { + this._duration = time; + } + + return this; + }; + + return Action; + }(Scheduler); + + var index = { + Simple: Simple, + Speed: Speed, + Action: Action + }; + + var FOV = + /*#__PURE__*/ + function () { + /** + * @class Abstract FOV algorithm + * @param {function} lightPassesCallback Does the light pass through x,y? + * @param {object} [options] + * @param {int} [options.topology=8] 4/6/8 + */ + function FOV(lightPassesCallback, options) { + if (options === void 0) { + options = {}; + } + + this._lightPasses = lightPassesCallback; + this._options = Object.assign({ + topology: 8 + }, options); + } + /** + * Return all neighbors in a concentric ring + * @param {int} cx center-x + * @param {int} cy center-y + * @param {int} r range + */ + + + var _proto16 = FOV.prototype; + + _proto16._getCircle = function _getCircle(cx, cy, r) { + var result = []; + var dirs, countFactor, startOffset; + + switch (this._options.topology) { + case 4: + countFactor = 1; + startOffset = [0, 1]; + dirs = [DIRS[8][7], DIRS[8][1], DIRS[8][3], DIRS[8][5]]; + break; + + case 6: + dirs = DIRS[6]; + countFactor = 1; + startOffset = [-1, 1]; + break; + + case 8: + dirs = DIRS[4]; + countFactor = 2; + startOffset = [-1, 1]; + break; + + default: + throw new Error("Incorrect topology for FOV computation"); + break; + } + /* starting neighbor */ + + + var x = cx + startOffset[0] * r; + var y = cy + startOffset[1] * r; + /* circle */ + + for (var i = 0; i < dirs.length; i++) { + for (var j = 0; j < r * countFactor; j++) { + result.push([x, y]); + x += dirs[i][0]; + y += dirs[i][1]; + } + } + + return result; + }; + + return FOV; + }(); + /** + * @class Discrete shadowcasting algorithm. Obsoleted by Precise shadowcasting. + * @augments ROT.FOV + */ + + + var DiscreteShadowcasting = + /*#__PURE__*/ + function (_FOV) { + _inheritsLoose(DiscreteShadowcasting, _FOV); + + function DiscreteShadowcasting() { + return _FOV.apply(this, arguments) || this; + } + + var _proto17 = DiscreteShadowcasting.prototype; + + _proto17.compute = function compute(x, y, R, callback) { + /* this place is always visible */ + callback(x, y, 0, 1); + /* standing in a dark place. FIXME is this a good idea? */ + + if (!this._lightPasses(x, y)) { + return; + } + /* start and end angles */ + + + var DATA = []; + var A, B, cx, cy, blocks; + /* analyze surrounding cells in concentric rings, starting from the center */ + + for (var r = 1; r <= R; r++) { + var neighbors = this._getCircle(x, y, r); + + var angle = 360 / neighbors.length; + + for (var i = 0; i < neighbors.length; i++) { + cx = neighbors[i][0]; + cy = neighbors[i][1]; + A = angle * (i - 0.5); + B = A + angle; + blocks = !this._lightPasses(cx, cy); + + if (this._visibleCoords(Math.floor(A), Math.ceil(B), blocks, DATA)) { + callback(cx, cy, r, 1); + } + + if (DATA.length == 2 && DATA[0] == 0 && DATA[1] == 360) { + return; + } + /* cutoff? */ + + } + /* for all cells in this ring */ + + } + /* for all rings */ + + }; + /** + * @param {int} A start angle + * @param {int} B end angle + * @param {bool} blocks Does current cell block visibility? + * @param {int[][]} DATA shadowed angle pairs + */ + + + _proto17._visibleCoords = function _visibleCoords(A, B, blocks, DATA) { + if (A < 0) { + var v1 = this._visibleCoords(0, B, blocks, DATA); + + var v2 = this._visibleCoords(360 + A, 360, blocks, DATA); + + return v1 || v2; + } + + var index = 0; + + while (index < DATA.length && DATA[index] < A) { + index++; + } + + if (index == DATA.length) { + /* completely new shadow */ + if (blocks) { + DATA.push(A, B); + } + + return true; + } + + var count = 0; + + if (index % 2) { + /* this shadow starts in an existing shadow, or within its ending boundary */ + while (index < DATA.length && DATA[index] < B) { + index++; + count++; + } + + if (count == 0) { + return false; + } + + if (blocks) { + if (count % 2) { + DATA.splice(index - count, count, B); + } else { + DATA.splice(index - count, count); + } + } + + return true; + } else { + /* this shadow starts outside an existing shadow, or within a starting boundary */ + while (index < DATA.length && DATA[index] < B) { + index++; + count++; + } + /* visible when outside an existing shadow, or when overlapping */ + + + if (A == DATA[index - count] && count == 1) { + return false; + } + + if (blocks) { + if (count % 2) { + DATA.splice(index - count, count, A); + } else { + DATA.splice(index - count, count, A, B); + } + } + + return true; + } + }; + + return DiscreteShadowcasting; + }(FOV); + /** + * @class Precise shadowcasting algorithm + * @augments ROT.FOV + */ + + + var PreciseShadowcasting = + /*#__PURE__*/ + function (_FOV2) { + _inheritsLoose(PreciseShadowcasting, _FOV2); + + function PreciseShadowcasting() { + return _FOV2.apply(this, arguments) || this; + } + + var _proto18 = PreciseShadowcasting.prototype; + + _proto18.compute = function compute(x, y, R, callback) { + /* this place is always visible */ + callback(x, y, 0, 1); + /* standing in a dark place. FIXME is this a good idea? */ + + if (!this._lightPasses(x, y)) { + return; + } + /* list of all shadows */ + + + var SHADOWS = []; + var cx, cy, blocks, A1, A2, visibility; + /* analyze surrounding cells in concentric rings, starting from the center */ + + for (var r = 1; r <= R; r++) { + var neighbors = this._getCircle(x, y, r); + + var neighborCount = neighbors.length; + + for (var i = 0; i < neighborCount; i++) { + cx = neighbors[i][0]; + cy = neighbors[i][1]; + /* shift half-an-angle backwards to maintain consistency of 0-th cells */ + + A1 = [i ? 2 * i - 1 : 2 * neighborCount - 1, 2 * neighborCount]; + A2 = [2 * i + 1, 2 * neighborCount]; + blocks = !this._lightPasses(cx, cy); + visibility = this._checkVisibility(A1, A2, blocks, SHADOWS); + + if (visibility) { + callback(cx, cy, r, visibility); + } + + if (SHADOWS.length == 2 && SHADOWS[0][0] == 0 && SHADOWS[1][0] == SHADOWS[1][1]) { + return; + } + /* cutoff? */ + + } + /* for all cells in this ring */ + + } + /* for all rings */ + + }; + /** + * @param {int[2]} A1 arc start + * @param {int[2]} A2 arc end + * @param {bool} blocks Does current arc block visibility? + * @param {int[][]} SHADOWS list of active shadows + */ + + + _proto18._checkVisibility = function _checkVisibility(A1, A2, blocks, SHADOWS) { + if (A1[0] > A2[0]) { + /* split into two sub-arcs */ + var v1 = this._checkVisibility(A1, [A1[1], A1[1]], blocks, SHADOWS); + + var v2 = this._checkVisibility([0, 1], A2, blocks, SHADOWS); + + return (v1 + v2) / 2; + } + /* index1: first shadow >= A1 */ + + + var index1 = 0, + edge1 = false; + + while (index1 < SHADOWS.length) { + var old = SHADOWS[index1]; + var diff = old[0] * A1[1] - A1[0] * old[1]; + + if (diff >= 0) { + /* old >= A1 */ + if (diff == 0 && !(index1 % 2)) { + edge1 = true; + } + + break; + } + + index1++; + } + /* index2: last shadow <= A2 */ + + + var index2 = SHADOWS.length, + edge2 = false; + + while (index2--) { + var _old = SHADOWS[index2]; + + var _diff = A2[0] * _old[1] - _old[0] * A2[1]; + + if (_diff >= 0) { + /* old <= A2 */ + if (_diff == 0 && index2 % 2) { + edge2 = true; + } + + break; + } + } + + var visible = true; + + if (index1 == index2 && (edge1 || edge2)) { + /* subset of existing shadow, one of the edges match */ + visible = false; + } else if (edge1 && edge2 && index1 + 1 == index2 && index2 % 2) { + /* completely equivalent with existing shadow */ + visible = false; + } else if (index1 > index2 && index1 % 2) { + /* subset of existing shadow, not touching */ + visible = false; + } + + if (!visible) { + return 0; + } + /* fast case: not visible */ + + + var visibleLength; + /* compute the length of visible arc, adjust list of shadows (if blocking) */ + + var remove = index2 - index1 + 1; + + if (remove % 2) { + if (index1 % 2) { + /* first edge within existing shadow, second outside */ + var P = SHADOWS[index1]; + visibleLength = (A2[0] * P[1] - P[0] * A2[1]) / (P[1] * A2[1]); + + if (blocks) { + SHADOWS.splice(index1, remove, A2); + } + } else { + /* second edge within existing shadow, first outside */ + var _P = SHADOWS[index2]; + visibleLength = (_P[0] * A1[1] - A1[0] * _P[1]) / (A1[1] * _P[1]); + + if (blocks) { + SHADOWS.splice(index1, remove, A1); + } + } + } else { + if (index1 % 2) { + /* both edges within existing shadows */ + var P1 = SHADOWS[index1]; + var P2 = SHADOWS[index2]; + visibleLength = (P2[0] * P1[1] - P1[0] * P2[1]) / (P1[1] * P2[1]); + + if (blocks) { + SHADOWS.splice(index1, remove); + } + } else { + /* both edges outside existing shadows */ + if (blocks) { + SHADOWS.splice(index1, remove, A1, A2); + } + + return 1; + /* whole arc visible! */ + } + } + + var arcLength = (A2[0] * A1[1] - A1[0] * A2[1]) / (A1[1] * A2[1]); + return visibleLength / arcLength; + }; + + return PreciseShadowcasting; + }(FOV); + /** Octants used for translating recursive shadowcasting offsets */ + + + var OCTANTS = [[-1, 0, 0, 1], [0, -1, 1, 0], [0, -1, -1, 0], [-1, 0, 0, -1], [1, 0, 0, -1], [0, 1, -1, 0], [0, 1, 1, 0], [1, 0, 0, 1]]; + /** + * @class Recursive shadowcasting algorithm + * Currently only supports 4/8 topologies, not hexagonal. + * Based on Peter Harkins' implementation of Björn Bergström's algorithm described here: http://www.roguebasin.com/index.php?title=FOV_using_recursive_shadowcasting + * @augments ROT.FOV + */ + + var RecursiveShadowcasting = + /*#__PURE__*/ + function (_FOV3) { + _inheritsLoose(RecursiveShadowcasting, _FOV3); + + function RecursiveShadowcasting() { + return _FOV3.apply(this, arguments) || this; + } + + var _proto19 = RecursiveShadowcasting.prototype; + + /** + * Compute visibility for a 360-degree circle + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {function} callback + */ + _proto19.compute = function compute(x, y, R, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + + for (var i = 0; i < OCTANTS.length; i++) { + this._renderOctant(x, y, OCTANTS[i], R, callback); + } + }; + /** + * Compute visibility for a 180-degree arc + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {int} dir Direction to look in (expressed in a ROT.DIRS value); + * @param {function} callback + */ + + + _proto19.compute180 = function compute180(x, y, R, dir, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + var previousOctant = (dir - 1 + 8) % 8; //Need to retrieve the previous octant to render a full 180 degrees + + var nextPreviousOctant = (dir - 2 + 8) % 8; //Need to retrieve the previous two octants to render a full 180 degrees + + var nextOctant = (dir + 1 + 8) % 8; //Need to grab to next octant to render a full 180 degrees + + this._renderOctant(x, y, OCTANTS[nextPreviousOctant], R, callback); + + this._renderOctant(x, y, OCTANTS[previousOctant], R, callback); + + this._renderOctant(x, y, OCTANTS[dir], R, callback); + + this._renderOctant(x, y, OCTANTS[nextOctant], R, callback); + }; + + /** + * Compute visibility for a 90-degree arc + * @param {int} x + * @param {int} y + * @param {int} R Maximum visibility radius + * @param {int} dir Direction to look in (expressed in a ROT.DIRS value); + * @param {function} callback + */ + _proto19.compute90 = function compute90(x, y, R, dir, callback) { + //You can always see your own tile + callback(x, y, 0, 1); + var previousOctant = (dir - 1 + 8) % 8; //Need to retrieve the previous octant to render a full 90 degrees + + this._renderOctant(x, y, OCTANTS[dir], R, callback); + + this._renderOctant(x, y, OCTANTS[previousOctant], R, callback); + }; + /** + * Render one octant (45-degree arc) of the viewshed + * @param {int} x + * @param {int} y + * @param {int} octant Octant to be rendered + * @param {int} R Maximum visibility radius + * @param {function} callback + */ + + + _proto19._renderOctant = function _renderOctant(x, y, octant, R, callback) { + //Radius incremented by 1 to provide same coverage area as other shadowcasting radiuses + this._castVisibility(x, y, 1, 1.0, 0.0, R + 1, octant[0], octant[1], octant[2], octant[3], callback); + }; + /** + * Actually calculates the visibility + * @param {int} startX The starting X coordinate + * @param {int} startY The starting Y coordinate + * @param {int} row The row to render + * @param {float} visSlopeStart The slope to start at + * @param {float} visSlopeEnd The slope to end at + * @param {int} radius The radius to reach out to + * @param {int} xx + * @param {int} xy + * @param {int} yx + * @param {int} yy + * @param {function} callback The callback to use when we hit a block that is visible + */ + + + _proto19._castVisibility = function _castVisibility(startX, startY, row, visSlopeStart, visSlopeEnd, radius, xx, xy, yx, yy, callback) { + if (visSlopeStart < visSlopeEnd) { + return; + } + + for (var i = row; i <= radius; i++) { + var dx = -i - 1; + var dy = -i; + var blocked = false; + var newStart = 0; //'Row' could be column, names here assume octant 0 and would be flipped for half the octants + + while (dx <= 0) { + dx += 1; //Translate from relative coordinates to map coordinates + + var mapX = startX + dx * xx + dy * xy; + var mapY = startY + dx * yx + dy * yy; //Range of the row + + var slopeStart = (dx - 0.5) / (dy + 0.5); + var slopeEnd = (dx + 0.5) / (dy - 0.5); //Ignore if not yet at left edge of Octant + + if (slopeEnd > visSlopeStart) { + continue; + } //Done if past right edge + + + if (slopeStart < visSlopeEnd) { + break; + } //If it's in range, it's visible + + + if (dx * dx + dy * dy < radius * radius) { + callback(mapX, mapY, i, 1); + } + + if (!blocked) { + //If tile is a blocking tile, cast around it + if (!this._lightPasses(mapX, mapY) && i < radius) { + blocked = true; + + this._castVisibility(startX, startY, i + 1, visSlopeStart, slopeStart, radius, xx, xy, yx, yy, callback); + + newStart = slopeEnd; + } + } else { + //Keep narrowing if scanning across a block + if (!this._lightPasses(mapX, mapY)) { + newStart = slopeEnd; + continue; + } //Block has ended + + + blocked = false; + visSlopeStart = newStart; + } + } + + if (blocked) { + break; + } + } + }; + + return RecursiveShadowcasting; + }(FOV); + + var index$1 = { + DiscreteShadowcasting: DiscreteShadowcasting, + PreciseShadowcasting: PreciseShadowcasting, + RecursiveShadowcasting: RecursiveShadowcasting + }; + + var Map = + /*#__PURE__*/ + function () { + /** + * @class Base map generator + * @param {int} [width=ROT.DEFAULT_WIDTH] + * @param {int} [height=ROT.DEFAULT_HEIGHT] + */ + function Map(width, height) { + if (width === void 0) { + width = DEFAULT_WIDTH; + } + + if (height === void 0) { + height = DEFAULT_HEIGHT; + } + + this._width = width; + this._height = height; + } + + var _proto20 = Map.prototype; + + _proto20._fillMap = function _fillMap(value) { + var map = []; + + for (var i = 0; i < this._width; i++) { + map.push([]); + + for (var j = 0; j < this._height; j++) { + map[i].push(value); + } + } + + return map; + }; + + return Map; + }(); + /** + * @class Simple empty rectangular room + * @augments ROT.Map + */ + + + var Arena = + /*#__PURE__*/ + function (_Map) { + _inheritsLoose(Arena, _Map); + + function Arena() { + return _Map.apply(this, arguments) || this; + } + + var _proto21 = Arena.prototype; + + _proto21.create = function create(callback) { + var w = this._width - 1; + var h = this._height - 1; + + for (var i = 0; i <= w; i++) { + for (var j = 0; j <= h; j++) { + var empty = i && j && i < w && j < h; + callback(i, j, empty ? 0 : 1); + } + } + + return this; + }; + + return Arena; + }(Map); + /** + * @class Dungeon map: has rooms and corridors + * @augments ROT.Map + */ + + + var Dungeon = + /*#__PURE__*/ + function (_Map2) { + _inheritsLoose(Dungeon, _Map2); + + function Dungeon(width, height) { + var _this10; + + _this10 = _Map2.call(this, width, height) || this; + _this10._rooms = []; + _this10._corridors = []; + return _this10; + } + /** + * Get all generated rooms + * @returns {ROT.Map.Feature.Room[]} + */ + + + var _proto22 = Dungeon.prototype; + + _proto22.getRooms = function getRooms() { + return this._rooms; + }; + /** + * Get all generated corridors + * @returns {ROT.Map.Feature.Corridor[]} + */ + + + _proto22.getCorridors = function getCorridors() { + return this._corridors; + }; + + return Dungeon; + }(Map); + /** + * @class Dungeon feature; has own .create() method + */ + + + var Feature = function Feature() {}; + /** + * @class Room + * @augments ROT.Map.Feature + * @param {int} x1 + * @param {int} y1 + * @param {int} x2 + * @param {int} y2 + * @param {int} [doorX] + * @param {int} [doorY] + */ + + + var Room = + /*#__PURE__*/ + function (_Feature) { + _inheritsLoose(Room, _Feature); + + function Room(x1, y1, x2, y2, doorX, doorY) { + var _this11; + + _this11 = _Feature.call(this) || this; + _this11._x1 = x1; + _this11._y1 = y1; + _this11._x2 = x2; + _this11._y2 = y2; + _this11._doors = {}; + + if (doorX !== undefined && doorY !== undefined) { + _this11.addDoor(doorX, doorY); + } + + return _this11; + } + + /** + * Room of random size, with a given doors and direction + */ + Room.createRandomAt = function createRandomAt(x, y, dx, dy, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + + if (dx == 1) { + /* to the right */ + var y2 = y - Math.floor(RNG$1.getUniform() * height); + return new this(x + 1, y2, x + width, y2 + height - 1, x, y); + } + + if (dx == -1) { + /* to the left */ + var _y = y - Math.floor(RNG$1.getUniform() * height); + + return new this(x - width, _y, x - 1, _y + height - 1, x, y); + } + + if (dy == 1) { + /* to the bottom */ + var x2 = x - Math.floor(RNG$1.getUniform() * width); + return new this(x2, y + 1, x2 + width - 1, y + height, x, y); + } + + if (dy == -1) { + /* to the top */ + var _x = x - Math.floor(RNG$1.getUniform() * width); + + return new this(_x, y - height, _x + width - 1, y - 1, x, y); + } + + throw new Error("dx or dy must be 1 or -1"); + }; + /** + * Room of random size, positioned around center coords + */ + + + Room.createRandomCenter = function createRandomCenter(cx, cy, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + var x1 = cx - Math.floor(RNG$1.getUniform() * width); + var y1 = cy - Math.floor(RNG$1.getUniform() * height); + var x2 = x1 + width - 1; + var y2 = y1 + height - 1; + return new this(x1, y1, x2, y2); + }; + /** + * Room of random size within a given dimensions + */ + + + Room.createRandom = function createRandom(availWidth, availHeight, options) { + var min = options.roomWidth[0]; + var max = options.roomWidth[1]; + var width = RNG$1.getUniformInt(min, max); + min = options.roomHeight[0]; + max = options.roomHeight[1]; + var height = RNG$1.getUniformInt(min, max); + var left = availWidth - width - 1; + var top = availHeight - height - 1; + var x1 = 1 + Math.floor(RNG$1.getUniform() * left); + var y1 = 1 + Math.floor(RNG$1.getUniform() * top); + var x2 = x1 + width - 1; + var y2 = y1 + height - 1; + return new this(x1, y1, x2, y2); + }; + + var _proto23 = Room.prototype; + + _proto23.addDoor = function addDoor(x, y) { + this._doors[x + "," + y] = 1; + return this; + }; + /** + * @param {function} + */ + + + _proto23.getDoors = function getDoors(cb) { + for (var key in this._doors) { + var parts = key.split(","); + cb(parseInt(parts[0]), parseInt(parts[1])); + } + + return this; + }; + + _proto23.clearDoors = function clearDoors() { + this._doors = {}; + return this; + }; + + _proto23.addDoors = function addDoors(isWallCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x != left && x != right && y != top && y != bottom) { + continue; + } + + if (isWallCallback(x, y)) { + continue; + } + + this.addDoor(x, y); + } + } + + return this; + }; + + _proto23.debug = function debug() { + console.log("room", this._x1, this._y1, this._x2, this._y2); + }; + + _proto23.isValid = function isValid(isWallCallback, canBeDugCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x == left || x == right || y == top || y == bottom) { + if (!isWallCallback(x, y)) { + return false; + } + } else { + if (!canBeDugCallback(x, y)) { + return false; + } + } + } + } + + return true; + }; + /** + * @param {function} digCallback Dig callback with a signature (x, y, value). Values: 0 = empty, 1 = wall, 2 = door. Multiple doors are allowed. + */ + + + _proto23.create = function create(digCallback) { + var left = this._x1 - 1; + var right = this._x2 + 1; + var top = this._y1 - 1; + var bottom = this._y2 + 1; + var value = 0; + + for (var x = left; x <= right; x++) { + for (var y = top; y <= bottom; y++) { + if (x + "," + y in this._doors) { + value = 2; + } else if (x == left || x == right || y == top || y == bottom) { + value = 1; + } else { + value = 0; + } + + digCallback(x, y, value); + } + } + }; + + _proto23.getCenter = function getCenter() { + return [Math.round((this._x1 + this._x2) / 2), Math.round((this._y1 + this._y2) / 2)]; + }; + + _proto23.getLeft = function getLeft() { + return this._x1; + }; + + _proto23.getRight = function getRight() { + return this._x2; + }; + + _proto23.getTop = function getTop() { + return this._y1; + }; + + _proto23.getBottom = function getBottom() { + return this._y2; + }; + + return Room; + }(Feature); + /** + * @class Corridor + * @augments ROT.Map.Feature + * @param {int} startX + * @param {int} startY + * @param {int} endX + * @param {int} endY + */ + + + var Corridor = + /*#__PURE__*/ + function (_Feature2) { + _inheritsLoose(Corridor, _Feature2); + + function Corridor(startX, startY, endX, endY) { + var _this12; + + _this12 = _Feature2.call(this) || this; + _this12._startX = startX; + _this12._startY = startY; + _this12._endX = endX; + _this12._endY = endY; + _this12._endsWithAWall = true; + return _this12; + } + + Corridor.createRandomAt = function createRandomAt(x, y, dx, dy, options) { + var min = options.corridorLength[0]; + var max = options.corridorLength[1]; + var length = RNG$1.getUniformInt(min, max); + return new this(x, y, x + dx * length, y + dy * length); + }; + + var _proto24 = Corridor.prototype; + + _proto24.debug = function debug() { + console.log("corridor", this._startX, this._startY, this._endX, this._endY); + }; + + _proto24.isValid = function isValid(isWallCallback, canBeDugCallback) { + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + var length = 1 + Math.max(Math.abs(dx), Math.abs(dy)); + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + var nx = dy; + var ny = -dx; + var ok = true; + + for (var i = 0; i < length; i++) { + var x = sx + i * dx; + var y = sy + i * dy; + + if (!canBeDugCallback(x, y)) { + ok = false; + } + + if (!isWallCallback(x + nx, y + ny)) { + ok = false; + } + + if (!isWallCallback(x - nx, y - ny)) { + ok = false; + } + + if (!ok) { + length = i; + this._endX = x - dx; + this._endY = y - dy; + break; + } + } + /** + * If the length degenerated, this corridor might be invalid + */ + + /* not supported */ + + + if (length == 0) { + return false; + } + /* length 1 allowed only if the next space is empty */ + + + if (length == 1 && isWallCallback(this._endX + dx, this._endY + dy)) { + return false; + } + /** + * We do not want the corridor to crash into a corner of a room; + * if any of the ending corners is empty, the N+1th cell of this corridor must be empty too. + * + * Situation: + * #######1 + * .......? + * #######2 + * + * The corridor was dug from left to right. + * 1, 2 - problematic corners, ? = N+1th cell (not dug) + */ + + + var firstCornerBad = !isWallCallback(this._endX + dx + nx, this._endY + dy + ny); + var secondCornerBad = !isWallCallback(this._endX + dx - nx, this._endY + dy - ny); + this._endsWithAWall = isWallCallback(this._endX + dx, this._endY + dy); + + if ((firstCornerBad || secondCornerBad) && this._endsWithAWall) { + return false; + } + + return true; + }; + /** + * @param {function} digCallback Dig callback with a signature (x, y, value). Values: 0 = empty. + */ + + + _proto24.create = function create(digCallback) { + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + var length = 1 + Math.max(Math.abs(dx), Math.abs(dy)); + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + for (var i = 0; i < length; i++) { + var x = sx + i * dx; + var y = sy + i * dy; + digCallback(x, y, 0); + } + + return true; + }; + + _proto24.createPriorityWalls = function createPriorityWalls(priorityWallCallback) { + if (!this._endsWithAWall) { + return; + } + + var sx = this._startX; + var sy = this._startY; + var dx = this._endX - sx; + var dy = this._endY - sy; + + if (dx) { + dx = dx / Math.abs(dx); + } + + if (dy) { + dy = dy / Math.abs(dy); + } + + var nx = dy; + var ny = -dx; + priorityWallCallback(this._endX + dx, this._endY + dy); + priorityWallCallback(this._endX + nx, this._endY + ny); + priorityWallCallback(this._endX - nx, this._endY - ny); + }; + + return Corridor; + }(Feature); + /** + * @class Dungeon generator which tries to fill the space evenly. Generates independent rooms and tries to connect them. + * @augments ROT.Map.Dungeon + */ + + + var Uniform = + /*#__PURE__*/ + function (_Dungeon) { + _inheritsLoose(Uniform, _Dungeon); + + function Uniform(width, height, options) { + var _this13; + + _this13 = _Dungeon.call(this, width, height) || this; + _this13._options = { + roomWidth: [3, 9], + roomHeight: [3, 5], + roomDugPercentage: 0.1, + timeLimit: 1000 + /* we stop after this much time has passed (msec) */ + + }; + Object.assign(_this13._options, options); + _this13._map = []; + _this13._dug = 0; + _this13._roomAttempts = 20; + /* new room is created N-times until is considered as impossible to generate */ + + _this13._corridorAttempts = 20; + /* corridors are tried N-times until the level is considered as impossible to connect */ + + _this13._connected = []; + /* list of already connected rooms */ + + _this13._unconnected = []; + /* list of remaining unconnected rooms */ + + _this13._digCallback = _this13._digCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + _this13._canBeDugCallback = _this13._canBeDugCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + _this13._isWallCallback = _this13._isWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this13))); + return _this13; + } + /** + * Create a map. If the time limit has been hit, returns null. + * @see ROT.Map#create + */ + + + var _proto25 = Uniform.prototype; + + _proto25.create = function create(callback) { + var t1 = Date.now(); + + while (1) { + var t2 = Date.now(); + + if (t2 - t1 > this._options.timeLimit) { + return null; + } + /* time limit! */ + + + this._map = this._fillMap(1); + this._dug = 0; + this._rooms = []; + this._unconnected = []; + + this._generateRooms(); + + if (this._rooms.length < 2) { + continue; + } + + if (this._generateCorridors()) { + break; + } + } + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this._map[i][j]); + } + } + } + + return this; + }; + /** + * Generates a suitable amount of rooms + */ + + + _proto25._generateRooms = function _generateRooms() { + var w = this._width - 2; + var h = this._height - 2; + var room; + + do { + room = this._generateRoom(); + + if (this._dug / (w * h) > this._options.roomDugPercentage) { + break; + } + /* achieved requested amount of free space */ + + } while (room); + /* either enough rooms, or not able to generate more of them :) */ + + }; + /** + * Try to generate one room + */ + + + _proto25._generateRoom = function _generateRoom() { + var count = 0; + + while (count < this._roomAttempts) { + count++; + var room = Room.createRandom(this._width, this._height, this._options); + + if (!room.isValid(this._isWallCallback, this._canBeDugCallback)) { + continue; + } + + room.create(this._digCallback); + + this._rooms.push(room); + + return room; + } + /* no room was generated in a given number of attempts */ + + + return null; + }; + /** + * Generates connectors beween rooms + * @returns {bool} success Was this attempt successfull? + */ + + + _proto25._generateCorridors = function _generateCorridors() { + var cnt = 0; + + while (cnt < this._corridorAttempts) { + cnt++; + this._corridors = []; + /* dig rooms into a clear map */ + + this._map = this._fillMap(1); + + for (var i = 0; i < this._rooms.length; i++) { + var room = this._rooms[i]; + room.clearDoors(); + room.create(this._digCallback); + } + + this._unconnected = RNG$1.shuffle(this._rooms.slice()); + this._connected = []; + + if (this._unconnected.length) { + this._connected.push(this._unconnected.pop()); + } + /* first one is always connected */ + + + while (1) { + /* 1. pick random connected room */ + var connected = RNG$1.getItem(this._connected); + + if (!connected) { + break; + } + /* 2. find closest unconnected */ + + + var room1 = this._closestRoom(this._unconnected, connected); + + if (!room1) { + break; + } + /* 3. connect it to closest connected */ + + + var room2 = this._closestRoom(this._connected, room1); + + if (!room2) { + break; + } + + var ok = this._connectRooms(room1, room2); + + if (!ok) { + break; + } + /* stop connecting, re-shuffle */ + + + if (!this._unconnected.length) { + return true; + } + /* done; no rooms remain */ + + } + } + + return false; + }; + + /** + * For a given room, find the closest one from the list + */ + _proto25._closestRoom = function _closestRoom(rooms, room) { + var dist = Infinity; + var center = room.getCenter(); + var result = null; + + for (var i = 0; i < rooms.length; i++) { + var r = rooms[i]; + var c = r.getCenter(); + var dx = c[0] - center[0]; + var dy = c[1] - center[1]; + var d = dx * dx + dy * dy; + + if (d < dist) { + dist = d; + result = r; + } + } + + return result; + }; + + _proto25._connectRooms = function _connectRooms(room1, room2) { + /* + room1.debug(); + room2.debug(); + */ + var center1 = room1.getCenter(); + var center2 = room2.getCenter(); + var diffX = center2[0] - center1[0]; + var diffY = center2[1] - center1[1]; + var start; + var end; + var dirIndex1, dirIndex2, min, max, index; + + if (Math.abs(diffX) < Math.abs(diffY)) { + /* first try connecting north-south walls */ + dirIndex1 = diffY > 0 ? 2 : 0; + dirIndex2 = (dirIndex1 + 2) % 4; + min = room2.getLeft(); + max = room2.getRight(); + index = 0; + } else { + /* first try connecting east-west walls */ + dirIndex1 = diffX > 0 ? 1 : 3; + dirIndex2 = (dirIndex1 + 2) % 4; + min = room2.getTop(); + max = room2.getBottom(); + index = 1; + } + + start = this._placeInWall(room1, dirIndex1); + /* corridor will start here */ + + if (!start) { + return false; + } + + if (start[index] >= min && start[index] <= max) { + /* possible to connect with straight line (I-like) */ + end = start.slice(); + var value = 0; + + switch (dirIndex2) { + case 0: + value = room2.getTop() - 1; + break; + + case 1: + value = room2.getRight() + 1; + break; + + case 2: + value = room2.getBottom() + 1; + break; + + case 3: + value = room2.getLeft() - 1; + break; + } + + end[(index + 1) % 2] = value; + + this._digLine([start, end]); + } else if (start[index] < min - 1 || start[index] > max + 1) { + /* need to switch target wall (L-like) */ + var diff = start[index] - center2[index]; + var rotation = 0; + + switch (dirIndex2) { + case 0: + case 1: + rotation = diff < 0 ? 3 : 1; + break; + + case 2: + case 3: + rotation = diff < 0 ? 1 : 3; + break; + } + + dirIndex2 = (dirIndex2 + rotation) % 4; + end = this._placeInWall(room2, dirIndex2); + + if (!end) { + return false; + } + + var mid = [0, 0]; + mid[index] = start[index]; + var index2 = (index + 1) % 2; + mid[index2] = end[index2]; + + this._digLine([start, mid, end]); + } else { + /* use current wall pair, but adjust the line in the middle (S-like) */ + var _index4 = (index + 1) % 2; + + end = this._placeInWall(room2, dirIndex2); + + if (!end) { + return false; + } + + var _mid = Math.round((end[_index4] + start[_index4]) / 2); + + var mid1 = [0, 0]; + var mid2 = [0, 0]; + mid1[index] = start[index]; + mid1[_index4] = _mid; + mid2[index] = end[index]; + mid2[_index4] = _mid; + + this._digLine([start, mid1, mid2, end]); + } + + room1.addDoor(start[0], start[1]); + room2.addDoor(end[0], end[1]); + index = this._unconnected.indexOf(room1); + + if (index != -1) { + this._unconnected.splice(index, 1); + + this._connected.push(room1); + } + + index = this._unconnected.indexOf(room2); + + if (index != -1) { + this._unconnected.splice(index, 1); + + this._connected.push(room2); + } + + return true; + }; + + _proto25._placeInWall = function _placeInWall(room, dirIndex) { + var start = [0, 0]; + var dir = [0, 0]; + var length = 0; + + switch (dirIndex) { + case 0: + dir = [1, 0]; + start = [room.getLeft(), room.getTop() - 1]; + length = room.getRight() - room.getLeft() + 1; + break; + + case 1: + dir = [0, 1]; + start = [room.getRight() + 1, room.getTop()]; + length = room.getBottom() - room.getTop() + 1; + break; + + case 2: + dir = [1, 0]; + start = [room.getLeft(), room.getBottom() + 1]; + length = room.getRight() - room.getLeft() + 1; + break; + + case 3: + dir = [0, 1]; + start = [room.getLeft() - 1, room.getTop()]; + length = room.getBottom() - room.getTop() + 1; + break; + } + + var avail = []; + var lastBadIndex = -2; + + for (var i = 0; i < length; i++) { + var x = start[0] + i * dir[0]; + var y = start[1] + i * dir[1]; + avail.push(null); + var isWall = this._map[x][y] == 1; + + if (isWall) { + if (lastBadIndex != i - 1) { + avail[i] = [x, y]; + } + } else { + lastBadIndex = i; + + if (i) { + avail[i - 1] = null; + } + } + } + + for (var _i3 = avail.length - 1; _i3 >= 0; _i3--) { + if (!avail[_i3]) { + avail.splice(_i3, 1); + } + } + + return avail.length ? RNG$1.getItem(avail) : null; + }; + /** + * Dig a polyline. + */ + + + _proto25._digLine = function _digLine(points) { + for (var i = 1; i < points.length; i++) { + var start = points[i - 1]; + var end = points[i]; + var corridor = new Corridor(start[0], start[1], end[0], end[1]); + corridor.create(this._digCallback); + + this._corridors.push(corridor); + } + }; + + _proto25._digCallback = function _digCallback(x, y, value) { + this._map[x][y] = value; + + if (value == 0) { + this._dug++; + } + }; + + _proto25._isWallCallback = function _isWallCallback(x, y) { + if (x < 0 || y < 0 || x >= this._width || y >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto25._canBeDugCallback = function _canBeDugCallback(x, y) { + if (x < 1 || y < 1 || x + 1 >= this._width || y + 1 >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + return Uniform; + }(Dungeon); + /** + * @class Cellular automaton map generator + * @augments ROT.Map + * @param {int} [width=ROT.DEFAULT_WIDTH] + * @param {int} [height=ROT.DEFAULT_HEIGHT] + * @param {object} [options] Options + * @param {int[]} [options.born] List of neighbor counts for a new cell to be born in empty space + * @param {int[]} [options.survive] List of neighbor counts for an existing cell to survive + * @param {int} [options.topology] Topology 4 or 6 or 8 + */ + + + var Cellular = + /*#__PURE__*/ + function (_Map3) { + _inheritsLoose(Cellular, _Map3); + + function Cellular(width, height, options) { + var _this14; + + if (options === void 0) { + options = {}; + } + + _this14 = _Map3.call(this, width, height) || this; + _this14._options = { + born: [5, 6, 7, 8], + survive: [4, 5, 6, 7, 8], + topology: 8 + }; + + _this14.setOptions(options); + + _this14._dirs = DIRS[_this14._options.topology]; + _this14._map = _this14._fillMap(0); + return _this14; + } + /** + * Fill the map with random values + * @param {float} probability Probability for a cell to become alive; 0 = all empty, 1 = all full + */ + + + var _proto26 = Cellular.prototype; + + _proto26.randomize = function randomize(probability) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + this._map[i][j] = RNG$1.getUniform() < probability ? 1 : 0; + } + } + + return this; + }; + /** + * Change options. + * @see ROT.Map.Cellular + */ + + + _proto26.setOptions = function setOptions(options) { + Object.assign(this._options, options); + }; + + _proto26.set = function set(x, y, value) { + this._map[x][y] = value; + }; + + _proto26.create = function create(callback) { + var newMap = this._fillMap(0); + + var born = this._options.born; + var survive = this._options.survive; + + for (var j = 0; j < this._height; j++) { + var widthStep = 1; + var widthStart = 0; + + if (this._options.topology == 6) { + widthStep = 2; + widthStart = j % 2; + } + + for (var i = widthStart; i < this._width; i += widthStep) { + var cur = this._map[i][j]; + + var ncount = this._getNeighbors(i, j); + + if (cur && survive.indexOf(ncount) != -1) { + /* survive */ + newMap[i][j] = 1; + } else if (!cur && born.indexOf(ncount) != -1) { + /* born */ + newMap[i][j] = 1; + } + } + } + + this._map = newMap; + callback && this._serviceCallback(callback); + }; + + _proto26._serviceCallback = function _serviceCallback(callback) { + for (var j = 0; j < this._height; j++) { + var widthStep = 1; + var widthStart = 0; + + if (this._options.topology == 6) { + widthStep = 2; + widthStart = j % 2; + } + + for (var i = widthStart; i < this._width; i += widthStep) { + callback(i, j, this._map[i][j]); + } + } + }; + /** + * Get neighbor count at [i,j] in this._map + */ + + + _proto26._getNeighbors = function _getNeighbors(cx, cy) { + var result = 0; + + for (var i = 0; i < this._dirs.length; i++) { + var dir = this._dirs[i]; + var x = cx + dir[0]; + var y = cy + dir[1]; + + if (x < 0 || x >= this._width || y < 0 || y >= this._height) { + continue; + } + + result += this._map[x][y] == 1 ? 1 : 0; + } + + return result; + }; + /** + * Make sure every non-wall space is accessible. + * @param {function} callback to call to display map when do + * @param {int} value to consider empty space - defaults to 0 + * @param {function} callback to call when a new connection is made + */ + + + _proto26.connect = function connect(callback, value, connectionCallback) { + if (!value) value = 0; + var allFreeSpace = []; + var notConnected = {}; // find all free space + + var widthStep = 1; + var widthStarts = [0, 0]; + + if (this._options.topology == 6) { + widthStep = 2; + widthStarts = [0, 1]; + } + + for (var y = 0; y < this._height; y++) { + for (var x = widthStarts[y % 2]; x < this._width; x += widthStep) { + if (this._freeSpace(x, y, value)) { + var p = [x, y]; + notConnected[this._pointKey(p)] = p; + allFreeSpace.push([x, y]); + } + } + } + + var start = allFreeSpace[RNG$1.getUniformInt(0, allFreeSpace.length - 1)]; + + var key = this._pointKey(start); + + var connected = {}; + connected[key] = start; + delete notConnected[key]; // find what's connected to the starting point + + this._findConnected(connected, notConnected, [start], false, value); + + while (Object.keys(notConnected).length > 0) { + // find two points from notConnected to connected + var _p = this._getFromTo(connected, notConnected); + + var from = _p[0]; // notConnected + + var to = _p[1]; // connected + // find everything connected to the starting point + + var local = {}; + local[this._pointKey(from)] = from; + + this._findConnected(local, notConnected, [from], true, value); // connect to a connected cell + + + var tunnelFn = this._options.topology == 6 ? this._tunnelToConnected6 : this._tunnelToConnected; + tunnelFn.call(this, to, from, connected, notConnected, value, connectionCallback); // now all of local is connected + + for (var k in local) { + var pp = local[k]; + this._map[pp[0]][pp[1]] = value; + connected[k] = pp; + delete notConnected[k]; + } + } + + callback && this._serviceCallback(callback); + }; + /** + * Find random points to connect. Search for the closest point in the larger space. + * This is to minimize the length of the passage while maintaining good performance. + */ + + + _proto26._getFromTo = function _getFromTo(connected, notConnected) { + var from = [0, 0], + to = [0, 0], + d; + var connectedKeys = Object.keys(connected); + var notConnectedKeys = Object.keys(notConnected); + + for (var i = 0; i < 5; i++) { + if (connectedKeys.length < notConnectedKeys.length) { + var keys = connectedKeys; + to = connected[keys[RNG$1.getUniformInt(0, keys.length - 1)]]; + from = this._getClosest(to, notConnected); + } else { + var _keys = notConnectedKeys; + from = notConnected[_keys[RNG$1.getUniformInt(0, _keys.length - 1)]]; + to = this._getClosest(from, connected); + } + + d = (from[0] - to[0]) * (from[0] - to[0]) + (from[1] - to[1]) * (from[1] - to[1]); + + if (d < 64) { + break; + } + } // console.log(">>> connected=" + to + " notConnected=" + from + " dist=" + d); + + + return [from, to]; + }; + + _proto26._getClosest = function _getClosest(point, space) { + var minPoint = null; + var minDist = null; + + for (var k in space) { + var p = space[k]; + var d = (p[0] - point[0]) * (p[0] - point[0]) + (p[1] - point[1]) * (p[1] - point[1]); + + if (minDist == null || d < minDist) { + minDist = d; + minPoint = p; + } + } + + return minPoint; + }; + + _proto26._findConnected = function _findConnected(connected, notConnected, stack, keepNotConnected, value) { + while (stack.length > 0) { + var p = stack.splice(0, 1)[0]; + var tests = void 0; + + if (this._options.topology == 6) { + tests = [[p[0] + 2, p[1]], [p[0] + 1, p[1] - 1], [p[0] - 1, p[1] - 1], [p[0] - 2, p[1]], [p[0] - 1, p[1] + 1], [p[0] + 1, p[1] + 1]]; + } else { + tests = [[p[0] + 1, p[1]], [p[0] - 1, p[1]], [p[0], p[1] + 1], [p[0], p[1] - 1]]; + } + + for (var i = 0; i < tests.length; i++) { + var key = this._pointKey(tests[i]); + + if (connected[key] == null && this._freeSpace(tests[i][0], tests[i][1], value)) { + connected[key] = tests[i]; + + if (!keepNotConnected) { + delete notConnected[key]; + } + + stack.push(tests[i]); + } + } + } + }; + + _proto26._tunnelToConnected = function _tunnelToConnected(to, from, connected, notConnected, value, connectionCallback) { + var a, b; + + if (from[0] < to[0]) { + a = from; + b = to; + } else { + a = to; + b = from; + } + + for (var xx = a[0]; xx <= b[0]; xx++) { + this._map[xx][a[1]] = value; + var p = [xx, a[1]]; + + var pkey = this._pointKey(p); + + connected[pkey] = p; + delete notConnected[pkey]; + } + + if (connectionCallback && a[0] < b[0]) { + connectionCallback(a, [b[0], a[1]]); + } // x is now fixed + + + var x = b[0]; + + if (from[1] < to[1]) { + a = from; + b = to; + } else { + a = to; + b = from; + } + + for (var yy = a[1]; yy < b[1]; yy++) { + this._map[x][yy] = value; + var _p2 = [x, yy]; + + var _pkey = this._pointKey(_p2); + + connected[_pkey] = _p2; + delete notConnected[_pkey]; + } + + if (connectionCallback && a[1] < b[1]) { + connectionCallback([b[0], a[1]], [b[0], b[1]]); + } + }; + + _proto26._tunnelToConnected6 = function _tunnelToConnected6(to, from, connected, notConnected, value, connectionCallback) { + var a, b; + + if (from[0] < to[0]) { + a = from; + b = to; + } else { + a = to; + b = from; + } // tunnel diagonally until horizontally level + + + var xx = a[0]; + var yy = a[1]; + + while (!(xx == b[0] && yy == b[1])) { + var stepWidth = 2; + + if (yy < b[1]) { + yy++; + stepWidth = 1; + } else if (yy > b[1]) { + yy--; + stepWidth = 1; + } + + if (xx < b[0]) { + xx += stepWidth; + } else if (xx > b[0]) { + xx -= stepWidth; + } else if (b[1] % 2) { + // Won't step outside map if destination on is map's right edge + xx -= stepWidth; + } else { + // ditto for left edge + xx += stepWidth; + } + + this._map[xx][yy] = value; + var p = [xx, yy]; + + var pkey = this._pointKey(p); + + connected[pkey] = p; + delete notConnected[pkey]; + } + + if (connectionCallback) { + connectionCallback(from, to); + } + }; + + _proto26._freeSpace = function _freeSpace(x, y, value) { + return x >= 0 && x < this._width && y >= 0 && y < this._height && this._map[x][y] == value; + }; + + _proto26._pointKey = function _pointKey(p) { + return p[0] + "." + p[1]; + }; + + return Cellular; + }(Map); + + var FEATURES = { + "room": Room, + "corridor": Corridor + }; + /** + * Random dungeon generator using human-like digging patterns. + * Heavily based on Mike Anderson's ideas from the "Tyrant" algo, mentioned at + * http://www.roguebasin.roguelikedevelopment.org/index.php?title=Dungeon-Building_Algorithm. + */ + + var Digger = + /*#__PURE__*/ + function (_Dungeon2) { + _inheritsLoose(Digger, _Dungeon2); + + function Digger(width, height, options) { + var _this15; + + if (options === void 0) { + options = {}; + } + + _this15 = _Dungeon2.call(this, width, height) || this; + _this15._options = Object.assign({ + roomWidth: [3, 9], + roomHeight: [3, 5], + corridorLength: [3, 10], + dugPercentage: 0.2, + timeLimit: 1000 + /* we stop after this much time has passed (msec) */ + + }, options); + _this15._features = { + "room": 4, + "corridor": 4 + }; + _this15._map = []; + _this15._featureAttempts = 20; + /* how many times do we try to create a feature on a suitable wall */ + + _this15._walls = {}; + /* these are available for digging */ + + _this15._dug = 0; + _this15._digCallback = _this15._digCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._canBeDugCallback = _this15._canBeDugCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._isWallCallback = _this15._isWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + _this15._priorityWallCallback = _this15._priorityWallCallback.bind(_assertThisInitialized(_assertThisInitialized(_this15))); + return _this15; + } + + var _proto27 = Digger.prototype; + + _proto27.create = function create(callback) { + this._rooms = []; + this._corridors = []; + this._map = this._fillMap(1); + this._walls = {}; + this._dug = 0; + var area = (this._width - 2) * (this._height - 2); + + this._firstRoom(); + + var t1 = Date.now(); + var priorityWalls; + + do { + priorityWalls = 0; + var t2 = Date.now(); + + if (t2 - t1 > this._options.timeLimit) { + break; + } + /* find a good wall */ + + + var wall = this._findWall(); + + if (!wall) { + break; + } + /* no more walls */ + + + var parts = wall.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + + var dir = this._getDiggingDirection(x, y); + + if (!dir) { + continue; + } + /* this wall is not suitable */ + // console.log("wall", x, y); + + /* try adding a feature */ + + + var featureAttempts = 0; + + do { + featureAttempts++; + + if (this._tryFeature(x, y, dir[0], dir[1])) { + /* feature added */ + //if (this._rooms.length + this._corridors.length == 2) { this._rooms[0].addDoor(x, y); } /* first room oficially has doors */ + this._removeSurroundingWalls(x, y); + + this._removeSurroundingWalls(x - dir[0], y - dir[1]); + + break; + } + } while (featureAttempts < this._featureAttempts); + + for (var id in this._walls) { + if (this._walls[id] > 1) { + priorityWalls++; + } + } + } while (this._dug / area < this._options.dugPercentage || priorityWalls); + /* fixme number of priority walls */ + + + this._addDoors(); + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this._map[i][j]); + } + } + } + + this._walls = {}; + this._map = []; + return this; + }; + + _proto27._digCallback = function _digCallback(x, y, value) { + if (value == 0 || value == 2) { + /* empty */ + this._map[x][y] = 0; + this._dug++; + } else { + /* wall */ + this._walls[x + "," + y] = 1; + } + }; + + _proto27._isWallCallback = function _isWallCallback(x, y) { + if (x < 0 || y < 0 || x >= this._width || y >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto27._canBeDugCallback = function _canBeDugCallback(x, y) { + if (x < 1 || y < 1 || x + 1 >= this._width || y + 1 >= this._height) { + return false; + } + + return this._map[x][y] == 1; + }; + + _proto27._priorityWallCallback = function _priorityWallCallback(x, y) { + this._walls[x + "," + y] = 2; + }; + + _proto27._firstRoom = function _firstRoom() { + var cx = Math.floor(this._width / 2); + var cy = Math.floor(this._height / 2); + var room = Room.createRandomCenter(cx, cy, this._options); + + this._rooms.push(room); + + room.create(this._digCallback); + }; + /** + * Get a suitable wall + */ + + + _proto27._findWall = function _findWall() { + var prio1 = []; + var prio2 = []; + + for (var _id2 in this._walls) { + var prio = this._walls[_id2]; + + if (prio == 2) { + prio2.push(_id2); + } else { + prio1.push(_id2); + } + } + + var arr = prio2.length ? prio2 : prio1; + + if (!arr.length) { + return null; + } + /* no walls :/ */ + + + var id = RNG$1.getItem(arr.sort()); // sort to make the order deterministic + + delete this._walls[id]; + return id; + }; + /** + * Tries adding a feature + * @returns {bool} was this a successful try? + */ + + + _proto27._tryFeature = function _tryFeature(x, y, dx, dy) { + var featureName = RNG$1.getWeightedValue(this._features); + var ctor = FEATURES[featureName]; + var feature = ctor.createRandomAt(x, y, dx, dy, this._options); + + if (!feature.isValid(this._isWallCallback, this._canBeDugCallback)) { + // console.log("not valid"); + // feature.debug(); + return false; + } + + feature.create(this._digCallback); // feature.debug(); + + if (feature instanceof Room) { + this._rooms.push(feature); + } + + if (feature instanceof Corridor) { + feature.createPriorityWalls(this._priorityWallCallback); + + this._corridors.push(feature); + } + + return true; + }; + + _proto27._removeSurroundingWalls = function _removeSurroundingWalls(cx, cy) { + var deltas = DIRS[4]; + + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + var x = cx + delta[0]; + var y = cy + delta[1]; + delete this._walls[x + "," + y]; + x = cx + 2 * delta[0]; + y = cy + 2 * delta[1]; + delete this._walls[x + "," + y]; + } + }; + /** + * Returns vector in "digging" direction, or false, if this does not exist (or is not unique) + */ + + + _proto27._getDiggingDirection = function _getDiggingDirection(cx, cy) { + if (cx <= 0 || cy <= 0 || cx >= this._width - 1 || cy >= this._height - 1) { + return null; + } + + var result = null; + var deltas = DIRS[4]; + + for (var i = 0; i < deltas.length; i++) { + var delta = deltas[i]; + var x = cx + delta[0]; + var y = cy + delta[1]; + + if (!this._map[x][y]) { + /* there already is another empty neighbor! */ + if (result) { + return null; + } + + result = delta; + } + } + /* no empty neighbor */ + + + if (!result) { + return null; + } + + return [-result[0], -result[1]]; + }; + /** + * Find empty spaces surrounding rooms, and apply doors. + */ + + + _proto27._addDoors = function _addDoors() { + var data = this._map; + + function isWallCallback(x, y) { + return data[x][y] == 1; + } + + for (var i = 0; i < this._rooms.length; i++) { + var room = this._rooms[i]; + room.clearDoors(); + room.addDoors(isWallCallback); + } + }; + + return Digger; + }(Dungeon); + /** + * Join lists with "i" and "i+1" + */ + + + function addToList(i, L, R) { + R[L[i + 1]] = R[i]; + L[R[i]] = L[i + 1]; + R[i] = i + 1; + L[i + 1] = i; + } + /** + * Remove "i" from its list + */ + + + function removeFromList(i, L, R) { + R[L[i]] = R[i]; + L[R[i]] = L[i]; + R[i] = i; + L[i] = i; + } + /** + * Maze generator - Eller's algorithm + * See http://homepages.cwi.nl/~tromp/maze.html for explanation + */ + + + var EllerMaze = + /*#__PURE__*/ + function (_Map4) { + _inheritsLoose(EllerMaze, _Map4); + + function EllerMaze() { + return _Map4.apply(this, arguments) || this; + } + + var _proto28 = EllerMaze.prototype; + + _proto28.create = function create(callback) { + var map = this._fillMap(1); + + var w = Math.ceil((this._width - 2) / 2); + var rand = 9 / 24; + var L = []; + var R = []; + + for (var i = 0; i < w; i++) { + L.push(i); + R.push(i); + } + + L.push(w - 1); + /* fake stop-block at the right side */ + + var j; + + for (j = 1; j + 3 < this._height; j += 2) { + /* one row */ + for (var _i4 = 0; _i4 < w; _i4++) { + /* cell coords (will be always empty) */ + var x = 2 * _i4 + 1; + var y = j; + map[x][y] = 0; + /* right connection */ + + if (_i4 != L[_i4 + 1] && RNG$1.getUniform() > rand) { + addToList(_i4, L, R); + map[x + 1][y] = 0; + } + /* bottom connection */ + + + if (_i4 != L[_i4] && RNG$1.getUniform() > rand) { + /* remove connection */ + removeFromList(_i4, L, R); + } else { + /* create connection */ + map[x][y + 1] = 0; + } + } + } + /* last row */ + + + for (var _i5 = 0; _i5 < w; _i5++) { + /* cell coords (will be always empty) */ + var _x2 = 2 * _i5 + 1; + + var _y2 = j; + map[_x2][_y2] = 0; + /* right connection */ + + if (_i5 != L[_i5 + 1] && (_i5 == L[_i5] || RNG$1.getUniform() > rand)) { + /* dig right also if the cell is separated, so it gets connected to the rest of maze */ + addToList(_i5, L, R); + map[_x2 + 1][_y2] = 0; + } + + removeFromList(_i5, L, R); + } + + for (var _i6 = 0; _i6 < this._width; _i6++) { + for (var _j = 0; _j < this._height; _j++) { + callback(_i6, _j, map[_i6][_j]); + } + } + + return this; + }; + + return EllerMaze; + }(Map); + /** + * @class Recursively divided maze, http://en.wikipedia.org/wiki/Maze_generation_algorithm#Recursive_division_method + * @augments ROT.Map + */ + + + var DividedMaze = + /*#__PURE__*/ + function (_Map5) { + _inheritsLoose(DividedMaze, _Map5); + + function DividedMaze() { + var _this16; + + _this16 = _Map5.apply(this, arguments) || this; + _this16._stack = []; + _this16._map = []; + return _this16; + } + + var _proto29 = DividedMaze.prototype; + + _proto29.create = function create(callback) { + var w = this._width; + var h = this._height; + this._map = []; + + for (var i = 0; i < w; i++) { + this._map.push([]); + + for (var j = 0; j < h; j++) { + var border = i == 0 || j == 0 || i + 1 == w || j + 1 == h; + + this._map[i].push(border ? 1 : 0); + } + } + + this._stack = [[1, 1, w - 2, h - 2]]; + + this._process(); + + for (var _i7 = 0; _i7 < w; _i7++) { + for (var _j2 = 0; _j2 < h; _j2++) { + callback(_i7, _j2, this._map[_i7][_j2]); + } + } + + this._map = []; + return this; + }; + + _proto29._process = function _process() { + while (this._stack.length) { + var room = this._stack.shift(); + /* [left, top, right, bottom] */ + + + this._partitionRoom(room); + } + }; + + _proto29._partitionRoom = function _partitionRoom(room) { + var availX = []; + var availY = []; + + for (var i = room[0] + 1; i < room[2]; i++) { + var top = this._map[i][room[1] - 1]; + var bottom = this._map[i][room[3] + 1]; + + if (top && bottom && !(i % 2)) { + availX.push(i); + } + } + + for (var j = room[1] + 1; j < room[3]; j++) { + var left = this._map[room[0] - 1][j]; + var right = this._map[room[2] + 1][j]; + + if (left && right && !(j % 2)) { + availY.push(j); + } + } + + if (!availX.length || !availY.length) { + return; + } + + var x = RNG$1.getItem(availX); + var y = RNG$1.getItem(availY); + this._map[x][y] = 1; + var walls = []; + var w = []; + walls.push(w); + /* left part */ + + for (var _i8 = room[0]; _i8 < x; _i8++) { + this._map[_i8][y] = 1; + w.push([_i8, y]); + } + + w = []; + walls.push(w); + /* right part */ + + for (var _i9 = x + 1; _i9 <= room[2]; _i9++) { + this._map[_i9][y] = 1; + w.push([_i9, y]); + } + + w = []; + walls.push(w); + /* top part */ + + for (var _j3 = room[1]; _j3 < y; _j3++) { + this._map[x][_j3] = 1; + w.push([x, _j3]); + } + + w = []; + walls.push(w); + /* bottom part */ + + for (var _j4 = y + 1; _j4 <= room[3]; _j4++) { + this._map[x][_j4] = 1; + w.push([x, _j4]); + } + + var solid = RNG$1.getItem(walls); + + for (var _i10 = 0; _i10 < walls.length; _i10++) { + var _w = walls[_i10]; + + if (_w == solid) { + continue; + } + + var hole = RNG$1.getItem(_w); + this._map[hole[0]][hole[1]] = 0; + } + + this._stack.push([room[0], room[1], x - 1, y - 1]); + /* left top */ + + + this._stack.push([x + 1, room[1], room[2], y - 1]); + /* right top */ + + + this._stack.push([room[0], y + 1, x - 1, room[3]]); + /* left bottom */ + + + this._stack.push([x + 1, y + 1, room[2], room[3]]); + /* right bottom */ + + }; + + return DividedMaze; + }(Map); + /** + * Icey's Maze generator + * See http://www.roguebasin.roguelikedevelopment.org/index.php?title=Simple_maze for explanation + */ + + + var IceyMaze = + /*#__PURE__*/ + function (_Map6) { + _inheritsLoose(IceyMaze, _Map6); + + function IceyMaze(width, height, regularity) { + var _this17; + + if (regularity === void 0) { + regularity = 0; + } + + _this17 = _Map6.call(this, width, height) || this; + _this17._regularity = regularity; + _this17._map = []; + return _this17; + } + + var _proto30 = IceyMaze.prototype; + + _proto30.create = function create(callback) { + var width = this._width; + var height = this._height; + + var map = this._fillMap(1); + + width -= width % 2 ? 1 : 2; + height -= height % 2 ? 1 : 2; + var cx = 0; + var cy = 0; + var nx = 0; + var ny = 0; + var done = 0; + var blocked = false; + var dirs = [[0, 0], [0, 0], [0, 0], [0, 0]]; + + do { + cx = 1 + 2 * Math.floor(RNG$1.getUniform() * (width - 1) / 2); + cy = 1 + 2 * Math.floor(RNG$1.getUniform() * (height - 1) / 2); + + if (!done) { + map[cx][cy] = 0; + } + + if (!map[cx][cy]) { + this._randomize(dirs); + + do { + if (Math.floor(RNG$1.getUniform() * (this._regularity + 1)) == 0) { + this._randomize(dirs); + } + + blocked = true; + + for (var i = 0; i < 4; i++) { + nx = cx + dirs[i][0] * 2; + ny = cy + dirs[i][1] * 2; + + if (this._isFree(map, nx, ny, width, height)) { + map[nx][ny] = 0; + map[cx + dirs[i][0]][cy + dirs[i][1]] = 0; + cx = nx; + cy = ny; + blocked = false; + done++; + break; + } + } + } while (!blocked); + } + } while (done + 1 < width * height / 4); + + for (var _i11 = 0; _i11 < this._width; _i11++) { + for (var j = 0; j < this._height; j++) { + callback(_i11, j, map[_i11][j]); + } + } + + this._map = []; + return this; + }; + + _proto30._randomize = function _randomize(dirs) { + for (var i = 0; i < 4; i++) { + dirs[i][0] = 0; + dirs[i][1] = 0; + } + + switch (Math.floor(RNG$1.getUniform() * 4)) { + case 0: + dirs[0][0] = -1; + dirs[1][0] = 1; + dirs[2][1] = -1; + dirs[3][1] = 1; + break; + + case 1: + dirs[3][0] = -1; + dirs[2][0] = 1; + dirs[1][1] = -1; + dirs[0][1] = 1; + break; + + case 2: + dirs[2][0] = -1; + dirs[3][0] = 1; + dirs[0][1] = -1; + dirs[1][1] = 1; + break; + + case 3: + dirs[1][0] = -1; + dirs[0][0] = 1; + dirs[3][1] = -1; + dirs[2][1] = 1; + break; + } + }; + + _proto30._isFree = function _isFree(map, x, y, width, height) { + if (x < 1 || y < 1 || x >= width || y >= height) { + return false; + } + + return map[x][y]; + }; + + return IceyMaze; + }(Map); + /** + * Dungeon generator which uses the "orginal" Rogue dungeon generation algorithm. See http://kuoi.com/~kamikaze/GameDesign/art07_rogue_dungeon.php + * @author hyakugei + */ + + + var Rogue = + /*#__PURE__*/ + function (_Map7) { + _inheritsLoose(Rogue, _Map7); + + function Rogue(width, height, options) { + var _this18; + + _this18 = _Map7.call(this, width, height) || this; + _this18.map = []; + _this18.rooms = []; + _this18.connectedCells = []; + options = Object.assign({ + cellWidth: 3, + cellHeight: 3 // ie. as an array with min-max values for each direction.... + + }, options); + /* + Set the room sizes according to the over-all width of the map, + and the cell sizes. + */ + + if (!options.hasOwnProperty("roomWidth")) { + options["roomWidth"] = _this18._calculateRoomSize(_this18._width, options["cellWidth"]); + } + + if (!options.hasOwnProperty("roomHeight")) { + options["roomHeight"] = _this18._calculateRoomSize(_this18._height, options["cellHeight"]); + } + + _this18._options = options; + return _this18; + } + + var _proto31 = Rogue.prototype; + + _proto31.create = function create(callback) { + this.map = this._fillMap(1); + this.rooms = []; + this.connectedCells = []; + + this._initRooms(); + + this._connectRooms(); + + this._connectUnconnectedRooms(); + + this._createRandomRoomConnections(); + + this._createRooms(); + + this._createCorridors(); + + if (callback) { + for (var i = 0; i < this._width; i++) { + for (var j = 0; j < this._height; j++) { + callback(i, j, this.map[i][j]); + } + } + } + + return this; + }; + + _proto31._calculateRoomSize = function _calculateRoomSize(size, cell) { + var max = Math.floor(size / cell * 0.8); + var min = Math.floor(size / cell * 0.25); + + if (min < 2) { + min = 2; + } + + if (max < 2) { + max = 2; + } + + return [min, max]; + }; + + _proto31._initRooms = function _initRooms() { + // create rooms array. This is the "grid" list from the algo. + for (var i = 0; i < this._options.cellWidth; i++) { + this.rooms.push([]); + + for (var j = 0; j < this._options.cellHeight; j++) { + this.rooms[i].push({ + "x": 0, + "y": 0, + "width": 0, + "height": 0, + "connections": [], + "cellx": i, + "celly": j + }); + } + } + }; + + _proto31._connectRooms = function _connectRooms() { + //pick random starting grid + var cgx = RNG$1.getUniformInt(0, this._options.cellWidth - 1); + var cgy = RNG$1.getUniformInt(0, this._options.cellHeight - 1); + var idx; + var ncgx; + var ncgy; + var found = false; + var room; + var otherRoom; + var dirToCheck; // find unconnected neighbour cells + + do { + //dirToCheck = [0, 1, 2, 3, 4, 5, 6, 7]; + dirToCheck = [0, 2, 4, 6]; + dirToCheck = RNG$1.shuffle(dirToCheck); + + do { + found = false; + idx = dirToCheck.pop(); + ncgx = cgx + DIRS[8][idx][0]; + ncgy = cgy + DIRS[8][idx][1]; + + if (ncgx < 0 || ncgx >= this._options.cellWidth) { + continue; + } + + if (ncgy < 0 || ncgy >= this._options.cellHeight) { + continue; + } + + room = this.rooms[cgx][cgy]; + + if (room["connections"].length > 0) { + // as long as this room doesn't already coonect to me, we are ok with it. + if (room["connections"][0][0] == ncgx && room["connections"][0][1] == ncgy) { + break; + } + } + + otherRoom = this.rooms[ncgx][ncgy]; + + if (otherRoom["connections"].length == 0) { + otherRoom["connections"].push([cgx, cgy]); + this.connectedCells.push([ncgx, ncgy]); + cgx = ncgx; + cgy = ncgy; + found = true; + } + } while (dirToCheck.length > 0 && found == false); + } while (dirToCheck.length > 0); + }; + + _proto31._connectUnconnectedRooms = function _connectUnconnectedRooms() { + //While there are unconnected rooms, try to connect them to a random connected neighbor + //(if a room has no connected neighbors yet, just keep cycling, you'll fill out to it eventually). + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + this.connectedCells = RNG$1.shuffle(this.connectedCells); + var room; + var otherRoom; + var validRoom; + + for (var i = 0; i < this._options.cellWidth; i++) { + for (var j = 0; j < this._options.cellHeight; j++) { + room = this.rooms[i][j]; + + if (room["connections"].length == 0) { + var directions = [0, 2, 4, 6]; + directions = RNG$1.shuffle(directions); + validRoom = false; + + do { + var dirIdx = directions.pop(); + var newI = i + DIRS[8][dirIdx][0]; + var newJ = j + DIRS[8][dirIdx][1]; + + if (newI < 0 || newI >= cw || newJ < 0 || newJ >= ch) { + continue; + } + + otherRoom = this.rooms[newI][newJ]; + validRoom = true; + + if (otherRoom["connections"].length == 0) { + break; + } + + for (var k = 0; k < otherRoom["connections"].length; k++) { + if (otherRoom["connections"][k][0] == i && otherRoom["connections"][k][1] == j) { + validRoom = false; + break; + } + } + + if (validRoom) { + break; + } + } while (directions.length); + + if (validRoom) { + room["connections"].push([otherRoom["cellx"], otherRoom["celly"]]); + } else { + console.log("-- Unable to connect room."); + } + } + } + } + }; + + _proto31._createRandomRoomConnections = function _createRandomRoomConnections() {// Empty for now. + }; + + _proto31._createRooms = function _createRooms() { + var w = this._width; + var h = this._height; + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + var cwp = Math.floor(this._width / cw); + var chp = Math.floor(this._height / ch); + var roomw; + var roomh; + var roomWidth = this._options["roomWidth"]; + var roomHeight = this._options["roomHeight"]; + var sx; + var sy; + var otherRoom; + + for (var i = 0; i < cw; i++) { + for (var j = 0; j < ch; j++) { + sx = cwp * i; + sy = chp * j; + + if (sx == 0) { + sx = 1; + } + + if (sy == 0) { + sy = 1; + } + + roomw = RNG$1.getUniformInt(roomWidth[0], roomWidth[1]); + roomh = RNG$1.getUniformInt(roomHeight[0], roomHeight[1]); + + if (j > 0) { + otherRoom = this.rooms[i][j - 1]; + + while (sy - (otherRoom["y"] + otherRoom["height"]) < 3) { + sy++; + } + } + + if (i > 0) { + otherRoom = this.rooms[i - 1][j]; + + while (sx - (otherRoom["x"] + otherRoom["width"]) < 3) { + sx++; + } + } + + var sxOffset = Math.round(RNG$1.getUniformInt(0, cwp - roomw) / 2); + var syOffset = Math.round(RNG$1.getUniformInt(0, chp - roomh) / 2); + + while (sx + sxOffset + roomw >= w) { + if (sxOffset) { + sxOffset--; + } else { + roomw--; + } + } + + while (sy + syOffset + roomh >= h) { + if (syOffset) { + syOffset--; + } else { + roomh--; + } + } + + sx = sx + sxOffset; + sy = sy + syOffset; + this.rooms[i][j]["x"] = sx; + this.rooms[i][j]["y"] = sy; + this.rooms[i][j]["width"] = roomw; + this.rooms[i][j]["height"] = roomh; + + for (var ii = sx; ii < sx + roomw; ii++) { + for (var jj = sy; jj < sy + roomh; jj++) { + this.map[ii][jj] = 0; + } + } + } + } + }; + + _proto31._getWallPosition = function _getWallPosition(aRoom, aDirection) { + var rx; + var ry; + var door; + + if (aDirection == 1 || aDirection == 3) { + rx = RNG$1.getUniformInt(aRoom["x"] + 1, aRoom["x"] + aRoom["width"] - 2); + + if (aDirection == 1) { + ry = aRoom["y"] - 2; + door = ry + 1; + } else { + ry = aRoom["y"] + aRoom["height"] + 1; + door = ry - 1; + } + + this.map[rx][door] = 0; // i'm not setting a specific 'door' tile value right now, just empty space. + } else { + ry = RNG$1.getUniformInt(aRoom["y"] + 1, aRoom["y"] + aRoom["height"] - 2); + + if (aDirection == 2) { + rx = aRoom["x"] + aRoom["width"] + 1; + door = rx - 1; + } else { + rx = aRoom["x"] - 2; + door = rx + 1; + } + + this.map[door][ry] = 0; // i'm not setting a specific 'door' tile value right now, just empty space. + } + + return [rx, ry]; + }; + + _proto31._drawCorridor = function _drawCorridor(startPosition, endPosition) { + var xOffset = endPosition[0] - startPosition[0]; + var yOffset = endPosition[1] - startPosition[1]; + var xpos = startPosition[0]; + var ypos = startPosition[1]; + var tempDist; + var xDir; + var yDir; + var move; // 2 element array, element 0 is the direction, element 1 is the total value to move. + + var moves = []; // a list of 2 element arrays + + var xAbs = Math.abs(xOffset); + var yAbs = Math.abs(yOffset); + var percent = RNG$1.getUniform(); // used to split the move at different places along the long axis + + var firstHalf = percent; + var secondHalf = 1 - percent; + xDir = xOffset > 0 ? 2 : 6; + yDir = yOffset > 0 ? 4 : 0; + + if (xAbs < yAbs) { + // move firstHalf of the y offset + tempDist = Math.ceil(yAbs * firstHalf); + moves.push([yDir, tempDist]); // move all the x offset + + moves.push([xDir, xAbs]); // move sendHalf of the y offset + + tempDist = Math.floor(yAbs * secondHalf); + moves.push([yDir, tempDist]); + } else { + // move firstHalf of the x offset + tempDist = Math.ceil(xAbs * firstHalf); + moves.push([xDir, tempDist]); // move all the y offset + + moves.push([yDir, yAbs]); // move secondHalf of the x offset. + + tempDist = Math.floor(xAbs * secondHalf); + moves.push([xDir, tempDist]); + } + + this.map[xpos][ypos] = 0; + + while (moves.length > 0) { + move = moves.pop(); + + while (move[1] > 0) { + xpos += DIRS[8][move[0]][0]; + ypos += DIRS[8][move[0]][1]; + this.map[xpos][ypos] = 0; + move[1] = move[1] - 1; + } + } + }; + + _proto31._createCorridors = function _createCorridors() { + // Draw Corridors between connected rooms + var cw = this._options.cellWidth; + var ch = this._options.cellHeight; + var room; + var connection; + var otherRoom; + var wall; + var otherWall; + + for (var i = 0; i < cw; i++) { + for (var j = 0; j < ch; j++) { + room = this.rooms[i][j]; + + for (var k = 0; k < room["connections"].length; k++) { + connection = room["connections"][k]; + otherRoom = this.rooms[connection[0]][connection[1]]; // figure out what wall our corridor will start one. + // figure out what wall our corridor will end on. + + if (otherRoom["cellx"] > room["cellx"]) { + wall = 2; + otherWall = 4; + } else if (otherRoom["cellx"] < room["cellx"]) { + wall = 4; + otherWall = 2; + } else if (otherRoom["celly"] > room["celly"]) { + wall = 3; + otherWall = 1; + } else { + wall = 1; + otherWall = 3; + } + + this._drawCorridor(this._getWallPosition(room, wall), this._getWallPosition(otherRoom, otherWall)); + } + } + } + }; + + return Rogue; + }(Map); + + var index$2 = { + Arena: Arena, + Uniform: Uniform, + Cellular: Cellular, + Digger: Digger, + EllerMaze: EllerMaze, + DividedMaze: DividedMaze, + IceyMaze: IceyMaze, + Rogue: Rogue + }; + /** + * Base noise generator + */ + + var Noise = function Noise() {}; + + var F2 = 0.5 * (Math.sqrt(3) - 1); + var G2 = (3 - Math.sqrt(3)) / 6; + /** + * A simple 2d implementation of simplex noise by Ondrej Zara + * + * Based on a speed-improved simplex noise algorithm for 2D, 3D and 4D in Java. + * Which is based on example code by Stefan Gustavson (stegu@itn.liu.se). + * With Optimisations by Peter Eastman (peastman@drizzle.stanford.edu). + * Better rank ordering method by Stefan Gustavson in 2012. + */ + + var Simplex = + /*#__PURE__*/ + function (_Noise) { + _inheritsLoose(Simplex, _Noise); + + /** + * @param gradients Random gradients + */ + function Simplex(gradients) { + var _this19; + + if (gradients === void 0) { + gradients = 256; + } + + _this19 = _Noise.call(this) || this; + _this19._gradients = [[0, -1], [1, -1], [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1]]; + var permutations = []; + + for (var i = 0; i < gradients; i++) { + permutations.push(i); + } + + permutations = RNG$1.shuffle(permutations); + _this19._perms = []; + _this19._indexes = []; + + for (var _i12 = 0; _i12 < 2 * gradients; _i12++) { + _this19._perms.push(permutations[_i12 % gradients]); + + _this19._indexes.push(_this19._perms[_i12] % _this19._gradients.length); + } + + return _this19; + } + + var _proto32 = Simplex.prototype; + + _proto32.get = function get(xin, yin) { + var perms = this._perms; + var indexes = this._indexes; + var count = perms.length / 2; + var n0 = 0, + n1 = 0, + n2 = 0, + gi; // Noise contributions from the three corners + // Skew the input space to determine which simplex cell we're in + + var s = (xin + yin) * F2; // Hairy factor for 2D + + var i = Math.floor(xin + s); + var j = Math.floor(yin + s); + var t = (i + j) * G2; + var X0 = i - t; // Unskew the cell origin back to (x,y) space + + var Y0 = j - t; + var x0 = xin - X0; // The x,y distances from the cell origin + + var y0 = yin - Y0; // For the 2D case, the simplex shape is an equilateral triangle. + // Determine which simplex we are in. + + var i1, j1; // Offsets for second (middle) corner of simplex in (i,j) coords + + if (x0 > y0) { + i1 = 1; + j1 = 0; + } else { + // lower triangle, XY order: (0,0)->(1,0)->(1,1) + i1 = 0; + j1 = 1; + } // upper triangle, YX order: (0,0)->(0,1)->(1,1) + // A step of (1,0) in (i,j) means a step of (1-c,-c) in (x,y), and + // a step of (0,1) in (i,j) means a step of (-c,1-c) in (x,y), where + // c = (3-sqrt(3))/6 + + + var x1 = x0 - i1 + G2; // Offsets for middle corner in (x,y) unskewed coords + + var y1 = y0 - j1 + G2; + var x2 = x0 - 1 + 2 * G2; // Offsets for last corner in (x,y) unskewed coords + + var y2 = y0 - 1 + 2 * G2; // Work out the hashed gradient indices of the three simplex corners + + var ii = mod(i, count); + var jj = mod(j, count); // Calculate the contribution from the three corners + + var t0 = 0.5 - x0 * x0 - y0 * y0; + + if (t0 >= 0) { + t0 *= t0; + gi = indexes[ii + perms[jj]]; + var grad = this._gradients[gi]; + n0 = t0 * t0 * (grad[0] * x0 + grad[1] * y0); + } + + var t1 = 0.5 - x1 * x1 - y1 * y1; + + if (t1 >= 0) { + t1 *= t1; + gi = indexes[ii + i1 + perms[jj + j1]]; + var _grad = this._gradients[gi]; + n1 = t1 * t1 * (_grad[0] * x1 + _grad[1] * y1); + } + + var t2 = 0.5 - x2 * x2 - y2 * y2; + + if (t2 >= 0) { + t2 *= t2; + gi = indexes[ii + 1 + perms[jj + 1]]; + var _grad2 = this._gradients[gi]; + n2 = t2 * t2 * (_grad2[0] * x2 + _grad2[1] * y2); + } // Add contributions from each corner to get the final noise value. + // The result is scaled to return values in the interval [-1,1]. + + + return 70 * (n0 + n1 + n2); + }; + + return Simplex; + }(Noise); + + var index$3 = { + Simplex: Simplex + }; + /** + * @class Abstract pathfinder + * @param {int} toX Target X coord + * @param {int} toY Target Y coord + * @param {function} passableCallback Callback to determine map passability + * @param {object} [options] + * @param {int} [options.topology=8] + */ + + var Path = + /*#__PURE__*/ + function () { + function Path(toX, toY, passableCallback, options) { + if (options === void 0) { + options = {}; + } + + this._toX = toX; + this._toY = toY; + this._passableCallback = passableCallback; + this._options = Object.assign({ + topology: 8 + }, options); + this._dirs = DIRS[this._options.topology]; + + if (this._options.topology == 8) { + /* reorder dirs for more aesthetic result (vertical/horizontal first) */ + this._dirs = [this._dirs[0], this._dirs[2], this._dirs[4], this._dirs[6], this._dirs[1], this._dirs[3], this._dirs[5], this._dirs[7]]; + } + } + + var _proto33 = Path.prototype; + + _proto33._getNeighbors = function _getNeighbors(cx, cy) { + var result = []; + + for (var i = 0; i < this._dirs.length; i++) { + var dir = this._dirs[i]; + var x = cx + dir[0]; + var y = cy + dir[1]; + + if (!this._passableCallback(x, y)) { + continue; + } + + result.push([x, y]); + } + + return result; + }; + + return Path; + }(); + /** + * @class Simplified Dijkstra's algorithm: all edges have a value of 1 + * @augments ROT.Path + * @see ROT.Path + */ + + + var Dijkstra = + /*#__PURE__*/ + function (_Path) { + _inheritsLoose(Dijkstra, _Path); + + function Dijkstra(toX, toY, passableCallback, options) { + var _this20; + + _this20 = _Path.call(this, toX, toY, passableCallback, options) || this; + _this20._computed = {}; + _this20._todo = []; + + _this20._add(toX, toY, null); + + return _this20; + } + /** + * Compute a path from a given point + * @see ROT.Path#compute + */ + + + var _proto34 = Dijkstra.prototype; + + _proto34.compute = function compute(fromX, fromY, callback) { + var key = fromX + "," + fromY; + + if (!(key in this._computed)) { + this._compute(fromX, fromY); + } + + if (!(key in this._computed)) { + return; + } + + var item = this._computed[key]; + + while (item) { + callback(item.x, item.y); + item = item.prev; + } + }; + /** + * Compute a non-cached value + */ + + + _proto34._compute = function _compute(fromX, fromY) { + while (this._todo.length) { + var item = this._todo.shift(); + + if (item.x == fromX && item.y == fromY) { + return; + } + + var neighbors = this._getNeighbors(item.x, item.y); + + for (var i = 0; i < neighbors.length; i++) { + var neighbor = neighbors[i]; + var x = neighbor[0]; + var y = neighbor[1]; + var id = x + "," + y; + + if (id in this._computed) { + continue; + } + /* already done */ + + + this._add(x, y, item); + } + } + }; + + _proto34._add = function _add(x, y, prev) { + var obj = { + x: x, + y: y, + prev: prev + }; + this._computed[x + "," + y] = obj; + + this._todo.push(obj); + }; + + return Dijkstra; + }(Path); + /** + * @class Simplified A* algorithm: all edges have a value of 1 + * @augments ROT.Path + * @see ROT.Path + */ + + + var AStar = + /*#__PURE__*/ + function (_Path2) { + _inheritsLoose(AStar, _Path2); + + function AStar(toX, toY, passableCallback, options) { + var _this21; + + if (options === void 0) { + options = {}; + } + + _this21 = _Path2.call(this, toX, toY, passableCallback, options) || this; + _this21._todo = []; + _this21._done = {}; + return _this21; + } + /** + * Compute a path from a given point + * @see ROT.Path#compute + */ + + + var _proto35 = AStar.prototype; + + _proto35.compute = function compute(fromX, fromY, callback) { + this._todo = []; + this._done = {}; + this._fromX = fromX; + this._fromY = fromY; + + this._add(this._toX, this._toY, null); + + while (this._todo.length) { + var _item = this._todo.shift(); + + var id = _item.x + "," + _item.y; + + if (id in this._done) { + continue; + } + + this._done[id] = _item; + + if (_item.x == fromX && _item.y == fromY) { + break; + } + + var neighbors = this._getNeighbors(_item.x, _item.y); + + for (var i = 0; i < neighbors.length; i++) { + var neighbor = neighbors[i]; + var x = neighbor[0]; + var y = neighbor[1]; + + var _id3 = x + "," + y; + + if (_id3 in this._done) { + continue; + } + + this._add(x, y, _item); + } + } + + var item = this._done[fromX + "," + fromY]; + + if (!item) { + return; + } + + while (item) { + callback(item.x, item.y); + item = item.prev; + } + }; + + _proto35._add = function _add(x, y, prev) { + var h = this._distance(x, y); + + var obj = { + x: x, + y: y, + prev: prev, + g: prev ? prev.g + 1 : 0, + h: h + }; + /* insert into priority queue */ + + var f = obj.g + obj.h; + + for (var i = 0; i < this._todo.length; i++) { + var item = this._todo[i]; + var itemF = item.g + item.h; + + if (f < itemF || f == itemF && h < item.h) { + this._todo.splice(i, 0, obj); + + return; + } + } + + this._todo.push(obj); + }; + + _proto35._distance = function _distance(x, y) { + switch (this._options.topology) { + case 4: + return Math.abs(x - this._fromX) + Math.abs(y - this._fromY); + break; + + case 6: + var dx = Math.abs(x - this._fromX); + var dy = Math.abs(y - this._fromY); + return dy + Math.max(0, (dx - dy) / 2); + break; + + case 8: + return Math.max(Math.abs(x - this._fromX), Math.abs(y - this._fromY)); + break; + } + }; + + return AStar; + }(Path); + + var index$4 = { + Dijkstra: Dijkstra, + AStar: AStar + }; + /** + * @class Asynchronous main loop + * @param {ROT.Scheduler} scheduler + */ + + var Engine = + /*#__PURE__*/ + function () { + function Engine(scheduler) { + this._scheduler = scheduler; + this._lock = 1; + } + /** + * Start the main loop. When this call returns, the loop is locked. + */ + + + var _proto36 = Engine.prototype; + + _proto36.start = function start() { + return this.unlock(); + }; + /** + * Interrupt the engine by an asynchronous action + */ + + + _proto36.lock = function lock() { + this._lock++; + return this; + }; + /** + * Resume execution (paused by a previous lock) + */ + + + _proto36.unlock = function unlock() { + if (!this._lock) { + throw new Error("Cannot unlock unlocked engine"); + } + + this._lock--; + + while (!this._lock) { + var actor = this._scheduler.next(); + + if (!actor) { + return this.lock(); + } + /* no actors */ + + + var result = actor.act(); + + if (result && result.then) { + /* actor returned a "thenable", looks like a Promise */ + this.lock(); + result.then(this.unlock.bind(this)); + } + } + + return this; + }; + + return Engine; + }(); + /** + * Lighting computation, based on a traditional FOV for multiple light sources and multiple passes. + */ + + + var Lighting = + /*#__PURE__*/ + function () { + function Lighting(reflectivityCallback, options) { + if (options === void 0) { + options = {}; + } + + this._reflectivityCallback = reflectivityCallback; + this._options = {}; + options = Object.assign({ + passes: 1, + emissionThreshold: 100, + range: 10 + }, options); + this._lights = {}; + this._reflectivityCache = {}; + this._fovCache = {}; + this.setOptions(options); + } + /** + * Adjust options at runtime + */ + + + var _proto37 = Lighting.prototype; + + _proto37.setOptions = function setOptions(options) { + Object.assign(this._options, options); + + if (options && options.range) { + this.reset(); + } + + return this; + }; + /** + * Set the used Field-Of-View algo + */ + + + _proto37.setFOV = function setFOV(fov) { + this._fov = fov; + this._fovCache = {}; + return this; + }; + /** + * Set (or remove) a light source + */ + + + _proto37.setLight = function setLight(x, y, color) { + var key = x + "," + y; + + if (color) { + this._lights[key] = typeof color == "string" ? fromString(color) : color; + } else { + delete this._lights[key]; + } + + return this; + }; + /** + * Remove all light sources + */ + + + _proto37.clearLights = function clearLights() { + this._lights = {}; + }; + /** + * Reset the pre-computed topology values. Call whenever the underlying map changes its light-passability. + */ + + + _proto37.reset = function reset() { + this._reflectivityCache = {}; + this._fovCache = {}; + return this; + }; + /** + * Compute the lighting + */ + + + _proto37.compute = function compute(lightingCallback) { + var doneCells = {}; + var emittingCells = {}; + var litCells = {}; + + for (var key in this._lights) { + /* prepare emitters for first pass */ + var light = this._lights[key]; + emittingCells[key] = [0, 0, 0]; + add_(emittingCells[key], light); + } + + for (var i = 0; i < this._options.passes; i++) { + /* main loop */ + this._emitLight(emittingCells, litCells, doneCells); + + if (i + 1 == this._options.passes) { + continue; + } + /* not for the last pass */ + + + emittingCells = this._computeEmitters(litCells, doneCells); + } + + for (var litKey in litCells) { + /* let the user know what and how is lit */ + var parts = litKey.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + lightingCallback(x, y, litCells[litKey]); + } + + return this; + }; + /** + * Compute one iteration from all emitting cells + * @param emittingCells These emit light + * @param litCells Add projected light to these + * @param doneCells These already emitted, forbid them from further calculations + */ + + + _proto37._emitLight = function _emitLight(emittingCells, litCells, doneCells) { + for (var key in emittingCells) { + var parts = key.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + + this._emitLightFromCell(x, y, emittingCells[key], litCells); + + doneCells[key] = 1; + } + + return this; + }; + /** + * Prepare a list of emitters for next pass + */ + + + _proto37._computeEmitters = function _computeEmitters(litCells, doneCells) { + var result = {}; + + for (var key in litCells) { + if (key in doneCells) { + continue; + } + /* already emitted */ + + + var _color = litCells[key]; + var reflectivity = void 0; + + if (key in this._reflectivityCache) { + reflectivity = this._reflectivityCache[key]; + } else { + var parts = key.split(","); + var x = parseInt(parts[0]); + var y = parseInt(parts[1]); + reflectivity = this._reflectivityCallback(x, y); + this._reflectivityCache[key] = reflectivity; + } + + if (reflectivity == 0) { + continue; + } + /* will not reflect at all */ + + /* compute emission color */ + + + var emission = [0, 0, 0]; + var intensity = 0; + + for (var i = 0; i < 3; i++) { + var part = Math.round(_color[i] * reflectivity); + emission[i] = part; + intensity += part; + } + + if (intensity > this._options.emissionThreshold) { + result[key] = emission; + } + } + + return result; + }; + /** + * Compute one iteration from one cell + */ + + + _proto37._emitLightFromCell = function _emitLightFromCell(x, y, color, litCells) { + var key = x + "," + y; + var fov; + + if (key in this._fovCache) { + fov = this._fovCache[key]; + } else { + fov = this._updateFOV(x, y); + } + + for (var fovKey in fov) { + var formFactor = fov[fovKey]; + var result = void 0; + + if (fovKey in litCells) { + /* already lit */ + result = litCells[fovKey]; + } else { + /* newly lit */ + result = [0, 0, 0]; + litCells[fovKey] = result; + } + + for (var i = 0; i < 3; i++) { + result[i] += Math.round(color[i] * formFactor); + } + /* add light color */ + + } + + return this; + }; + /** + * Compute FOV ("form factor") for a potential light source at [x,y] + */ + + + _proto37._updateFOV = function _updateFOV(x, y) { + var key1 = x + "," + y; + var cache = {}; + this._fovCache[key1] = cache; + var range = this._options.range; + + function cb(x, y, r, vis) { + var key2 = x + "," + y; + var formFactor = vis * (1 - r / range); + + if (formFactor == 0) { + return; + } + + cache[key2] = formFactor; + } + + this._fov.compute(x, y, range, cb.bind(this)); + + return cache; + }; + + return Lighting; + }(); + + var Util = util; + var Color = color; + var Text = text; + exports.Util = Util; + exports.Color = Color; + exports.Text = Text; + exports.RNG = RNG$1; + exports.Display = Display; + exports.StringGenerator = StringGenerator; + exports.EventQueue = EventQueue; + exports.Scheduler = index; + exports.FOV = index$1; + exports.Map = index$2; + exports.Noise = index$3; + exports.Path = index$4; + exports.Engine = Engine; + exports.Lighting = Lighting; + exports.DEFAULT_WIDTH = DEFAULT_WIDTH; + exports.DEFAULT_HEIGHT = DEFAULT_HEIGHT; + exports.DIRS = DIRS; + exports.KEYS = KEYS; + Object.defineProperty(exports, '__esModule', { + value: true + }); +}); + diff --git a/rot.min.js b/rot.min.js new file mode 100644 index 0000000..c8d1f38 --- /dev/null +++ b/rot.min.js @@ -0,0 +1,138 @@ +var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(g,p,r){g!=Array.prototype&&g!=Object.prototype&&(g[p]=r.value)};$jscomp.getGlobal=function(g){return"undefined"!=typeof window&&window===g?g:"undefined"!=typeof global&&null!=global?global:g};$jscomp.global=$jscomp.getGlobal(this); +$jscomp.polyfill=function(g,p,r,t){if(p){r=$jscomp.global;g=g.split(".");for(t=0;tr&&(r=Math.max(0,p+r));if(null==t||t>p)t=p;t=Number(t);0>t&&(t=Math.max(0,p+t));for(r=Number(r||0);rg||1342177279>>=1)p+=p;return t}},"es6","es3");$jscomp.stringPadding=function(g,p){g=void 0!==g?String(g):" ";return 0a?a:d}function t(d){return d.charAt(0).toUpperCase()+d.substring(1)}function w(d){for(var c=arguments.length,a=Array(1c;c++)a[c+1]+=16*a[c],a.splice(c,1);else a=(c=d.match(/rgb\(([0-9, ]+)\)/i))? +c[1].split(/\s*,\s*/).map(function(b){return parseInt(b)}):[0,0,0];Q[d]=a}return a.slice()}function Y(d){for(var c=arguments.length,a=Array(1c;c++)for(b=0;be;e++)b[e]=Math.round(b[e]+a*(c[e]-d[e]));return b}function aa(d,c,a){void 0===a&&(a=.5);d=R(d);c=R(c);for(var b=0;3>b;b++)d[b]+=a*(c[b]-d[b]);return ba(d)}function R(d){var c=d[0]/255,a=d[1]/255; +d=d[2]/255;var b=Math.max(c,a,d),e=Math.min(c,a,d),f=0,m=(b+e)/2;if(b==e)e=0;else{var k=b-e;e=.5a&&(a+=1);1a?c:a<2/3?d+(c-d)*(2/3-a)*6:d}function ba(d){var c=d[2];if(0==d[1])return c=Math.round(255*c),[c,c,c];var a=d[1];a=.5>c?c*(1+a):c+a-c*a;var b=2*c-a;c=S(b,a,d[0]+1/3);var e=S(b,a,d[0]);d=S(b,a,d[0]-1/3);return[Math.round(255* +c),Math.round(255*e),Math.round(255*d)]}function fa(d,c,a){var b=d.createShader(d.VERTEX_SHADER);d.shaderSource(b,c);d.compileShader(b);if(!d.getShaderParameter(b,d.COMPILE_STATUS))throw Error(d.getShaderInfoLog(b)||"");c=d.createShader(d.FRAGMENT_SHADER);d.shaderSource(c,a);d.compileShader(c);if(!d.getShaderParameter(c,d.COMPILE_STATUS))throw Error(d.getShaderInfoLog(c)||"");a=d.createProgram();d.attachShader(a,b);d.attachShader(a,c);d.linkProgram(a);if(!d.getProgramParameter(a,d.LINK_STATUS))throw Error(d.getProgramInfoLog(a)|| +"");return a}function ha(d){var c=new Float32Array([0,0,1,0,0,1,1,1]),a=d.createBuffer();d.bindBuffer(d.ARRAY_BUFFER,a);d.bufferData(d.ARRAY_BUFFER,c,d.STATIC_DRAW);d.enableVertexAttribArray(0);d.vertexAttribPointer(0,2,d.FLOAT,!1,0,0)}function M(d){if(!(d in T)){if("transparent"==d)var c=[0,0,0,0];else if(-1a;a++)c[a]/=255}else c=L(d).map(function(b){return b/255}),c.push(1);T[d]=c}return T[d]}function U(d){d=L(d);return 36* +Math.floor(.0234375*d[0])+6*Math.floor(.0234375*d[1])+1*Math.floor(.0234375*d[2])+16}function V(d,c){var a=[],b=0;d.replace(ia,function(e,m,k,h){var f=d.substring(b,h);f.length&&a.push({type:0,value:f});a.push({type:"c"==m?2:3,value:k.trim()});b=h+e.length;return""});var e=d.substring(b);e.length&&a.push({type:0,value:e});return ja(a,c)}function ja(d,c){c||(c=Infinity);for(var a=0,b=0,e=-1;ac){for(m=-1;;){var k=f.value.indexOf(" ",m+1);if(-1==k)break;if(b+k>c)break;m=k}-1!=m?f.value=N(d,a,m,!0):-1!=e?(a=d[e],f=a.value.lastIndexOf(" "),a.value=N(d,e,f,!0),a=e):f.value=N(d,a,c-b,!1)}else b+=f.value.length,-1!=f.value.indexOf(" ")&&(e=a);a++}else d.splice(a,1)}}d.push({type:1});c=null;for(b= +0;ba?1/a:a;this._s0=2.3283064365386963E-10*(a>>>0);a=69069*a+1>>>0;this._s1=2.3283064365386963E-10*a;this._s2=2.3283064365386963E-10*(69069*a+1>>>0);this._c=1;return this};c.getUniform=function(){var a=2091639*this._s0+2.3283064365386963E-10*this._c;this._s0=this._s1;this._s1=this._s2;this._c=a|0;return this._s2=a-this._c};c.getUniformInt=function(a,b){var e=Math.max(a,b);a=Math.min(a,b);return Math.floor(this.getUniform()* +(e-a+1))+a};c.getNormal=function(a,b){void 0===a&&(a=0);void 0===b&&(b=1);do{var e=2*this.getUniform()-1;var f=2*this.getUniform()-1;f=e*e+f*f}while(1b||0>e||b>=f.width||e>=f.height?[-1,-1]:this._normalizedEventToPosition(b,e)};return c}(I);w.map={s:"toString"};var ka=Object.freeze({mod:p,clamp:r,capitalize:t,format:w}),O=function(d){function c(){var b=d.call(this)||this; +b._spacingX=0;b._spacingY=0;b._hexSize=0;return b}_inheritsLoose(c,d);var a=c.prototype;a.draw=function(b,e){var f=b[2],a=b[3],k=b[4];b=[(b[0]+1)*this._spacingX,b[1]*this._spacingY+this._hexSize];this._options.transpose&&b.reverse();e&&(this._ctx.fillStyle=k,this._fill(b[0],b[1]));if(f)for(this._ctx.fillStyle=a,e=[].concat(f),f=0;fa;a++)for(e=0;ea;a++){for(e=0;e< +b.length;e++)c[a]*=b[e][a]/255;c[a]=Math.round(c[a])}return c},multiply_:function(d){for(var c=arguments.length,a=Array(1c;c++){for(b=0;ba;a++)d[a]+=c instanceof Array?Math.round(q.getNormal(0,c[a])):c;return d},rgb2hsl:R,hsl2rgb:ba, +toRGB:function(d){return"rgb("+d.map(function(c){return r(c,0,255)}).join(",")+")"},toHex:function(d){return"#"+d.map(function(c){return r(c,0,255).toString(16).padStart(2,"0")}).join("")}});var x=function(d){function c(){var b=d.call(this)||this;b._uniforms={};try{b._gl=b._initWebGL()}catch(e){alert(e.message)}return b}_inheritsLoose(c,d);c.isSupported=function(){return!!document.createElement("canvas").getContext("webgl2",{preserveDrawingBuffer:!0})};var a=c.prototype;a.schedule=function(b){requestAnimationFrame(b)}; +a.getContainer=function(){return this._gl.canvas};a.setOptions=function(b){var e=this;d.prototype.setOptions.call(this,b);this._updateSize();var f=this._options.tileSet;f&&"complete"in f&&!f.complete?f.addEventListener("load",function(){return e._updateTexture(f)}):this._updateTexture(f)};a.draw=function(b,e){var f=this._gl,a=this._options,k=b[0],h=b[1],c=b[2],d=b[3];b=b[4];f.scissor(k*a.tileWidth,f.canvas.height-(h+1)*a.tileHeight,a.tileWidth,a.tileHeight);e&&(a.tileColorize?f.clearColor(0,0,0,0): +f.clearColor.apply(f,M(b)),f.clear(f.COLOR_BUFFER_BIT));if(c)for(e=[].concat(c),c=[].concat(b),d=[].concat(d),f.uniform2fv(this._uniforms.targetPosRel,[k,h]),k=0;k +b||0>e||b>=f.width||e>=f.height?[-1,-1]:this._normalizedEventToPosition(b,e)};a._initWebGL=function(){var b=this,e=document.createElement("canvas").getContext("webgl2",{preserveDrawingBuffer:!0});window.gl=e;var f=fa(e,la,ma);e.useProgram(f);ha(e);na.forEach(function(a){return b._uniforms[a]=e.getUniformLocation(f,a)});this._program=f;e.enable(e.BLEND);e.blendFuncSeparate(e.SRC_ALPHA,e.ONE_MINUS_SRC_ALPHA,e.ONE,e.ONE_MINUS_SRC_ALPHA);e.enable(e.SCISSOR_TEST);return e};a._normalizedEventToPosition= +function(b,e){return[Math.floor(b/this._options.tileWidth),Math.floor(e/this._options.tileHeight)]};a._updateSize=function(){var b=this._gl,e=this._options,a=[e.width*e.tileWidth,e.height*e.tileHeight];b.canvas.width=a[0];b.canvas.height=a[1];b.viewport(0,0,a[0],a[1]);b.uniform2fv(this._uniforms.tileSize,[e.tileWidth,e.tileHeight]);b.uniform2fv(this._uniforms.targetSize,a)};a._updateTexture=function(b){var e=this._gl,a=e.createTexture();e.bindTexture(e.TEXTURE_2D,a);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MAG_FILTER, +e.NEAREST);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.NEAREST);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.REPEAT);e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.REPEAT);e.pixelStorei(e.UNPACK_FLIP_Y_WEBGL,0);e.texImage2D(e.TEXTURE_2D,0,e.RGBA,e.RGBA,e.UNSIGNED_BYTE,b)};return c}(I),na="targetPosRel tilesetPosAbs tileSize targetSize colorize bg tint".split(" "),la="#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}", +ma="#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}", +T={},u=function(d){function c(){var b=d.call(this)||this;b._offset=[0,0];b._cursor=[-1,-1];b._lastColor="";return b}_inheritsLoose(c,d);var a=c.prototype;a.schedule=function(b){setTimeout(b,1E3/60)};a.setOptions=function(b){d.prototype.setOptions.call(this,b);var e=[b.width,b.height];this._offset=this.computeSize().map(function(b,a){return Math.floor((b-e[a])/2)})};a.clear=function(){process.stdout.write("\u001b[0;48;5;"+U(this._options.bg)+"m\u001b[2J")};a.draw=function(b,e){var a=b[2],m=b[3],k= +b[4],c=this._offset[0]+b[0],d=this._offset[1]+b[1];b=this.computeSize();if(!(0>c||c>=b[0]||0>d||d>=b[1])){if(c!==this._cursor[0]||d!==this._cursor[1])process.stdout.write("\u001b["+(d+1)+";"+(c+1)+"H"),this._cursor[0]=c,this._cursor[1]=d;e&&(a||(a=" "));a&&(e="\u001b[0;38;5;"+U(m)+";48;5;"+U(k)+"m",e!==this._lastColor&&(process.stdout.write(e),this._lastColor=e),a=[].concat(a),process.stdout.write(a[0]),this._cursor[0]++,this._cursor[0]>=b[0]&&(this._cursor[0]=0,this._cursor[1]++))}};a.computeFontSize= +function(){throw Error("Terminal backend has no notion of font size");};a.eventToPosition=function(b,e){return[b,e]};a.computeSize=function(){return[process.stdout.columns,process.stdout.rows]};return c}(I),ia=/%([bc]){([^}]*)}/g;I=Object.freeze({TYPE_TEXT:0,TYPE_NEWLINE:1,TYPE_FG:2,TYPE_BG:3,measure:function(d,c){var a={width:0,height:1};d=V(d,c);for(var b=c=0;bl||65500l||65518this._options.order?a=a.slice(-this._options.order):a.lengthb){e=f;break}this._events.splice(e,0,a);this._eventTimes.splice(e,0,b)};c.get=function(){if(!this._events.length)return null;var a=this._eventTimes.splice(0,1)[0];if(0b)return e=this._visibleCoords(0,e,a,m),b=this._visibleCoords(360+b,360,a,m),e||b;for(var f=0;fe[0])return b=this._checkVisibility(b,[b[1],b[1]],a,c),e=this._checkVisibility([0,1],e,a,c),(b+e)/2;for(var f=0,m=!1;fd&&f%2&&(g=!1);if(!g)return 0;m=d-f+1;if(m%2)f%2?(d=c[f],d=(e[0]*d[1]-d[0]*e[1])/(d[1]*e[1]),a&&c.splice(f,m,e)):(d=c[d],d=(d[0]*b[1]-b[0]*d[1])/(b[1]*d[1]),a&&c.splice(f,m,b));else if(f%2)l=c[f],d=c[d],d=(d[0]*l[1]-l[0]*d[1])/(l[1]*d[1]),a&&c.splice(f,m);else return a&&c.splice(f,m,b,e),1;return d/((e[0]*b[1]-b[0]*e[1])/(b[1]*e[1]))};return c}(u);var C=[[-1,0,0,1],[0,-1,1,0],[0,-1,-1,0],[-1,0,0,-1],[1, +0,0,-1],[0,1,-1,0],[0,1,1,0],[1,0,0,1]];u=function(d){function c(){return d.apply(this,arguments)||this}_inheritsLoose(c,d);var a=c.prototype;a.compute=function(b,e,a,c){c(b,e,0,1);for(var f=0;f=f;){f+=1;var z=b+f*n+m*l,y=e+f*g+m*q,r=(f-.5)/(m+.5),t=(f+.5)/(m-.5);if(!(t>c)){if(rthis._options.timeLimit)return null;this._map=this._fillMap(1);this._dug=0;this._rooms=[];this._unconnected=[];this._generateRooms();if(!(2>this._rooms.length)&&this._generateCorridors())break}if(b)for(a=0;athis._options.roomDugPercentage)break}while(f)};a._generateRoom=function(){for(var b=0;b=n&&d[e]<=l){c=d.slice();n=0;switch(h){case 0:n=a.getTop()- +1;break;case 1:n=a.getRight()+1;break;case 2:n=a.getBottom()+1;break;case 3:n=a.getLeft()-1}c[(e+1)%2]=n;this._digLine([d,c])}else if(d[e]l+1){c=d[e]-c[e];n=0;switch(h){case 0:case 1:n=0>c?3:1;break;case 2:case 3:n=0>c?1:3}c=this._placeInWall(a,(h+n)%4);if(!c)return!1;h=[0,0];h[e]=d[e];e=(e+1)%2;h[e]=c[e];this._digLine([d,h,c])}else{n=(e+1)%2;c=this._placeInWall(a,h);if(!c)return!1;h=Math.round((c[n]+d[n])/2);l=[0,0];var g=[0,0];l[e]=d[e];l[n]=h;g[e]=c[e];g[n]=h;this._digLine([d,l,g,c])}b.addDoor(d[0], +d[1]);a.addDoor(c[0],c[1]);e=this._unconnected.indexOf(b);-1!=e&&(this._unconnected.splice(e,1),this._connected.push(b));e=this._unconnected.indexOf(a);-1!=e&&(this._unconnected.splice(e,1),this._connected.push(a));return!0};a._placeInWall=function(b,a){var e=[0,0],c=[0,0],d=0;switch(a){case 0:c=[1,0];e=[b.getLeft(),b.getTop()-1];d=b.getRight()-b.getLeft()+1;break;case 1:c=[0,1];e=[b.getRight()+1,b.getTop()];d=b.getBottom()-b.getTop()+1;break;case 2:c=[1,0];e=[b.getLeft(),b.getBottom()+1];d=b.getRight()- +b.getLeft()+1;break;case 3:c=[0,1],e=[b.getLeft()-1,b.getTop()],d=b.getBottom()-b.getTop()+1}b=[];a=-2;for(var h=0;hb||0>a||b>=this._width||a>=this._height?!1:1==this._map[b][a]};a._canBeDugCallback=function(b,a){return 1>b||1>a||b+1>=this._width||a+1>=this._height?!1:1==this._map[b][a]};return c}(H);var E=function(d){function c(b,a,f){void 0===f&&(f={});b=d.call(this,b,a)||this;b._options={born:[5,6,7,8],survive:[4,5,6,7,8],topology:8};b.setOptions(f);b._dirs=v[b._options.topology];b._map=b._fillMap(0);return b}_inheritsLoose(c,d);var a=c.prototype; +a.randomize=function(b){for(var a=0;ah||h>=this._width||0>d||d>=this._height||(e+=1==this._map[h][d]?1:0)}return e};a.connect=function(b,a,f){a||(a=0);var e=[],c={},d=1,n=[0,0];6==this._options.topology&& +(d=2,n=[0,1]);for(var l=0;ll&&!(h.lengthd);l++);return[e,c]};a._getClosest=function(b,a){var e=null,c=null,d;for(d in a){var h=a[d],n=(h[0]-b[0])*(h[0]-b[0])+(h[1]- +b[1])*(h[1]-b[1]);if(null==c||nf[1]&&(e--, +g=1);m=mf[0]?m-g:f[1]%2?m-g:m+g;this._map[m][e]=k;g=[m,e];var q=this._pointKey(g);c[q]=g;delete d[q]}h&&h(a,b)};a._freeSpace=function(b,a,f){return 0<=b&&bthis._options.timeLimit)break;var d=this._findWall();if(!d)break;var h=d.split(",");d=parseInt(h[0]);h=parseInt(h[1]);var g=this._getDiggingDirection(d,h);if(g){var l=0;do if(l++,this._tryFeature(d,h,g[0],g[1])){this._removeSurroundingWalls(d,h);this._removeSurroundingWalls(d-g[0],h-g[1]);break}while(l< +this._featureAttempts);for(var q in this._walls)1b||0>a||b>=this._width||a>=this._height?!1:1==this._map[b][a]};a._canBeDugCallback=function(b,a){return 1> +b||1>a||b+1>=this._width||a+1>=this._height?!1:1==this._map[b][a]};a._priorityWallCallback=function(b,a){this._walls[b+","+a]=2};a._firstRoom=function(){var b=P.createRandomCenter(Math.floor(this._width/2),Math.floor(this._height/2),this._options);this._rooms.push(b);b.create(this._digCallback)};a._findWall=function(){var b=[],a=[],f;for(f in this._walls)2==this._walls[f]?a.push(f):b.push(f);b=a.length?a:b;if(!b.length)return null;b=q.getItem(b.sort());delete this._walls[b];return b};a._tryFeature= +function(b,a,f,c){var e=q.getWeightedValue(this._features);b=qa[e].createRandomAt(b,a,f,c,this._options);if(!b.isValid(this._isWallCallback,this._canBeDugCallback))return!1;b.create(this._digCallback);b instanceof P&&this._rooms.push(b);b instanceof X&&(b.createPriorityWalls(this._priorityWallCallback),this._corridors.push(b));return!0};a._removeSurroundingWalls=function(b,a){for(var e=v[4],c=0;c=b||0>=a||b>=this._width-1||a>=this._height-1)return null;for(var e=null,c=v[4],d=0;dr;r++){var t=g+2*h[r][0];var A=l+2*h[r][1];if(this._isFree(d,t,A,a,c)){d[t][A]=0;d[g+h[r][0]][l+h[r][1]]=0;g=t;l= +A;p=!1;k++;break}}}while(!p)}}while(k+1a;a++)b[a][0]=0,b[a][1]=0;switch(Math.floor(4*q.getUniform())){case 0:b[0][0]=-1;b[1][0]=1;b[2][1]=-1;b[3][1]=1;break;case 1:b[3][0]=-1;b[2][0]=1;b[1][1]=-1;b[0][1]=1;break;case 2:b[2][0]=-1;b[3][0]=1;b[0][1]=-1;b[1][1]=1;break;case 3:b[1][0]=-1,b[0][0]=1,b[3][1]=-1,b[2][1]=1}};a._isFree=function(b,a,c,d,k){return 1>a|| +1>c||a>=d||c>=k?!1:b[a][c]};return c}(u);u=function(d){function c(b,a,c){b=d.call(this,b,a)||this;b.map=[];b.rooms=[];b.connectedCells=[];c=Object.assign({cellWidth:3,cellHeight:3},c);c.hasOwnProperty("roomWidth")||(c.roomWidth=b._calculateRoomSize(b._width,c.cellWidth));c.hasOwnProperty("roomHeight")||(c.roomHeight=b._calculateRoomSize(b._height,c.cellHeight));b._options=c;return b}_inheritsLoose(c,d);var a=c.prototype;a.create=function(b){this.map=this._fillMap(1);this.rooms=[];this.connectedCells= +[];this._initRooms();this._connectRooms();this._connectUnconnectedRooms();this._createRandomRoomConnections();this._createRooms();this._createCorridors();if(b)for(var a=0;ab&&(b=2);2>c&&(c=2);return[b,c]};a._initRooms=function(){for(var b=0;bh||h>=this._options.cellWidth||0>k||k>=this._options.cellHeight)){var g=this.rooms[b][a];if(0r||r>=b||0>p||p>=a)){d=this.rooms[r][p]; +k=!0;if(0==d.connections.length)break;for(r=0;rA-(u.y+u.height);)A++;if(0t-(u.x+u.width);)t++;u=Math.round(q.getUniformInt(0,k-g)/2);for(var x=Math.round(q.getUniformInt(0,h-l)/2);t+u+g>=b;)u?u--:g--;for(;A+x+l>=a;)x?x--:l--;t+=u;A+=x;this.rooms[v][w].x=t;this.rooms[v][w].y=A;this.rooms[v][w].width=g;this.rooms[v][w].height=l;for(u=t;ud.cellx? +(k=2,h=4):g.cellxd.celly?(k=3,h=1):(k=1,h=3),this._drawCorridor(this._getWallPosition(d,k),this._getWallPosition(g,h))}};return c}(u);x={Arena:x,Uniform:D,Cellular:E,Digger:H,EllerMaze:ra,DividedMaze:sa,IceyMaze:ta,Rogue:u};var ua=.5*(Math.sqrt(3)-1),K=(3-Math.sqrt(3))/6;u={Simplex:function(d){function c(a){void 0===a&&(a=256);var b=d.call(this)||this;b._gradients=[[0,-1],[1,-1],[1,0],[1,1],[0,1],[-1,1],[-1,0],[-1,-1]];for(var c=[],f=0;fu){var v=1;var w=0}else v=0,w=1;t=l-v+K;var x=u-w+K;b=l-1+2*K;a=u-1+2*K;q=p(q,g);g=p(r,g);var B=.5-l*l-u*u;0<=B&&(B*=B,r=d[q+c[g]],k=this._gradients[r],k=B*B*(k[0]*l+k[1]*u));l=.5-t*t- +x*x;0<=l&&(l*=l,r=d[q+v+c[g+w]],h=this._gradients[r],h=l*l*(h[0]*t+h[1]*x));l=.5-b*b-a*a;0<=l&&(l*=l,r=d[q+1+c[g+1]],c=this._gradients[r],n=l*l*(c[0]*b+c[1]*a));return 70*(k+h+n)};return c}(function(){})};E=function(){function d(c,a,b,d){void 0===d&&(d={});this._toX=c;this._toY=a;this._passableCallback=b;this._options=Object.assign({topology:8},d);this._dirs=v[this._options.topology];8==this._options.topology&&(this._dirs=[this._dirs[0],this._dirs[2],this._dirs[4],this._dirs[6],this._dirs[1],this._dirs[3], +this._dirs[5],this._dirs[7]])}d.prototype._getNeighbors=function(c,a){for(var b=[],d=0;dl;l++){var p=Math.round(g[l]*k);h[l]=p;n+=p}n>this._options.emissionThreshold&&(c[d]=h)}}return c};c._emitLightFromCell=function(a,b,c,d){var e=a+","+b;a=e in this._fovCache?this._fovCache[e]:this._updateFOV(a,b);for(var f in a){b=a[f];f in +d?e=d[f]:(e=[0,0,0],d[f]=e);for(var g=0;3>g;g++)e[g]+=Math.round(c[g]*b)}return this};c._updateFOV=function(a,b){var c={};this._fovCache[a+","+b]=c;var d=this._options.range;this._fov.compute(a,b,d,function(a,b,e,f){e=f*(1-e/d);0!=e&&(c[a+","+b]=e)}.bind(this));return c};return d}();g.Util=ka;g.Color=J;g.Text=I;g.RNG=q;g.Display=G;g.StringGenerator=O;g.EventQueue=ea;g.Scheduler=F;g.FOV=B;g.Map=x;g.Noise=u;g.Path=D;g.Engine=E;g.Lighting=H;g.DEFAULT_WIDTH=80;g.DEFAULT_HEIGHT=25;g.DIRS=v;g.KEYS={VK_CANCEL:3, +VK_HELP:6,VK_BACK_SPACE:8,VK_TAB:9,VK_CLEAR:12,VK_RETURN:13,VK_ENTER:14,VK_SHIFT:16,VK_CONTROL:17,VK_ALT:18,VK_PAUSE:19,VK_CAPS_LOCK:20,VK_ESCAPE:27,VK_SPACE:32,VK_PAGE_UP:33,VK_PAGE_DOWN:34,VK_END:35,VK_HOME:36,VK_LEFT:37,VK_UP:38,VK_RIGHT:39,VK_DOWN:40,VK_PRINTSCREEN:44,VK_INSERT:45,VK_DELETE:46,VK_0:48,VK_1:49,VK_2:50,VK_3:51,VK_4:52,VK_5:53,VK_6:54,VK_7:55,VK_8:56,VK_9:57,VK_COLON:58,VK_SEMICOLON:59,VK_LESS_THAN:60,VK_EQUALS:61,VK_GREATER_THAN:62,VK_QUESTION_MARK:63,VK_AT:64,VK_A:65,VK_B:66,VK_C:67, +VK_D:68,VK_E:69,VK_F:70,VK_G:71,VK_H:72,VK_I:73,VK_J:74,VK_K:75,VK_L:76,VK_M:77,VK_N:78,VK_O:79,VK_P:80,VK_Q:81,VK_R:82,VK_S:83,VK_T:84,VK_U:85,VK_V:86,VK_W:87,VK_X:88,VK_Y:89,VK_Z:90,VK_CONTEXT_MENU:93,VK_NUMPAD0:96,VK_NUMPAD1:97,VK_NUMPAD2:98,VK_NUMPAD3:99,VK_NUMPAD4:100,VK_NUMPAD5:101,VK_NUMPAD6:102,VK_NUMPAD7:103,VK_NUMPAD8:104,VK_NUMPAD9:105,VK_MULTIPLY:106,VK_ADD:107,VK_SEPARATOR:108,VK_SUBTRACT:109,VK_DECIMAL:110,VK_DIVIDE:111,VK_F1:112,VK_F2:113,VK_F3:114,VK_F4:115,VK_F5:116,VK_F6:117,VK_F7:118, +VK_F8:119,VK_F9:120,VK_F10:121,VK_F11:122,VK_F12:123,VK_F13:124,VK_F14:125,VK_F15:126,VK_F16:127,VK_F17:128,VK_F18:129,VK_F19:130,VK_F20:131,VK_F21:132,VK_F22:133,VK_F23:134,VK_F24:135,VK_NUM_LOCK:144,VK_SCROLL_LOCK:145,VK_CIRCUMFLEX:160,VK_EXCLAMATION:161,VK_DOUBLE_QUOTE:162,VK_HASH:163,VK_DOLLAR:164,VK_PERCENT:165,VK_AMPERSAND:166,VK_UNDERSCORE:167,VK_OPEN_PAREN:168,VK_CLOSE_PAREN:169,VK_ASTERISK:170,VK_PLUS:171,VK_PIPE:172,VK_HYPHEN_MINUS:173,VK_OPEN_CURLY_BRACKET:174,VK_CLOSE_CURLY_BRACKET:175, +VK_TILDE:176,VK_COMMA:188,VK_PERIOD:190,VK_SLASH:191,VK_BACK_QUOTE:192,VK_OPEN_BRACKET:219,VK_BACK_SLASH:220,VK_CLOSE_BRACKET:221,VK_QUOTE:222,VK_META:224,VK_ALTGR:225,VK_WIN:91,VK_KANA:21,VK_HANGUL:21,VK_EISU:22,VK_JUNJA:23,VK_FINAL:24,VK_HANJA:25,VK_KANJI:25,VK_CONVERT:28,VK_NONCONVERT:29,VK_ACCEPT:30,VK_MODECHANGE:31,VK_SELECT:41,VK_PRINT:42,VK_EXECUTE:43,VK_SLEEP:95};Object.defineProperty(g,"__esModule",{value:!0})}); diff --git a/rpccalls.js b/rpccalls.js new file mode 100644 index 0000000..af721bb --- /dev/null +++ b/rpccalls.js @@ -0,0 +1,57 @@ +var axios = require('axios'); +var request = require('request'); + +/*List of RPC calls +Daemon - +Get blockheight: "get_block_count" +*/ + +function constructCall(method, params) { + var body = { + "jsonrpc": "2.0", + "id": "0", + "method": method, + "params": params + } + return body; +} + +var lastBlock = { + height: 0, + hash: 0, + setHeight: function(newHeight) {this.height = newHeight} +} +var daemonURL = 'http://localhost:34568/json_rpc'; + +function daemonCall(method, params, callback, io) { + // Real blockchain call (now used for all cases) + var body = constructCall(method, params); + request({ + url: daemonURL, + method: 'POST', + headers: {"content-type": "application/json"}, + json: body + }, function (error, res, body) { + if (error) { + console.log("Daemon connection error:", error.message); + callback(null); + return; + } + callback(body); + }); +} + +function getBlockHeight(body) { + if (body == null || body.result == null || body.result.count == null) { + return null; + } + return body.result.count; +} + + +// Export the functions +module.exports = { + daemonCall: daemonCall, + getBlockHeight: getBlockHeight, + lastBlock: lastBlock, +}; diff --git a/user.js b/user.js new file mode 100644 index 0000000..b4e13d9 --- /dev/null +++ b/user.js @@ -0,0 +1,45 @@ +function User(socketid, ip) { + this.id = null; + this.socketid = socketid; + this.ip = ip; + this.nick = null; + this.receiveAddy = ""; + this.payoutAddy = ""; + this.blockRec = null; + this.map = null; + this.player = false; + this.won = false; + this.game = null; // Reference to current game + this.paymentAmount = 0; + this.paymentVerified = false; +} + +User.prototype.startGame = function(mapWidth, mapHeight) { + const Game = require('./game'); + this.game = new Game(this.socketid, mapWidth, mapHeight); + return this.game; +}; + +User.prototype.verifyPayment = function(amount) { + this.paymentAmount = amount; + this.paymentVerified = true; + return true; +}; + +User.prototype.calculateReward = function() { + if (!this.game || this.game.gameState !== 'won') return 0; + + // Base reward is 2x the entrance fee + let reward = this.paymentAmount * 2; + + // Bonus for finding treasure + if (this.game.player.hasTreasure) { + reward = this.paymentAmount * 5; + } + + return reward; +}; + +module.exports = { + User: User +};

F)j14a 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 literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorHB8.ttf b/html/styles/fonts/pixel-operator/PixelOperatorHB8.ttf new file mode 100644 index 0000000000000000000000000000000000000000..5283cb51b364fbcaef3e34acf509f647c295d38c GIT binary patch literal 19076 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 HH<|ty^k|7o literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorHBSC.ttf b/html/styles/fonts/pixel-operator/PixelOperatorHBSC.ttf new file mode 100644 index 0000000000000000000000000000000000000000..b8fa149c00ea526de161dccb02fe21ce5e296176 GIT binary patch literal 17112 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 literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorMono-Bold.ttf b/html/styles/fonts/pixel-operator/PixelOperatorMono-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..215d4a29f146cc23cd1869bd50f30dff2df45ce2 GIT binary patch literal 16744 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 O^7~aQc?|!*1OEq~H{whH literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorMono.ttf b/html/styles/fonts/pixel-operator/PixelOperatorMono.ttf new file mode 100644 index 0000000000000000000000000000000000000000..1c1edccac2370813c6c4dd8c7609ebfa6ca5da2a GIT binary patch literal 16972 zcmcIs3wTvmm0stboA)KjO>zUYv^^n|hfN_sDIw4nfl|aiD1D_AkdPZ5EqNFMrHF_a z6>Fzrb*gokj@HMZ*4jF?YRzbe(e{qxI8G;4thJ4{DpF@YoDUsmKFFQ_UwiL!&%H^s zes)ec_w2Lp-fOSD*1sNmpK}pUL=tj9d|A43<&D?e*){oPk!8)OopRj`bLQQ2sO)wT zZx!x0b#%4&zWbKRKN9gjED}4owS8xAHjAFJY$m=h-MZthE${1U`-Vu#8Ik6Dwsp3r z6Cb_26W@Io=cU_FQM%vzAJB{Ae%iLK{yi<9TKEF)kK#PJqourrQ~OmANcPN^*;BO zswKabisGf{C*L{pKnJfs{PBtvA|pe7P*jK8Qi-t^2l^G&jSR^uKj1AsDV69E*P7qR zQmK}iQm#F9Jk+2A?&E&o9hM@Icy)Xe>W0k~!nw|SkV6%fp%%vhkr}v@v&>`F%0-vT zQxY^xH9Qp6c}=KR4q}7;0LtJ8Jf+zhS3S`tgBsSQy(ZkToJL(H{KnLTpIVRawI6zo z^EcKvwl1VBc5Fk#@Zsp?_YZkA+*v-wUcosinI1}0>-lXyP14S%Yep-qE4+6+jn_Z= z{U2^K9%ZmqAjiUcBX7XY|4+oD0Uul@wFctPpynS3gEl1_^p!%ph4yxbuO1*@4jyDZd zFY&JO)_QH;dT*1L_I7~k+hb2#se(jy?iKjNExnG( zBaiIrxPv#h_n+9j`>yvtlljSuKYRJ5;V;OSe;~g;`Krh-`hNP#ul5|c^PT(OHSq3( z@4H(L9sb}4jvaqNo|hl*6oH4wQE&fd$`aWopOgQEpK0|rdI!Bnyl;8Wd9Qec z*v+v+u_t50ez8B#U*{k82mOpc=rAtfKmiCt(D7~-r$|oiEvM0)pmnX`D@@3`g%J-FjwEXe%?^nbtf{NCPjTHwg1}laWrHR>z zC5g?61BpY4`x3_zrzT9B&@y55g#8olp75~=&rUd1nW#L!vZZou<@(D0$^(^mSKeRw zP~{_)PgXu%`E2Fys+y`=s#a93sajvPt*XE3K-E1}k5&yuQ7A%WGHH-dwx6w!3z3?R#n;uKjB5w`#v%`$FxB z+S7HVb#-;i>aML@SGTY3@w%t#zFT*^?v=Vzb!SqgsruB^)a+DiYGrC|YGdm5)WOup zQje#eO+BCbS?W}MyuQ9ZsBfxosb5y#R=>M`p#H=4rzcLD*gCOy;{6j(Oqw!jC6Eoj z8f!z0@udW4Z%8)id3t2XYZ~eGPLCw~;Oq)NII~Y;@Kxd+4%^O8Hm2sM8oj184u9b6 zigX(EGO;%Av};p~Has)wH2(PmN_7axGUGC~ohuiJ)Xq=MUw|{!n8cZCT%hLy^jt8% z2z42D=V2~hQzqjNWHOob$WR)W4BToOWdw0aXIo-z@vC({6;dS^foF25XA)O(1f=hOvyv7Ow@Tc zBJN)#b7a2qbP;*-ae|-52Am5E&I{+K^4i4O92>Zj$>;$lat8ziW{?O_V)oC~NO7q1 zA}Is6NlD3Ma+GXX(4g{ZNHzGBQ$uQ&%I!2pBOEXQr_OPBC3){Ks`chD%R`hKrtf)8 zz=6REDJx2R=pWw|5l12BjC=%hZJdEq$F*{xF7l5|I@UIlfE+Ry1iHpR4v&_OlOa(@ z*^*{H4cz6CAsz2<9zW-*ej3RW5n_2miO9@h#Gu3?M3qB{0Fe9#5{&qoELEDn{kjb_ndrTWUoQSqWg+m{7NqQOb>77O!fo>XbOB1#7Mg!AdWvQHy8aq0B z1Ru^KtyLP)P=64to>s0_9+WDvD+@6m^++2j0cX&Y&d2a!!9dCK9}a^P`VJz(z$63f zp=nTWmVOmE;#@(k!B`<$Lo6c+(1{I#&Y58p+R&vW>=(uDc}fA?)xv?`pIQ-VdZ=r} zRR>RyCvzAdgt9Rb9gSs5EHXyE?Fw-<-^#$)EHE98VCG8->W$!v%={?~YZW=;@WXi+ z+Y^;5W}j+Me`n`lJrRjo+x7>}?6XYMrXfm+hqMg8wa`?AQ*y{Z&RmU@#OT%4oXH%D z(25dMdkXEqcrE2^mZ$yzbn<*cI7>5EN1qdgpTq~(S&(TyT_P$)ov9xVeIBAt;{xT= zXo-`C1e8%a6;7Cx0p}bJ3Uox8MK~?L^k0fuN`V3Z5JSb}#G$IP{1zxH-xf-&CpWyS zZ-hP2XM(=-GfoO-AR`%-21bW1G|_Ko(%GzurLn>4>F~c&UBb^;8**>;1E`;2YO0Gd zD*3>g!8;9KlAE(yj`Mf4M)F{+&&d!Hq~M?nXc#_*UOCogd<><-KjTHMC9ZaE_i!nKVCyIKeq}6=XMhS9v3m%PK#zP4CM zzBv+e`3n^huPGKX;PM{=F5<8SfayD=Dm#4iv%>h8e@BwFr z$M$Q`I&m1mVxF9>C}^3+T?5iNTs!O-3@Q!SmAfjQxnM+J{Zv+9r$-GxWd(C^7`Q+h zF>iV#$k4@H-ZLW5e$5G)jBzL~3@~zu%*c?9ZK`RS<(NJ`Ckr>uSh7$9f=LoI5jrkU zM&t$G&^&YG%OF~wF5{wiAk(l6lW)<9xml1P_h+%5v;JIn33Of5z+GoJ${}CfB=ldf z)}Zw+_Q*GQHY6bmMqKvMwV>ik*Kmp}cz(21QPKOJ*+<_CxiD*iZ;9wOs)vb?KQZo@ zw(bh62j(I~3Gge~7C*=y0S%!fu%m%>1#_ahC zo$gH?|5*8u(T9x~ibr7Z>`{L}qg_;f+(Cgybh!h$Mte;kI9YlYNRCWntwx>|$7bI} zFyF=!@Ege^AU6}*!%QL#|LQV{!Wfm8N6-d%7UmK3SHzV$6x;gY?vX|e0$`AjSuW7t zLqDkbo12}RnR-pyW*lvi7loL_Duz}MZwQYIOlhPbWW`u)WYf6Y1yl9>E&2 z;2g+egJ<>uVpw8OL^d{BIbk&c&Aa#p?O?8lO;DmvAREG-;I#S<dzUSS^_^@e9D^> zwN80BnV6UnV%8v4Q3{5s5b$hc{+M*wUuiM+`5aI#Zit}H@zeW^XNz=p<>rLTCky0Xa zve2?Q1L#CzJ$MC{7v{x!>|ENF04dm54<t;ol%n=>rF(4^5hVQAAZ;3lq(NE}^CK2?3&R zTo>T9YYteLQ}S7h&0~o+oa8>70r$2I-g9}ZD%ffnQ}G9M3C>C3z%;C`$9Oix%ou#& zK%-uCxvt^s3^=PT^oqPn10MWb}zOEv+XSL)|`-?l`yzs>oCy%ZQKY zN!j91-I}aPb3I5Ha)Vn3RZN(9Khtvvi>nUWq<0v9r_C-Yo^mkmz@Oqt2urkiK`c~% zuhO8c8EF6j6hlPUGvrlLg}uLO>P;RAd!K6TUE4xt@kg--yBsVxq3twF!`1hUQ-6F^ z{h-p}8%~9Et_J;Wm_a6=eo-Cjf1GO{kr`JW(4g}R%o|~4KpR8ika~n(niALKToMkc z2F%u^<`R6wqkhcoW$V*dCp-8W^<~WH8HJq3QQxJZOvOp>!vd2z!dYDn6vrGD$bh(w zyq&C^3}+V9I~f+%I~hjnqq2(DM|GrFF?d&*JNkw7j()U0N+0#WHa{pUjZFDc#}h!x zoW9S<+=##rg-+m}U6GSRJ_hC%$ic~HUO~O%zp&o%pR3QOpR31n@Ce3GuepwSCYg)x z?%8zcjcMubB-YHDqF{}!nl~Tncxh-fU;Y7jbV2x_7z_O+y}8CAjg%Y&OsZZ9|nIS-`rBzA}=ZTP?g!zLIGPp^c%&(7`IQkXLVXFuLC8 zAiq8*>-_qhj*pE)e{{W}pI@J&uk{x1CSS8pcBvQUuH1#eT85d14HL+s)R5sg&7)_t zV!+pSzEKQaKZ;L-(Y2%MjeJJe8~&s9QToyPC`Pqj*S1k#$*fEBJ3jL<*2YOBxRt?3 zOJ!PL7p_TPS6|10xPsyOSI1ZX!MrICD@I0btnV0c~`oujtLdyAT96}JD8`k3+C&j6*k zPRQWczL}wG81C`Hhc8$hGs(7k6Z#dKVp1J^K~C3nT-@h)&Esiiu3r75;VI8X^XB{p z(>|2Dne*yVb9OSiC`Uh!&YRK0?&krQWA5kajtKa7HkjA{V)V!Je8We$&tTpe%iFu8 z|7G65wI!boXcE9^lsm91Hq1N`U->5(k_vcs`ita95m~7}u(_FAFAH@P&Cm1+f_coq z?Ck7OF8DPw1uNtRLKtPIRd@sLJVY9i5!u_683(k81B^SlHg+ZT$8Nl|IOEeTJL{nS#EVa*M8t!+50Fc;4Ds zO94;MtDS{DgLzQidM46768rPo=jE)(r}F%Po7-i%`iSf{P!?PpM%J!a8%A+yGDj!{ z8KS~(jP~&JiUH=mX2nhb`vc57l|CR8uA@Moal!4w>b{QK^9;Li4X-?%uI{Iz`=Al&Yu|(bW$wsI&W+e@I64>SA!qeHg~LY?*$?voIR>rOMGWH`aUi> zr8G?R3e!OPaqf7ycPUk3Y-gl}xC6HaKI}V+Sceab;OQ-O!w6|&=S$c_DVCRxfF3?6r=MPK?PJc`lxCn*U`im9LFmskZ~eD4ZX;5(`4Pb&H;XYm7!J9^#Z z-sxQ^i{%PMgQ5p3CtkJe_Gub0s#{sPtMfRn4WvE#$oHZq#}8XEqX$koO{Vn<9D+wD zZW4XIa~sWNbX7|kI4;~ekNqQut{d!vjw0ZGGtoEhduX&7o)H=>QZ4pRX{e8h?z01J zTpgjO(Is<6@<+Quey=;9oS=2PCY!Wt8%-!_(S$1|4e?-y!XJR=&Fwc$h9BSvh~;(^ zy)#JDwY-_Sp$Qu7Zx4OJhLJOSWK0aebK*&t@`(4&aAn-!yNEgYLi30t?k#uD(VW=V zvh2Ib81AWX%mn}PRqqe55^EE@e$JWZ9r^Fax%DI7kE102@UA2W%G)&M(2SyEY)H}+ zK=ZU8=zI1R=IwDa0&NiQm|#3gmVfk!N(-+)S{LUJkm^x$tNW@L8dU4ON~1B9zwO;) z%bwK6_S$kxN@5S%vM)1ZzqjSM)cS9-khdTqfuFzq93pTpaJUCYvt^Sj?J|XMkb+$Y~E{{KG%ayV|J|b(SQ+D8Nm!0@bOCX!&E_|*=&0Vq^b)C4o z62JRtm#wl(+XeV#;wqH-^!tA4mzBuY_sAl-6f5XJf5j91c1!qeAh)4kzidFOUi9xl zxd*hnP`e#`@cXpZvPB0-9E@M zG)D~eIhe(49k)ZroQDycA+L*trMc3AZ)I)gj?VU-o#|lnUBT-1yLNYW23K~sZ{5|t zGnl!my>EACfB(v!J&P`#6)f3iZny9@xUIc^L(tpT)8EtG)xLd4a9g?u6&*cYmp27F zws&-Pljg4ObZ1}C9xU(cZ13N`yE9nc)790}y)#(X+1C@yT)w<{Rxo#VGf4OM_wH<+ zGpEBg1Rb`U-P5;qj-|G9&R%qygXVKCpB>EXm=(-xZeDcpyym$rn8q5&e-GwQZC(dy zQbW`Vr4`6EstxR8t=Yb(b4PGpZ)ab7e@|a*#K9j@`PlryJt!+uGTx^O)N_yZMrf+49er z&bY&mH^g|e8_lo$85Syk5M2^lBX!n_{j}H5mW2TA?`eH)_?17?rsa=-T`;%*KZ}=tb2isf$c;+th`5Uc`!Gp(<-xOngSqfiYj*K>e_k$|24_u9WvIZGX9o`?S z#}4=;M9p*X%bF=zcb<>^@BpjNsdzd&4ZEGw@jJ1Z@JDaJuf>{R7qj8H=#A##mt&X6 z0(kR<@Jx$8Z-YLJ9|CA>^AOCwm7C*i(@`}9@{4Tl7EB7kAg#6H(;8o(c&(-p%Jmw|68n4!? zlUL;DUdpTYCVG>+$=*5mE%PtrmvUTwik;`5;FqpnlE0HD4gBi)TyF|~OMSlFQ?jdjdvo&}n=6)gZ13yX)wN|u=bnm=T)B8fM|)pScX8TW zt~8fUy;NM4Yge%~QeG7)Z;O;yN6NS7%Ei|js@>+Y)?E6`7&qkFRqV`_i*Gco`pxC0 z&3&D_JBxSerRb)W{Q2Y=5cFAH^ JM*nYx{{!TAB+LK+ literal 0 HcmV?d00001 diff --git a/html/styles/fonts/pixel-operator/PixelOperatorMono8-Bold.ttf b/html/styles/fonts/pixel-operator/PixelOperatorMono8-Bold.ttf new file mode 100644 index 0000000000000000000000000000000000000000..fc5b82b1b012632271a30dacffe0df847c67cb59 GIT binary patch literal 18624 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