Skip to content

Instantly share code, notes, and snippets.

@Ge0rg3
Created February 1, 2019 07:20
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Ge0rg3/dae8a336a0929acafb73144fea1bf6ef to your computer and use it in GitHub Desktop.
Save Ge0rg3/dae8a336a0929acafb73144fea1bf6ef to your computer and use it in GitHub Desktop.
Gynvael's Winter GameDev Challenge 2018/19
<head>
<title>Game</title>
<meta charset="UTF-8">
<style>
html, body {
margin: 0px;
padding: 0px;
}
/* https://www.dafont.com/typecast.font?l[]=10&l[]=1 */
@font-face {
font-family: 'Typecast';
src: local('Typecast'), url(Typecast.woff2) format('woff2');
}
</style>
</head>
<body>
<!-- We have to use a button so that we can force Full screen. Can probably style nicely later on-->
<button onclick="run(true)" id="run" style="width:100%;"><h1>Click here to enter fullscreen</h1></button>
<button onclick="fullscreen()" style="display: none; width:100%;" id="fs"><h1>If you can read this, click here.</h1></button>
<!-- Game will be loaded into here -->
<div id="game"></div>
</body>
<script>
/*
Info:
GB (Game box), (61, 183, 1024, 768), center=(573, 567)
CB (Control box), (1137, 75, 720, 480), center=(1497, 315)
Marine size: Image=(13x16), Render=(52x64)
Entities:
-Level
-Marine
-Robot
-Door
-Joystick
-Damage box
-Bullet
-Breakout
*/
//Helper functions
const fullscreen = () => {
try{gameDiv.webkitRequestFullscreen();}catch(ex){null;}
try{gameDiv.mozRequestFullScreen();}catch(ex){null;}
try{gameDiv.msRequestFullscreen();}catch(ex){null;}
}; //Forces fullscreen
const ranbetween = (l, h) => Math.floor(Math.random()*(h-l+1)+l); //Inclusive random number generator
const distBetweenTwoPoints = (x1, y1, x2, y2) => Math.sqrt((x1-x2)**2 + (y1-y2)**2);
const collide = (x1, y1, w1, l1, x2, y2, w2, l2) => !(x2 > x1+w1-1 || x2+w2-1 < x1 || y2 > y1 + l1-1 || y2 + l2-1 < y1); // *EX*CLUSIVE Collision detection: X1, Y1, Width1, Length1, X2, Y2, Width2, Length2
var requestAnimationFrame = requestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame || window.mozRequestAnimationFrame;
document.body.onmousedown = () => mouseDown = 1;
document.body.onmouseup = () => mouseDown = 0;
window.onblur = () => mouseDown = 0;
document.addEventListener('contextmenu', event => event.preventDefault());
//Global variables (bad practice who?)
const tag = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAA";
var renderType, s, ctx, canvas, marine, selectedmarine, currentMinigame, currentLevel, moveMarine, gameoverObj, previousRenderType;
var mouseDown=upgradeCount=totalRobotsKilled=money=totalDoorsHacked=minigameCount=startTimer=0,levelCount=mX=mY=1;
var levels=[], doors=[], marines=[], damageboxes=[], enemies=[], bullets=[], items=[]; //Entity arrays
var keysDown = {};
var gameOver = false;
/*
Class definitions
*/
class Sprites {
constructor() {
this.marine1a = new Image(); //Marine 1, standing facing right
this.marine1a.src = tag+"A0AAAAQCAYAAADNo/U5AAABKElEQVQokYWSsUrDYBSFv5t2CwUpmUyLi0s7pPQNujh1EMRH6NIXcvIRRBCcdKkvoNKhXTooMZ1KKUjGcBxMftOY6oEf7s9/zr3nHn4bTwcUWK92enl8d3dJZmZUYQDj6YD4KdF8seF6Jvc4GdUoAA9gPovVCH2ifsBk9MMruyijWRRZktIIfaLvCQB0e+16UbfXVtBp7QmHoQ/A5uPTES/OLwVwe3djzZpGZEkKQNBpKV5uyckAXM8kK08qT6vWeaoGyKvaaIQ+WZLuCXIUCZkXL7e1sf6Lbq8twB1JSGJ4dqKoH6jKt/F0wHq1U3mH49MjA7i/euXgj4j6gcr+syRlvtgctO0BbuHnhzerCeC3SJLrXjQo6oPIRS4ASoH8aa+AmVWJtcIvkoSFvliaHUUAAAAASUVORK5CYII="; //Left
this.marine1aa = new Image(); //Marine 1, walking right 1
this.marine1aa.src = tag+"A0AAAAQCAYAAADNo/U5AAABKElEQVQokYWSsU4CQRiEv/+gu5AYcpUHsbGB4ghvQGNFYWJ8BBpeyIpHMCYmVtrgC6ihgIZCcx4VISTmystYeBzLeegkm/ybndl//tm14bjHDqvlVq9PH8VekpkZZRjAcNwjfk40m6+ZTFUcjgYVCsADmE1j1UKfqBswGux5rgsX9V2RJSm10Cf66QBAu9OsFrU7TQWtxoGwH/oArD+/CuLV5bUA7u5vrV5xEVmSAhC0GooXG3IyAJOpZG4nt1u5zlM1QF7ZRi30yZL0QJBjl5B58WJTGeu/aHeaAoolCUn0L84UdQOV+TYc91gtt3JnOD0/MYCHmzeO/oioG8j1nyUps/n6qG0PKAZ+eXy3igB+w/UuCXe2P0VuACVRpfDgR5iZ2L/HUXwDiY6I4fwyIO0AAAAASUVORK5CYII=";
this.marine1ab = new Image(); //Marine 1, walking right 2
this.marine1ab.src = tag+"A0AAAAQCAYAAADNo/U5AAABK0lEQVQokYWSsUrDYBSFv5t2CwUpmUyLi0s7pPQNujh1EMRH6NIXcvIRRBCcdKkvoNKhXTooMZ1KKUjGcBxM0iRN9cAP9+ee899zD7+NpwMyrFc7vT1/5ndJZmZUYQDj6YDwJdJ8seF2prw5GdUoAAdgPgvV8F2CvsdktOcVXRTRzIokimn4LsHvBAC6vXa9qNtry+u0SsKh7wKw+frOiVeX1wK4f7izZs1DJFEMgNdpKVxuSckA3M4kK04qTqvWaaoGyKnaaPguSRSXBCmyhMwJl9vaWP9Ft9cWkB9JSGJ4caag76nKt/F0wHq1U3GH0/MTA3i8eefojwj6nor+kyhmvtgcte0A+cKvTx9WE8ABmpJKFrL0/hSVvJoVlxb7mA/tpU2rIR0kB/ADdaJ4/uRp/nkAAAAASUVORK5CYII=";
this.marine1b = new Image(); //Marine 1, standing facing left
this.marine1b.src = tag+"A0AAAAQCAYAAADNo/U5AAABIklEQVQokYWQsU4CURBFz8h2xISQrVgJDQ0UKF8gDZUmJsZPoNEfsuETjImFjRVfYCKFNBYmy1oRNCFbrteG97IuT5zqTd7cO3OPEShJmJlcPxx3aHUb5vooJDIzpjOvYTIyiixX+zSxx9sXDkKis+vjX4JBP6aW1JnPUgFYSNTuNUkXawFeUGQ5n/omXawtAri8uBLA/cOdNxmOO96kyHJqSZ14GzmazqTJyM8KID46pMhyAGpJfTfzdtAAOXfnXH0DrJYbolIuZ+AzVDetlhuAML19lS7Wu/AG/VjDcUeSkORyClC71/wbuSTOb04A+Hj7UjlXq9uwoKi8tZypyHLmryvbm8kBeX56N9fDPyCq6N3p+8oDKAORFAaxHQh/SPYDwQGDWZpaWdQAAAAASUVORK5CYII="; //Right
this.marine1ba = new Image(); //Marine 1, walking left 1
this.marine1ba.src = tag+"A0AAAAQCAYAAADNo/U5AAABJklEQVQokX2SsU4CQRRFz5PtiAkhW7GSbWigQPkCaag0MTF+Ao3+kA2fYEwsbLThCzRSSGOhWdaKoAnZcr02zGSBhanmTd65792bMUqOJMxMru4NYhqtmrk6KIPMjNHYMwz7Rp5map5G9nj7xkEZdHZ9vAZ0OyGVqMpknAjAyqBmu04yXQjwQJ5m/OiPZLqwAODy4koA9w93XqQ3iL1InmZUoirhynIwGkvDvu8VQHh0SJ5mAFSi6rbnVaMBcupOefMOMJ8tCQq+nID3sDlpPlsClKe37yTTxXZ43U6o3iCWJCQ5nwLUbNd3Ry6J85sTAL4/flX01WjVrBQqTi16ytOMyfvc9npygbw8fZqrYcffKyq7xtfnL7/6vvVU+ijZrkmbwJr4P7bTeP4hczfdAAAAAElFTkSuQmCC";
this.marine1bb = new Image(); //Marine 1, walking left 2
this.marine1bb.src = tag+"A0AAAAQCAYAAADNo/U5AAABLElEQVQokX2SsUoDQRRFz3O3C0IIW2UNadIkRTRfYJpUCoL4CWn0h2zyCSJY2GiTL1BMYRoLZbNWIQphy/VamFk2ycSBgffg3fvmXMbwHEmYmVzfGzSpt6rm+tAnMjNG40LDsG/kaabGcWz31y/s+UQnl4drgm4nIogrTMaJAMwnarRrJNOFgEKQpxlf+iGZLiwEOD+7EMDt3U1h0hs0C5M8zQjiCtEKORyNpWG/mBVAdLBPnmYABHFlm3k1aICcu3PerAHmsyVhicsZFAybm+azJYA/vf9OMl1sh9ftROoNmpKEJMcpQI12bXfkkji9OgLg8+1bZa56q2peUXlrmSlPMyavc/uXyQXy9PBurocdf8+98vnxY21LEFccp19QvuVAJPmD2GHyV0j2C04XhO1jSysDAAAAAElFTkSuQmCC";
this.marine1c = new Image(); //Marine 1, Glowing
this.marine1c.src = tag+"BMAAAAWCAYAAAAinad/AAABoklEQVQ4ja2Vv2vCQBTHv2mki9gp2EFRh5s6FAS3FuyiGQulgjg3/ZuKcW0pWAodjYsB3UIFB6cMWuqguBUXIdiheeclOaNCv9PL/fjw3vfeXYB/lCIbLBlWTTbumNX2UTAfpAMoh6ZsAJ04YAAmgryJwYbdqTjnEjC3aHLg+8cbX5OQgdaDBhuNl2j1Nnzh03OXx1/pxxoAiFAAOBFiHUB53q8zNZPE5YWGhxuppbRWJ2gAFjbcm60gAkNQ8rMMQBf3KmJ5836dadlUAEhSC6ZLcW7RZH653EfHrLa5ZwDSsnq82cqPtgfi+COtXpuRlyXDCngWkJpJ8uwoLlbyKFbytNkNeypmtgBwtvz+AZVKEIpJ1CYlw4JY5onfhB0A9vn1q4vjFGjkhGyFpFnhTQzmzVY4vXrhpgPBKxaBadkUtGwqfJq2WjChFqLZiIocQNij9aDB8NdTdhxICiPIpzVRwr0WB5LCwtlt+2y/IrBhd4rReBmIHbNKpfLrc3d7f1hmAKAoykb8lgEjeyiIeRRFxR7Arsdxlw5/aQWgVPv+Ab8RiMuNB81h5QAAAABJRU5ErkJggg=="; //Selected
this.marine1d = new Image(); //Marine 1, Greyscale
this.marine1d.src = tag+"A0AAAAQCAQAAABnqj2yAAAD13pUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarVdtkusoDPzPKfYISEJ8HAcbqHo32ONvg7GT2HEm82rNJMhCSKhbIjWm/vunmX/wUBRvnIbok/cWj0sucYYQ7fZsM1k3vrenzJle9WZftwyVYJbt1ddpn6HXx4bgpn551ZuwTj9xOqLD8XikR+7ytIvTkfCmp/lu0tyX3VM688PrdDudn99dABhF4U/YcBUSi+/YowhOIEnymDPeI3fJQpbxTeLfY2d27M7gHdIJO5unXl6hMNZPA3/CaOpJT3o5wvCZtT3yywIcePv8PGHXWomt1S277DyQ8mYmtacyJBgugFLGNo8R8FHIYYyEEZHiCsYK2FwwVkOJGGg2clQoU6M65pVWHNFx5YCZeWUZuiiBE6+DDNcHNQ6gpxiJ4GYFawI1H2ehETeNeCtFRC5oBGaCM8KOyzDvlH8zDket9dIlsnHDqQyCudc0jtGZ69+wAiHUJqY68B3DPNWNfSJWwKAOmCMSzHbZXCxKj9qSwbPATq0zdmsNCmU6AESIrTgMCRiwnkTJkw3MgQg4RvCTcXIWxwsYIFUuZBq4EfEgB92A2NgTaNiy8qbG1QIiVLwEUIMGAlnOKeonuIgayirqjKp6DRo1afbinVfvffD9jspBggsafAghhhRylOiiRh9DjDHFnDgJrjBNPgWTYkopZwTNcJ2xO8Mi54UXWdyii1/CEpe05BXls7pVV7+GNa5pzYWLFLR/8SWYEksquVJFKVVXtfoaaqyp5oZaa9Jc0+ZbaLGllg/WaLbtC2t0Yu4zazRZ64y5YRcerEEdwu6C+nWinTMwxo7AeOgMoKC5c2YjOceduc6ZTYymUAZrpJ2cQp0xMOgqsTY6uHsw95E3o+5XvPEdc6ZT938wZzp1k7krb29YK3n8osggqHdhx9RKM12bOeLPnmeB9ynFW5va2hBNl+2d2e32ApC6bG3loco4UdVdiaPnKfJpbsn6m6XDEd8Y1LR7LWk/Ce+qS3TzEpZ537GG/PEAl9k8BU77WtEPJ7geuHqsma+ivsnSnmKZp/gXbugl5iv4erI2gGOp3wd+mzfvYD/W4o8VVJd6iD7sovfmBpU17zYXlN8vbWDXL2Dmu6zt0SJ8sb2F/z51s5vg8jjy/Sld+yY3c8rkFyX1WhOvLbK0eq6XeKgeIKc3qZvb6yF8wRZi7Ebm6OGjS1v8tlEf+eZsfiTqQ9/yHUa3Aa/QLU8o5vwXLXLbOma/vHvvSLvk05bHVfiRQPPr0Ij89HKI5ieDb2fz28i/dvR1qg2/vvhfzfwH7s90dNY3EXgAAAACYktHRAD/h4/MvwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+MBHAoeGLERIEQAAACrSURBVBjTZdC9ccJAFEXh72loQQGpAwI14RkqcAtqzDVQAQOBAzdAoICUQEVcB/oDfINNznt3z2714J4rSJUlRe83N2dw3IiGn7Q6R9BvxA5GCzw8oTpkP0N41ICvcKrdNjVinwEnnDNvLXvTeaWk4QFa41qrUM3wpPsvh4hIxGe6rIa9e6Y7PopvL7/RpZ1Fbi/lDS0utSpsKPOLWuO7REwKk8pbIVS2ySV/FxE9n8LUeVwAAAAASUVORK5CYII="; //Dead
this.marine2a = new Image(); //Marine 2, standing facing right
this.marine2a.src = tag+"A0AAAAQCAYAAADNo/U5AAAAvUlEQVQokY2RMQ7DIAxFP6gnYG+R2DqFe+QkOWZP0QmkqHvGrr9DMbWAJP0SiiF+/sYAvVjWriwAhBQ5LxMAMHtXYfKQBUOK4sCQouyPoeLC7F0Fi/s+JMkavN7dMNnqTfYOYd1q/HputUVdwEJNKqwbZBAqJgA+3r9uLlJVS9zas5AiAm79fdp7yReD92t/kCQU0GteJrSV52XC2eN2bZb4WAKctlUtvm0we0cd/wWJEwaT0rLtgTFGJw/BD7dMle8bgNZLAAAAAElFTkSuQmCC";
this.marine2aa = new Image(); //Marine 2, walking right 1
this.marine2aa.src = tag+"A0AAAAQCAYAAADNo/U5AAAAvklEQVQokY1SMQ7DIBAzUV7A3iLd1in8Iy/JM/uKTCBF3TN2dYdyFEFCaglxwPlsDoAWTOMUAwBI8JyXCQAYnc1ksssFJXhVoASv6z4pqTA6m4lJ/ZykySXx9rCHyUO5iM5Ctj3Hr3XPFssCA4pOybZDG1HEBMDn++dm1KolVK3ek+AhuLf3qe+lMw7erz4gSRSEFvMyoa48LxOuHrexmeI+lHBpK0t8bTA6q//tf5Iq4aRbirHeMMYQgOmJfABfB5Tj6h61nQAAAABJRU5ErkJggg==";
this.marine2ab = new Image(); //Marine 2, walking right 2
this.marine2ab.src = tag+"A0AAAAQCAYAAADNo/U5AAAAu0lEQVQokY2SPQ7DIAyFX6OegL1F8tYp3CMnyTF7ikxEirpn7Po6FLsW5KdPQjGEz88YgFYsY1cdAEhOHMYeADjHYDB5yIKSkzpQctL5MVRcOMdgYHHfh3SzB2+PsLm585M5BsiyWvyaVivRJ+jgOiXLCm2EiwmAz/evmqtm9VK3ek1yguDenqc+l36xcX/1D5KEA1oNY4868zD2OLvcpswSH0uB07LM4luGQc71Pwg7nfLyL+LihuXbgj5Ky5HjpxLDBwAAAABJRU5ErkJggg==";
this.marine2b = new Image(); //Marine 2, standing facing left
this.marine2b.src = tag+"A0AAAAQCAYAAADNo/U5AAAAv0lEQVQokYWSPQ6DMAyFHxwhexspWyc4RDdOwiUr9RSdiIS6Z+z6OuCkzl/5pAgr+PnZBuA/lJMxNjPJKIC3BgC4rBPcNlcFMtw2U5IIQMdtVFV6a+itSeKu6HI7WtICJfzNJIkAgPcrUGaB20OcKzHGKs9Psqe3Bm4PiIuIscDRbTPuj2v5IrloSkftUi2gNVcJvTVU36o8bUhiWadUID7lrk9v3WdkbYrw3OnolFl86qQSM1HzL9f9D8NQlf8CQryWzUjq0gUAAAAASUVORK5CYII=";
this.marine2ba = new Image(); //Marine 2, walking left 1
this.marine2ba.src = tag+"A0AAAAQCAYAAADNo/U5AAAAvUlEQVQokYWRMQ6DMAxFf6OeIHsbKVsnOEQ3TsIlK/UUnYiEujN2/R2wgwkBnmRhJfn+tgGOocQKV31JqgApeABg1zeIQ7spsCIOLeURAdi8jqnKFDxT8Fm8K7o95paswAiXmeQhAOD7mSizII6TzpVxWuX9y/ZMwSOOE3QRmgt0cWjxfN3Li+xiKR2ty2YBtblKmIKn+Vdl1CGJrm9yAf3K2T576z5j1aYIz53mTpfZJD92KkNF1wOBcikv/x+vksEji5p6AAAAAElFTkSuQmCC";
this.marine2bb = new Image(); //Marine 2, walking left 2
this.marine2bb.src = tag+"A0AAAAQCAYAAADNo/U5AAAAwElEQVQokYWROw6DMBBEB5QTuE8suUsFh0jHSbhkpJwiFZZQesq0k4K1s/7BkyxW9s7sB+AYyknoq5lkEMBbAwCc5gFuGQuDBLeMlCQC0HEd5UpvDb01UdwUXe97S1qghP+ZJBEA8HlvlFng1i3MFemDy+sby9NbA7duCIsIscDeLSMez1v+EKto8oq6SrGA2lw59NZQ/av81CGJaR6iQfjKXZvWus9I2hThuWjvlAiVxOBYoBIT0aUh6mLQdYX9D+polcEggbzSAAAAAElFTkSuQmCC";
this.marine2c = new Image(); //Marine 2, Glowing
this.marine2c.src = tag+"BMAAAAWCAYAAAAinad/AAABWElEQVQ4jZWUvW3DMBCFH41M4PRxQGkAF+zVGNIEBjxAtEKQXbSBPYFZBHCvQgPYCrSAVmCK8IQTeaKcBxAi+PPpHXk8ICFT26Op7TG1hmsjAdi3AlA9C1QCqAJw9d/CT90AXNumvKRgLwKIAEXblLmfozVIATchaPz6zAnU77YAAA8tsBJydGZ91sEDoYcR+rGHfuxT0cVhhkBypbMugnF3POzIGQD0uy30ME79Puv4dMUbB4swCcjOLWwTUPHDp9sj0BSq73M4jZva3uFTJ74Av5BEgHDs8P0WnaV4AdzJorusm7lqm/KigHmeUahcprb3sz3lLCzS7GUotmEC0kZyIgAAAG1TfvCfircZhnm2J3J7w9+7pTaTnLQe5JxTP++vTg8jDJtfep9JZ2F/TYtJy1NCSo9/wQBAKeWo/0zlWCqOhbQYK0VShQMMKClZbSMYA0ZaK9u/SK/IYu8eWHAAAAAASUVORK5CYII=";
this.marine2d = new Image(); //Marine 2, Greyscale
this.marine2d.src = tag+"A0AAAAQCAQAAABnqj2yAAADm3pUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZVbsusoDEX/NYoeApJ4DgeDqboz6OH3BhMncRyf5Nw2FYNlkMRewqH13z+N/sHF0UayLkSfvDe4bLJJMgbRbNfWs7Hjvl119vxsp9t7IzApet0e/TrnZ9jdfUGw07482ymU6SdOR7w7Hpf2yH0858XpSGWz83ymNNdl+7Cd+ZMy3U7nx2cbIEZ18KdCsiqrwT32KIoMNGkefcZzlD4yGKta3K2+0Y5u2h3F20cH7Uyedn2WgoyfE/xBo2lnd7DrHkaO1G6Rn16I7CFetGutxtbWbXfZeijlaW7qtpUxwsQFUupY5tECfg7jMFpCi9hiAbEKmgtaIU4sULOx5cqZG6+jL1yQopVVAnqRIjpsUYMkKQOG7Y2bBOCppBFsCqh1KrLnwiNuGvEKR0SujJnCcMZY8dLozPibtjtqrZcus4mbTnUAll7TSKOT63fMAhBuU1M39B2NHurGPIBVEHRD5ogNZrNsLhbH99rSwVkxzxlLZjsaHOp0AIkQ2yEZVhAwntWxZxNEAjN0jOCTkbmolQUE2DmpTA1sVD3g4DQgNtYEHnPFyWbGpwUgnHoNQIMDBFjWOtRPsBE1lJ06S84574KLLrns1VvvvPfB929UDhpscMGHEGJIIUfFF8xFH0OMMcWcJCk+YS75FCjFlFLOCJrhOmN1xoycF1l0sYtb/BKWuKQlF5RPscUVX0KJJZVcpWrF8a++BqqxpppXXlFKq13d6tewxjWtuaHWmjbbXPMttNhSyzs1nsf2iRofyF1T40mtE7NjXrhTgzmEmwvunxPXmYGYWAbx0AmgoKUzM5GtlU6uMzNJcCicgBq7DqdyJwaCdmVxjXd2d3KX3MjZr7jJO3LU0f0f5Kijm+ReuZ1Qq3n8o+gA1E9h19Row4cNE9aYJeb+n/Trnr5agJRuMZtwHmajpSuxOWpBd6u+rF7uq+PbGPRNEuniLd1t6W8kEnryv+/QvO70Qp/njD4W/EzPFugihzXl28j7n8LQj3HPdnnykvRdjG/ygWf6LJ5eKrRTu1z6oX/ST5aevDxWBT3a0k+ML4z0nRLve/qiEh8Obyr70JRjRj/1WuOtDKq8JExvdu7309Q/lbfhRTD6NJuXvTwZO7XDW/PLns5jra3tw88I0vfE4lm1rRTLq5SnWf6wN3rV9XFbn7+lv1L4wS1dFscXPZ3FwR9zov8ALfV60LB6KOwAAAACYktHRAD/h4/MvwAAAAlwSFlzAAAuIwAALiMBeKU/dgAAAAd0SU1FB+MBHAoiK30yOK0AAAB+SURBVBjTbZDBEYMwEAM3FEM1SRGuQXW4JveRZjYPOAgGPW58szfSyFASuWiBYQMD4ERxiDgcM0GMEYdtRjnges0CCB0IXwHWHQnQSU3xY8QFshv0w6rzZpxJlRbx7FiLkmvxRl03bsX+DGflyWyLwrjNB4Te/n6px8u6K/0A6QZmW+0FSGYAAAAASUVORK5CYII=";
this.marine3a = new Image(); //Marine 3, standing facing right
this.marine3a.src = tag+"A0AAAAQCAYAAADNo/U5AAAA9ElEQVQokY2RMQ6CQBRE51NZ22uhNNpgpYfgBNZEEwoSo+eg0cRCYu0FOIAtnbGhUQvpvcJYwMJCWHQSskuy7+/MLFAX8YfE9Z3yZ2SfeNgtcpoUETGTru8gCBMCIJ8z8jn7fWMQJuxNN9RB3UFTlpq68paIzhcEYQIZ33C/ZuZMxXRE50sJrrwlAOCwWwgADCb9EsjSDywFKCmwEAEwSz98x0O+42GeV2VpW/Wctc8EBGFS7tF8v6IIVXO+Z+WgtQjXdzCyT7UyXo+1xMcbOh+3acd0g5KlN7bfzjtG65k0/2RVzE8IWgGoqu22pyQi+mEj+AU7SrtmOhoOKgAAAABJRU5ErkJggg==";
this.marine3aa = new Image(); //Marine 3, walking right 1
this.marine3aa.src = tag+"A0AAAAQCAYAAADNo/U5AAAA+klEQVQokY2RMW7CQBRE37dSpE4fCkKTNKYKh/AJqBGRXFiKwjncBCkFiJoL+ABp3aE0NCEF7rnCpLDXWVu2yUir3S3e35lZaEr8QxbFYX0ZTzZar2YlLZmZ9ZNRHJKkuQDpNJVO0+svJmmu26dX+aDvoK3ATV0u5mx3e5I0xx4OfH0W/Zmq6Wx3+xpcLuYArFczA7h/vKuB4nghcICTAysJUHG86JyNdM5GZV6XpWv3czZWH5CkeX2m/X9VEa7m8qw/B51FRHHIeLJplPHz/WLZx4HBz23b6XvBKfAbe397HhjtZ/L8S8JraRjCK4BmvZ268S9mJuCqxV8iPLkEr3fuqwAAAABJRU5ErkJggg==";
this.marine3ab = new Image(); //Marine 3, walking right 2
this.marine3ab.src = tag+"A0AAAAQCAYAAADNo/U5AAAA9klEQVQokY2SIQ7CMBiF378g0HgQMANmKDjEToAmI5lYQuAcM5AgIGgusANg5whmhiGY5woPsbV0CwVe0rRN+v3932uBuog/JH7o6U3f3XO7npY0KSJiJ/3QQxSnBEDmYzIf/74xilO2R0uaoNlBU46qGsxnOBxPiOIUMrjgei7snqrqOBxPGgzmMwDAdj0VAOgOOxoosiccBSgpsBIBsMiefCQ9PpJe6Vd5+TSbPmvDBkRxqtdovl8VhIq5XPPdwccg/NBD393XwrjfFpLsLvj6uM12bDcoOWZim9XkS2nTEwnTi2HeqlbNoMhfv9xR542hm7BBL1uzrxKrj0axAAAAAElFTkSuQmCC";
this.marine3b = new Image(); //Marine 3, standing facing left
this.marine3b.src = tag+"A0AAAAQCAYAAADNo/U5AAAA60lEQVQokY2RIa4CMRRFTwkC/f1HAAYMo9gEbABNIIFkEsI+xnz5yWg2wAKw4wgGwyAYzxYuAloKTCfcpGmavtP37i18J/mHerBKwhgjgDjJOJ9mXz6fR1IeCVCcZBrO+9XAcN7HBxq9peIkE0AtBB12Baa9J04y1umG6WTsuhuA3+6PKy6OVx4+BDjAB2vKI122TV22TRXHq7gn9QJYrdPN06+/7PzWQ9n+EZi9DAF27A/ZAkluEpukC6JMkhgtIlqdf/nezqdZkHnp6I8LFf/k6281MO9JBmW7SHr3Wam7eT8QiSpTpU9KMjc2EL3rvAYQFgAAAABJRU5ErkJggg==";
this.marine3ba = new Image(); //Marine 3, walking left 1
this.marine3ba.src = tag+"A0AAAAQCAYAAADNo/U5AAAA7UlEQVQokY2SMY7CMBREnxEFNf1SAM3SkIpLwAWoEUisFAlxjzSUi6i5AAegTYdoaAgF6bnCUICNE3DESFZk+T//PxPDd5K/qQerJIwxAoiTlMt59uX1WSRlkQDFSarhvF8NDOd9fKDRWyhOUgHUQtBxn2M6B+IkZb3ZMp2MXXcD8PPbdMX56cbThwAH+GBNWaTrrqXrrqX8dBOPpAqA1Xqzffn1l53fevj0fQvMHoYAO/abbIEkN4lN0gXxSZIY/UW0u//yvV3OsyBT6OiPCxX/yddqOTDlJIOyXQreJKrnK71uHpQJvvISULj8DpDkspRivN+tAAAAAElFTkSuQmCC";
this.marine3bb = new Image(); //Marine 3, walking left 2
this.marine3bb.src = tag+"A0AAAAQCAYAAADNo/U5AAAA7ElEQVQokY2RMY7CMBREnxEF9fabAmiWhlRcAi5AjUBipUgr7pFmy0XUXIAD0KZDNGkIBem5wlAEex0gFiNZtuX/7D9jeE/yN+3GKgljjACSNON8Wrx5fRFLRSxASZppvByGgfFyiA90Bj9K0kwArSbouC8xvQNJmrHebJnPpu51A/D59eGKy/zK3YcAB/hgS0Wsyy7SZRepzK+iSqoGWK0323+//rD9Ww+v5qfA7GETYNt+ki2Q5DqxSbogXkkSk++Ybv9PvrfzadHI1F7024XAP/n6XY3MY5IhVT6kR59hwEL+OmyqfkG1kMwNSqq8hZTblX0AAAAASUVORK5CYII=";
this.marine3c = new Image(); //Marine 3, Glowing
this.marine3c.src = tag+"BMAAAAWCAYAAAAinad/AAABhUlEQVQ4jZ2Uv0vDQBTHP1c6uPlHNIM4dYgWJ7f0L3DIHDNWxIL4J4hQKHaSI3OGLk5Cs3WQUszQQUqH9o/o1q0uufjys9UvHLnk7n3y3r13Dypk+9FN1VqVGjWg7l+BqgoEXANTgFg7t3+GSVCsHcv2o3WyNAUmsXbGdbDSMAF6gzmxdqxYO1bi5cGwU5j06urs1Br1O+w3bfabdp19Rs0ykA5CeoM5qtUpwPLeydAbEvT19GgB+J7LL3Ahbbv5IeFNufPu/Q0AHYQZIGDNVtvK8Gw/ItbOuJlf0EGYzg3Q91ySRABkQr94fkmBmWwaw/y7DkJOzu+Nl6jWIh1SGc+kJ/mn9FrUH4gaVPkEqNaC/aad/tX2o/X354fley6z1VYWsVFazCoxyJSGDFEAJGRiPsjSKE2A77kyRCsBTg2k6loVrpOBvD5cFppAHagUJg/cgI9VAbZbDhn1OwCM+h12y+H/YUZKqb2ZH9s50nPJNcUyHexpVc2xTAebY1XbLugQCOAHEEzQTENe+hoAAAAASUVORK5CYII=";
this.marine3d = new Image(); //Marine 3, Greyscale
this.marine3d.src = tag+"A0AAAAQCAQAAABnqj2yAAAD0HpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHjarZdrkusoDIX/axWzBCTxXA7mUTU7mOXPARN3YrvT6TtjKgHLWBLnE6RC7Z+/O/2Fi6P3ZF2IPnlvcNlkk2QMotmvvWdj5/d+1dXzq50ez43ApOh1v/Vtzc+wu68Xgl327dVOoSw/cTniw/G8dEQe4zUvLkcqu53XPaX1XrZPy1kfKcvtcn6+twFiVAd/KiRNWQ2+44iiyECT5tln3EcZI4Oxqpt2udeOHtqdxTtGJ+1MXnZ9lYKMXxP8SaNlZ3ey6xFGztQekV8eqB4hLtr1XmPvbV9dth5KeVqLeixljjBxg5Q6X/NoAR+HcZgtoUUssYBYBc0NrRAnFqjZ2XLlzJ3b7AsXpGilSUAvUkSnLWqQJGXCsKNxlwA8lTSCTQE1hVmOXHjGTTNe4YjIlTFTGM4Yb1wa3Rn/pB2Oeh+ly2zirlOdgGVUDdIY5MY3ZgEI96Wpm/rORk91Y57AKgi6KXPEArPZdheb46/a0slZMc8ZS2bfGhzqcgCJENshGVYQMJ7VsWcTRAIzdIzgk5G5qJUNBNg5qUwdbFQ94GA3IDbeCTznipPdjKMFIJx6DUCDDQRY1jrUT7ARNZSdOkvOOe+Ciy657NVb77z3wY8zKgcNNrjgQwgxpJCjRhtd9DHEGFPMSZLiCHPJp0ApppRyRtAM1xlvZ8zIeZNNN7u5zW9hi1vackH5FFtc8SWUWFLJVapWbP/qa6Aaa6q5cUMpNdtc8y202FLLHbXWtdvuuu+hx556Pqjx2rYv1PhE7j01XtQGMTvnhS9qMIfwcMHjOHGDGYiJZRAPgwAKWgYzE9laGeQGM5NkHFUCauwGnMqDGAjaxuI6H+y+yL3lRs7+ipt8R44Guv+DHA10i9yV2w21mucvik5AYxcOTY12HGyY0GKWmMdv0h/39NHE7jnPMc7+117zto/IaAt6ftp6f7q5vH3X022YCip7Li0/lt1TOYZbvORMMfxXgTp+SB8adeEjmYH+TQpPay7H1M/FfnIk21mIMoRYGbl2SHtIr6jMNUK5/iQ3nXnFchvwHO9ipBcv10I4srqQPbLcg9M5gFyiv0/tEZxuYrX2nRTYi/UG72BOt9bvjea7MqEPau2TAEo/5HLjJ91uYLoXRxv3t9bn/f0QW3Givd0gHx0y9Hqq/MAax/wjkdRejxn66Zy5P82uSyDzHsvHC6Rfom/1a/giLf1e2+sZ04+C7HHLV2nr18FmyhVCs8/7k34fe4U+PaX3jz/v6TdR3/X0hwL3ij969C/M+IiTZ0yX2QAAAAJiS0dEAP+Hj8y/AAAACXBIWXMAAC4jAAAuIwF4pT92AAAAB3RJTUUH4wEcCiMGIfZVmQAAAJ1JREFUGNNlkbENAyEMRZ9PDJIqDRIjITFDbgxmSCTqWyMjpLmKTX4KIyUcRq6evv2/AS+xlBUAonZAZjMtVKGuflFuENWo3IAyoy7IOHxPKBxAGxDtBncATgI0wJUZBCfdZUlVv06qYryQx7ih8hmeoQt1ISSSqqbIUW7kY0/+I28v2jARZdfImcbD1hviG0RV0oLcAmK9IYBp/Zov8NhStLAE22IAAAAASUVORK5CYII=";
this.marineImages = [[this.marine1a, this.marine1b, this.marine1aa, this.marine1ab, this.marine1ba, this.marine1bb], [this.marine2a, this.marine2b, this.marine2aa, this.marine2ab, this.marine2ba, this.marine2bb], [this.marine3a, this.marine3b, this.marine3aa, this.marine3ab, this.marine3ba, this.marine3bb]];
//Bullets
this.bullet1 = new Image();
this.bullet1.src = tag+"BAAAAAQCAYAAAAf8/9hAAADyXpUWHRSYXcgcHJvZmlsZSB0eXBlIGV4aWYAAHja3ZdZlvMoDIXftYpeAkKIYTmM5/QOevl9wSTlpFzTn3rpNonBBMRFHwiH+j9/D/oLlzXJk9MQffLe4HLJJZtRiOa4jpyNW/f9YG6Fh3q6/2BRJcjlePR9t8+o17cOwe368lhPoW47cRu6Wd4GZY5sUdjt4jYk9qjn/Uxp98vuNJ39LW3X6ZE9P7sAZzSFPbFku7AY3OMcRaBAkuSVZzyznSWDsohbd7n2Hd2LT867l558Z/Kul0dXkPG7gX/y0a5nvfbd8tATtdvIDz9wMsGcr5PvxmhxjH7MLjsPT3nak7pNZZXQsMCVhzc8UsBXUQ4rJaSIKVYQa6BZkCpxYgtvDnbcOPPgvvLKFRKd7TYgt7bC77MuSrDJ1gXDzcTDBuBpJBFsKqhNKvauhde4aY1XOWLkxmhpGcYYPd4luqr8k3Q3NMZcuswm3n0FXXauaciY5OYdrQCEx/apLv+uRKd1Y05gBQR1uTligtmUw0RRfltbsjgL2qlxZI6twaFtA3ARxlaIYQEB41mUPZtgbWCGHyP4ZCi34mwBAVa1jWmAjYgHnGjn2OgTeLW1ao9qhBaAUPESgAYbCLCcU6yf4CLWUFZRR6rqNWjUpNmLd16998HPGJWDBBc0+BBCDCnkKNFFjT6GGGOKOdkkCGGafAqUYkopZwyaYTqjd0aLnIstUlzR4ksosaSSK5ZPdVWrr6HGmmputknD9m++BWqxpZY7dyyl7rp230OPPfU8sNaGDDd0+BFGHGnkO7VN9ZEaP5H7nBpvapOYW+3CGzVUh3AzwTOc6GQGYtYxiIdJAAvaTmYmsnN2kpvMTLLYFGpBjXXCaTyJgaDrbHXwnd0buU+5kbofcbMfkaOJ7jfI0US3yb3ndkGt5XWiyAI0d+H0qZGBwIZG2UZ8EI//PKdXDfzHDEkPuoql5zpqc6s6z3P9MYdz8yqORA5c8i9Ios8lJL8KfR4pH6iKhybqgqPmvdIfC6VLQRdC9sDncR9yutZ/6vZNmfQ1stM4n8iij3x43f1jeXTtvp/Loks5fyCTvkH7W/LovduG9NUtpYHI7RQfvBVnvI7MMsKSfx7J6rGyS8H5a48xYy3SY94C1IyGgP3RTkvtkDZyERo4AbbwR3vvJghfrG4+NETtJc9wj7I047Wma3wV/czp5ZW4c3oF+VkefbGxvy2TXl6JWxb9JO58Jo++G2++CjdUXwmLJ5n0Spw+y6dXBd1y+o0zbSqg3zjTrmP2/9CQ4G0M/93pX1VlB556nF4qAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAB3RJTUUH4wEVCiIh4O+eOQAAAItJREFUOMtj/P//PwMlgImBQsCCS4Jx4Zk0ZP7/eJNZWNWhewGukUl2JorEv8fp2AxCMYBx4Zk0uEaoBoRnEeLIhmAPA3TNuMSQDYDbjkMh3BAm2ZnI4YM/FuYe0GSYe0BzYKKRgYGBgSHZ4TrRCel/vMksmB9xq4aEEeFYwGYIDoOpm5CokpTpnhsBA75Qk4kLkKMAAAAASUVORK5CYII=";
//Item drops
this.heart1 = new Image();
this.heart1.src = tag+"BAAAAAQCAYAAAAf8/9hAAAAcElEQVQ4jWNgGGjACGMclZD4jyxh/eIFI7piZDUweUZsmtEV4ZNnwec8XBqRARO6gNXz54T0YBqAzb+EAEwPhguOSUqS5AoUm4nxM7LtWF1AKsAb14Rsp40L8LkCW2zhjD5ikjZBcFRC4j+xMUM2AAA7IS8Rr3kzxgAAAABJRU5ErkJggg==";
this.bitcoin1 = new Image();
this.bitcoin1.src = tag+"BAAAAAQCAYAAAAf8/9hAAAA0ElEQVQ4EZ2TMQ7CQAwEk1MewCNokCjyDBp6nkhPwzNSINHwiDwAKWgvGmnP3AHiithe727sKNd34UyXw7LfbQK6lrf73I3Ha+/NXNREImPkOWLMBgEiCuAgpCbWONkAAkKIxFZfeGEAUREzMJlFTL30fJwWSEQR49vpeZQ2/UJ0kefSJgf+yZvfQGY+XW1/cT4auEhmXkusk2rg2vr+lDYN23Pxa0rWelu0lLa5gu8vYWvSwgCRyD4FONEnyQZO9mbMfQrM3vav3UyMJIrX+QUu8VwuLu9BLgAAAABJRU5ErkJggg==";
//Space background
this.space1 = new Image(); //https://opengameart.org/content/space-background-1
this.space1.src = tag+"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";
//Robot images (a=right, b=left)
this.robot1a = new Image();
this.robot1a.src = tag+"AgAAAAQCAYAAAArij59AAAAnElEQVQokYWOvQ3CMBCFP1uMEi+QHRyJmhkoCA37ZAVSR7qM4qzAAFSPgtgS4IQnna54v9zbVuzAr1/rbUL/kvYTYoybpAdoQkBSVeRijDIz+uuVJSWyAeD2eL4FTQgsKRViSYl5nh3AIUeZGV3XARSyDJSkS99XN3ig9Nd2+twJ4JyrC8zsl8kYxkmSGMZpe0MtOsN9O8+n44f6Bf+xSb4+s90YAAAAAElFTkSuQmCC";
this.robot1b = new Image();
this.robot1b.src = tag+"AgAAAAQCAYAAAArij59AAAAo0lEQVQokYWRyw2CQBRFzxgTC7AFpoHpYWjBAlwJzbjBDS3AmmSoxLzp5boyiPze9v7zYOe6EHTewLQnpAtBR6RDAjFGAZxW5ZIK7wFw79tdz+sFgGwGQOE9r6ahLEvcr+VXlc0ovCebTRHjOLpsRjYjpbTbj0dVSZJijFqUlEQ2o6prVlc452aFV2cCpJTcFkbbD5JE2w/LDv9RC5u2H2Y/+ABaU0gZBFfSpwAAAABJRU5ErkJggg==";
this.robot2a = new Image();
this.robot2a.src = tag+"AgAAAAQCAYAAAArij59AAAAmUlEQVQokYWPvQ3CMBCF31mMEg9AdrgFHMmR0zITpqBHQoIJvFKkFOloHgUJYISdTzpd8T3dDw5nEhXM0rlUEd7ath6oTgjeFaUpiRUhyaHvAADjNAsApJQ+geAdL9c7hr7DOM1orH3Lx/6I3fe4xlqcYhRVZUpJgPg6MHhHklRVqmp+8CpLn2x+YQBARKQa2II/PUP+iGzdEygtPXJX9wHJAAAAAElFTkSuQmCC";
this.robot2b = new Image();
this.robot2b.src = tag+"AgAAAAQCAYAAAArij59AAAAmklEQVQokYWQMQrCQBBF30iwsxA8Se6QCySQkLTBwnikYCsIeoHdQ3iAeAALC2/wLdSAwu5O+9+f+X8gMv0oZQFNMSPnPFcKSgK0dSmARZQCfkIWRQHAZr0SgCRl/Sgtr/sZuk0TAMfTha6pyA5bs49b3nvbDYOej/tssL8TAnDO0TVVvIEktXWpZIsgYPbOltwQmu+bZRERgBdtNjTtd5lXwgAAAABJRU5ErkJggg==";
this.robotImages = [[this.robot1a, this.robot1b], [this.robot2a, this.robot2b]];
//Wall images
this.wall1 = new Image();
this.wall1.src = tag+"BAAAAAQCAYAAAAf8/9hAAAAs0lEQVQ4jaWTuw6DIBSGfwwOMlRnOxgS4f2fR13rbBc72MROh3JVjN90uPznCkx2cscNCgBYP6vZ8O2jMwDgACAqAQBQvc6KOk6D0XDaVL1G/WiyHKheY5yGvwM7taY+drK8F5BGVMItgWjbZ1Q8zy9jByX4lLx01tt3i94LppALaYrLylgGfg9yOO1BqmafYIyA2+0UyTHSnM8gDbM/05WnTDDZyZ3SsVMj244Wu8fufucfmVNTgx8MNgEAAAAASUVORK5CYII=";
//Floor images
this.floor1 = new Image(); //https://opengameart.org/content/faded-stone-surface
this.floor1.src = tag+"BAAAAAQCAIAAACQkWg2AAABB0lEQVQokU2SUY7dMAwDZ/hynqK9/9ki7ofs13WAwJBFSqTkv79/ZgZIIrZtq0zbFgPMTFuBEgBo22kpoAAqCAWiycl8uGc6mYtfJOdXFdDStIUls23ZrE3YYgs6ZbPh+7T0FGKQslIKh+uJKdN2Sa+gTlaEuhSnxDOdTtvhfxOi7YCJypTbLNnsU/iKUD+f6NHvpSpNEo4HrldHYwWLJAjtKs77vlGPzY3RnIl8RwTGPdkOYtYHNUlyhved6XWXB7gzFjozXqsWcqr1F2A6FKN1ZtpRk8+2pGvGae35RvdLXLveeWXbPislog830oX5oYV2ug9nBe/tu3zS9q5I27OhHnbPkvkDoxPH4cD4g/oAAAAASUVORK5CYII=";
//Door images
this.door1 = new Image();
this.door1.src = tag+"BAAAAAQCAYAAAAf8/9hAAAAuUlEQVQ4jc2TsQ3DIBREn6M0ZonI1JkirjMDBRJTuPQUSC48Q+p4itQZA7cpIiNMAMepchX6J45/9/lVc2paoAXOwJXvcAMewP0YM252AIhaJOsxd4gFRC0QtUAr42taGV+PhT86WDCMlkv3fJ97mfWyEsi1WeJWAiGhlfEva2UYRrvdQYhhtD6H3GVIhLgXfyywBBdmkUJ2jPE/2D3GGDmuaGHqJVMvixaqcBvd7Pw2bvzE9Db+YuEFc/NBlX/7RVIAAAAASUVORK5CYII=";
//Shop textures
this.bulletSizeImg = new Image();
this.bulletSizeImg.src = tag+"CAAAAAgCAYAAABzenr0AAABEElEQVRYhe1XOw6DMAx1Ik7AzgG6s7D1IoihEpwJpA6Ii3RjYe8B2DkC6dBSBScp+UlRKt6G4/g9E8dJAGLGuAxsXAbmEoO4kPPfRVpaxbKapMraVoQ1fCwB9SXmFBAttKqWMbHOSD/VO58q7wQfchzeSMCOlGbtzmmdGyzGqwDST/WOlCMUBK1zw6q80xFgV4SYfLPJ7CYCXJuKDjAHVQ3w+P5+nSzXuQGatbhIVSISbDA6ZO6PCwAA3K5PHTJsL9KSBG9ECcA7y02p0Yn2I/MNOB7moSpHHqzKu21thf2P8akVWWOScVHVwCGJzHYkTsIRvAbiacXCRE+HUdw474R/ISD4wyT408wJPnZBcLwAw4CmXhyxl1QAAAAASUVORK5CYII=";
this.bulletSpeedImg = new Image();
this.bulletSpeedImg.src = tag+"CAAAAAgCAYAAABzenr0AAAA8ElEQVRYhe2UMQ6DMAxFDeoJunMAdpZuvUjFUKmcCSQG1IuwdWHvAdh7BNyhSpU4MXEkKjr4jWDyf76NARRFUXYmixU8Xnc8HS9eHSL6hw3Tzampq86rydyjRAYAAKgJY8ARzYvW+XiZG2omasAIhrBNIOJH3Ba1BD1Dy9xgXXXUwIETS4IK0+c0mTUDNGquBVuRS4pC4t/4udvbLHMDedHSIRUZSL55P5bQj6W0XJTAL4kOIbcHWK7nZ4oBUQKhXxPrqjO9jat8ZiW0mLwEuD2QnISQbfaASWFtETHsvopFCaxFb/c1Gyb2naIoyt/yBnJEdMM4frBaAAAAAElFTkSuQmCC";
this.spawnHealthImg = new Image();
this.spawnHealthImg.src = tag+"CAAAAAgCAYAAABzenr0AAAA9UlEQVRYhe2Wyw3DIAyGTdUJOIVRSGdhOmZpGYWcWIGeIlFig00qNar4joAf/MYAwGRyNULymTuHraXsqfFbPWC1U60kKlRIPofkm4tC8tlqp1AHzECYUwCADADKajfqZsIvwXNZPs7FY9sOtuUabH44gTp4HaQ33+JeD+wdQJ1aTmIYlF+xAmuM8DKGFZSjwOEeGHU0asNKoORlDKwxSs1IRDvj1lyimFiBb4Nm2uqEngrU7k91wf7YWO2GE6AQl6AVYKRbhl/D3tVcqtaiq0BIHrD3vgzY2Hm3a7glIO/6juySzw3OaQd/zSXU+WkSl1BgcpY3VmaMNC3eMxgAAAAASUVORK5CYII=";
this.fireRateImg = new Image();
this.fireRateImg.src = tag+"CAAAAAgCAYAAABzenr0AAABcElEQVRYhe1WPW7CMBh9QTlB9h6AMRIdvHXnDBGllcJSFg7C0qmWEEQ5AzubByJl7AHYcwTSgcRNwP91harmSRmc7/P7XuLPzwYG/HcEthPquu4TZEXKY7MJ7cUCPb2zAF549PDBg+fToivEm4CUxKCs5AKCrEh54aZoT8z5tKhnE2oiYGQiQIpucdHYAFqJrMpjAC8A3kiUBNgdL1+vKtbGnx+pNKdN1SVsp+uSRMmSRIlc7OYw1vE4C5jvVzGr8ndW5bU06fXp01WAdglSEgOAuAlFy9C899aElJW8OHC1tbpbUDQ2gLUPcOyOXnwgtK3bccJLkaz4jl054Z/AzT9Seb3JvhaiXS4IzguZAC9eb9InIgFevL51TA2Hehs6en1vGTUcgQ+v/wlHSKKkBLBsHjE2h7HKbrfTtTNHeKNeBI3Xz/crzkEtOdRNaOH10kuLhkPdhBZe3z0vbDh+xQesOGSTuUKHW68Nx4ABd8cXHR4WrNBjW5QAAAAASUVORK5CYII=";
this.persistanceImg = new Image();
this.persistanceImg.src = tag+"CAAAAAgCAYAAABzenr0AAABXElEQVRYhe2VPW6DQBCF31qcwI2r1JAjuEsxFD4EaVK4MNxmKVIkhel8AQoo0qVMGW3txmlyBL8UBGLIIgK2ZEXaT1oJ7c6+ecz+AQ6HwzGS3W7HS+rNJs7jd7savFQlFFnpqOyjEWS0UACglOo1UM+3Do7Q9JrA437duMrAeoINEUFZlr3jYzS9biAA4LhfqwwEoF4/MwLQAJ6X8+gNAHzfR1EUVD0lGqPptYKeXm7xcPd+2rWcR60kIkKtNeI4hoiwNgQASZIgCIK2qQHNtoFOIADYKhDHMYwxTWJjDMqyVGma/i7HgGblZHtol2x288hoYa2wiND3fWitEYYhANj3w181SVa7dntg3Zo+CyJCktxsNr3HcIymd+Lo5+O+T7qiXgKS1qM6RnPSTWiM6SaazCQDRVGcn/kc8jwnSeR5fvZ1PPUxukj5gZ67fIjun69Wq+suicPh+Nd8AXGR0L8fn0dPAAAAAElFTkSuQmCC";
this.bulletDamageImg = new Image();
this.bulletDamageImg.src = tag+"CAAAAAgCAYAAABzenr0AAABgElEQVRYhe2WsW6DQAyGDeoLwB4pY7IzhK0PUoTUSMmSx8kSpKAi+iDZ6MDeFSk7vEHokDt6mDNnIFWG8k/kZN//4RjfAcz677LGJGVl6ujWfTeo/gwAmS6JsGIoDAtAmKum70RorMJwIIwAirlqeiDCjwjGCNELgMxVU8t3AxwLAFAjGCPEC9d847y1YT9WO/XnxvEiUF7oq/qUMHFWpmRPaCtAmVtJ/mtqL06tpNt1Lx/r0IsUiN5KkBXokCb5rmWqGGIgK8kbCJPYAKQxXseVMcjGC7j8vhuMGlYAACL3IPZa6gZYB0CnpvzU26u6XfdgL06tfukRC4DU+bKG82U9ZYtpAA/Q8CZUtX39ngrAqkAdepH8b8073nuF+xl2AMSwKOA+PI5ZmdadLKZE7mMGUSNZhZ5BNERsgDr0IivJaUPNKOaIHDKmwwh/59iUcw70Augg5Do1HVG/sI7jp19IjD3gu0ElLhuxKRbFFAAw/Uom9dRLqQGm0Zhr+axZP3J0u8rhzSFXAAAAAElFTkSuQmCC";
//Joystick textures
this.joystickBackground = new Image();
this.joystickBackground.src = tag+"EAAAABACAYAAACqaXHeAAAFKUlEQVR4nNVb224bNxA9FPKUugGKOutrFcsu8v/fEyCIXRhoO7XdND+gPqyWGpIzs0PuriCdB6+4Sw5nDucMFUYbcCB0Xbet6U9EYSlfON4tZTgP+MOHdf8hAAEAwj6++DE+AwAk45ciZFYCeNA/n62HQMA9D9kdHjy//nL+iZERAEbInGTMQsAQ+NlPa76CiB8HIoZG0s6fI8uE/uav3R3vuwXmIWISATHw9+s8fcW2Gbw4QxD7nl/eDR0mE9FMQNd127P3e13nV5EMBTJxGTMCcedXd0N720rCqmWQFHwwpo+6V1Z/lDjF9nD74/WmepcZUJUBScoLjgyNSbpnD/O4ld0CCEB3swEaJOEmIFl15meT7vnjHEHWvZ41IU7T3W4GK25JuCSgBZ9f3bpXiRvXPX8szRACcPGbXxKjBFjBL6p7yy7LrDLj+uvF2keCSYAYfDZX4rR3y8sdZo2Akb4VBfPy0zgJ9buAQ/dlEUyGl22n7vftINvhbWcZVAlo0n38KMzuKpjQgy+cMPqy9uXdvZkFIgGm7jVLceJa3Qc+RLarji2v6Zx9plxtdBIKAkZ1bzri0H1psUL3wfbB8PfqXibBVwMaCpA0PO2bpZRD96bdYmwo/ROQEODa8gRjue6tb2xtBZPN4NA9EEQfrh/KLLAzwNJ9MnGD7jW7RV+5Xfqwt23VkxyRAE37k3QvThnkvrW6VzDm783vaRboGTCH7ou+lboXjOePRnU/4q9MgLYqRRdZ9/m1WfdaX6/uRbspVoCc/qIBp+6to63Zdb+7KdpV/Lv9/BBlUGaAy5Ej0n01camllABv+uq+HKfuDewJUDRZOqKvfm0ByqaOHV2pL+hetausPgC84/rPZDVN9+xhUU+8RIk+7G0XdhV/+nba+/bzAwBsV15HxODTObKbE3Wv2XX7CzV4jkICVTpSHXHqvpicmR5J/Sm651glxgVM1r1llwXTpHvVXz7WpqPYBVypr5HBGqUjWV9vHcgczKdqTf0BiQT8Baj0j6f+IkdbDt2n/vqEIBfB+FEwUl2AsnY2g9nXq3vZUxfEfwsc69GWarch9QesJMdcuk9d4F0cxLUfbc2he44oAbcjyPtmue3QvWm3GGukftGuF0IigVz3x3q0VdqV2x5EAk7taGuK7jlWRBR+/PgDVvCy6aA4krZHda9gSd0DwPOXryCiUH4VdjlSqXvBeP5o6tFWK4pt8NSOtlpTf0BaBA3HFtf97qZoVyVuehqsgP4nJf99f0qNi90X1H01ce3BD/oHtG+CoiNHoPsF0HYmaBVM1tGV+oLuVbszpv6ASAARhe9vTyd3tFULnv6A53+HT+RoqxUJAUQU/n19qtd9tCDofiT1D6n7fPWBmiKoIPA/rbrX7CZjlymDBQFEFN5enuLMduXG+AqKfs9/tDUGafUBJQOIKLz983hSR1sWtOABowgSUXilxzrdjxK1+2NkySF0z9H0a/G6yp0OMuvJAap+DpMAIgqvf5dSULc8U/eH3/LGVh9wZAARhZe/JCkIW17ert3yDNu18AQPOCVAROHlz8dC92mxSh4d/GiLwxs8UPG+wM7gFgA+3myOUvfPX75yX12oemOEGd7GlxOCvWKH0n3NqnM07QJEFOj5G4CxL0oVup+A1uCBCW+NcUlcrPtsOPTRVkvK55j03iCXBNC/oNBj2aOtOQLPXJoH/BeYV5v7OIOV+t7gh6CBI3x1dkDmWPKj5OuH+9GCycEDFmzPhuW/a+5wrK/P/w+9DgPAhREizgAAAABJRU5ErkJggg==";
this.joystick = new Image();
this.joystick.src = tag+"AgAAAAICAYAAADED76LAAAAeUlEQVQYlYWPsQ3DMAwEj+RLA3iNbJM5Aw2QDbKAS1cGvAQBp5AUOGny7R0PoDF2l04ua5kGoAlvy0KJoEZQJdj3s2WaTSh3qkSN6KLEc9twgHCnRCB3NIQSAdCF8gM05I+gCMql8lVomfY6jn41K+481pWWafbvzTdDwR6609/uxAAAAABJRU5ErkJggg==";
//Overlays
this.tvOverlay = new Image();
this.tvOverlay.src = tag+"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";
this.overlay = new Image();
this.overlay.src = "./a.png";
//Control box background
this.ctrlBackground = new Image();
this.ctrlBackground.src = tag+"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";
this.gameoverBackground = new Image();
this.gameoverBackground.src = tag+"GQAAABkCAYAAABw4pVUAAALRklEQVR4nN2dzZrzqA6EGS7z3MXZz70zi27H+qkSEuAkT3tDOxFCKvQS8CTf/PP///072oFrjB83o43Wxuuv1sZv20YbQ7eo37Cvjyu8qx+3RWOwGOjYM7/MH4qd+UOa/L7ep0pXryGa8bp9ialMiW1Dtq9WJ9mYaKJ9eUgUQgOtFQ36I34bihPF99scmRAVxCyYhGjT5BpILhDNj4ZFRQWkaqNQbKoLs1Vj/ES1PSGRaE4GMklaNBWrD/y4ENIWx8an9Bx1V89zSxYRrQHRvBDmhd8gRcg+ucT6/rIvipahrjUcH1odQurkNTYJgUuVHDL48NKhGT/BOrxGnZ4id3OQOmZLqTM5LU/IIBUzFw0HDIUo2MbU6Y70M+ULqDvwGSKGZkKol0CSLLkGkquIJv1Udj+BaDvU0ZoTtksTYkWzIrxlqTLjyQxDISqEtoRtgbrLkS0gmUt5QtBSpQfAlXBCCFuB8qWIuqMbBNGunDkQddLf+meIbJVoJDkHuQ9GJveRDYIZTyYbUke0qHzoX7alCXnsoDbdIPiR5M0OdfPzSYI6kNMqdWuEVIQo2GaoazI5VN1F6q77xzYIsnWFqbuNVpiQ049HmGir1DHROHXkM88Qg0SzV4Y6e2tzujqmJuT84xEriegSJbdgy6kTfxSoY0sVLCRGHSi8S+PaknVUCOmPJPnUBmGVOhMnpA6RVKBuOiFHD2qSkqc2CG6S/O3TO6Ud6sIJWX88YkWD+agXM9SpLlPqrtZMVOWgVqTuNSIrzAR1yc+QhBAovNHmyTWQ3Gnqio9HmGir1DFb1IFOyPc/yUWjmBBvc+0C5RvZvpE6OCGlpcpllRSiYJuhjj0e2T2o0aXqEHW2MOPPECiEeEO8qYYJntWgoBAFnzmoDdUNFZtKi9nKLhPq7K2bkOnuJ7lUOQk2qVNdbXI2h8gWCeGKrU6dKswN6tSEeNFAci79xm2B8TJ1oqXUyeS+jjo9Gsp5NLJkqSHNDMLkGkiuKNqUOukvIRqdTCKEHA4V3Q512jamrt92JDk9PU2KpkczFWFEs6KqgFFeBepUl4loGerY45F3bBA8IQUh9s4neEKPUScL6RB1TVtuU4dsuwtiFkxCtGlyAXVINP6xH1CHhPhm6n7b/tyT3HcJsUYdEu1dj0eiQr+XrIJoXgjzhuiY2TJmHo9URMtQVxEtQ51ybW2NhpHGHQUVzaBLTkSytA5vUseEQFeGOm67Rl12qbq06MiBG0i9TwKmCvwN6phf6C9BnfZ3j9DrO6XJuvkNj0cC0fgGweQMCggVXZm6hmzvnNSSBSlhyYk2IxqrHZfFTIgCdarLRLQMdZcjW0CwkBJnjtfIwm/3ouFKOCGErUCXBqGOLVWr1FVEgyOzpcrF6XOeUde9aCQ5VAksGJncx6kbKr+VnZLvkKPO5ZKgrisPGdGGH2D3Kzc71OXOJzg2lUMg2jup6yo5qkBONCxE038Q6pBo3/8kV3ejdcRsAXV9mlwDyQWiocrJUFcRLUNdKIS5MtTZW5uT7EjPHIkNQneVQCoGDaAkKZBUsm3YdpU6JhosJEYdKLxT1HUmhBoOCiHGlEPKJJ/aIIACSlHXtF9InYoT5/wkdb16up0uKUXRMtSlhMhQh4QIbfeog4U0oe5esghmKmCUV0YIc2VEy1BXEe0bnuSqkUix+S85mE7TivBD8WAIdUy0VeqYaD6PCXXyYrYL1LlcRE49TE609d1PdoMAhHicuqudUAdyooV5gLrWXksWCHwmRMEWU9d4cqB9y0FtgTpfmHvUdVURkxn8iie5Jk6Z2e0PCGGIyYiWoc7e2pyq1HWYnGijAa4oWe24wE9Qh4Q4QN1UNNGuPsnNbBB6Wgg3FBJC//0XqPNxAjGMFitL1fW6O6nHwZiKQJQY0XRoedF2qKPwLVKnbZ+lrlsHrhtdqqxLXD0Z6lSXiWh0ogAFtoDeukGQ7ZS6e9SOhEAlpkIjwaiKQJVQoU60pXV4e6nSWhw9nzRvq52Lk7r0Pk2ugeSMaNCfrVQgWiiESeIUdfp2nzpVmMGZ4+dt7ff1rRNW1/ImTK5ia8T2hM6pg5T8AerUf6DSFQiGkEmyddhNaV20DHW+nrlo2l+NOlpzi9ShpxdSi/s/4UpKFpYqHRmjTlfM40JA2xp106VKapKgDhaS8NutW5/VRAgXlra1wmMJ8ITC5ECS3/RFN3exYiMV5765+BUHtUC0j1PXkC0voCp1+ru9ywc1LUooRIE61WUi2g51SLQnH49Iv1bDvi+EtE1UBGjfclALqJuLZsyFCyofs51Q16fJJURDrne2jPb9LHXCXLsAV6bY7lucU4o6kJNbqoS/bl+woplahkKEyZmrTt09xd9CXbstlN/X+4P4E35tzpcL/bNoKETTf8jkUHWzYIrUIdF2qEOi3f6cNvpihDqSsC1yzqhzP2mD++urNaLpaPOikZr2gTMhzFUTwrSMugEiXFyqKtSpg6GMGiZnsgqFQF0gdU0nN6GOiQakrh3UKhsE2dKlCkclc0bF1nWnIBgiGg7mg9SpOIEaSeqYLeqQoe5yNqOuu+SKovEFyIo2EeIAdV60PepgIT1MXX9GCBMaCaYi2vd80W0oM+VadKtQJ/3Rn7RNk0NJsiVFikX8Qn9T0c4JIcymxeZyMTnJjhnqZGGCn7TFAzQ3AIx1npy58kL46V19PPLYBmGVugZ+0oZEU8MJW5ocGurrH4/YwvwAdQP8pO2VZEK0zO6nacvcBmHo0XzgRAhzrVF32Z6lLrtB6PygBjKdCWGqJKJOdaGi5ambiibaTz3JlX/aka7r/m4vqB41DFs3iWir1DHRQupMnC8/A/nzeSpz4YLWEbNdoO5yckXX7Qt0SRFtZqmKqRORJ4WISarYPkMd3SAg6mRrCt2c1H2SYXLmyohGppZTN1wKx6gLNwiynVIH6CNaIJKkrfvmIq+dIBiZHGhL6/D2UhUIga6kaDlCcQFVNgjuJ21hRQQDXFGGQpgkTlGnb/epm4mmRju0VF12e//mYsO2f486mdw56oT5y9b/pA1VQlG0Jeqa9uupG0vUIQ3q1DWXk+yYOXOowgSbqMuupw5qbiAT+FNCQNsadbsHNeePFNB0w0ELU3fDv8KVtkC0nS2jff/n7Tl1MMntg5oVDRQSKzZScRnbiLoOk9PmvwMkkkNJpqnTFUOTQ9c2dc3ldIo6WpiEutfBUDoIhTAzD5Mz11wIxYBOrrL7+QPU6e/2jgaDqZxuHzuoBdTNRZsIga5ANGOm2wJ1aIOgD4ai3dky2vez1Alzbmtyjai7b3FOKepATm6pQmeOBHWokOBP2s4tP9J2nTomGhht66Bmx3P+hF+XrHCxQ53/FS4LRiaHKEmItkMdEu32ty+EfC1HnYn0EHX+5wgJ0UhN+8CZEOYqC+FscXJbGwTRnn48ElGn/81FWmIZ0dhEYQoyoj22QZDtdKnSo8mcM9RVbEdr9puLk+RAW9r9LG8QEsmhq0JdY7Y6p6c3CJ0vQFa0iRBm5s9Q56Z0jbqggKC/AnWtCX8HqPP/5qIR+xYNBCOTm4j2PQe1ocyUa9GtQp3zh7JKUtdVkgnRXhZGNB1tXrRHhJhQ53IxOcmOGepUYQ7ib6bxdTC0K5y7YcmZKy+Ety3tfhKirVIHCwmIxqkTico/TbE5GYUW4v+wE1R1FAza/fwx6pgtcp6h7nKGqPP/UzDiICMa21e4GyaEucrUyfYwddsbhCR16//mYkvYFqibiiaTq+x+EqLVNwi+AKQgaeqat+1MNB5MsFSJ9rkvuolRF6gLbafUWQd3TmxqZUdHHSigLg2rA4TJmSsmacX2LHV0g7BIHSz0BHX/ASMV1+xA0R00AAAAAElFTkSuQmCC";
//Title text
this.titleImg = new Image();
this.titleImg.src = tag+"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";
this.gameOverImg = new Image();
this.gameOverImg.src = tag+"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";
}
}
class Shop {
constructor() {
//Obj info
this.show = false;
this.page = 0;
//Entity stats
this.statNames = ['fireRate','bulletPersistance','bulletSpeed','bulletDamage','bulletSize','spawnHealth'];
this.bulletSize = 32; //32
this.bulletSpeed = 6; //6
this.bulletDamage = 5; //5
this.bulletPersistance = 1; //1
this.fireRate = 25; //25, Lower=Faster
//Upgrade prices
this.healthPrice = 3;
this.bulletSizePrice = 5;
this.bulletSpeedPrice = 5;
this.bulletDamagePrice = 5;
this.bulletPersistancePrice = 5;
this.fireRatePrice = 5;
//Click cooldown
this.clickCooldown = 0;
}
render() {
//Reduce click cooldown
if (this.clickCooldown > 0) this.clickCooldown--;
//Draw background
ctx.fillStyle = "#440b0e";
ctx.fillRect(1137, 75, 720, 480);
//Draw URL Bar
ctx.fillStyle = "#aaa7a7";
ctx.fillRect(1137, 75, 720, 85); // background
ctx.fillStyle = "#3a3a3a"; //Frame
ctx.fillRect(1137, 75, 720, 10); //Top
ctx.fillRect(1137, 150, 720, 10); //Bottom
ctx.fillRect(1137, 75, 10, 75); //Left
ctx.fillRect(1847, 75, 10, 75); //Right
ctx.fillStyle = "#3a3a3a";
ctx.font = "50px Typecast";
ctx.fillText("https://upgradeshop.onion/purchase", 1225, 127);
//Draw shop options
let offset = 0;
for (let c=this.page; c < this.page+3; c++) {
let stat = this.statNames[c];
let image = this.getImage(stat);
let description = this.getDescription(stat);
let price = this.getPrice(stat);
try {
ctx.drawImage(image, 1200+offset, 250, 128, 128);
} catch(ex) {continue;}
ctx.font = "40px Typecast";
ctx.fillStyle = "white";
ctx.fillText(description, 1195+offset, 425);
ctx.fillText(("Cost: "+price+" BTC"), 1195+offset, 450);
ctx.font = "45px Typecast";
ctx.fillStyle = "white";
//Check if upgrade is clicked, and upgrade if so
if (renderType != 'pause' && collide(1198+offset, 458, 140, 30, mX, mY, 1, 1)) {
ctx.fillStyle = (money >= price ? "#34af63" : "#d62000"); //Go green if hover
if (mouseDown && this.clickCooldown == 0 && money >= price) {
this.upgrade(stat);
money -= price;
this.clickCooldown = 25;
};
}
ctx.fillText("UPGRADE", 1198+offset, 478);
offset += 225;
}
//Draw back buttom
ctx.fillStyle = "white";
if (renderType != 'pause' && (collide(1145, 170, 80, 28, mX, mY, 1, 1) || keysDown[66])) {
ctx.fillStyle = "#34af63";
if (mouseDown && this.clickCooldown == 0 || keysDown[66]) this.show = false;
}
ctx.font = "40px Typecast";
ctx.fillText("(B)ack", 1145, 190);
//Draw balance
ctx.fillStyle = "white";
ctx.font = "65px Typecast";
let text = "Current balance: "+money+" BTC";
ctx.fillText(text, (money < 100 ? 1245 : 1220), 220);
//Draw "Next" and "Previous"
ctx.fillStyle = "white";
ctx.font = "40px Typecast";
if (this.page != 0) {
if (renderType != 'pause' && (collide(1150, 520, 125, 25, mX, mY, 1, 1) || keysDown[80])) {
ctx.fillStyle = "#34af63";
if (mouseDown && this.clickCooldown == 0 || keysDown[80]) {
this.page -= 3;
this.clickCooldown = 25;
}
}
ctx.fillText("(P)revious", 1150, 540);
}
ctx.fillStyle = "white";
if (this.page != 3) {
if (renderType != 'pause' && (collide(1770, 520, 75, 25, mX, mY, 1, 1) || keysDown[78])) {
ctx.fillStyle = "#34af63";
if (mouseDown && this.clickCooldown == 0 || keysDown[78]) {
this.page += 3;
this.clickCooldown = 25;
}
}
ctx.fillText("(N)ext", 1770, 540);
}
//Draw slight overlay
ctx.globalAlpha = 0.2;
ctx.drawImage(s.tvOverlay, 1137, 75, 1300, 1000);
ctx.globalAlpha = 1;
}
getDescription(key) {
switch (key) {
case 'spawnHealth':
return "Spawn health";
case 'bulletSize':
return "Bullet Size";
case 'bulletSpeed':
return "Bullet Speed";
case 'bulletDamage':
return "Bullet Damage";
case 'bulletPersistance':
return "Persistance";
case 'fireRate':
return "Fire Rate";
default:
return null;
}
}
getPrice(key) {
switch (key) {
case 'spawnHealth':
return this.healthPrice;
case 'bulletSize':
return this.bulletSizePrice;
case 'bulletSpeed':
return this.bulletSpeedPrice;
case 'bulletDamage':
return this.bulletDamagePrice;
case 'bulletPersistance':
return this.bulletPersistancePrice;
case 'fireRate':
return this.fireRatePrice;
default:
return null;
}
}
getImage(key) {
switch (key) {
case 'spawnHealth':
return s.spawnHealthImg;
case 'bulletSize':
return s.bulletSizeImg;
case 'bulletSpeed':
return s.bulletSpeedImg;
case 'bulletDamage':
return s.bulletDamageImg;
case 'bulletPersistance':
return s.persistanceImg;
case 'fireRate':
return s.fireRateImg;
default:
return null;
}
}
upgrade(key) {
upgradeCount++;
switch (key) {
case 'spawnHealth':
let spawnable = currentLevel.spawnable[ranbetween(0, currentLevel.spawnable.length-1)];
items.push(new Health(spawnable[0], spawnable[1]));
this.healthPrice += 4
break;
case 'bulletSize':
this.bulletSizePrice += 5;
this.bulletSize+=8;
break;
case 'bulletSpeed':
this.bulletSpeedPrice += 5;
this.bulletSpeed += 2;
break;
case 'bulletDamage':
this.bulletDamagePrice += 5;
this.bulletDamage += 3;
break;
case 'bulletPersistance':
this.bulletPersistancePrice += 5;
this.bulletPersistance++;
break;
case 'fireRate':
this.fireRatePrice += 5;
this.fireRate -= 2;
break;
default:
return null;
}
}
}
class GameOver {
/*
Renders game over screen
*/
constructor() {
this.highscore = document.cookie;
}
render() {
//Game box
ctx.drawImage(s.gameoverBackground, 61, 183, 1024, 768);
ctx.drawImage(s.gameOverImg, 215, 320, 686, 70);
ctx.fillStyle = "white";
ctx.font = "75px Typecast";
ctx.fillText(("Your level: "+levelCount), 415, 475);
ctx.fillText(("Robots destroyed: "+totalRobotsKilled), 340, 530);
ctx.fillText(("Doors hacked: "+totalDoorsHacked), 365, 585);
if (this.highscore == "" || levelCount >= parseInt(this.highscore)) {
ctx.fillStyle = "#6eb67c";
ctx.fillText("New High Score!", 365, 640);
document.cookie = levelCount;
} else {
ctx.fillText(("High score: "+this.highscore), 385, 640);
}
let playAgainCol = collide(220, 680, 677, 50, mX, mY, 1, 1);
if (playAgainCol) {
ctx.fillStyle = "#77f48f";
if (mouseDown) restart();
}
ctx.font = "85px Typecast";
ctx.fillText("Click", 215, 725);
ctx.fillText("to play again", 529, 725);
ctx.fillStyle = (playAgainCol ? "#509dba" : "#7ccbe8");
ctx.fillText("here", 385, 725);
//Control box
ctx.drawImage(s.gameoverBackground, 1137, 75, 720, 480);
ctx.font = "120px Typecast";
ctx.fillStyle = "white";
ctx.fillText("Info", 1420, 165);
let offset = 240;
ctx.font = "40px Typecast";
//Sentence one
ctx.fillStyle = "white";
ctx.fillText("This game was made as part of ", 1200, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("Gynvael's ", 1633, offset);
offset+=35;
//Sentence two
ctx.fillStyle = "#7ccbe8";
ctx.fillText("Winter GameDev Challenge 2018/19. ", 1200, offset);
ctx.fillStyle = "white";
ctx.fillText("Some of", 1678, offset);
offset+=35;
//Sentence three
ctx.fillStyle = "white";
ctx.fillText("the rules include the game being ", 1200, offset);
ctx.fillText(",", 1820, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("browser-based", 1643, offset);
offset+=35;
//Sentence four
ctx.fillStyle = "white";
ctx.fillText("using the computer frame", 1200, offset);
ctx.fillText("and being", 1655, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("overlay", 1550, offset);
offset+=35;
//Sentence five
ctx.fillStyle = "white";
ctx.fillText("under", 1200, offset);
ctx.fillText(". The code was developed by me,", 1360, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("128Kb", 1285, offset);
offset+=35;
//Sentence six
ctx.fillStyle = "white";
ctx.fillText("and most of the art was created by", 1200, offset);
ctx.fillText(":)", 1820, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("Joe Satoor", 1678, offset);
offset+=35;
//Sentence seven
ctx.fillStyle = "white";
ctx.fillText("The title text was created by", 1200, offset);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("@areajack_", 1593, offset);
offset+=35;
//Sentenve Eight
ctx.fillStyle = "white";
ctx.fillText("Thanks for playing!", 1200, offset);
}
}
class Marine {
/*
Marines are stored in the "marines" array, and are our three primary marines.
Status 2 = Alive
Status 1 = Dying (Fading out)
Status 0 = Dead
*/
constructor(_image, _Speed=3) {
this.health = 100;
this.maxHealth = 100;
this.bulletCooldown = 0;
this.spawnLocation = currentLevel.spawnable[ranbetween(0, currentLevel.spawnable.length-1)];
this.x = this.spawnLocation[0];
this.y = this.spawnLocation[1];
this.status = 2;
this.Speed = _Speed;
this.image = _image;
this.direction = 'right';
this.width = 52;
this.length = 64;
this.opacity = 1;
this.deg = 3;
this.moveMarine = false; //For dragging
this.walkingTimer = 5;
this.walkingstate = true; //Alternate image
}
draw() {
//Check for death status (since this is called every frame)
if (this.health <= 0) this.status = 1;
if (this.status == 1) {
this.dying();
return;
}
//Draw health bar
ctx.fillStyle = "#bc4343";
ctx.fillRect(this.x, this.y - 15, (this.health/100)*this.width, 10)
//Draw arrow if selectedMarine
if (this === selectedMarine) {
ctx.setLineDash([5]);
ctx.strokeStyle = '#FFFFFF';
ctx.beginPath();
//Start of arrow (Center of marine)
ctx.moveTo(this.x + this.width/2, this.y + this.length/2);
//Calculate end point
let toX = this.x - 100*Math.cos(this.deg) + this.width/2;
let toY = this.y - 100*Math.sin(this.deg) + this.length/2;
ctx.lineTo(toX,toY);
//Draw arrowhead
let potentialX = toX + 10*Math.cos(this.deg-Math.PI/6);
let potentialY = toY + 10*Math.sin(this.deg-Math.PI/6);
ctx.lineTo(potentialX, potentialY); //Draw first half of arrow
ctx.moveTo(toX, toY); //Move back to end of line
potentialX = toX + 10*Math.cos(this.deg+Math.PI/6);
potentialY = toY + 10*Math.sin(this.deg+Math.PI/6);
ctx.lineTo(potentialX, potentialY); //Draw second half of arrow
ctx.stroke();
ctx.setLineDash([0]);
}
//Draw actual sprite
this.drawSprite();
}
drawSprite() {
if (!mouseDown || !this.moveMarine || this !== selectedMarine) {
let drImage = this.direction == 'right' ? this.image[0] : this.image[1];
ctx.drawImage(drImage, 0, 0, 13, 16, this.x, this.y, this.width, this.length);
} else {
//Check walking image switch
if (--this.walkingTimer == 0) {
this.walkingTimer = 20;
this.walkingState = !this.walkingState;
}
if (this.direction == "right") {
ctx.drawImage((this.walkingState ? this.image[2] : this.image[3]), 0, 0, 13, 16, this.x, this.y, this.width, this.length);
}
else {
ctx.drawImage((this.walkingState ? this.image[4] : this.image[5]), 0, 0, 13, 16, this.x, this.y, this.width, this.length);
}
}
}
dying() {
this.opacity -= 0.01;
if (this.opacity <= 0) {
this.status = 0;
if (selectedMarine === this) this.selectNew();
this.x = 9999;
this.y = 9999;
return;
};
ctx.globalAlpha = this.opacity;
this.drawSprite();
ctx.globalAlpha = 1;
}
move() {
//If mouse not in joystick, don't move
let mouseDist = distBetweenTwoPoints(mX, mY, joystickObj.centerX, joystickObj.centerY);
if (!mouseDown || !this.moveMarine) { //Allow mouse drag
this.moveMarine = (!(mouseDist > 99 || isNaN(mouseDist)));
}
if (!this.moveMarine) return;
//If dead, don't move
if (this.status < 2) return;
this.storedmX = mX; //Needed for bullets to fire
this.storedmY = mY;
let potentialX, potentialY, brick, xCol, yCol;
this.deg = Math.atan2(450-mY, 1497-mX);
this.direction = (this.deg >= -1.5 && this.deg <= 1.5) ? 'left' : 'right';
if (!mouseDown) return;
potentialX = this.x - this.Speed*Math.cos(this.deg);
potentialY = this.y - this.Speed*Math.sin(this.deg);
// Collision detection for s.wall1s (aka bricks)
for (brick of currentLevel.bricks) {
xCol = collide(potentialX, this.y, this.width, this.length, brick[0], brick[1], 32, 32); //just x
yCol = collide(this.x, potentialY, this.width, this.length, brick[0], brick[1], 32, 32); //just y
if (xCol && yCol) return;
if (xCol) potentialX = this.x;
if (yCol) potentialY = this.y;
}
//We do not need to bounds check, since walls are drawn at the edge.
this.x = potentialX;
this.y = potentialY;
}
fire() {
if (keysDown[32] && this.bulletCooldown == 0) {
bullets.push(new Bullet(this.x, this.y, this.storedmX, this.storedmY));
this.bulletCooldown = shopObj.fireRate;
}
if (this.bulletCooldown > 0) this.bulletCooldown--;
}
selectNew() {
//Used to automatically select another marine when dying
for (let marine of marines) {
if (marine.status==2) {
selectedMarine = marine;
return;
}
}
}
}
class Bullet {
/*
Bullet object.
Status:
0: Has hit brick, to be deleted.
1: Alive and good :)
*/
constructor(_x, _y, _gotoX, _gotoY) {
this.x = _x;
this.y = _y;
this.Speed = shopObj.bulletSpeed;
this.degree = Math.atan2(450-_gotoY, 1497-_gotoX);
this.moveX = this.Speed*Math.cos(this.degree);
this.moveY = this.Speed*Math.sin(this.degree);
this.size = shopObj.bulletSize;
this.width = this.size;
this.length = this.size;
this.status = 1;
this.persistance = shopObj.bulletPersistance;
this.collided = []; //To ensure that passing bullets do not do more damage than intended
}
render() {
this.draw();
this.move();
this.damage();
}
draw() {
ctx.drawImage(s.bullet1, 0, 0, 16, 16, this.x, this.y, this.width, this.length);
}
move() {
this.x -= this.moveX;
this.y -= this.moveY;
//Collision detection
for (let brick of currentLevel.bricks) {
if (collide(this.x, this.y, this.width, this.length, brick[0], brick[1], 32, 32)) {
this.status = 0;
}
}
}
damage() {
//This function damages nearby marines
for (let enemy of enemies) {
if (this.persistance == 0) break;
if (collide(this.x, this.y, this.width, this.length, enemy.x, enemy.y, enemy.width, enemy.length) && this.collided.indexOf(enemy) == -1) {
enemy.health -= shopObj.bulletDamage;
damageboxes.push(new Damage(enemy.x, enemy.y, ("-"+shopObj.bulletDamage)));
this.persistance--;
this.collided.push(enemy);
}
}
if (this.persistance == 0) this.status = 0;
}
}
class Robot {
/*
Enemy class
Pass in an image object to create.
Status 2 = Alive
Status 1 = Dying (Fading out)
Status 0 = Dead
*/
constructor() {
this.health = 25;
this.maxHealth = 25;
this.spawnLocation = currentLevel.spawnable[ranbetween(0, currentLevel.spawnable.length-1)];
this.x = this.spawnLocation[0];
this.y = this.spawnLocation[1];
this.image = s.robotImages[ranbetween(0,s.robotImages.length-1)];
this.Speed = ranbetween(2,(levelCount*2 > 15 ? 15 : levelCount*2))/10;
this.width = 32;
this.length = 64;
this.status = 2;
this.opacity = 1;
this.direction = 'right';
this.spawnedEntity = false; //To repeat duplicate spawns
}
draw() {
//Start dying if health low
if (this.health <= 0) this.status = 1;
//Fadeout if dying
if (this.status == 1) {
this.opacity -= 0.1;
ctx.globalAlpha = this.opacity;
if (this.opacity < 0) this.status = 0;
}
if (this.status == 0 && !this.spawnedEntity) {
this.spawnEntity();
totalRobotsKilled++;
}
//Don't draw if dead
if (this.status == 0) return;
//Start drawing image
let drImage = this.direction == 'right' ? this.image[0] : this.image[1];
ctx.drawImage(drImage, 0, 0, 8, 16, this.x, this.y, this.width, this.length); //sprite
ctx.fillStyle = "#547a66";
if (this.status == 2) ctx.fillRect(this.x, this.y - 15, (this.health/this.maxHealth)*this.width, 10); //health
ctx.globalAlpha = 1;
}
move() {
let xCol, yCol, potentialX, potentialY, deg;
//Get closest Marine
let shortestDistance = 99999;
marines.forEach((marine) => {
let distanceFrommarine = distBetweenTwoPoints(this.x, this.y, marine.x, marine.y);
if (distanceFrommarine < shortestDistance) {
shortestDistance = distanceFrommarine;
this.closestmarine = marine;
}
});
//Move (Speed) pixels towards them
let gotoX = this.closestmarine.x;
let gotoY = this.closestmarine.y;
//Attack (This also stops movement if within 2 pixels to the marine)
if ((gotoX > this.x-10 && gotoX < this.x+10 && gotoY > this.y-10 && gotoY < this.y+10)) {
this.closestmarine.health -= (levelCount < 15 ? 0.12 : 0.17);
damageboxes.push(new Damage(this.x, this.y, "!"));
return;
}
deg = Math.atan2(this.y-gotoY, this.x-gotoX);
this.direction = (deg >= -1.5 && deg <= 1.5) ? 'left' : 'right'; //Set sprite direction
potentialX = this.x - this.Speed*Math.cos(deg);
potentialY = this.y - this.Speed*Math.sin(deg);
// Collision detection for walls (aka bricks)
for (let brick of currentLevel.bricks) {
xCol = collide(potentialX, this.y, this.width, this.length, brick[0], brick[1], 32, 32); //just x
yCol = collide(this.x, potentialY, this.width, this.length, brick[0], brick[1], 32, 32); //just y
if (xCol && yCol) return;
if (xCol) potentialX = this.x;
if (yCol) potentialY = this.y;
}
this.x = potentialX;
this.y = potentialY;
}
spawnEntity() {
let ranint = ranbetween(1,4);
items.push(ranint == 4 ? new Health(this.x, this.y) : new Bitcoin(this.x, this.y));
this.spawnedEntity = true;
}
}
class Level {
/*
Holds the map, the bricks and spawn locations for a level.
Statuses:
2: In progress
1: All enemies killed (Door should spawn)
0: Finished (Player at door)
*/
constructor(_w, _h) {
this.width = _w;
this.height = _h;
this.status = 2;
this.map = generateLevel(_w, _h);
this.findBricks();
}
draw() {
this.drawSpace();
let drImage;
for (let r=0; r < this.height; r++) {
for (let c=0; c < this.width; c++) {
let drawC = 61+(32*c); //61 * 183 are the offset
let drawR = 183+(32*r);
if (this.map[r][c] == 0) drImage = false;
if (this.map[r][c] == 1) drImage = s.floor1;
if (this.map[r][c] == 2) drImage = s.wall1;
if (drImage) ctx.drawImage(drImage, 0, 0, 16, 16, drawC, drawR, 32, 32);
}
}
}
findBricks() {
/*
To find locations that the player should not be able to travel through, and to find spawnable locations
This should populate both this.bricks and this.spawnable
*/
this.spawnable = []; //Data contains [row, column]
this.bricks = []; //Data contains [x, y]
for (let r=0; r < this.height; r++) {
for (let c=0; c < this.width; c++) {
if (this.map[r][c] == 2) this.bricks.push([61+(32*c), 183+(32*r)]); //Brick
if (r == 0 || c == 0 || r == this.height || c == this.width) continue;
if (this.map[r-1][c-1] == 1 && //Top-left
this.map[r-1][c] == 1 && //Top
this.map[r-1][c+1] == 1 && //Top-right
this.map[r][c+1] == 1 && //Right
this.map[r+1][c+1] == 1 && //Bottom-right
this.map[r+1][c] == 1 && //Bottom
this.map[r+1][c-1] == 1 && //Bottom-left
this.map[r][c-1] == 1 //Left
) this.spawnable.push([61+(32*c), 183+(32*r)]); //Spawnable
}
}
//If too small, redo
if (this.spawnable.length < 4) {
this.map = generateLevel(this.width, this.height);
this.findBricks();
}
}
drawSpace() {
/*
To draw a nice spacey background
*/
ctx.drawImage(s.space1, 61, 183, 1024, 768);
}
}
class Damage {
/*
Damage box class
Pass in an object's x and y coords, and the amount of damage taken
Status 1 = Fading
Status 0 = Faded (To be removed)
"!" is passed in whenever a Marine is being attacked.
*/
constructor(_x, _y, _text) {
this.x = _x;
this.y = _y;
this.status = 1;
this.text = _text;
this.opacity = (_text == "!" ? 0.3 : 1);
}
draw() {
this.opacity -= 0.01;
ctx.font = (this.text == "!" ? "60px" : "30px")+" Typecast";
if (this.opacity < 0) this.status = 0; //Set status to 0 if opacity is 0
if (this.status == 0) return; //Don't draw if status is 0
ctx.globalAlpha = this.opacity;
ctx.fillStyle = (this.text[0] == '+' ? 'green' : 'white'); //Green if health increase, else white
ctx.fillText(this.text, this.x + (this.text == "!" ? 17 : 0), this.y-20); //Offset of 20y, so box appears above entity
ctx.globalAlpha = 1;
}
}
class Door {
/*
Doors which appear at end of level
If a player touches the door, the level's status is set to 0 (which invokes a new level)
*/
constructor(_image) {
this.width = 64;
this.length = 64;
this.spawnLocation = this.findSpawnLocation();
this.x = this.spawnLocation[0];
this.y = this.spawnLocation[1];
this.image = _image;
this.marineCollide = false;
}
draw() {
//Draw actual door
ctx.drawImage(this.image, 0, 0, 16, 16, this.x, this.y, this.width, this.length);
//Check player collision
this.marineCollide = false;
marines.forEach((marine) => {
if (collide(this.x, this.y, this.width, this.length, marine.x, marine.y, marine.width, marine.length)) {
if (levelCount % 4 != 3) { // One before minigame
currentLevel.status = 0;
}
this.marineCollide = true;
}
});
if (this.marineCollide && keysDown[32]) { //For hackable doors
totalDoorsHacked++;
currentLevel.status = 0;
}
}
drawLockText() {
if (levelCount % 4 == 3 && this.marineCollide) {
ctx.fillStyle = "white";
ctx.font = "40px Typecast";
ctx.fillText("Door is locked!", this.x-60, this.y-10);
ctx.font = "30px Typecast";
ctx.fillText("Press <SPACE> to hack it open.", this.x-120, this.y+80);
}
}
findSpawnLocation() {
//This function tries to ensure that a door doesn't spawn inside of a marine (no guarantee)
for (let c=0; c < 20; c++) {
let attempt = currentLevel.spawnable[ranbetween(0, currentLevel.spawnable.length-1)];
let collidingMarines = marines.filter(marine => {
return (collide(attempt[0],attempt[1],this.width, this.length, marine.x, marine.y, marine.width, marine.length))
});
if (collidingMarines.length == 0) return attempt;
}
return attempt;
}
}
class Joystick {
/*
We store the joystick as an entity, so that we can conveniently store its properties and draw it.
storedmX & storedmY are used to store the previous mouse position if the mouse leaves the joystick background.
*/
constructor() {
this.x = 1455;
this.y = 423;
this.width = 64;
this.length = 64;
this.centerX = this.x + this.width/2;
this.centerY = this.y + this.length/2;
this.storedmX;
this.storedmY;
}
draw(mX=this.centerX, mY=this.centerY) {
//We must first draw out the background
ctx.drawImage(s.joystickBackground, 0, 0, 64, 64, 1387, 350, 200, 200);
//Move joystick *center* to mouse
mX -= this.width/2;
mY -= this.length/2;
//Float joystick back to center if out of background
if (renderType == 'level' && distBetweenTwoPoints(mX, mY, this.x, this.y) > 99 && !selectedMarine.moveMarine) {
let deg = Math.atan2(this.storedmY-this.y, this.storedmX-this.x);
mX = this.storedmX - 0.5*Math.cos(deg);
mY = this.storedmY - 0.5*Math.sin(deg);
}
if (renderType == 'level' && distBetweenTwoPoints(mX, mY, this.x, this.y) > 99 && selectedMarine.moveMarine) {
let deg = Math.atan2(this.y-mY, this.x-mX);
mX = this.x - 99*Math.cos(deg);
mY = this.y - 99*Math.sin(deg);
}
if (renderType == 'level') {
this.storedmX = mX;
this.storedmY = mY;
}
ctx.drawImage(s.joystick, 0, 0, 8, 8, this.storedmX, this.storedmY, this.width, this.length);
}
}
class Obstacle {
/*
Minigame 2/3
Status -1 = Game Over
Status 9 = Game Won
*/
constructor() {
//Level params
this.status = 3; //3 = Typing instructions, 2=Countdown, 1=In-game, 0=Won, -1=Lost, 9=Complete
this.lives = marines.filter(marine => marine.status == 2).length;
this.typePosition = 0;
//Game params
//Ball
this.ballX = 570;
this.ballY = 900;
this.ballRadius = 20;
this.ballDiameter = this.ballRadius*2;
//Obstacles
this.obstacles = this.createObstacles();
this.obstacleOffset = -4300; //Adjust manually pls thanks
//Countdown
this.countdown = 4;
this.countdownTimer = 90;
}
render() {
this.ballCornerX = this.ballX-this.ballRadius;
this.ballCornerY = this.ballY-this.ballRadius;
ctx.fillStyle = "black";
ctx.fillRect(61, 183, 1024, 768);
if (this.status == 2) {
this.runCountdown();
}
else if (this.status == 1) {
this.checkCollision();
this.obstacleOffset += 5;
}
this.drawControlBox();
this.drawGameBox();
if (this.obstacleOffset >= 1000) {
this.status = 0;
};
if (this.status == 0 || this.status == -1) {
this.drawWinLose();
}
this.moveBall();
if (this.lives == 0) this.status = -1;
}
createObstacles() {
//Generate grid
let grid = [];
for (let r=0; r < 60; r++) {
grid[r] = [];
let ranSpaces = [ranbetween(0,9),ranbetween(0,9)];
for (let c=0; c < 10; c++) {
if (ranSpaces.indexOf(c) != -1) grid[r][c] = 1;
else grid[r][c] = 0;
}
}
return grid;
}
drawGameBox() {
//Draw ball
ctx.fillStyle = "green";
ctx.beginPath();
ctx.arc(this.ballX, this.ballY, this.ballRadius, 0, 2 * Math.PI);
ctx.fill();
//Draw obstacles
for (let r=0; r < 60; r++) {
for (let c=0; c < 10; c++) {
ctx.fillStyle = "green";
if (this.obstacles[r][c] == 1) ctx.fillRect(87+c*98, this.obstacleOffset+r*75, 93, 50);
ctx.fillStyle = "red";
if (this.obstacles[r][c] == 2) ctx.fillRect(87+c*98, this.obstacleOffset+r*75, 93, 50);
}
}
//Draw old TV overlay
ctx.globalAlpha = 0.5;
ctx.drawImage(s.tvOverlay, 61, 183, 1024, 768);
ctx.globalAlpha = 1;
}
drawControlBox() {
//Control Box
ctx.fillStyle = "black";
ctx.fillRect(1137, 75, 720, 480);
//Intro sequence
ctx.fillStyle = "green";
ctx.font = "30px Typecast";
let totalString = `break network.exe|Loading...||The anti-malware has locked onto our position!||Use your <ARROW KEYS> to evade it. Don't get|hit by the anti-malware or you'll lose a life!||You have one attempt per Marine alive.||Lives remaining:||${'❤'.repeat(this.lives)}`; //Will be split on "|"
let substring = totalString.substring(0, this.typePosition);
let substringParts = substring.split("|");
let startY = 175;
substringParts.forEach((part, index) => {
if (index == 0) part = "me@zenith:~$ "+part;
ctx.fillText(part, 1237, startY);
startY += 25;
});
if (this.typePosition == totalString.length) { //Set status to "countdown" if instructions finished
this.status = (this.status == 3 ? 2 : this.status);
} else {
this.typePosition += 1;
}
}
runCountdown() {
if (--this.countdownTimer == 0) {
this.countdownTimer = 90;
this.countdown--;
}
ctx.fillStyle = "green";
ctx.font = "225px Typecast";
if (this.countdown == 1) {
ctx.fillText("Go!", 495, 475);
}
else if (this.countdown == 0) {
this.status = 1;
}
else {
ctx.fillText(this.countdown-1, 540, 475);
}
}
moveBall() {
//Left
if (keysDown[37] && !collide(61, 183, 1, 768, this.ballCornerX, this.ballCornerY, this.ballDiameter, this.ballDiameter)) {
this.ballX -= 5;
}
//Up
if (keysDown[38] && !collide(61, 183, 1024, 3, this.ballCornerX, this.ballCornerY, this.ballDiameter, this.ballDiameter)) {
this.ballY -= 5;
}
//Right
if (keysDown[39] && !collide(1084, 183, 1, 768, this.ballCornerX, this.ballCornerY, this.ballDiameter, this.ballDiameter)) {
this.ballX += 5;
}
//Down
if (keysDown[40] && !collide(61, 949, 1084, 1, this.ballCornerX, this.ballCornerY, this.ballDiameter, this.ballDiameter)) {
this.ballY += 5;
}
}
checkCollision() {
for (let r=0; r < 60; r++) {
for (let c=0; c < 10; c++) {
if (this.obstacles[r][c] == 1) {
if (collide(87+c*98, this.obstacleOffset+r*75, 93, 50, this.ballCornerX, this.ballCornerY, this.ballDiameter, this.ballDiameter)) {
this.lives--;
this.obstacles[r][c] = 2
}
}
}
}
}
drawWinLose() {
ctx.fillStyle = "green";
if (this.status == 0) {
ctx.font = "125px Typecast";
ctx.fillText("Anti-virus evaded!", 200, 500);
ctx.font = "75px Typecast";
ctx.fillText("Door successfully opened.", 250, 550);
ctx.font = "50px Typecast";
ctx.fillText("Press <SPACE> to continue.", 325, 600);
if (keysDown[32]) this.status = 9;
}
}
}
class Breakout {
/*
Minigame 1/3.
Status -1 = Game Over
Status 9 = Game Won
*/
constructor() {
this.typePosition = 0;
this.lives = marines.filter(marine => marine.status == 2).length;
this.platformX = 500;
this.platformY = 900;
this.platformWidth = 140;
this.platformLength = 20;
this.ballX = 1055;
this.ballY = 940;
this.ballRadius = 20;
this.ballSpeed = 13;
this.deg = 1;
this.status = 3; //3 = Typing instructions, 2 = Countdown, 1 = In-game, 0 = Won, -1 = Lost, 9 = Complete
this.countdownTimer = 90;
this.countdown = 3;
this.generateTiles();
this.startedGame = false; //Hardcoded bug-fix to stop ball colliding with paddle on spawn
}
generateTiles() {
this.tiles=[];
let showRows=[ranbetween(1,9)];
for (let r=0; r < 10; r++) {
this.tiles[r]=[];
for (let c=0; c < 10; c+=2) {
this.tiles[r][c] = (showRows.indexOf(r) != -1 ? 1 : 0);
}
}
}
render() {
this.movePlatform(); //Player-controller movement
if (this.status == 1) { //If intro sequence being typed, don't move entities.
this.moveBall(); //Move and bounce, and also check collisions with tiles
}
this.drawControlBox(); //Draw typing sequence/instructions
if (this.status == 0 || this.status == 9) {
this.drawGameBox();
this.winSequence();
return;
}
if (this.status == 2) { //Trigger countdown
this.runCountdown();
}
this.checkWinLose(); //Check if we have won/lost
this.drawGameBox(); //Draw out game box
}
checkWinLose() {
//Check lose
if (this.ballY >= 951 && this.status != 0) {
//Reset countdown
this.status = 2;
this.startedGame = false;
this.countdownTimer = 90;
this.countdown = 3;
//Remove life
this.lives--;
//Reset ball pos
this.ballX = 1055;
this.ballY = 940;
this.deg = 1;
if (this.lives == 0) this.status = -1;
}
//Check win
let win = true;
for (let r=0; r < 10; r++) {
for (let c=0; c < 10; c++) {
if (this.tiles[r][c] == 1) win = false;
}
}
if (win) {
this.status = 0;
this.countdownTimer = 90;
this.countdown = 3;
}
}
movePlatform() { //37 = left, 39 = Right
if (keysDown[37] && this.platformX - 10 > 58) {
this.platformX -= 10;
} else if (keysDown[39] && this.platformX + 10 <= 1090-this.platformWidth) {
this.platformX += 10;
}
}
moveBall() {
//Check bounce with tiles
for (let r=0; r < 10; r++) {
for (let c=0; c < 10; c++) {
if (this.tiles[r][c] == 1) {
if (collide(100+c*100, (183+r*35), 140, 30, this.ballX-this.ballRadius, this.ballY-this.ballRadius, this.ballRadius*2, this.ballRadius*2)) {
this.tiles[r][c] = 0;
this.deg = Math.atan2((183+r*35)-this.ballY, (100+c*100)-this.ballX);
this.startedGame = true;
}
}
}
}
//Check bounce with platform
if (collide(this.platformX, this.platformY, this.platformWidth, this.platformLength, this.ballX-this.ballRadius, this.ballY-this.ballRadius, this.ballRadius*2, this.ballRadius*2)) {
//Check that ball doesn't collide within start
if (this.startedGame) {
this.deg = Math.atan2(this.platformY-this.ballY, (this.platformX+this.platformWidth/2)-this.ballX);
}
}
//Check bounce with walls
if (this.ballX-this.ballRadius < 58 || this.ballX+this.ballRadius > 1084) {
this.deg = -Math.PI - this.deg;
this.startedGame = true;
}
if (this.ballY-this.ballRadius < 183) {
this.deg = 2*Math.PI - this.deg;
this.startedGame = true;
}
//Move ball
this.ballX -= this.ballSpeed*Math.cos(this.deg);
this.ballY -= this.ballSpeed*Math.sin(this.deg);
}
drawControlBox() {
ctx.fillStyle = "black";
ctx.fillRect(1137, 75, 720, 480);
/* TYPING INTRO SEQUENCE */
ctx.fillStyle = "green";
ctx.font = "30px Typecast";
let totalString = `run doorcrack.pl|Loading...||You must manually break through the firewall!||Use <Left Arrow> and <Right Arrow> to move the|platform. Hit the ball against all of the barriers,|and don't let the ball hit the floor.||You have one attempt per Marine alive.||Lives remaining:||${'❤'.repeat(this.lives)}`; //Will be split on "|"
let substring = totalString.substring(0, this.typePosition);
let substringParts = substring.split("|");
let startY = 175;
substringParts.forEach((part, index) => {
if (index == 0) part = "me@zenith:~$ "+part;
ctx.fillText(part, 1237, startY);
startY += 25;
});
if (this.typePosition == totalString.length) { //Set status to "countdown" if instructions finished
this.status = (this.status == 3 ? 2 : this.status);
} else {
this.typePosition += 1;
}
}
drawGameBox() {
//Draw background
ctx.fillStyle = "black";
ctx.fillRect(61, 183, 1024, 768);
//Draw countdown
if (this.status == 2 || (this.status == 1 && this.countdown >= 0)) {
ctx.fillStyle = "green";
ctx.font = "125px Typecast";
ctx.fillText((this.countdown == 0 ? "Go!" : this.countdown), 100, 890);
}
//Draw platform
ctx.fillStyle = "green";
ctx.fillRect(this.platformX, this.platformY, this.platformWidth, this.platformLength);
//Draw ball if ingame
if (this.status == 1) {
ctx.fillStyle = "red";
ctx.beginPath();
ctx.arc(this.ballX, this.ballY, this.ballRadius, 0, 2 * Math.PI);
ctx.fill();
}
//Draw tiles
ctx.fillStyle = "green";
for (let r=0; r < 10; r++) {
for (let c=0; c < 10; c++) {
if (this.tiles[r][c] == 1) {
ctx.fillRect(100+(c*100), 183+(r*35), 140, 30);
}
}
}
//Draw old TV overlay
ctx.drawImage(s.tvOverlay, 61, 183, 1024, 768);
}
runCountdown() {
this.countdownTimer--;
if (this.countdownTimer < 0) {
this.countdown--;
this.countdownTimer = 90;
}
if (this.countdown < 1) {
this.status = 1;
}
}
winSequence() {
ctx.fillStyle = "green";
ctx.font = "125px Typecast";
ctx.fillText("Firewall breached!", 200, 500);
ctx.font = "75px Typecast";
ctx.fillText("Door successfully opened.", 250, 550);
ctx.font = "50px Typecast";
ctx.fillText("Press <SPACE> to continue.", 325, 600);
if (keysDown[32]) {
this.status = 9;
}
}
}
class Health {
/*
One of the entites dropped when "killing" a robot
Should partially resotre a marine's health
Status:
-2 Active
-1 Fading
-0 Dead
*/
constructor(_x, _y) {
this.x = _x;
this.y = _y;
this.width = 48;
this.length = 48;
this.nutrition = 10;
this.image = s.heart1;
this.status = 2;
this.opacity = 1;
}
render() {
if (this.status == 0) return;
//Draw image
ctx.globalAlpha = this.opacity;
ctx.drawImage(this.image, 0, 0, 16, 16, this.x, this.y, 48, 48);
ctx.globalAlpha = 1;
//Fade out if dying
if (this.status == 1) {
if (this.opacity <= 0.02) this.status = 0;
else this.opacity -= 0.02;
return;
}
//Check marine collisions
let colMarine;
for (let marine of marines) {
if (collide(this.x, this.y, this.width, this.length, marine.x, marine.y, marine.width, marine.length)) {
colMarine = marine;
damageboxes.push(new Damage(this.x, this.y-10, ("+"+this.nutrition)));
break;
}
}
//Check marine col, and give them health
if (colMarine && this.status == 2) {
if (colMarine.maxHealth > colMarine.health) colMarine.health += this.nutrition;
this.status = 1;
}
}
}
class Bitcoin {
/*
Physical bitcoin??? Okay
The secondary drop from killing a robot
Functions as ingame currency
Statuses are standard:
-2 spawned
-1 Fading out
-0 "Dead"
*/
constructor(_x, _y) {
this.x = _x;
this.y = _y;
this.width = 48;
this.length = 48;
this.image = s.bitcoin1;
this.status = 2;
this.opacity = 1;
}
render() {
if (this.status == 0) return;
//Draw image
ctx.globalAlpha = this.opacity;
ctx.drawImage(this.image, 0, 0, 16, 16, this.x, this.y, 48, 48);
ctx.globalAlpha = 1;
//Fade out if dying
if (this.status == 1) {
if (this.opacity <= 0.02) this.status = 0;
else this.opacity -= 0.02;
return;
}
//Check marine collisions
let colMarine;
for (let marine of marines) {
if (collide(this.x, this.y, this.width, this.length, marine.x, marine.y, marine.width, marine.length)) {
colMarine = true;
break;
}
}
if (colMarine && this.status == 2) {
money++;
this.status = 1;
}
}
}
function run(firstRun) {
/*
This function is called by the start button being pressed, and performs some initialisation before starting the render loop
*/
//Change button visibility
document.getElementById("run").style.display = 'none';
document.getElementById("fs").style.display = 'inline';
if (firstRun) renderType = 'start';
if (firstRun) initCanvas(); //Load canvas
//Load images
if (firstRun) s = new Sprites();
currentLevel = new Level(32, 24); //Usually done within loadLevel, but we need to create Marines
joystickObj = new Joystick(); //Create joystick
shopObj = new Shop(); //Create shop
gameoverObj = new GameOver();
createMarines(); //Create marines
createRobots(0); //Create first enemy (aww)
selectedMarine = marines[0]; //Select the first marine
//Mouse move listener (mX/mY will ALWAYS be available)
canvas.addEventListener('mousemove', function(e) {
mX = e.offsetX;
mY = e.offsetY;
});
//Keypress listener (keysDown will ALWAYS be available)
window.onkeyup = (e) => keysDown[e.keyCode]=false;
window.onkeydown = (e) => keysDown[e.keyCode]=true;
//Get keycode:
// window.onkeydown = (e) => console.log(e.keyCode);
//Start render loop
if (firstRun) update();
}
function render() {
/*
MAIN RENDER LOOP FUNCTION!
This function calls most functions in the program.
*/
//Run game
if (renderType == 'start') {
ctx.drawImage(s.gameoverBackground, 61, 183, 1024, 768);
ctx.drawImage(s.gameoverBackground, 1137, 75, 720, 480);
ctx.drawImage(s.titleImg, 340, 440, 440, 75);
ctx.fillStyle = "white";
ctx.font = "50px Typecast";
ctx.fillText("Gynvael's Winter GameDev Challenge 2018/19", 200, 570);
ctx.fillStyle = "#dbe8ff";
ctx.font = "100px Typecast";
if (++startTimer < 50) ctx.fillText("PRESS <Enter> TO START", 130, 650);
if (startTimer == 100) startTimer = 0;
if (keysDown[13]) {
renderType = 'level';
//Set mouse pos
mX = joystickObj.centerX+20;
mY = joystickObj.centerY-10;
}
ctx.fillStyle = "white";
ctx.fillText("How To Play", 1285, 180);
ctx.font = "50px Typecast";
ctx.fillText("All controls are done within", 1190, 240);
ctx.fillText(".", 1803, 240);
ctx.fillText("Click and", 1190, 280);
ctx.fillText("to move", 1653, 280);
ctx.fillText("the selected marine. Press \"", 1190, 320);
ctx.fillText("\", \"", 1655, 320);
ctx.fillText("\" or", 1724, 320);
ctx.fillText("\"", 1190, 360);
ctx.fillText("\" to select different marines, or click", 1221, 360);
ctx.fillText("on their sprites. You can", 1190, 400);
ctx.fillText("through the shop by pressing \"", 1190, 440);
ctx.fillText("\".", 1713, 440);
ctx.fillText("by pressing \"", 1409, 480);
ctx.fillText("\".", 1709, 480);
ctx.fillStyle = "#7ccbe8";
ctx.fillText("this box", 1671, 240);
ctx.fillText("drag the joystick", 1365, 280);
ctx.fillText("1", 1643, 320);
ctx.fillText("2", 1706, 320);
ctx.fillText("3", 1202, 360);
ctx.fillText("buy upgrades", 1612, 400);
ctx.fillText("S", 1694, 440);
ctx.fillText("Fire the gun", 1190, 480);
ctx.fillText("Space", 1621, 480);
}
//Pause menu
if (keysDown[80] && renderType == 'level' && !shopObj.show) {
previousRenderType = renderType;
renderType = 'pause';
}
if (renderType == 'pause') {
if (previousRenderType == 'level') currentLevel.draw();
drawControlBox();
ctx.drawImage(s.tvOverlay, 1137, 75, 1300, 1000);
ctx.drawImage(s.tvOverlay, 61, 183, 1024, 768);
ctx.fillStyle = "white";
ctx.font = "100px Typecast";
ctx.fillText("Press <ENTER> to Continue", 130, 575);
if (keysDown[13]) renderType = previousRenderType;
}
if (renderType == 'level') {
//Clean dead entities
enemies.forEach((enemy, index, enemyObject) => (enemy.status == 0) ? enemyObject.splice(index, 1) : null); //Remove dead enemies from screen
damageboxes.forEach((damagebox, index, damageObject) => (damagebox.status == 0) ? damageObject.splice(index, 1) : null); //Remove faded damage objects
bullets.forEach((bullet, index, bulletObject) => (bullet.status == 0) ? bulletObject.splice(index, 1) : null); //Remove dead bullets
items.forEach((item, index, itemObject) => (item.status == 0) ? itemObject.splice(index, 1) : null); //Remove dead items
drawControlBox();
//Draw entities
currentLevel.draw(); //Draw the level tiles
doors.forEach((door) => door.draw()); //Draw doors
items.forEach((item) => item.render()); //Draw and run loop for all items
enemies.forEach((n) => n.draw()); //Draw enemies
marines.forEach((n) => n.draw()); //Draw marines
bullets.forEach((bullet) => bullet.render()); //Draw, move and check damage for bullets
damageboxes.forEach((damagebox) => damagebox.draw()); //Draw damage boxes
doors.forEach((door) => door.drawLockText()); //Draw door lock text
//Control entities
enemies.forEach((enemy) => enemy.move()) //Move all enemies
//Check if level complete!
if (enemies.length == 0 && currentLevel.status == 2) {
doors.push(new Door(s.door1));
currentLevel.status = 1;
}
//End level and load new level
if (currentLevel.status == 0) {
if (levelCount % 4 == 3) loadMinigame();
else loadLevel();
}
if (marines.filter(m => m.status == 0).length == 3) renderType = 'gameover';
}
else if (renderType == 'minigame') { // RENDER LOOP FOR MINIGAME
currentMinigame.render();
if (currentMinigame.status == 9) {
loadLevel();
renderType = 'level';
}
if (currentMinigame.status == -1) renderType = 'gameover';
}
else if (renderType == 'gameover') { // RENDER LOOP FOR GAME OVER SCREEN
gameoverObj.render();
}
//Draw overlay
ctx.drawImage(s.overlay, 0, 0);
}
function drawControlBox() {
//Draw control box
//If showing game controls
if (!shopObj.show) {
//Background
ctx.drawImage(s.ctrlBackground, 1137, 75, 720, 480);
//title
ctx.drawImage(s.titleImg, 1345, 100, 300, 49);
//Check if other marine chosen
selectmarine();
//Move marine
selectedMarine.move(); //Move marine
//Fire bullets
selectedMarine.fire(); // Move/fire bullets
//Draw three players for selection
if (marines[0] !== selectedMarine) ctx.drawImage((marines[0].status == 2 ? s.marine1a : s.marine1d), 0, 0, 16, 16, 1317, 210, 100, 100);
else ctx.drawImage(s.marine1c, 0, 0, 19, 22, 1298, 191, 119, 138);
if (marines[1] !== selectedMarine) ctx.drawImage((marines[1].status == 2 ? s.marine2a : s.marine2d), 0, 0, 16, 16, 1457, 210, 100, 100);
else ctx.drawImage(s.marine2c, 0, 0, 19, 22, 1438, 191, 119, 138);
if (marines[2] !== selectedMarine) ctx.drawImage((marines[2].status == 2 ? s.marine3a : s.marine3d), 0, 0, 16, 16, 1597, 210, 100, 100);
else ctx.drawImage(s.marine3c, 0, 0, 19, 22, 1578, 191, 119, 138);
//Draw stats
ctx.fillStyle = "white";
ctx.font = "40px Typecast";
ctx.fillText("Current Level: "+levelCount, 1605, 420);
ctx.fillText("Total BTC: "+money, 1605, 450);
ctx.fillText("Upgrades bought: "+upgradeCount, 1605, 480);
//Draw shop icon (33x43)
ctx.font = "50px Typecast";
ctx.fillText("Open Shop (S)", 1145, 440);
ctx.fillText("Pause (P)", 1185, 480);
//Open shop if selected
if (renderType != 'pause' && (collide(1145, 415, 230, 34, mX, mY, 1, 1) && !selectedMarine.moveMarine || keysDown[83])) {
ctx.globalAlpha = 0.8;
ctx.fillRect(1145, 445, 230, 3) //Draw underline
ctx.globalAlpha = 1;
//Swap to shop if selected (no other place for this to go)
if (mouseDown || keysDown[83]) {
shopObj.show = !shopObj.show;
shopObj.clickCooldown = 25;
shopObj.page = 0;
}
}
if (renderType != 'pause' && (collide(1185, 455, 150, 34, mX, mY, 1, 1) && !selectedMarine.moveMarine)) {
ctx.globalAlpha = 0.8;
ctx.fillRect(1185, 485, 150, 3) //Draw underline
ctx.globalAlpha = 1;
if (mouseDown) {
previousRenderType = renderType;
renderType = 'pause';
}
}
//Draw joystick
joystickObj.draw(mX, mY);
}
//If showing shop
else { //Draw shop
shopObj.render();
}
}
function initCanvas() {
/*
This function initiallises the canvas, creating the elements.
*/
gameDiv = document.getElementById("game");
canvas = document.createElement("canvas");
ctx = canvas.getContext("2d");
canvas.width = 1920;
canvas.height = 1080;
gameDiv.appendChild(canvas);
ctx.imageSmoothingEnabled = false; //Remove blurs
fullscreen();
}
function createMarines() {
/*
This function creates a set of three Marines.
We can only create 3, because there are only 3 marine images.
*/
//https://www.reddit.com/r/ProgrammerHumor/comments/adbkej/error_handling_101/
for (let i=0; i<3; i++) {
try {
marines.push(new Marine(s.marineImages[i]));
} catch(ex) {
i--;
}
}
}
function createRobots(num) {
/*
This function creates n robots.
The robot spawn locs/images are all dealt with within the class' constructor
*/
for (let i=0; i<num; i++) {
try {
enemies.push(new Robot());
}
catch (ex) {
num--;
}
}
}
function selectmarine() {
/*
This function checks whether a new marine is being selectedMarine.
TODO:
Do marine selection through clicking on marines instead of number keys
*/
//Keyboard selection
if (keysDown[49] && marines[0].status == 2) selectedMarine = marines[0];
else if (keysDown[50] && marines[1].status == 2) selectedMarine = marines[1];
else if (keysDown[51] && marines[2].status == 2) selectedMarine = marines[2];
//Mouse selection
if (mouseDown && !selectedMarine.moveMarine) {
if (collide(1317, 210, 100, 100, mX, mY, 1, 1) && marines[0].status == 2) selectedMarine = marines[0];
if (collide(1457, 210, 100, 100, mX, mY, 1, 1) && marines[1].status == 2) selectedMarine = marines[1];
if (collide(1597, 210, 100, 100, mX, mY, 1, 1) && marines[2].status == 2) selectedMarine = marines[2];
}
}
function generateLevel(width, height) {
/*
This function generates a level, as an array:
0: Space
1: Ground
2: s.wall1
Parameters:
width: Length of grid
height: Height of grid
This should be called only from within the Level class.
Prototype can be found at https://repl.it/@georgeomnet/randomDungeonPrototype
*/
let level = [];
//Generate 2d array
for (let r=0; r < height; r++) {
level[r] = [];
for (let c=0; c < width; c++) {
level[r][c] = 0;
}
}
//Generate random *overlapping* rectangles as shapes.
for (let i=1; i < 5; i++) {
tempLevel = level.map(l => l.slice());
randomStartX = ranbetween(0, Math.round((2/3)*width));
randomStartY = ranbetween(0, Math.round((2/3)*height));
randomEndX = ranbetween(randomStartX+4, width);
randomEndY = ranbetween(randomStartY+4, height);
for (c=randomStartX; c < randomEndX; c++) {
for (r=randomStartY; r < randomEndY; r++) {
tempLevel[r][c] += 1;
}
}
if ([].concat.apply([],tempLevel).indexOf(i) != -1) {
level = tempLevel.map(l => l.slice());
} else {
i--; //If not overlapping, go again!
}
}
level = level.map(row => row.map(c => c == 0 ? c : 1));
//Turn ground to s.wall1 if on edge (not on boundary)
for (let r=0; r < height; r++) {
for (let c=0; c < width; c++) {
if (level[r][c] == 0) continue;
surroundingCells = [];
if (r == 0 || c == 0 || r == height-1 || c == width-1) {
surroundingCells.push(0);
}
else {
surroundingCells = [
level[r-1][c-1], //Top-left
level[r-1][c], //Top-mid
level[r-1][c+1], //Top-right
level[r][c+1], //Right-mid
level[r+1][c+1], //Bottom-right
level[r+1][c], //Bottom-mid
level[r+1][c-1], //Bottom-left
level[r][c-1] //Left-mid
];
}
if (surroundingCells.indexOf(0) != -1) level[r][c] = 2;
}
}
return level;
}
function loadLevel() {
items = [], doors = [], bullets = [];
levelCount++;
currentLevel = new Level(32, 24);
marines.forEach(marine => {
marine.spawnLocation = currentLevel.spawnable[ranbetween(0, currentLevel.spawnable.length-1)];
if (marine.status == 2) {
marine.x = marine.spawnLocation[0];
marine.y = marine.spawnLocation[1];
}
})
createRobots(ranbetween((levelCount < 3 ? 1 : levelCount-2), (levelCount < 9 ? levelCount : 9)));
}
function loadMinigame() {
renderType = 'minigame';
minigameCount++;
switch(minigameCount%2) {
case 0:
currentMinigame = new Obstacle();
break;
case 1:
currentMinigame = new Breakout();
break;
default:
alert("How did this happen");
}
}
function restart() {
levelCount=1, upgradeCount=0, money=0, totalRobotsKilled=0, totalDoorsHacked=0;
levels=[], doors=[], marines=[], damageboxes=[], enemies=[], bullets=[], items=[]; //Entity arrays
renderType = 'level';
gameOver = false;
run(false);
}
function update() {
/*
This function keeps the render loop going.
(Do not touch)
*/
render();
requestAnimationFrame(update);
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment