├── .gitattributes
├── src
├── FontData
│ ├── small.ase
│ ├── small.png
│ ├── standard.ase
│ ├── standard.png
│ ├── small.config.json
│ ├── FontData.js
│ ├── Font.js
│ ├── standard.config.json
│ ├── small.font.json
│ └── standard.font.json
├── index.js
├── lz-string
│ ├── bower.json
│ ├── bin
│ │ └── bin.js
│ ├── package.json
│ ├── LICENSE
│ ├── README.md
│ ├── libs
│ │ ├── lz-string.min.js
│ │ ├── base64-string.js
│ │ └── lz-string.js
│ └── reference
│ │ └── lz-string-1.0.2.js
├── Screen
│ └── standardPalette.js
├── libIndex.js
├── MapData
│ ├── MapData.js
│ └── TileMap.js
├── ConvertData
│ ├── ConvertData.js
│ └── ConvertData.test.js
├── Builder
│ └── Builder.js
├── Audio
│ ├── Notes.js
│ ├── Frequencies.js
│ ├── Sound.js
│ └── Audio.js
├── Input
│ ├── Keys.js
│ └── Input.js
├── ConvertProject
│ └── ConvertProject.js
├── TileData
│ └── TileData.js
└── Engine
│ └── Engine.js
├── .eslintignore
├── .esdoc.json
├── .editorconfig
├── demo
├── config
│ ├── webpack.demo.prod.js
│ ├── webpack.demo.dev.js
│ └── webpack.demo.common.js
├── dist
│ └── index.html
├── src
│ ├── style.css
│ ├── index.js
│ └── createGameSource.js
└── data
│ ├── tilebug.project.json
│ └── WelcomeTransfer.json
├── README.md
├── utils
├── renameTxtLib.js
└── cleanLib.js
├── config
├── webpack.config.lib.txt.js
├── webpack.config.lib.common.js
├── webpack.config.lib.js
└── webpack.config.lib.min.js
├── .eslintrc.js
├── license.txt
├── .gitignore
├── .npmignore
└── package.json
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.js text eol=lf
2 |
--------------------------------------------------------------------------------
/src/FontData/small.ase:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byersdz/bitmelo/HEAD/src/FontData/small.ase
--------------------------------------------------------------------------------
/src/FontData/small.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byersdz/bitmelo/HEAD/src/FontData/small.png
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | /lib
2 | /node_modules
3 | /config
4 | /demo/config
5 | /demo/dist
6 | /src/lz-string
7 |
--------------------------------------------------------------------------------
/src/FontData/standard.ase:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byersdz/bitmelo/HEAD/src/FontData/standard.ase
--------------------------------------------------------------------------------
/src/FontData/standard.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/byersdz/bitmelo/HEAD/src/FontData/standard.png
--------------------------------------------------------------------------------
/.esdoc.json:
--------------------------------------------------------------------------------
1 |
2 | {
3 | "source": "./src",
4 | "destination": "./docs",
5 | "plugins": [
6 | {"name": "esdoc-standard-plugin"}
7 | ]
8 | }
9 |
--------------------------------------------------------------------------------
/src/FontData/small.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "tileSize": 8,
3 | "originX" : 2,
4 | "originY": 2,
5 | "standardWidth": 3,
6 | "letterSpacing": 1
7 | }
8 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 |
2 | export * from './libIndex';
3 |
4 | export { default as Builder } from './Builder/Builder';
5 | export { default as libText } from '../lib/bitmelo.min.txt';
6 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 2
6 | tab_width = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
--------------------------------------------------------------------------------
/demo/config/webpack.demo.prod.js:
--------------------------------------------------------------------------------
1 |
2 | var merge = require( 'webpack-merge' );
3 | var common = require( './webpack.demo.common.js' );
4 |
5 | module.exports = merge( common, {
6 | mode: 'production',
7 | devtool: 'source-map'
8 | } );
9 |
--------------------------------------------------------------------------------
/demo/dist/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Bitmelo Demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/src/lz-string/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lz-string",
3 | "version": "1.4.4",
4 | "main": "libs/lz-string.min.js",
5 | "ignore": [
6 | "bin/",
7 | "reference/",
8 | "tests/"
9 | ],
10 | "keywords": ["compression", "lzw", "string"]
11 | }
12 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Bitmelo Engine
2 | Bitmelo is a game engine for making small pixel art games.
3 |
4 | [Click here to view the API docs](https://bitmelo.com/api)
5 |
6 | ### License
7 | Copyright 2019 David Byers.
8 |
9 | This software is licensed under the MIT license, located in license.txt
10 |
--------------------------------------------------------------------------------
/demo/config/webpack.demo.dev.js:
--------------------------------------------------------------------------------
1 |
2 | var merge = require( 'webpack-merge' );
3 | var common = require( './webpack.demo.common.js' );
4 |
5 | module.exports = merge( common, {
6 | mode: 'development',
7 | devtool: 'inline-source-map',
8 | devServer: {
9 | contentBase: './demo/dist',
10 | port: 9000,
11 | },
12 | } );
13 |
--------------------------------------------------------------------------------
/utils/renameTxtLib.js:
--------------------------------------------------------------------------------
1 |
2 | // renaming is required because webpack wont minify a txt lib
3 | const fs = require( 'fs' );
4 |
5 | const oldName = 'lib/bitmelo.min.txt.js';
6 | const newName = 'lib/bitmelo.min.txt';
7 |
8 | fs.rename( oldName, newName, ( err ) => {
9 | if ( err ) {
10 | console.log( err );
11 | }
12 | } );
13 |
--------------------------------------------------------------------------------
/src/Screen/standardPalette.js:
--------------------------------------------------------------------------------
1 |
2 | export default [
3 | '000000',
4 | '0b0711',
5 | 'eaf2de',
6 | '766e76',
7 | '561f6e',
8 | '7d4f31',
9 | 'e98c49',
10 | 'fbc0a0',
11 | 'f681b2',
12 | 'd83232',
13 | 'e3e962',
14 | '65cf57',
15 | '2ba957',
16 | '187575',
17 | '1e2cB0',
18 | '2379e5',
19 | '95cae5',
20 | ];
21 |
--------------------------------------------------------------------------------
/src/lz-string/bin/bin.js:
--------------------------------------------------------------------------------
1 | #! /usr/bin/env node
2 | var lzString = require('../libs/lz-string.js');
3 | var fs = require('fs');
4 |
5 | if (process.argv.length < 3) {
6 | console.error('Usage: lz-string ');
7 | process.exit(1);
8 | }
9 |
10 | console.log(lzString.compress(fs.readFileSync(process.argv[2], {
11 | encoding: 'utf8',
12 | })));
13 |
14 |
--------------------------------------------------------------------------------
/demo/src/style.css:
--------------------------------------------------------------------------------
1 | html, body {
2 | height: 100%;
3 | }
4 |
5 | body {
6 | min-height: 100%;
7 | margin: 0;
8 | }
9 |
10 | #main-container {
11 | display: flex;
12 | flex-direction: column;
13 | height: 100%;
14 | }
15 |
16 | #play-iframe {
17 | width: 100%;
18 | height: 100%;
19 | border: none;
20 | border-width: 0;
21 | margin: 0;
22 | padding: 0;
23 | }
24 |
--------------------------------------------------------------------------------
/config/webpack.config.lib.txt.js:
--------------------------------------------------------------------------------
1 | var merge = require( 'webpack-merge' );
2 | var common = require( './webpack.config.lib.common' );
3 | var path = require( 'path' );
4 |
5 | module.exports = merge( common, {
6 | mode: 'production',
7 | output: {
8 | path: path.resolve(__dirname, '../lib'),
9 | filename: `bitmelo.min.txt.js`,
10 | library: 'bitmelo',
11 | libraryTarget: 'umd'
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/config/webpack.config.lib.common.js:
--------------------------------------------------------------------------------
1 | var path = require('path');
2 |
3 | module.exports = {
4 | entry: './src/libIndex.js',
5 | module: {
6 | rules: [
7 | {
8 | test: /\.js$/,
9 | exclude: /node_modules/,
10 | use: ['eslint-loader']
11 | },
12 | {
13 | test: /\.txt$/i,
14 | use: [
15 | 'raw-loader'
16 | ]
17 | }
18 | ]
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/config/webpack.config.lib.js:
--------------------------------------------------------------------------------
1 | var merge = require( 'webpack-merge' );
2 | var common = require( './webpack.config.lib.common' );
3 | var path = require( 'path' );
4 |
5 | module.exports = merge( common, {
6 | mode: 'development',
7 | output: {
8 | path: path.resolve(__dirname, '../lib'),
9 | filename: `bitmelo.${ process.env.npm_package_version }.js`,
10 | library: 'bitmelo',
11 | libraryTarget: 'umd'
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/config/webpack.config.lib.min.js:
--------------------------------------------------------------------------------
1 | var merge = require( 'webpack-merge' );
2 | var common = require( './webpack.config.lib.common' );
3 | var path = require( 'path' );
4 |
5 | module.exports = merge( common, {
6 | mode: 'production',
7 | output: {
8 | path: path.resolve(__dirname, '../lib'),
9 | filename: `bitmelo.${ process.env.npm_package_version }.min.js`,
10 | library: 'bitmelo',
11 | libraryTarget: 'umd'
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/src/FontData/FontData.js:
--------------------------------------------------------------------------------
1 |
2 | import Font from './Font';
3 |
4 | /**
5 | * Holds all of the font data
6 | */
7 | class FontData {
8 | constructor() {
9 | /**
10 | * Array of Font objects
11 | */
12 | this.fonts = [];
13 | }
14 |
15 | /**
16 | * Add a Font to this.fonts from font data
17 | * @param {*} fontData
18 | */
19 | addFont( fontData ) {
20 | this.fonts.push( new Font( fontData ) );
21 | }
22 | }
23 |
24 | export default FontData;
25 |
--------------------------------------------------------------------------------
/utils/cleanLib.js:
--------------------------------------------------------------------------------
1 |
2 | const fs = require( 'fs' );
3 | const path = require( 'path' );
4 |
5 | const libDirectory = 'lib';
6 |
7 | fs.readdir( libDirectory, ( err, files ) => {
8 | if ( err ) {
9 | console.log( err );
10 | return;
11 | }
12 |
13 | files.forEach( ( file ) => {
14 | const filePath = path.join( libDirectory, file );
15 | fs.unlink( filePath, ( unlinkErr ) => {
16 | if ( unlinkErr ) {
17 | console.log( unlinkErr );
18 | }
19 | } );
20 | } );
21 | } );
22 |
--------------------------------------------------------------------------------
/demo/config/webpack.demo.common.js:
--------------------------------------------------------------------------------
1 |
2 | var path = require( 'path' );
3 |
4 | module.exports = {
5 | entry: './demo/src/index.js',
6 | output: {
7 | filename: 'bundle.js',
8 | path: path.resolve(__dirname, '../dist')
9 | },
10 | module: {
11 | rules: [
12 | {
13 | test: /\.css$/,
14 | use: [
15 | 'style-loader',
16 | 'css-loader'
17 | ]
18 | },
19 | {
20 | test: /\.js$/,
21 | exclude: /node_modules/,
22 | use: ['eslint-loader']
23 | },
24 | {
25 | test: /\.txt$/i,
26 | use: [
27 | 'raw-loader'
28 | ]
29 | }
30 | ]
31 | }
32 | };
33 |
--------------------------------------------------------------------------------
/demo/src/index.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable */
2 |
3 | // import { Engine, Notes } from '../../src/index';
4 | // // import testProject from '../data/WelcomeDemo.project.json';
5 | import testProject from '../data/WelcomeTransfer.json';
6 | import createGameSource from './createGameSource';
7 | import './style.css';
8 |
9 | // const testScript = `
10 | // while(true) {
11 | // console.log(engine.shouldBreak());
12 | // }
13 | // `;
14 |
15 | const iframe = document.createElement( 'iframe' );
16 | iframe.id = 'play-iframe';
17 | iframe.srcdoc = createGameSource( testProject );
18 |
19 | const container = document.getElementById( 'main-container' );
20 | container.appendChild( iframe );
21 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 |
2 | module.exports = {
3 | "extends": "airbnb-base",
4 | "env": {
5 | "browser": true,
6 | "node": true,
7 | "jest": true
8 | },
9 | "rules": {
10 | "no-underscore-dangle": "off",
11 | "no-continue": "off",
12 | "class-methods-use-this": "off",
13 | "space-in-parens": ["error", "always"],
14 | "template-curly-spacing": ["error", "never"],
15 | "no-bitwise": "off",
16 | "template-curly-spacing": ["error", "always"],
17 | "arrow-body-style": "off",
18 | "brace-style": ["error", "stroustrup"],
19 | "max-len": ["error", { "code": 120, "ignoreComments": true, "ignoreTrailingComments": true }],
20 | "operator-assignment": "off",
21 | "no-lonely-if": "off",
22 | "no-console": 'off',
23 | "prefer-destructuring": ["error", {
24 | "array": false,
25 | "object": true
26 | }, {
27 | "enforceForRenamedProperties": false
28 | }]
29 | },
30 | "globals": {
31 | "bitmelo": "readonly"
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/libIndex.js:
--------------------------------------------------------------------------------
1 |
2 | export { default as Audio } from './Audio/Audio';
3 | export { default as Frequencies } from './Audio/Frequencies';
4 | export { default as Notes } from './Audio/Notes';
5 | export { default as Sound } from './Audio/Sound';
6 |
7 | export { default as ConvertProject } from './ConvertProject/ConvertProject';
8 |
9 | export { default as ConvertData } from './ConvertData/ConvertData';
10 |
11 | export { default as Font } from './FontData/Font';
12 | export { default as FontData } from './FontData/FontData';
13 |
14 | export { default as Input } from './Input/Input';
15 | export { default as Keys } from './Input/Keys';
16 |
17 | export { default as MapData } from './MapData/MapData';
18 | export { default as TileMap } from './MapData/TileMap';
19 |
20 | export { default as Engine } from './Engine/Engine';
21 |
22 | export { default as Screen } from './Screen/Screen';
23 | export { default as standardPalette } from './Screen/standardPalette';
24 |
25 | export { default as TileData } from './TileData/TileData';
26 |
--------------------------------------------------------------------------------
/license.txt:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 David Byers
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6 |
7 | The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
10 |
11 |
--------------------------------------------------------------------------------
/src/lz-string/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lz-string",
3 | "version": "1.4.4",
4 | "license": "MIT",
5 | "filename": "lz-string.js",
6 | "description": "LZ-based compression algorithm",
7 | "homepage": "http://pieroxy.net/blog/pages/lz-string/index.html",
8 | "keywords": [
9 | "lz",
10 | "compression",
11 | "string"
12 | ],
13 | "main": "libs/lz-string.js",
14 | "typings": "typings/lz-string.d.ts",
15 | "bin": {
16 | "lz-string": "bin/bin.js"
17 | },
18 | "scripts": {},
19 | "dependencies": {},
20 | "devDependencies": {},
21 | "repository": {
22 | "type": "git",
23 | "url": "https://github.com/pieroxy/lz-string.git"
24 | },
25 | "bugs": {
26 | "url": "https://github.com/pieroxy/lz-string/issues"
27 | },
28 | "directories": {
29 | "test": "tests"
30 | },
31 | "author": "pieroxy ",
32 | "autoupdate": {
33 | "source": "git",
34 | "target": "git://github.com/pieroxy/lz-string.git",
35 | "basePath": "libs/",
36 | "files": [
37 | "lz-string.js",
38 | "lz-string.min.js",
39 | "base64-string.js"
40 | ]
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/lz-string/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2013 pieroxy
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 | .env.test
60 |
61 | # parcel-bundler cache (https://parceljs.org/)
62 | .cache
63 |
64 | # next.js build output
65 | .next
66 |
67 | # nuxt.js build output
68 | .nuxt
69 |
70 | # vuepress build output
71 | .vuepress/dist
72 |
73 | # Serverless directories
74 | .serverless/
75 |
76 | # FuseBox cache
77 | .fusebox/
78 |
79 | # DynamoDB Local files
80 | .dynamodb/
81 |
82 | docs/
83 | demo/dist/bundle.js
84 | demo/dist/bundle.js.map
85 | out/
86 |
--------------------------------------------------------------------------------
/src/MapData/MapData.js:
--------------------------------------------------------------------------------
1 | import TileMap from './TileMap';
2 |
3 | /**
4 | * Holds all of the Tile Map data.
5 | */
6 | class MapData {
7 | constructor() {
8 | /**
9 | * Array of TileMap objects
10 | */
11 | this.tileMaps = [];
12 | }
13 |
14 | /**
15 | * Add a tilemap from a data object
16 | * @param {Object} tileMap - The tile map data
17 | */
18 | addTileMap( tileMap ) {
19 | this.tileMaps.push( new TileMap( tileMap ) );
20 | return this.tileMaps.length - 1;
21 | }
22 |
23 | /**
24 | * Get the tile GID at a given position
25 | * @param {number} x - The x position
26 | * @param {number} y - The y position
27 | * @param {number} tileMap - The index of the tile map you are checking
28 | * @param {number} layer - The index of the layer on the tile map you are checking
29 | */
30 | getTile( x, y, tileMap = 0, layer = 0 ) {
31 | if ( tileMap < 0 || tileMap >= this.tileMaps.length ) {
32 | return -1;
33 | }
34 |
35 | return this.tileMaps[tileMap].getTile( x, y, layer );
36 | }
37 |
38 | /**
39 | * Set the tile GID at a given position
40 | * @param {*} gid - The gid
41 | * @param {*} x - The x position
42 | * @param {*} y - The y position
43 | * @param {*} tileMap - The index of the tile map you are setting
44 | * @param {*} layer - The index of the layer on the tile map you are setting
45 | */
46 | setTile( gid, x, y, tileMap = 0, layer = 0 ) {
47 | if ( tileMap < 0 || tileMap >= this.tileMaps.length ) {
48 | return;
49 | }
50 |
51 | this.tileMaps[tileMap].setTile( gid, x, y, layer );
52 | }
53 | }
54 |
55 | export default MapData;
56 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 | .env.test
60 |
61 | # parcel-bundler cache (https://parceljs.org/)
62 | .cache
63 |
64 | # next.js build output
65 | .next
66 |
67 | # nuxt.js build output
68 | .nuxt
69 |
70 | # vuepress build output
71 | .vuepress/dist
72 |
73 | # Serverless directories
74 | .serverless/
75 |
76 | # FuseBox cache
77 | .fusebox/
78 |
79 | # DynamoDB Local files
80 | .dynamodb/
81 |
82 | # bitmelo specific
83 | demo/
84 | docs/
85 | config/
86 |
87 | .editorconfig
88 | .esdoc.json
89 | .eslintignore
90 | .eslintrc.js
91 | .gitattributes
92 | .gitignore
93 |
94 |
--------------------------------------------------------------------------------
/src/ConvertData/ConvertData.js:
--------------------------------------------------------------------------------
1 |
2 | import LZString from '../lz-string/libs/lz-string';
3 |
4 | class ConvertData {
5 | static arrayToRun( array ) {
6 | const result = [];
7 | let currentValue = array[0];
8 | let runNumber = 0;
9 |
10 | for ( let i = 0; i < array.length; i += 1 ) {
11 | if ( array[i] === currentValue ) {
12 | runNumber += 1;
13 | }
14 | else {
15 | result.push( runNumber );
16 | result.push( currentValue );
17 | runNumber = 1;
18 | currentValue = array[i];
19 | }
20 | }
21 | // add the last item
22 | result.push( runNumber );
23 | result.push( currentValue );
24 | return result;
25 | }
26 |
27 | static runToArray( runArray ) {
28 | const result = [];
29 | let runPosition = 0;
30 | while ( runPosition < runArray.length ) {
31 | const runLength = runArray[runPosition];
32 | const item = runArray[runPosition + 1];
33 | for ( let j = 0; j < runLength; j += 1 ) {
34 | result.push( item );
35 | }
36 | runPosition += 2;
37 | }
38 |
39 | return result;
40 | }
41 |
42 | static arrayToCompressedString( array ) {
43 | const arrayString = array.join( ',' );
44 | const compressed = LZString.compressToEncodedURIComponent( arrayString );
45 | return compressed;
46 | }
47 |
48 | static compressedStringToArray( compressedString ) {
49 | const decompressedString = LZString.decompressFromEncodedURIComponent( compressedString );
50 | const stringArray = decompressedString.split( ',' );
51 | const result = [];
52 | for ( let i = 0; i < stringArray.length; i += 1 ) {
53 | result.push( Number.parseInt( stringArray[i], 10 ) );
54 | }
55 | return result;
56 | }
57 | }
58 |
59 | export default ConvertData;
60 |
--------------------------------------------------------------------------------
/demo/src/createGameSource.js:
--------------------------------------------------------------------------------
1 | import cloneDeep from 'lodash/cloneDeep';
2 | import { libText, Builder } from '../../src/index';
3 |
4 | function createGameSource( projectData, testScript = '' ) {
5 | const projectCopy = cloneDeep( projectData );
6 |
7 | if ( projectCopy.tileset && projectCopy.tileset.present ) {
8 | projectCopy.tileset = projectCopy.tileset.present;
9 | }
10 | if ( projectCopy.tilemap && projectCopy.tilemap.present ) {
11 | projectCopy.tilemap = projectCopy.tilemap.present;
12 | }
13 |
14 | const { scripts } = projectCopy.code;
15 | delete projectCopy.code;
16 | let scriptsString = '';
17 |
18 | for ( let i = 0; i < scripts.length; i += 1 ) {
19 | scriptsString += scripts[i].text;
20 | }
21 |
22 | if ( testScript ) {
23 | scriptsString = testScript;
24 | }
25 |
26 | scriptsString = Builder.instrumentScript( scriptsString );
27 |
28 | const style = `
29 |
48 | `;
49 |
50 | const result = `
51 |
52 |
53 | ${ style }
54 |
55 |
56 |
59 |
68 |
69 |
70 | `;
71 |
72 | return result;
73 | }
74 |
75 | export default createGameSource;
76 |
--------------------------------------------------------------------------------
/src/Builder/Builder.js:
--------------------------------------------------------------------------------
1 | // esprima requires a require for some reason
2 | const esprima = require( 'esprima' );
3 |
4 | class Builder {
5 | /**
6 | * Instrument a script string to add calls that can break out of loops.
7 | * The instrumented code will assume that there is a global bitmelo.Engine variable
8 | * named 'engine'.
9 | * @param {string} script
10 | */
11 | static instrumentScript( script ) {
12 | try {
13 | const patches = [];
14 |
15 | esprima.parseScript(
16 | script,
17 | {
18 | range: true,
19 | tolerant: false,
20 | },
21 | ( node ) => {
22 | switch ( node.type ) {
23 | case 'DoWhileStatement':
24 | case 'ForStatement':
25 | case 'ForInStatement':
26 | case 'ForOfStatement':
27 | case 'WhileStatement': {
28 | let start = 1 + node.body.range[0];
29 | const end = node.body.range[1];
30 |
31 | let startCode = 'if (engine.shouldBreak()) { break; }';
32 | let endCode = '';
33 |
34 | if ( node.body.type !== 'BlockStatement' ) {
35 | startCode = `{${ startCode }`;
36 | endCode = '}';
37 | start -= 1;
38 | }
39 |
40 | patches.push( { position: start, code: startCode } );
41 | patches.push( { position: end, code: endCode } );
42 | break;
43 | }
44 | default: break;
45 | }
46 | },
47 | );
48 |
49 | let result = script;
50 |
51 | patches.sort( ( a, b ) => {
52 | return b.position - a.position;
53 | } ).forEach( ( patch ) => {
54 | result = result.slice( 0, patch.position ) + patch.code + result.slice( patch.position );
55 | } );
56 |
57 | return result;
58 | }
59 | catch ( err ) {
60 | console.error( err );
61 | return script;
62 | }
63 | }
64 | }
65 |
66 | export default Builder;
67 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "bitmelo",
3 | "version": "1.7.0",
4 | "description": "A game engine for making small pixel art games.",
5 | "main": "src/index.js",
6 | "scripts": {
7 | "test": "jest",
8 | "clean-builds": "node utils/cleanlib.js",
9 | "build": "webpack --config config/webpack.config.lib.js",
10 | "build-min": "webpack --config config/webpack.config.lib.min.js",
11 | "build-txt": "webpack --config config/webpack.config.lib.txt.js",
12 | "rename-txt": "node utils/renameTxtLib.js",
13 | "build-all": "npm run clean-builds && npm run build-txt && npm run rename-txt && npm run build && npm run build-min",
14 | "build-docs": "jsdoc -r ./src",
15 | "demo-start": "webpack-dev-server --open --config demo/config/webpack.demo.dev.js",
16 | "demo-build": "webpack --config demo/config/webpack.demo.prod.js",
17 | "prepublishOnly": "npm run build-all"
18 | },
19 | "repository": {
20 | "type": "git",
21 | "url": "git+https://github.com/byersdz/bitmelo.git"
22 | },
23 | "keywords": [],
24 | "author": "David Byers",
25 | "license": "MIT",
26 | "bugs": {
27 | "url": "https://github.com/byersdz/bitmelo/issues"
28 | },
29 | "homepage": "https://github.com/byersdz/bitmelo#readme",
30 | "devDependencies": {
31 | "babel-jest": "^24.9.0",
32 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.2",
33 | "css-loader": "^2.1.0",
34 | "eslint": "^5.14.0",
35 | "eslint-config-airbnb-base": "^13.1.0",
36 | "eslint-loader": "^2.1.2",
37 | "eslint-plugin-import": "^2.16.0",
38 | "jest": "^24.1.0",
39 | "style-loader": "^0.23.1",
40 | "wait-on": "^3.3.0",
41 | "webpack": "^4.29.3",
42 | "webpack-cli": "^3.2.3",
43 | "webpack-dev-server": "^3.1.14",
44 | "webpack-merge": "^4.2.1"
45 | },
46 | "babel": {
47 | "plugins": [
48 | "transform-es2015-modules-commonjs"
49 | ]
50 | },
51 | "jest": {
52 | "moduleNameMapper": {
53 | "^SRC(.*)$": "/src$1"
54 | }
55 | },
56 | "dependencies": {
57 | "esprima": "^4.0.1",
58 | "lodash": "^4.17.21",
59 | "raw-loader": "^3.1.0"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/ConvertData/ConvertData.test.js:
--------------------------------------------------------------------------------
1 |
2 | import ConvertData from './ConvertData';
3 |
4 | test( 'array to run min', () => {
5 | expect( ConvertData.arrayToRun( [1, 2, 3] ) ).toEqual( [1, 1, 1, 2, 1, 3] );
6 | } );
7 |
8 | test( 'array to run large', () => {
9 | const source = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 6, 6, 6, 6, 2, 2];
10 | const target = [10, 5, 1, 2, 4, 6, 2, 2];
11 | expect( ConvertData.arrayToRun( source ) ).toEqual( target );
12 | } );
13 |
14 | test( 'array to run mono', () => {
15 | const size = 10000;
16 | const source = new Array( size );
17 | source.fill( 99 );
18 | const target = [size, 99];
19 | expect( ConvertData.arrayToRun( source ) ).toEqual( target );
20 | } );
21 |
22 | test( 'run to array min', () => {
23 | expect( ConvertData.runToArray( [1, 1, 1, 2, 1, 3] ) ).toEqual( [1, 2, 3] );
24 | } );
25 |
26 | test( 'run to array large', () => {
27 | const source = [10, 5, 1, 2, 4, 6, 2, 2];
28 | const target = [5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 2, 6, 6, 6, 6, 2, 2];
29 | expect( ConvertData.runToArray( source ) ).toEqual( target );
30 | } );
31 |
32 | test( 'run to array mono', () => {
33 | const size = 10000;
34 | const source = [size, 99];
35 | const target = new Array( size );
36 | target.fill( 99 );
37 | expect( ConvertData.runToArray( source ) ).toEqual( target );
38 | } );
39 |
40 | test( 'array to compressed min', () => {
41 | const testArray = [4, 5, 6];
42 | const compressed = ConvertData.arrayToCompressedString( testArray );
43 | const decompressed = ConvertData.compressedStringToArray( compressed );
44 |
45 | expect( decompressed ).toEqual( testArray );
46 | } );
47 |
48 | test( 'array to match known compressed string', () => {
49 | const testArray = [255, 0, 1, 5, 6, 7, 99, 128, 22, 37];
50 | const compressed = ConvertData.arrayToCompressedString( testArray );
51 | expect( compressed ).toEqual( 'EwVhBoAZwRnCBs4Ds4CcbbABzmMcAZmSA' );
52 | } );
53 |
54 | test( 'compressed string to match known array', () => {
55 | const compressed = 'EwVhBoAZwRnCBs4Ds4CcbbABzmMcAZmSA';
56 | const decompressed = ConvertData.compressedStringToArray( compressed );
57 |
58 | expect( decompressed ).toEqual( [255, 0, 1, 5, 6, 7, 99, 128, 22, 37] );
59 | } );
60 |
--------------------------------------------------------------------------------
/src/lz-string/README.md:
--------------------------------------------------------------------------------
1 | lz-string
2 | =========
3 | LZ-based compression algorithm for JavaScript
4 |
5 | ## Warning (migrating from version 1.3.4 - nov 2014)
6 | Files have changed locations and name since a recent release. The new release file is in `libs/lz-string.min.js` (or in `libs/lz-string.js` if you don't care for the minified version)
7 |
8 | Sorry about the mess in other repos. This will not happen again.
9 |
10 | ## Note on server side
11 |
12 | If you are using one of the ports of lz-string to decode on the server what was encoded in the browser, you might want to use version 1.3.7 as the version 1.3.8 introduced a slight change in the encoding. While the JS versions are completely cross-compatible, the PHP, Go, ... versions might not be as forgiving.
13 |
14 | ## Install via [npm](https://npmjs.org/)
15 |
16 | ```shell
17 | $ npm install -g lz-string
18 | $ lz-string input.js > output.txt
19 | ```
20 |
21 | ## Home page
22 | Home page for this program with examples, documentation and a live demo: http://pieroxy.net/blog/pages/lz-string/index.html
23 |
24 | ## Other languages
25 | This lib has numerous ports to other languages, for server side processing, mostly. Here they are:
26 |
27 |
28 | * **Java:** [by Diogo Duailibe](https://github.com/diogoduailibe/lzstring4j)
29 | * **Java:** [by rufushuang, with base64 support and better performances](https://github.com/rufushuang/lz-string4java)
30 | * **C#:** [by Jawa-the-Hutt](https://github.com/jawa-the-hutt/lz-string-csharp)
31 | * **C#:** [by kreudom, another implementation in C#, more up to date](https://github.com/kreudom/lz-string-csharp)
32 | * **PHP:** [by nullpunkt](https://github.com/nullpunkt/lz-string-php)
33 | * **Python3:** [by eduardtomasek](https://github.com/eduardtomasek/lz-string-python)
34 | * **Go** [I helped a friend to write a Go implementation of the decompression algorithm](https://github.com/pieroxy/lz-string-go)
35 | * **Go** [Austin wrote the decompression part as well](https://github.com/austinh115/lz-string-go)
36 | * **Elixir** [by Michael Shapiro](https://github.com/koudelka/elixir-lz-string)
37 | * **C++/QT** [by AmiArt](https://github.com/AmiArt/qt-lzstring)
38 | * **VB.NET** [by gsemac](https://github.com/gsemac/lz-string-vb)
39 | * **Salesforce Apex** (Java like language): [bilal did the port](https://github.com/bilalfastian/LZ4String)
40 | * **Kotlin:** [from Zen Liu](https://github.com/ZenLiuCN/lz-string4k)
41 | * **Dart:** [from skipness](https://github.com/ZenLiuCN/lz-string4k)
42 | * **Haxe:** [from markknol](https://github.com/markknol/hx-lzstring)
43 |
--------------------------------------------------------------------------------
/src/Audio/Notes.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Object mapping Node identifiers to numbers. AKA Notes.C4 = 48
4 | */
5 | const Notes = {};
6 |
7 | Notes.C0 = 0;
8 | Notes.Cs0 = 1;
9 | Notes.Db0 = 1;
10 | Notes.D0 = 2;
11 | Notes.Ds0 = 3;
12 | Notes.Eb0 = 3;
13 | Notes.E0 = 4;
14 | Notes.F0 = 5;
15 | Notes.Fs0 = 6;
16 | Notes.Gb0 = 6;
17 | Notes.G0 = 7;
18 | Notes.Gs0 = 8;
19 | Notes.Ab0 = 8;
20 | Notes.A0 = 9;
21 | Notes.As0 = 10;
22 | Notes.Bb0 = 10;
23 | Notes.B0 = 11;
24 |
25 | Notes.C1 = 12;
26 | Notes.Cs1 = 13;
27 | Notes.Db1 = 13;
28 | Notes.D1 = 14;
29 | Notes.Ds1 = 15;
30 | Notes.Eb1 = 15;
31 | Notes.E1 = 16;
32 | Notes.F1 = 17;
33 | Notes.Fs1 = 18;
34 | Notes.Gb1 = 18;
35 | Notes.G1 = 19;
36 | Notes.Gs1 = 20;
37 | Notes.Ab1 = 20;
38 | Notes.A1 = 21;
39 | Notes.As1 = 22;
40 | Notes.Bb1 = 22;
41 | Notes.B1 = 23;
42 |
43 | Notes.C2 = 24;
44 | Notes.Cs2 = 25;
45 | Notes.Db2 = 25;
46 | Notes.D2 = 26;
47 | Notes.Ds2 = 27;
48 | Notes.Eb2 = 27;
49 | Notes.E2 = 28;
50 | Notes.F2 = 29;
51 | Notes.Fs2 = 30;
52 | Notes.Gb2 = 30;
53 | Notes.G2 = 31;
54 | Notes.Gs2 = 32;
55 | Notes.Ab2 = 32;
56 | Notes.A2 = 33;
57 | Notes.As2 = 34;
58 | Notes.Bb2 = 34;
59 | Notes.B2 = 35;
60 |
61 | Notes.C3 = 36;
62 | Notes.Cs3 = 37;
63 | Notes.Db3 = 37;
64 | Notes.D3 = 38;
65 | Notes.Ds3 = 39;
66 | Notes.Eb3 = 39;
67 | Notes.E3 = 40;
68 | Notes.F3 = 41;
69 | Notes.Fs3 = 42;
70 | Notes.Gb3 = 42;
71 | Notes.G3 = 43;
72 | Notes.Gs3 = 44;
73 | Notes.Ab3 = 44;
74 | Notes.A3 = 45;
75 | Notes.As3 = 46;
76 | Notes.Bb3 = 46;
77 | Notes.B3 = 47;
78 |
79 | Notes.C4 = 48;
80 | Notes.Cs4 = 49;
81 | Notes.Db4 = 49;
82 | Notes.D4 = 50;
83 | Notes.Ds4 = 51;
84 | Notes.Eb4 = 51;
85 | Notes.E4 = 52;
86 | Notes.F4 = 53;
87 | Notes.Fs4 = 54;
88 | Notes.Gb4 = 54;
89 | Notes.G4 = 55;
90 | Notes.Gs4 = 56;
91 | Notes.Ab4 = 56;
92 | Notes.A4 = 57;
93 | Notes.As4 = 58;
94 | Notes.Bb4 = 58;
95 | Notes.B4 = 59;
96 |
97 | Notes.C5 = 60;
98 | Notes.Cs5 = 61;
99 | Notes.Db5 = 61;
100 | Notes.D5 = 62;
101 | Notes.Ds5 = 63;
102 | Notes.Eb5 = 63;
103 | Notes.E5 = 64;
104 | Notes.F5 = 65;
105 | Notes.Fs5 = 66;
106 | Notes.Gb5 = 66;
107 | Notes.G5 = 67;
108 | Notes.Gs5 = 68;
109 | Notes.Ab5 = 68;
110 | Notes.A5 = 69;
111 | Notes.As5 = 70;
112 | Notes.Bb5 = 70;
113 | Notes.B5 = 71;
114 |
115 | Notes.C6 = 72;
116 | Notes.Cs6 = 73;
117 | Notes.Db6 = 73;
118 | Notes.D6 = 74;
119 | Notes.Ds6 = 75;
120 | Notes.Eb6 = 75;
121 | Notes.E6 = 76;
122 | Notes.F6 = 77;
123 | Notes.Fs6 = 78;
124 | Notes.Gb6 = 78;
125 | Notes.G6 = 79;
126 | Notes.Gs6 = 80;
127 | Notes.Ab6 = 80;
128 | Notes.A6 = 81;
129 | Notes.As6 = 82;
130 | Notes.Bb6 = 82;
131 | Notes.B6 = 83;
132 |
133 | Notes.C7 = 84;
134 | Notes.Cs7 = 85;
135 | Notes.Db7 = 85;
136 | Notes.D7 = 86;
137 | Notes.Ds7 = 87;
138 | Notes.Eb7 = 87;
139 | Notes.E7 = 88;
140 | Notes.F7 = 89;
141 | Notes.Fs7 = 90;
142 | Notes.Gb7 = 90;
143 | Notes.G7 = 91;
144 | Notes.Gs7 = 92;
145 | Notes.Ab7 = 92;
146 | Notes.A7 = 93;
147 | Notes.As7 = 94;
148 | Notes.Bb7 = 94;
149 | Notes.B7 = 95;
150 |
151 | Notes.C8 = 96;
152 | Notes.Cs8 = 97;
153 | Notes.Db8 = 97;
154 | Notes.D8 = 98;
155 | Notes.Ds8 = 99;
156 | Notes.Eb8 = 99;
157 | Notes.E8 = 100;
158 | Notes.F8 = 101;
159 | Notes.Fs8 = 102;
160 | Notes.Gb8 = 102;
161 | Notes.G8 = 103;
162 | Notes.Gs8 = 104;
163 | Notes.Ab8 = 104;
164 | Notes.A8 = 105;
165 | Notes.As8 = 106;
166 | Notes.Bb8 = 106;
167 | Notes.B8 = 107;
168 |
169 | export default Notes;
170 |
--------------------------------------------------------------------------------
/src/FontData/Font.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Represents a font. Data is stored similarly to tilesets in an array, with the ability to remap characters
4 | * that have a unicode point larger than the array can hold.
5 | */
6 | class Font {
7 | constructor( fontData ) {
8 | /**
9 | * The standard width for a character. Used as the default if none is specified for a character.
10 | */
11 | this.standardWidth = 5;
12 |
13 | /**
14 | * Number of pixels between each character
15 | */
16 | this.letterSpacing = 1;
17 |
18 | /**
19 | * The tile size of the tile sheet where the characters are drawn
20 | */
21 | this.tileSize = 16;
22 |
23 | /**
24 | * The number of columns in the tile sheet
25 | */
26 | this.width = 16;
27 |
28 | /**
29 | * The number of rows in the tile sheet
30 | */
31 | this.height = 16;
32 |
33 | /**
34 | * The x origin in pixels of the character relative to the bottom left.
35 | */
36 | this.originX = 1;
37 |
38 | /**
39 | * The y origin in pixels of the character relative to the bottom left.
40 | */
41 | this.originY = 3;
42 |
43 | /**
44 | * Object mapping unicode points to character information.
45 | * Used for changing a characters size or remapping unicode points larger than what fits on the tile sheet.
46 | */
47 | this.charData = null;
48 |
49 | /**
50 | * Uint8ClampedArray of the tile sheet data.
51 | * Generated by the constructor.
52 | */
53 | this.data = null;
54 |
55 | if ( fontData ) {
56 | this.standardWidth = fontData.standardWidth;
57 | this.letterSpacing = fontData.letterSpacing;
58 |
59 | this.tileSize = fontData.tileSize;
60 | this.width = fontData.width;
61 | this.height = fontData.height;
62 | this.originX = fontData.originX;
63 | this.originY = fontData.originY;
64 | this.charData = fontData.charData;
65 |
66 | this.data = new Uint8ClampedArray( this.width * this.height * this.tileSize * this.tileSize );
67 | const { data } = fontData;
68 | let runPosition = 0;
69 | let dataPosition = 0;
70 | while ( runPosition < data.length ) {
71 | const runLength = data[runPosition];
72 | const paletteId = parseInt( data[runPosition + 1], 10 );
73 | for ( let j = 0; j < runLength; j += 1 ) {
74 | this.data[dataPosition] = paletteId;
75 | dataPosition += 1;
76 | }
77 | runPosition += 2;
78 | }
79 | }
80 | }
81 |
82 | /**
83 | * Get the base index in the data array for the character
84 | * @param {number} charCode - the unicode point for the character
85 | */
86 | baseIndexForChar( charCode ) {
87 | let codePoint = charCode;
88 | if ( charCode >= this.width * this.height ) {
89 | const key = charCode.toString();
90 |
91 | if ( this.charData && this.charData[key] ) {
92 | if ( this.charData[key] !== undefined ) {
93 | codePoint = this.charData[key].remap;
94 | }
95 | }
96 | }
97 | return codePoint * this.tileSize * this.tileSize;
98 | }
99 |
100 | /**
101 | * Get the width of a character
102 | * @param {number} charCode - the unicode point for the character
103 | */
104 | widthForChar( charCode ) {
105 | const charKey = charCode.toString();
106 | if ( this.charData && this.charData[charKey] ) {
107 | if ( this.charData[charKey].width !== undefined ) {
108 | return this.charData[charKey].width;
109 | }
110 | }
111 | return this.standardWidth;
112 | }
113 | }
114 |
115 | export default Font;
116 |
--------------------------------------------------------------------------------
/src/MapData/TileMap.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Represents a Tile Map.
4 | */
5 | class TileMap {
6 | constructor( data ) {
7 | /**
8 | * The name of the Tile Map
9 | */
10 | this.name = '';
11 | /**
12 | * The number of columns in the Tile Map
13 | */
14 | this.width = 0;
15 | /**
16 | * The number of rows in the Tile Map
17 | */
18 | this.height = 0;
19 |
20 | /**
21 | * Array of layer data
22 | */
23 | this.layers = [];
24 |
25 | if ( data ) {
26 | this.name = data.name;
27 | this.width = data.width;
28 | this.height = data.height;
29 |
30 | if ( data.layers ) {
31 | for ( let i = 0; i < data.layers.length; i += 1 ) {
32 | this.layers.push( this._getTypedArrayFromDataLayer( data.layers[i] ) );
33 | }
34 | }
35 | }
36 | }
37 |
38 | /**
39 | * Convert an array of numbers into a Uint16Array
40 | * @param {number[]} dataLayer
41 | */
42 | _getTypedArrayFromDataLayer( dataLayer ) {
43 | const result = new Uint16Array( this.width * this.height );
44 | for ( let i = 0; i < dataLayer.length; i += 1 ) {
45 | result[i] = dataLayer[i];
46 | }
47 | return result;
48 | }
49 |
50 | /**
51 | * Get the tile GID at a given position
52 | * @param {number} x - The x position
53 | * @param {number} y - The y position
54 | * @param {number} layer - The index of the layer on the tile map you are checking
55 | */
56 | getTile( x, y, layer = 0 ) {
57 | if ( layer < 0 || layer >= this.layers.length ) {
58 | return -1;
59 | }
60 |
61 | if ( x < 0 || x >= this.width ) {
62 | return -1;
63 | }
64 |
65 | if ( y < 0 || y >= this.height ) {
66 | return -1;
67 | }
68 |
69 | const currentLayer = this.layers[layer];
70 | const index = y * this.width + x;
71 | return currentLayer[index];
72 | }
73 |
74 | /**
75 | * Set the tile GID at a given position
76 | * @param {*} gid - The gid
77 | * @param {*} x - The x position
78 | * @param {*} y - The y position
79 | * @param {*} layer - The index of the layer on the tile map you are setting
80 | */
81 | setTile( gid, x, y, layer = 0 ) {
82 | if ( layer < 0 || layer >= this.layers.length ) {
83 | return;
84 | }
85 |
86 | if ( x < 0 || x >= this.width ) {
87 | return;
88 | }
89 |
90 | if ( y < 0 || y >= this.height ) {
91 | return;
92 | }
93 |
94 | const currentLayer = this.layers[layer];
95 | const index = y * this.width + x;
96 | currentLayer[index] = gid;
97 | }
98 |
99 | /**
100 | * get an array of the layer data, optionally only getting a subsection of the layer
101 | * @param {number} layer - The layer
102 | * @param {number} startX - The bottom left x position
103 | * @param {number} startY - The bottom left y position
104 | * @param {number} endX - The top right x position
105 | * @param {number} endY - The top right y position
106 | */
107 | getLayerData( layer = 0, startX = 0, startY = 0, endX = 0, endY = 0 ) {
108 | const finishX = endX || this.width;
109 | const finishY = endY || this.height;
110 |
111 | const width = finishX - startX;
112 | const height = finishY - startY;
113 |
114 | const data = new Array( width * height );
115 |
116 | for ( let y = 0; y < height; y += 1 ) {
117 | for ( let x = 0; x < width; x += 1 ) {
118 | const targetX = x + startX;
119 | const targetY = y + startY;
120 |
121 | if ( targetX < 0 || targetY < 0 || targetX >= this.width || targetY >= this.height ) {
122 | data[y * width + x] = 0;
123 | continue;
124 | }
125 |
126 | data[y * width + x] = this.getTile( targetX, targetY, layer );
127 | }
128 | }
129 |
130 | return { data, width, height };
131 | }
132 | }
133 |
134 | export default TileMap;
135 |
--------------------------------------------------------------------------------
/src/FontData/standard.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "tileSize": 16,
3 | "originX" : 2,
4 | "originY": 4,
5 | "standardWidth": 5,
6 | "letterSpacing": 1,
7 | "charData": {
8 | "8364": {
9 | "name": "euro",
10 | "remap": 1,
11 | "width": 6
12 | },
13 | "33": {
14 | "name": "!",
15 | "width": 3
16 | },
17 | "34": {
18 | "name": "double quote",
19 | "width": 4
20 | },
21 | "37": {
22 | "name": "percent",
23 | "width": 7
24 | },
25 | "38": {
26 | "name": "and",
27 | "width": 7
28 | },
29 | "39": {
30 | "name": "single quote",
31 | "width": 1
32 | },
33 | "40": {
34 | "name": "(",
35 | "width": 3
36 | },
37 | "41": {
38 | "name": ")",
39 | "width": 3
40 | },
41 | "44": {
42 | "name": ",",
43 | "width": 2
44 | },
45 | "46": {
46 | "name": ".",
47 | "width": 1
48 | },
49 | "47": {
50 | "name": "f slash",
51 | "width": 7
52 | },
53 | "49": {
54 | "name": "1",
55 | "width": 3
56 | },
57 | "58": {
58 | "name": ":",
59 | "width": 1
60 | },
61 | "59": {
62 | "name": ";",
63 | "width": 2
64 | },
65 | "60": {
66 | "name": "<",
67 | "width": 4
68 | },
69 | "62": {
70 | "name": ">",
71 | "width": 4
72 | },
73 | "64": {
74 | "name": "@",
75 | "width": 7
76 | },
77 | "91": {
78 | "name": "[",
79 | "width": 3
80 | },
81 | "92": {
82 | "name": "backslash",
83 | "width": 7
84 | },
85 | "93": {
86 | "name": "]",
87 | "width": 3
88 | },
89 | "96": {
90 | "name": "grave",
91 | "width": 2
92 | },
93 | "105": {
94 | "name": "i",
95 | "width": 1
96 | },
97 | "107": {
98 | "name": "k",
99 | "width": 4
100 | },
101 | "108": {
102 | "name": "l",
103 | "width": 1
104 | },
105 | "123": {
106 | "name": "{",
107 | "width": 3
108 | },
109 | "124": {
110 | "name": "|",
111 | "width": 1
112 | },
113 | "125": {
114 | "name": "}",
115 | "width": 3
116 | },
117 | "161": {
118 | "name": "upside down !",
119 | "width": 3
120 | },
121 | "164": {
122 | "name": "currency",
123 | "width": 6
124 | },
125 | "165": {
126 | "name": "yen",
127 | "width": 7
128 | },
129 | "166": {
130 | "name": "broken bar",
131 | "width": 1
132 | },
133 | "167": {
134 | "name": "section",
135 | "width": 6
136 | },
137 | "169": {
138 | "name": "copyright",
139 | "width": 7
140 | },
141 | "170": {
142 | "name": "f ordinal",
143 | "width": 4
144 | },
145 | "171": {
146 | "name": "<<",
147 | "width": 6
148 | },
149 | "172": {
150 | "name": "not",
151 | "width": 6
152 | },
153 | "174": {
154 | "name": "(r)",
155 | "width": 8
156 | },
157 | "176": {
158 | "name": "degree",
159 | "width": 4
160 | },
161 | "178": {
162 | "name": "^2",
163 | "width": 3
164 | },
165 | "179": {
166 | "name": "^3",
167 | "width": 3
168 | },
169 | "180": {
170 | "name": "acute",
171 | "width": 2
172 | },
173 | "182": {
174 | "name": "pilcrow",
175 | "width": 3
176 | },
177 | "183": {
178 | "name": "middle dot",
179 | "width": 1
180 | },
181 | "185": {
182 | "name": "^1",
183 | "width": 4
184 | },
185 | "186": {
186 | "name": "m ordinal",
187 | "width": 4
188 | },
189 | "187": {
190 | "name": ">>",
191 | "width": 6
192 | },
193 | "188": {
194 | "name": "1/4",
195 | "width": 7
196 | },
197 | "189": {
198 | "name": "1/2",
199 | "width": 7
200 | },
201 | "190": {
202 | "name": "3/4",
203 | "width": 7
204 | },
205 | "236": {
206 | "name": "i",
207 | "width": 3
208 | },
209 | "237": {
210 | "name": "i",
211 | "width": 3
212 | },
213 | "238": {
214 | "name": "i",
215 | "width": 3
216 | },
217 | "239": {
218 | "name": "i",
219 | "width": 3
220 | }
221 | }
222 | }
223 |
--------------------------------------------------------------------------------
/src/Audio/Frequencies.js:
--------------------------------------------------------------------------------
1 |
2 | import Notes from './Notes';
3 |
4 | /**
5 | * Array of Frequency values for notes.
6 | */
7 | const Frequencies = new Array( 108 );
8 |
9 | Frequencies[Notes.C0] = 16.35160;
10 | Frequencies[Notes.Cs0] = 17.32391;
11 | Frequencies[Notes.D0] = 18.35405;
12 | Frequencies[Notes.Ds0] = 19.44544;
13 | Frequencies[Notes.E0] = 20.60172;
14 | Frequencies[Notes.F0] = 21.82676;
15 | Frequencies[Notes.Fs0] = 23.12465;
16 | Frequencies[Notes.G0] = 24.49971;
17 | Frequencies[Notes.Gs0] = 25.95654;
18 | Frequencies[Notes.A0] = 27.50000;
19 | Frequencies[Notes.As0] = 29.13524;
20 | Frequencies[Notes.B0] = 30.86771;
21 |
22 | Frequencies[Notes.C1] = 32.70320;
23 | Frequencies[Notes.Cs1] = 34.64783;
24 | Frequencies[Notes.D1] = 36.70810;
25 | Frequencies[Notes.Ds1] = 38.89087;
26 | Frequencies[Notes.E1] = 41.20344;
27 | Frequencies[Notes.F1] = 43.65353;
28 | Frequencies[Notes.Fs1] = 46.24930;
29 | Frequencies[Notes.G1] = 48.99943;
30 | Frequencies[Notes.Gs1] = 51.91309;
31 | Frequencies[Notes.A1] = 55.00000;
32 | Frequencies[Notes.As1] = 58.27047;
33 | Frequencies[Notes.B1] = 61.73541;
34 |
35 | Frequencies[Notes.C2] = 65.40639;
36 | Frequencies[Notes.Cs2] = 69.29566;
37 | Frequencies[Notes.D2] = 73.41619;
38 | Frequencies[Notes.Ds2] = 77.78175;
39 | Frequencies[Notes.E2] = 82.40689;
40 | Frequencies[Notes.F2] = 87.30706;
41 | Frequencies[Notes.Fs2] = 92.49861;
42 | Frequencies[Notes.G2] = 97.99886;
43 | Frequencies[Notes.Gs2] = 103.8262;
44 | Frequencies[Notes.A2] = 110.0000;
45 | Frequencies[Notes.As2] = 116.5409;
46 | Frequencies[Notes.B2] = 123.4708;
47 |
48 | Frequencies[Notes.C3] = 130.8128;
49 | Frequencies[Notes.Cs3] = 138.5913;
50 | Frequencies[Notes.D3] = 146.8324;
51 | Frequencies[Notes.Ds3] = 155.5635;
52 | Frequencies[Notes.E3] = 164.8138;
53 | Frequencies[Notes.F3] = 174.6141;
54 | Frequencies[Notes.Fs3] = 184.9972;
55 | Frequencies[Notes.G3] = 195.9977;
56 | Frequencies[Notes.Gs3] = 207.6523;
57 | Frequencies[Notes.A3] = 220.0000;
58 | Frequencies[Notes.As3] = 233.0819;
59 | Frequencies[Notes.B3] = 246.9417;
60 |
61 | Frequencies[Notes.C4] = 261.6256;
62 | Frequencies[Notes.Cs4] = 277.1826;
63 | Frequencies[Notes.D4] = 293.6648;
64 | Frequencies[Notes.Ds4] = 311.1270;
65 | Frequencies[Notes.E4] = 329.6276;
66 | Frequencies[Notes.F4] = 349.2282;
67 | Frequencies[Notes.Fs4] = 369.9944;
68 | Frequencies[Notes.G4] = 391.9954;
69 | Frequencies[Notes.Gs4] = 415.3047;
70 | Frequencies[Notes.A4] = 440.0000;
71 | Frequencies[Notes.As4] = 466.1638;
72 | Frequencies[Notes.B4] = 493.8833;
73 |
74 | Frequencies[Notes.C5] = 523.2511;
75 | Frequencies[Notes.Cs5] = 554.3653;
76 | Frequencies[Notes.D5] = 587.3295;
77 | Frequencies[Notes.Ds5] = 622.2540;
78 | Frequencies[Notes.E5] = 659.2551;
79 | Frequencies[Notes.F5] = 698.4565;
80 | Frequencies[Notes.Fs5] = 739.9888;
81 | Frequencies[Notes.G5] = 783.9909;
82 | Frequencies[Notes.Gs5] = 830.6094;
83 | Frequencies[Notes.A5] = 880.0000;
84 | Frequencies[Notes.As5] = 932.3275;
85 | Frequencies[Notes.B5] = 987.7666;
86 |
87 | Frequencies[Notes.C6] = 1046.502;
88 | Frequencies[Notes.Cs6] = 1108.731;
89 | Frequencies[Notes.D6] = 1174.659;
90 | Frequencies[Notes.Ds6] = 1244.508;
91 | Frequencies[Notes.E6] = 1318.510;
92 | Frequencies[Notes.F6] = 1396.913;
93 | Frequencies[Notes.Fs6] = 1479.978;
94 | Frequencies[Notes.G6] = 1567.982;
95 | Frequencies[Notes.Gs6] = 1661.219;
96 | Frequencies[Notes.A6] = 1760.000;
97 | Frequencies[Notes.As6] = 1864.655;
98 | Frequencies[Notes.B6] = 1975.533;
99 |
100 | Frequencies[Notes.C7] = 2093.005;
101 | Frequencies[Notes.Cs7] = 2217.461;
102 | Frequencies[Notes.D7] = 2349.318;
103 | Frequencies[Notes.Ds7] = 2489.016;
104 | Frequencies[Notes.E7] = 2637.020;
105 | Frequencies[Notes.F7] = 2793.826;
106 | Frequencies[Notes.Fs7] = 2959.955;
107 | Frequencies[Notes.G7] = 3135.963;
108 | Frequencies[Notes.Gs7] = 3322.438;
109 | Frequencies[Notes.A7] = 3520.000;
110 | Frequencies[Notes.As7] = 3729.310;
111 | Frequencies[Notes.B7] = 3951.066;
112 |
113 | Frequencies[Notes.C8] = 4186.009;
114 | Frequencies[Notes.Cs8] = 4434.922;
115 | Frequencies[Notes.D8] = 4698.636;
116 | Frequencies[Notes.Ds8] = 4978.032;
117 | Frequencies[Notes.E8] = 5274.041;
118 | Frequencies[Notes.F8] = 5587.652;
119 | Frequencies[Notes.Fs8] = 5919.911;
120 | Frequencies[Notes.G8] = 6271.927;
121 | Frequencies[Notes.Gs8] = 6644.875;
122 | Frequencies[Notes.A8] = 7040.000;
123 | Frequencies[Notes.As8] = 7458.620;
124 | Frequencies[Notes.B8] = 7902.133;
125 |
126 | export default Frequencies;
127 |
--------------------------------------------------------------------------------
/src/lz-string/libs/lz-string.min.js:
--------------------------------------------------------------------------------
1 | var LZString=function(){function o(o,r){if(!t[o]){t[o]={};for(var n=0;ne;e++){var s=r.charCodeAt(e);n[2*e]=s>>>8,n[2*e+1]=s%256}return n},decompressFromUint8Array:function(o){if(null===o||void 0===o)return i.decompress(o);for(var n=new Array(o.length/2),e=0,t=n.length;t>e;e++)n[e]=256*o[2*e]+o[2*e+1];var s=[];return n.forEach(function(o){s.push(r(o))}),i.decompress(s.join(""))},compressToEncodedURIComponent:function(o){return null==o?"":i._compress(o,6,function(o){return e.charAt(o)})},decompressFromEncodedURIComponent:function(r){return null==r?"":""==r?null:(r=r.replace(/ /g,"+"),i._decompress(r.length,32,function(n){return o(e,r.charAt(n))}))},compress:function(o){return i._compress(o,16,function(o){return r(o)})},_compress:function(o,r,n){if(null==o)return"";var e,t,i,s={},p={},u="",c="",a="",l=2,f=3,h=2,d=[],m=0,v=0;for(i=0;ie;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++),s[c]=f++,a=String(u)}if(""!==a){if(Object.prototype.hasOwnProperty.call(p,a)){if(a.charCodeAt(0)<256){for(e=0;h>e;e++)m<<=1,v==r-1?(v=0,d.push(n(m)),m=0):v++;for(t=a.charCodeAt(0),e=0;8>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}else{for(t=1,e=0;h>e;e++)m=m<<1|t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t=0;for(t=a.charCodeAt(0),e=0;16>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1}l--,0==l&&(l=Math.pow(2,h),h++),delete p[a]}else for(t=s[a],e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;l--,0==l&&(l=Math.pow(2,h),h++)}for(t=2,e=0;h>e;e++)m=m<<1|1&t,v==r-1?(v=0,d.push(n(m)),m=0):v++,t>>=1;for(;;){if(m<<=1,v==r-1){d.push(n(m));break}v++}return d.join("")},decompress:function(o){return null==o?"":""==o?null:i._decompress(o.length,32768,function(r){return o.charCodeAt(r)})},_decompress:function(o,n,e){var t,i,s,p,u,c,a,l,f=[],h=4,d=4,m=3,v="",w=[],A={val:e(0),position:n,index:1};for(i=0;3>i;i+=1)f[i]=i;for(p=0,c=Math.pow(2,2),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(t=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;l=r(p);break;case 2:return""}for(f[3]=l,s=l,w.push(l);;){if(A.index>o)return"";for(p=0,c=Math.pow(2,m),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;switch(l=p){case 0:for(p=0,c=Math.pow(2,8),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 1:for(p=0,c=Math.pow(2,16),a=1;a!=c;)u=A.val&A.position,A.position>>=1,0==A.position&&(A.position=n,A.val=e(A.index++)),p|=(u>0?1:0)*a,a<<=1;f[d++]=r(p),l=d-1,h--;break;case 2:return w.join("")}if(0==h&&(h=Math.pow(2,m),m++),f[l])v=f[l];else{if(l!==d)return null;v=s+s.charAt(0)}w.push(v),f[d++]=s+v.charAt(0),h--,s=v,0==h&&(h=Math.pow(2,m),m++)}}};return i}();"function"==typeof define&&define.amd?define(function(){return LZString}):"undefined"!=typeof module&&null!=module&&(module.exports=LZString);
2 |
--------------------------------------------------------------------------------
/src/Input/Keys.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Object mapping KeyCodes to key numbers.
4 | * Keys.codesToKeyCodes maps key numbers to KeyCodes.
5 | */
6 | const Keys = {};
7 |
8 | Keys.NONE = 0;
9 | Keys.BACKSPACE = 8;
10 | Keys.TAB = 9;
11 | Keys.ENTER = 13;
12 | Keys.SHIFT = 16;
13 | Keys.CTRL = 17;
14 | Keys.ALT = 18;
15 | Keys.PAUSE_BREAK = 19;
16 | Keys.CAPSLOCK = 20;
17 | Keys.ESCAPE = 27;
18 | Keys.SPACE = 32;
19 | Keys.PAGE_UP = 33;
20 | Keys.PAGE_DOWN = 34;
21 | Keys.END = 35;
22 | Keys.HOME = 36;
23 | Keys.LEFT_ARROW = 37;
24 | Keys.UP_ARROW = 38;
25 | Keys.RIGHT_ARROW = 39;
26 | Keys.DOWN_ARROW = 40;
27 | Keys.INSERT = 45;
28 | Keys.DELETE = 46;
29 | Keys.ZERO = 48;
30 | Keys.ONE = 49;
31 | Keys.TWO = 50;
32 | Keys.THREE = 51;
33 | Keys.FOUR = 52;
34 | Keys.FIVE = 53;
35 | Keys.SIX = 54;
36 | Keys.SEVEN = 55;
37 | Keys.EIGHT = 56;
38 | Keys.NINE = 57;
39 | Keys.A_KEY = 65;
40 | Keys.B_KEY = 66;
41 | Keys.C_KEY = 67;
42 | Keys.D_KEY = 68;
43 | Keys.E_KEY = 69;
44 | Keys.F_KEY = 70;
45 | Keys.G_KEY = 71;
46 | Keys.H_KEY = 72;
47 | Keys.I_KEY = 73;
48 | Keys.J_KEY = 74;
49 | Keys.K_KEY = 75;
50 | Keys.L_KEY = 76;
51 | Keys.M_KEY = 77;
52 | Keys.N_KEY = 78;
53 | Keys.O_KEY = 79;
54 | Keys.P_KEY = 80;
55 | Keys.Q_KEY = 81;
56 | Keys.R_KEY = 82;
57 | Keys.S_KEY = 83;
58 | Keys.T_KEY = 84;
59 | Keys.U_KEY = 85;
60 | Keys.V_KEY = 86;
61 | Keys.W_KEY = 87;
62 | Keys.X_KEY = 88;
63 | Keys.Y_KEY = 89;
64 | Keys.Z_KEY = 90;
65 | Keys.LEFT_WINDOW = 91;
66 | Keys.RIGHT_WINDOW = 92;
67 | Keys.SELECT = 93;
68 | Keys.NUM_ZERO = 96;
69 | Keys.NUM_ONE = 97;
70 | Keys.NUM_TWO = 98;
71 | Keys.NUM_THREE = 99;
72 | Keys.NUM_FOUR = 100;
73 | Keys.NUM_FIVE = 101;
74 | Keys.NUM_SIX = 102;
75 | Keys.NUM_SEVEN = 103;
76 | Keys.NUM_EIGHT = 104;
77 | Keys.NUM_NINE = 105;
78 | Keys.MULTIPLY = 106;
79 | Keys.ADD = 107;
80 | Keys.SUBTRACT = 109;
81 | Keys.DECIMAL_POINT = 110;
82 | Keys.DIVIDE = 111;
83 | Keys.F1 = 112;
84 | Keys.F2 = 113;
85 | Keys.F3 = 114;
86 | Keys.F4 = 115;
87 | Keys.F5 = 116;
88 | Keys.F6 = 117;
89 | Keys.F7 = 118;
90 | Keys.F8 = 119;
91 | Keys.F9 = 120;
92 | Keys.F10 = 121;
93 | Keys.F11 = 122;
94 | Keys.F12 = 123;
95 | Keys.NUM_LOCK = 144;
96 | Keys.SCROLL_LOCK = 145;
97 | Keys.SEMI_COLON = 186;
98 | Keys.EQUAL_SIGN = 187;
99 | Keys.COMMA = 188;
100 | Keys.DASH = 189;
101 | Keys.PERIOD = 190;
102 | Keys.FORWARD_SLASH = 191;
103 | Keys.GRAVE_ACCENT = 192;
104 | Keys.OPEN_BRACKET = 219;
105 | Keys.BACK_SLASH = 220;
106 | Keys.CLOSE_BRACKET = 221;
107 | Keys.SINGLE_QUOTE = 222;
108 |
109 | Keys.codesToKeyCodes = {
110 | Backspace: Keys.BACKSPACE,
111 | Tab: Keys.TAB,
112 | Enter: Keys.ENTER,
113 | ShiftLeft: Keys.SHIFT,
114 | ShiftRight: Keys.SHIFT,
115 | ControlLeft: Keys.CTRL,
116 | ControlRight: Keys.CTRL,
117 | AltLeft: Keys.ALT,
118 | AltRight: Keys.ALT,
119 | CapsLock: Keys.CAPSLOCK,
120 | Escape: Keys.ESCAPE,
121 | Space: Keys.SPACE,
122 | PageUp: Keys.PAGE_UP,
123 | PageDown: Keys.PAGE_DOWN,
124 | End: Keys.END,
125 | Home: Keys.HOME,
126 | ArrowLeft: Keys.LEFT_ARROW,
127 | ArrowUp: Keys.UP_ARROW,
128 | ArrowRight: Keys.RIGHT_ARROW,
129 | ArrowDown: Keys.DOWN_ARROW,
130 | Insert: Keys.INSERT,
131 | Delete: Keys.DELETE,
132 | Digit0: Keys.ZERO,
133 | Digit1: Keys.ONE,
134 | Digit2: Keys.TWO,
135 | Digit3: Keys.THREE,
136 | Digit4: Keys.FOUR,
137 | Digit5: Keys.FIVE,
138 | Digit6: Keys.SIX,
139 | Digit7: Keys.SEVEN,
140 | Digit8: Keys.EIGHT,
141 | Digit9: Keys.NINE,
142 | KeyA: Keys.A_KEY,
143 | KeyB: Keys.B_KEY,
144 | KeyC: Keys.C_KEY,
145 | KeyD: Keys.D_KEY,
146 | KeyE: Keys.E_KEY,
147 | KeyF: Keys.F_KEY,
148 | KeyG: Keys.G_KEY,
149 | KeyH: Keys.H_KEY,
150 | KeyI: Keys.I_KEY,
151 | KeyJ: Keys.J_KEY,
152 | KeyK: Keys.K_KEY,
153 | KeyL: Keys.L_KEY,
154 | KeyM: Keys.M_KEY,
155 | KeyN: Keys.N_KEY,
156 | KeyO: Keys.O_KEY,
157 | KeyP: Keys.P_KEY,
158 | KeyQ: Keys.Q_KEY,
159 | KeyR: Keys.R_KEY,
160 | KeyS: Keys.S_KEY,
161 | KeyT: Keys.T_KEY,
162 | KeyU: Keys.U_KEY,
163 | KeyV: Keys.V_KEY,
164 | KeyW: Keys.W_KEY,
165 | KeyX: Keys.X_KEY,
166 | KeyY: Keys.Y_KEY,
167 | KeyZ: Keys.Z_KEY,
168 | Select: Keys.SELECT,
169 | Numpad0: Keys.NUM_ZERO,
170 | Numpad1: Keys.NUM_ONE,
171 | Numpad2: Keys.NUM_TWO,
172 | Numpad3: Keys.NUM_THREE,
173 | Numpad4: Keys.NUM_FOUR,
174 | Numpad5: Keys.NUM_FIVE,
175 | Numpad6: Keys.NUM_SIX,
176 | Numpad7: Keys.NUM_SEVEN,
177 | Numpad8: Keys.NUM_EIGHT,
178 | Numpad9: Keys.NUM_NINE,
179 | NumpadMultiply: Keys.MULTIPLY,
180 | NumpadAdd: Keys.ADD,
181 | NumpadSubtract: Keys.SUBTRACT,
182 | NumpadDecimal: Keys.DECIMAL_POINT,
183 | NumpadDivide: Keys.DIVIDE,
184 | F1: Keys.F1,
185 | F2: Keys.F2,
186 | F3: Keys.F3,
187 | F4: Keys.F4,
188 | F5: Keys.F5,
189 | F6: Keys.F6,
190 | F7: Keys.F7,
191 | F8: Keys.F8,
192 | F9: Keys.F9,
193 | F10: Keys.F10,
194 | F11: Keys.F11,
195 | F12: Keys.F12,
196 | NumLock: Keys.NUM_LOCK,
197 | ScrollLock: Keys.SCROLL_LOCK,
198 | Semicolon: Keys.SEMI_COLON,
199 | Equal: Keys.EQUAL_SIGN,
200 | NumpadEqual: Keys.EQUAL_SIGN,
201 | Comma: Keys.COMMA,
202 | NumpadComma: Keys.COMMA,
203 | Period: Keys.PERIOD,
204 | Slash: Keys.FORWARD_SLASH,
205 | Backquote: Keys.GRAVE_ACCENT,
206 | BracketLeft: Keys.OPEN_BRACKET,
207 | Backslash: Keys.BACK_SLASH,
208 | BracketRight: Keys.CLOSE_BRACKET,
209 | Quote: Keys.SINGLE_QUOTE,
210 | Minus: Keys.DASH,
211 | NumpadEnter: Keys.ENTER,
212 | };
213 |
214 | export default Keys;
215 |
--------------------------------------------------------------------------------
/src/Audio/Sound.js:
--------------------------------------------------------------------------------
1 |
2 | /**
3 | * Represents a sound that can be played.
4 | */
5 | class Sound {
6 | constructor( data ) {
7 | /**
8 | * Array of volume values for the duration of the sound.
9 | * Each value must be 0 to 15.
10 | * Length of the array must always be 32.
11 | */
12 | this.volumeTics = new Int8Array( 32 );
13 |
14 | /**
15 | * Array of pitch values for the duration of the sound.
16 | * Each value must be -10 to 10.
17 | * Length of the array must always be 32.
18 | */
19 | this.pitchTics = new Int8Array( 32 );
20 |
21 | /**
22 | * Array of arp values for the duration of the sound.
23 | * Each value is the number of notes above or below the note of the sound.
24 | * Length of the array must always be 32.
25 | */
26 | this.arpTics = new Int8Array( 32 );
27 |
28 | /**
29 | * Should we loop over the volumeTics when playing a sound?
30 | * If false the last volume tic will be played infinitely once reaching it.
31 | */
32 | this.useVolumeLoop = false;
33 |
34 | /**
35 | * The volumeTics index we will start looping at if useVolumeLoop is true.
36 | */
37 | this.volumeLoopStart = -1;
38 |
39 | /**
40 | * The volumeTics index we will stop looping at if useVolumeLoop is true.
41 | */
42 | this.volumeLoopEnd = -1;
43 |
44 | /**
45 | * Should we loop over the pitchTics when playing a sound?
46 | * If false the last pitch tic will be played infinitely once reaching it.
47 | */
48 | this.usePitchLoop = false;
49 |
50 | /**
51 | * The pitchTics index we will start looping at if usePitchLoop is true.
52 | */
53 | this.pitchLoopStart = -1;
54 |
55 | /**
56 | * The pitchTics index we will stop looping at if usePitchLoop is true.
57 | */
58 | this.pitchLoopEnd = -1;
59 |
60 | /**
61 | * Should we loop over the arpTics when playing a sound?
62 | * If false the last arp tic will be played infinitely once reaching it.
63 | */
64 | this.useArpLoop = false;
65 |
66 | /**
67 | * The arpTics index we will start looping at if useArpLoop is true.
68 | */
69 | this.arpLoopStart = -1;
70 |
71 | /**
72 | * The arpTics index we will stop looping at id useArpLoop is true.
73 | */
74 | this.arpLoopEnd = -1;
75 |
76 | /**
77 | * The Wave index used by this sound.
78 | * 0 is Sine.
79 | * 1 is Triangle.
80 | * 2 is Square.
81 | * 3 is Sawtooth.
82 | */
83 | this.wave = 0;
84 |
85 | /**
86 | * The pitch scale used by the pitchTics. Value is in cents.
87 | */
88 | this.pitchScale = 10;
89 |
90 | /**
91 | * Number of tics to ramp down playing of the sound.
92 | * Must always be at least 1.
93 | */
94 | this.releaseLength = 1;
95 |
96 | /**
97 | * The ramp type used when ramping down after stopping a sound.
98 | * 'linear' uses a linear ramp
99 | * 'expo' uses an exponential ramp
100 | */
101 | this.releaseMode = Sound.RELEASE_LINEAR;
102 |
103 | /**
104 | * Is an infinite sound currently playing on this sound?
105 | */
106 | this.isPlayingInfiniteSound = false;
107 |
108 | /**
109 | * The start time of the current infinite sound.
110 | */
111 | this.infiniteStartTime = 0;
112 |
113 | /**
114 | * The oscillator node of the current infinite sound.
115 | */
116 | this.infiniteOsc = null;
117 |
118 | /**
119 | * The gain node of the current infinite sound.
120 | */
121 | this.infiniteGain = null;
122 |
123 | /**
124 | * The duration of a tic in the current infinite sound.
125 | */
126 | this.infiniteTicDuration = 0;
127 |
128 | /**
129 | * The number of tics played in the current infinite sound.
130 | */
131 | this.infiniteTicsPlayed = 0;
132 |
133 | /**
134 | * The volume of the current infinite sound.
135 | */
136 | this.infiniteVolume = 0;
137 |
138 | /**
139 | * The note of the current infinite sound.
140 | */
141 | this.infiniteNote = 0;
142 |
143 | /**
144 | * The last volume tic played.
145 | */
146 | this.lastVolumeTic = 0;
147 |
148 | /**
149 | * The last pitch tic played.
150 | */
151 | this.lastPitchTic = 0;
152 |
153 | /**
154 | * The last arp tic played.
155 | */
156 | this.lastArpTic = 0;
157 |
158 | if ( data ) {
159 | const {
160 | volumeTics,
161 | pitchTics,
162 | arpTics,
163 | wave,
164 | pitchScale,
165 | releaseLength,
166 | releaseMode,
167 | useVolumeLoop,
168 | volumeLoopStart,
169 | volumeLoopEnd,
170 | usePitchLoop,
171 | pitchLoopStart,
172 | pitchLoopEnd,
173 | useArpLoop,
174 | arpLoopStart,
175 | arpLoopEnd,
176 | } = data;
177 |
178 | if ( volumeTics && Array.isArray( volumeTics ) ) {
179 | for ( let i = 0; i < volumeTics.length; i += 1 ) {
180 | this.volumeTics[i] = volumeTics[i];
181 | }
182 | }
183 |
184 | if ( pitchTics && Array.isArray( pitchTics ) ) {
185 | for ( let i = 0; i < pitchTics.length; i += 1 ) {
186 | this.pitchTics[i] = pitchTics[i];
187 | }
188 | }
189 |
190 | if ( arpTics && Array.isArray( arpTics ) ) {
191 | for ( let i = 0; i < arpTics.length; i += 1 ) {
192 | this.arpTics[i] = arpTics[i];
193 | }
194 | }
195 |
196 | this.wave = wave;
197 | this.pitchScale = pitchScale;
198 | this.releaseLength = releaseLength;
199 | this.releaseMode = releaseMode;
200 | this.useVolumeLoop = useVolumeLoop;
201 | this.volumeLoopStart = volumeLoopStart;
202 | this.volumeLoopEnd = volumeLoopEnd;
203 | this.usePitchLoop = usePitchLoop;
204 | this.pitchLoopStart = pitchLoopStart;
205 | this.pitchLoopEnd = pitchLoopEnd;
206 | this.useArpLoop = useArpLoop;
207 | this.arpLoopStart = arpLoopStart;
208 | this.arpLoopEnd = arpLoopEnd;
209 | }
210 | }
211 | }
212 |
213 | Sound.RELEASE_LINEAR = 'linear';
214 | Sound.RELEASE_EXPO = 'expo';
215 |
216 | export default Sound;
217 |
--------------------------------------------------------------------------------
/src/lz-string/reference/lz-string-1.0.2.js:
--------------------------------------------------------------------------------
1 | // Copyright © 2013 Pieroxy
2 | // This work is free. You can redistribute it and/or modify it
3 | // under the terms of the WTFPL, Version 2
4 | // For more information see LICENSE.txt or http://www.wtfpl.net/
5 | //
6 | // LZ-based compression algorithm, version 1.0.2-rc1
7 | var LZString = {
8 |
9 | writeBit : function(value, data) {
10 | data.val = (data.val << 1) | value;
11 | if (data.position == 15) {
12 | data.position = 0;
13 | data.string += String.fromCharCode(data.val);
14 | data.val = 0;
15 | } else {
16 | data.position++;
17 | }
18 | },
19 |
20 | writeBits : function(numBits, value, data) {
21 | if (typeof(value)=="string")
22 | value = value.charCodeAt(0);
23 | for (var i=0 ; i> 1;
26 | }
27 | },
28 |
29 | produceW : function (context) {
30 | if (Object.prototype.hasOwnProperty.call(context.dictionaryToCreate,context.w)) {
31 | if (context.w.charCodeAt(0)<256) {
32 | this.writeBits(context.numBits, 0, context.data);
33 | this.writeBits(8, context.w, context.data);
34 | } else {
35 | this.writeBits(context.numBits, 1, context.data);
36 | this.writeBits(16, context.w, context.data);
37 | }
38 | this.decrementEnlargeIn(context);
39 | delete context.dictionaryToCreate[context.w];
40 | } else {
41 | this.writeBits(context.numBits, context.dictionary[context.w], context.data);
42 | }
43 | this.decrementEnlargeIn(context);
44 | },
45 |
46 | decrementEnlargeIn : function(context) {
47 | context.enlargeIn--;
48 | if (context.enlargeIn == 0) {
49 | context.enlargeIn = Math.pow(2, context.numBits);
50 | context.numBits++;
51 | }
52 | },
53 |
54 | compress: function (uncompressed) {
55 | var context = {
56 | dictionary: {},
57 | dictionaryToCreate: {},
58 | c:"",
59 | wc:"",
60 | w:"",
61 | enlargeIn: 2, // Compensate for the first entry which should not count
62 | dictSize: 3,
63 | numBits: 2,
64 | result: "",
65 | data: {string:"", val:0, position:0}
66 | }, i;
67 |
68 | for (i = 0; i < uncompressed.length; i += 1) {
69 | context.c = uncompressed.charAt(i);
70 | if (!Object.prototype.hasOwnProperty.call(context.dictionary,context.c)) {
71 | context.dictionary[context.c] = context.dictSize++;
72 | context.dictionaryToCreate[context.c] = true;
73 | }
74 |
75 | context.wc = context.w + context.c;
76 | if (Object.prototype.hasOwnProperty.call(context.dictionary,context.wc)) {
77 | context.w = context.wc;
78 | } else {
79 | this.produceW(context);
80 | // Add wc to the dictionary.
81 | context.dictionary[context.wc] = context.dictSize++;
82 | context.w = String(context.c);
83 | }
84 | }
85 |
86 | // Output the code for w.
87 | if (context.w !== "") {
88 | this.produceW(context);
89 | }
90 |
91 | // Mark the end of the stream
92 | this.writeBits(context.numBits, 2, context.data);
93 |
94 | // Flush the last char
95 | while (context.data.val>0) this.writeBit(0,context.data)
96 | return context.data.string;
97 | },
98 |
99 | readBit : function(data) {
100 | var res = data.val & data.position;
101 | data.position >>= 1;
102 | if (data.position == 0) {
103 | data.position = 32768;
104 | data.val = data.string.charCodeAt(data.index++);
105 | }
106 | //data.val = (data.val << 1);
107 | return res>0 ? 1 : 0;
108 | },
109 |
110 | readBits : function(numBits, data) {
111 | var res = 0;
112 | var maxpower = Math.pow(2,numBits);
113 | var power=1;
114 | while (power!=maxpower) {
115 | res |= this.readBit(data) * power;
116 | power <<= 1;
117 | }
118 | return res;
119 | },
120 |
121 | decompress: function (compressed) {
122 | var dictionary = {},
123 | next,
124 | enlargeIn = 4,
125 | dictSize = 4,
126 | numBits = 3,
127 | entry = "",
128 | result = "",
129 | i,
130 | w,
131 | c,
132 | errorCount=0,
133 | literal,
134 | data = {string:compressed, val:compressed.charCodeAt(0), position:32768, index:1};
135 |
136 | for (i = 0; i < 3; i += 1) {
137 | dictionary[i] = i;
138 | }
139 |
140 | next = this.readBits(2, data);
141 | switch (next) {
142 | case 0:
143 | c = String.fromCharCode(this.readBits(8, data));
144 | break;
145 | case 1:
146 | c = String.fromCharCode(this.readBits(16, data));
147 | break;
148 | case 2:
149 | return "";
150 | }
151 | dictionary[3] = c;
152 | w = result = c;
153 | while (true) {
154 | c = this.readBits(numBits, data);
155 |
156 | switch (c) {
157 | case 0:
158 | if (errorCount++ > 10000) return "Error";
159 | c = String.fromCharCode(this.readBits(8, data));
160 | dictionary[dictSize++] = c;
161 | c = dictSize-1;
162 | enlargeIn--;
163 | break;
164 | case 1:
165 | c = String.fromCharCode(this.readBits(16, data));
166 | dictionary[dictSize++] = c;
167 | c = dictSize-1;
168 | enlargeIn--;
169 | break;
170 | case 2:
171 | return result;
172 | }
173 |
174 | if (enlargeIn == 0) {
175 | enlargeIn = Math.pow(2, numBits);
176 | numBits++;
177 | }
178 |
179 | if (dictionary[c]) {
180 | entry = dictionary[c];
181 | } else {
182 | if (c === dictSize) {
183 | entry = w + w.charAt(0);
184 | } else {
185 | return null;
186 | }
187 | }
188 | result += entry;
189 |
190 | // Add w+entry[0] to the dictionary.
191 | dictionary[dictSize++] = w + entry.charAt(0);
192 | enlargeIn--;
193 |
194 | w = entry;
195 |
196 | if (enlargeIn == 0) {
197 | enlargeIn = Math.pow(2, numBits);
198 | numBits++;
199 | }
200 |
201 | }
202 | return result;
203 | }
204 | };
205 |
--------------------------------------------------------------------------------
/src/ConvertProject/ConvertProject.js:
--------------------------------------------------------------------------------
1 | import get from 'lodash/get';
2 |
3 | import ConvertData from '../ConvertData/ConvertData';
4 |
5 | class ConvertProject {
6 | static convertProjectTilemaps( projectTilemaps ) {
7 | const tilemaps = [];
8 |
9 | for ( let i = 0; i < projectTilemaps.length; i += 1 ) {
10 | const tilemap = {};
11 | tilemap.width = projectTilemaps[i].width;
12 | tilemap.height = projectTilemaps[i].height;
13 | tilemap.name = projectTilemaps[i].name;
14 | tilemap.layers = [];
15 |
16 | for ( let j = 0; j < projectTilemaps[i].layers.length; j += 1 ) {
17 | const currentLayer = projectTilemaps[i].layers[j];
18 | const format = currentLayer.format ? currentLayer.format : 'array';
19 |
20 | if ( format === 'rc' ) {
21 | // run and compressed string
22 | const runData = ConvertData.compressedStringToArray( currentLayer.data );
23 | tilemap.layers.push( ConvertData.runToArray( runData ) );
24 | }
25 | else if ( format === 'c' ) {
26 | // compressed string
27 | tilemap.layers.push( ConvertData.compressedStringToArray( currentLayer.data ) );
28 | }
29 | else if ( format === 'run' ) {
30 | // run length encoding
31 | tilemap.layers.push( ConvertData.runToArray( currentLayer.data ) );
32 | }
33 | else {
34 | // array
35 | tilemap.layers.push( ...[currentLayer.data] );
36 | }
37 | }
38 |
39 | tilemaps.push( tilemap );
40 | }
41 |
42 | return tilemaps;
43 | }
44 |
45 | static convertProjectTilesets( projectTilesets, tileSize ) {
46 | const tilesets = [];
47 |
48 | for ( let i = 0; i < projectTilesets.length; i += 1 ) {
49 | const currentProjectTileset = projectTilesets[i];
50 | const tileset = {};
51 | const layerData = [];
52 |
53 | for ( let j = 0; j < currentProjectTileset.layers.length; j += 1 ) {
54 | const currentLayer = currentProjectTileset.layers[j];
55 | if ( currentLayer.isVisible ) {
56 | let dataArray = null;
57 |
58 | const format = currentLayer.format ? currentLayer.format : 'array';
59 |
60 | if ( format === 'rc' ) {
61 | // run and compressed string
62 | const runArray = ConvertData.compressedStringToArray( currentLayer.data );
63 | dataArray = ConvertProject.convertToTilesetArray(
64 | ConvertData.runToArray( runArray ),
65 | currentProjectTileset.width * tileSize,
66 | currentProjectTileset.height * tileSize,
67 | tileSize,
68 | );
69 | }
70 | else if ( format === 'c' ) {
71 | // compressed string
72 | dataArray = ConvertProject.convertToTilesetArray(
73 | ConvertData.compressedStringToArray( currentLayer.data ),
74 | currentProjectTileset.width * tileSize,
75 | currentProjectTileset.height * tileSize,
76 | tileSize,
77 | );
78 | }
79 | else if ( format === 'run' ) {
80 | // run length encoding
81 | dataArray = ConvertProject.convertToTilesetArray(
82 | ConvertData.runToArray( currentLayer.data ),
83 | currentProjectTileset.width * tileSize,
84 | currentProjectTileset.height * tileSize,
85 | tileSize,
86 | );
87 | }
88 | else {
89 | // array
90 | dataArray = ConvertProject.convertToTilesetArray(
91 | currentLayer.data,
92 | currentProjectTileset.width * tileSize,
93 | currentProjectTileset.height * tileSize,
94 | tileSize,
95 | );
96 | }
97 |
98 | layerData.push( dataArray );
99 | }
100 | }
101 |
102 | // flatten the layer data into 1 layer, ignoring transparent pixels
103 | if ( layerData.length > 0 ) {
104 | tileset.data = new Array( layerData[0].length );
105 | tileset.data.fill( 0 );
106 | for ( let position = 0; position < layerData[0].length; position += 1 ) {
107 | for ( let layer = 0; layer < layerData.length; layer += 1 ) {
108 | const currentValue = layerData[layer][position];
109 | if ( currentValue ) {
110 | tileset.data[position] = currentValue;
111 | break;
112 | }
113 | }
114 | }
115 | }
116 | else {
117 | tileset.data = new Array( currentProjectTileset.width * currentProjectTileset.height * tileSize * tileSize );
118 | tileset.data.fill( 0 );
119 | }
120 |
121 | // add the flags
122 | let flags = get( currentProjectTileset, 'flags' );
123 | if ( !flags || flags.length !== currentProjectTileset.width * currentProjectTileset.height ) {
124 | flags = new Array( currentProjectTileset.width * currentProjectTileset.height );
125 | flags.fill( 0 );
126 | }
127 |
128 | tileset.width = currentProjectTileset.width;
129 | tileset.height = currentProjectTileset.height;
130 | tileset.format = 'array';
131 | tileset.name = 'test';
132 | tileset.tileSize = tileSize;
133 | tileset.flags = flags;
134 |
135 | tilesets.push( tileset );
136 | }
137 | return tilesets;
138 | }
139 |
140 | static convertToTilesetArray( sourceArray, width, height, tileSize ) {
141 | const imageData = new Array( width * height );
142 | const tileColumns = width / tileSize;
143 |
144 | for ( let i = 0; i < sourceArray.length; i += 1 ) {
145 | const x = i % width;
146 | const y = Math.floor( i / width );
147 | const tileX = Math.floor( x / tileSize );
148 | const tileY = Math.floor( y / tileSize );
149 |
150 | const iPerTile = tileSize * tileSize;
151 | const startIndex = tileY * iPerTile * tileColumns + ( tileX * iPerTile ); // the starting index of the current tile
152 |
153 | // relative x and y from the tile origin
154 | const relativeX = x - ( tileX * tileSize );
155 | const relativeY = y - ( tileY * tileSize );
156 |
157 | const destinationIndex = startIndex + ( relativeY * tileSize ) + relativeX;
158 | imageData[destinationIndex] = sourceArray[i];
159 | }
160 |
161 | return imageData;
162 | }
163 | }
164 |
165 | export default ConvertProject;
166 |
--------------------------------------------------------------------------------
/demo/data/tilebug.project.json:
--------------------------------------------------------------------------------
1 | {"layout":{"activeNavigationTab":"project","navigationPanelIsOpen":true,"referencePanelIsOpen":true,"activeSoundTicTab":"volume","tileSelectorIsOpen":true,"tileEditor":{"showGrid":false},"tilemapEditor":{"tilemapSelectorIsOpen":true,"tileSelectorIsOpen":true,"cursorX":-11,"cursorY":18,"showGrid":true},"soundEditor":{"pianoOctave":4,"lastVolumeTic":-1,"lastPitchTic":-1,"lastArpTic":-1},"referenceTabTitle":"Motivation","play":{"stickConsoleToBottom":true},"referenceRoutes":{"about":{"current":["REFERENCE_ABOUT"],"cached":{"REFERENCE_ABOUT":["REFERENCE_ABOUT"]}},"project":{"current":["MOTIVATION"],"cached":{"MOTIVATION":["MOTIVATION"]}},"play":{"current":["CONSOLE"],"cached":{"CONSOLE":["CONSOLE"]}},"code":{"current":["API","API_SCREEN_SNIPPETS"],"cached":{"API":["API","API_SCREEN_SNIPPETS"]}},"tile":{"current":["ARTICLES"],"cached":{"ARTICLES":["ARTICLES"]}},"tilemap":{"current":["ARTICLES"],"cached":{"ARTICLES":["ARTICLES"]}},"sound":{"current":["HOTKEYS"],"cached":{"HOTKEYS":["HOTKEYS"]}}},"colorPickerIsOpen":false},"sound":{"sounds":[{"volumeTics":[15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15],"pitchTics":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"arpTics":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],"pitchScale":100,"wave":0,"useVolumeLoop":false,"volumeLoopStart":0,"volumeLoopEnd":31,"usePitchLoop":false,"pitchLoopStart":0,"pitchLoopEnd":31,"useArpLoop":false,"arpLoopStart":0,"arpLoopEnd":31,"name":"","releaseLength":1,"releaseMode":"linear","needToAddToAudioEngine":false}],"activeSound":0,"audioEvents":[],"piano":{"speed":0,"volume":0.75}},"palette":{"colors":["000000","0b0711","eaf2de","766e76","561f6e","7d4f31","e98c49","fbc0a0","f681b2","d83232","e3e962","65cf57","2ba957","187575","1e2cB0","2379e5","95cae5"],"selectedIndex":6,"altIndex":0},"pixelTools":{"selectedTool":"PENCIL_TOOL","selectedTileTool":"TILE_DRAW_TOOL","pixelToolSettings":{"pencilSize":1,"eraserSize":1}},"tileset":{"tilesets":[{"width":2,"height":3,"selectedTile":5,"selectionWidth":1,"selectionHeight":1,"mapSelectedTile":0,"mapSelectionWidth":2,"mapSelectionHeight":3,"activeLayer":0,"layers":[{"isVisible":true,"data":[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,6,0,0,0,0,0,0,6,6,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,6,0,0,0,0,0,0,6,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,6,6,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,6,6,6,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,6,6,6,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}]}],"activeIndex":0,"editorSelection":{"width":0,"height":0,"offsetX":0,"offsetY":0,"data":[],"isActive":false}},"tilemap":{"activeIndex":0,"tilemaps":[{"name":"untitled","width":24,"height":16,"activeLayer":0,"layers":[{"isVisible":true,"data":[1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,1,2,1,2,1,2,1,2,1,2,1,2,0,0,0,0,0,0,0,0,0,0,0,0,3,4,3,4,3,4,3,4,3,4,3,4,0,0,0,0,0,0,0,0,0,0,0,0,5,6,5,6,5,6,5,6,5,6,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]}]}]},"project":{"tileSize":16,"name":"tilebug","screen":{"width":192,"height":128,"scaleMode":1,"scale":3,"minScale":1,"maxScale":4,"horizontalScaleCushion":10,"verticalScaleCushion":10,"rescaleOnWindowResize":true},"misc":{"hideCursor":false,"clickToBegin":false,"startTransitionFrames":60,"useNegativeMotivation":false},"editorVersion":"1.2.0"},"code":{"scripts":[{"text":"\nengine.onInit = () => {\n\n};\n\nengine.onUpdate = () => {\n\tengine.screen.drawMap(\n\t 0, // originX on map\n\t 0, // originY on map\n\t -1, // width\n\t -1, // height\n\t 0, // screenX\n\t 0, // screenY\n\t 0 // tilemap index\n\t);\n};\n\n","cursorRow":14,"cursorColumn":3,"scrollTop":0}],"activeIndex":0,"playLogs":[]},"clipboard":{"pixels":{"width":0,"height":0,"offsetX":0,"offsetY":0,"data":[],"isActive":false}}}
--------------------------------------------------------------------------------
/src/TileData/TileData.js:
--------------------------------------------------------------------------------
1 |
2 | import isInteger from 'lodash/isInteger';
3 |
4 | const flagValues = [];
5 | let f = 1;
6 | for ( let i = 0; i < 16; i += 1 ) {
7 | flagValues.push( f );
8 | f = f * 2;
9 | }
10 |
11 | /**
12 | * Holds all of the tile data.
13 | */
14 | class TileData {
15 | constructor() {
16 | /**
17 | * The size of each tile in pixels.
18 | * Used for both width and height.
19 | */
20 | this.tileSize = 16;
21 | /**
22 | * Array of tileset data.
23 | * All tiledata is added to this.data when init is called.
24 | * More tilesets can not be added after this.
25 | */
26 | this.tilesets = [];
27 | /**
28 | * All of the tile data in a single Uint8ClampedArray.
29 | * This is whats used by Screen to draw tiles.
30 | */
31 | this.data = null;
32 | /**
33 | * All of the flag data in a single Uint16Array.
34 | * Each item is a flag value for each tile.
35 | */
36 | this.flagData = null;
37 | }
38 |
39 | /**
40 | * Parse all of the tilesets and add them to the data array
41 | */
42 | init() {
43 | let numberOfTiles = 0;
44 | for ( let i = 0; i < this.tilesets.length; i += 1 ) {
45 | const currentTileset = this.tilesets[i];
46 | numberOfTiles += currentTileset.width * currentTileset.height;
47 | }
48 | this.data = new Uint8ClampedArray( numberOfTiles * this.tileSize * this.tileSize );
49 | this.flagData = new Uint16Array( numberOfTiles + 1 );
50 | this.flagData.fill( 0 );
51 |
52 | let startPosition = 0;
53 | let firstGid = 1;
54 | for ( let i = 0; i < this.tilesets.length; i += 1 ) {
55 | const currentTileset = this.tilesets[i];
56 | currentTileset.firstGid = firstGid;
57 | const { data } = currentTileset;
58 | if ( currentTileset.format === 'array' ) {
59 | for ( let j = 0; j < data.length; j += 1 ) {
60 | this.data[startPosition + j] = parseInt( data[j], 10 );
61 | }
62 | }
63 | else if ( currentTileset.format === 'run' ) {
64 | let runPosition = 0;
65 | let dataPosition = 0;
66 | while ( runPosition < data.length ) {
67 | const runLength = data[runPosition];
68 | const paletteId = parseInt( data[runPosition + 1], 10 );
69 | for ( let j = 0; j < runLength; j += 1 ) {
70 | this.data[startPosition + dataPosition] = paletteId;
71 | dataPosition += 1;
72 | }
73 | runPosition += 2;
74 | }
75 | }
76 |
77 | const { flags } = currentTileset;
78 | for ( let j = 0; j < flags.length; j += 1 ) {
79 | this.flagData[firstGid + j] = parseInt( flags[j], 10 );
80 | }
81 |
82 | firstGid += currentTileset.width * currentTileset.height;
83 | startPosition += currentTileset.width * currentTileset.height * this.tileSize * this.tileSize;
84 |
85 | // data is no longer needed in the current tileset as it has been added to this.data.
86 | delete currentTileset.data;
87 |
88 | // flags are no longer needed
89 | delete currentTileset.flags;
90 | }
91 | }
92 |
93 | /**
94 | * Add a tileset.
95 | * All tilesets must be added before init is called.
96 | * @param {Object} tileset - the tileset data
97 | */
98 | addTileset( tileset ) {
99 | this.tilesets.push( tileset );
100 | }
101 |
102 | /**
103 | * Get the GID for a tile
104 | * @param {number} x - x position of the tile
105 | * @param {number} y - y position of the tile
106 | * @param {number} tileset - the index of the tileset
107 | */
108 | getGid( x, y, tileset = 0 ) {
109 | if ( x < 0 || y < 0 ) {
110 | return -1;
111 | }
112 | const currentTileset = this.tilesets[tileset];
113 | const { width, height, firstGid } = currentTileset;
114 | if ( x >= width || y >= height ) {
115 | return -1;
116 | }
117 | return y * width + x + firstGid;
118 | }
119 |
120 | /**
121 | * Get the tileset info for a given gid
122 | * @param {number} gid - the gid of the tile
123 | */
124 | getTilesetInfoForGid( gid ) {
125 | if ( !this.tilesets || this.tilesets.length === 0 || !gid ) {
126 | return null;
127 | }
128 |
129 | let tilesetIndex = 0;
130 | for ( let i = 0; i < this.tilesets.length; i += 1 ) {
131 | const tileset = this.tilesets[i];
132 | if ( tileset.firstGid <= gid ) {
133 | tilesetIndex = i;
134 | }
135 | else {
136 | break;
137 | }
138 | }
139 |
140 | return {
141 | firstGid: this.tilesets[tilesetIndex].firstGid,
142 | width: this.tilesets[tilesetIndex].width,
143 | height: this.tilesets[tilesetIndex].height,
144 | index: tilesetIndex,
145 | };
146 | }
147 |
148 | /**
149 | * Get the array data for a tile section
150 | * @param {number} gid - the gid of the bottom left tile
151 | * @param {number} tileWidth - the width in tiles of the tile section
152 | * @param {number} tileHeight - the height in tiles of the tile section
153 | */
154 | getTileSectionData( gid, tileWidth = 1, tileHeight = 1 ) {
155 | const tilesetInfo = this.getTilesetInfoForGid( gid );
156 |
157 | if ( !tilesetInfo ) {
158 | return null;
159 | }
160 |
161 | const { tileSize } = this;
162 |
163 | const localGid = gid - tilesetInfo.firstGid;
164 | const localY = Math.floor( localGid / tilesetInfo.width );
165 | const localX = localGid - localY * tilesetInfo.width;
166 |
167 | const data = new Uint8ClampedArray( tileWidth * tileHeight * tileSize * tileSize );
168 | const width = tileWidth * tileSize;
169 | const height = tileHeight * tileSize;
170 |
171 | for ( let tileY = 0; tileY < tileHeight; tileY += 1 ) {
172 | for ( let tileX = 0; tileX < tileWidth; tileX += 1 ) {
173 | if ( tileX + localX >= tilesetInfo.width || tileY + localY >= tilesetInfo.height ) {
174 | // tile is outside of tileset
175 | break;
176 | }
177 |
178 | const tileGid = localGid + tileY * tilesetInfo.width + tileX + tilesetInfo.firstGid;
179 | const basePosition = ( tileGid - 1 ) * tileSize * tileSize;
180 | for ( let y = 0; y < tileSize; y += 1 ) {
181 | for ( let x = 0; x < tileSize; x += 1 ) {
182 | const paletteId = this.data[basePosition + y * tileSize + x];
183 | const targetX = tileX * tileSize + x;
184 | const targetY = tileY * tileSize + y;
185 | data[targetY * width + targetX] = paletteId;
186 | }
187 | }
188 | }
189 | }
190 |
191 | return { data, width, height };
192 | }
193 |
194 | /**
195 | * Get flag for a gid. If the flagNumber is not specified or negative, returns the bit field for a gid
196 | * @param {number} gid - the gid of the tile
197 | * @param {number} flagNumber - the flag number, 0 - 15. If negative the number of the bit field will be returned
198 | */
199 | getFlag( gid, flagNumber = -1 ) {
200 | if ( gid < 0 || gid >= this.flagData.length ) {
201 | return 0;
202 | }
203 |
204 | const gidFlags = this.flagData[gid];
205 |
206 | if ( flagNumber < 0 || flagNumber >= 16 ) {
207 | return gidFlags;
208 | }
209 |
210 | if ( flagValues[flagNumber] & gidFlags ) {
211 | return true;
212 | }
213 |
214 | return false;
215 | }
216 |
217 | /**
218 | * Set flag for a gid. If the flagNumber is negative, set the bit field for a gid
219 | * @param {number} gid - the gid of the tile
220 | * @param {number} flagNumber - the flag number, 0 - 15. Set negative to set the entire bit field for the flags
221 | * @param {number | boolean} value - true or false if setting a flag, number if setting the bit field
222 | */
223 | setFlag( gid, flagNumber, value ) {
224 | if ( gid < 0 || gid >= this.flagData.length ) {
225 | return;
226 | }
227 |
228 | if ( flagNumber < 0 ) {
229 | // set the entire bitfield
230 | if ( isInteger( value ) && value >= 0 && value <= 65535 ) {
231 | this.flagData[gid] = value;
232 | }
233 | }
234 | else if ( isInteger( flagNumber ) && flagNumber >= 0 && flagNumber < 16 ) {
235 | const flagValue = flagValues[flagNumber];
236 | if ( value ) {
237 | // add the flag
238 | this.flagData[gid] = this.flagData[gid] | flagValue;
239 | }
240 | else {
241 | // remove the flag
242 | this.flagData[gid] = this.flagData[gid] & ~flagValue;
243 | }
244 | }
245 | }
246 | }
247 |
248 | export default TileData;
249 |
--------------------------------------------------------------------------------
/src/FontData/small.font.json:
--------------------------------------------------------------------------------
1 | {"name":"small","tileSize":8,"width":16,"height":8,"originX":2,"originY":2,"standardWidth":3,"letterSpacing":1,"data":[2122,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,36,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,2,2,2,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,14,0,3,2,3,0,3,2,1,1,1,2,3,0,1,2,1,1,3,2,3,0,2,2,1,1,2,2,3,0,3,2,1,1,1,2,3,0,1,2,1,1,3,2,3,0,3,2,13,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,2,1,2,2,3,0,2,2,1,1,1,2,5,0,3,2,37,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,13,0,3,2,4,0,2,2,1,1,1,2,4,0,1,2,1,1,2,2,4,0,1,2,1,1,1,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,3,2,13,0,3,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,1,2,4,0,1,2,1,1,2,2,4,0,3,2,28,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,20,0,3,2,4,0,2,2,1,1,2,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,20,0,3,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,3,2,52,0,5,2,3,0,1,2,3,1,1,2,3,0,5,2,28,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,52,0,3,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,3,2,19,0,4,2,4,0,1,2,2,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,2,1,1,2,4,0,4,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,1,2,1,1,1,2,4,0,2,2,1,1,1,2,4,0,1,2,2,1,1,2,4,0,4,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,13,0,3,2,5,0,1,2,1,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,12,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,20,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,20,0,3,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,22,0,3,2,4,0,2,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,2,2,4,0,2,2,1,1,2,2,4,0,2,2,1,1,1,2,5,0,3,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,5,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,3,2,5,0,1,2,1,1,2,2,4,0,2,2,1,1,2,2,4,0,2,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,2,2,4,0,3,2,14,0,3,2,5,0,1,2,1,1,1,2,5,0,4,2,4,0,1,2,2,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,12,0,4,2,3,0,2,2,2,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,12,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,4,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,1,2,5,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,4,2,4,0,1,2,2,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,4,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,1,2,1,1,1,2,4,0,2,2,1,1,2,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,3,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,13,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,12,0,4,2,3,0,2,2,2,1,1,2,3,0,1,2,2,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,4,2,4,0,1,2,2,1,2,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,2,2,2,1,1,2,4,0,4,2,12,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,2,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,12,0,3,2,4,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,12,0,3,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,2,2,1,1,2,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,11,0,4,2,4,0,1,2,2,1,1,2,4,0,1,2,1,1,2,2,4,0,1,2,1,1,1,2,5,0,1,2,1,1,2,2,4,0,1,2,2,1,1,2,4,0,4,2,22,0,3,2,4,0,2,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,2,2,4,0,3,2,22,0,4,2,4,0,1,2,2,1,1,2,4,0,2,2,1,1,1,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,1,2,4,0,1,2,2,1,1,2,4,0,4,2,35,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,5,2,68,0,3,2,4,0,2,2,1,1,1,2,4,0,1,2,1,1,2,2,4,0,3,2,14,0,4,2,3,0,2,2,2,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,2,1,1,2,4,0,4,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,3,2,13,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,5,0,3,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,2,2,4,0,1,2,2,1,1,2,4,0,1,2,1,1,3,2,3,0,2,2,2,1,1,2,4,0,4,2,11,0,5,2,3,0,1,2,3,1,1,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,3,2,3,0,3,2,14,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,3,2,1,1,1,2,5,0,3,2,5,0,1,2,1,1,1,2,5,0,3,2,11,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,3,2,3,0,1,2,1,1,1,2,5,0,3,2,14,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,12,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,3,2,5,0,1,2,1,1,3,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,21,0,3,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,19,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,3,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,2,1,2,2,3,0,4,2,20,0,4,2,4,0,1,2,2,1,2,2,3,0,3,2,1,1,1,2,3,0,1,2,1,1,3,2,3,0,2,2,2,1,1,2,4,0,4,2,20,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,2,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,12,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,20,0,3,2,4,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,1,2,3,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,20,0,3,2,5,0,1,2,1,1,1,2,4,0,2,2,1,1,2,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,5,2,19,0,5,2,3,0,1,2,3,1,1,2,3,0,2,2,1,1,2,2,3,0,3,2,1,1,1,2,3,0,1,2,3,1,1,2,3,0,5,2,20,0,4,2,4,0,1,2,2,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,2,1,1,2,4,0,2,2,1,1,2,2,4,0,1,2,2,1,1,2,4,0,4,2,12,0,3,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,1,2,1,1,1,2,5,0,3,2,12,0,4,2,4,0,1,2,2,1,1,2,4,0,2,2,1,1,2,2,4,0,1,2,2,1,1,2,3,0,2,2,1,1,2,2,3,0,1,2,2,1,1,2,4,0,4,2,28,0,5,2,3,0,1,2,1,1,1,2,1,1,1,2,3,0,2,2,1,1,2,2,4,0,3,2,75,0]}
--------------------------------------------------------------------------------
/src/lz-string/libs/base64-string.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013 Pieroxy
2 | // This work is free. You can redistribute it and/or modify it
3 | // under the terms of the WTFPL, Version 2
4 | // For more information see LICENSE.txt or http://www.wtfpl.net/
5 | //
6 | // This lib is part of the lz-string project.
7 | // For more information, the home page:
8 | // http://pieroxy.net/blog/pages/lz-string/index.html
9 | //
10 | // Base64 compression / decompression for already compressed content (gif, png, jpg, mp3, ...)
11 | // version 1.4.1
12 | var Base64String = {
13 |
14 | compressToUTF16 : function (input) {
15 | var output = [],
16 | i,c,
17 | current,
18 | status = 0;
19 |
20 | input = this.compress(input);
21 |
22 | for (i=0 ; i> 1)+32));
27 | current = (c & 1) << 14;
28 | break;
29 | case 1:
30 | output.push(String.fromCharCode((current + (c >> 2))+32));
31 | current = (c & 3) << 13;
32 | break;
33 | case 2:
34 | output.push(String.fromCharCode((current + (c >> 3))+32));
35 | current = (c & 7) << 12;
36 | break;
37 | case 3:
38 | output.push(String.fromCharCode((current + (c >> 4))+32));
39 | current = (c & 15) << 11;
40 | break;
41 | case 4:
42 | output.push(String.fromCharCode((current + (c >> 5))+32));
43 | current = (c & 31) << 10;
44 | break;
45 | case 5:
46 | output.push(String.fromCharCode((current + (c >> 6))+32));
47 | current = (c & 63) << 9;
48 | break;
49 | case 6:
50 | output.push(String.fromCharCode((current + (c >> 7))+32));
51 | current = (c & 127) << 8;
52 | break;
53 | case 7:
54 | output.push(String.fromCharCode((current + (c >> 8))+32));
55 | current = (c & 255) << 7;
56 | break;
57 | case 8:
58 | output.push(String.fromCharCode((current + (c >> 9))+32));
59 | current = (c & 511) << 6;
60 | break;
61 | case 9:
62 | output.push(String.fromCharCode((current + (c >> 10))+32));
63 | current = (c & 1023) << 5;
64 | break;
65 | case 10:
66 | output.push(String.fromCharCode((current + (c >> 11))+32));
67 | current = (c & 2047) << 4;
68 | break;
69 | case 11:
70 | output.push(String.fromCharCode((current + (c >> 12))+32));
71 | current = (c & 4095) << 3;
72 | break;
73 | case 12:
74 | output.push(String.fromCharCode((current + (c >> 13))+32));
75 | current = (c & 8191) << 2;
76 | break;
77 | case 13:
78 | output.push(String.fromCharCode((current + (c >> 14))+32));
79 | current = (c & 16383) << 1;
80 | break;
81 | case 14:
82 | output.push(String.fromCharCode((current + (c >> 15))+32, (c & 32767)+32));
83 | status = 0;
84 | break;
85 | }
86 | }
87 | output.push(String.fromCharCode(current + 32));
88 | return output.join('');
89 | },
90 |
91 |
92 | decompressFromUTF16 : function (input) {
93 | var output = [],
94 | current,c,
95 | status=0,
96 | i = 0;
97 |
98 | while (i < input.length) {
99 | c = input.charCodeAt(i) - 32;
100 |
101 | switch (status++) {
102 | case 0:
103 | current = c << 1;
104 | break;
105 | case 1:
106 | output.push(String.fromCharCode(current | (c >> 14)));
107 | current = (c&16383) << 2;
108 | break;
109 | case 2:
110 | output.push(String.fromCharCode(current | (c >> 13)));
111 | current = (c&8191) << 3;
112 | break;
113 | case 3:
114 | output.push(String.fromCharCode(current | (c >> 12)));
115 | current = (c&4095) << 4;
116 | break;
117 | case 4:
118 | output.push(String.fromCharCode(current | (c >> 11)));
119 | current = (c&2047) << 5;
120 | break;
121 | case 5:
122 | output.push(String.fromCharCode(current | (c >> 10)));
123 | current = (c&1023) << 6;
124 | break;
125 | case 6:
126 | output.push(String.fromCharCode(current | (c >> 9)));
127 | current = (c&511) << 7;
128 | break;
129 | case 7:
130 | output.push(String.fromCharCode(current | (c >> 8)));
131 | current = (c&255) << 8;
132 | break;
133 | case 8:
134 | output.push(String.fromCharCode(current | (c >> 7)));
135 | current = (c&127) << 9;
136 | break;
137 | case 9:
138 | output.push(String.fromCharCode(current | (c >> 6)));
139 | current = (c&63) << 10;
140 | break;
141 | case 10:
142 | output.push(String.fromCharCode(current | (c >> 5)));
143 | current = (c&31) << 11;
144 | break;
145 | case 11:
146 | output.push(String.fromCharCode(current | (c >> 4)));
147 | current = (c&15) << 12;
148 | break;
149 | case 12:
150 | output.push(String.fromCharCode(current | (c >> 3)));
151 | current = (c&7) << 13;
152 | break;
153 | case 13:
154 | output.push(String.fromCharCode(current | (c >> 2)));
155 | current = (c&3) << 14;
156 | break;
157 | case 14:
158 | output.push(String.fromCharCode(current | (c >> 1)));
159 | current = (c&1) << 15;
160 | break;
161 | case 15:
162 | output.push(String.fromCharCode(current | c));
163 | status=0;
164 | break;
165 | }
166 |
167 |
168 | i++;
169 | }
170 |
171 | return this.decompress(output.join(''));
172 | //return output;
173 |
174 | },
175 |
176 |
177 | // private property
178 | _keyStr : "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",
179 |
180 | decompress : function (input) {
181 | var output = [];
182 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
183 | var i = 1;
184 | var odd = input.charCodeAt(0) >> 8;
185 |
186 | while (i < input.length*2 && (i < input.length*2-1 || odd==0)) {
187 |
188 | if (i%2==0) {
189 | chr1 = input.charCodeAt(i/2) >> 8;
190 | chr2 = input.charCodeAt(i/2) & 255;
191 | if (i/2+1 < input.length)
192 | chr3 = input.charCodeAt(i/2+1) >> 8;
193 | else
194 | chr3 = NaN;
195 | } else {
196 | chr1 = input.charCodeAt((i-1)/2) & 255;
197 | if ((i+1)/2 < input.length) {
198 | chr2 = input.charCodeAt((i+1)/2) >> 8;
199 | chr3 = input.charCodeAt((i+1)/2) & 255;
200 | } else
201 | chr2=chr3=NaN;
202 | }
203 | i+=3;
204 |
205 | enc1 = chr1 >> 2;
206 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
207 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
208 | enc4 = chr3 & 63;
209 |
210 | if (isNaN(chr2) || (i==input.length*2+1 && odd)) {
211 | enc3 = enc4 = 64;
212 | } else if (isNaN(chr3) || (i==input.length*2 && odd)) {
213 | enc4 = 64;
214 | }
215 |
216 | output.push(this._keyStr.charAt(enc1));
217 | output.push(this._keyStr.charAt(enc2));
218 | output.push(this._keyStr.charAt(enc3));
219 | output.push(this._keyStr.charAt(enc4));
220 | }
221 |
222 | return output.join('');
223 | },
224 |
225 | compress : function (input) {
226 | var output = [],
227 | ol = 1,
228 | output_,
229 | chr1, chr2, chr3,
230 | enc1, enc2, enc3, enc4,
231 | i = 0, flush=false;
232 |
233 | input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
234 |
235 | while (i < input.length) {
236 |
237 | enc1 = this._keyStr.indexOf(input.charAt(i++));
238 | enc2 = this._keyStr.indexOf(input.charAt(i++));
239 | enc3 = this._keyStr.indexOf(input.charAt(i++));
240 | enc4 = this._keyStr.indexOf(input.charAt(i++));
241 |
242 | chr1 = (enc1 << 2) | (enc2 >> 4);
243 | chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
244 | chr3 = ((enc3 & 3) << 6) | enc4;
245 |
246 | if (ol%2==0) {
247 | output_ = chr1 << 8;
248 | flush = true;
249 |
250 | if (enc3 != 64) {
251 | output.push(String.fromCharCode(output_ | chr2));
252 | flush = false;
253 | }
254 | if (enc4 != 64) {
255 | output_ = chr3 << 8;
256 | flush = true;
257 | }
258 | } else {
259 | output.push(String.fromCharCode(output_ | chr1));
260 | flush = false;
261 |
262 | if (enc3 != 64) {
263 | output_ = chr2 << 8;
264 | flush = true;
265 | }
266 | if (enc4 != 64) {
267 | output.push(String.fromCharCode(output_ | chr3));
268 | flush = false;
269 | }
270 | }
271 | ol+=3;
272 | }
273 |
274 | if (flush) {
275 | output.push(String.fromCharCode(output_));
276 | output = output.join('');
277 | output = String.fromCharCode(output.charCodeAt(0)|256) + output.substring(1);
278 | } else {
279 | output = output.join('');
280 | }
281 |
282 | return output;
283 |
284 | }
285 | }
286 |
--------------------------------------------------------------------------------
/src/Engine/Engine.js:
--------------------------------------------------------------------------------
1 | /* eslint-disable prefer-destructuring */
2 | import Screen from '../Screen/Screen';
3 | import Input from '../Input/Input';
4 | import TileData from '../TileData/TileData';
5 | import MapData from '../MapData/MapData';
6 | import FontData from '../FontData/FontData';
7 | import Audio from '../Audio/Audio';
8 | import ConvertProject from '../ConvertProject/ConvertProject';
9 |
10 | import standardFont from '../FontData/standard.font.json';
11 | import smallFont from '../FontData/small.font.json';
12 |
13 | class Engine {
14 | constructor() {
15 | /**
16 | * The id of the div that the engine will be contained by
17 | */
18 | this.containerId = 'bitmelo-container';
19 |
20 | /**
21 | * Function to be called to add assets and configuration during initialization
22 | */
23 | this.onConfigure = null;
24 |
25 | /**
26 | * Function to be called when the engine is initialized
27 | */
28 | this.onInit = null;
29 |
30 | /**
31 | * Function to draw the initial screen when the engine loads.
32 | * Only seen when clickToBegin is true
33 | */
34 | this.onDrawStartScreen = null;
35 |
36 | /**
37 | * Function to draw the transition frames after start click.
38 | * Only seen when clickToBegin is true
39 | */
40 | this.onUpdateStartTransition = null;
41 |
42 | /**
43 | * Number of frames to show after begin click before the game starts.
44 | * Only relevant when clickToBegin is true.
45 | */
46 | this.startTransitionFrames = 60;
47 |
48 | /**
49 | * Function to be called every update of the engine.
50 | * Perform game logic and rendering here.
51 | */
52 | this.onUpdate = null;
53 |
54 | /**
55 | * Should we require the user to click the screen before the game starts?
56 | * This stops a game from automatically starring in a web page which can be annoying.
57 | */
58 | this.clickToBegin = true;
59 |
60 | /**
61 | * Instance of the Screen class used by the Engine. Automatically created by the engine.
62 | */
63 | this.screen = new Screen();
64 |
65 | /**
66 | * Instance of the Input class used by the Engine. Automatically created by the engine.
67 | */
68 | this.input = new Input();
69 |
70 | /**
71 | * Instance of the TileData class used by the Engine. Automatically created by the engine
72 | */
73 | this.tileData = new TileData();
74 |
75 | /**
76 | * Instance of the MapData class used by the Engine. Automatically created by the engine
77 | */
78 | this.mapData = new MapData();
79 |
80 | /**
81 | * Instance of the FontData class used by the Engine. Automatically created by the engine.
82 | * The Standard font is automatically added at index 0.
83 | * The Small font is automatically added at index 1.
84 | */
85 | this.fontData = new FontData();
86 |
87 | /**
88 | * Instance of the Audio class used by the Engine. Automatically created by the engine.
89 | */
90 | this.audio = new Audio();
91 |
92 | /**
93 | * The number of seconds since init was called
94 | */
95 | this.realTimeSinceInit = 0;
96 |
97 | /**
98 | * The number of seconds since the game was started
99 | */
100 | this.realTimeSinceGameStart = 0;
101 |
102 | /**
103 | * This mode runs the engine without drawing to a canvas or playing audio.
104 | * This is useful to use the engine to generate image data.
105 | */
106 | this.dataOnlyMode = false;
107 |
108 | this.fontData.addFont( standardFont );
109 | this.fontData.addFont( smallFont );
110 |
111 | this._hasBegun = false;
112 | this._update = this._update.bind( this );
113 | this._initTime = 0;
114 | this._gameStartTime = 0;
115 | this._frameStartTime = new Date().getTime();
116 | this._paused = false;
117 |
118 | /**
119 | * Whether we have detected a condition that should stop the games execution.
120 | * Likely from an infinite loop.
121 | */
122 | this._didCrash = false;
123 |
124 | /**
125 | * How many milliseconds an update frame can run until the game crashes.
126 | * This is to stop an infinite loop from locking up the browser forever.
127 | */
128 | this._msToFrameCrash = 5000;
129 | }
130 |
131 | /**
132 | * Add project data from the Bitmelo Editor to the engine
133 | */
134 | addProjectData( projectData ) {
135 | let format = 'project';
136 | if ( projectData.format ) {
137 | format = projectData.format;
138 | }
139 |
140 | let project = null;
141 | let sounds = null;
142 | let tilesets = null;
143 | let tilemaps = null;
144 | let palette = null;
145 |
146 | if ( format === 'transfer' ) {
147 | project = projectData.project;
148 | sounds = projectData.sounds;
149 | tilesets = projectData.tilesets;
150 | tilemaps = projectData.tilemaps;
151 | palette = projectData.palette;
152 | }
153 | else {
154 | project = projectData.project;
155 | sounds = projectData.sound.sounds;
156 | tilesets = projectData.tileset.tilesets;
157 | tilemaps = projectData.tilemap.tilemaps;
158 | palette = projectData.palette;
159 | }
160 |
161 | // engine settings
162 | this.clickToBegin = project.misc.clickToBegin;
163 | this.startTransitionFrames = project.misc.startTransitionFrames;
164 |
165 | // screen settings
166 | this.screen.width = project.screen.width;
167 | this.screen.height = project.screen.height;
168 | this.screen.scaleMode = project.screen.scaleMode;
169 | this.screen.scale = project.screen.scale;
170 | this.screen.minScale = project.screen.minScale;
171 | this.screen.maxScale = project.screen.maxScale;
172 | this.screen.horizontalScaleCushion = project.screen.horizontalScaleCushion;
173 | this.screen.verticalScaleCushion = project.screen.verticalScaleCushion;
174 | this.screen.rescaleOnWindowResize = project.screen.rescaleOnWindowResize;
175 | this.screen.hideCursor = project.misc.hideCursor;
176 | this.screen.setPalette( palette.colors );
177 |
178 | // tilesets
179 | this.tileData.tileSize = project.tileSize;
180 | const convertedTilesets = ConvertProject.convertProjectTilesets( tilesets, project.tileSize );
181 | for ( let i = 0; i < convertedTilesets.length; i += 1 ) {
182 | this.tileData.addTileset( convertedTilesets[i] );
183 | }
184 |
185 | // tilemaps
186 | const convertedTilemaps = ConvertProject.convertProjectTilemaps( tilemaps );
187 | for ( let i = 0; i < convertedTilemaps.length; i += 1 ) {
188 | this.mapData.addTileMap( convertedTilemaps[i] );
189 | }
190 |
191 | // sounds
192 | for ( let i = 0; i < sounds.length; i += 1 ) {
193 | this.audio.addSound( sounds[i] );
194 | }
195 | }
196 |
197 | /**
198 | * Begin running the engine. This will perform initial setup, call the onInit function, and begin the game loop
199 | */
200 | begin() {
201 | const date = new Date();
202 | this._initTime = date.getTime();
203 | if ( this.onConfigure ) {
204 | this.onConfigure();
205 | }
206 |
207 | this.screen.dataOnlyMode = this.dataOnlyMode;
208 | this.screen.conainerId = this.containerId;
209 | this.screen.init();
210 | this.screen.onScaleChange = ( scale ) => {
211 | this.input.canvasScale = scale;
212 | };
213 |
214 | this.input.dataOnlyMode = this.dataOnlyMode;
215 | this.input.canvas = this.screen.canvas;
216 | this.input.canvasScale = this.screen.scale;
217 | this.input.screenWidth = this.screen.width;
218 | this.input.screenHeight = this.screen.height;
219 | this.input.init();
220 | this.tileData.init();
221 | this.screen.tileData = this.tileData;
222 | this.screen.mapData = this.mapData;
223 | this.screen.fontData = this.fontData;
224 | this.audio.dataOnlyMode = this.dataOnlyMode;
225 | this.audio.init();
226 |
227 | if ( this.onInit ) {
228 | this.onInit();
229 | }
230 |
231 | if ( this._didCrash ) {
232 | this.screen.clear( 1 );
233 | this.screen.drawText( 'Game Crashed', 10, 10, 2, 1, 0 );
234 | this.screen._setCanvasStyle();
235 | this.screen.drawScreen();
236 | return;
237 | }
238 |
239 | if ( this.clickToBegin && !this.dataOnlyMode ) {
240 | if ( this.onDrawStartScreen ) {
241 | this.onDrawStartScreen();
242 | }
243 | else {
244 | this.screen.clear( 1 );
245 | this.screen.drawText( 'Click to begin...', 10, 10, 2, 1, 0 );
246 | }
247 | const screenHidesCursor = this.screen.hideCursor;
248 | this.screen.hideCursor = false;
249 | this.screen._setCanvasStyle();
250 | this.screen.drawScreen();
251 | this.screen.canvas.addEventListener( 'click', () => {
252 | if ( !this._hasBegun ) {
253 | this._hasBegun = true;
254 | this.screen.hideCursor = screenHidesCursor;
255 | this.screen._setCanvasStyle();
256 | this.input.clearInput();
257 | requestAnimationFrame( this._update );
258 | }
259 | } );
260 | }
261 | else {
262 | this._gameStartTime = date.getTime();
263 | this._hasBegun = true;
264 | requestAnimationFrame( this._update );
265 | }
266 | this._didCrash = false;
267 | }
268 |
269 | pause() {
270 | this._paused = true;
271 | }
272 |
273 | unpause() {
274 | this._paused = false;
275 | requestAnimationFrame( this._update );
276 | }
277 |
278 | isPaused() {
279 | return this._paused;
280 | }
281 |
282 | /**
283 | * Game loop
284 | */
285 | _update() {
286 | if ( this._paused ) {
287 | return;
288 | }
289 |
290 | this.advanceFrame();
291 |
292 | if ( this._didCrash ) {
293 | this.screen.clear( 1 );
294 | this.screen.drawText( 'Game Crashed', 10, 10, 2, 1, 0 );
295 | this.screen.drawScreen();
296 | }
297 | else {
298 | requestAnimationFrame( this._update );
299 | }
300 | }
301 |
302 | advanceFrame() {
303 | if ( this._didCrash ) {
304 | return;
305 | }
306 |
307 | const date = new Date();
308 | this._frameStartTime = date.getTime();
309 | const msSinceInit = date.getTime() - this._initTime;
310 | this.realTimeSinceInit = msSinceInit / 1000;
311 |
312 | this.input.pollInput();
313 |
314 | // the first game frame after transition
315 | if ( this.clickToBegin && this.startTransitionFrames === 0 ) {
316 | this._gameStartTime = date.getTime();
317 | this.startTransitionFrames -= 1;
318 | }
319 |
320 | if ( this.clickToBegin && this.startTransitionFrames > 0 ) {
321 | this.startTransitionFrames -= 1;
322 |
323 | if ( this.onUpdateStartTransition ) {
324 | this.clearInput();
325 | this.onUpdateStartTransition();
326 | }
327 | else {
328 | this.screen.clear( 1 );
329 | }
330 | }
331 | else if ( this.onUpdate ) {
332 | this.realTimeSinceGameStart = ( date.getTime() - this._gameStartTime ) / 1000;
333 | this.onUpdate();
334 | this.audio.update();
335 | }
336 |
337 | this.screen.drawScreen();
338 | }
339 |
340 | /**
341 | * Should we break out of a loop?
342 | * This is used by instrumented code in case a frame is taking long enough that
343 | * the game should crash instead of locking up the browser.
344 | */
345 | shouldBreak() {
346 | if ( this._didCrash ) {
347 | return true;
348 | }
349 |
350 | const currentTime = new Date().getTime();
351 | const msSinceFrameStart = currentTime - this._frameStartTime;
352 | if ( msSinceFrameStart > this._msToFrameCrash ) {
353 | this._didCrash = true;
354 | return true;
355 | }
356 |
357 | return false;
358 | }
359 | }
360 |
361 | export default Engine;
362 |
--------------------------------------------------------------------------------
/src/Audio/Audio.js:
--------------------------------------------------------------------------------
1 | import Sound from './Sound';
2 | import Frequencies from './Frequencies';
3 |
4 | /**
5 | * Handles playing of audio and adding audio data.
6 | */
7 | class Audio {
8 | constructor() {
9 | /**
10 | * The AudioContext used. Created in init.
11 | */
12 | this.context = null;
13 |
14 | /**
15 | * Array of sounds used, of the Sound class type.
16 | * Add a sound from data using the addSound method.
17 | */
18 | this.sounds = [];
19 |
20 | /**
21 | * Time in second we should look ahead during update to add audio events to the context.
22 | */
23 | this.lookAheadTime = 0.05; // in seconds
24 |
25 | /**
26 | * This mode runs the engine without drawing to a canvas or playing audio.
27 | * This is useful to use the engine to generate image data.
28 | */
29 | this.dataOnlyMode = false;
30 | }
31 |
32 | /**
33 | * Initialize the audio context. Called automatically by the Engine.
34 | */
35 | init() {
36 | if ( this.dataOnlyMode ) {
37 | return;
38 | }
39 |
40 | const AudioContext = window.AudioContext || window.webkitAudioContext;
41 | this.context = new AudioContext();
42 | }
43 |
44 | /**
45 | * Update audio events. Called automatically by the Engine in the update loop.
46 | */
47 | update() {
48 | if ( this.dataOnlyMode ) {
49 | return;
50 | }
51 |
52 | let sound = null;
53 | for ( let i = 0; i < this.sounds.length; i += 1 ) {
54 | sound = this.sounds[i];
55 | if ( sound.isPlayingInfiniteSound ) {
56 | const lastScheduledTime = this.context.currentTime - sound.infiniteStartTime + this.lookAheadTime;
57 | const totalNumberOfTics = Math.floor( lastScheduledTime / sound.infiniteTicDuration );
58 | if ( totalNumberOfTics > sound.infiniteTicsPlayed ) {
59 | let volumeTicIndex = 0;
60 | let pitchTicIndex = 0;
61 | let arpTicIndex = 0;
62 | for ( let tic = sound.infiniteTicsPlayed + 1; tic <= totalNumberOfTics; tic += 1 ) {
63 | const time = sound.infiniteStartTime + tic * sound.infiniteTicDuration;
64 | volumeTicIndex = Audio.indexAtTic(
65 | tic, sound.useVolumeLoop,
66 | sound.volumeLoopStart,
67 | sound.volumeLoopEnd,
68 | );
69 | pitchTicIndex = Audio.indexAtTic( tic, sound.usePitchLoop, sound.pitchLoopStart, sound.pitchLoopEnd );
70 | arpTicIndex = Audio.indexAtTic( tic, sound.useArpLoop, sound.arpLoopStart, sound.arpLoopEnd );
71 |
72 | const currentVolume = Audio.valueForVolume( sound.volumeTics[volumeTicIndex] )
73 | * Audio.linearToAdjustedVolume( sound.infiniteVolume );
74 |
75 | sound.infiniteGain.gain.linearRampToValueAtTime( currentVolume, time );
76 | sound.infiniteOsc.detune.linearRampToValueAtTime( sound.pitchTics[pitchTicIndex] * sound.pitchScale, time );
77 | const currentNote = sound.infiniteNote + sound.arpTics[arpTicIndex];
78 | const currentFrequency = Audio.frequencyForNote( currentNote );
79 | sound.infiniteOsc.frequency.setValueAtTime( currentFrequency, time );
80 |
81 | sound.infiniteTicsPlayed = tic;
82 | }
83 |
84 | sound.lastVolumeTic = volumeTicIndex;
85 | sound.lastPitchTic = pitchTicIndex;
86 | sound.lastArpTic = arpTicIndex;
87 | }
88 | }
89 | }
90 | }
91 |
92 | /**
93 | * Add a Sound instance to the sounds array from data.
94 | * @param {*} soundData
95 | */
96 | addSound( soundData ) {
97 | this.sounds.push( new Sound( soundData ) );
98 | return this.sounds.length - 1;
99 | }
100 |
101 | /**
102 | * Play a sound
103 | * @param {*} soundIndex
104 | * @param {*} note
105 | * @param {*} duration
106 | * @param {*} volume
107 | * @param {*} speed
108 | */
109 | playSound( soundIndex, note, duration = 32, volume = 1, speed = 0 ) {
110 | if ( this.dataOnlyMode ) {
111 | return;
112 | }
113 |
114 | if ( soundIndex >= this.sounds.length || soundIndex < 0 ) {
115 | console.error( 'Invalid sound index' );
116 | return;
117 | }
118 |
119 | if ( duration < 0 ) {
120 | this.playInfiniteSound( soundIndex, note, volume, speed );
121 | return;
122 | }
123 |
124 | const sound = this.sounds[soundIndex];
125 |
126 | const osc = this.context.createOscillator();
127 | osc.type = Audio.oscTypeForWaveValue( sound.wave );
128 |
129 | const ticDuration = Audio.ticDurationForSpeedValue( speed );
130 |
131 | osc.frequency.value = Audio.frequencyForNote( note );
132 |
133 | const gainNode = this.context.createGain();
134 |
135 | const initialVolume = Audio.valueForVolume( sound.volumeTics[0] ) * Audio.linearToAdjustedVolume( volume );
136 | gainNode.gain.setValueAtTime( initialVolume, this.context.currentTime );
137 |
138 | osc.detune.setValueAtTime( sound.pitchTics[0] * sound.pitchScale, this.context.currentTime );
139 |
140 | for ( let tic = 1; tic < duration; tic += 1 ) {
141 | const time = this.context.currentTime + tic * ticDuration;
142 | const volumeTicIndex = Audio.indexAtTic( tic, sound.useVolumeLoop, sound.volumeLoopStart, sound.volumeLoopEnd );
143 | const pitchTicIndex = Audio.indexAtTic( tic, sound.usePitchLoop, sound.pitchLoopStart, sound.pitchLoopEnd );
144 | const arpTicIndex = Audio.indexAtTic( tic, sound.useArpLoop, sound.arpLoopStart, sound.arpLoopEnd );
145 |
146 | const currentVolume = Audio.valueForVolume( sound.volumeTics[volumeTicIndex] )
147 | * Audio.linearToAdjustedVolume( volume );
148 |
149 | gainNode.gain.linearRampToValueAtTime( currentVolume, time );
150 | osc.detune.linearRampToValueAtTime( sound.pitchTics[pitchTicIndex] * sound.pitchScale, time );
151 | const currentNote = note + sound.arpTics[arpTicIndex];
152 | const currentFrequency = Audio.frequencyForNote( currentNote );
153 | osc.frequency.setValueAtTime( currentFrequency, time );
154 | }
155 | const stopTime = this.context.currentTime + ( duration * ticDuration ) + ( sound.releaseLength * ticDuration );
156 |
157 | if ( sound.releaseMode === Sound.RELEASE_EXPO ) {
158 | gainNode.gain.exponentialRampToValueAtTime( 0, stopTime );
159 | }
160 | else {
161 | // default to linear
162 | gainNode.gain.linearRampToValueAtTime( 0, stopTime );
163 | }
164 | osc.connect( gainNode ).connect( this.context.destination );
165 | osc.start();
166 |
167 | osc.stop( stopTime );
168 | }
169 |
170 | /**
171 | * Stop a sound that is being played infinitely
172 | * @param {*} soundIndex
173 | */
174 | stopInfiniteSound( soundIndex ) {
175 | const sound = this.sounds[soundIndex];
176 | if ( sound.isPlayingInfiniteSound ) {
177 | const stopTime = this.context.currentTime + ( sound.releaseLength * sound.infiniteTicDuration );
178 | if ( sound.releaseMode === Sound.RELEASE_EXPO ) {
179 | try {
180 | sound.infiniteGain.gain.exponentialRampToValueAtTime( 0.01, stopTime );
181 | }
182 | catch ( err ) {
183 | sound.infiniteGain.gain.linearRampToValueAtTime( 0, stopTime );
184 | }
185 | }
186 | else {
187 | // default to linear
188 | sound.infiniteGain.gain.linearRampToValueAtTime( 0, stopTime );
189 | }
190 | sound.infiniteTicsPlayed = 0;
191 | sound.infiniteOsc.stop( stopTime );
192 | sound.isPlayingInfiniteSound = false;
193 | }
194 | }
195 |
196 | /**
197 | * Stop all infinitely playing sounds
198 | */
199 | stopAllInfiniteSounds() {
200 | for ( let i = 0; i < this.sounds.length; i += 1 ) {
201 | this.stopInfiniteSound( i );
202 | }
203 | }
204 |
205 | /**
206 | * Play a sound infinitely. Only one instance of a sound at each index can be played at a time.
207 | * @param {*} soundIndex
208 | * @param {*} note
209 | * @param {*} volume
210 | * @param {*} speed
211 | */
212 | playInfiniteSound( soundIndex, note, volume, speed ) {
213 | if ( this.dataOnlyMode ) {
214 | return;
215 | }
216 |
217 | const sound = this.sounds[soundIndex];
218 | if ( sound.isPlayingInfiniteSound ) {
219 | this.stopInfiniteSound( soundIndex );
220 | }
221 |
222 | sound.isPlayingInfiniteSound = true;
223 | sound.infiniteStartTime = this.context.currentTime;
224 | sound.infiniteOsc = this.context.createOscillator();
225 | sound.infiniteTicDuration = Audio.ticDurationForSpeedValue( speed );
226 | sound.infiniteGain = this.context.createGain();
227 | sound.infiniteVolume = volume;
228 | sound.infiniteNote = note;
229 |
230 | sound.infiniteOsc.frequency.value = Audio.frequencyForNote( note );
231 | sound.infiniteOsc.type = Audio.oscTypeForWaveValue( sound.wave );
232 |
233 | const initialVolume = Audio.valueForVolume( sound.volumeTics[0] ) * volume;
234 | sound.infiniteGain.gain.setValueAtTime( initialVolume, this.context.currentTime );
235 |
236 | sound.infiniteOsc.connect( sound.infiniteGain ).connect( this.context.destination );
237 | sound.infiniteOsc.start();
238 | }
239 |
240 | /**
241 | * Get the frequency in hertz for a note number.
242 | * @param {*} note
243 | */
244 | static frequencyForNote( note ) {
245 | let trimmedNote = note;
246 | if ( trimmedNote < 0 ) {
247 | trimmedNote = 0;
248 | }
249 | else if ( trimmedNote >= Frequencies.length ) {
250 | trimmedNote = Frequencies.length - 1;
251 | }
252 | return Frequencies[trimmedNote];
253 | }
254 |
255 | /**
256 | * Get the duration in seconds for a tic at a given speed number.
257 | * @param {*} speed
258 | */
259 | static ticDurationForSpeedValue( speed ) {
260 | return Audio.fullDurationForSpeedValue( speed ) / Audio.TICS_PER_SOUND;
261 | }
262 |
263 | /**
264 | * Get the total length of a sound in seconds for a given speed number
265 | * @param {*} speed
266 | */
267 | static fullDurationForSpeedValue( speed ) {
268 | switch ( speed ) {
269 | case -1:
270 | return 1.5;
271 | case -2:
272 | return 2;
273 | case -3:
274 | return 2.5;
275 | case -4:
276 | return 3;
277 | case 1:
278 | return 0.75;
279 | case 2:
280 | return 0.5;
281 | case 3:
282 | return 0.25;
283 | default:
284 | return 1;
285 | }
286 | }
287 |
288 | /**
289 | * Get the wave type for a wave index
290 | * @param {*} waveValue
291 | */
292 | static oscTypeForWaveValue( waveValue ) {
293 | switch ( waveValue ) {
294 | case 0:
295 | return 'sine';
296 | case 1:
297 | return 'triangle';
298 | case 2:
299 | return 'square';
300 | case 3:
301 | return 'sawtooth';
302 | default:
303 | return 'sine';
304 | }
305 | }
306 |
307 | /**
308 | * Get a 0 - 1 volume value for a 0 - 15 value used by the Sound class.
309 | * @param {*} volume
310 | */
311 | static valueForVolume( volume ) {
312 | const normalizedValue = volume / 15;
313 | return normalizedValue ** 2.5;
314 | }
315 |
316 | /**
317 | * Adjust a linear volume value to account for human hearing.
318 | * @param {*} volume
319 | */
320 | static linearToAdjustedVolume( volume ) {
321 | return volume ** 2.5;
322 | }
323 |
324 | /**
325 | * Get the current tic index, taking into account looping.
326 | * @param {*} tic
327 | * @param {*} useLoop
328 | * @param {*} loopStart
329 | * @param {*} loopEnd
330 | */
331 | static indexAtTic( tic, useLoop, loopStart, loopEnd ) {
332 | if ( !useLoop || loopStart < 0 || loopEnd < loopStart ) {
333 | // no looping
334 | if ( tic < 0 ) {
335 | return 0;
336 | }
337 |
338 | if ( tic >= Audio.TICS_PER_SOUND ) {
339 | return Audio.TICS_PER_SOUND - 1;
340 | }
341 |
342 | return tic;
343 | }
344 |
345 | if ( tic <= loopEnd ) {
346 | // not looping yet
347 | return tic;
348 | }
349 |
350 | const loopLength = loopEnd - loopStart + 1;
351 | const loopAdd = ( tic - loopStart ) % loopLength;
352 |
353 | return loopStart + loopAdd;
354 | }
355 | }
356 |
357 | Audio.TICS_PER_SOUND = 32;
358 |
359 | export default Audio;
360 |
--------------------------------------------------------------------------------
/demo/data/WelcomeTransfer.json:
--------------------------------------------------------------------------------
1 | {
2 | "_id": "5e6ec15503e08617f0babdd7",
3 | "sounds": [
4 | {
5 | "volumeTics": [
6 | 9,
7 | 9,
8 | 0,
9 | 0,
10 | 14,
11 | 14,
12 | 0,
13 | 0,
14 | 0,
15 | 0,
16 | 0,
17 | 0,
18 | 0,
19 | 0,
20 | 0,
21 | 0,
22 | 14,
23 | 14,
24 | 0,
25 | 0,
26 | 10,
27 | 10,
28 | 0,
29 | 0,
30 | 0,
31 | 0,
32 | 0,
33 | 0,
34 | 0,
35 | 0,
36 | 0,
37 | 0
38 | ],
39 | "pitchTics": [
40 | 0,
41 | 0,
42 | 0,
43 | 0,
44 | 0,
45 | 0,
46 | 0,
47 | 0,
48 | 0,
49 | 0,
50 | 0,
51 | 0,
52 | 0,
53 | 0,
54 | 0,
55 | 0,
56 | 0,
57 | 0,
58 | 0,
59 | 0,
60 | 0,
61 | 0,
62 | 0,
63 | 0,
64 | 0,
65 | 0,
66 | 0,
67 | 0,
68 | 0,
69 | 0,
70 | 0,
71 | 0
72 | ],
73 | "arpTics": [
74 | 0,
75 | 0,
76 | 0,
77 | 0,
78 | 0,
79 | 0,
80 | 0,
81 | 0,
82 | 0,
83 | 0,
84 | 0,
85 | 0,
86 | 0,
87 | 0,
88 | 0,
89 | -2,
90 | -2,
91 | -2,
92 | -2,
93 | -2,
94 | -2,
95 | -2,
96 | -2,
97 | -2,
98 | -2,
99 | -2,
100 | -2,
101 | -2,
102 | -2,
103 | -2,
104 | -2,
105 | -2
106 | ],
107 | "_id": "5e6ec18803e08617f0babe21",
108 | "pitchScale": 100,
109 | "wave": 2,
110 | "useVolumeLoop": true,
111 | "volumeLoopStart": 0,
112 | "volumeLoopEnd": 31,
113 | "usePitchLoop": false,
114 | "pitchLoopStart": 0,
115 | "pitchLoopEnd": 31,
116 | "useArpLoop": true,
117 | "arpLoopStart": 0,
118 | "arpLoopEnd": 31,
119 | "name": "walk",
120 | "releaseLength": 1,
121 | "releaseMode": "linear"
122 | },
123 | {
124 | "volumeTics": [
125 | 15,
126 | 15,
127 | 15,
128 | 15,
129 | 15,
130 | 15,
131 | 15,
132 | 15,
133 | 15,
134 | 15,
135 | 15,
136 | 15,
137 | 15,
138 | 15,
139 | 15,
140 | 15,
141 | 15,
142 | 15,
143 | 15,
144 | 15,
145 | 15,
146 | 15,
147 | 15,
148 | 15,
149 | 15,
150 | 15,
151 | 15,
152 | 15,
153 | 15,
154 | 15,
155 | 15,
156 | 15
157 | ],
158 | "pitchTics": [
159 | 0,
160 | 0,
161 | 0,
162 | 0,
163 | 0,
164 | 0,
165 | 0,
166 | 0,
167 | 0,
168 | 0,
169 | 0,
170 | 0,
171 | 0,
172 | 0,
173 | 0,
174 | 0,
175 | 0,
176 | 0,
177 | 0,
178 | 0,
179 | 0,
180 | 0,
181 | 0,
182 | 0,
183 | 0,
184 | 0,
185 | 0,
186 | 0,
187 | 0,
188 | 0,
189 | 0,
190 | 0
191 | ],
192 | "arpTics": [
193 | 0,
194 | 0,
195 | 0,
196 | 0,
197 | 1,
198 | 1,
199 | 1,
200 | 1,
201 | 3,
202 | 3,
203 | 3,
204 | 3,
205 | 5,
206 | 5,
207 | 5,
208 | 5,
209 | 7,
210 | 7,
211 | 7,
212 | 7,
213 | 9,
214 | 9,
215 | 9,
216 | 9,
217 | 11,
218 | 11,
219 | 11,
220 | 11,
221 | 8,
222 | 8,
223 | 8,
224 | 8
225 | ],
226 | "_id": "5e6ec18803e08617f0babe20",
227 | "pitchScale": 100,
228 | "wave": 2,
229 | "useVolumeLoop": false,
230 | "volumeLoopStart": 0,
231 | "volumeLoopEnd": 31,
232 | "usePitchLoop": false,
233 | "pitchLoopStart": 0,
234 | "pitchLoopEnd": 31,
235 | "useArpLoop": false,
236 | "arpLoopStart": 0,
237 | "arpLoopEnd": 31,
238 | "name": "pickup",
239 | "releaseLength": 10,
240 | "releaseMode": "linear"
241 | }
242 | ],
243 | "tilesets": [
244 | {
245 | "layers": [
246 | {
247 | "_id": "5e6ec18803e08617f0babe23",
248 | "isVisible": true,
249 | "data": "CwGgDCoIwjHSA7OStbPmgHFlBmNOEAmATn0JQQ1RiJJFIggCZaU3ojO0IHy+lVqlLd2wrh3EgeUMQgmNmMkADYRK9TTbqC5HjpC5h6mKD1p1WAZbTJQ5GKaQuITuyACsjWzGTHfFwcPaxR1chtkR2VwpTCfKBiEpIjlZFiIdJ9MtSMAw2RCqS0XbVyirBp3NmQ6Yhc6v1dbGsoCWsoit1zWuvbKJqx1brr1XrR+xpdhgZ6XXDMUKbGGidW6-xnFuTRQbuhu733YOqw9+tAFryXFo4ujbBnyUBpn5recFHtsoJ-v4BYLACwAWbCwyhBsDBENBRmUsMk0Fk22RtFRSNoKLhFCgbG8O1A3kR12JRJOqDJOwI+NgBAx4JxbDoTW8BDG5BpUDpUOxglxhBZ9XU3hpY2phG5-IZfKZ5OQrNyOwVsWV9U5kuhVB5zJkEFVHKFFIl9SlEO15Jg3kMUHlhsS10MhONJE1mH5OstmmIwudPOlaIFsBFXsB1zoBBdvJNsp2UB91vF7lt4YD-sjOp97jwesC6tTynT5LwBpT9IL5qpJdpAbwbD1TJjMGLYerkdr11qeOrLAx+JIdEbLituWDhkzivHXOjsAN1s9pjYTO5HSnvdbPL7YcX1Zexvt7rlDtyTtApnFbJHvv5Tov-OHpk9+O3U6aoFlK4jFeX09Lv35S48N8PBTRxBynMkzyPEo80jG8emDJ892mFRXx5ICMXQr8PBWQYKxgLs5ygmQu1-a9rgvFgEKwppkFkAwA0wg8X1KFRYR1LsLzwJ1SLYdtgyYhgijo1BhMYmNBJcME8JUe8ZyIpUWhbVceR7IifQXDxaIYlQMJk80hIeJj8PFa0c1vJSNRkJ0x2uDSaJQySHO5d8VFlZyPAINzNJUUDAzwUc5hg7Uc0MFgczs1YeC0lzn3uGKnJEjyEqafDUGihJB2bIL3RCnpwpU34XNS3TRL0-9CuAnzpKgYMKM9FM2y7CKshckrtJIlycJcXyMyI206os6c+MVTqHO+MjSo67CxsMwdbUMXBRUvQwAvUSdLJI3IDVqBgdkW2xxU7OYNO3E6VCOlYevJVTZPHNbBoxO9jQi2MuwRVzEKA-cwO4npfuU91NqnF6B2uNj6n6SjzU-Wo3EyqsAYbQaQY3EaUIYTyZpYSMAKbVzgNBnUsqvJG8xRp6zuYzGYpx6s8di2pCYtKtINk-7P0B5Hqq7I6UyaanHrplxMdewNNtMWq0bZwb0yB28wLe-T6kXRD+ZQpnY1nRV9oa7VFZ2O7rm8cHkGp1XhZQuHA320KEcs4aTeVmRzdNy3pJtnpxcvHijQo4NwepjwoYPQOUqtom7e01Uoe8SmMfqWjaaphPYHDotyMVXKxnqndUdkmO0dxp2aYK5OGYtQcOMz+Sves3JE3Xf8s9TjtqOLoPBbLmbRaJltTBZlvZIbqdZb7ocvXtY2lbN6f1ek4ndc52SoH2x2Z4PV2mQ1vHKW5XejWgPfaCPw+AxYH1OLB2eVeviu-NzsjEeP7Sn9P2FDbCojxTXj7b88RCHbQ3xk0YOXly7-x5IAkOKdQFrH6BA-kUCwFY3NqHFipovhtzQbRVBwD0GukLkLTeW4wwcxIomZ8ElMZHX9IhACrQRZ-nEmlH8udxqUPOk7JoGlaFtw6K1GagtiFCKdp3CSqVUIuUQrwgSlUvLDhEZjRROk+FoHkWVAhzU1FrHLtuZRwk1ZTRSglXRGioxaO3AwlRG9RF-yVpYi2U1-RaK0iA5Kjig7uOIYYtY9knFJBscVRy8UvI+LcaEjxYSTSRRYduaRATtzfCKtYlySi7HlSSXIkhzilZdXYUlAxHiXZzEFBgiAWi8kBh8fokh3CZrxMwfyFYZ1rQOIuhPAh70b4TQaAQyEZTICwmxvEcCRB+mLgICMbkOFqQQg1vLKySwhYrA6M4cCyhP5GV1FhE6dwsxDjGaDEgG1zj7PlHWSASMAKPRsKABAughyTOILzOm4cAiLGCPReUTy8AvJfG8ig5BzL6ApE8lgfz3CPxIACwQbxLoqM8PQOhdNCb5DmEC48CQKQQiRimVWaKHkgp9I4VAwBblXIfkyAl5JnjkrQt2bUNhYinjQByZQUAro7GGeVEeKllDeDhayrwMIVIXIsBeTwFzxm8iAA",
250 | "format": "rc"
251 | }
252 | ],
253 | "_id": "5e6ec18803e08617f0babe22",
254 | "width": 8,
255 | "height": 8
256 | }
257 | ],
258 | "tilemaps": [
259 | {
260 | "layers": [
261 | {
262 | "_id": "5e6ec18803e08617f0babe25",
263 | "isVisible": true,
264 | "data": "IwGgzGLADOAsVwFZF1AJhEg7CTSAOcLXUJATjxNUlDRADZqyjIcbVQzStKn2MRUGFh1aIeoKrpKw2AgESEdJmM6Iwq8DzCyJTNj0KIKJnnHGSlqFCpNDeWZhMuzYSUVmBA",
265 | "format": "rc"
266 | }
267 | ],
268 | "_id": "5e6ec18803e08617f0babe24",
269 | "name": "untitled",
270 | "width": 12,
271 | "height": 8
272 | }
273 | ],
274 | "dateCreated": "2020-03-15T23:59:17.018Z",
275 | "dateUpdated": "2020-03-16T00:00:08.532Z",
276 | "connectedProject": "5e6ec14503e08617f0babdba",
277 | "user": "5e4c88490450551f7c7262e6",
278 | "urlName": "welcome",
279 | "palette": {
280 | "colors": [
281 | "000000",
282 | "0b0711",
283 | "eaf2de",
284 | "766e76",
285 | "561f6e",
286 | "7d4f31",
287 | "e98c49",
288 | "fbc0a0",
289 | "f681b2",
290 | "d83232",
291 | "e3e962",
292 | "65cf57",
293 | "2ba957",
294 | "187575",
295 | "1e2cB0",
296 | "2379e5",
297 | "95cae5"
298 | ],
299 | "_id": "5e6ec18803e08617f0babe26"
300 | },
301 | "code": {
302 | "_id": "5e6ec18803e08617f0babe27",
303 | "scripts": [
304 | {
305 | "_id": "5e6ec18803e08617f0babe1f",
306 | "text": "\n// Globals\nlet inp = null; // input\nlet scr = null; // screen\nlet aud = null; // audio\n\nconst player = {\n\tx: 90,\n\ty: 30,\n\tspeed: 0.5,\n\tisWalking: false,\n\tflip: 0,\n\tframesSinceWalkStart: 0\n}\n\nconst mushrooms = [\n\t{ \n\t\tx: 36,\n\t\ty: 30,\n\t\twasGrabbed: false\n\t},\n\t{ \n\t\tx: 130,\n\t\ty: 70,\n\t\twasGrabbed: false\n\t}\n];\n\nlet numberOfGrabbedMushrooms = 0;\n\nlet randomColor = 1;\n\n// initialization\nengine.onInit = () => {\n\tinp = engine.input;\n\tscr = engine.screen;\n\taud = engine.audio;\n\t\n\tupdateColors();\n};\n\n\n// update loop\nengine.onUpdate = () => {\n scr.clear( 1 );\n\n\tscr.drawMap(\n\t 0, // originX on map\n\t 0, // originY on map\n\t -1, // width\n\t -1, // height\n\t 0, // screenX\n\t 0, // screenY\n\t 0 // tilemap index\n\t);\n\t\n\tdrawMushrooms();\n\t\n\tupdatePlayer();\n\t\n\tlet textMainColor = 2;\n\tif ( numberOfGrabbedMushrooms > 0 ) {\n\t\ttextMainColor = randomColor;\n\t}\n\t\n\tlet textPositionOffset = 0;\n\tif ( numberOfGrabbedMushrooms > 1 ) {\n\t\ttextPositionOffset = Math.sin( engine.realTimeSinceGameStart * 10 ) * 8;\n\t}\n\t\n\tscr.drawText(\n\t\t'Welcome to Bitmelo!',\n\t\t50,\n\t\t90 + Math.floor( textPositionOffset ),\n\t\ttextMainColor,\n\t\t1,\n\t\t0\n\t);\n};\n\nfunction drawMushrooms() {\n\tmushrooms.forEach( mushroom => {\n\t\tif ( !mushroom.wasGrabbed ) {\n\t\t\tscr.drawTile(\n\t\t\t\t61,\n\t\t\t\tmushroom.x - 8, // center on the position\n\t\t\t\tmushroom.y - 8, // center on the position\n\t\t\t\t0\n\t\t\t);\n\t\t}\n\t} );\n}\n\nfunction updatePlayer() {\n\tlet newX = player.x;\n\tlet newY = player.y;\n\t\n\tlet isWalking = false;\n\tif ( inp.left.pressed ) {\n\t\tnewX -= player.speed;\n\t\tisWalking = true;\n\t\tplayer.flip = 1;\n\t}\n\telse if ( inp.right.pressed ) {\n\t\tnewX += player.speed;\n\t\tisWalking = true;\n\t\tplayer.flip = 0;\n\t}\n\t\n\tif ( inp.down.pressed ) {\n\t\tnewY -= player.speed;\n\t\tisWalking = true;\n\t}\n\telse if ( inp.up.pressed ) {\n\t\tnewY += player.speed;\n\t\tisWalking = true;\n\t}\n\t\n\tif ( isWalking ) {\n\t\tplayer.framesSinceWalkStart += 1;\n\t}\n\t\n\t// play or stop audio\n\tif ( isWalking && !player.isWalking ) {\n\t\t// started walking\n\t\tplayer.framesSinceWalkStart = 0;\n\t\t\n\t\tlet note = bitmelo.Notes.C4;\n\t\tif ( numberOfGrabbedMushrooms > 1 ) {\n\t\t\tnote = bitmelo.Notes.C2;\n\t\t}\n\t\telse if ( numberOfGrabbedMushrooms > 0 ) {\n\t\t\tnote = bitmelo.Notes.C3;\n\t\t}\n\t\t\n\t\taud.playInfiniteSound(\n\t\t\t0,\n\t\t\tnote,\n\t\t\t0.5,\n\t\t\t2\n\t\t);\n\t}\n\telse if ( !isWalking && player.isWalking ) {\n\t\t// stopped walking\n\t\taud.stopInfiniteSound( 0 );\n\t}\n\t\n\tplayer.isWalking = isWalking;\n\t\n\t// make sure we are not colliding with the fence\n\tif ( \n\t\tnewX >= 16\n\t\t&& newX < scr.width - 16\n\t\t&& newY >= 24\n\t\t&& newY < scr.height - 16\n\t) {\n\t\tplayer.x = newX;\n\t\tplayer.y = newY;\n\t}\n\t\n\t// check mushroom collisions\n\tfor ( let i = 0; i < mushrooms.length; i += 1 ) {\n\t\tconst mushroom = mushrooms[i];\n\t\tif ( !mushroom.wasGrabbed ) {\n\t\t\tconst deltaX = Math.abs( player.x - mushroom.x );\n\t\t\tconst deltaY= Math.abs( player.y - mushroom.y );\n\t\t\tconst distance = Math.sqrt( deltaX * deltaX + deltaY * deltaY );\n\t\t\t\n\t\t\t// player has grabbed a mushroom\n\t\t\tif ( distance <= 12 ) {\n\t\t\t\tmushroom.wasGrabbed = true;\n\t\t\t\tnumberOfGrabbedMushrooms += 1;\n\t\t\t\t\n\t\t\t\taud.playSound(\n\t\t\t\t\t1,\n\t\t\t\t\tbitmelo.Notes.E3,\n\t\t\t\t\t48,\n\t\t\t\t\t0.25,\n\t\t\t\t\t1\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\t\n\t// draw the player\n\tlet frameGID = 1;\n\tif ( player.isWalking ) {\n\t\tif ( player.framesSinceWalkStart % 16 < 8 ) {\n\t\t\tframeGID = 2;\n\t\t}\n\t\telse {\n\t\t\tframeGID = 3;\n\t\t}\n\t}\n\t\n\tscr.drawTile(\n\t\tframeGID,\n\t\tMath.floor( player.x ) - 8, // center the tile on the position\n\t\tMath.floor( player.y ) - 8, // center the tile on the position\n\t\tplayer.flip\n\t);\n}\n\nfunction updateColors() {\n\trandomColor = Math.floor( Math.random() * 16 ) + 1;\n\tsetTimeout( updateColors, 100 );\n}\n\n\n\n\n\n\n\n\n\n\n\n"
307 | }
308 | ]
309 | },
310 | "project": {
311 | "_id": "5e6ec18803e08617f0babe28",
312 | "tileSize": 16,
313 | "name": "Welcome",
314 | "screen": {
315 | "_id": "5e6ec18803e08617f0babe29",
316 | "width": 192,
317 | "height": 128,
318 | "scaleMode": 1,
319 | "scale": 3,
320 | "minScale": 1,
321 | "maxScale": 4,
322 | "horizontalScaleCushion": 10,
323 | "verticalScaleCushion": 10,
324 | "rescaleOnWindowResize": true
325 | },
326 | "misc": {
327 | "_id": "5e6ec18803e08617f0babe2a",
328 | "hideCursor": false,
329 | "clickToBegin": true,
330 | "startTransitionFrames": 60
331 | },
332 | "editorVersion": "1.3.1"
333 | },
334 | "__v": 2,
335 | "format": "transfer"
336 | }
337 |
--------------------------------------------------------------------------------
/src/lz-string/libs/lz-string.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013 Pieroxy
2 | // This work is free. You can redistribute it and/or modify it
3 | // under the terms of the WTFPL, Version 2
4 | // For more information see LICENSE.txt or http://www.wtfpl.net/
5 | //
6 | // For more information, the home page:
7 | // http://pieroxy.net/blog/pages/lz-string/testing.html
8 | //
9 | // LZ-based compression algorithm, version 1.4.4
10 | var LZString = (function() {
11 |
12 | // private property
13 | var f = String.fromCharCode;
14 | var keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
15 | var keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
16 | var baseReverseDic = {};
17 |
18 | function getBaseValue(alphabet, character) {
19 | if (!baseReverseDic[alphabet]) {
20 | baseReverseDic[alphabet] = {};
21 | for (var i=0 ; i>> 8;
66 | buf[i*2+1] = current_value % 256;
67 | }
68 | return buf;
69 | },
70 |
71 | //decompress from uint8array (UCS-2 big endian format)
72 | decompressFromUint8Array:function (compressed) {
73 | if (compressed===null || compressed===undefined){
74 | return LZString.decompress(compressed);
75 | } else {
76 | var buf=new Array(compressed.length/2); // 2 bytes per character
77 | for (var i=0, TotalLen=buf.length; i> 1;
159 | }
160 | } else {
161 | value = 1;
162 | for (i=0 ; i> 1;
184 | }
185 | }
186 | context_enlargeIn--;
187 | if (context_enlargeIn == 0) {
188 | context_enlargeIn = Math.pow(2, context_numBits);
189 | context_numBits++;
190 | }
191 | delete context_dictionaryToCreate[context_w];
192 | } else {
193 | value = context_dictionary[context_w];
194 | for (i=0 ; i> 1;
204 | }
205 |
206 |
207 | }
208 | context_enlargeIn--;
209 | if (context_enlargeIn == 0) {
210 | context_enlargeIn = Math.pow(2, context_numBits);
211 | context_numBits++;
212 | }
213 | // Add wc to the dictionary.
214 | context_dictionary[context_wc] = context_dictSize++;
215 | context_w = String(context_c);
216 | }
217 | }
218 |
219 | // Output the code for w.
220 | if (context_w !== "") {
221 | if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate,context_w)) {
222 | if (context_w.charCodeAt(0)<256) {
223 | for (i=0 ; i> 1;
244 | }
245 | } else {
246 | value = 1;
247 | for (i=0 ; i> 1;
269 | }
270 | }
271 | context_enlargeIn--;
272 | if (context_enlargeIn == 0) {
273 | context_enlargeIn = Math.pow(2, context_numBits);
274 | context_numBits++;
275 | }
276 | delete context_dictionaryToCreate[context_w];
277 | } else {
278 | value = context_dictionary[context_w];
279 | for (i=0 ; i> 1;
289 | }
290 |
291 |
292 | }
293 | context_enlargeIn--;
294 | if (context_enlargeIn == 0) {
295 | context_enlargeIn = Math.pow(2, context_numBits);
296 | context_numBits++;
297 | }
298 | }
299 |
300 | // Mark the end of the stream
301 | value = 2;
302 | for (i=0 ; i> 1;
312 | }
313 |
314 | // Flush the last char
315 | while (true) {
316 | context_data_val = (context_data_val << 1);
317 | if (context_data_position == bitsPerChar-1) {
318 | context_data.push(getCharFromInt(context_data_val));
319 | break;
320 | }
321 | else context_data_position++;
322 | }
323 | return context_data.join('');
324 | },
325 |
326 | decompress: function (compressed) {
327 | if (compressed == null) return "";
328 | if (compressed == "") return null;
329 | return LZString._decompress(compressed.length, 32768, function(index) { return compressed.charCodeAt(index); });
330 | },
331 |
332 | _decompress: function (length, resetValue, getNextValue) {
333 | var dictionary = [],
334 | next,
335 | enlargeIn = 4,
336 | dictSize = 4,
337 | numBits = 3,
338 | entry = "",
339 | result = [],
340 | i,
341 | w,
342 | bits, resb, maxpower, power,
343 | c,
344 | data = {val:getNextValue(0), position:resetValue, index:1};
345 |
346 | for (i = 0; i < 3; i += 1) {
347 | dictionary[i] = i;
348 | }
349 |
350 | bits = 0;
351 | maxpower = Math.pow(2,2);
352 | power=1;
353 | while (power!=maxpower) {
354 | resb = data.val & data.position;
355 | data.position >>= 1;
356 | if (data.position == 0) {
357 | data.position = resetValue;
358 | data.val = getNextValue(data.index++);
359 | }
360 | bits |= (resb>0 ? 1 : 0) * power;
361 | power <<= 1;
362 | }
363 |
364 | switch (next = bits) {
365 | case 0:
366 | bits = 0;
367 | maxpower = Math.pow(2,8);
368 | power=1;
369 | while (power!=maxpower) {
370 | resb = data.val & data.position;
371 | data.position >>= 1;
372 | if (data.position == 0) {
373 | data.position = resetValue;
374 | data.val = getNextValue(data.index++);
375 | }
376 | bits |= (resb>0 ? 1 : 0) * power;
377 | power <<= 1;
378 | }
379 | c = f(bits);
380 | break;
381 | case 1:
382 | bits = 0;
383 | maxpower = Math.pow(2,16);
384 | power=1;
385 | while (power!=maxpower) {
386 | resb = data.val & data.position;
387 | data.position >>= 1;
388 | if (data.position == 0) {
389 | data.position = resetValue;
390 | data.val = getNextValue(data.index++);
391 | }
392 | bits |= (resb>0 ? 1 : 0) * power;
393 | power <<= 1;
394 | }
395 | c = f(bits);
396 | break;
397 | case 2:
398 | return "";
399 | }
400 | dictionary[3] = c;
401 | w = c;
402 | result.push(c);
403 | while (true) {
404 | if (data.index > length) {
405 | return "";
406 | }
407 |
408 | bits = 0;
409 | maxpower = Math.pow(2,numBits);
410 | power=1;
411 | while (power!=maxpower) {
412 | resb = data.val & data.position;
413 | data.position >>= 1;
414 | if (data.position == 0) {
415 | data.position = resetValue;
416 | data.val = getNextValue(data.index++);
417 | }
418 | bits |= (resb>0 ? 1 : 0) * power;
419 | power <<= 1;
420 | }
421 |
422 | switch (c = bits) {
423 | case 0:
424 | bits = 0;
425 | maxpower = Math.pow(2,8);
426 | power=1;
427 | while (power!=maxpower) {
428 | resb = data.val & data.position;
429 | data.position >>= 1;
430 | if (data.position == 0) {
431 | data.position = resetValue;
432 | data.val = getNextValue(data.index++);
433 | }
434 | bits |= (resb>0 ? 1 : 0) * power;
435 | power <<= 1;
436 | }
437 |
438 | dictionary[dictSize++] = f(bits);
439 | c = dictSize-1;
440 | enlargeIn--;
441 | break;
442 | case 1:
443 | bits = 0;
444 | maxpower = Math.pow(2,16);
445 | power=1;
446 | while (power!=maxpower) {
447 | resb = data.val & data.position;
448 | data.position >>= 1;
449 | if (data.position == 0) {
450 | data.position = resetValue;
451 | data.val = getNextValue(data.index++);
452 | }
453 | bits |= (resb>0 ? 1 : 0) * power;
454 | power <<= 1;
455 | }
456 | dictionary[dictSize++] = f(bits);
457 | c = dictSize-1;
458 | enlargeIn--;
459 | break;
460 | case 2:
461 | return result.join('');
462 | }
463 |
464 | if (enlargeIn == 0) {
465 | enlargeIn = Math.pow(2, numBits);
466 | numBits++;
467 | }
468 |
469 | if (dictionary[c]) {
470 | entry = dictionary[c];
471 | } else {
472 | if (c === dictSize) {
473 | entry = w + w.charAt(0);
474 | } else {
475 | return null;
476 | }
477 | }
478 | result.push(entry);
479 |
480 | // Add w+entry[0] to the dictionary.
481 | dictionary[dictSize++] = w + entry.charAt(0);
482 | enlargeIn--;
483 |
484 | w = entry;
485 |
486 | if (enlargeIn == 0) {
487 | enlargeIn = Math.pow(2, numBits);
488 | numBits++;
489 | }
490 |
491 | }
492 | }
493 | };
494 | return LZString;
495 | })();
496 |
497 | if (typeof define === 'function' && define.amd) {
498 | define(function () { return LZString; });
499 | } else if( typeof module !== 'undefined' && module != null ) {
500 | module.exports = LZString
501 | } else if( typeof angular !== 'undefined' && angular != null ) {
502 | angular.module('LZString', [])
503 | .factory('LZString', function () {
504 | return LZString;
505 | });
506 | }
507 |
--------------------------------------------------------------------------------
/src/Input/Input.js:
--------------------------------------------------------------------------------
1 | import Keys from './Keys';
2 |
3 |
4 | /**
5 | * Handle game input
6 | */
7 | class Input {
8 | constructor() {
9 | /**
10 | * Reference to the canvas used for mouse input.
11 | * Automatically added by the Engine.
12 | */
13 | this.canvas = null;
14 |
15 | /**
16 | * The scale of the canvas, aka the pixel size.
17 | * Added automatically by the Engine
18 | */
19 | this.canvasScale = 1;
20 |
21 | /**
22 | * The width of the game screen.
23 | * Not affected by this.canvasScale.
24 | * Added automatically by the Engine.
25 | */
26 | this.screenWidth = 1;
27 |
28 | /**
29 | * The height of the game screen.
30 | * Not affected by this.canvasScale.
31 | * Added automatically by the Engine.
32 | */
33 | this.screenHeight = 1;
34 |
35 | /**
36 | * Object containing input state of the mouse.
37 | * mouse.isOffScreen,
38 | * mouse.position.x,
39 | * mouse.position.y,
40 | * mouse.left.pressed,
41 | * mouse.left.down,
42 | * mouse.left.up,
43 | * mouse.right.pressed,
44 | * mouse.right.down,
45 | * mouse.right.up
46 | */
47 | this.mouse = {};
48 | this.mouse.isOffScreen = true;
49 | this.mouse.position = {
50 | x: -1,
51 | y: -1,
52 | };
53 |
54 | this.mouse.left = {
55 | pressed: false,
56 | down: false,
57 | up: false,
58 | };
59 |
60 | this.mouse.right = {
61 | pressed: false,
62 | down: false,
63 | up: false,
64 | };
65 |
66 | /**
67 | * Caches keyboard key states.
68 | */
69 | this._keysRaw = new Uint8ClampedArray( 256 );
70 |
71 | /**
72 | * Keyboard states for the current frame
73 | */
74 | this._currentKeys = new Uint8ClampedArray( 256 );
75 |
76 | /**
77 | * Keyboard states for the last frame
78 | */
79 | this._lastKeys = new Uint8ClampedArray( 256 );
80 |
81 | /**
82 | * Maps standard game buttons to keyboard keys.
83 | */
84 | this._buttonsToKeys = new Uint8ClampedArray( 32 );
85 |
86 | /**
87 | * Maps standard game buttons to alternate keyboard keys
88 | */
89 | this._buttonsToAltKeys = new Uint8ClampedArray( 32 );
90 |
91 | /**
92 | * Maps standard game buttons to joypad buttons
93 | */
94 | this._buttonsToJoyButtons = new Int8Array( 32 );
95 |
96 | /**
97 | * Maps standard game buttons to alternate joypad buttons
98 | */
99 | this._buttonsToAltJoyButtons = new Int8Array( 32 );
100 | this._buttonsToAltJoyButtons.fill( -1 );
101 |
102 | /**
103 | * Maps standard game buttons to joypad axes
104 | */
105 | this._buttonsToJoyAxes = new Int8Array( 32 );
106 |
107 | /**
108 | * gamepad button states for the current frame
109 | */
110 | this._currentJoyButtons = new Uint8ClampedArray( 20 );
111 |
112 | /**
113 | * gamepad button states for the last frame
114 | */
115 | this._lastJoyButtons = new Uint8ClampedArray( 20 );
116 |
117 | /**
118 | * gamepad axes states for the current frame
119 | */
120 | this._currentJoyAxes = new Array( 9 );
121 |
122 | /**
123 | * gamepad axes states for the last frame
124 | */
125 | this._lastJoyAxes = new Array( 9 );
126 |
127 | // default button mappings
128 | this._buttonsToKeys[Input.GAME_LEFT] = Keys.LEFT_ARROW;
129 | this._buttonsToKeys[Input.GAME_RIGHT] = Keys.RIGHT_ARROW;
130 | this._buttonsToKeys[Input.GAME_UP] = Keys.UP_ARROW;
131 | this._buttonsToKeys[Input.GAME_DOWN] = Keys.DOWN_ARROW;
132 |
133 | this._buttonsToKeys[Input.GAME_ACTION_ONE] = Keys.Z_KEY;
134 | this._buttonsToKeys[Input.GAME_ACTION_TWO] = Keys.X_KEY;
135 | this._buttonsToKeys[Input.GAME_ACTION_THREE] = Keys.A_KEY;
136 | this._buttonsToKeys[Input.GAME_ACTION_FOUR] = Keys.S_KEY;
137 | this._buttonsToKeys[Input.GAME_LEFT_TRIGGER] = Keys.Q_KEY;
138 | this._buttonsToKeys[Input.GAME_RIGHT_TRIGGER] = Keys.W_KEY;
139 |
140 | this._buttonsToKeys[Input.GAME_PAUSE] = Keys.P_KEY;
141 |
142 | this._buttonsToKeys[Input.MENU_LEFT] = Keys.LEFT_ARROW;
143 | this._buttonsToKeys[Input.MENU_RIGHT] = Keys.RIGHT_ARROW;
144 | this._buttonsToKeys[Input.MENU_UP] = Keys.UP_ARROW;
145 | this._buttonsToKeys[Input.MENU_DOWN] = Keys.DOWN_ARROW;
146 |
147 | this._buttonsToKeys[Input.MENU_CONFIRM] = Keys.Z_KEY;
148 | this._buttonsToKeys[Input.MENU_BACK] = Keys.X_KEY;
149 |
150 | // default alt button mappings
151 | this._buttonsToAltKeys[Input.GAME_LEFT] = Keys.J_KEY;
152 | this._buttonsToAltKeys[Input.GAME_RIGHT] = Keys.L_KEY;
153 | this._buttonsToAltKeys[Input.GAME_UP] = Keys.I_KEY;
154 | this._buttonsToAltKeys[Input.GAME_DOWN] = Keys.K_KEY;
155 |
156 | this._buttonsToAltKeys[Input.GAME_ACTION_ONE] = Keys.SPACE;
157 | this._buttonsToAltKeys[Input.GAME_ACTION_TWO] = Keys.D_KEY;
158 | this._buttonsToAltKeys[Input.GAME_ACTION_THREE] = Keys.C_KEY;
159 | this._buttonsToAltKeys[Input.GAME_ACTION_FOUR] = Keys.V_KEY;
160 | this._buttonsToAltKeys[Input.GAME_LEFT_TRIGGER] = Keys.SHIFT;
161 | this._buttonsToAltKeys[Input.GAME_RIGHT_TRIGGER] = Keys.ALT;
162 |
163 | this._buttonsToAltKeys[Input.GAME_PAUSE] = Keys.ENTER;
164 |
165 | this._buttonsToAltKeys[Input.MENU_LEFT] = Keys.J_KEY;
166 | this._buttonsToAltKeys[Input.MENU_RIGHT] = Keys.L_KEY;
167 | this._buttonsToAltKeys[Input.MENU_UP] = Keys.I_KEY;
168 | this._buttonsToAltKeys[Input.MENU_DOWN] = Keys.K_KEY;
169 |
170 | this._buttonsToAltKeys[Input.MENU_CONFIRM] = Keys.SPACE;
171 | this._buttonsToAltKeys[Input.MENU_BACK] = Keys.D_KEY;
172 |
173 | // default joypad button mappings
174 | this._buttonsToJoyButtons[Input.GAME_LEFT] = 14;
175 | this._buttonsToJoyButtons[Input.GAME_RIGHT] = 15;
176 | this._buttonsToJoyButtons[Input.GAME_UP] = 12;
177 | this._buttonsToJoyButtons[Input.GAME_DOWN] = 13;
178 |
179 | this._buttonsToJoyButtons[Input.GAME_ACTION_ONE] = 0;
180 | this._buttonsToJoyButtons[Input.GAME_ACTION_TWO] = 1;
181 | this._buttonsToJoyButtons[Input.GAME_ACTION_THREE] = 2;
182 | this._buttonsToJoyButtons[Input.GAME_ACTION_FOUR] = 3;
183 | this._buttonsToJoyButtons[Input.GAME_LEFT_TRIGGER] = 4;
184 | this._buttonsToJoyButtons[Input.GAME_RIGHT_TRIGGER] = 5;
185 |
186 | this._buttonsToJoyButtons[Input.GAME_PAUSE] = 9;
187 |
188 | this._buttonsToJoyButtons[Input.MENU_LEFT] = 14;
189 | this._buttonsToJoyButtons[Input.MENU_RIGHT] = 15;
190 | this._buttonsToJoyButtons[Input.MENU_UP] = 12;
191 | this._buttonsToJoyButtons[Input.MENU_DOWN] = 13;
192 |
193 | this._buttonsToJoyButtons[Input.MENU_CONFIRM] = 0;
194 | this._buttonsToJoyButtons[Input.MENU_BACK] = 1;
195 |
196 | // default joypad alt button mappings
197 | this._buttonsToAltJoyButtons[Input.GAME_LEFT_TRIGGER] = 6;
198 | this._buttonsToAltJoyButtons[Input.GAME_RIGHT_TRIGGER] = 7;
199 |
200 | this._buttonsToAltJoyButtons[Input.GAME_PAUSE] = 16;
201 |
202 | // default joypad axis mappings
203 | this._buttonsToJoyAxes[Input.GAME_LEFT] = -1;
204 | this._buttonsToJoyAxes[Input.GAME_RIGHT] = 1;
205 | this._buttonsToJoyAxes[Input.GAME_UP] = -2;
206 | this._buttonsToJoyAxes[Input.GAME_DOWN] = 2;
207 |
208 | this._buttonsToJoyAxes[Input.MENU_LEFT] = -1;
209 | this._buttonsToJoyAxes[Input.MENU_RIGHT] = 1;
210 | this._buttonsToJoyAxes[Input.MENU_UP] = -2;
211 | this._buttonsToJoyAxes[Input.MENU_DOWN] = 2;
212 |
213 | /**
214 | * Is the left mouse button down this frame?
215 | */
216 | this._currentMouseLeft = false;
217 | /**
218 | * Was the left mouse button down last frame?
219 | */
220 | this._lastMouseLeft = false;
221 |
222 | /**
223 | * Force the left mouse button state to be down this frame.
224 | * Used for the edge case in which a mouse button is clicked up and down all in the span of one frame.
225 | */
226 | this._forceMouseLeftDown = false;
227 |
228 | /**
229 | * Is the right mouse button down this frame?
230 | */
231 | this._currentMouseRight = false;
232 |
233 | /**
234 | * Was the right mouse button down last frame?
235 | */
236 | this._lastMouseRight = false;
237 |
238 | /**
239 | * Force the right mouse button state to be down this frame.
240 | * Used for the edge case in which a mouse button is clicked up and down all in the span of one frame.
241 | */
242 | this._forceMouseRightDown = false;
243 |
244 | /**
245 | * How far from center does an axis need to be to count as pressed?
246 | */
247 | this._axisThreshold = 0.4;
248 |
249 | /**
250 | * Which keys do not cause event.preventDefault to be called on keydown events.
251 | * By default this is the escape key and all function keys
252 | */
253 | this._allowDefaultKeys = [
254 | 27,
255 | 112,
256 | 113,
257 | 114,
258 | 115,
259 | 116,
260 | 117,
261 | 118,
262 | 119,
263 | 120,
264 | 121,
265 | 122,
266 | 123,
267 | ];
268 |
269 | /**
270 | * This mode runs the engine without drawing to a canvas or playing audio.
271 | * This is useful to use the engine to generate image data.
272 | */
273 | this.dataOnlyMode = false;
274 | }
275 |
276 | /**
277 | * Do initial setup. Add event listeners.
278 | */
279 | init() {
280 | if ( this.dataOnlyMode ) {
281 | return;
282 | }
283 |
284 | window.addEventListener( 'keydown', this._keyDown.bind( this ), false );
285 | window.addEventListener( 'keyup', this._keyUp.bind( this ), false );
286 |
287 | window.onfocus = () => {
288 | this.clearInput();
289 | };
290 |
291 | window.onblur = () => {
292 | this.clearInput();
293 | };
294 |
295 | if ( this.canvas ) {
296 | this.canvas.oncontextmenu = ( e ) => {
297 | e.preventDefault();
298 | };
299 |
300 | this.canvas.addEventListener( 'pointerenter', this._pointerEnter.bind( this ), false );
301 | this.canvas.addEventListener( 'pointermove', this._pointerMove.bind( this ), false );
302 | this.canvas.addEventListener( 'pointerdown', this._pointerDown.bind( this ), false );
303 | this.canvas.addEventListener( 'pointerup', this._pointerUp.bind( this ), false );
304 | this.canvas.addEventListener( 'pointerleave', this._pointerLeave.bind( this ), false );
305 | }
306 | }
307 |
308 | /**
309 | * handle window keydown events
310 | * @param {*} e
311 | */
312 | _keyDown( e ) {
313 | // prevent default on all keys but escape and function keys
314 | if ( !this._allowDefaultKeys.includes( e.which ) ) {
315 | e.preventDefault();
316 | }
317 |
318 | if ( e.code ) {
319 | this._keysRaw[Keys.codesToKeyCodes[e.code]] = 1;
320 | }
321 | else {
322 | this._keysRaw[e.keyCode] = 1;
323 | }
324 | }
325 |
326 | /**
327 | * handle window keyup events
328 | * @param {*} e
329 | */
330 | _keyUp( e ) {
331 | if ( e.code ) {
332 | this._keysRaw[Keys.codesToKeyCodes[e.code]] = 0;
333 | }
334 | else {
335 | this._keysRaw[e.keyCode] = 0;
336 | }
337 | }
338 |
339 | /**
340 | * Handle pointerenter event
341 | */
342 | _pointerEnter() {
343 | this.mouse.isOffScreen = false;
344 | this._currentMouseLeft = false;
345 | this._currentMouseRight = false;
346 | }
347 |
348 | /**
349 | * Handle pointermove event
350 | * @param {*} e
351 | */
352 | _pointerMove( e ) {
353 | const canvasRect = this.canvas.getBoundingClientRect();
354 | this.mouse.position = {
355 | x: Math.floor( ( e.clientX - canvasRect.left ) / this.canvasScale ),
356 | y: this.screenHeight - Math.floor( ( e.clientY - canvasRect.top ) / this.canvasScale ) - 1,
357 | };
358 | }
359 |
360 | /**
361 | * Handle pointerdown event
362 | * @param {*} e
363 | */
364 | _pointerDown( e ) {
365 | if ( e.button === 0 ) {
366 | // left button
367 | this._currentMouseLeft = true;
368 | this._forceMouseLeftDown = true;
369 | }
370 | else if ( e.button === 2 ) {
371 | // right button
372 | this._currentMouseRight = true;
373 | this._forceMouseRightDown = true;
374 | }
375 | }
376 |
377 | /**
378 | * handle pointerup event
379 | * @param {*} e
380 | */
381 | _pointerUp( e ) {
382 | if ( e.button === 0 ) {
383 | // left button
384 | this._currentMouseLeft = false;
385 | }
386 | else if ( e.button === 2 ) {
387 | // right button
388 | this._currentMouseRight = false;
389 | }
390 | }
391 |
392 | /**
393 | * handle pointerleave event
394 | */
395 | _pointerLeave() {
396 | this.mouse.isOffScreen = true;
397 | }
398 |
399 | /**
400 | * clear out all of the input
401 | */
402 | clearInput() {
403 | for ( let i = 0; i < 256; i += 1 ) {
404 | this._keysRaw[i] = 0;
405 | this._lastKeys[i] = 0;
406 | this._currentKeys[i] = 0;
407 | }
408 | }
409 |
410 | /**
411 | * Update the input, should be done first thing in the game loop.
412 | * Called automatically by the Engine.
413 | */
414 | pollInput() {
415 | for ( let i = 0; i < 20; i += 1 ) {
416 | this._lastJoyButtons[i] = this._currentJoyButtons[i];
417 | this._currentJoyButtons[i] = 0;
418 | }
419 |
420 | for ( let i = 0; i < 9; i += 1 ) {
421 | this._lastJoyAxes[i] = this._currentJoyAxes[i];
422 | this._currentJoyAxes[i] = 0;
423 | }
424 |
425 | try {
426 | const gamePads = navigator.getGamepads();
427 | for ( let i = 0; i < gamePads.length; i += 1 ) {
428 | const gamePad = gamePads[i];
429 | if ( gamePad ) {
430 | for ( let b = 0; b < gamePad.buttons.length; b += 1 ) {
431 | if ( b < 20 && gamePad.buttons[b].pressed ) {
432 | this._currentJoyButtons[b] = 1;
433 | }
434 | }
435 | for ( let a = 0; a < gamePad.axes.length; a += 1 ) {
436 | if ( a < 8 ) {
437 | this._currentJoyAxes[a + 1] = gamePad.axes[a];
438 | }
439 | }
440 | }
441 | }
442 | }
443 | // eslint-disable-next-line no-empty
444 | catch ( err ) {}
445 |
446 | for ( let i = 0; i < 256; i += 1 ) {
447 | this._lastKeys[i] = this._currentKeys[i];
448 | this._currentKeys[i] = this._keysRaw[i];
449 | }
450 | // index 0 is always off
451 | this._lastKeys[0] = 0;
452 | this._currentKeys[0] = 0;
453 |
454 | this._updateButtons();
455 |
456 | this.mouse.left.pressed = this._forceMouseLeftDown ? true : this._currentMouseLeft;
457 | this.mouse.left.down = this._forceMouseLeftDown ? true : this._currentMouseLeft && !this._lastMouseLeft;
458 | this.mouse.left.up = !this._currentMouseLeft && this._lastMouseLeft;
459 |
460 | this.mouse.right.pressed = this._forceMouseRightDown ? true : this._currentMouseRight;
461 | this.mouse.right.down = this._forceMouseRightDown ? true : this._currentMouseRight && !this._lastMouseRight;
462 | this.mouse.right.up = !this._currentMouseRight && this._lastMouseRight;
463 |
464 | this._forceMouseLeftDown = false;
465 | this._forceMouseRightDown = false;
466 |
467 | this._lastMouseLeft = this._currentMouseLeft;
468 | this._lastMouseRight = this._currentMouseRight;
469 | }
470 |
471 | /**
472 | * return true if the key is currently held down
473 | * @param {number} keyCode
474 | */
475 | getKeyPressed( keyCode ) {
476 | if ( keyCode < 0 || keyCode >= 256 ) {
477 | return false;
478 | }
479 |
480 | return this._currentKeys[keyCode] > 0;
481 | }
482 |
483 | /**
484 | * return true if the key was pressed down this frame
485 | * @param {number} keyCode
486 | */
487 | getKeyDown( keyCode ) {
488 | if ( keyCode < 0 || keyCode >= 256 ) {
489 | return false;
490 | }
491 |
492 | const current = this._currentKeys[keyCode] > 0;
493 | const last = this._lastKeys[keyCode] > 0;
494 | return current && !last;
495 | }
496 |
497 | /**
498 | * return true if the key was released this frame
499 | * @param {number} keyCode
500 | */
501 | getKeyUp( keyCode ) {
502 | if ( keyCode < 0 || keyCode >= 256 ) {
503 | return false;
504 | }
505 |
506 | const current = this._currentKeys[keyCode] > 0;
507 | const last = this._lastKeys[keyCode] > 0;
508 | return !current && last;
509 | }
510 |
511 | /**
512 | * return true if the joypad button is currently held down
513 | * This is the joypad from the Gamepad API, and generally should only
514 | * be used when detecting inputs to remap controls. For normal
515 | * gameplay use Input.getButtonPressed
516 | * @param {number} buttonIndex
517 | */
518 | getJoyButtonPressed( buttonIndex ) {
519 | if ( buttonIndex < 0 || buttonIndex >= 20 ) {
520 | return false;
521 | }
522 |
523 | return this._currentJoyButtons[buttonIndex] > 0;
524 | }
525 |
526 | /**
527 | * return true if the joypad button was pressed down this frame.
528 | * This is the joypad from the Gamepad API, and generally should only
529 | * be used when detecting inputs to remap controls. For normal
530 | * gameplay use Input.getButtonDown
531 | * @param {number} buttonIndex
532 | */
533 | getJoyButtonDown( buttonIndex ) {
534 | if ( buttonIndex < 0 || buttonIndex >= 20 ) {
535 | return false;
536 | }
537 |
538 | const current = this._currentJoyButtons[buttonIndex] > 0;
539 | const last = this._lastJoyButtons[buttonIndex] > 0;
540 | return current && !last;
541 | }
542 |
543 | /**
544 | * return true if the joypad button was released this frame.
545 | * This is the joypad from the Gamepad API, and generally should only
546 | * be used when detecting inputs to remap controls. For normal
547 | * gameplay use Input.getButtonUp
548 | * @param {number} buttonIndex
549 | */
550 | getJoyButtonUp( buttonIndex ) {
551 | if ( buttonIndex < 0 || buttonIndex >= 20 ) {
552 | return false;
553 | }
554 |
555 | const current = this._currentJoyButtons[buttonIndex] > 0;
556 | const last = this._lastJoyButtons[buttonIndex] > 0;
557 | return !current && last;
558 | }
559 |
560 | /**
561 | * Helper function for joypad axes
562 | * @param {*} axisIndex
563 | * @param {*} axisArray
564 | */
565 | _axisFromArrayIsPressed( axisIndex, axisArray ) {
566 | if ( axisIndex === 0 || axisIndex > 8 || axisIndex < -8 ) {
567 | return 0;
568 | }
569 |
570 | const isNegative = axisIndex < 0;
571 | const value = axisArray[Math.abs( axisIndex )];
572 |
573 | return isNegative ? value <= -this._axisThreshold : value >= this._axisThreshold;
574 | }
575 |
576 | /**
577 | * return true if the joypad axis is currently held down
578 | * This is the joypad from the Gamepad API, and generally should only
579 | * be used when detecting inputs to remap controls. For normal
580 | * gameplay use Input.getButtonPressed
581 | * @param {number} axisIndex
582 | */
583 | getJoyAxisPressed( axisIndex ) {
584 | return this._axisFromArrayIsPressed( axisIndex, this._currentJoyAxes );
585 | }
586 |
587 | /**
588 | * return true if the joypad axis was pressed down this frame
589 | * This is the joypad from the Gamepad API, and generally should only
590 | * be used when detecting inputs to remap controls. For normal
591 | * gameplay use Input.getButtonDown
592 | * @param {number} axisIndex
593 | */
594 | getJoyAxisDown( axisIndex ) {
595 | const current = this.getJoyAxisPressed( axisIndex );
596 | const last = this._axisFromArrayIsPressed( axisIndex, this._lastJoyAxes );
597 |
598 | return current && !last;
599 | }
600 |
601 | /**
602 | * return true if the joypad axis was released this frame
603 | * This is the joypad from the Gamepad API, and generally should only
604 | * be used when detecting inputs to remap controls. For normal
605 | * gameplay use Input.getButtonUp
606 | * @param {number} axisIndex
607 | */
608 | getJoyAxisUp( axisIndex ) {
609 | const current = this.getJoyAxisPressed( axisIndex );
610 | const last = this._axisFromArrayIsPressed( axisIndex, this._lastJoyAxes );
611 |
612 | return !current && last;
613 | }
614 |
615 | /**
616 | * return true if the standard game button is currently held down
617 | * @param {number} buttonCode
618 | */
619 | getButtonPressed( buttonCode ) {
620 | const key = this._buttonsToKeys[buttonCode];
621 | const altKey = this._buttonsToAltKeys[buttonCode];
622 | const joyButton = this._buttonsToJoyButtons[buttonCode];
623 | const altJoyButton = this._buttonsToAltJoyButtons[buttonCode];
624 | const joyAxis = this._buttonsToJoyAxes[buttonCode];
625 |
626 | const keyPressed = this._currentKeys[key];
627 | const altKeyPressed = this._currentKeys[altKey];
628 | const joyButtonPressed = this._currentJoyButtons[joyButton];
629 | const altJoyButtonPressed = this._currentJoyButtons[altJoyButton];
630 | const joyAxisPressed = this._axisFromArrayIsPressed( joyAxis, this._currentJoyAxes );
631 | return keyPressed || altKeyPressed || joyButtonPressed || altJoyButtonPressed || joyAxisPressed;
632 | }
633 |
634 | /**
635 | * return true if the standard game button was pressed down this frame
636 | * @param {number} buttonCode
637 | */
638 | getButtonDown( buttonCode ) {
639 | const currentPressed = this.getButtonPressed( buttonCode );
640 |
641 | if ( currentPressed ) {
642 | const key = this._buttonsToKeys[buttonCode];
643 | const altKey = this._buttonsToAltKeys[buttonCode];
644 | const joyButton = this._buttonsToJoyButtons[buttonCode];
645 | const altJoyButton = this._buttonsToAltJoyButtons[buttonCode];
646 | const joyAxis = this._buttonsToJoyAxes[buttonCode];
647 |
648 | const lastKeyPressed = this._lastKeys[key];
649 | const lastAltKeyPressed = this._lastKeys[altKey];
650 | const lastJoyButtonPressed = this._lastJoyButtons[joyButton];
651 | const lastAltJoyButtonPressed = this._lastJoyButtons[altJoyButton];
652 | const lastJoyAxisPressed = this._axisFromArrayIsPressed( joyAxis, this._lastJoyAxes );
653 |
654 | if (
655 | !lastKeyPressed
656 | && !lastAltKeyPressed
657 | && !lastJoyButtonPressed
658 | && !lastAltJoyButtonPressed
659 | && !lastJoyAxisPressed
660 | ) {
661 | return true;
662 | }
663 | }
664 |
665 | return false;
666 | }
667 |
668 | /**
669 | * return true if the standard game button was released this frame
670 | * @param {number} buttonCode
671 | */
672 | getButtonUp( buttonCode ) {
673 | const currentPressed = this.getButtonPressed( buttonCode );
674 |
675 | if ( !currentPressed ) {
676 | const key = this._buttonsToKeys[buttonCode];
677 | const altKey = this._buttonsToAltKeys[buttonCode];
678 | const joyButton = this._buttonsToJoyButtons[buttonCode];
679 | const altJoyButton = this._buttonsToAltJoyButtons[buttonCode];
680 | const joyAxis = this._buttonsToJoyAxes[buttonCode];
681 |
682 | const lastKeyPressed = this._lastKeys[key];
683 | const lastAltKeyPressed = this._lastKeys[altKey];
684 | const lastJoyButtonPressed = this._lastJoyButtons[joyButton];
685 | const lastAltJoyButtonPressed = this._lastJoyButtons[altJoyButton];
686 | const lastJoyAxisPressed = this._axisFromArrayIsPressed( joyAxis, this._lastJoyAxes );
687 |
688 | if (
689 | lastKeyPressed
690 | || lastAltKeyPressed
691 | || lastJoyButtonPressed
692 | || lastAltJoyButtonPressed
693 | || lastJoyAxisPressed
694 | ) {
695 | return true;
696 | }
697 | }
698 |
699 | return false;
700 | }
701 |
702 | /**
703 | * update standard game button states.
704 | */
705 | _updateButtons() {
706 | this._updateButton( 'left', Input.GAME_LEFT );
707 | this._updateButton( 'right', Input.GAME_RIGHT );
708 | this._updateButton( 'up', Input.GAME_UP );
709 | this._updateButton( 'down', Input.GAME_DOWN );
710 |
711 | this._updateButton( 'action1', Input.GAME_ACTION_ONE );
712 | this._updateButton( 'action2', Input.GAME_ACTION_TWO );
713 | this._updateButton( 'action3', Input.GAME_ACTION_THREE );
714 | this._updateButton( 'action4', Input.GAME_ACTION_FOUR );
715 | this._updateButton( 'leftTrigger', Input.GAME_LEFT_TRIGGER );
716 | this._updateButton( 'rightTrigger', Input.GAME_RIGHT_TRIGGER );
717 |
718 | this._updateButton( 'pause', Input.GAME_PAUSE );
719 |
720 | this._updateButton( 'menuLeft', Input.MENU_LEFT );
721 | this._updateButton( 'menuRight', Input.MENU_RIGHT );
722 | this._updateButton( 'menuUp', Input.MENU_UP );
723 | this._updateButton( 'menuDown', Input.MENU_DOWN );
724 |
725 | this._updateButton( 'menuConfirm', Input.MENU_CONFIRM );
726 | this._updateButton( 'menuBack', Input.MENU_BACK );
727 | }
728 |
729 | /**
730 | * Update the state for a standard game button.
731 | * @param {*} name
732 | * @param {*} index
733 | */
734 | _updateButton( name, index ) {
735 | const pressed = this.getButtonPressed( index );
736 | const down = this.getButtonDown( index );
737 | const up = this.getButtonUp( index );
738 |
739 | this[name] = { pressed, down, up };
740 | }
741 | }
742 |
743 | Input.GAME_LEFT = 0;
744 | Input.GAME_RIGHT = 1;
745 | Input.GAME_UP = 2;
746 | Input.GAME_DOWN = 3;
747 | Input.GAME_ACTION_ONE = 4;
748 | Input.GAME_ACTION_TWO = 5;
749 | Input.GAME_ACTION_THREE = 6;
750 | Input.GAME_ACTION_FOUR = 7;
751 | Input.GAME_PAUSE = 8;
752 | Input.GAME_LEFT_TRIGGER = 9;
753 | Input.GAME_RIGHT_TRIGGER = 10;
754 |
755 | Input.MENU_LEFT = 11;
756 | Input.MENU_RIGHT = 12;
757 | Input.MENU_UP = 13;
758 | Input.MENU_DOWN = 14;
759 | Input.MENU_CONFIRM = 15;
760 | Input.MENU_BACK = 16;
761 |
762 | export default Input;
763 |
--------------------------------------------------------------------------------
/src/FontData/standard.font.json:
--------------------------------------------------------------------------------
1 | {"name":"standard","tileSize":16,"width":16,"height":16,"originX":2,"originY":4,"standardWidth":5,"letterSpacing":1,"charData":{"33":{"name":"!","width":3},"34":{"name":"double quote","width":4},"37":{"name":"percent","width":7},"38":{"name":"and","width":7},"39":{"name":"single quote","width":1},"40":{"name":"(","width":3},"41":{"name":")","width":3},"44":{"name":",","width":2},"46":{"name":".","width":1},"47":{"name":"f slash","width":7},"49":{"name":"1","width":3},"58":{"name":":","width":1},"59":{"name":";","width":2},"60":{"name":"<","width":4},"62":{"name":">","width":4},"64":{"name":"@","width":7},"91":{"name":"[","width":3},"92":{"name":"backslash","width":7},"93":{"name":"]","width":3},"96":{"name":"grave","width":2},"105":{"name":"i","width":1},"107":{"name":"k","width":4},"108":{"name":"l","width":1},"123":{"name":"{","width":3},"124":{"name":"|","width":1},"125":{"name":"}","width":3},"161":{"name":"upside down !","width":3},"164":{"name":"currency","width":6},"165":{"name":"yen","width":7},"166":{"name":"broken bar","width":1},"167":{"name":"section","width":6},"169":{"name":"copyright","width":7},"170":{"name":"f ordinal","width":4},"171":{"name":"<<","width":6},"172":{"name":"not","width":6},"174":{"name":"(r)","width":8},"176":{"name":"degree","width":4},"178":{"name":"^2","width":3},"179":{"name":"^3","width":3},"180":{"name":"acute","width":2},"182":{"name":"pilcrow","width":3},"183":{"name":"middle dot","width":1},"185":{"name":"^1","width":4},"186":{"name":"m ordinal","width":4},"187":{"name":">>","width":6},"188":{"name":"1/4","width":7},"189":{"name":"1/2","width":7},"190":{"name":"3/4","width":7},"236":{"name":"i","width":3},"237":{"name":"i","width":3},"238":{"name":"i","width":3},"239":{"name":"i","width":3},"8364":{"name":"euro","remap":1,"width":6}},"data":[307,0,5,2,10,0,2,2,3,1,2,2,8,0,2,2,1,1,3,2,1,1,1,2,8,0,1,2,4,1,3,2,8,0,2,2,1,1,4,2,9,0,1,2,4,1,3,2,8,0,2,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,8058,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,12,0,2,2,1,1,2,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,5,2,219,0,6,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,6,2,107,0,5,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,5,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,5,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,5,2,140,0,3,2,11,0,3,2,1,1,2,2,10,0,1,2,4,1,2,2,9,0,3,2,1,1,1,2,1,1,1,2,10,0,2,2,1,1,1,2,1,1,1,2,9,0,2,2,3,1,2,2,9,0,1,2,1,1,1,2,1,1,2,2,10,0,1,2,1,1,1,2,1,1,3,2,9,0,2,2,4,1,1,2,10,0,2,2,1,1,3,2,11,0,3,2,107,0,3,2,2,0,3,2,8,0,1,2,1,1,4,2,1,1,2,2,7,0,2,2,1,1,2,2,1,1,1,2,1,1,1,2,8,0,2,2,1,1,2,2,1,1,2,2,8,0,3,2,1,1,3,2,8,0,2,2,1,1,2,2,1,1,2,2,8,0,1,2,1,1,1,2,1,1,2,2,1,1,2,2,7,0,2,2,1,1,4,2,1,1,1,2,8,0,3,2,2,0,3,2,120,0,8,2,7,0,2,2,4,1,1,2,1,1,1,2,7,0,1,2,1,1,4,2,1,1,2,2,7,0,1,2,1,1,3,2,1,1,1,2,1,1,1,2,7,0,1,2,1,1,2,2,2,1,3,2,7,0,2,2,2,1,2,2,1,1,1,2,9,0,2,2,1,1,2,2,1,1,1,2,10,0,2,2,2,1,2,2,11,0,4,2,217,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,111,0,3,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,123,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,189,0,6,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,2,2,2,1,2,2,10,0,2,2,2,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,6,2,108,0,3,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,3,2,139,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,236,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,185,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,221,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,120,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,5,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,12,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,2,2,1,1,1,2,12,0,1,2,2,1,1,2,12,0,2,2,1,1,1,2,13,0,3,2,124,0,7,2,9,0,1,2,5,1,1,2,9,0,2,2,1,1,4,2,10,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,9,0,5,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,123,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,5,2,1,1,1,2,10,0,1,2,3,1,2,2,9,0,5,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,126,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,9,0,5,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,6,2,10,0,1,2,4,1,2,2,9,0,5,2,1,1,1,2,9,0,5,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,122,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,124,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,9,0,5,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,7,2,122,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,123,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,5,2,1,1,1,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,138,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,157,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,175,0,3,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,138,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,169,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,127,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,2,2,12,0,1,2,2,1,2,2,9,0,5,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,124,0,7,2,8,0,2,2,5,1,1,2,7,0,2,2,1,1,6,2,7,0,1,2,1,1,1,2,2,1,1,2,1,1,2,2,7,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,1,1,1,2,7,0,1,2,1,1,1,2,3,1,1,2,1,1,1,2,7,0,2,2,1,1,4,2,1,1,1,2,8,0,2,2,4,1,2,2,9,0,6,2,120,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,12,0,3,2,123,0,6,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,123,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,3,2,9,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,6,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,122,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,121,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,122,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,3,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,7,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,121,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,121,0,3,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,2,2,1,1,2,2,9,0,1,2,1,1,1,2,1,1,2,2,10,0,1,2,2,1,2,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,1,2,1,1,2,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,125,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,2,1,1,2,2,1,1,2,9,0,7,2,121,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,3,2,122,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,4,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,123,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,2,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,122,0,6,2,10,0,1,2,4,1,2,2,9,0,5,2,1,1,1,2,10,0,4,2,1,1,1,2,9,0,2,2,3,1,2,2,9,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,2,2,4,1,1,2,10,0,6,2,123,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,122,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,123,0,3,2,12,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,7,2,9,0,1,2,2,1,1,2,2,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,123,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,121,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,2,2,9,0,5,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,7,2,121,0,4,2,12,0,1,2,2,1,1,2,12,0,1,2,1,1,2,2,12,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,1,2,2,1,1,2,12,0,4,2,130,0,3,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,125,0,4,2,12,0,1,2,2,1,1,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,2,2,1,1,1,2,12,0,1,2,2,1,1,2,12,0,4,2,188,0,3,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,12,0,3,2,107,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,314,0,3,2,12,0,2,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,1,2,1,1,1,2,13,0,3,2,110,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,154,0,6,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,126,0,6,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,1,2,13,0,1,2,1,1,5,2,9,0,2,2,4,1,1,2,10,0,6,2,154,0,6,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,4,1,1,2,10,0,4,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,122,0,5,2,10,0,2,2,3,1,1,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,154,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,3,2,11,0,1,2,3,1,1,2,11,0,1,2,1,1,5,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,91,0,5,2,11,0,1,2,3,1,2,2,10,0,4,2,1,1,1,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,154,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,125,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,94,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,121,0,6,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,1,2,1,1,2,2,10,0,1,2,2,1,2,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,125,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,125,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,154,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,155,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,4,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,126,0,4,2,12,0,1,2,2,1,1,2,9,0,4,2,1,1,2,2,8,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,154,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,1,2,2,1,4,2,9,0,1,2,1,1,1,2,3,1,1,2,9,0,7,2,153,0,6,2,10,0,1,2,4,1,2,2,9,0,5,2,1,1,1,2,9,0,2,2,3,1,2,2,9,0,1,2,1,1,5,2,9,0,2,2,4,1,1,2,10,0,6,2,155,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,3,2,124,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,155,0,3,2,12,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,154,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,153,0,3,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,3,2,122,0,5,2,11,0,1,2,3,1,2,2,10,0,4,2,1,1,1,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,153,0,7,2,9,0,1,2,5,1,1,2,9,0,2,2,1,1,4,2,10,0,2,2,1,1,2,2,10,0,4,2,1,1,2,2,9,0,1,2,5,1,1,2,9,0,7,2,139,0,3,2,12,0,2,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,1,2,1,1,1,2,12,0,2,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,91,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,93,0,3,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,2,2,12,0,2,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,1,2,1,1,1,2,12,0,2,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,3,2,157,0,6,2,10,0,1,2,1,1,1,2,2,1,2,2,9,0,2,2,2,1,1,2,1,1,1,2,10,0,6,2,8857,0,5,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,126,0,3,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,1,2,1,1,3,2,9,0,1,2,1,1,1,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,3,2,139,0,7,2,9,0,1,2,5,1,1,2,9,0,2,2,1,1,4,2,9,0,2,2,1,1,2,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,5,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,3,2,3,0,3,2,7,0,1,2,1,1,5,2,1,1,1,2,7,0,2,2,5,1,2,2,8,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,8,0,2,2,5,1,2,2,7,0,1,2,1,1,5,2,1,1,1,2,7,0,3,2,3,0,3,2,106,0,3,2,12,0,2,2,1,1,2,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,8,0,2,2,1,1,3,2,1,1,2,2,7,0,1,2,1,1,2,2,1,0,2,2,1,1,1,2,7,0,3,2,3,0,3,2,103,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,3,2,110,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,5,2,1,1,1,2,9,0,2,2,4,1,2,2,8,0,1,2,1,1,4,2,1,1,1,2,8,0,1,2,1,1,4,2,1,1,1,2,8,0,2,2,4,1,2,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,218,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,92,0,5,2,10,0,2,2,3,1,2,2,8,0,2,2,1,1,3,2,1,1,2,2,7,0,1,2,1,1,1,2,3,1,1,2,1,1,1,2,7,0,1,2,1,1,1,2,1,1,3,2,1,1,1,2,7,0,1,2,1,1,1,2,3,1,1,2,1,1,1,2,7,0,2,2,1,1,3,2,1,1,2,2,8,0,2,2,3,1,2,2,10,0,5,2,169,0,6,2,10,0,1,2,4,1,1,2,10,0,6,2,10,0,2,2,1,1,1,2,1,1,1,2,10,0,1,2,1,1,1,2,2,1,1,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,2,2,2,1,2,2,11,0,4,2,109,0,6,2,9,0,2,2,1,1,2,2,1,1,1,2,8,0,2,2,1,1,2,2,1,1,2,2,8,0,1,2,1,1,2,2,1,1,2,2,9,0,2,2,1,1,2,2,1,1,2,2,9,0,2,2,1,1,2,2,1,1,1,2,10,0,6,2,173,0,3,2,13,0,1,2,1,1,1,2,8,0,6,2,1,1,1,2,8,0,1,2,6,1,1,2,8,0,8,2,410,0,6,2,9,0,2,2,4,1,2,2,7,0,2,2,2,1,2,2,2,1,2,2,6,0,1,2,1,1,1,2,1,1,2,2,1,1,1,2,1,1,1,2,6,0,1,2,1,1,1,2,3,1,2,2,1,1,1,2,6,0,1,2,1,1,1,2,1,1,2,2,1,1,1,2,1,1,1,2,6,0,1,2,1,1,1,2,4,1,1,2,1,1,1,2,6,0,2,2,1,1,4,2,1,1,2,2,7,0,2,2,4,1,2,2,9,0,6,2,200,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,186,0,4,2,11,0,2,2,2,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,2,2,2,1,2,2,11,0,4,2,107,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,11,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,3,2,187,0,5,2,11,0,1,2,3,1,1,2,11,0,1,2,2,1,2,2,11,0,3,2,1,1,1,2,11,0,1,2,2,1,2,2,11,0,4,2,172,0,5,2,11,0,1,2,3,1,1,2,11,0,2,2,2,1,1,2,11,0,3,2,1,1,1,2,11,0,1,2,3,1,1,2,11,0,5,2,187,0,3,2,13,0,1,2,1,1,2,2,12,0,1,2,2,1,1,2,12,0,2,2,1,1,1,2,13,0,3,2,76,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,5,2,9,0,1,2,3,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,3,2,1,0,3,2,153,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,1,2,1,1,1,2,1,1,1,2,10,0,2,2,1,1,1,2,1,1,1,2,10,0,1,2,2,1,1,2,1,1,1,2,10,0,1,2,2,1,1,2,1,1,1,2,10,0,1,2,2,1,1,2,1,1,1,2,10,0,2,2,3,1,1,2,11,0,5,2,139,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,142,0,5,2,11,0,1,2,3,1,1,2,11,0,3,2,1,1,1,2,12,0,1,2,1,1,2,2,12,0,3,2,283,0,5,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,2,2,11,0,2,2,1,1,1,2,12,0,1,2,2,1,1,2,12,0,4,2,156,0,6,2,10,0,1,2,4,1,1,2,10,0,6,2,10,0,2,2,2,1,2,2,10,0,1,2,1,1,2,0,1,1,1,2,10,0,1,2,1,1,2,0,1,1,1,2,10,0,2,2,2,1,2,2,11,0,4,2,107,0,6,2,10,0,1,2,1,1,2,2,1,1,2,2,9,0,2,2,1,1,2,2,1,1,2,2,9,0,2,2,1,1,2,2,1,1,1,2,8,0,2,2,1,1,2,2,1,1,2,2,8,0,1,2,1,1,2,2,1,1,2,2,9,0,6,2,144,0,3,2,11,0,3,2,1,1,1,2,8,0,4,2,3,1,1,2,8,0,1,2,1,1,2,2,1,1,1,2,1,1,1,2,8,0,2,2,1,1,5,2,8,0,3,2,1,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,112,0,6,2,10,0,1,2,4,1,1,2,7,0,6,2,1,1,2,2,7,0,1,2,1,1,2,2,3,1,1,2,8,0,2,2,1,1,5,2,8,0,3,2,1,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,114,0,3,2,11,0,3,2,1,1,1,2,8,0,4,2,3,1,1,2,8,0,1,2,1,1,2,2,1,1,1,2,1,1,1,2,8,0,2,2,1,1,5,2,7,0,4,2,1,1,2,2,9,0,1,2,3,1,1,2,1,1,1,2,9,0,2,2,2,1,3,2,9,0,1,2,3,1,1,2,11,0,5,2,108,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,5,2,9,0,2,2,2,1,1,2,12,0,2,2,1,1,1,2,13,0,3,2,13,0,1,2,1,1,1,2,13,0,3,2,123,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,12,0,4,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,60,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,4,2,12,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,58,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,75,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,5,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,73,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,11,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,90,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,12,0,3,2,12,0,2,2,1,1,2,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,59,0,3,2,1,0,6,2,6,0,1,2,1,1,1,2,1,0,1,2,4,1,1,2,6,0,1,2,1,1,3,2,1,1,4,2,6,0,1,2,5,1,3,2,7,0,2,2,1,1,2,2,3,1,1,2,8,0,2,2,1,1,1,2,1,1,3,2,9,0,2,2,2,1,4,2,9,0,2,2,4,1,1,2,10,0,6,2,71,0,5,2,11,0,1,2,3,1,1,2,11,0,3,2,1,1,1,2,11,0,2,2,1,1,2,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,3,2,9,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,122,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,11,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,60,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,58,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,75,0,7,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,4,2,10,0,1,2,4,1,1,2,10,0,1,2,1,1,4,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,90,0,7,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,11,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,60,0,7,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,58,0,7,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,75,0,7,2,9,0,1,2,5,1,1,2,9,0,3,2,1,1,3,2,11,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,11,0,3,2,1,1,3,2,9,0,1,2,5,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,90,0,6,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,8,0,2,2,1,1,3,2,1,1,1,2,8,0,1,2,3,1,2,2,1,1,1,2,8,0,2,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,122,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,74,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,61,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,59,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,76,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,74,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,90,0,3,2,1,0,3,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,3,2,1,0,3,2,136,0,3,2,13,0,1,2,1,1,5,2,9,0,2,2,4,1,2,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,2,2,4,1,2,2,9,0,5,2,1,1,1,2,13,0,3,2,105,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,11,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,61,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,59,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,76,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,92,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,2,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,58,0,5,2,11,0,1,2,3,1,1,2,11,0,2,2,1,1,3,2,11,0,1,2,3,1,2,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,1,1,2,2,1,1,1,2,10,0,1,2,3,1,2,2,9,0,2,2,1,1,3,2,10,0,1,2,3,1,1,2,11,0,5,2,91,0,6,2,10,0,1,2,1,1,1,2,2,1,2,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,2,2,1,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,6,2,91,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,93,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,91,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,108,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,106,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,123,0,6,2,9,0,2,2,2,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,92,0,8,2,7,0,2,2,1,1,1,2,4,1,1,2,7,0,1,2,1,1,1,2,2,1,5,2,6,0,1,2,1,1,2,2,5,1,1,2,6,0,1,2,1,1,2,2,1,1,3,2,1,1,1,2,6,0,2,2,6,1,2,2,7,0,8,2,104,0,5,2,11,0,1,2,3,1,1,2,11,0,3,2,1,1,1,2,11,0,2,2,1,1,3,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,5,2,9,0,1,2,1,1,1,2,13,0,1,2,1,1,5,2,9,0,2,2,4,1,1,2,10,0,6,2,154,0,5,2,10,0,2,2,3,1,1,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,93,0,5,2,10,0,2,2,3,1,1,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,91,0,5,2,10,0,2,2,3,1,1,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,108,0,5,2,10,0,2,2,3,1,1,2,10,0,1,2,1,1,5,2,9,0,1,2,5,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,123,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,4,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,94,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,4,2,12,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,92,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,109,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,1,2,12,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,124,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,4,1,1,2,10,0,3,2,1,1,2,2,9,0,2,2,2,1,2,2,10,0,1,2,2,1,1,2,1,1,1,2,10,0,6,2,106,0,3,2,1,0,3,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,106,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,12,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,93,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,91,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,108,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,2,2,10,0,2,2,1,1,1,2,1,1,1,2,11,0,5,2,106,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,2,2,3,1,2,2,10,0,5,2,11,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,124,0,3,2,13,0,1,2,1,1,1,2,11,0,7,2,9,0,1,2,5,1,1,2,9,0,7,2,11,0,1,2,1,1,1,2,13,0,3,2,138,0,3,2,13,0,1,2,1,1,5,2,9,0,2,2,4,1,2,2,9,0,1,2,2,1,2,2,1,1,1,2,9,0,1,2,1,1,1,2,1,1,1,2,1,1,1,2,9,0,1,2,1,1,2,2,2,1,1,2,9,0,2,2,4,1,2,2,9,0,5,2,1,1,1,2,13,0,3,2,137,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,11,0,2,2,1,1,1,2,11,0,2,2,1,1,2,2,11,0,1,2,1,1,2,2,12,0,3,2,93,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,91,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,2,2,1,1,2,2,12,0,3,2,108,0,5,2,10,0,2,2,3,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,91,0,5,2,11,0,1,2,3,1,2,2,10,0,4,2,1,1,1,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,2,2,12,0,2,2,1,1,2,2,12,0,2,2,1,1,1,2,13,0,3,2,58,0,3,2,13,0,1,2,1,1,1,2,13,0,1,2,1,1,4,2,10,0,1,2,4,1,2,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,4,1,2,2,9,0,1,2,1,1,4,2,10,0,1,2,1,1,1,2,13,0,3,2,94,0,5,2,11,0,1,2,3,1,2,2,10,0,4,2,1,1,1,2,9,0,2,2,4,1,1,2,9,0,1,2,1,1,3,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,1,2,1,1,1,2,1,0,1,2,1,1,1,2,9,0,7,2,10,0,1,2,1,1,1,2,1,1,1,2,11,0,5,2,73,0]}
--------------------------------------------------------------------------------