├── arrasio ├── logs │ └── info.txt ├── extra │ ├── Neph.png │ ├── pics.png │ ├── Banner.png │ ├── Untitled.png │ ├── favicon2.png │ ├── favicon 1.png │ ├── palette3 Dark.png │ ├── palette7 Snow.png │ ├── palette1 Light.png │ ├── palette5 Forest.png │ ├── palette8 Space.png │ ├── palette9 Nebula.png │ ├── palette12 Badlands.png │ ├── palette2 Classic.png │ ├── palette4 Natural.png │ ├── palette6 Midnight.png │ ├── palette11 Coral Reef.png │ ├── palette10 Oversaturated.png │ ├── config.json │ ├── server setup guide.txt │ └── changelog_build_0_0_1_4.txt ├── bin │ └── info.txt ├── src │ ├── client │ │ ├── favicons │ │ │ ├── favicon.ico │ │ │ ├── apple-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-96x96.png │ │ │ ├── ms-icon-70x70.png │ │ │ ├── apple-icon-57x57.png │ │ │ ├── apple-icon-60x60.png │ │ │ ├── apple-icon-72x72.png │ │ │ ├── apple-icon-76x76.png │ │ │ ├── ms-icon-144x144.png │ │ │ ├── ms-icon-150x150.png │ │ │ ├── ms-icon-310x310.png │ │ │ ├── android-icon-36x36.png │ │ │ ├── android-icon-48x48.png │ │ │ ├── android-icon-72x72.png │ │ │ ├── android-icon-96x96.png │ │ │ ├── apple-icon-114x114.png │ │ │ ├── apple-icon-120x120.png │ │ │ ├── apple-icon-144x144.png │ │ │ ├── apple-icon-152x152.png │ │ │ ├── apple-icon-180x180.png │ │ │ ├── android-icon-144x144.png │ │ │ ├── android-icon-192x192.png │ │ │ ├── apple-icon-precomposed.png │ │ │ ├── browserconfig.xml │ │ │ └── manifest.json │ │ ├── api │ │ │ └── hi.html │ │ ├── js │ │ │ ├── lib │ │ │ │ ├── global.js │ │ │ │ ├── color.js │ │ │ │ ├── util.js │ │ │ │ └── fasttalk.js │ │ │ └── canvas.js │ │ ├── css │ │ │ └── main.css │ │ ├── json │ │ │ └── color.json │ │ └── index.html │ └── server │ │ ├── lib │ │ ├── random.js │ │ ├── util.js │ │ ├── fasttalk.js │ │ └── hshg.js │ │ └── newserver.js ├── app │ └── info.txt ├── app.json ├── webpack.config.js ├── package.json ├── config.json └── gulpfile.js ├── README.md └── LICENSE /arrasio/logs/info.txt: -------------------------------------------------------------------------------- 1 | logs write here -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # arrasio 2 | A fan-made sequel to diep.io 3 | -------------------------------------------------------------------------------- /arrasio/extra/Neph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/Neph.png -------------------------------------------------------------------------------- /arrasio/extra/pics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/pics.png -------------------------------------------------------------------------------- /arrasio/extra/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/Banner.png -------------------------------------------------------------------------------- /arrasio/extra/Untitled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/Untitled.png -------------------------------------------------------------------------------- /arrasio/extra/favicon2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/favicon2.png -------------------------------------------------------------------------------- /arrasio/extra/favicon 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/favicon 1.png -------------------------------------------------------------------------------- /arrasio/bin/info.txt: -------------------------------------------------------------------------------- 1 | this is where gulp will copy your files to when run, so point the server to serve from here -------------------------------------------------------------------------------- /arrasio/extra/palette3 Dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette3 Dark.png -------------------------------------------------------------------------------- /arrasio/extra/palette7 Snow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette7 Snow.png -------------------------------------------------------------------------------- /arrasio/extra/palette1 Light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette1 Light.png -------------------------------------------------------------------------------- /arrasio/extra/palette5 Forest.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette5 Forest.png -------------------------------------------------------------------------------- /arrasio/extra/palette8 Space.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette8 Space.png -------------------------------------------------------------------------------- /arrasio/extra/palette9 Nebula.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette9 Nebula.png -------------------------------------------------------------------------------- /arrasio/extra/palette12 Badlands.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette12 Badlands.png -------------------------------------------------------------------------------- /arrasio/extra/palette2 Classic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette2 Classic.png -------------------------------------------------------------------------------- /arrasio/extra/palette4 Natural.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette4 Natural.png -------------------------------------------------------------------------------- /arrasio/extra/palette6 Midnight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette6 Midnight.png -------------------------------------------------------------------------------- /arrasio/extra/palette11 Coral Reef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette11 Coral Reef.png -------------------------------------------------------------------------------- /arrasio/extra/palette10 Oversaturated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/extra/palette10 Oversaturated.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/favicon.ico -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/favicon-16x16.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/favicon-32x32.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/favicon-96x96.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/ms-icon-70x70.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-57x57.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-60x60.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-72x72.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-76x76.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/ms-icon-144x144.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/ms-icon-150x150.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/ms-icon-310x310.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-36x36.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-48x48.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-72x72.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-96x96.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-114x114.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-120x120.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-144x144.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-152x152.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-180x180.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-144x144.png -------------------------------------------------------------------------------- /arrasio/src/client/favicons/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/android-icon-192x192.png -------------------------------------------------------------------------------- /arrasio/app/info.txt: -------------------------------------------------------------------------------- 1 | i copied over /src and the contents of / to here, then i compressed it to a tar and uploaded it and extracted it on my servers to push updates -------------------------------------------------------------------------------- /arrasio/src/client/favicons/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nepphhh/arrasio/HEAD/arrasio/src/client/favicons/apple-icon-precomposed.png -------------------------------------------------------------------------------- /arrasio/src/client/api/hi.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | thanks for joining me today 6 | 7 | 8 | hi there good to see you! 9 | -------------------------------------------------------------------------------- /arrasio/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arras-io", 3 | "description": "A fanmade sequel to diep.io", 4 | "scripts": { 5 | "build": "gulp build", 6 | "start": "gulp run", 7 | "watch": "gulp watch", 8 | "test": "gulp test" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /arrasio/src/client/favicons/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /arrasio/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: "./src/client/js/app.js", 3 | output: { 4 | path: require("path").resolve("./src/bin/client/js"), 5 | library: "app", 6 | filename: "app.js" 7 | }, 8 | module: { 9 | loaders: [ 10 | { 11 | test: /\.jsx?$/, 12 | exclude: /(node_modules|bower_components)/, 13 | loader: 'babel' 14 | } 15 | ] 16 | } 17 | }; 18 | -------------------------------------------------------------------------------- /arrasio/src/client/favicons/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /arrasio/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arras-io", 3 | "version": "1.0.0", 4 | "description": "A fanmade sequel to diep.io", 5 | "main": "server/server.js", 6 | "scripts": { 7 | "start": "gulp run" 8 | }, 9 | "author": "Anthony Hengst", 10 | "license": "GNU GPL3", 11 | "contributors": [ 12 | "nepphhhh " 13 | ], 14 | "dependencies": { 15 | "babel-core": "^6.24.1", 16 | "babel-loader": "^6.4.1", 17 | "babel-preset-es2015": "^6.24.1", 18 | "chai": "^3.5.0", 19 | "express": "^4.13.4", 20 | "fs": "^0.0.2", 21 | "google-closure-library": "^20170910.0.0", 22 | "gulp": "^3.9.1", 23 | "gulp-babel": "^6.1.2", 24 | "gulp-jshint": "^2.0.1", 25 | "gulp-mocha": "^2.2.0", 26 | "gulp-nodemon": "^2.0.7", 27 | "gulp-rev": "^8.1.1", 28 | "gulp-rev-dist-clean": "^1.0.4", 29 | "gulp-rev-replace": "^0.4.3", 30 | "gulp-todo": "^4.1.0", 31 | "gulp-uglify": "^1.5.4", 32 | "gulp-util": "^3.0.7", 33 | "jshint": "^2.9.2", 34 | "keypress": "^0.2.1", 35 | "mocha": "^2.5.3", 36 | "mysql": "^2.5.5", 37 | "nodemon": "^1.9.2", 38 | "paper": "^0.11.5", 39 | "rev-del": "^1.0.5", 40 | "rimraf": "^2.6.2", 41 | "sat": "^0.6.0", 42 | "seedrandom": "^2.4.3", 43 | "simple-node-logger": "^0.93.33", 44 | "simple-quadtree": "^0.1.3", 45 | "webpack": "^1.4.0", 46 | "webpack-stream": "^3.2.0", 47 | "ws": "^3.3.2" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /arrasio/extra/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "0.0.0.0", 3 | "port": 3000, 4 | "logpath": "logger.php", 5 | "networkUpdateFactor": 25, 6 | "networkFrontlog": 3, 7 | "networkFallbackTime": 2000, 8 | "gameSpeed": 1, 9 | "runSpeed": 1.5, 10 | "maxHeartbeatInterval": 120000, 11 | "sqlinfo":{ 12 | "connectionLimit": 50, 13 | "host": "DEFAULT", 14 | "user": "root", 15 | "password": "DEFAULT", 16 | "database": "DEFAULT", 17 | "debug": false 18 | }, 19 | "verbose": true, 20 | 21 | "WIDTH": 4500, 22 | "HEIGHT": 4500, 23 | "MODE": "tdm", 24 | "RANDOM_COLORS": false, 25 | "REAL_COLOR": true, 26 | "ROOM_SETUP": [ 27 | [ "bas1", "norm", "norm", "norm", "norm" ], 28 | [ "norm", "norm", "norm", "norm", "norm" ], 29 | [ "norm", "norm", "norm", "norm", "norm" ], 30 | [ "norm", "norm", "norm", "norm", "norm" ], 31 | [ "norm", "norm", "norm", "norm", "bas3" ] 32 | ], 33 | "X_GRID": 5, 34 | "Y_GRID": 5, 35 | "ROOM_BOUND_FORCE": 0.015, 36 | "FOOD": [ 37 | 0, 38 | 0.75, 39 | 0.22, 40 | 0.1, 41 | 0.025, 42 | 0.005, 43 | 0 44 | ], 45 | "MAX_SKILL": 9, 46 | "SOFT_MAX_SKILL": 0.56, 47 | "TIER_1": 10, 48 | "TIER_2": 25, 49 | "TIER_3": 45, 50 | "SKILL_CAP": 45, 51 | "SKILL_SOFT_CAP": 15, 52 | "SKILL_CHEAT_CAP": 45, 53 | "SKILL_LEAK": 0, 54 | "STEALTH": 4, 55 | "MIN_SPEED": 0.001, 56 | "FOOD_AMOUNT": 1.5, 57 | "SKILL_BOOST": 5, 58 | "BOTS": 0 59 | } 60 | -------------------------------------------------------------------------------- /arrasio/src/client/js/lib/global.js: -------------------------------------------------------------------------------- 1 | /*jslint esversion: 6*/ 2 | /*global require, module, exports, console*/ 3 | /*jshint -W097*/ 4 | "use strict"; 5 | 6 | module.exports = { 7 | // Keys and other mathematical constants 8 | KEY_ESC: 27, 9 | KEY_ENTER: 13, 10 | KEY_CHAT: 13, 11 | KEY_FIREFOOD: 119, 12 | KEY_SPLIT: 32, 13 | KEY_LEFT: 65, 14 | KEY_UP: 87, 15 | KEY_RIGHT: 68, 16 | KEY_DOWN: 83, 17 | KEY_LEFT_ARROW: 37, 18 | KEY_UP_ARROW: 38, 19 | KEY_RIGHT_ARROW: 39, 20 | KEY_DOWN_ARROW: 40, 21 | KEY_AUTO_SPIN: 67, 22 | KEY_AUTO_FIRE: 69, 23 | KEY_OVER_RIDE: 82, 24 | KEY_UPGRADE_ATK: 49, 25 | KEY_UPGRADE_HTL: 50, 26 | KEY_UPGRADE_SPD: 51, 27 | KEY_UPGRADE_STR: 52, 28 | KEY_UPGRADE_PEN: 53, 29 | KEY_UPGRADE_DAM: 54, 30 | KEY_UPGRADE_RLD: 55, 31 | KEY_UPGRADE_MOB: 56, 32 | KEY_UPGRADE_RGN: 57, 33 | KEY_UPGRADE_SHI: 48, 34 | KEY_MOUSE_0: 32, 35 | KEY_MOUSE_1: 86, 36 | KEY_MOUSE_2: 16, 37 | KEY_CHOOSE_1: 89, 38 | KEY_CHOOSE_2: 72, 39 | KEY_CHOOSE_3: 85, 40 | KEY_CHOOSE_4: 74, 41 | KEY_CHOOSE_5: 73, 42 | KEY_CHOOSE_6: 75, 43 | KEY_CHOOSE_7: 79, 44 | KEY_CHOOSE_8: 76, 45 | KEY_LEVEL_UP: 78, 46 | KEY_FUCK_YOU: 191, 47 | 48 | // Canvas 49 | screenWidth: window.innerWidth, 50 | screenHeight: window.innerHeight, 51 | gameWidth: 0, 52 | gameHeight: 0, 53 | xoffset: -0, 54 | yoffset: -0, 55 | gameStart: false, 56 | disconnected: false, 57 | died: false, 58 | kicked: false, 59 | continuity: false, 60 | startPingTime: 0, 61 | toggleMassState: 0, 62 | backgroundColor: '#f2fbff', 63 | lineColor: '#000000', 64 | }; 65 | -------------------------------------------------------------------------------- /arrasio/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "host": "0.0.0.0", 3 | "servesStatic": true, 4 | "port": 3000, 5 | "logpath": "logger.php", 6 | "networkUpdateFactor": 24, 7 | "socketWarningLimit": 5, 8 | "networkFrontlog": 1, 9 | "networkFallbackTime": 150, 10 | "visibleListInterval": 1000, 11 | "gameSpeed": 1, 12 | "runSpeed": 1.5, 13 | "maxHeartbeatInterval": 30000, 14 | "sqlinfo":{ 15 | "connectionLimit": 50, 16 | "host": "DEFAULT", 17 | "user": "root", 18 | "password": "DEFAULT", 19 | "database": "DEFAULT", 20 | "debug": false 21 | }, 22 | "verbose": true, 23 | 24 | "WIDTH": 2000, 25 | "HEIGHT": 2000, 26 | "MODE": "tdm", 27 | "RANDOM_COLORS": false, 28 | "BANNED_CHARACTER_REGEX": "/[\uFDFD\u200E\u0000]/gi", 29 | "ROOM_SETUP": [ 30 | [ "roid", "norm", "norm", "roid" ], 31 | [ "norm", "nest", "roid", "norm" ], 32 | [ "norm", "roid", "nest", "norm" ], 33 | [ "roid", "norm", "norm", "roid" ] 34 | ], 35 | "X_GRID": 4, 36 | "Y_GRID": 4, 37 | "DAMAGE_CONSTANT": 0.6, 38 | "KNOCKBACK_CONSTANT": 1, 39 | "ROOM_BOUND_FORCE": 0.01, 40 | "FOOD": [ 41 | 0, 42 | 0.75, 43 | 0.22, 44 | 0.1, 45 | 0.005, 46 | 0, 47 | 0 48 | ], 49 | "FOOD_NEST": [ 50 | 0, 51 | 0.0, 52 | 0.0, 53 | 0.75, 54 | 0.23, 55 | 0.02, 56 | 0 57 | ], 58 | "MAX_SKILL": 9, 59 | "SOFT_MAX_SKILL": 0.59, 60 | "TIER_1": 10, 61 | "TIER_2": 25, 62 | "TIER_3": 45, 63 | "SKILL_CAP": 45, 64 | "SKILL_SOFT_CAP": 0, 65 | "SKILL_CHEAT_CAP": 45, 66 | "SKILL_LEAK": 0, 67 | "STEALTH": 4, 68 | "MIN_SPEED": 0.001, 69 | "FOOD_AMOUNT": 2, 70 | "SKILL_BOOST": 5, 71 | "BOTS": 0, 72 | "GLASS_HEALTH_FACTOR": 2, 73 | "TOKEN_REQUIRED": true 74 | } 75 | -------------------------------------------------------------------------------- /arrasio/src/client/js/lib/color.js: -------------------------------------------------------------------------------- 1 | /*exports.white = "#DDE6EB"; // 0 2 | exports.orange = "#E7896D"; // 1 x 3 | exports.teal = "#70D1CA"; // 2 x 4 | exports.pink = "#F4A9C8"; // 3 x 5 | exports.lgreen = "#B9E87E"; // 4 x 6 | exports.yellow = "#FEE07E"; // 5 x 7 | exports.grey = "#B7B7B7"; // 6 8 | exports.red = "#D65152"; // 7 x 9 | exports.blue = "#3CA4CB"; // 8 x 10 | exports.purple = "#9371E1"; // 9 x 11 | exports.green = "#8ABC3F"; // 10 x 12 | exports.gold = "#EFB64B"; // 11 x 13 | exports.black = "#484848"; // 12 14 | exports.crimson = "#BB2940"; // 13 x 15 | exports.dblue = "#4175A7"; // 14 x 16 | exports.dpurple = "#6944A4"; // 15 x 17 | exports.dgreen = "#6C8D09"; // 16 x 18 | exports.brown = "#C7860E"; // 17 x 19 | exports.guiwhite ='#FFFFFF'; // -1 x*/ 20 | 21 | /*exports.white = "#FFF9F0"; 22 | exports.orange = "#F75E4E"; 23 | exports.teal = "#5BCDD7"; 24 | exports.pink = "#FC9FCE"; 25 | exports.lgreen = "#79D977"; 26 | exports.yellow = "#FFF07D"; 27 | exports.grey = "#ACB1C5"; 28 | exports.red = "#D90031"; 29 | exports.blue = "#1C9BC6"; 30 | exports.purple = "#9D24C7"; 31 | exports.green = "#6CA91D"; 32 | exports.gold = "#FBBC15"; 33 | exports.black = "#302C2B"; 34 | exports.crimson = "#8F1431"; 35 | exports.dblue = "#2E5377"; 36 | exports.dpurple = "#442F5A"; 37 | exports.dgreen = "#495E07"; 38 | */ 39 | 40 | exports.teal = '#70D1CA'; // 0 41 | exports.lgreen = '#B9E87E'; // 1 42 | exports.orange = '#E7896D'; // 2 43 | exports.yellow = '#FDF380'; // 3 44 | exports.lavender ='#B58EFD'; // 4 45 | exports.pink = '#EF99C3'; // 5 46 | exports.vlgrey = '#EAEAEA'; // 6 47 | exports.lgrey = '#D8D6D6'; // 7 48 | exports.guiwhite ='#FFFFFF'; // 8 49 | exports.black = '#484848'; // 9 50 | 51 | exports.blue = '#3CA4CB'; // 10 52 | exports.green = '#8ABC3F'; // 11 53 | exports.red = '#D83848'; // 12 54 | exports.gold = '#EFC74B'; // 13 55 | exports.purple = '#8D6ADF'; // 14 56 | exports.magenta = '#CC669C'; // 15 57 | exports.grey = '#B5B5B9'; // 16 58 | exports.dgrey = '#999797'; // 17 59 | exports.white = '#DDE6EB'; // 18 60 | exports.guiblack ='#000000'; // 19 61 | 62 | exports.paletteSize = 10; -------------------------------------------------------------------------------- /arrasio/src/client/js/lib/util.js: -------------------------------------------------------------------------------- 1 | exports.submitToLocalStorage = name => { 2 | localStorage.setItem(name+'Value', document.getElementById(name).value); 3 | localStorage.setItem(name+'Checked', document.getElementById(name).checked); 4 | return false; 5 | }; 6 | exports.retrieveFromLocalStorage = name => { 7 | document.getElementById(name).value = localStorage.getItem(name+'Value'); 8 | document.getElementById(name).checked = localStorage.getItem(name+'Checked') === 'true'; 9 | return false; 10 | }; 11 | exports.handleLargeNumber = (a, cullZeroes = false) => { 12 | if (cullZeroes && a == 0) { 13 | return ''; 14 | } 15 | 16 | if (a < Math.pow(10, 3)) { 17 | return '' + a.toFixed(0); 18 | } 19 | 20 | if (a < Math.pow(10, 6)) { 21 | return (a / Math.pow(10, 3)).toFixed(2) + "k"; 22 | } 23 | 24 | if (a < Math.pow(10, 9)) { 25 | return (a / Math.pow(10, 6)).toFixed(2) + "m"; 26 | } 27 | 28 | if (a < Math.pow(10, 12)) { 29 | return (a / Math.pow(10, 9)).toFixed(2) + "b"; 30 | } 31 | 32 | if (a < Math.pow(10, 15)) { 33 | return (a / Math.pow(10, 12)).toFixed(2) + "t"; 34 | } 35 | 36 | return (a / Math.pow(10, 15)).toFixed(2) + "q"; 37 | 38 | }; 39 | exports.timeForHumans = x => { 40 | // ought to be in seconds 41 | let seconds = x % 60; 42 | x /= 60; x = Math.floor(x); 43 | let minutes = x % 60; 44 | x /= 60; x = Math.floor(x); 45 | let hours = x % 24; 46 | x /= 24; x = Math.floor(x); 47 | let days = x; 48 | let y = ''; 49 | function weh(z, text) { 50 | if (z) { y = y + ((y === '') ? '' : ', ') + z + ' ' + text + ((z > 1) ? 's' : ''); } 51 | } 52 | weh(days, 'day'); 53 | weh(hours, 'hour'); 54 | weh(minutes, 'minute'); 55 | weh(seconds, 'second'); 56 | if (y === '') { y = 'less than a second'; } 57 | return y; 58 | }; 59 | exports.addArticle = string => { 60 | return (/[aeiouAEIOU]/.test(string[0])) ? 'an ' + string : 'a ' + string; 61 | }; 62 | exports.formatLargeNumber = x => { 63 | return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); 64 | }; 65 | exports.pullJSON = filename => { 66 | let request = new XMLHttpRequest(); 67 | let url = "/json/" + filename + ".json?v="+VERSION; 68 | // Set up the request 69 | console.log("Loading JSON from " + url); 70 | request.responseType = 'json'; 71 | // Return a promise 72 | return new Promise((resolve, reject) => { 73 | request.open('GET', url); 74 | request.onload = () => { resolve(request.response); console.log('JSON load complete.'); }; 75 | request.onerror = () => { reject(request.statusText); console.log('JSON load failed.'); console.log(request.statusText); }; 76 | request.send(); 77 | }); 78 | }; -------------------------------------------------------------------------------- /arrasio/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var babel = require("gulp-babel"); 3 | var jshint = require("gulp-jshint"); 4 | var nodemon = require("gulp-nodemon"); 5 | var uglify = require("gulp-uglify"); 6 | var util = require("gulp-util"); 7 | var mocha = require("gulp-mocha"); 8 | var todo = require("gulp-todo"); 9 | var webpack = require("webpack-stream"); 10 | var fs = require("fs"); 11 | var rev = require("gulp-rev"); 12 | var replace = require("gulp-rev-replace"); 13 | var clean = require("gulp-rev-dist-clean"); 14 | //var nodeInspector = require("gulp-node-inspector"); 15 | var rimraf = require('rimraf'); 16 | // Clear the old bin first 17 | 18 | gulp.task("build", ["build-client", "build-server"]); 19 | 20 | gulp.task("clear-bin", function gulpRimraf() { 21 | rimraf.sync('bin', {}, function cb() { console.log('Old bin folder cleared.'); }); 22 | }); 23 | 24 | gulp.task("build-server", ["clear-bin"], function gulpBuildServer() { 25 | return gulp.src(["src/server/**/*.*", "src/server/**/*.js"]) 26 | .pipe(babel()) 27 | .pipe(gulp.dest("bin/server/")); 28 | }); 29 | 30 | gulp.task("build-client", ["move-client", "compile-client", "rev-rename", "rev-replace", "rev-clean"]); 31 | 32 | gulp.task("move-client", ["clear-bin"], function gulpMoveClient() { 33 | return gulp.src(["src/client/**/*.*", "!client/js/*.js"]) 34 | .pipe(gulp.dest("bin/client/")); 35 | }); 36 | 37 | gulp.task("compile-client", ["move-client"], function gulpBuildClient() { 38 | return gulp.src(["src/client/js/app.js"]) 39 | //.pipe(uglify()) 40 | .pipe(webpack(require("./webpack.config.js"))) 41 | .pipe(babel({ 42 | presets: [ 43 | ["es2015", { "modules": false }] 44 | ] 45 | })) 46 | .pipe(gulp.dest("bin/client/js/")); 47 | }); 48 | 49 | gulp.task("rev-rename", ["compile-client"], function gulpRevRename() { 50 | return gulp.src(["bin/client/**/*.html", 51 | "bin/client/**/*.css", 52 | "bin/client/**/*.js", 53 | "bin/client/**/*.json", 54 | "bin/client/**/*.{jpg,png,jpeg,gif,svg}"]) 55 | .pipe(rev()) 56 | .pipe(gulp.dest("bin/client/")) 57 | .pipe(rev.manifest({ path: "manifest.json" })) 58 | .pipe(gulp.dest("bin/manifest/")); 59 | }); 60 | 61 | gulp.task("rev-replace", ["compile-client", "rev-rename"], function gulpRevReplace() { 62 | return gulp.src("bin/client/**/*.{css,js,html}") 63 | .pipe(replace({ manifest: gulp.src("bin/manifest/manifest.json"), })) 64 | .pipe(gulp.dest("bin/client/")); 65 | }); 66 | 67 | gulp.task('rev-clean', ["compile-client", "rev-rename"], function gulpRevClean() { 68 | return gulp.src(['bin/client/**/*'], {read: false}) 69 | .pipe(clean('bin/manifest/manifest.json')); 70 | }); 71 | 72 | gulp.task("run", ["build"], function gulpRun() { 73 | nodemon({ 74 | delay: 1000, 75 | script: "./server/server.js", 76 | cwd: "./bin/", 77 | args: ["config.json"], 78 | ext: "html js css" 79 | }) 80 | .on("restart", function gulpRunOnRestart() { 81 | util.log("server restarted!"); 82 | }); 83 | }); 84 | 85 | gulp.task("default", ["run"]); -------------------------------------------------------------------------------- /arrasio/src/server/lib/random.js: -------------------------------------------------------------------------------- 1 | /*jslint node: true */ 2 | "use strict"; 3 | 4 | require('seedrandom'); 5 | // Seed math 6 | Math.seedrandom('' + Date.now()); 7 | 8 | exports.random = x => { 9 | return x * Math.random(); 10 | }; 11 | 12 | exports.randomAngle = () => { 13 | return Math.PI * 2 * Math.random(); 14 | }; 15 | 16 | exports.randomRange = (min, max) => { 17 | return Math.random() * (max - min) + min; 18 | }; 19 | 20 | exports.irandom = i => { 21 | let max = Math.floor(i); 22 | return Math.floor(Math.random() * (max + 1)); //Inclusive 23 | }; 24 | 25 | exports.irandomRange = (min, max) => { 26 | min = Math.ceil(min); 27 | max = Math.floor(max); 28 | return Math.floor(Math.random() * (max - min + 1)) + min; //Inclusive 29 | }; 30 | 31 | exports.gauss = (mean, deviation) => { 32 | let x1, x2, w; 33 | do { 34 | x1 = 2*Math.random() - 1; 35 | x2 = 2*Math.random() - 1; 36 | w = x1 * x1 + x2 * x2; 37 | } while (0 == w || w >= 1); 38 | 39 | w = Math.sqrt(-2 * Math.log(w) / w); 40 | return mean + deviation * x1 * w; 41 | }; 42 | 43 | exports.gaussInverse = (min, max, clustering) => { 44 | let range = max - min; 45 | let output = exports.gauss(0, range / clustering); 46 | 47 | while (output < 0) { 48 | output += range; 49 | } 50 | 51 | while (output > range) { 52 | output -= range; 53 | } 54 | 55 | return output + min; 56 | }; 57 | 58 | exports.gaussRing = (radius, clustering) => { 59 | let r = exports.random(Math.PI * 2); 60 | let d = exports.gauss(radius, radius*clustering); 61 | return { 62 | x: d * Math.cos(r), 63 | y: d * Math.sin(r), 64 | }; 65 | }; 66 | 67 | exports.chance = prob => { 68 | return exports.random(1) < prob; 69 | }; 70 | 71 | exports.dice = sides => { 72 | return exports.random(sides) < 1; 73 | }; 74 | 75 | exports.choose = arr => { 76 | return arr[exports.irandom(arr.length - 1)]; 77 | }; 78 | 79 | exports.chooseN = (arr, n) => { 80 | let o = []; 81 | for (let i=0; i { 88 | let totalProb = 0; 89 | arg.forEach(function(value) { totalProb += value; }); 90 | let answer = exports.random(totalProb); 91 | for (let i=0; i { 99 | return exports.choose([ 100 | 'Alice', 101 | 'Bob', 102 | 'Carmen', 103 | 'David', 104 | 'Edith', 105 | 'Freddy', 106 | 'Gustav', 107 | 'Helga', 108 | 'Janet', 109 | 'Lorenzo', 110 | 'Mary', 111 | 'Nora', 112 | 'Olivia', 113 | 'Peter', 114 | 'Queen', 115 | 'Roger', 116 | 'Suzanne', 117 | 'Tommy', 118 | 'Ursula', 119 | 'Vincent', 120 | 'Wilhelm', 121 | 'Xerxes', 122 | 'Yvonne', 123 | 'Zachary', 124 | 'Alpha', 125 | 'Bravo', 126 | 'Charlie', 127 | 'Delta', 128 | 'Echo', 129 | 'Foxtrot', 130 | 'Hotel', 131 | 'India', 132 | 'Juliet', 133 | 'Kilo', 134 | 'Lima', 135 | 'Mike', 136 | 'November', 137 | 'Oscar', 138 | 'Papa', 139 | 'Quebec', 140 | 'Romeo', 141 | 'Sierra', 142 | 'Tango', 143 | 'Uniform', 144 | 'Victor', 145 | 'Whiskey', 146 | 'X-Ray', 147 | 'Yankee', 148 | 'Zulu', 149 | ]); 150 | }; 151 | 152 | exports.chooseBossName = (code, n) => { 153 | switch (code) { 154 | case 'a': 155 | return exports.chooseN([ 156 | 'Archimedes', 157 | 'Akilina', 158 | 'Anastasios', 159 | 'Athena', 160 | 'Alkaios', 161 | 'Amyntas', 162 | 'Aniketos', 163 | 'Artemis', 164 | 'Anaxagoras', 165 | 'Apollon', 166 | ], n); 167 | case 'castle': 168 | return exports.chooseN([ 169 | 'Berezhany', 170 | 'Lutsk', 171 | 'Dobromyl', 172 | 'Akkerman', 173 | 'Palanok', 174 | 'Zolochiv', 175 | 'Palanok', 176 | 'Mangup', 177 | 'Olseko', 178 | 'Brody', 179 | 'Isiaslav', 180 | 'Kaffa', 181 | 'Bilhorod', 182 | ], n); 183 | default: return 'God'; 184 | } 185 | }; 186 | -------------------------------------------------------------------------------- /arrasio/extra/server setup guide.txt: -------------------------------------------------------------------------------- 1 | 1) Install ubuntu 2 | 2) adduser arras && adduser arras sudo 3 | 3) apt update && apt upgrade 4 | 4) Install nginx 5 | 5) mkdir ~/logs && sudo vim /etc/nginx/nginx.conf && sudo service nginx restart 6 | * * * * 7 | user arras; 8 | 9 | worker_processes auto; 10 | 11 | pid /var/run/nginx.pid; 12 | 13 | events { 14 | worker_connections 1024; 15 | } 16 | 17 | http { 18 | include /etc/nginx/mime.types; 19 | 20 | error_log /home/arras/logs/errors.log; 21 | access_log /home/arras/logs/access.log; 22 | 23 | default_type application/octet-stream; 24 | sendfile on; 25 | tcp_nodelay on; 26 | 27 | keepalive_timeout 100; 28 | 29 | map $http_upgrade $connection_upgrade { 30 | default upgrade; 31 | '' close; 32 | } 33 | 34 | upstream websocket { 35 | server localhost:35000; 36 | } 37 | 38 | server { 39 | listen 8080 default_server; 40 | 41 | root /home/arras/app/bin/client; 42 | index index.html; 43 | expires max; 44 | 45 | location /favicon.ico { 46 | root /home/arras/app/src/client; 47 | } 48 | } 49 | 50 | server { 51 | listen 3000; 52 | location / { 53 | proxy_pass http://websocket; 54 | proxy_http_version 1.1; 55 | proxy_set_header Upgrade $http_upgrade; 56 | proxy_set_header Connection $connection_upgrade; 57 | proxy_set_header Host $host; 58 | proxy_set_header X-Real-IP $remote_addr; 59 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 60 | 61 | } 62 | } 63 | } 64 | * * * * 65 | 6) Install gdrive 66 | * https://docs.google.com/uc?id=0B3X9GlR6EmbnQ0FtZmJJUXEyRTA&export=download 67 | * curl https://doc-08-48-docs.googleusercontent.com/docs/securesc/ha0ro937gcuc7l7deffksulhg5h7mbp1/aonef2hk994avnod20atfm4oc0866r85/1512554400000/15876260727594163214/*/0B3X9GlR6EmbnQ0FtZmJJUXEyRTA --output ~/gdrive 68 | * sudo chmod +x gdrive 69 | * ~/gdrive about 70 | 7) mkdir ~/app/ 71 | 8) sudo apt install npm 72 | * ~/gdrive download --force 1skGvMOaOtLoXyy9wnJszmwKV951168zY && tar -xf app.tar && cd ~/app && npm install 73 | * sudo ln -s /usr/bin/nodejs /usr/bin/node 74 | * sudo npm install -g gulp 75 | * sudo npm install -g n 76 | * sudo n latest 77 | 9) sudo apt install fail2ban 78 | 10) configure fail2ban https://www.digitalocean.com/community/tutorials/how-to-protect-an-nginx-server-with-fail2ban-on-ubuntu-14-04 79 | * sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local 80 | * sudo vim /etc/fail2ban/jail.local 81 | * * * * 82 | [nginx-http-auth] 83 | 84 | enabled = true 85 | filter = nginx-http-auth 86 | port = http,https 87 | logpath = /var/log/nginx/error.log 88 | 89 | [nginx-noscript] 90 | 91 | enabled = true 92 | port = http,https 93 | filter = nginx-noscript 94 | logpath = /var/log/nginx/access.log 95 | maxretry = 6 96 | 97 | [nginx-badbots] 98 | 99 | enabled = true 100 | port = http,https 101 | filter = nginx-badbots 102 | logpath = /var/log/nginx/access.log 103 | maxretry = 2 104 | 105 | [nginx-noproxy] 106 | 107 | enabled = true 108 | port = http,https 109 | filter = nginx-noproxy 110 | logpath = /var/log/nginx/access.log 111 | maxretry = 2 112 | * * * * 113 | * cd /etc/fail2ban/filter.d 114 | * sudo nano nginx-http-auth.conf 115 | * ^ \[error\] \d+#\d+: \*\d+ no user/password was provided for basic authentication, client: , server: \S+, request: "\S+ \S+ HTTP/\d+\.\d+", host: "\S+"\s*$ 116 | * sudo cp apache-badbots.conf nginx-badbots.conf 117 | * sudo nano nginx-noscript.conf 118 | * * * * 119 | [Definition] 120 | 121 | failregex = ^ -.*GET.*(\.php|\.asp|\.exe|\.pl|\.cgi|\.scgi) 122 | 123 | ignoreregex = 124 | * * * * 125 | * sudo nano nginx-nohome.conf 126 | * * * * 127 | [Definition] 128 | 129 | failregex = ^ -.*GET .*/~.* 130 | 131 | ignoreregex = 132 | * * * * 133 | * sudo nano nginx-noproxy.conf 134 | * * * * 135 | [Definition] 136 | 137 | failregex = ^ -.*GET http.* 138 | 139 | ignoreregex = 140 | * * * * 141 | * sudo service fail2ban restart 142 | 11) configure ufw 143 | * sudo ufw default allow outgoing 144 | * sudo ufw default deny incoming 145 | * sudo ufw allow ssh 146 | * sudo ufw allow 3000 147 | * sudo ufw allow 8080 148 | * sudo ufw enable 149 | 12) cd ~/ && ~/gdrive download --force **********APP.TAR GDRIVE CODE HERE, USE GDRIVE -H TO FIND IT IIRC*********** && tar -xf app.tar && cd ~/app && gulp run 150 | -------------------------------------------------------------------------------- /arrasio/src/server/lib/util.js: -------------------------------------------------------------------------------- 1 | /* jslint node: true */ 2 | 3 | 'use strict'; 4 | 5 | var cfg = require('../../../config.json'); 6 | 7 | exports.addArticle = function(string) { 8 | return (/[aeiouAEIOU]/.test(string[0])) ? 'an ' + string : 'a ' + string; 9 | }; 10 | 11 | exports.getDistance = function (p1, p2) { 12 | return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)); 13 | }; 14 | 15 | exports.getDirection = function (p1, p2) { 16 | return Math.atan2(p2.y - p1.y, p2.x - p1.x); 17 | }; 18 | 19 | exports.clamp = function(value, min, max) { 20 | return Math.min(Math.max(value, min), max); 21 | }; 22 | 23 | 24 | /*exports.angleDifference = function(a1, a2) { 25 | let diff1 = a2 - a1; 26 | while (diff1 >= 2*Math.PI) { 27 | diff1 -= 2*Math.PI; 28 | } 29 | while (diff1 < 0) { 30 | diff1 += 2*Math.PI; 31 | } 32 | let diff2 = a1 - a2; 33 | while (diff2 >= 2*Math.PI) { 34 | diff2 -= 2*Math.PI; 35 | } 36 | while (diff2 < 0) { 37 | diff2 += 2*Math.PI; 38 | } 39 | 40 | if (Math.abs(diff1) <= Math.abs(diff2)) { return diff1; } 41 | if (Math.abs(diff2) <= Math.abs(diff1)) { return diff2; } 42 | };*/ 43 | exports.angleDifference = (() => { 44 | let mod = function(a, n) { 45 | return (a % n + n) % n; 46 | }; 47 | return (sourceA, targetA) => { 48 | let a = targetA - sourceA; 49 | return mod(a + Math.PI, 2*Math.PI) - Math.PI; 50 | }; 51 | })(); 52 | 53 | exports.loopSmooth = (angle, desired, slowness) => { 54 | return exports.angleDifference(angle, desired)/slowness; 55 | }; 56 | 57 | /*exports.loopClamp = function(angle, min, max) { 58 | angle = angle % (Math.PI * 2); 59 | min = min % (Math.PI * 2); if (min < 0) min += Math.PI * 2; 60 | max = max % (Math.PI * 2); if (max < 0) max += Math.PI * 2; 61 | let a = (max - min) % (Math.PI * 2); if (a < 0) a += Math.PI * 2; 62 | if (angle - min > a) return max; 63 | if (angle - min < 0) return min; 64 | return angle; 65 | };*/ 66 | 67 | 68 | /*exports.pointInArc = function(point, givenAngle, allowedDifference) { 69 | let len = Math.sqrt(point.x * point.x + point.y * point.y); 70 | let norm = { x: point.x / len, y: point.y / len, }; 71 | let vect = { x: Math.cos(givenAngle), y: Math.sin(givenAngle), }; 72 | let dot = norm.x * vect.x + norm.y * vect.y; 73 | let a1 = Math.atan2(point.y, point.x); 74 | let a2 = Math.acos(dot); 75 | let diff = exports.angleDifference(a1, a2); 76 | };*/ 77 | 78 | /*exports.isInArc = function(angle, arc) { 79 | return exports.loopClamp(angle, arc[0], arc[1]) == angle; 80 | };*/ 81 | 82 | exports.deepClone = (obj, hash = new WeakMap()) => { 83 | let result; 84 | // Do not try to clone primitives or functions 85 | if (Object(obj) !== obj || obj instanceof Function) return obj; 86 | if (hash.has(obj)) return hash.get(obj); // Cyclic reference 87 | try { // Try to run constructor (without arguments, as we don't know them) 88 | result = new obj.constructor(); 89 | } catch(e) { // Constructor failed, create object without running the constructor 90 | result = Object.create(Object.getPrototypeOf(obj)); 91 | } 92 | // Optional: support for some standard constructors (extend as desired) 93 | if (obj instanceof Map) 94 | Array.from(obj, ([key, val]) => result.set(exports.deepClone(key, hash), 95 | exports.deepClone(val, hash)) ); 96 | else if (obj instanceof Set) 97 | Array.from(obj, (key) => result.add(exports.deepClone(key, hash)) ); 98 | // Register in hash 99 | hash.set(obj, result); 100 | // Clone and assign enumerable own properties recursively 101 | return Object.assign(result, ...Object.keys(obj).map ( 102 | key => ({ [key]: exports.deepClone(obj[key], hash) }) )); 103 | }; 104 | 105 | exports.averageArray = arr => { 106 | if (!arr.length) return 0; 107 | var sum = arr.reduce((a, b) => { return a + b; }); 108 | return sum / arr.length; 109 | }; 110 | 111 | exports.sumArray = arr => { 112 | if (!arr.length) return 0; 113 | var sum = arr.reduce((a, b) => { return a + b; }); 114 | return sum; 115 | }; 116 | 117 | 118 | exports.signedSqrt = x => { 119 | return Math.sign(x) * Math.sqrt(Math.abs(x)); 120 | }; 121 | 122 | exports.getJackpot = x => { 123 | return (x > 26300 * 1.5) ? Math.pow(x - 26300, 0.85) + 26300 : x / 1.5; 124 | }; 125 | 126 | exports.serverStartTime = Date.now(); 127 | // Get a better logging function 128 | exports.time = () => { 129 | return Date.now() - exports.serverStartTime; 130 | }; 131 | 132 | // create a custom timestamp format for log statements 133 | const SimpleNodeLogger = require('simple-node-logger'), 134 | logger = SimpleNodeLogger.createRollingFileLogger({ 135 | logDirectory: __dirname + '/../../../logs', 136 | fileNamePattern:'diep2-.log', 137 | dateFormat:'YYYY-MM-DD', 138 | level: 'warn', 139 | }); 140 | exports.log = text => { 141 | console.log('[' + (exports.time()/1000).toFixed(3) + ']: ' + text); 142 | logger.info(text); 143 | }; 144 | exports.warn = text => { 145 | console.log('[' + (exports.time()/1000).toFixed(3) + ']: ' + '[WARNING] ' + text); 146 | logger.warn(text); 147 | }; 148 | exports.error = text => { 149 | console.log(text); 150 | logger.error(text); 151 | }; 152 | exports.remove = (array, index) => { 153 | // there is more than one object in the container 154 | if(index === array.length - 1){ 155 | // special case if the obj is the newest in the container 156 | return array.pop(); 157 | } else { 158 | let o = array[index]; 159 | array[index] = array.pop(); 160 | return o; 161 | } 162 | }; -------------------------------------------------------------------------------- /arrasio/extra/changelog_build_0_0_1_4.txt: -------------------------------------------------------------------------------- 1 | Mockup 0.0.1.4 2 | ------- 3 | 4 | **Adds:** 5 | 6 | * Traps, both unguided and guided. 7 | * Drones. Probably not balanced yet. 8 | * Swarm (battleship drones). 9 | * Manager (lvl. 10, no invisibility), Overseer, Overlord, Cruiser, Battleship, Carrier, Trap Guard, Double Trap Guard, Gunner, Rifle, Hybrid, Flamethrower, and nine(??) unnamed tanks. Probably some more I missed, too. 10 | 11 | **Balances:** 12 | 13 | * Rebalanced polygons, esp. Pentagon shields. 14 | * Nerfed/redesigned Blaster. 15 | * Increased Triplet, Dual, and Quintuplet's FOV slightly. 16 | * Seriously decreased Assassin's recoil. I have no clue what that was supposed to be. 17 | * Changed Sniper gunline's bonuses out of damage and health and into natural resistance. 18 | * Increased Twin and Destroyer gunlines' recoil. 19 | * Shifted around a lot of penetration bonuses. 20 | * Decreased Machine Gun gunline's natural resist and reload. 21 | * Buffed Gunner gunline's raw damage and resist. 22 | * Slightly buffed Flank Guard gunline's reload and damage. 23 | * Slightly buffed Hunter and Predator's damage. Decreased reload. Tightened up Predator firing timing. Decreased bullet size. 24 | * Made Power Gunner bullets heavier. 25 | 26 | **Changes:** 27 | 28 | * Renamed Bullet Strength to Bullet Health. 29 | * Levels 1, 3, 5, 7, and 9 now only give one skillpoint (used to be 2). 30 | * Improved differentiation between Bullet Strength (now Bullet Health) and Bullet Penetration skills 31 | * Increased agility, especially at high levels. 32 | * Slightly increased all recoil. 33 | * Made it easier to shoot through shields. 34 | * Changed health bar colors. 35 | * Lengthened the Sniper and Destroyer gunlines' barrels. 36 | * Changed Sprayer's barrel shape to look more traditional. 37 | * Restored Flank Guard's name. Named Sprayer, Splasher, and Tornado. Fixed some other names, see Bug Fixes below. 38 | 39 | **Change Details:** 40 | 41 | * Changed healthtype ratio to be proportional. 42 | * Changed damage script to independently calculate healthtype ratio and applied penetration values to them. 43 | * Shifted some things around under the hood with how resistance stats are handled. 44 | * Moved bullet resistance increase from Bullet Health to Bullet Penetration. 45 | * Changed basically everyhing about resistance actually. (NOTE TO SELF: be careful when porting changes to web version) 46 | * Bullet Speed skills no longer improve bullet penetration, now only Bullet Penetration skills do. 47 | * Penetration decreases glancing hit damage reduction. 48 | * Penetration mutually accelerates collision damage. 49 | * Bullet Health no longer directly increases bullet density (and thus mass and thus knockback). 50 | * Bullets decrease in density with increasing player size. 51 | * Bullets slightly increase in damage and health with increasing player health. 52 | * Collision elasticity is now determined by the arctangent of a proportional combination of entity penetrations rather than the arctangent of a square combination. 53 | * Entity penetration no longer directly reduces knockback. 54 | * Entity resistance no longer directly decreases damage taken to the health. 55 | * Increased body friction. 56 | * Body acceleration now decreases with the fourth root of body size, not the square root. 57 | * Doubled basic barrel recoil. 58 | * Changed shield cohesion curve to make it more permeable at higher %s. 59 | * Significantly nerfed polygon body damage and buffed polygon max health across the board. 60 | * Decreased all polygon resists by 15% resist. Squares now have 0% resist. 61 | * Skill leak now only 0.2 instead of 0.3. 62 | * Make skill leak up and down curves more gentle (ratios raised to the power of 1.5 instead of squared). 63 | * Bullet Health no longer directly decreases damage. 64 | * Decreased alpha and beta pentagon shield recharge and increased shield capacity. 65 | * Density no longer decreases drag by default. This most affects high-level pentagons suffering severe knockback from bullet spammers. 66 | * Maxed Bullet Penetration now gives 3 times as much penetration (used to be x2). 67 | * Changed Bullet Health skillcurve to exponential instead of linear. 68 | * Made the collision acceleration factor not apply to inertia. 69 | * Made collision depth not apply to elastic inertia. 70 | * Changed the way shield level affects acceleration from collisions. 71 | 72 | **Fixes:** 73 | 74 | * [!!!] Identified and fixed bug which failed to reduce elastic impulse with penetration (I had commented it out and forgot about it). 75 | * [!!!] Identified and fixed bug where shield coherence failed to reduce knockback (same thing, I forgot I commented it out smh). 76 | * Identified a flaw in elasticity calculations where it sometimes came up with half the elastic impulse it ought to. 77 | * Identified a flaw in collisions calculations where it often imparted only half the appropriate acceleration. 78 | * Fixed damage resistance factor being applied in the wrong place in damage calculations, leading to some collisions that only pushed things around, not doing any damage 79 | * Identified and fixed bug which failed to apply hooke field impulse upon collision. 80 | * Made skillpoint text not change color when body damage is maxed out. 81 | * Fixed missing Predator and Gatling names. 82 | * Fixed Death Star upgrade path from Destroyer. 83 | 84 | **Known Bugs/Things That Aren't Going To Change In The Mockup:** 85 | 86 | * Drones can be really bouncy against each other. I'm not sure how to fix it; we'll call this one a known bug until I can figure out some better way to handle drone-to-drone collisions. 87 | * Traps, on the other hand, don't interact. 88 | * Reload timing gets messed up with upgrades and skill changes. This is already fixed in the web version. 89 | * No room borders. This is already in the web version. 90 | * Text rendering/graphics are blocky and ugly. This is already fixed in the web version. 91 | * Trapezoid/traps have wonky borders. This is already fixed in the web version. 92 | * In the upgrade menu large tanks can be clipped. This is already fixed in the web version. -------------------------------------------------------------------------------- /arrasio/src/client/js/canvas.js: -------------------------------------------------------------------------------- 1 | var global = require('./lib/global'); 2 | 3 | class Canvas { 4 | constructor(params) { 5 | this.directionLock = false; 6 | this.target = global.target; 7 | this.reenviar = true; 8 | this.socket = global.socket; 9 | this.directions = []; 10 | var self = this; 11 | 12 | this.cv = document.getElementById('gameCanvas'); 13 | this.cv.width = global.screenWidth; 14 | this.cv.height = global.screenHeight; 15 | this.cv.addEventListener('mousemove', this.gameInput, false); 16 | this.cv.addEventListener('keydown', this.keyboardDown, false); 17 | this.cv.addEventListener('keyup', this.keyboardUp, false); 18 | this.cv.addEventListener("mousedown", this.mouseDown, false); 19 | this.cv.addEventListener("mouseup", this.mouseUp, false); 20 | this.cv.parent = self; 21 | global.canvas = this; 22 | } 23 | 24 | keyboardDown(event) { 25 | switch (event.keyCode) { 26 | case 13: if (global.died) this.parent.socket.talk('s', global.playerName, 0); global.died = false; break; // Enter to respawn 27 | case global.KEY_UP_ARROW: 28 | case global.KEY_UP: this.parent.socket.cmd.set(0, true); break; 29 | case global.KEY_DOWN_ARROW: 30 | case global.KEY_DOWN: this.parent.socket.cmd.set(1, true); break; 31 | case global.KEY_LEFT_ARROW: 32 | case global.KEY_LEFT: this.parent.socket.cmd.set(2, true); break; 33 | case global.KEY_RIGHT_ARROW: 34 | case global.KEY_RIGHT: this.parent.socket.cmd.set(3, true); break; 35 | case global.KEY_MOUSE_0: this.parent.socket.cmd.set(4, true); break; 36 | case global.KEY_MOUSE_1: this.parent.socket.cmd.set(5, true); break; 37 | case global.KEY_MOUSE_2: this.parent.socket.cmd.set(6, true); break; 38 | case global.KEY_LEVEL_UP: this.parent.socket.talk('L'); break; 39 | case global.KEY_FUCK_YOU: this.parent.socket.talk('0'); break; 40 | } 41 | if (!event.repeat) { 42 | switch (event.keyCode) { 43 | case global.KEY_AUTO_SPIN: this.parent.socket.talk('t', 0); break; 44 | case global.KEY_AUTO_FIRE: this.parent.socket.talk('t', 1); break; 45 | case global.KEY_OVER_RIDE: this.parent.socket.talk('t', 2); break; 46 | } 47 | if (global.canSkill) { 48 | switch (event.keyCode) { 49 | case global.KEY_UPGRADE_ATK: this.parent.socket.talk('x', 0); break; 50 | case global.KEY_UPGRADE_HTL: this.parent.socket.talk('x', 1); break; 51 | case global.KEY_UPGRADE_SPD: this.parent.socket.talk('x', 2); break; 52 | case global.KEY_UPGRADE_STR: this.parent.socket.talk('x', 3); break; 53 | case global.KEY_UPGRADE_PEN: this.parent.socket.talk('x', 4); break; 54 | case global.KEY_UPGRADE_DAM: this.parent.socket.talk('x', 5); break; 55 | case global.KEY_UPGRADE_RLD: this.parent.socket.talk('x', 6); break; 56 | case global.KEY_UPGRADE_MOB: this.parent.socket.talk('x', 7); break; 57 | case global.KEY_UPGRADE_RGN: this.parent.socket.talk('x', 8); break; 58 | case global.KEY_UPGRADE_SHI: this.parent.socket.talk('x', 9); break; 59 | } 60 | } 61 | if (global.canUpgrade) { 62 | switch (event.keyCode) { 63 | case global.KEY_CHOOSE_1: this.parent.socket.talk('U', 0); break; 64 | case global.KEY_CHOOSE_2: this.parent.socket.talk('U', 1); break; 65 | case global.KEY_CHOOSE_3: this.parent.socket.talk('U', 2); break; 66 | case global.KEY_CHOOSE_4: this.parent.socket.talk('U', 3); break; 67 | case global.KEY_CHOOSE_5: this.parent.socket.talk('U', 4); break; 68 | case global.KEY_CHOOSE_6: this.parent.socket.talk('U', 5); break; 69 | case global.KEY_CHOOSE_7: this.parent.socket.talk('U', 6); break; 70 | case global.KEY_CHOOSE_8: this.parent.socket.talk('U', 7); break; 71 | } 72 | } 73 | } 74 | } 75 | keyboardUp(event) { 76 | switch (event.keyCode) { 77 | case global.KEY_UP_ARROW: 78 | case global.KEY_UP: this.parent.socket.cmd.set(0, false); break; 79 | case global.KEY_DOWN_ARROW: 80 | case global.KEY_DOWN: this.parent.socket.cmd.set(1, false); break; 81 | case global.KEY_LEFT_ARROW: 82 | case global.KEY_LEFT: this.parent.socket.cmd.set(2, false); break; 83 | case global.KEY_RIGHT_ARROW: 84 | case global.KEY_RIGHT: this.parent.socket.cmd.set(3, false); break; 85 | case global.KEY_MOUSE_0: this.parent.socket.cmd.set(4, false); break; 86 | case global.KEY_MOUSE_1: this.parent.socket.cmd.set(5, false); break; 87 | case global.KEY_MOUSE_2: this.parent.socket.cmd.set(6, false); break; 88 | } 89 | } 90 | mouseDown(mouse) { 91 | switch (mouse.button) { 92 | case 0: 93 | let mpos = { x: mouse.clientX, y: mouse.clientY, }; 94 | let statIndex = global.clickables.stat.check(mpos); 95 | if (statIndex !== -1) this.parent.socket.talk('x', statIndex); 96 | else if (global.clickables.skipUpgrades.check(mpos) !== -1) global.clearUpgrades(); 97 | else { 98 | let upgradeIndex = global.clickables.upgrade.check(mpos); 99 | if (upgradeIndex !== -1) this.parent.socket.talk('U', upgradeIndex); 100 | else this.parent.socket.cmd.set(4, true); 101 | } 102 | break; 103 | case 1: this.parent.socket.cmd.set(5, true); break; 104 | case 2: this.parent.socket.cmd.set(6, true); break; 105 | } 106 | } 107 | mouseUp(mouse) { 108 | switch (mouse.button) { 109 | case 0: this.parent.socket.cmd.set(4, false); break; 110 | case 1: this.parent.socket.cmd.set(5, false); break; 111 | case 2: this.parent.socket.cmd.set(6, false); break; 112 | } 113 | } 114 | // Mouse location (we send target information in the heartbeat) 115 | gameInput(mouse) { 116 | this.parent.target.x = mouse.clientX - this.width / 2; 117 | this.parent.target.y = mouse.clientY - this.height / 2; 118 | global.target = this.parent.target; 119 | global.statHover = global.clickables.hover.check({ x: mouse.clientX, y: mouse.clientY, }) === 0; 120 | } 121 | 122 | } 123 | 124 | module.exports = Canvas; 125 | -------------------------------------------------------------------------------- /arrasio/src/client/css/main.css: -------------------------------------------------------------------------------- 1 | * { 2 | font-family: Ubuntu; 3 | font-size: 14px; 4 | } 5 | 6 | .conceal { 7 | -webkit-text-security: disc; 8 | } 9 | 10 | #mainBody { 11 | background-color: #484848; 12 | } 13 | 14 | html, body, canvas { 15 | width: 100%; 16 | height: 100%; 17 | margin: 0; 18 | padding: 0; 19 | } 20 | 21 | h1 { 22 | padding: 0; 23 | margin-top: 5px; 24 | margin-bottom: 10px; 25 | text-align: center; 26 | font-size: xx-large; 27 | font-weight: bolder; 28 | } 29 | 30 | h2 { 31 | font-size: small; 32 | color: #000000; 33 | font-weight: bold; 34 | text-align: center; 35 | } 36 | 37 | optionsHeader { 38 | padding: 0; 39 | padding-bottom: 5px; 40 | margin: 0; 41 | font-size: small; 42 | color: #000000; 43 | font-weight: bold; 44 | text-align: center; 45 | } 46 | 47 | h3 { 48 | font-size: small; 49 | color: #484848; 50 | font-style: italic; 51 | text-align: center; 52 | } 53 | 54 | h4 { 55 | font-size: small; 56 | color: #8ABC3F; 57 | text-align: center; 58 | } 59 | 60 | h5 { 61 | font-size: x-small; 62 | color: #484848; 63 | text-align: center; 64 | } 65 | 66 | small { 67 | font-size: x-small; 68 | } 69 | 70 | a:link, a:visited { 71 | color: #484848; 72 | } 73 | a:hover { 74 | color: #B5B5B9; 75 | } 76 | 77 | ul { 78 | padding-left: 15px; 79 | margin-left: 10px; 80 | } 81 | 82 | input { 83 | text-align: center; 84 | width: 100%; 85 | padding: 10px; 86 | border: solid 1px #dcdcdc; 87 | transition: box-shadow 0.3s, border 0.3s; 88 | box-sizing: border-box; 89 | border-radius: 5px; 90 | -moz-border-radius: 5px; 91 | -webkit-border-radius: 5px; 92 | margin-top: 5px; 93 | margin-bottom: 5px; 94 | outline: none; 95 | } 96 | 97 | input.checkbox { 98 | width: 13px; 99 | height: 13px; 100 | padding: 0; 101 | margin: 0; 102 | vertical-align: bottom; 103 | position: relative; 104 | top: -2px; 105 | *overflow: hidden; 106 | } 107 | 108 | #playerNameInput { 109 | padding: 10px; 110 | font-size: larger; 111 | } 112 | 113 | #playerKeyInput { 114 | padding: 3px; 115 | color: gray; 116 | } 117 | 118 | input:focus, input.focus { 119 | border: solid 1px #CCCCCC; 120 | box-shadow: 0 0 3px 1px #DDDDDD; 121 | } 122 | 123 | div { 124 | -webkit-user-select: none; /* webkit (safari, chrome) browsers */ 125 | -moz-user-select: none; /* mozilla browsers */ 126 | -khtml-user-select: none; /* webkit (konqueror) browsers */ 127 | -ms-user-select: none; /* IE10+ */ 128 | } 129 | 130 | #startMenu { 131 | position: relative; 132 | margin: auto; 133 | width: 1150px; 134 | padding: 10px; 135 | margin-top: 100px; 136 | margin-bottom: 100px; 137 | border-radius: 5px; 138 | -moz-border-radius: 5px; 139 | -webkit-border-radius: 5px; 140 | background-color: #DDE6EB; 141 | box-sizing: border-box; 142 | overflow: hidden; 143 | } 144 | #startMenuHeader { 145 | text-align: left; 146 | width: 100%; 147 | height: 100%; 148 | } 149 | 150 | .startMenuHolder { 151 | width: 350px; 152 | height: 340px; 153 | padding: 10px; 154 | overflow: hidden; 155 | display: inline-block; 156 | vertical-align: text-top; 157 | } 158 | 159 | .sliderHolder { 160 | width: 350px; 161 | height: 285px; 162 | overflow: hidden; 163 | } 164 | 165 | td { 166 | width: 50%; 167 | } 168 | 169 | table { 170 | width: 100%; 171 | } 172 | 173 | .slider { 174 | position: relative; 175 | top: 0px; 176 | width: 100%; 177 | -webkit-transition: top 500ms; 178 | -moz-transition: top 500ms; 179 | -o-transition: top 500ms; 180 | transition: top 500ms; 181 | } 182 | 183 | #startMenuSlidingContent { 184 | height: 265px; 185 | } 186 | 187 | #startMenuSlidingTrigger { 188 | cursor: pointer; 189 | height: 15px; 190 | } 191 | #startMenuSlidingTrigger:hover { 192 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); 193 | } 194 | 195 | update { 196 | color: #D83848; 197 | font-weight: bold; 198 | } 199 | 200 | #patchNotesIFrame { 201 | width: 350px; 202 | height: 335px; 203 | } 204 | 205 | #patchNotes { 206 | padding: 10px; 207 | width: 90%; 208 | height: 100%; 209 | overflow: auto; 210 | } 211 | 212 | #startButton { 213 | position: relative; 214 | margin: auto; 215 | width: 100%; 216 | height: 40px; 217 | box-sizing: border-box; 218 | font-size: larger; 219 | color: white; 220 | text-align: center; 221 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); 222 | background: #B9E87E; 223 | border: 0; 224 | border-bottom: 2px solid #8ABC3F; 225 | cursor: pointer; 226 | -webkit-box-shadow: inset 0 -2px #8ABC3F; 227 | box-shadow: inset 0 -2px #8ABC3F; 228 | border-radius: 5px; 229 | -moz-border-radius: 5px; 230 | -webkit-border-radius: 5px; 231 | } 232 | #startButton:active, #startButton:hover { 233 | top: 1px; 234 | background: #8ABC3F; 235 | outline: none; 236 | -webkit-box-shadow: none; 237 | box-shadow: none; 238 | } 239 | 240 | form { 241 | display: inline-block; 242 | } 243 | 244 | #bottomHolder { 245 | text-align: right; 246 | } 247 | #donate { 248 | position: relative; 249 | margin: 2px; 250 | padding: 5px; 251 | width: 80px; 252 | box-sizing: border-box; 253 | font-size: smaller; 254 | color: white; 255 | text-align: center; 256 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); 257 | background: #B58EFD; 258 | border: 0; 259 | border-bottom: 2px solid #8D6ADF; 260 | cursor: pointer; 261 | -webkit-box-shadow: inset 0 -2px #8D6ADF; 262 | box-shadow: inset 0 -2px #8D6ADF; 263 | border-radius: 5px; 264 | -moz-border-radius: 5px; 265 | -webkit-border-radius: 5px; 266 | } 267 | #donate:active, #donate:hover { 268 | top: 1px; 269 | background: #8D6ADF; 270 | outline: none; 271 | -webkit-box-shadow: none; 272 | box-shadow: none; 273 | } 274 | 275 | #pledge { 276 | position: relative; 277 | margin: 2px; 278 | padding: 5px; 279 | width: 80px; 280 | box-sizing: border-box; 281 | font-size: smaller; 282 | color: white; 283 | text-align: center; 284 | text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25); 285 | background: #E7896D; 286 | border: 0; 287 | border-bottom: 2px solid #D83848; 288 | cursor: pointer; 289 | -webkit-box-shadow: inset 0 -2px #D83848; 290 | box-shadow: inset 0 -2px #D83848; 291 | border-radius: 5px; 292 | -moz-border-radius: 5px; 293 | -webkit-border-radius: 5px; 294 | } 295 | #pledge:active, #pledge:hover { 296 | top: 1px; 297 | background: #D83848; 298 | outline: none; 299 | -webkit-box-shadow: none; 300 | box-shadow: none; 301 | } 302 | 303 | #startMenuWrapper { 304 | -webkit-transition: max-height 1s; 305 | -moz-transition: max-height 1s; 306 | -ms-transition: max-height 1s; 307 | -o-transition: max-height 1s; 308 | transition: max-height 1s; 309 | overflow: hidden; 310 | } 311 | 312 | .nopadding { 313 | padding : 0; 314 | margin: 0; 315 | } 316 | 317 | #startMenu ul { 318 | margin: 10px; 319 | padding: 10px; 320 | margin-top: 0; 321 | } 322 | 323 | #startMenu .input-error { 324 | color: red; 325 | opacity: 0; 326 | font-size : 12px; 327 | } 328 | 329 | #startMenuWrapper { 330 | z-index: 2; 331 | } 332 | 333 | #gameAreaWrapper { 334 | position: absolute !important; 335 | top: 0; 336 | left: 0; 337 | opacity: 0; 338 | } 339 | 340 | input [type="image"]:focus{ 341 | border:none; 342 | outline: 1px solid transparent; 343 | border-style: none; 344 | } 345 | 346 | *:focus { 347 | outline: 1px solid transparent; 348 | border-style: none; 349 | } 350 | -------------------------------------------------------------------------------- /arrasio/src/server/lib/fasttalk.js: -------------------------------------------------------------------------------- 1 | /*jslint esversion: 6*/ 2 | /*function checkEndian() { 3 | var arrayBuffer = new ArrayBuffer(2); 4 | var uint8Array = new Uint8Array(arrayBuffer); 5 | var uint16array = new Uint16Array(arrayBuffer); 6 | uint8Array[0] = 0xAA; // set first byte 7 | uint8Array[1] = 0xBB; // set second byte 8 | if(uint16array[0] === 0xBBAA) return 0; 9 | if(uint16array[0] === 0xAABB) return 1; 10 | else throw new Error("Something crazy just happened"); 11 | } 12 | var isBigEndian = new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x12; 13 | var isLittleEndian = new Uint8Array(new Uint32Array([0x12345678]).buffer)[0] === 0x78;*/ 14 | 15 | exports.encode = (() => { 16 | // unsigned 8-bit integer 17 | var arrUint8 = new Uint8Array(1); 18 | // unsigned 16-bit integer 19 | var arrUint16 = new Uint16Array(1); 20 | var charUint16 = new Uint8Array(arrUint16.buffer); 21 | // unsigned 32-bit integer 22 | var arrUint32 = new Uint32Array(1); 23 | var charUint32 = new Uint8Array(arrUint32.buffer); 24 | // 32-bit float 25 | var arrFloat32 = new Float32Array(1); 26 | var charFloat32 = new Uint8Array(arrFloat32.buffer); 27 | // build some useful internal functions 28 | var typeEncoder = (type, number) => { 29 | let output = ''; 30 | switch (type) { 31 | case 'RawUint8': 32 | arrUint8[0] = number; 33 | return String.fromCharCode(arrUint8[0]); 34 | case 'RawUint16': 35 | arrUint16[0] = number; 36 | return String.fromCharCode(charUint16[0], charUint16[1]); 37 | case 'Uint8': 38 | arrUint8[0] = number; 39 | return '0' + String.fromCharCode(arrUint8[0]); 40 | case 'Uint16': 41 | arrUint16[0] = number; 42 | return '1' + String.fromCharCode(charUint16[0], charUint16[1]); 43 | case 'Uint32': 44 | arrUint32[0] = number; 45 | return '2' + String.fromCharCode(charUint32[0], charUint32[1], charUint32[2], charUint32[3]); 46 | case 'Sint8': 47 | arrUint8[0] = -1 - number; 48 | return '3' + String.fromCharCode(arrUint8[0]); 49 | case 'Sint16': 50 | arrUint16[0] = -1 - number; 51 | return '4' + String.fromCharCode(charUint16[0], charUint16[1]); 52 | case 'Sint32': 53 | arrUint32[0] = -1 - number; 54 | return '5' + String.fromCharCode(charUint32[0], charUint32[1], charUint32[2], charUint32[3]); 55 | case 'Float32': 56 | arrFloat32[0] = number; 57 | return '6' + String.fromCharCode(charFloat32[0], charFloat32[1], charFloat32[2], charFloat32[3]); 58 | case 'String8': 59 | return '7' + typeEncoder('RawUint16', number.length) + number; 60 | case 'String16': 61 | for (let i=0, strLen=number.length; i < strLen; i++) { 62 | output += typeEncoder('RawUint16', number.charCodeAt(i)); 63 | } 64 | return '8' + typeEncoder('RawUint16', output.length) + output; 65 | default: throw new Error('Unknown encoding type.'); 66 | } 67 | }; 68 | var findType = value => { 69 | if (typeof value === 'string') { 70 | for (var i = 0; i < value.length; i++) { 71 | if (value.charCodeAt(i) > 255) return 'String16'; 72 | } 73 | return 'String8'; 74 | } 75 | if (typeof value === 'boolean') return 'Uint8'; 76 | if (typeof value !== 'number') { console.log(value); throw new Error('Unencodable data type'); } 77 | if (value != Math.round(value)) return 'Float32'; 78 | if (value < 0) { 79 | if (value >= -256) return 'Sint8'; 80 | if (value >= -65535) return 'Sint16'; 81 | if (value >= -4294967295) return 'Sint32'; 82 | } else { 83 | if (value < 256) return 'Uint8'; 84 | if (value < 65535) return 'Uint16'; 85 | if (value < 4294967295) return 'Uint32'; 86 | } 87 | return 'Float32'; 88 | }; 89 | // build the function 90 | return (arr, verbose = false) => { 91 | let output = arr.splice(0, 1)[0]; 92 | if (typeof output !== 'string') throw new Error('No identification code!'); 93 | arr.forEach((value) => { output += typeEncoder(findType(value), value); }); 94 | let len = output.length; 95 | let buffer = new ArrayBuffer(len); 96 | let integerView = new Uint8Array(buffer); 97 | for (let i=0; i { 110 | // unsigned 8-bit integer (none needed) 111 | // unsigned 16-bit integer 112 | var arrUint16 = new Uint16Array(1); 113 | var charUint16 = new Uint8Array(arrUint16.buffer); 114 | // unsigned 32-bit integer 115 | var arrUint32 = new Uint32Array(1); 116 | var charUint32 = new Uint8Array(arrUint32.buffer); 117 | // 32-bit float 118 | var arrFloat32 = new Float32Array(1); 119 | var charFloat32 = new Uint8Array(arrFloat32.buffer); 120 | // build a useful internal function 121 | var typeDecoder = (str, type, offset) => { 122 | switch(type) { 123 | case 'Uint8': 124 | return str.charCodeAt(offset++); 125 | case 'Uint16': 126 | for (let i=0; i<2; i++) { 127 | charUint16[i] = str.charCodeAt(offset++); 128 | } 129 | return arrUint16[0]; 130 | case 'Uint32': 131 | for (let i=0; i<4; i++) { 132 | charUint32[i] = str.charCodeAt(offset++); 133 | } 134 | return arrUint32[0]; 135 | case 'Sint8': 136 | return -1 - str.charCodeAt(offset++); 137 | case 'Sint16': 138 | for (let i=0; i<2; i++) { 139 | charUint16[i] = str.charCodeAt(offset++); 140 | } 141 | return -1 - arrUint16[0]; 142 | case 'Sint32': 143 | for (let i=0; i<4; i++) { 144 | charUint32[i] = str.charCodeAt(offset++); 145 | } 146 | return -1 - arrUint32[0]; 147 | case 'Float32': 148 | for (let i=0; i<4; i++) { 149 | charFloat32[i] = str.charCodeAt(offset++); 150 | } 151 | return arrFloat32[0]; 152 | default: throw new Error('Unknown decoding type.'); 153 | } 154 | }; 155 | // actually decode it 156 | return raw => { try { 157 | let intView = new Uint8Array(raw); 158 | let str = ''; 159 | for (let i=0, len=intView.length; i { 20 | // unsigned 8-bit integer 21 | var arrUint8 = new Uint8Array(1); 22 | // unsigned 16-bit integer 23 | var arrUint16 = new Uint16Array(1); 24 | var charUint16 = new Uint8Array(arrUint16.buffer); 25 | // unsigned 32-bit integer 26 | var arrUint32 = new Uint32Array(1); 27 | var charUint32 = new Uint8Array(arrUint32.buffer); 28 | // 32-bit float 29 | var arrFloat32 = new Float32Array(1); 30 | var charFloat32 = new Uint8Array(arrFloat32.buffer); 31 | // build some useful internal functions 32 | var typeEncoder = (type, number) => { 33 | let output = ''; 34 | switch (type) { 35 | case 'RawUint8': 36 | arrUint8[0] = number; 37 | return String.fromCharCode(arrUint8[0]); 38 | case 'RawUint16': 39 | arrUint16[0] = number; 40 | return String.fromCharCode(charUint16[0], charUint16[1]); 41 | case 'Uint8': 42 | arrUint8[0] = number; 43 | return '0' + String.fromCharCode(arrUint8[0]); 44 | case 'Uint16': 45 | arrUint16[0] = number; 46 | return '1' + String.fromCharCode(charUint16[0], charUint16[1]); 47 | case 'Uint32': 48 | arrUint32[0] = number; 49 | return '2' + String.fromCharCode(charUint32[0], charUint32[1], charUint32[2], charUint32[3]); 50 | case 'Sint8': 51 | arrUint8[0] = -1 - number; 52 | return '3' + String.fromCharCode(arrUint8[0]); 53 | case 'Sint16': 54 | arrUint16[0] = -1 - number; 55 | return '4' + String.fromCharCode(charUint16[0], charUint16[1]); 56 | case 'Sint32': 57 | arrUint32[0] = -1 - number; 58 | return '5' + String.fromCharCode(charUint32[0], charUint32[1], charUint32[2], charUint32[3]); 59 | case 'Float32': 60 | arrFloat32[0] = number; 61 | return '6' + String.fromCharCode(charFloat32[0], charFloat32[1], charFloat32[2], charFloat32[3]); 62 | case 'String8': 63 | return '7' + typeEncoder('RawUint16', number.length) + number; 64 | case 'String16': 65 | for (let i=0, strLen=number.length; i < strLen; i++) { 66 | output += typeEncoder('RawUint16', number.charCodeAt(i)); 67 | } 68 | return '8' + typeEncoder('RawUint16', output.length) + output; 69 | default: throw new Error('Unknown encoding type.'); 70 | } 71 | }; 72 | var findType = (value) => { 73 | if (typeof value === 'string') { 74 | for (var i = 0; i < value.length; i++) { 75 | if (value.charCodeAt(i) > 255) return 'String16'; 76 | } 77 | return 'String8'; 78 | } 79 | if (typeof value === 'boolean') return 'Uint8'; 80 | if (typeof value !== 'number') { throw new Error('Unencodable data type'); } 81 | if (value != Math.round(value)) return 'Float32'; 82 | if (value < 0) { 83 | if (value >= -256) return 'Sint8'; 84 | if (value >= -65535) return 'Sint16'; 85 | if (value >= -4294967295) return 'Sint32'; 86 | } else { 87 | if (value < 256) return 'Uint8'; 88 | if (value < 65535) return 'Uint16'; 89 | if (value < 4294967295) return 'Uint32'; 90 | } 91 | return 'Float32'; 92 | }; 93 | // build the function 94 | return (arr, verbose = false) => { 95 | let output = arr.splice(0, 1)[0]; 96 | if (typeof output !== 'string') throw new Error('No identification code!'); 97 | arr.forEach((value) => { output += typeEncoder(findType(value), value); }); 98 | let len = output.length; 99 | let buffer = new ArrayBuffer(len); 100 | let integerView = new Uint8Array(buffer); 101 | for (let i=0; i { 114 | // unsigned 8-bit integer (none needed) 115 | // unsigned 16-bit integer 116 | var arrUint16 = new Uint16Array(1); 117 | var charUint16 = new Uint8Array(arrUint16.buffer); 118 | // unsigned 32-bit integer 119 | var arrUint32 = new Uint32Array(1); 120 | var charUint32 = new Uint8Array(arrUint32.buffer); 121 | // 32-bit float 122 | var arrFloat32 = new Float32Array(1); 123 | var charFloat32 = new Uint8Array(arrFloat32.buffer); 124 | // build a useful internal function 125 | var typeDecoder = (str, type, offset) => { 126 | switch(type) { 127 | case 'Uint8': 128 | return str.charCodeAt(offset++); 129 | case 'Uint16': 130 | for (let i=0; i<2; i++) { 131 | charUint16[i] = str.charCodeAt(offset++); 132 | } 133 | return arrUint16[0]; 134 | case 'Uint32': 135 | for (let i=0; i<4; i++) { 136 | charUint32[i] = str.charCodeAt(offset++); 137 | } 138 | return arrUint32[0]; 139 | case 'Sint8': 140 | return -1 - str.charCodeAt(offset++); 141 | case 'Sint16': 142 | for (let i=0; i<2; i++) { 143 | charUint16[i] = str.charCodeAt(offset++); 144 | } 145 | return -1 - arrUint16[0]; 146 | case 'Sint32': 147 | for (let i=0; i<4; i++) { 148 | charUint32[i] = str.charCodeAt(offset++); 149 | } 150 | return -1 - arrUint32[0]; 151 | case 'Float32': 152 | for (let i=0; i<4; i++) { 153 | charFloat32[i] = str.charCodeAt(offset++); 154 | } 155 | return arrFloat32[0]; 156 | default: throw new Error('Unknown decoding type.'); 157 | } 158 | }; 159 | // actually decode it 160 | return raw => { try { 161 | let intView = new Uint8Array(raw); 162 | let str = ''; 163 | for (let i=0, len=intView.length; i 2 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | arras.io beta 14 | 15 | 16 | 17 | 18 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 |
60 | 61 |
62 |
63 |
64 |
65 | 68 |
69 |
70 |
71 |
72 |

arras.io beta

73 |

Connecting...

74 | 75 | 76 |
77 |

view options/help 🡲

78 |
79 |
80 | Advanced Controls:
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 |
E: auto-fireC: auto-spin
R: disable auto-weaponsN: level up (sandbox)
91 | Options: 92 | 104 | 110 | 111 | 112 | 115 | 118 | 119 | 122 | 125 | 126 | 127 |
113 | 114 |
116 | 117 |
120 | 121 |
123 | 124 |
128 |
129 |
130 |
131 | 132 |
133 |
134 |
135 | 136 |
137 |
138 |
Help support the dev:
139 |
140 | 141 |
142 |
143 | 144 | 145 | 146 | 147 |
148 |
149 |
150 |
151 |
152 | 153 | 154 | 155 | 169 | 182 | 183 | -------------------------------------------------------------------------------- /arrasio/src/server/lib/hshg.js: -------------------------------------------------------------------------------- 1 | // Hierarchical Spatial Hash Grid: HSHG 2 | // https://gist.github.com/kirbysayshi/1760774 3 | 4 | (function(root, undefined){ 5 | 6 | //--------------------------------------------------------------------- 7 | // GLOBAL FUNCTIONS 8 | //--------------------------------------------------------------------- 9 | 10 | /** 11 | * Updates every object's position in the grid, but only if 12 | * the hash value for that object has changed. 13 | * This method DOES NOT take into account object expansion or 14 | * contraction, just position, and does not attempt to change 15 | * the grid the object is currently in; it only (possibly) changes 16 | * the cell. 17 | * 18 | * If the object has significantly changed in size, the best bet is to 19 | * call removeObject() and addObject() sequentially, outside of the 20 | * normal update cycle of HSHG. 21 | * 22 | * @return void desc 23 | */ 24 | function update_RECOMPUTE(){ 25 | 26 | var i 27 | ,obj 28 | ,grid 29 | ,meta 30 | ,objAABB 31 | ,newObjHash; 32 | 33 | // for each object 34 | for(i = 0; i < this._globalObjects.length; i++){ 35 | obj = this._globalObjects[i]; 36 | meta = obj.HSHG; 37 | grid = meta.grid; 38 | 39 | // recompute hash 40 | objAABB = obj.getAABB(); 41 | newObjHash = grid.toHash(objAABB.min[0], objAABB.min[1]); 42 | 43 | if(newObjHash !== meta.hash){ 44 | // grid position has changed, update! 45 | grid.removeObject(obj); 46 | grid.addObject(obj, newObjHash); 47 | } 48 | } 49 | } 50 | 51 | // not implemented yet :) 52 | function update_REMOVEALL(){ 53 | 54 | } 55 | 56 | function testAABBOverlap(objA, objB){ 57 | var a = objA.getAABB() 58 | ,b = objB.getAABB(); 59 | 60 | //if(a.min[0] > b.max[0] || a.min[1] > b.max[1] || a.min[2] > b.max[2] 61 | //|| a.max[0] < b.min[0] || a.max[1] < b.min[1] || a.max[2] < b.min[2]){ 62 | if (!a.active && !b.active) return false; 63 | 64 | if(a.min[0] > b.max[0] || a.min[1] > b.max[1] 65 | || a.max[0] < b.min[0] || a.max[1] < b.min[1]){ 66 | return false; 67 | } else { 68 | return true; 69 | } 70 | } 71 | 72 | function getLongestAABBEdge(min, max){ 73 | return Math.max( 74 | Math.abs(max[0] - min[0]) 75 | ,Math.abs(max[1] - min[1]) 76 | //,Math.abs(max[2] - min[2]) 77 | ); 78 | } 79 | 80 | //--------------------------------------------------------------------- 81 | // ENTITIES 82 | //--------------------------------------------------------------------- 83 | 84 | function HSHG(){ 85 | 86 | this.MAX_OBJECT_CELL_DENSITY = 1/8 // objects / cells 87 | this.INITIAL_GRID_LENGTH = 256 // 16x16 88 | this.HIERARCHY_FACTOR = 2 89 | this.HIERARCHY_FACTOR_SQRT = Math.SQRT2 90 | this.UPDATE_METHOD = update_RECOMPUTE // or update_REMOVEALL 91 | 92 | this._grids = []; 93 | this._globalObjects = []; 94 | } 95 | 96 | //HSHG.prototype.init = function(){ 97 | // this._grids = []; 98 | // this._globalObjects = []; 99 | //} 100 | 101 | HSHG.prototype.addObject = function(obj){ 102 | var x ,i 103 | ,cellSize 104 | ,objAABB = obj.getAABB() 105 | ,objSize = getLongestAABBEdge(objAABB.min, objAABB.max) 106 | ,oneGrid, newGrid; 107 | 108 | // for HSHG metadata 109 | obj.HSHG = { 110 | globalObjectsIndex: this._globalObjects.length 111 | }; 112 | 113 | // add to global object array 114 | this._globalObjects.push(obj); 115 | 116 | if(this._grids.length == 0) { 117 | // no grids exist yet 118 | cellSize = objSize * this.HIERARCHY_FACTOR_SQRT; 119 | newGrid = new Grid(cellSize, this.INITIAL_GRID_LENGTH, this); 120 | newGrid.initCells(); 121 | newGrid.addObject(obj); 122 | 123 | this._grids.push(newGrid); 124 | } else { 125 | x = 0; 126 | 127 | // grids are sorted by cellSize, smallest to largest 128 | for(i = 0; i < this._grids.length; i++){ 129 | oneGrid = this._grids[i]; 130 | x = oneGrid.cellSize; 131 | if(objSize < x){ 132 | x = x / this.HIERARCHY_FACTOR; 133 | if(objSize < x) { 134 | // find appropriate size 135 | while( objSize < x ) { 136 | x = x / this.HIERARCHY_FACTOR; 137 | } 138 | newGrid = new Grid(x * this.HIERARCHY_FACTOR, this.INITIAL_GRID_LENGTH, this); 139 | newGrid.initCells(); 140 | // assign obj to grid 141 | newGrid.addObject(obj) 142 | // insert grid into list of grids directly before oneGrid 143 | this._grids.splice(i, 0, newGrid); 144 | } else { 145 | // insert obj into grid oneGrid 146 | oneGrid.addObject(obj); 147 | } 148 | return; 149 | } 150 | } 151 | 152 | while( objSize >= x ){ 153 | x = x * this.HIERARCHY_FACTOR; 154 | } 155 | 156 | newGrid = new Grid(x, this.INITIAL_GRID_LENGTH, this); 157 | newGrid.initCells(); 158 | // insert obj into grid 159 | newGrid.addObject(obj) 160 | // add newGrid as last element in grid list 161 | this._grids.push(newGrid); 162 | } 163 | } 164 | 165 | HSHG.prototype.checkIfInHSHG = function(obj){ 166 | var meta = obj.HSHG 167 | ,globalObjectsIndex 168 | ,replacementObj; 169 | 170 | if(meta === undefined) return false; 171 | return true; 172 | } 173 | 174 | HSHG.prototype.removeObject = function(obj){ 175 | var meta = obj.HSHG 176 | ,globalObjectsIndex 177 | ,replacementObj; 178 | 179 | if(meta === undefined){ 180 | throw Error( obj + ' was not in the HSHG.' ); 181 | return; 182 | } 183 | 184 | // remove object from global object list 185 | globalObjectsIndex = meta.globalObjectsIndex 186 | if(globalObjectsIndex === this._globalObjects.length - 1){ 187 | this._globalObjects.pop(); 188 | } else { 189 | replacementObj = this._globalObjects.pop(); 190 | replacementObj.HSHG.globalObjectsIndex = globalObjectsIndex; 191 | this._globalObjects[ globalObjectsIndex ] = replacementObj; 192 | } 193 | 194 | meta.grid.removeObject(obj); 195 | 196 | // remove meta data 197 | delete obj.HSHG; 198 | } 199 | 200 | HSHG.prototype.update = function(){ 201 | this.UPDATE_METHOD.call(this); 202 | } 203 | 204 | HSHG.prototype.queryForCollisionPairs = function(broadOverlapTestCallback){ 205 | 206 | var i, j, k, l, c 207 | ,grid 208 | ,cell 209 | ,objA 210 | ,objB 211 | ,offset 212 | ,adjacentCell 213 | ,biggerGrid 214 | ,objAAABB 215 | ,objAHashInBiggerGrid 216 | ,possibleCollisions = [] 217 | 218 | // default broad test to internal aabb overlap test 219 | broadOverlapTest = broadOverlapTestCallback || testAABBOverlap; 220 | 221 | // for all grids ordered by cell size ASC 222 | for(i = 0; i < this._grids.length; i++){ 223 | grid = this._grids[i]; 224 | 225 | // for each cell of the grid that is occupied 226 | for(j = 0; j < grid.occupiedCells.length; j++){ 227 | cell = grid.occupiedCells[j]; 228 | 229 | // collide all objects within the occupied cell 230 | for(k = 0; k < cell.objectContainer.length; k++){ 231 | objA = cell.objectContainer[k]; 232 | if (!objA.getAABB().active) continue; 233 | for(l = k+1; l < cell.objectContainer.length; l++){ 234 | objB = cell.objectContainer[l]; 235 | if (!objB.getAABB().active) continue; 236 | if(broadOverlapTest(objA, objB) === true){ 237 | possibleCollisions.push( [ objA, objB ] ); 238 | } 239 | } 240 | } 241 | 242 | // for the first half of all adjacent cells (offset 4 is the current cell) 243 | for(c = 0; c < 4; c++){ 244 | offset = cell.neighborOffsetArray[c]; 245 | 246 | //if(offset === null) { continue; } 247 | 248 | adjacentCell = grid.allCells[ cell.allCellsIndex + offset ]; 249 | 250 | // collide all objects in cell with adjacent cell 251 | for(k = 0; k < cell.objectContainer.length; k++){ 252 | objA = cell.objectContainer[k]; 253 | if (!objA.getAABB().active) continue; 254 | for(l = 0; l < adjacentCell.objectContainer.length; l++){ 255 | objB = adjacentCell.objectContainer[l]; 256 | if (!objB.getAABB().active) continue; 257 | if(broadOverlapTest(objA, objB) === true){ 258 | possibleCollisions.push( [ objA, objB ] ); 259 | } 260 | } 261 | } 262 | } 263 | } 264 | 265 | // forall objects that are stored in this grid 266 | for(j = 0; j < grid.allObjects.length; j++){ 267 | objA = grid.allObjects[j]; 268 | objAAABB = objA.getAABB(); 269 | if (!objAAABB.active) continue; 270 | // for all grids with cellsize larger than grid 271 | for(k = i + 1; k < this._grids.length; k++){ 272 | biggerGrid = this._grids[k]; 273 | objAHashInBiggerGrid = biggerGrid.toHash(objAAABB.min[0], objAAABB.min[1]); 274 | cell = biggerGrid.allCells[objAHashInBiggerGrid]; 275 | 276 | // check objA against every object in all cells in offset array of cell 277 | // for all adjacent cells... 278 | for(c = 0; c < cell.neighborOffsetArray.length; c++){ 279 | offset = cell.neighborOffsetArray[c]; 280 | 281 | //if(offset === null) { continue; } 282 | 283 | adjacentCell = biggerGrid.allCells[ cell.allCellsIndex + offset ]; 284 | 285 | // for all objects in the adjacent cell... 286 | for(l = 0; l < adjacentCell.objectContainer.length; l++){ 287 | objB = adjacentCell.objectContainer[l]; 288 | if (!objB.getAABB().active) continue; 289 | // test against object A 290 | if(broadOverlapTest(objA, objB) === true){ 291 | possibleCollisions.push( [ objA, objB ] ); 292 | } 293 | } 294 | } 295 | } 296 | } 297 | } 298 | 299 | // return list of object pairs 300 | return possibleCollisions; 301 | } 302 | 303 | HSHG.update_RECOMPUTE = update_RECOMPUTE; 304 | HSHG.update_REMOVEALL = update_REMOVEALL; 305 | 306 | /** 307 | * Grid 308 | * 309 | * @constructor 310 | * @param int cellSize the pixel size of each cell of the grid 311 | * @param int cellCount the total number of cells for the grid (width x height) 312 | * @param HSHG parentHierarchy the HSHG to which this grid belongs 313 | * @return void 314 | */ 315 | function Grid(cellSize, cellCount, parentHierarchy){ 316 | this.cellSize = cellSize; 317 | this.inverseCellSize = 1/cellSize; 318 | this.rowColumnCount = ~~Math.sqrt(cellCount); 319 | this.xyHashMask = this.rowColumnCount - 1; 320 | this.occupiedCells = []; 321 | this.allCells = Array(this.rowColumnCount*this.rowColumnCount); 322 | this.allObjects = []; 323 | this.sharedInnerOffsets = []; 324 | 325 | this._parentHierarchy = parentHierarchy || null; 326 | } 327 | 328 | Grid.prototype.initCells = function(){ 329 | 330 | // TODO: inner/unique offset rows 0 and 2 may need to be 331 | // swapped due to +y being "down" vs "up" 332 | 333 | var i, gridLength = this.allCells.length 334 | ,x, y 335 | ,wh = this.rowColumnCount 336 | ,isOnRightEdge, isOnLeftEdge, isOnTopEdge, isOnBottomEdge 337 | ,innerOffsets = [ 338 | // y+ down offsets 339 | //-1 + -wh, -wh, -wh + 1, 340 | //-1, 0, 1, 341 | //wh - 1, wh, wh + 1 342 | 343 | // y+ up offsets 344 | wh - 1, wh, wh + 1, 345 | -1, 0, 1, 346 | -1 + -wh, -wh, -wh + 1 347 | ] 348 | ,leftOffset, rightOffset, topOffset, bottomOffset 349 | ,uniqueOffsets = [] 350 | ,cell; 351 | 352 | this.sharedInnerOffsets = innerOffsets; 353 | 354 | // init all cells, creating offset arrays as needed 355 | 356 | for(i = 0; i < gridLength; i++){ 357 | 358 | cell = new Cell(); 359 | // compute row (y) and column (x) for an index 360 | y = ~~(i / this.rowColumnCount); 361 | x = ~~(i - (y*this.rowColumnCount)); 362 | 363 | // reset / init 364 | isOnRightEdge = false; 365 | isOnLeftEdge = false; 366 | isOnTopEdge = false; 367 | isOnBottomEdge = false; 368 | 369 | // right or left edge cell 370 | if((x+1) % this.rowColumnCount == 0){ isOnRightEdge = true; } 371 | else if(x % this.rowColumnCount == 0){ isOnLeftEdge = true; } 372 | 373 | // top or bottom edge cell 374 | if((y+1) % this.rowColumnCount == 0){ isOnTopEdge = true; } 375 | else if(y % this.rowColumnCount == 0){ isOnBottomEdge = true; } 376 | 377 | // if cell is edge cell, use unique offsets, otherwise use inner offsets 378 | if(isOnRightEdge || isOnLeftEdge || isOnTopEdge || isOnBottomEdge){ 379 | 380 | // figure out cardinal offsets first 381 | rightOffset = isOnRightEdge === true ? -wh + 1 : 1; 382 | leftOffset = isOnLeftEdge === true ? wh - 1 : -1; 383 | topOffset = isOnTopEdge === true ? -gridLength + wh : wh; 384 | bottomOffset = isOnBottomEdge === true ? gridLength - wh : -wh; 385 | 386 | // diagonals are composites of the cardinals 387 | uniqueOffsets = [ 388 | // y+ down offset 389 | //leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset, 390 | //leftOffset, 0, rightOffset, 391 | //leftOffset + topOffset, topOffset, rightOffset + topOffset 392 | 393 | // y+ up offset 394 | leftOffset + topOffset, topOffset, rightOffset + topOffset, 395 | leftOffset, 0, rightOffset, 396 | leftOffset + bottomOffset, bottomOffset, rightOffset + bottomOffset 397 | ]; 398 | 399 | cell.neighborOffsetArray = uniqueOffsets; 400 | } else { 401 | cell.neighborOffsetArray = this.sharedInnerOffsets; 402 | } 403 | 404 | cell.allCellsIndex = i; 405 | this.allCells[i] = cell; 406 | } 407 | } 408 | 409 | Grid.prototype.toHash = function(x, y, z){ 410 | var i, xHash, yHash, zHash; 411 | 412 | if(x < 0){ 413 | i = (-x) * this.inverseCellSize; 414 | xHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask ); 415 | } else { 416 | i = x * this.inverseCellSize; 417 | xHash = ~~i & this.xyHashMask; 418 | } 419 | 420 | if(y < 0){ 421 | i = (-y) * this.inverseCellSize; 422 | yHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask ); 423 | } else { 424 | i = y * this.inverseCellSize; 425 | yHash = ~~i & this.xyHashMask; 426 | } 427 | 428 | //if(z < 0){ 429 | // i = (-z) * this.inverseCellSize; 430 | // zHash = this.rowColumnCount - 1 - ( ~~i & this.xyHashMask ); 431 | //} else { 432 | // i = z * this.inverseCellSize; 433 | // zHash = ~~i & this.xyHashMask; 434 | //} 435 | 436 | return xHash + yHash * this.rowColumnCount 437 | //+ zHash * this.rowColumnCount * this.rowColumnCount; 438 | } 439 | 440 | Grid.prototype.addObject = function(obj, hash){ 441 | var objAABB 442 | ,objHash 443 | ,targetCell; 444 | 445 | // technically, passing this in this should save some computational effort when updating objects 446 | if(hash !== undefined){ 447 | objHash = hash; 448 | } else { 449 | objAABB = obj.getAABB() 450 | objHash = this.toHash(objAABB.min[0], objAABB.min[1]) 451 | } 452 | targetCell = this.allCells[objHash]; 453 | 454 | if(targetCell.objectContainer.length === 0){ 455 | // insert this cell into occupied cells list 456 | targetCell.occupiedCellsIndex = this.occupiedCells.length; 457 | this.occupiedCells.push(targetCell); 458 | } 459 | 460 | // add meta data to obj, for fast update/removal 461 | obj.HSHG.objectContainerIndex = targetCell.objectContainer.length; 462 | obj.HSHG.hash = objHash; 463 | obj.HSHG.grid = this; 464 | obj.HSHG.allGridObjectsIndex = this.allObjects.length; 465 | // add obj to cell 466 | targetCell.objectContainer.push(obj); 467 | 468 | // we can assume that the targetCell is already a member of the occupied list 469 | 470 | // add to grid-global object list 471 | this.allObjects.push(obj); 472 | 473 | // do test for grid density 474 | if(this.allObjects.length / this.allCells.length > this._parentHierarchy.MAX_OBJECT_CELL_DENSITY){ 475 | // grid must be increased in size 476 | this.expandGrid(); 477 | } 478 | } 479 | 480 | Grid.prototype.removeObject = function(obj){ 481 | var meta = obj.HSHG 482 | ,hash 483 | ,containerIndex 484 | ,allGridObjectsIndex 485 | ,cell 486 | ,replacementCell 487 | ,replacementObj; 488 | 489 | hash = meta.hash; 490 | containerIndex = meta.objectContainerIndex; 491 | allGridObjectsIndex = meta.allGridObjectsIndex; 492 | cell = this.allCells[hash]; 493 | 494 | // remove object from cell object container 495 | if(cell.objectContainer.length === 1){ 496 | // this is the last object in the cell, so reset it 497 | cell.objectContainer.length = 0; 498 | 499 | // remove cell from occupied list 500 | if(cell.occupiedCellsIndex === this.occupiedCells.length - 1){ 501 | // special case if the cell is the newest in the list 502 | this.occupiedCells.pop(); 503 | } else { 504 | replacementCell = this.occupiedCells.pop(); 505 | replacementCell.occupiedCellsIndex = cell.occupiedCellsIndex; 506 | this.occupiedCells[ cell.occupiedCellsIndex ] = replacementCell; 507 | } 508 | 509 | cell.occupiedCellsIndex = null; 510 | } else { 511 | // there is more than one object in the container 512 | if(containerIndex === cell.objectContainer.length - 1){ 513 | // special case if the obj is the newest in the container 514 | cell.objectContainer.pop(); 515 | } else { 516 | replacementObj = cell.objectContainer.pop(); 517 | replacementObj.HSHG.objectContainerIndex = containerIndex; 518 | cell.objectContainer[ containerIndex ] = replacementObj; 519 | } 520 | } 521 | 522 | // remove object from grid object list 523 | if(allGridObjectsIndex === this.allObjects.length - 1){ 524 | this.allObjects.pop(); 525 | } else { 526 | replacementObj = this.allObjects.pop(); 527 | replacementObj.HSHG.allGridObjectsIndex = allGridObjectsIndex; 528 | this.allObjects[ allGridObjectsIndex ] = replacementObj; 529 | } 530 | } 531 | 532 | Grid.prototype.expandGrid = function(){ 533 | var i, j 534 | ,currentCellCount = this.allCells.length 535 | ,currentRowColumnCount = this.rowColumnCount 536 | ,currentXYHashMask = this.xyHashMask 537 | 538 | ,newCellCount = currentCellCount * 4 // double each dimension 539 | ,newRowColumnCount = ~~Math.sqrt(newCellCount) 540 | ,newXYHashMask = newRowColumnCount - 1 541 | ,allObjects = this.allObjects.slice(0) // duplicate array, not objects contained 542 | ,aCell 543 | ,push = Array.prototype.push; 544 | 545 | // remove all objects 546 | for(i = 0; i < allObjects.length; i++){ 547 | this.removeObject(allObjects[i]); 548 | } 549 | 550 | // reset grid values, set new grid to be 4x larger than last 551 | this.rowColumnCount = newRowColumnCount; 552 | this.allCells = Array(this.rowColumnCount*this.rowColumnCount); 553 | this.xyHashMask = newXYHashMask; 554 | 555 | // initialize new cells 556 | this.initCells(); 557 | 558 | // re-add all objects to grid 559 | for(i = 0; i < allObjects.length; i++){ 560 | this.addObject(allObjects[i]); 561 | } 562 | } 563 | 564 | /** 565 | * A cell of the grid 566 | * 567 | * @constructor 568 | * @return void desc 569 | */ 570 | function Cell(){ 571 | this.objectContainer = []; 572 | this.neighborOffsetArray; 573 | this.occupiedCellsIndex = null; 574 | this.allCellsIndex = null; 575 | } 576 | 577 | //--------------------------------------------------------------------- 578 | // EXPORTS 579 | //--------------------------------------------------------------------- 580 | 581 | root['HSHG'] = HSHG; 582 | HSHG._private = { 583 | Grid: Grid, 584 | Cell: Cell, 585 | testAABBOverlap: testAABBOverlap, 586 | getLongestAABBEdge: getLongestAABBEdge 587 | }; 588 | 589 | })(this); -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU General Public License is a free, copyleft license for 11 | software and other kinds of works. 12 | 13 | The licenses for most software and other practical works are designed 14 | to take away your freedom to share and change the works. By contrast, 15 | the GNU General Public License is intended to guarantee your freedom to 16 | share and change all versions of a program--to make sure it remains free 17 | software for all its users. We, the Free Software Foundation, use the 18 | GNU General Public License for most of our software; it applies also to 19 | any other work released this way by its authors. You can apply it to 20 | your programs, too. 21 | 22 | When we speak of free software, we are referring to freedom, not 23 | price. Our General Public Licenses are designed to make sure that you 24 | have the freedom to distribute copies of free software (and charge for 25 | them if you wish), that you receive source code or can get it if you 26 | want it, that you can change the software or use pieces of it in new 27 | free programs, and that you know you can do these things. 28 | 29 | To protect your rights, we need to prevent others from denying you 30 | these rights or asking you to surrender the rights. Therefore, you have 31 | certain responsibilities if you distribute copies of the software, or if 32 | you modify it: responsibilities to respect the freedom of others. 33 | 34 | For example, if you distribute copies of such a program, whether 35 | gratis or for a fee, you must pass on to the recipients the same 36 | freedoms that you received. You must make sure that they, too, receive 37 | or can get the source code. And you must show them these terms so they 38 | know their rights. 39 | 40 | Developers that use the GNU GPL protect your rights with two steps: 41 | (1) assert copyright on the software, and (2) offer you this License 42 | giving you legal permission to copy, distribute and/or modify it. 43 | 44 | For the developers' and authors' protection, the GPL clearly explains 45 | that there is no warranty for this free software. For both users' and 46 | authors' sake, the GPL requires that modified versions be marked as 47 | changed, so that their problems will not be attributed erroneously to 48 | authors of previous versions. 49 | 50 | Some devices are designed to deny users access to install or run 51 | modified versions of the software inside them, although the manufacturer 52 | can do so. This is fundamentally incompatible with the aim of 53 | protecting users' freedom to change the software. The systematic 54 | pattern of such abuse occurs in the area of products for individuals to 55 | use, which is precisely where it is most unacceptable. Therefore, we 56 | have designed this version of the GPL to prohibit the practice for those 57 | products. If such problems arise substantially in other domains, we 58 | stand ready to extend this provision to those domains in future versions 59 | of the GPL, as needed to protect the freedom of users. 60 | 61 | Finally, every program is threatened constantly by software patents. 62 | States should not allow patents to restrict development and use of 63 | software on general-purpose computers, but in those that do, we wish to 64 | avoid the special danger that patents applied to a free program could 65 | make it effectively proprietary. To prevent this, the GPL assures that 66 | patents cannot be used to render the program non-free. 67 | 68 | The precise terms and conditions for copying, distribution and 69 | modification follow. 70 | 71 | TERMS AND CONDITIONS 72 | 73 | 0. Definitions. 74 | 75 | "This License" refers to version 3 of the GNU General Public License. 76 | 77 | "Copyright" also means copyright-like laws that apply to other kinds of 78 | works, such as semiconductor masks. 79 | 80 | "The Program" refers to any copyrightable work licensed under this 81 | License. Each licensee is addressed as "you". "Licensees" and 82 | "recipients" may be individuals or organizations. 83 | 84 | To "modify" a work means to copy from or adapt all or part of the work 85 | in a fashion requiring copyright permission, other than the making of an 86 | exact copy. The resulting work is called a "modified version" of the 87 | earlier work or a work "based on" the earlier work. 88 | 89 | A "covered work" means either the unmodified Program or a work based 90 | on the Program. 91 | 92 | To "propagate" a work means to do anything with it that, without 93 | permission, would make you directly or secondarily liable for 94 | infringement under applicable copyright law, except executing it on a 95 | computer or modifying a private copy. Propagation includes copying, 96 | distribution (with or without modification), making available to the 97 | public, and in some countries other activities as well. 98 | 99 | To "convey" a work means any kind of propagation that enables other 100 | parties to make or receive copies. Mere interaction with a user through 101 | a computer network, with no transfer of a copy, is not conveying. 102 | 103 | An interactive user interface displays "Appropriate Legal Notices" 104 | to the extent that it includes a convenient and prominently visible 105 | feature that (1) displays an appropriate copyright notice, and (2) 106 | tells the user that there is no warranty for the work (except to the 107 | extent that warranties are provided), that licensees may convey the 108 | work under this License, and how to view a copy of this License. If 109 | the interface presents a list of user commands or options, such as a 110 | menu, a prominent item in the list meets this criterion. 111 | 112 | 1. Source Code. 113 | 114 | The "source code" for a work means the preferred form of the work 115 | for making modifications to it. "Object code" means any non-source 116 | form of a work. 117 | 118 | A "Standard Interface" means an interface that either is an official 119 | standard defined by a recognized standards body, or, in the case of 120 | interfaces specified for a particular programming language, one that 121 | is widely used among developers working in that language. 122 | 123 | The "System Libraries" of an executable work include anything, other 124 | than the work as a whole, that (a) is included in the normal form of 125 | packaging a Major Component, but which is not part of that Major 126 | Component, and (b) serves only to enable use of the work with that 127 | Major Component, or to implement a Standard Interface for which an 128 | implementation is available to the public in source code form. A 129 | "Major Component", in this context, means a major essential component 130 | (kernel, window system, and so on) of the specific operating system 131 | (if any) on which the executable work runs, or a compiler used to 132 | produce the work, or an object code interpreter used to run it. 133 | 134 | The "Corresponding Source" for a work in object code form means all 135 | the source code needed to generate, install, and (for an executable 136 | work) run the object code and to modify the work, including scripts to 137 | control those activities. However, it does not include the work's 138 | System Libraries, or general-purpose tools or generally available free 139 | programs which are used unmodified in performing those activities but 140 | which are not part of the work. For example, Corresponding Source 141 | includes interface definition files associated with source files for 142 | the work, and the source code for shared libraries and dynamically 143 | linked subprograms that the work is specifically designed to require, 144 | such as by intimate data communication or control flow between those 145 | subprograms and other parts of the work. 146 | 147 | The Corresponding Source need not include anything that users 148 | can regenerate automatically from other parts of the Corresponding 149 | Source. 150 | 151 | The Corresponding Source for a work in source code form is that 152 | same work. 153 | 154 | 2. Basic Permissions. 155 | 156 | All rights granted under this License are granted for the term of 157 | copyright on the Program, and are irrevocable provided the stated 158 | conditions are met. This License explicitly affirms your unlimited 159 | permission to run the unmodified Program. The output from running a 160 | covered work is covered by this License only if the output, given its 161 | content, constitutes a covered work. This License acknowledges your 162 | rights of fair use or other equivalent, as provided by copyright law. 163 | 164 | You may make, run and propagate covered works that you do not 165 | convey, without conditions so long as your license otherwise remains 166 | in force. You may convey covered works to others for the sole purpose 167 | of having them make modifications exclusively for you, or provide you 168 | with facilities for running those works, provided that you comply with 169 | the terms of this License in conveying all material for which you do 170 | not control copyright. Those thus making or running the covered works 171 | for you must do so exclusively on your behalf, under your direction 172 | and control, on terms that prohibit them from making any copies of 173 | your copyrighted material outside their relationship with you. 174 | 175 | Conveying under any other circumstances is permitted solely under 176 | the conditions stated below. Sublicensing is not allowed; section 10 177 | makes it unnecessary. 178 | 179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 180 | 181 | No covered work shall be deemed part of an effective technological 182 | measure under any applicable law fulfilling obligations under article 183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 184 | similar laws prohibiting or restricting circumvention of such 185 | measures. 186 | 187 | When you convey a covered work, you waive any legal power to forbid 188 | circumvention of technological measures to the extent such circumvention 189 | is effected by exercising rights under this License with respect to 190 | the covered work, and you disclaim any intention to limit operation or 191 | modification of the work as a means of enforcing, against the work's 192 | users, your or third parties' legal rights to forbid circumvention of 193 | technological measures. 194 | 195 | 4. Conveying Verbatim Copies. 196 | 197 | You may convey verbatim copies of the Program's source code as you 198 | receive it, in any medium, provided that you conspicuously and 199 | appropriately publish on each copy an appropriate copyright notice; 200 | keep intact all notices stating that this License and any 201 | non-permissive terms added in accord with section 7 apply to the code; 202 | keep intact all notices of the absence of any warranty; and give all 203 | recipients a copy of this License along with the Program. 204 | 205 | You may charge any price or no price for each copy that you convey, 206 | and you may offer support or warranty protection for a fee. 207 | 208 | 5. Conveying Modified Source Versions. 209 | 210 | You may convey a work based on the Program, or the modifications to 211 | produce it from the Program, in the form of source code under the 212 | terms of section 4, provided that you also meet all of these conditions: 213 | 214 | a) The work must carry prominent notices stating that you modified 215 | it, and giving a relevant date. 216 | 217 | b) The work must carry prominent notices stating that it is 218 | released under this License and any conditions added under section 219 | 7. This requirement modifies the requirement in section 4 to 220 | "keep intact all notices". 221 | 222 | c) You must license the entire work, as a whole, under this 223 | License to anyone who comes into possession of a copy. This 224 | License will therefore apply, along with any applicable section 7 225 | additional terms, to the whole of the work, and all its parts, 226 | regardless of how they are packaged. This License gives no 227 | permission to license the work in any other way, but it does not 228 | invalidate such permission if you have separately received it. 229 | 230 | d) If the work has interactive user interfaces, each must display 231 | Appropriate Legal Notices; however, if the Program has interactive 232 | interfaces that do not display Appropriate Legal Notices, your 233 | work need not make them do so. 234 | 235 | A compilation of a covered work with other separate and independent 236 | works, which are not by their nature extensions of the covered work, 237 | and which are not combined with it such as to form a larger program, 238 | in or on a volume of a storage or distribution medium, is called an 239 | "aggregate" if the compilation and its resulting copyright are not 240 | used to limit the access or legal rights of the compilation's users 241 | beyond what the individual works permit. Inclusion of a covered work 242 | in an aggregate does not cause this License to apply to the other 243 | parts of the aggregate. 244 | 245 | 6. Conveying Non-Source Forms. 246 | 247 | You may convey a covered work in object code form under the terms 248 | of sections 4 and 5, provided that you also convey the 249 | machine-readable Corresponding Source under the terms of this License, 250 | in one of these ways: 251 | 252 | a) Convey the object code in, or embodied in, a physical product 253 | (including a physical distribution medium), accompanied by the 254 | Corresponding Source fixed on a durable physical medium 255 | customarily used for software interchange. 256 | 257 | b) Convey the object code in, or embodied in, a physical product 258 | (including a physical distribution medium), accompanied by a 259 | written offer, valid for at least three years and valid for as 260 | long as you offer spare parts or customer support for that product 261 | model, to give anyone who possesses the object code either (1) a 262 | copy of the Corresponding Source for all the software in the 263 | product that is covered by this License, on a durable physical 264 | medium customarily used for software interchange, for a price no 265 | more than your reasonable cost of physically performing this 266 | conveying of source, or (2) access to copy the 267 | Corresponding Source from a network server at no charge. 268 | 269 | c) Convey individual copies of the object code with a copy of the 270 | written offer to provide the Corresponding Source. This 271 | alternative is allowed only occasionally and noncommercially, and 272 | only if you received the object code with such an offer, in accord 273 | with subsection 6b. 274 | 275 | d) Convey the object code by offering access from a designated 276 | place (gratis or for a charge), and offer equivalent access to the 277 | Corresponding Source in the same way through the same place at no 278 | further charge. You need not require recipients to copy the 279 | Corresponding Source along with the object code. If the place to 280 | copy the object code is a network server, the Corresponding Source 281 | may be on a different server (operated by you or a third party) 282 | that supports equivalent copying facilities, provided you maintain 283 | clear directions next to the object code saying where to find the 284 | Corresponding Source. Regardless of what server hosts the 285 | Corresponding Source, you remain obligated to ensure that it is 286 | available for as long as needed to satisfy these requirements. 287 | 288 | e) Convey the object code using peer-to-peer transmission, provided 289 | you inform other peers where the object code and Corresponding 290 | Source of the work are being offered to the general public at no 291 | charge under subsection 6d. 292 | 293 | A separable portion of the object code, whose source code is excluded 294 | from the Corresponding Source as a System Library, need not be 295 | included in conveying the object code work. 296 | 297 | A "User Product" is either (1) a "consumer product", which means any 298 | tangible personal property which is normally used for personal, family, 299 | or household purposes, or (2) anything designed or sold for incorporation 300 | into a dwelling. In determining whether a product is a consumer product, 301 | doubtful cases shall be resolved in favor of coverage. For a particular 302 | product received by a particular user, "normally used" refers to a 303 | typical or common use of that class of product, regardless of the status 304 | of the particular user or of the way in which the particular user 305 | actually uses, or expects or is expected to use, the product. A product 306 | is a consumer product regardless of whether the product has substantial 307 | commercial, industrial or non-consumer uses, unless such uses represent 308 | the only significant mode of use of the product. 309 | 310 | "Installation Information" for a User Product means any methods, 311 | procedures, authorization keys, or other information required to install 312 | and execute modified versions of a covered work in that User Product from 313 | a modified version of its Corresponding Source. The information must 314 | suffice to ensure that the continued functioning of the modified object 315 | code is in no case prevented or interfered with solely because 316 | modification has been made. 317 | 318 | If you convey an object code work under this section in, or with, or 319 | specifically for use in, a User Product, and the conveying occurs as 320 | part of a transaction in which the right of possession and use of the 321 | User Product is transferred to the recipient in perpetuity or for a 322 | fixed term (regardless of how the transaction is characterized), the 323 | Corresponding Source conveyed under this section must be accompanied 324 | by the Installation Information. But this requirement does not apply 325 | if neither you nor any third party retains the ability to install 326 | modified object code on the User Product (for example, the work has 327 | been installed in ROM). 328 | 329 | The requirement to provide Installation Information does not include a 330 | requirement to continue to provide support service, warranty, or updates 331 | for a work that has been modified or installed by the recipient, or for 332 | the User Product in which it has been modified or installed. Access to a 333 | network may be denied when the modification itself materially and 334 | adversely affects the operation of the network or violates the rules and 335 | protocols for communication across the network. 336 | 337 | Corresponding Source conveyed, and Installation Information provided, 338 | in accord with this section must be in a format that is publicly 339 | documented (and with an implementation available to the public in 340 | source code form), and must require no special password or key for 341 | unpacking, reading or copying. 342 | 343 | 7. Additional Terms. 344 | 345 | "Additional permissions" are terms that supplement the terms of this 346 | License by making exceptions from one or more of its conditions. 347 | Additional permissions that are applicable to the entire Program shall 348 | be treated as though they were included in this License, to the extent 349 | that they are valid under applicable law. If additional permissions 350 | apply only to part of the Program, that part may be used separately 351 | under those permissions, but the entire Program remains governed by 352 | this License without regard to the additional permissions. 353 | 354 | When you convey a copy of a covered work, you may at your option 355 | remove any additional permissions from that copy, or from any part of 356 | it. (Additional permissions may be written to require their own 357 | removal in certain cases when you modify the work.) You may place 358 | additional permissions on material, added by you to a covered work, 359 | for which you have or can give appropriate copyright permission. 360 | 361 | Notwithstanding any other provision of this License, for material you 362 | add to a covered work, you may (if authorized by the copyright holders of 363 | that material) supplement the terms of this License with terms: 364 | 365 | a) Disclaiming warranty or limiting liability differently from the 366 | terms of sections 15 and 16 of this License; or 367 | 368 | b) Requiring preservation of specified reasonable legal notices or 369 | author attributions in that material or in the Appropriate Legal 370 | Notices displayed by works containing it; or 371 | 372 | c) Prohibiting misrepresentation of the origin of that material, or 373 | requiring that modified versions of such material be marked in 374 | reasonable ways as different from the original version; or 375 | 376 | d) Limiting the use for publicity purposes of names of licensors or 377 | authors of the material; or 378 | 379 | e) Declining to grant rights under trademark law for use of some 380 | trade names, trademarks, or service marks; or 381 | 382 | f) Requiring indemnification of licensors and authors of that 383 | material by anyone who conveys the material (or modified versions of 384 | it) with contractual assumptions of liability to the recipient, for 385 | any liability that these contractual assumptions directly impose on 386 | those licensors and authors. 387 | 388 | All other non-permissive additional terms are considered "further 389 | restrictions" within the meaning of section 10. If the Program as you 390 | received it, or any part of it, contains a notice stating that it is 391 | governed by this License along with a term that is a further 392 | restriction, you may remove that term. If a license document contains 393 | a further restriction but permits relicensing or conveying under this 394 | License, you may add to a covered work material governed by the terms 395 | of that license document, provided that the further restriction does 396 | not survive such relicensing or conveying. 397 | 398 | If you add terms to a covered work in accord with this section, you 399 | must place, in the relevant source files, a statement of the 400 | additional terms that apply to those files, or a notice indicating 401 | where to find the applicable terms. 402 | 403 | Additional terms, permissive or non-permissive, may be stated in the 404 | form of a separately written license, or stated as exceptions; 405 | the above requirements apply either way. 406 | 407 | 8. Termination. 408 | 409 | You may not propagate or modify a covered work except as expressly 410 | provided under this License. Any attempt otherwise to propagate or 411 | modify it is void, and will automatically terminate your rights under 412 | this License (including any patent licenses granted under the third 413 | paragraph of section 11). 414 | 415 | However, if you cease all violation of this License, then your 416 | license from a particular copyright holder is reinstated (a) 417 | provisionally, unless and until the copyright holder explicitly and 418 | finally terminates your license, and (b) permanently, if the copyright 419 | holder fails to notify you of the violation by some reasonable means 420 | prior to 60 days after the cessation. 421 | 422 | Moreover, your license from a particular copyright holder is 423 | reinstated permanently if the copyright holder notifies you of the 424 | violation by some reasonable means, this is the first time you have 425 | received notice of violation of this License (for any work) from that 426 | copyright holder, and you cure the violation prior to 30 days after 427 | your receipt of the notice. 428 | 429 | Termination of your rights under this section does not terminate the 430 | licenses of parties who have received copies or rights from you under 431 | this License. If your rights have been terminated and not permanently 432 | reinstated, you do not qualify to receive new licenses for the same 433 | material under section 10. 434 | 435 | 9. Acceptance Not Required for Having Copies. 436 | 437 | You are not required to accept this License in order to receive or 438 | run a copy of the Program. Ancillary propagation of a covered work 439 | occurring solely as a consequence of using peer-to-peer transmission 440 | to receive a copy likewise does not require acceptance. However, 441 | nothing other than this License grants you permission to propagate or 442 | modify any covered work. These actions infringe copyright if you do 443 | not accept this License. Therefore, by modifying or propagating a 444 | covered work, you indicate your acceptance of this License to do so. 445 | 446 | 10. Automatic Licensing of Downstream Recipients. 447 | 448 | Each time you convey a covered work, the recipient automatically 449 | receives a license from the original licensors, to run, modify and 450 | propagate that work, subject to this License. You are not responsible 451 | for enforcing compliance by third parties with this License. 452 | 453 | An "entity transaction" is a transaction transferring control of an 454 | organization, or substantially all assets of one, or subdividing an 455 | organization, or merging organizations. If propagation of a covered 456 | work results from an entity transaction, each party to that 457 | transaction who receives a copy of the work also receives whatever 458 | licenses to the work the party's predecessor in interest had or could 459 | give under the previous paragraph, plus a right to possession of the 460 | Corresponding Source of the work from the predecessor in interest, if 461 | the predecessor has it or can get it with reasonable efforts. 462 | 463 | You may not impose any further restrictions on the exercise of the 464 | rights granted or affirmed under this License. For example, you may 465 | not impose a license fee, royalty, or other charge for exercise of 466 | rights granted under this License, and you may not initiate litigation 467 | (including a cross-claim or counterclaim in a lawsuit) alleging that 468 | any patent claim is infringed by making, using, selling, offering for 469 | sale, or importing the Program or any portion of it. 470 | 471 | 11. Patents. 472 | 473 | A "contributor" is a copyright holder who authorizes use under this 474 | License of the Program or a work on which the Program is based. The 475 | work thus licensed is called the contributor's "contributor version". 476 | 477 | A contributor's "essential patent claims" are all patent claims 478 | owned or controlled by the contributor, whether already acquired or 479 | hereafter acquired, that would be infringed by some manner, permitted 480 | by this License, of making, using, or selling its contributor version, 481 | but do not include claims that would be infringed only as a 482 | consequence of further modification of the contributor version. For 483 | purposes of this definition, "control" includes the right to grant 484 | patent sublicenses in a manner consistent with the requirements of 485 | this License. 486 | 487 | Each contributor grants you a non-exclusive, worldwide, royalty-free 488 | patent license under the contributor's essential patent claims, to 489 | make, use, sell, offer for sale, import and otherwise run, modify and 490 | propagate the contents of its contributor version. 491 | 492 | In the following three paragraphs, a "patent license" is any express 493 | agreement or commitment, however denominated, not to enforce a patent 494 | (such as an express permission to practice a patent or covenant not to 495 | sue for patent infringement). To "grant" such a patent license to a 496 | party means to make such an agreement or commitment not to enforce a 497 | patent against the party. 498 | 499 | If you convey a covered work, knowingly relying on a patent license, 500 | and the Corresponding Source of the work is not available for anyone 501 | to copy, free of charge and under the terms of this License, through a 502 | publicly available network server or other readily accessible means, 503 | then you must either (1) cause the Corresponding Source to be so 504 | available, or (2) arrange to deprive yourself of the benefit of the 505 | patent license for this particular work, or (3) arrange, in a manner 506 | consistent with the requirements of this License, to extend the patent 507 | license to downstream recipients. "Knowingly relying" means you have 508 | actual knowledge that, but for the patent license, your conveying the 509 | covered work in a country, or your recipient's use of the covered work 510 | in a country, would infringe one or more identifiable patents in that 511 | country that you have reason to believe are valid. 512 | 513 | If, pursuant to or in connection with a single transaction or 514 | arrangement, you convey, or propagate by procuring conveyance of, a 515 | covered work, and grant a patent license to some of the parties 516 | receiving the covered work authorizing them to use, propagate, modify 517 | or convey a specific copy of the covered work, then the patent license 518 | you grant is automatically extended to all recipients of the covered 519 | work and works based on it. 520 | 521 | A patent license is "discriminatory" if it does not include within 522 | the scope of its coverage, prohibits the exercise of, or is 523 | conditioned on the non-exercise of one or more of the rights that are 524 | specifically granted under this License. You may not convey a covered 525 | work if you are a party to an arrangement with a third party that is 526 | in the business of distributing software, under which you make payment 527 | to the third party based on the extent of your activity of conveying 528 | the work, and under which the third party grants, to any of the 529 | parties who would receive the covered work from you, a discriminatory 530 | patent license (a) in connection with copies of the covered work 531 | conveyed by you (or copies made from those copies), or (b) primarily 532 | for and in connection with specific products or compilations that 533 | contain the covered work, unless you entered into that arrangement, 534 | or that patent license was granted, prior to 28 March 2007. 535 | 536 | Nothing in this License shall be construed as excluding or limiting 537 | any implied license or other defenses to infringement that may 538 | otherwise be available to you under applicable patent law. 539 | 540 | 12. No Surrender of Others' Freedom. 541 | 542 | If conditions are imposed on you (whether by court order, agreement or 543 | otherwise) that contradict the conditions of this License, they do not 544 | excuse you from the conditions of this License. If you cannot convey a 545 | covered work so as to satisfy simultaneously your obligations under this 546 | License and any other pertinent obligations, then as a consequence you may 547 | not convey it at all. For example, if you agree to terms that obligate you 548 | to collect a royalty for further conveying from those to whom you convey 549 | the Program, the only way you could satisfy both those terms and this 550 | License would be to refrain entirely from conveying the Program. 551 | 552 | 13. Use with the GNU Affero General Public License. 553 | 554 | Notwithstanding any other provision of this License, you have 555 | permission to link or combine any covered work with a work licensed 556 | under version 3 of the GNU Affero General Public License into a single 557 | combined work, and to convey the resulting work. The terms of this 558 | License will continue to apply to the part which is the covered work, 559 | but the special requirements of the GNU Affero General Public License, 560 | section 13, concerning interaction through a network will apply to the 561 | combination as such. 562 | 563 | 14. Revised Versions of this License. 564 | 565 | The Free Software Foundation may publish revised and/or new versions of 566 | the GNU General Public License from time to time. Such new versions will 567 | be similar in spirit to the present version, but may differ in detail to 568 | address new problems or concerns. 569 | 570 | Each version is given a distinguishing version number. If the 571 | Program specifies that a certain numbered version of the GNU General 572 | Public License "or any later version" applies to it, you have the 573 | option of following the terms and conditions either of that numbered 574 | version or of any later version published by the Free Software 575 | Foundation. If the Program does not specify a version number of the 576 | GNU General Public License, you may choose any version ever published 577 | by the Free Software Foundation. 578 | 579 | If the Program specifies that a proxy can decide which future 580 | versions of the GNU General Public License can be used, that proxy's 581 | public statement of acceptance of a version permanently authorizes you 582 | to choose that version for the Program. 583 | 584 | Later license versions may give you additional or different 585 | permissions. However, no additional obligations are imposed on any 586 | author or copyright holder as a result of your choosing to follow a 587 | later version. 588 | 589 | 15. Disclaimer of Warranty. 590 | 591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 599 | 600 | 16. Limitation of Liability. 601 | 602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 610 | SUCH DAMAGES. 611 | 612 | 17. Interpretation of Sections 15 and 16. 613 | 614 | If the disclaimer of warranty and limitation of liability provided 615 | above cannot be given local legal effect according to their terms, 616 | reviewing courts shall apply local law that most closely approximates 617 | an absolute waiver of all civil liability in connection with the 618 | Program, unless a warranty or assumption of liability accompanies a 619 | copy of the Program in return for a fee. 620 | 621 | END OF TERMS AND CONDITIONS 622 | 623 | How to Apply These Terms to Your New Programs 624 | 625 | If you develop a new program, and you want it to be of the greatest 626 | possible use to the public, the best way to achieve this is to make it 627 | free software which everyone can redistribute and change under these terms. 628 | 629 | To do so, attach the following notices to the program. It is safest 630 | to attach them to the start of each source file to most effectively 631 | state the exclusion of warranty; and each file should have at least 632 | the "copyright" line and a pointer to where the full notice is found. 633 | 634 | 635 | Copyright (C) 636 | 637 | This program is free software: you can redistribute it and/or modify 638 | it under the terms of the GNU General Public License as published by 639 | the Free Software Foundation, either version 3 of the License, or 640 | (at your option) any later version. 641 | 642 | This program is distributed in the hope that it will be useful, 643 | but WITHOUT ANY WARRANTY; without even the implied warranty of 644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 645 | GNU General Public License for more details. 646 | 647 | You should have received a copy of the GNU General Public License 648 | along with this program. If not, see . 649 | 650 | Also add information on how to contact you by electronic and paper mail. 651 | 652 | If the program does terminal interaction, make it output a short 653 | notice like this when it starts in an interactive mode: 654 | 655 | Copyright (C) 656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 657 | This is free software, and you are welcome to redistribute it 658 | under certain conditions; type `show c' for details. 659 | 660 | The hypothetical commands `show w' and `show c' should show the appropriate 661 | parts of the General Public License. Of course, your program's commands 662 | might be different; for a GUI interface, you would use an "about box". 663 | 664 | You should also get your employer (if you work as a programmer) or school, 665 | if any, to sign a "copyright disclaimer" for the program, if necessary. 666 | For more information on this, and how to apply and follow the GNU GPL, see 667 | . 668 | 669 | The GNU General Public License does not permit incorporating your program 670 | into proprietary programs. If your program is a subroutine library, you 671 | may consider it more useful to permit linking proprietary applications with 672 | the library. If this is what you want to do, use the GNU Lesser General 673 | Public License instead of this License. But first, please read 674 | . 675 | -------------------------------------------------------------------------------- /arrasio/src/server/newserver.js: -------------------------------------------------------------------------------- 1 | /*jslint node: true */ 2 | /* global goog */ 3 | "use strict"; 4 | 5 | // General requires 6 | require('google-closure-library'); 7 | goog.require('goog.structs.PriorityQueue'); 8 | goog.require('goog.structs.QuadTree'); 9 | 10 | // Import game settings. 11 | const c = require('../../config.json'); 12 | 13 | // Import utilities. 14 | const util = require('./lib/util'); 15 | const ran = require('./lib/random'); 16 | const hshg = require('./lib/hshg'); 17 | 18 | // Let's get a cheaper array removal thing 19 | Array.prototype.remove = index => { 20 | if(index === this.length - 1){ 21 | return this.pop(); 22 | } else { 23 | let r = this[index]; 24 | this[index] = this.pop(); 25 | return r; 26 | } 27 | }; 28 | 29 | // Define player keys 30 | const keys = [ 31 | 'k', 'l', 'testk', 'testl', 32 | // Focus Group 33 | 'ZNr3GBQOhD2CDDYpZD3JZkZ6hmhoF4wGiTYTikZlSLr1Z66yWKuVMitRkpUbPy6s', // Mine 34 | 'HKib09Ep3hIcwFXpiCj5iEkpLBN88HQ22hiFqg5alcxn4AYl6VcsPFTqMvllLt1D', // Parodia 35 | 'n9hx8iQH8453dWQpdDvJcAvPzQej80xQz86TxuYaJ8CaOr4hEH2zHPlSeayVPjFZ', // SGM 36 | '5piWwi06VXdEuOsz1rbcHiglurbaYIPtslIgE0NNMGQgNcqErdJ4kUVYpDJsRlVC', // Aznaft 37 | 'q80UgWYIQVM2oZW5iQO6VRdLcOTuHkSgUx4U7NN8z76Ltgj7gVc6tSWvmpPkRUGH', // Licht 38 | '9zcVcKxiv60ZoBr6CaO9ecjR3i0Mj9yx4Qgt9IGwzxps8Q5ge1GQJiYe59GBxKip', // Tenderlicious 39 | 'M67ZAZIgboiBcUtcKoHOuwXlQJWN9DEwhr0CIqR9xjiwpDyb4cUrwUIynKnuQmrU', // ManticoreKiller 40 | 'iBKZrtZEP6Gq1m1y4hpbIH2htBKegkaj6eyO70L9FMAEydiV4gA4ufiLWFx0R5C2', // JB Columbia 41 | 'zbH5Myv66HmR9Mda39xlLXa9TyBGzXnKZV7xpN5NCDTXorn52123eHY4kcZmPNLx', // Teal Knight 42 | 'pee4OZmPo9yrINv30kIMMVviEr1PRfiuIYQEOGXTK6lnLZumy9O942NabE8BiEce', // unnamed 43 | '08IhobFLBYah8Mk8MKqqG6W576iS4jznjK4WnIsSzcFC0OhkIY51DQV0DWWsgfbg', // Pie 44 | '36spA3cA2FNDamjM4SaiNNfNMkUMSERgduUvAL3Ms8bsioX4uoMyQteMWx1dRpdp', // Sergio 45 | 'i3tpmHTC2ty8CCzjhISDKO1MrkZOwmoWZ08XZLOg3IfCqbtAsdC8QPKPMhbPHQmV', // Corrupt X 46 | 'gQHpJkeGoxknxqkiX9msLhwS1NzikXa1RiOKOJD2o2zf15XL35P1YWZeMcivXLNB', // Jorjito Gamer 47 | 'kKWsRf0OdLWzipECohr5FqjuyecPZYOGxl1zAXabtllaWx2OVKfLTKBiit8KVg5j', // warrior 48 | '77L1QgQgsTQrZHhTSuv1iK1NyvpBL9AYyvmkF21Sjp4T7ldxGodQnC9dM1YtvZzG', // TTTank 49 | 'M6I9vmmRiitxg07rBG2IuC7aNpp7LHQGVPtwGfkk3hIBR0jhlWwaqzpzPXqU2awM', // CX 50 | '5AxKhPIu5jF3B3cIxjA2BHUy30ccYgEUXJmK16ksJotp9D9WVlY6QqPLDPGim1MK', // Faxaro 51 | 'kcrJTPqvhraysgCNrFZORGNR4UTMRvbQ2zuhI3iXpGyMg6wDtU5QMgcV8vNdLLHQ', // Mipha 52 | 'EXoiZYDuwSwmp7Zg0m7hdaLyv2PMbQgQorkwRznC0NC3saubVNtxVUGtOWZ2xdcz', // svorlds 53 | 'G0t2lQYeaTHHU8sp5ibNjFCCLMr41cPCOJRKUC5eUGfkUKDxpVwo5azomBSznZuR', // FTM 54 | 'kf2VcjtzpMvVwhlgIjq4MX6LWbIoNzcvfsxARS0qWiuVWf6BPPsQ2p1FgBVvNoB1', // pnvv / Cannon Man 55 | '3hO6R7AOR0aiiFuRyGaHKrgJHjTEpsD2LZ866bhvlz2Ru9AT8QmiBNf5PZuXCFIA', // wowie's friend 56 | 'z272UlNODnYVK79jva6pybRpwtp1h0FdJh8F8JRQJ5VY9lPrcugp6nd403Op4voC', 57 | 'eOb4DCk81Hzay8Kgjcu6tbbpIUCveloxahmnkmg3aU6FlvdWjJd2Uui5cFQdsnby', 58 | '9qGqNv5iYTSIhkCaMmZpvYhSpaLnHQJnj6m2gdoVWIXgLaFgIrbcFYHM8bcBsGYS', 59 | 'qqWz1E1uVtErG4N80YDVQJywzOk6PJFDrC6uzqoQ9XL2nNrCCr1KvY8XUEyCroHT', 60 | 'r0KXqfIifiavtqP3v0b5gqb5ArQY5sJWO7fjG4P6AFE5MRyfjDGK7sO7nXg23Tkv', 61 | 'nUzNolF4Yys4ua6x78GiVH0Fparcm8GyD60IZzVHji0b2gQL3citWEEi3b1J9iRT', 62 | 'XSxFurVLlc7o99nnakK5EPA2Z16tqBxP3xKcq5y4XOjRyfFRqaSxbBNRUtab71FH', 63 | 'uYLfr6k6wEmgMtGVna366Gujor3gUWhWUHgbsz2uUNhQ8OKkwzb1IpDehnz7dfFL', 64 | 'TVA4eYx29geFN6kb2Osyt5veaih0OOJG2MzB4qBBlUQr5CpRJqIhrTModxcT5NXI', 65 | 'eyQqQE0h0l6x7XpkXpnZdYPsRJgvdl6L8xAoEzF0ZGlTV8HH0wUePj03LuULDhSN', 66 | 'ZuOzwoZw4lCWwekTMh9bEAw4Tv92uLhzGN0DMDV2Rk7Sfn3Hsbf87ssHcvxTbDek', 67 | 68 | // Public 69 | 'PUBLICRSUZbhCMu2ocDrhtje1ev6ff3eM6IxsCPUBLIC', 70 | 'PUBLICb7HbKa0zFp5PzJVkcu17GIbp56JeHxZlPUBLIC', 71 | 'PUBLICwxTybWuUrYfEA84kVunN5btV4vROYCW0PUBLIC', 72 | 'PUBLICfOKBjTZzW1VvoEfJTY3G7U2TcwT8iREyPUBLIC', 73 | 'PUBLICKKRLO0lpLy2IDHUdqzE0MBsZUhrBnYRpPUBLIC', 74 | 'PUBLICsC7wKFQ6CXPB241uA5RzORP2Z14CSO86PUBLIC', 75 | 'PUBLIC6criSrXdLBoTtIWQHCmcOPfzqgDZcGOiPUBLIC', 76 | 'PUBLIC3QdiZpPEAtB4gif0TEU3822qJz3W23J2PUBLIC', 77 | 'PUBLICEDZLxLjRRfa8tS5EqRIExtHpWq0MJSVZPUBLIC', 78 | 'PUBLIC5vmCtP1IjDnglKJk7AmWg3hAuZ4ZGGnVPUBLIC', 79 | 'PUBLICe1r6NsdjhOnpNuPqnskTzLvJoaXn3dsqPUBLIC', 80 | 'PUBLICTbfzA0MB2H6hRataGEQENmu1o9eOpytkPUBLIC', 81 | 'PUBLICpJlxtdn2iplYuIWXznUX3f6RHHPC3uFrPUBLIC', 82 | 'PUBLICadVvUN4mp0MTSAnsc3BKIJ6l40Y5sV00PUBLIC', 83 | 84 | 'TRUSTED5vmCtP1IjDnglKJk7sAmWg3hAuZ4ZGGnVTRUSTED', 85 | 'TRUSTEDe1r6NsdjhOnpNuPqnskTfzLvJoaXn3dsqTRUSTED', 86 | 'TRUSTEDTbfzA0MB2H6hRataGE3QENmu1o9eOpytkTRUSTED', 87 | 'TRUSTEDpJlxtdn2iplYuIWXsznUX3f6RHHPC3uFrTRUSTED', 88 | 'TRUSTEDadVvUN4mp0MTSAnsc3BKfIJ6l40Y5sV00TRUSTED', 89 | 'TRUSTED3nYR28Kwhnx1n6JvP4Tm r2dxLhrTvrcNTRUSTED', 90 | 'TRUSTEDNwHIdUtjLSmITUVNg5B6c4uVWiB7IFq2STRUSTED', 91 | 'TRUSTEDDIIocNBJS9mYstVFSuiwNxbQeEXOFlrPhTRUSTED', 92 | 'TRUSTED17rtKXqQ7wzek6Ejf9rGCfOdRr5vrm5AxTRUSTED', 93 | 'TRUSTEDWJkuJFZ2Wljq2WXasxHrM0Vsbra5iyb6vTRUSTED', 94 | 'TRUSTEDzxVdPsuU1yGRQrkbADH6rBaE8TKdAvJabTRUSTED', 95 | 'TRUSTED7nAZ3NBi9ZB07KfLV0cnGO0YEXoSGf1lLTRUSTED', 96 | 'TRUSTEDFyJTLBCrokyoFICQFi4hAGJd09jkCDqOJTRUSTED', 97 | 'TRUSTEDPBHbBZkW9foaXPDfGe6xq9Y6XvJhrwowqTRUSTED', 98 | 'TRUSTEDtTZe5CYcmmCQBLj0WztAHn5MnI0dhqNrXTRUSTED', 99 | 100 | 'GUDPOSTERNwR7FWcY1eeNkyiCrzGfuo3wGWhETFmbGUDPOSTER', 101 | 'GUDPOSTERR2gdw10L7u4auP3yr1G1EC59TnRA3H31GUDPOSTER', 102 | 'GUDPOSTERVLX8LwHtMrLIMFx0XdzTdauVAmSKV9SZGUDPOSTER', 103 | 'GUDPOSTER8Uk4cGa2ut3vFfaPmjbmRBtAXpFHXsBNGUDPOSTER', 104 | 'GUDPOSTERdHHy9pqMejwGZJ7nUZMRw0Mnc1g8UJ8oGUDPOSTER', 105 | 'GUDPOSTERrgZPXqFSJXdChEMvgQjjxjGZfsObOArCGUDPOSTER', 106 | 'GUDPOSTERysJI3BfzB2cRCDDdFkAaFWxZk5TNHwfvGUDPOSTER', 107 | 'GUDPOSTERlFps80nCJ6cnFGjyH9QoKqgETwGX1sIQGUDPOSTER', 108 | 'GUDPOSTERmED6CZg213gXoCYyDqxMLGFtuuCPn8NmGUDPOSTER', 109 | 'GUDPOSTERlSL92YPpoqh48GuQwydpGuocJAH6Vx5VGUDPOSTER', 110 | 111 | 'GIVEAWAYZ1yVvobK3MWgCBxYjFheJd3UrWW2ULJuGIVEAWAY', 112 | 'GIVEAWAYaVGcMBm3LwxmLkxxGSt6NNg9AUDsj5v5GIVEAWAY', 113 | 'GIVEAWAYAMkJmX3xKv3tiieS5oAfEsJbni4xInIwGIVEAWAY', 114 | 'GIVEAWAYi3AbdptFr9m2fGGqY9p6Vvi3uRX6ALHRGIVEAWAY', 115 | 'GIVEAWAYxwABlNSPU4291UJICWyeXQB4ET0ZyA0uGIVEAWAY', 116 | 'GIVEAWAYczPSwYnpHDGKaimREjN1e86N6CmSH0NWGIVEAWAY', 117 | 'GIVEAWAYDx3U7MOBNyDmjv6Rz6Le6wgG4Xk0cwilGIVEAWAY', 118 | 'GIVEAWAYCOr2yK7od6RRch52ToBO5s0xxizBVVajGIVEAWAY', 119 | 'GIVEAWAYV7fiIzckU8xQ57i3Bu8ngWetPOzS9ktvGIVEAWAY', 120 | 'GIVEAWAYpbo21yNoMcvwhbIeMOsqMIjzYKOLZyEgGIVEAWAY', 121 | 122 | // Twitter 123 | '500kBomberContestTokenVUBefeRUMQsLShjas4dhfSF', 124 | '500kBomberContestTokenNSEefeRUMQsLShjbs4dhfSF', // TnT 125 | '500kBomberContestTokenWDWefeRUMQsLShjcs4dhfSF', // crnz 126 | '500kPoacherContestTokenZZb1FkYER7B0ZV7bs9df8s', 127 | '500kAutoDoubleContestTokenKBSj41qloynOGws87X2', // JeShAn 128 | '500kFortressContestTokenl2fd42tL7C6ZynSDF33ox', // Lucario 129 | // Youtube 130 | 'SGMTokenGiveaway51NP3JOh9NKvsnVh6PDRGI1wALGXWLzE2jZXztWKxlyPN00w', 131 | 'SGMTokenGiveaway2puyw4VGFTTSqgxeFvvvqxMTzZ5S3XPtVQXLCSIOpW7Rxv8m', 132 | 'SGMTokenGiveawayYAu4abk9oLMaBqOXfx2QvSqznNqw7mTFv7lBFk5LJ7ksPd7W', 133 | 'SGMTokenGiveawaybgSA5xNNpo4Vhsfg8lOlop8f4FOPWk9VXcMvjl62JYWhKOWF', 134 | 'SGMTokenGiveawaya7C7vBTBPxgWEgg1g3UbYttE30A33aFVqEEd2pdV3PfbxvA0', 135 | 'SGMTokenGiveawayBFu7eKC22KxKYuFiUTOyjmMCpBhr1HseP7pNo4yl5xOZt9IS', 136 | 'SGMTokenGiveawayAHVq7eEAUWZzCtK4vcHslWIDMPykPAfsnq4jdsHYE3HIhlBO', 137 | 'SGMTokenGiveawayS0wxtOYFcnBirWbbP9EePvgo8rPVrhatpixkaH78CdKdtorr', 138 | 'SGMTokenGiveaway7p8JwRnATdS3H10gIKy5dKQXlbj93WplkC9NpfjNTREG9IQn', 139 | 'SGMTokenGiveawaynM1ffqsEM31Vv6KMmlxhs6Ug0s65FiyN3w9eP6QM7FmpbS2i', 140 | 141 | 'SGMTokenAa05Q1oDwf0Mxaw57vBTBPX3M25gjitRD0daHTObk796GqSJ3KUhKf5p', 142 | 'SGMTokenxg3Kw7jPUoxFOXbO4POF19iovCUnNzqoQ9XL2rTAoXoAtyHDZR5YFgAk', 143 | 'SGMToken7KteCaOERDa8TkfzIQIm54rhewlKL2lWIDMPykPAfsnq41MGxgogphB9', 144 | 145 | 'OMTokenIGnPS8RSGiP8lvTQDdve9ANPfSOyTgvPQMYdFlcn7IVcJg8oeGreEBYs', 146 | 'OMTokenLTARU3UJldlHUf8215Wg4AbdThRvA3j0wG2FbwyZCTixkaH78CdK8BnV', 147 | 'OMToken7sOXlNs9Qu58TmaCu9TpD4JkzRuGrKKOS74tZimimR8Iu5du7v6GRbRH', 148 | 149 | 'JBColombiaTokenwZXpYskkovgQL4jZlqS42xaqgVAvHZPZgVcccsBkHhsXhq69', 150 | 'JBColombiaToken8WwiA5demyL1gQZ9D5kvFMOwkJRc3STikct22cMoPmjfli69', 151 | 'JBColombiaTokenPDuZydKLePKQ9TyOMqiquI0YVHcCJBJb3pORyzfo42nHhT69', 152 | 'JBColombiaTokeniC0Eh8jMoncX4bAKbslR174tZimimBXoUGhvaKY0dBwbLI69', 153 | 'JBColombiaTokenWWqX44i7VqxtQB3qsViJHbJnK3FryxqgAAFerRFxYO2wJc69', 154 | 'JBColombiaTokenlzgPyfwuto7KY8BqxDserADmpeuMR31wxgD0dWpNWvHZv969', 155 | 156 | 'SMTokenlSrBG8RTazOHzZ6zeyBPFI1tOSiuDSJNcfozraRKb8votLtwmNFC964KG', 157 | 'SMTokennrNg7MzqzJe2xz11cKDETqCBKVhDiOS6x1gyTMV8EHLkRGGFXAHLUVUjk', 158 | 'SMTokenfjlzipOhA8Lfp38kt9FnzGKRg6g79hujlFVPbEyzsbEqbYOD2ohveMSh8', 159 | 'SMTokenNHPtbYKUDrR8MBQoQIymCwdbFSoHHNTuBMPvS4iugQigBMvfrGurB3qM4', 160 | 'SMTokenI33BqYnppCCVAMOkykIeOWIsmetgkymFK1A7XgeZGGW52xVq1xRKv38vC', 161 | 'SMTokenHxNBGJGRf6SqXAOIhgMEOuPUp4X4LszwBEeco3Wrw2IuOe3jxoWyLKdR0', 162 | 'SMTokennjophXq0WC3jzDpPrDbfXLE2eoFOMvQWKucR0ZwECIlXDBTQnF33uyDXd', 163 | // Patreon / rewards 164 | 'tokenlordkarma88tokenlordkarma88tokenlordkarma88tokenlordkarma88', 165 | 'hereIsUrTokenBuddyThxForTheOverGunnerLmao', 166 | 'DukeonkledDukeonkleThankYouSoMuch123e911DukeonkledDukeonkledDuke', 167 | 'FireNationFireNationThanksATon018s380280FireNationFireNationFire', 168 | 169 | 'rewardTokenJSdf323H0Cj85aVOG3SPlgp7Y9BuBoFcwpmNFjfLEDQhOFTIpukdr', // Call 170 | 'rewardTokenDg2JDTp0rxDKXIPE8PHcmdHqWyH2CqPqpcAf6QcT8m2hgBZnJ7KHE', 171 | 'rewardTokenad3JTsTwuVLkQvfmVH2d2Ukbf8WbFuPBqTpYFdFx9AuZEnmv9EW8U', 172 | 'rewardTokenJsa43Tthn1M5Ey9oDRODzzrazqRxL28cTchgInjVCrSfnWEATdYeP', 173 | 'rewardTokensdfsJTyz2YMS3GLDfD2NvqXK46p1ScsmdLxI1owBkjHw983lwkR8Z', 174 | // Wiki 175 | 'WIKIREWARDV7V0bZRP8lM3fUvwuAX7DC5FpZCU1AyJByaulkH9YHZ7WIKIREWARD', 176 | 'WIKIREWARDDOE8Iqg5K124sNXSR51WWycmCnFtCLjyF7uole5sgQgoWIKIREWARD', 177 | 'WIKIREWARD5z5xXA0flzxeRgGu6EjSWlOq23gdGoYALClfsUT143Y9WIKIREWARD', 178 | 'WIKIREWARD4DTEvdwSBKPBRCAJxeS9surL09uzxx33gAHmMYFldRsMWIKIREWARD', 179 | 'WIKIREWARDqGXxMucMJcSeqWFcAfCLVNStnmOezkzOUot8xbfpCuk1WIKIREWARD', 180 | 'EDITOR1eKAAURvtnHYFuUz6dzPqOwPt6SFWbacEucDnm8KroabolnzLZrdEDITOR', 181 | 'EDITOR38Gi67EFmLdh6nXuKqtRc79HKk34c6bQl08tbUeZlGcxBS2c350yEDITOR', 182 | 'EDITOR7mAKjd6XYprdtvbWqqUjEEfCqomx67aLSyG70eiFuvRVv2Eest27EDITOR', 183 | 'EDITORoNzv0DxKzLYY7YCYdIsRHdNz8DNNiuqI2I9mBM2blBpWZ39chumsEDITOR', 184 | 'EDITOR399V1FLGtsne5BMg5QfeeHdR63bxkV51Av0ET3F5y92q7EMhI8R3EDITOR', 185 | 'EDITORmUJbmoFVshllWIUb11kyXxQfyESa4t3SYcGRHSlWzLrzfwkHCIVUEDITOR', 186 | // Themes 187 | 'YouAreTheCreatorOfBadlands', 188 | 'WowYouMadeADopeFishyTheme', 189 | 'ThanksForHelpingPlantAForest', 190 | 'MidnightIsSuperCoolNotYouTheTheme', 191 | 'DrinkBleachPlz', 192 | 'FrostyAndBeautifulJustLikeYourColdHeart', 193 | ]; 194 | 195 | // Get class definitions and index them 196 | const Class = (() => { 197 | const def = require('./lib/definitions'); 198 | let i = 0; 199 | for (let k in def) { 200 | if (!def.hasOwnProperty(k)) continue; 201 | def[k].index = i++; 202 | } 203 | return def; 204 | })(); 205 | 206 | const ROOMSPEED = 1; 207 | // Define entities 208 | const makeEntity = (() => { 209 | // Pooled memory 210 | const __a = { 211 | int: [], 212 | float: [], 213 | str: [], 214 | }; 215 | // Shared math functions 216 | const getLength = (x, y) => { 217 | return Math.sqrt(x * x + y * y); 218 | }; 219 | const getDirection = (x, y) => { 220 | return Math.atan2(y, x); 221 | }; 222 | const DEGTORAD = Math.PI / 180; 223 | // The value loader 224 | const load = (fallback, val) => { return (val == null) ? fallback : val; }; 225 | // A status container creator 226 | const newStatusBox = (() => { 227 | const attribute = (status, id, index, inital) => { 228 | status[index] += id * inital; 229 | return { 230 | get: () => { return status[index] & id; }, 231 | set: bool => { 232 | if (bool) status[index] = status[index] | id; 233 | else status[index] = status[index] & ~id; 234 | }, 235 | }; 236 | }; 237 | return () => { 238 | let status = [0]; 239 | return { 240 | ghost: attribute(status, 1, 0, false), 241 | inGrid: attribute(status, 2, 0, false), 242 | invuln: attribute(status, 4, 0, false), 243 | }; 244 | }; 245 | })(); 246 | // A kills container creator 247 | const newKillBox = () => { 248 | let data = [0, 0, 0]; 249 | return { 250 | get: data.slice, 251 | addSolo: () => data[0]++, 252 | addAssist: () => data[1]++, 253 | addBoss: () => data[2]++, 254 | }; 255 | }; 256 | // A health bar creator 257 | const healthTypes = (() => { 258 | // Static-type functions 259 | const regenerateStatic = (data, boost) => { 260 | const amount = data[0], max = data[1]; 261 | data[0] += max / 10 / 60 / 2.5 + boost; 262 | data[0] = Math.min(data[0], max); 263 | }; 264 | const getStaticDamage = (data, amount, capped) => { 265 | return capped ? Math.min(amount, data[0]) : amount; 266 | }; 267 | // Dynamic-type functions 268 | const regenerateDynamic = (data, boost) => { 269 | const amount = data[0], max = data[1], regen = data[2]; 270 | const r = util.clamp(amount / max, 0, 1); 271 | if (!r) data[0] = 0.0001; 272 | else if (r === 1) data[0] = max; 273 | else { 274 | data[0] += regen * Math.exp(-50 * Math.pow(Math.sqrt(0.5 * r) - 0.4, 2)) / 3 + r * max / 10 / 15 + boost; 275 | data[0] = Math.min(data[0], max); 276 | } 277 | }; 278 | const getDynamicDamage = (data, amount, capped) => { 279 | const permeability = data[1] ? util.clamp(data[0] / data[1], 0, 1) : 0; 280 | return (capped) ? 281 | Math.min(amount * permeability, data[0]) : 282 | amount * permeability; 283 | }; 284 | // Shared functions 285 | const getRatio = data => { 286 | return data[1] ? util.clamp(1 - Math.pow(data[0] / data[1] - 1, 4), 0, 1) : 0; 287 | }; 288 | return { 289 | newStatic: () => { 290 | var data = [1.0, 0.0]; 291 | return { 292 | dealDamage: amount => data[0] -= getStaticDamage(data, amount, 1), 293 | getAmount: () => { return data[0]; }, 294 | getDisplay: () => { return data[0] / data[1]; }, 295 | getRatio: () => { return getRatio(data); }, 296 | getDamage: (amount, capped) => { return getStaticDamage(data, amount, capped); }, 297 | regenerate: boost => regenerateStatic(data, boost), 298 | }; 299 | }, 300 | newDynamic: () => { 301 | var data = [0.0, 0.0, 0.0]; 302 | return { 303 | dealDamage: amount => data[0] -= getDynamicDamage(data, amount, 1), 304 | getAmount: () => { return data[0]; }, 305 | getDisplay: () => { return data[0] / data[1]; }, 306 | getRatio: () => { return getRatio(data); }, 307 | getDamage: (amount, capped) => { return getDynamicDamage(data, amount, capped); }, 308 | regenerate: boost => regenerateDynamic(data, boost), 309 | }; 310 | }, 311 | }; 312 | })(); 313 | // The skills container creator 314 | // Index references 315 | const skc = { 316 | rld: 0, 317 | pen: 1, 318 | str: 2, 319 | dam: 3, 320 | spd: 4, 321 | shi: 5, 322 | atk: 6, 323 | hlt: 7, 324 | rgn: 8, 325 | mob: 9, 326 | accel: 10, 327 | rst: 11, 328 | brst: 12, 329 | ghost: 13, 330 | }; 331 | const newSkills = (() => { 332 | // The big update method 333 | const update = (() => { 334 | // Some math functions 335 | const apply = (f, x) => { return (x<0) ? 1 / (1 - x * f) : f * x + 1; }; 336 | const curves = (() => { 337 | const make = x => { return Math.log(4*x + 1) / Math.log(5); }; 338 | let length = c.MAX_SKILL*2; 339 | let storedValues = new Array(length); 340 | for (let i=0; i { 344 | // Reset it if it's past the cap 345 | for (let i=0; i<10; i++) { 346 | if (data.raw[i] > data.caps[i]) { 347 | data.points += data.raw[i] - data.caps[i]; 348 | data.raw[i] = data.caps[i]; 349 | } 350 | } 351 | // Refresh all the stuff 352 | // Bullet stats 353 | data.real[skc.rld] = Math.pow(0.5, curves[data.raw[skc.rld]]); 354 | data.real[skc.pen] = apply(2.5, curves[data.raw[skc.pen]]); 355 | data.real[skc.str] = apply(2, curves[data.raw[skc.str]]); 356 | data.real[skc.dam] = apply(3, curves[data.raw[skc.dam]]); 357 | data.real[skc.spd] = 0.5 + apply(1.5, curves[data.raw[skc.spd]]); 358 | // Misc bullet stats 359 | data.real[skc.accel] = apply(0.5, curves[data.raw[skc.rld]]); 360 | data.real[skc.rst] = 0.5 * curves[data.raw[skc.str]] + 2.5 * curves[data.raw[skc.pen]]; 361 | data.real[skc.ghost] = curves[data.raw[skc.pen]]; 362 | // Body stats 363 | data.real[skc.shi] = c.GLASS_HEALTH_FACTOR * apply(3 / c.GLASS_HEALTH_FACTOR - 1, curves[data.raw[skc.shi]]); 364 | data.real[skc.atk] = apply(1, curves[data.raw[skc.atk]]); 365 | data.real[skc.hlt] = c.GLASS_HEALTH_FACTOR * apply(2 / c.GLASS_HEALTH_FACTOR - 1, curves[data.raw[skc.hlt]]); 366 | data.real[skc.mob] = apply(0.8, curves[data.raw[skc.mob]]); 367 | data.real[skc.rgn] = apply(25, curves[data.raw[skc.rgn]]); 368 | // Misc body stats 369 | data.real[skc.brst] = 0.3 * (0.5 * curves[data.raw[skc.atk]] + 0.5 * curves[data.raw[skc.hlt]] + curves[data.raw[skc.rgn]]); 370 | }; 371 | })(); 372 | // Modification methods 373 | const change = (data, index, levels) => { 374 | if (data.points && data.raw[index] < data.caps[index]) { 375 | data.raw[index] += levels; 376 | update(data); 377 | } 378 | }; 379 | const set = (data, values) => { 380 | for (let i=0; i<10; i++) { 381 | data.raw[i] = values[i]; 382 | } 383 | update(data); 384 | }; 385 | const setCaps = (data, values) => { 386 | for (let i=0; i<10; i++) { 387 | data.caps[i] = values[i]; 388 | } 389 | update(data); 390 | }; 391 | const maintain = (() => { 392 | const levelToPoint = (() => { 393 | const templevelers = [ 394 | 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 395 | 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 396 | 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 397 | 31, 32, 33, 34, 35, 36, 38, 40, 42, 44, 398 | ]; 399 | // Generate the real level array check thingy 400 | const levelers = new Array(c.SKILL_CAP); 401 | for (let i=0; i { 405 | let tempArray = []; 406 | for (let i=0; i { 411 | if (data.level < c.SKILL_CAP) { 412 | let didStuff = false; 413 | while (data.score - data.deduction >= levelToScore[data.level]) { 414 | data.deduction += levelToScore[data.level]; 415 | data.level++; 416 | data.points += levelToPoint[data.level]; 417 | data.canUpgrade = data.canUpgrade || data.level == c.TIER_1 || data.level == c.TIER_2 || data.level == c.TIER_3; 418 | didStuff = true; 419 | } 420 | if (didStuff) { 421 | update(data); 422 | return 1; 423 | } 424 | } 425 | return false; 426 | }; 427 | })(); 428 | const returnSkills = data => { 429 | for (let i=0; i<10; i++) { 430 | __a.int[i] = data.raw[i]; 431 | } 432 | return __a.int; 433 | }; 434 | return () => { 435 | const data = { 436 | raw: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0], 437 | caps: [c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, 438 | c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL, c.MAX_SKILL], 439 | real: [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0], 440 | points: 0, 441 | score: 0, 442 | deduction: 0, 443 | level: 0, 444 | canUpgrade: false, 445 | }; 446 | return { 447 | change: (index, levels) => change(data, index, levels), 448 | update: () => update(data), 449 | set: values => set(data, values), 450 | setCaps: values => setCaps(data, values), 451 | maintain: () => maintain(data), 452 | get: () => returnSkills(data), 453 | }; 454 | }; 455 | })(); 456 | // A gun 457 | const newGun = (() => { 458 | const live = (() => { 459 | const doRecoil = gun => { 460 | let motion = gun.physics[0], position = gun.physics[1]; 461 | if (motion || position) { 462 | position += motion; 463 | motion -= 0.25 * position / ROOMSPEED; 464 | if (motion > 0) motion *= 0.75; 465 | } 466 | if (gun.settings.canShoot.get() && gun.settings.hasNoRecoil.get()) { 467 | if (motion > 0) gun.body.accelerate( 468 | -position * gun.physics[2] /*trueRecoil*/ * 0.045 / ROOMSPEED, 469 | gun.body.facing + gun.mechanics.angle 470 | ); 471 | } 472 | gun.physics[0] = motion; gun.physics[1] = position; 473 | }; 474 | const doLive = (() => { 475 | // The shooting function 476 | const fire = (() => { 477 | const bulletInit = (() => { 478 | const interpret = (() => { 479 | const out = { 480 | SPEED: 0.0, 481 | HEALTH: 0.0, 482 | RESIST: 0.0, 483 | DAMAGE: 0.0, 484 | PENETRATION: 0.0, 485 | RANGE: 0.0, 486 | DENSITY: 0.0, 487 | PUSHABILITY: 0.0, 488 | HETERO: 0.0, 489 | }; 490 | return gun => { 491 | const shoot = gun.properties.settings; 492 | const sk = gun.body.getSkills(); 493 | // Defaults 494 | out.SPEED = shoot.maxSpeed * sk[skc.spd]; 495 | out.HEALTH = shoot.health * sk[skc.str]; 496 | out.RESIST = shoot.resist + sk[skc.rst]; 497 | out.DAMAGE = shoot.damage * sk[skc.dam]; 498 | out.PENETRATION = Math.max(1, shoot.pen * sk[skc.pen]); 499 | out.RANGE = shoot.range / Math.sqrt(sk[skc.spd]); 500 | out.DENSITY = shoot.density * sk[skc.pen] * sk[skc.pen]; 501 | out.PUSHABILITY = 1 / sk[skc.pen]; 502 | out.HETERO = 3 - 2.8 * sk[skc.ghost]; 503 | // Special cases 504 | switch (gun.properties.calculator) { 505 | case 0: break; 506 | case 5: // THRUSTER 507 | gun.physics[3] = shoot.recoil * Math.sqrt(sk[skc.rld] * sk[skc.spd]); 508 | break; 509 | case 6: // SUSTAINED 510 | out.RANGE = shoot.range; 511 | break; 512 | case 3: // SWARM 513 | out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk[skc.pen] - 1) + 1)); 514 | out.HEALTH /= shoot.pen * sk[skc.pen]; 515 | break; 516 | case 8: // TRAP 517 | out.PUSHABILITY = 1 / Math.pow(sk[skc.pen], 0.5); 518 | out.RANGE = shoot.range; 519 | break; 520 | case 7: // NECRO 521 | case 2: // DRONE 522 | out.PUSHABILITY = 1; 523 | out.PENETRATION = Math.max(1, shoot.pen * (0.5 * (sk[skc.pen] - 1) + 1)); 524 | out.HEALTH = (shoot.health * sk[skc.str]) / Math.pow(sk[skc.pen], 0.8); 525 | out.DAMAGE = shoot.damage * sk[skc.dam] * shoot.pen * sk[skc.pen]; 526 | out.RANGE = shoot.range; 527 | break; 528 | } 529 | // Go through and make sure we respect its natural properties 530 | for (let property in out) { 531 | if (gun.properties.bullet.stat[property] == null || !out.hasOwnProperty(property)) continue; 532 | out[property] *= gun.properties.bullet.stat[property]; 533 | } 534 | return out; 535 | }; 536 | })(); 537 | const necroFunction = (gun, mancer, host) => { 538 | const body = gun.body, props = gun.properties; 539 | const reloadFactor = body.getSkills()[0]; 540 | const permission = props.countsOwnKids ? 541 | props.countsOwnKids > gun.children.length * reloadFactor : 542 | body.getMaxChildren() ? 543 | body.getMaxChildren() > body.getKids() * reloadFactor : 544 | true; 545 | if (permission) { 546 | __a.float[0] = host.getFacing(); 547 | __a.float[1] = host.getSize(); 548 | // Reset it as much as possible 549 | host.define(Class.genericEntity); 550 | // Turn it 551 | bulletInit(gun, host); 552 | // Init it with stuff 553 | host.setTeam(mancer.getTeam()); 554 | host.setMaster(mancer.getMaster()); 555 | host.setColor(mancer.getBulletColor()); 556 | host.setFacing(__a.float[0]); 557 | host.setSize(__a.float[1]); 558 | host.fullHeal(); 559 | return true; 560 | } 561 | return false; 562 | }; 563 | return (gun, o) => { 564 | const body = gun.body, props = gun.properties; 565 | // Define it by its natural properties 566 | props.bullet.types.forEach(type => o.define(type)); 567 | // Pass the gun attributes 568 | o.define({ 569 | BODY: interpret(gun), 570 | SIZE: body.size * gun.mechanics.width * props.settings.size / 2 , 571 | LABEL: this.master.label + (props.label === '' ? '' : ' ' + props.label) + ' ' + o.getLabel(), 572 | }); 573 | o.setColor(body.getBulletColor()); 574 | // Prepare to pass gun skills 575 | let skill = body.getSkills(); 576 | skill[5] = skill[6] = skill[7] = skill[8] = skill[9] = 0; 577 | o.assignSkills(skill); 578 | // Keep track of it and give it the function it needs to remove itself upon death 579 | gun.children.push(o); 580 | o.addDerefFunction(() => util.remove(gun.children, gun.children.indexOf(o))); 581 | if (body.getMaxChildren()) { 582 | body.addChild(o); 583 | } 584 | o.addDerefFunction((() => body.removeChild(o))); 585 | // Set the source 586 | o.setSource(body); 587 | // Necromancers' bullshit 588 | if (props.calculator === 7) o.necro = host => necroFunction(gun, o, host); 589 | // Otherwise 590 | o.refreshBodyAttributes(); 591 | o.life(); 592 | }; 593 | })(); 594 | return (gun, x, y, ddd) => { 595 | const body = gun.body, props = gun.properties, physics = gun.physics, mech = gun.mechanics; 596 | const sk = body.getSkills(); 597 | // Recoil 598 | gun.lastShot[0] = util.time(); 599 | gun.lastShot[1] = 3 * Math.log(Math.sqrt(sk[skc.spd]) + physics[3] + 1) + 1; 600 | physics.motion += gun.lastShot[1]; 601 | // Find inaccuracy 602 | let ss, sd; 603 | do { 604 | ss = ran.gauss(0, Math.sqrt(props.settings.shudder)); 605 | } while (Math.abs(ss) >= props.settings.shudder * 2); 606 | do { 607 | sd = ran.gauss(0, props.settings.spray * props.settings.shudder); 608 | } while (Math.abs(sd) >= props.settings.spray / 2); 609 | sd *= Math.PI / 180; 610 | // Find speed 611 | const speed = (props.negRecoil ? -1 : 1) * props.settings.speed * c.runSpeed * sk[skc.spd] * (1 + ss); 612 | let sx = speed * Math.cos(mech.angle + body.facing + sd), 613 | sy = speed * Math.sin(mech.angle + body.facing + sd); 614 | // Boost it if we should 615 | let velocity = body.getVelocity(); 616 | let vlen = getLength(velocity[0], velocity[1]); 617 | if (vlen) { 618 | let slen = getLength(sx, sy); 619 | let extraBoost = 620 | Math.max(0, sx * velocity[0] + sy * velocity[1]); 621 | if (extraBoost) { 622 | extraBoost /= slen * slen; 623 | sx += extraBoost * sx; 624 | sy += extraBoost * sy; 625 | } 626 | } 627 | // Create the bullet 628 | const position = body.getPosition(), size = body.getSize(); 629 | const o = makeEntity( 630 | position[0] + size * x - sx, 631 | position[1] + size * y - sy 632 | ); 633 | o.shove(sx, sy); 634 | o.forceSizeUpdate(); 635 | bulletInit(gun, o); 636 | }; 637 | })(); 638 | // The actual update function 639 | return gun => { 640 | // Live 641 | const body = gun.body, props = gun.properties, physics = gun.physics, mech = gun.mechanics; 642 | const sk = body.getSkills(); 643 | // Decides what to do based on child-counting settings 644 | let permission = (props.countsOwnKids ? 645 | props.countsOwnKids > gun.children.length * (props.calculator === 7 ? sk[0] : 1) : 646 | body.getMaxChildren() ? body.getKids().length * (props.calculator === 7 ? sk[0] : 1) : 647 | true) && !body.isInvulnurable(); 648 | // Cycle up if we should 649 | if (permission || !props.waitToCycle && physics.cycle < 1) 650 | physics.cycle += 1 / props.settings.reload / ROOMSPEED / ((props.calculator === 7 || props.calculator === 4) ? 1 : sk[skc.rld]); 651 | // Firing routines 652 | if (permission && physics.cycle >= 1 && (props.autofire || (props.altFire ? body.controls.alt.get() : body.controls.fire.get()))) { 653 | // Find the end of the gun barrel 654 | const gx = 655 | mech.offset * Math.cos(mech.direction + mech.angle + body.facing) + 656 | (1.5 * mech.length - mech.width * props.settings.size / 2) * Math.cos(mech.angle + body.facing); 657 | const gy = 658 | mech.offset * Math.sin(mech.direction + mech.angle + body.facing) + 659 | (1.5 * mech.length - mech.width * props.settings.size / 2) * Math.sin(mech.angle + body.facing); 660 | // Shoot, multiple times in a tick if needed 661 | while (permission && physics.cycle >= 1) { 662 | fire(gun, gx, gy, sk); 663 | // Figure out if we may still shoot 664 | permission = props.countsOwnKids ? 665 | props.countsOwnKids > gun.children.length * (props.calculator === 7 ? sk[0] : 1) : 666 | body.getMaxChildren() ? body.getKids().length * (props.calculator === 7 ? sk[0] : 1) : 667 | true; 668 | // Cycle down 669 | physics.cycle -= 1; 670 | } // If we're not shooting, only cycle up to where we'll have the proper firing delay 671 | } else if (physics.cycle > !props.waitToCycle - mech.delay) physics.cycle = !props.waitToCycle - mech.delay; 672 | }; 673 | })(); 674 | // The life function 675 | return gun => { 676 | doRecoil(gun); 677 | doLive(gun); 678 | }; 679 | })(); 680 | const getTracking = gun => { 681 | const speed = gun.body.getSkills()[skc.spd]; 682 | __a.float[0] = c.runSpeed * speed * gun.properties.settings.maxSpeed * gun.properties.bullet.stats.SPEED; 683 | __a.float[1] = speed * gun.properties.settings.range * gun.properties.bullet.stats.RANGE; 684 | return __a.float; 685 | }; 686 | return (body, info) => { 687 | const isInert = info.PROPERTIES == null; 688 | const properties = isInert ? null : { 689 | settings: info.PROPERTIES.SHOOT_SETTINGS, 690 | label: load('', info.PROPERTIES.LABEL), 691 | autofire: load(false, info.PROPERTIES.AUTOFIRE), 692 | altFire: load(false, info.PROPERTIES.ALT_FIRE), 693 | calculator: load(0, info.PROPERTIES.STAT_CALCULATOR), 694 | waitToCycle: load(false, info.PROPERTIES.WAIT_TO_CYCLE), 695 | countsOwnKids: load(false, info.PROPERTIES.MAX_CHILDREN), 696 | syncsSkills: load(false, info.PROPERTIES.SYNCS_SKILLS), 697 | negRecoil: load(false, info.PROPERTIES.NEGATIVE_RECOIL), 698 | bullet: (() => { 699 | let types = (Array.isArray(info.PROPERTIES.TYPE)) ? info.PROPERTIES.TYPE.splice() : [info.PROPERTIES.TYPE]; 700 | let stats = {}; 701 | types.forEach(function setStats(type) { 702 | if (type.PARENT != null) { // Make sure we load from the parents first 703 | for (let i=0; i {} : () => getTracking(gun), 737 | live: isInert ? () => {} : () => live(gun), 738 | }; 739 | }; 740 | }); 741 | // The attributes object 742 | const Attributes = () => { 743 | return { 744 | physical: { 745 | acceleration: 0, 746 | topSpeed: 0, 747 | penetration: 0, 748 | damage: 0, 749 | fov: 0, 750 | density: 0, 751 | stealth: 0, 752 | pushability: 0, 753 | range: 0, 754 | }, 755 | settings: { 756 | drawHealth: false, 757 | drawShape: false, 758 | damageEffects: false, 759 | ratioEffects: false, 760 | motionEffects: false, 761 | acceptsScore: false, 762 | givesKillMessage: false, 763 | canGoOutsideRoom: false, 764 | hitsOwnType: false, 765 | diesAtLowSpeed: false, 766 | diesAtRange: false, 767 | independent: false, 768 | persistsAfterDeath: false, 769 | clearOnMasterUpgrade: false, 770 | healthWithLevel: false, 771 | isObstacle: false, 772 | isNecromancer: false, 773 | hasNoRecoil: false, 774 | cravesAttention: false, 775 | buffVsFood: false, 776 | leaderboardable: false, 777 | reloadToAcceleration: false, 778 | variesInSize: false, 779 | isFood: false, 780 | isIntangable: false, 781 | }, 782 | body: { 783 | acceleration: 0, 784 | speed: 0, 785 | health: 0, 786 | resist: 0, 787 | shield: 0, 788 | regen: 0, 789 | damage: 0, 790 | penetration: 0, 791 | fov: 0, 792 | range: 0, 793 | density: 0, 794 | stealth: 0, 795 | pushability: 0, 796 | heteroMultiplier: 0, 797 | }, 798 | aiSettings: { 799 | farm: false, 800 | blind: false, 801 | chase: false, 802 | skynet: false, 803 | view360: false, 804 | reverseDirection: false, 805 | shapefriend: false, 806 | }, 807 | index: -1, 808 | mockup: {}, 809 | label: '', 810 | type: -1, 811 | shape: 0, 812 | color: 0, 813 | motionType: -1, 814 | facingType: -1, 815 | damageClass: 0, 816 | skillNames: 0, 817 | dangerValue: 1, 818 | squiggle: 1, 819 | upgrades: [], 820 | maxChildren: 0, 821 | creationMessage: '', 822 | }; 823 | }; 824 | // A definer 825 | const define = (() => { 826 | const check = val => { 827 | return val != null; 828 | }; 829 | return (def) => { 830 | const obj = Attributes(); 831 | if (def.PARENT != null) { 832 | for (let i=0; i { 845 | toAdd.push(eval('new io_' + ioName + '(this)')); 846 | }); 847 | this.addController(toAdd); 848 | } 849 | if (check(def.MOTION_TYPE)) obj.motionType = def.MOTION_TYPE; 850 | if (check(def.FACING_TYPE)) obj.facingType = def.FACING_TYPE; 851 | if (check(def.BROADCAST_MESSAGE)) obj.creationMessage = def.BROADCAST_MESSAGE; 852 | if (check(def.DAMAGE_CLASS)) obj.damageClass = def.DAMAGE_CLASS; 853 | if (check(def.STAT_NAMES)) obj.skillNames = def.STAT_NAMES; 854 | if (check(def.DANGER)) obj.dangervalue = def.DANGER; 855 | // Settings stuff 856 | if (check(def.DRAW_HEALTH)) obj.settings.drawHealth = def.DRAW_HEALTH; 857 | if (check(def.DRAW_SELF)) obj.settings.drawShape = def.DRAW_SELF; 858 | if (check(def.DAMAGE_EFFECTS)) obj.settings.damageEffects = def.DAMAGE_EFFECTS; 859 | if (check(def.RATIO_EFFECTS)) obj.settings.ratioEffects = def.RATIO_EFFECTS; 860 | if (check(def.MOTION_EFFECTS)) obj.settings.motionEffects = def.MOTION_EFFECTS; 861 | if (check(def.ACCEPTS_SCORE)) obj.settings.acceptsScore = def.ACCEPTS_SCORE; 862 | if (check(def.GIVE_KILL_MESSAGE)) obj.settings.givesKillMessage = def.GIVE_KILL_MESSAGE; 863 | if (check(def.CAN_GO_OUTSIDE_ROOM)) obj.settings.canGoOutsideRoom = def.CAN_GO_OUTSIDE_ROOM; 864 | if (check(def.HITS_OWN_TYPE)) obj.settings.hitsOwnType = def.HITS_OWN_TYPE; 865 | if (check(def.DIE_AT_LOW_SPEED)) obj.settings.diesAtLowSpeed = def.DIE_AT_LOW_SPEED; 866 | if (check(def.DIE_AT_RANGE)) obj.settings.diesAtRange = def.DIE_AT_RANGE; 867 | if (check(def.INDEPENDENT)) obj.settings.independent = def.INDEPENDENT; 868 | if (check(def.PERSISTS_AFTER_DEATH)) obj.settings.persistsAfterDeath = def.PERSISTS_AFTER_DEATH; 869 | if (check(def.CLEAR_ON_MASTER_UPGRADE)) obj.settings.clearOnMasterUpgrade = def.CLEAR_ON_MASTER_UPGRADE; 870 | if (check(def.HEALTH_WITH_LEVEL)) obj.settings.health = def.HEALTH_WITH_LEVEL; 871 | if (check(def.OBSTACLE)) obj.settings.isObstacle = def.OBSTACLE; 872 | if (check(def.NECRO)) obj.settings.isNecromancer = def.NECRO; 873 | if (check(def.HAS_NO_RECOIL)) obj.settings.hasNoRecoil = def.HAS_NO_RECOIL; 874 | if (check(def.CRAVES_ATTENTION)) obj.settings.cravesAttention = def.CRAVES_ATTENTION; 875 | if (check(def.BUFF_VS_FOOD)) obj.settings.buffVsFood = def.BUFF_VS_FOOD; 876 | if (check(def.CAN_BE_ON_LEADERBOARD)) obj.settings.leaderboardable = def.CAN_BE_ON_LEADERBOARD; 877 | if (check(def.IS_SMASHER)) obj.settings.reloadToAcceleration = def.IS_SMASHER; 878 | if (check(def.INTANGIBLE)) obj.settings.isIntangable = def.INTANGIBLE; 879 | if (check(def.VARIES_IN_SIZE)) obj.settings.variesInSize = def.VARIES_IN_SIZE; 880 | // AI settings 881 | if (check(def.AI)) { 882 | if (check(def.AI.NO_LEAD)) obj.aiSettings.chase = def.AI.NO_LEAD; 883 | if (check(def.AI.SKYNET)) obj.aiSettings.skynet = def.AI.SKYNET; 884 | if (check(def.AI.BLIND)) obj.aiSettings.blind = def.AI.BLIND; 885 | if (check(def.AI.FARMER)) obj.aiSettings.farm = def.AI.FARMER; 886 | if (check(def.AI.FULL_VIEW)) obj.aiSettings.view360 = def.AI.FULL_VIEW; 887 | if (check(def.AI.STRAFE)) obj.aiSettings.reverseDirection = def.AI.STRAFE; 888 | if (check(def.AI.LIKES_SHAPES)) obj.aiSettings.shapefriend = def.AI.LIKES_SHAPES; 889 | } 890 | // Upgrades stuff 891 | if (def.RESET_UPGRADES) obj.upgrades = []; 892 | if (check(def.UPGRADES_TIER_1)) 893 | def.UPGRADES_TIER_1.forEach(e => { 894 | obj.upgrades.push({ class: e, level: c.TIER_1, index: e.index,}); 895 | }); 896 | if (check(def.UPGRADES_TIER_2)) 897 | def.UPGRADES_TIER_2.forEach(e => { 898 | obj.upgrades.push({ class: e, level: c.TIER_2, index: e.index,}); 899 | }); 900 | if (check(def.UPGRADES_TIER_3)) 901 | def.UPGRADES_TIER_3.forEach(e => { 902 | obj.upgrades.push({ class: e, level: c.TIER_3, index: e.index,}); 903 | }); 904 | if (def.SIZE != null) { 905 | this.SIZE = def.SIZE * this.squiggle; 906 | if (this.coreSize == null) { this.coreSize = this.SIZE; } 907 | } 908 | if (def.SKILL != null && def.SKILL != []) { 909 | if (def.SKILL.length != 10) { 910 | throw('Inappropiate skill raws.'); 911 | } 912 | this.skill.set(def.SKILL); 913 | } 914 | if (def.LEVEL != null) { 915 | if (def.LEVEL === -1) { 916 | this.skill.reset(); 917 | } 918 | while (this.skill.level < c.SKILL_CHEAT_CAP && this.skill.level < def.LEVEL) { 919 | this.skill.score += this.skill.levelScore; 920 | this.skill.maintain(); 921 | } 922 | this.refreshBodyAttributes(); 923 | } 924 | if (def.SKILL_CAP != null && def.SKILL_CAP != []) { 925 | if (def.SKILL_CAP.length != 10) { 926 | throw('Inappropiate skill caps.'); 927 | } 928 | this.skill.setCaps(def.SKILL_CAP); 929 | } 930 | if (def.VALUE != null) { 931 | this.skill.score = Math.max(this.skill.score, def.VALUE * this.squiggle); 932 | } 933 | if (def.ALT_ABILITIES != null) { 934 | this.abilities = def.ALT_ABILITIES; 935 | } 936 | if (def.GUNS != null) { 937 | let newGuns = []; 938 | def.GUNS.forEach((gundef) => { 939 | newGuns.push(new Gun(this, gundef)); 940 | }); 941 | this.guns = newGuns; 942 | } 943 | if (def.MAX_CHILDREN != null) { 944 | this.maxChildren = def.MAX_CHILDREN; 945 | } 946 | if (def.FOOD != null) { 947 | if (def.FOOD.LEVEL != null) { 948 | this.foodLevel = def.FOOD.LEVEL; 949 | this.foodCountup = 0; 950 | } 951 | } 952 | if (def.BODY != null) { 953 | if (def.BODY.ACCELERATION != null) { 954 | this.ACCELERATION = def.BODY.ACCELERATION; 955 | } 956 | if (def.BODY.SPEED != null) { 957 | this.SPEED = def.BODY.SPEED; 958 | } 959 | if (def.BODY.HEALTH != null) { 960 | this.HEALTH = def.BODY.HEALTH; 961 | } 962 | if (def.BODY.RESIST != null) { 963 | this.RESIST = def.BODY.RESIST; 964 | } 965 | if (def.BODY.SHIELD != null) { 966 | this.SHIELD = def.BODY.SHIELD; 967 | } 968 | if (def.BODY.REGEN != null) { 969 | this.REGEN = def.BODY.REGEN; 970 | } 971 | if (def.BODY.DAMAGE != null) { 972 | this.DAMAGE = def.BODY.DAMAGE; 973 | } 974 | if (def.BODY.PENETRATION != null) { 975 | this.PENETRATION = def.BODY.PENETRATION; 976 | } 977 | if (def.BODY.FOV != null) { 978 | this.FOV = def.BODY.FOV; 979 | } 980 | if (def.BODY.RANGE != null) { 981 | this.RANGE = def.BODY.RANGE; 982 | } 983 | if (def.BODY.SHOCK_ABSORB != null) { 984 | this.SHOCK_ABSORB = def.BODY.SHOCK_ABSORB; 985 | } 986 | if (def.BODY.DENSITY != null) { 987 | this.DENSITY = def.BODY.DENSITY; 988 | } 989 | if (def.BODY.STEALTH != null) { 990 | this.STEALTH = def.BODY.STEALTH; 991 | } 992 | if (def.BODY.PUSHABILITY != null) { 993 | this.PUSHABILITY = def.BODY.PUSHABILITY; 994 | } 995 | if (def.BODY.HETERO != null) { 996 | this.heteroMultiplier = def.BODY.HETERO; 997 | } 998 | this.refreshBodyAttributes(); 999 | } 1000 | if (def.TURRETS != null) { 1001 | let o; 1002 | this.turrets.forEach(o => o.destroy()); 1003 | this.turrets = []; 1004 | def.TURRETS.forEach(def => { 1005 | o = new Entity(this, this.master); 1006 | ((Array.isArray(def.TYPE)) ? def.TYPE : [def.TYPE]).forEach(type => o.define(type)); 1007 | o.bindToMaster(def.POSITION, this); 1008 | }); 1009 | } 1010 | if (def.mockup != null) { 1011 | this.mockup = def.mockup; 1012 | } 1013 | }; 1014 | })(); 1015 | // Return the constructor 1016 | return (x, y) => { 1017 | const creationTime = util.time(); 1018 | const status = newStatusBox(); 1019 | const kills = newKillBox(); 1020 | const skills = newSkills(); 1021 | // Inheritance and control 1022 | let family = { 1023 | master: null, 1024 | source: null, 1025 | parent: null, 1026 | }; 1027 | // Health 1028 | const health = healthTypes.newStatic(); 1029 | const shield = healthTypes.newDynamic(); 1030 | // Return the new entity 1031 | return { 1032 | life: () => {}, 1033 | getSkills: () => { return skills.get(); }, 1034 | refreshBodyAttributes: () => {}, 1035 | define: type => {}, 1036 | setTeam: team => {}, 1037 | getTeam: () => {}, 1038 | setMaster: master => {}, 1039 | getMaster: () => {}, 1040 | setColor: col => {}, 1041 | setFacing: dir => {}, 1042 | setSize: size => {}, 1043 | getFacing: () => {}, 1044 | getSize: () => {}, 1045 | getLabel: () => {}, 1046 | getMaxChildren: () => {}, 1047 | addChild: newlyborn => {}, 1048 | removeChild: deadkid => {}, 1049 | addDerefFunction: func => {}, 1050 | isInvulnurable: () => {}, 1051 | getVelocity: () => { return [0, 0]; }, 1052 | getPosition: () => { return [0, 0]; }, 1053 | accelerate: (amount, direction) => {}, 1054 | shove: (x, y) => {}, 1055 | forceSizeUpdate: () => {}, 1056 | getBulletColor: () => {}, 1057 | assignSkills: assignment => skills.set(assignment), 1058 | necro: () => {}, 1059 | fullHeal: () => {}, 1060 | }; 1061 | }; 1062 | }); --------------------------------------------------------------------------------